2015年1月5日月曜日

[JWT/OAuth]Service Accountを使ってGoogle APIを利用する①

今回はサーバアプリケーションからAPIを利用する際の認可の話をGoogleAppsでのOAuth(JWT)の使い方の例をベースに紹介したいと思います。

◆アプリケーションがAPIを利用する際の課題とOAuth2.0
Forefront Identity Manager(FIM)などのサーバアプリケーションからGoogle Admin Directory APIなどを利用する際、サーバアプリケーションに管理者ユーザのIDやパスワードを保持すると様々なデメリットがあります。
例)

  • 管理者のパスワードを変更する際、サーバアプリケーションの設定を変える必要が出てくる
  • サーバアプリケーションに管理者パスワードを保存しておく必要がありセキュリティ上の問題となる可能性がある

※実際、現在codeplex上に公開しているFIM用GoogleApps管理エージェント(Management Agent/MA)ではMA設定にGoogleAppsの管理者ユーザのIDとパスワードを保持しています。

 FIM 2010 GoogleApps MA
 https://fim2010gapps.codeplex.com/


また、サーバアプリケーションに限らずアプリケーションにIDやパスワードを持たせてユーザの代わりにAPIへアクセスするのはよろしくない、ということでOAuth2.0を使った認可(アプリケーションへの権限委譲)が主流になってきています。

(フローの例)
①認可サーバでユーザがAPI(保護対象リソース)へWebアプリケーションがアクセスすることを許可
②認可サーバより発行される認可コードをWebアプリケーションへ渡す
③Webアプリケーションが認可サーバで認可コードとアクセストークンを交換する
④発行されたアクセストークンを使ってAPIを利用


◆サーバアプリケーションがOAuthを使う際の課題と対応
しかし、一般的なWebアプリケーションとは異なりサーバアプリケーションではリソースオーナーであるユーザが一切介在することなくAPIを利用することが求められます。

このようなケースに対応し、Azure Active DirectoryやGoogleApps、Salesforce.comなどの主要クラウドベンダはサーバアプリケーション向けにJWT(JSON Web Token)やJWS(JSON Web Signature)を使ったAPI利用フローを用意しています。

 Azure ADの例(少し古いです)
  http://idmlab.eidentity.jp/2012/09/waad-rest-client-graph-api.html

 GoogleAppsの例(公式ドキュメント)
  https://developers.google.com/accounts/docs/OAuth2ServiceAccount


今回はちょうど先にあげたCodeplexに上げているFIM 2010 GoogleApps MAが使っているGoogleAppsのProvisioning APIの提供が終了するので、代わりに提供されているDirectory APIへ対応させるために改修を行う過程で行ったGoogleApps APIへのアクセス認可の方法を紹介していきます。


◆GoogleAPIへのアクセス用トークンを取得する
さて、実際にGoogleAppsの場合のアクセストークンの取得方法を解説していきます。
先のGoogleのドキュメントをみるとサービスアカウントを使ったAPI利用、というケースが今回のユースケースに該当します。流れとしてはJWTにRSA-SHA256で署名したものをOAuthのトークンエンドポイントへPOSTすればアクセストークが取得できる、とあります。
以下が公式ドキュメントに書いてあるフローです。



【準備】
まずは、JWTを生成する上で必要な設定をGoogle側に入れていきます。

必要なのは、以下の4点です。
①必要なAPIを有効化する
 ⇒GoogleAppsでは最初からすべてのAPIが有効になっているわけではないので、必要なAPIを有効化します。
②クライアントIDを生成する
 ⇒Googleにクライアント情報を登録し、署名に使う証明書を発行してもらう
③GoogleAppsのテナントのAPIアクセスを有効化する
 ⇒初期状態ではAPIアクセスは無効なので有効化する必要があります。
④生成したクライアントから利用できるAPIの範囲(スコープ)を設定する
 ⇒②で生成したクライアントが利用できるAPIをあらかじめ定義しておきます。


順番に見ていきます。①②はGoogle Developer Consoleから、③④はGoogleAppsの管理ダッシュボードのセキュリティメニューから設定します。

①必要なAPIを有効化する
 Google Developer Console(https://console.developers.google.com)にアクセスするとプロジェクトを作成する画面になりますので、まだプロジェクトを作成したことのない人はプロジェクトを作成してください。
 作成が終わったら左ペインの[APIと認証]メニューよりAPIを選択するとAPI一覧の画面になりますので、今回使いたいDirectory APIが含まれるAdmin SDKを探してステータス列の[OFF]のボタンをクリックし有効化を行います。


 確認・同意画面がポップアップするので[同意]をクリックしてAPIを有効化します。


 有効なAPI一覧にAdmin SDKが出てきます。



②クライアントIDを生成する
 次に、同じくDeveloper Consoleの[認証情報]メニューを開き、新しいクライアントIDを作成します。


 作成するクライアントIDの種類を聞かれるので[サービスアカウント]を選択します。


 作成が成功すると、公開鍵/秘密鍵のペアが生成され、秘密鍵の入った証明書ファイル(.p12ファイル)が自動的にダウンロードされます。このファイルは後で使うので大切に保管しておいてください。秘密鍵のパスワードは[notasecret]で固定みたいですが、その値の通り特に秘密事項ではありませんので合言葉として覚えておけばよいです。


 その後、画面上にサービスID情報が表示されます。
 ここで表示されるサービスIDおよびメールアドレス(サービスアカウントのメールアドレス)は後で使いますので、保存しておいてください。



 これでDeveloper Consoleは終わりです。

③GoogleAppsのテナントのAPIアクセスを有効化する
 次はGoogleAppsの管理ダッシュボードの設定です。
 ダッシュボードよりセキュリティメニューを開き、[APIリファレンス]を開くと[APIアクセス]が出てきますので、ここで[APIアクセスを有効にする]にチェックを入れておきます。これでこのGoogleAppsテナントへAPI経由でのアクセスが出来るようになります。


④生成したクライアントから利用できるAPIの範囲(スコープ)を設定する
 同じくセキュリティメニューの[詳細設定]を開きます。ちなみに詳細設定が表示されていない場合は[もっと見る]というリンクがシングルサインオン設定メニューの下にありますので、そちらをクリックしてください。
 サブメニューの中の[APIクライアントアクセスを管理する]をクリックして実際の設定を行います。


 クライアント名に②で生成したクライアントID、APIの範囲に使いたいAPIに対応したスコープを設定します。
 ちなみにDirectory APIの中で今回はユーザを管理したいので、以下を設定します。
  https://www.googleapis.com/auth/admin.directory.user


 スコープの一覧は以下に記載されています。
  https://developers.google.com/admin-sdk/directory/v1/guides/authorizing


ここまでで準備は終わりです。
次回は実際にJWTを生成してアクセストークンを取得するところを解説します。
(.Net標準でSystem.IdentityModel.Tokens.jwtのJwtSecurityTokenHandlerがあるのでせっかくなので使おうとしましたが、結果的にGoogleとはかなり相性が悪く、ほぼスクラッチでコードを書きました...orz。詳しくは次回)

0 件のコメント: