2013年7月20日土曜日

[WAAD] OAuth2.0 への対応状況まとめ&ちょこっと OpenID Connect も

まず初めにお断りしておきますが、公式リソースでは Windows Azure Active Directory の OAuth2.0 への対応自体はアナウンスされていますが、内容について明確には言及がない状態なので、あくまで今日時点で色々と探索した結果を書いており、間違いや今後の変更などは高い確率で発生すると思われます。あくまで、エンドポイントを探して叩いてみたらこんな結果が返ってきた、という状態であるとご理解ください。


さて、始めます。

WAAD でアプリケーションを追加すると様々なエンドポイントが付与されます。


その中には OAuth2.0 のトークン・エンドポイントも含まれており、OAuth2.0 プロトコルで使う client_id や client_secret の取得、redirect_uri 等の設定もアプリケーションの構成の中で行うことが出来ます。


さらに、現状ではプレビュー提供ですが protected resource として同じく WAAD 上に構成したアプリケーションを登録することも可能であり、OAuth2.0 を使って WAAD 上のアプリケーション(API)をマッシュアップしていくことも可能になっています。



基本的には WAAD Authentication Library(AAL)を使ってアクセストークンなどを取得することが前提のようですが、折角そこに OAuth のエンドポイントがあるので叩いてみたいと思います。

まず、叩き方ですが、先日日本語訳がされた OAuth2.0 の仕様(RFC6749)に定義されている各種フローをそれぞれ試してみます。

 The OAuth 2.0 Authorization Framework(OpenID Foundation Japan 翻訳 WG 訳)
 - http://openid-foundation-japan.github.io/rfc6749.ja.html


試したのは、
・認可コードグラント
・インプリシットグラント
・リソースオーナーパスワードクレデンシャル
・クライアントクレデンシャル
です。

それぞれやってみます。


◆認可コードグラント

仕様上は、ざっくりいうと
1.クライアントが認可エンドポイントから認可コードを取得
2.トークンエンドポイントで認可コードとアクセストークンを交換
という流れになります。

ここで疑問。先ほど出てきた WAAD の OAuth2.0 エンドポイントにはトークンエンドポイントはありましたが、認可エンドポイントが出てきていませんでした。

トークンエンドポイントのアドレスが
 https://login.windows.net/<テナントID>/oauth2/token?api-version=1.0
だったので、token ⇒ authorize に変えたら行けるかな?ということで
 https://login.windows.net/<テナントID>/oauth2/authorize?api-version=1.0
を試してみます。意外と行けるもんです(笑)


ということで以下を試します。
1.認可コードの取得

 エンドポイント:認可エンドポイント
 メソッド:GET
 パラメータ:
  ・response_type : code
  ・client_id : <WAADで取得した client_id>

 こんなクエリになります。

 GET /<テナントID>/oauth2/authorize?api-version=1.0&response_type=code&client_id=<client_id> HTTP/1.1
 Host: login.windows.net

 仕様上は HTTP 302 が返ってきて Location に redirect_uri?code=xxx という形で認可コードが返ってくるはずです。

 結果、Microsoft Online アカウントでの認証が実行された後、ちゃんと認可コードが返ってきました。







2.認可コードとアクセストークンの交換

 次は取得した認可コードをトークンエンドポイントへ投げてアクセストークンを取得します。

 エンドポイント:トークンエンドポイント
 メソッド:POST
 パラメータ:
  ・grant_type : authorization_code
  ・code : <取得した認可コード>
  ・resource : アクセス対象の保護リソースの URI(WAAD 上で指定した WebAPI のURI)。今回は Graph API の URI(https://graph.windows.net)を指定します。

 ※OAuth2.0 の仕様上は resource パラメータは存在しませんが、WAAD の OAuth2.0 エンドポイントへアクセスする場合は必ず resource パラメータを要求されます。

 POST /<テナントID>/oauth2/token HTTP/1.1 Host: login.windows.net
 Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=<取得した認可コード>&resource=https%3A%2F%2Fgraph.windows.net

 結果、残念ながら、「unsupported_grant_type」が返ってきてしまいました。
 エラーの説明として「ACS70003: The access grant 'authorization_code' is not supported」とあるので、現状は認可コードグラントは使えない、ということです。




◆インプリシットグラント

次はインプリシットグラントです。こちらは非常に単純なフローで、認可エンドポイントに対してアクセストークンを直接要求します。

 エンドポイント:認可エンドポイント
 メソッド:GET
 パラメータ:
  ・response_type : token
  ・client_id : <WAADで取得した client_id>

 こんなクエリになります。

 GET /<テナントID>/oauth2/authorize?api-version=1.0&response_type=token&client_id=<client_id> HTTP/1.1
 Host: login.windows.net

 仕様上は HTTP 302 が返ってきて Location に redirect_uri#access_token=xxx&token_type=xxx という形でフラグメントにアクセストークンが返ってくるはずです。

 しかし、これも残念。「unsupported_response_type」といわれてしまいます。こちらも使えない、といことです。



◆リソースオーナーパスワードクレデンシャル

続いてリソースオーナーパスワードクレデンシャルです。こちらも単純でリソースオーナーのユーザ名とパスワードをクエリに埋め込んでアクセストークンを要求します。

 エンドポイント:トークンエンドポイント
 メソッド:POST
 パラメータ:
  ・grant_type : password
  ・username : <WAADのユーザ名>
  ・password : <WAADのパスワード>
  ・resource : https://graph.windows.net

 こんなクエリになります。

 POST /<テナントID>/oauth2/token HTTP/1.1 Host: login.windows.net
 Content-Type: application/x-www-form-urlencoded grant_type=password&username=<WAADのユーザ名>&password=<WAADのパスワード>&resource=https%3A%2F%2Fgraph.windows.net

 こちらもうまくいけば HTTP 200 でアクセストークンが返ってくるはずです。

 しかし、同じくこちらも残念ながら「unsupported_grant_type」です。なかなかうまく行かないもんです。



◆クライアントクレデンシャルグラント

最後はクライアントクレデンシャルグラントです。こちらはトークンエンドポイントへ直接トークンを要求します。

 エンドポイント:トークンエンドポイント
 メソッド:POST
 パラメータ:
  ・grant_type : client_credentials
  ・client_id : <取得した client_id>
  ・client_secret : <取得した client_secret>
  ・resource : https://graph.windows.net

 ※こちらも仕様上は grant_type 以外のパラメータは必須ではありませんが、認証を行うことが必要なフローなので、WAAD では client_id と client_secret を投げてクライアント認証を行っているようです。

 こんなクエリになります。

 POST /<テナントID>/oauth2/token HTTP/1.1 Host: login.windows.net
 Content-Type: application/x-www-form-urlencoded grant_type=client_credentials&client_id=<取得した client_id>&client_secret=<取得した client_secret>&resource=https%3A%2F%2Fgraph.windows.net

 うまくいけば HTTP 200 でアクセストークンが返ってくるはずです。

 こちらは、、、、、うまく行きました。

{
 "token_type":"Bearer",
 "access_token":"eyJ0eX........(略)",
 "expires_in":"43199",
 "not_before":"1374294762",
 "expires_on":"1374337962",
 "resource":"https://graph.windows.net"
}



と、いうことで結果をまとめると下記の通りとなります。
まぁ、まだまだですねぇ。

フロー結果備考
認可コードグラント×Code requetは成功
Token requestでunsupported_grant_type
インプリシットグラント×unsupported_response_type
リソースオーナーパスワードクレデンシャル×unsupported_grant_type
クライアントクレデンシャルグラント以下のパラメータが要求される
Resource
Client_id
Client_secret







◆おまけ(OpenID Connect)

ここからはおまけですが、WAAD も OpenID Connect に対応するという話があります。OpenID Connect は OAuth2.0 ベースなので少し試してみました。
試したのはインプリシットのみで、結果的に言うと id_token の取得が出来てしまいました。が、仕様への対応状況はまだかなり怪しい感じです。

 エンドポイント:認可エンドポイント
 メソッド:GET
 パラメータ:
  ・response_type : id_token token
  ・client_id : <WAADで取得した client_id>
  ・scope : openid profile
  ・nonce : <任意の文字列>

 こんなクエリになります。

 GET /<テナントID>/oauth2/authorize?api-version=1.0&response_type=id_token%20token&client_id=<client_id>&scope=openid%20profile&nonce=<任意の文字列> HTTP/1.1
 Host: login.windows.net

 仕様上は HTTP 302 が返ってきて Location に redirect_uri#id_token=xxx&access_token=xxx&token_type=xxx という形でフラグメントに ID トークンとアクセストークンが返ってくるはずです。

 しかし、先に述べたように response_type に token を指定するとエラーになるので、今回は response_type = id_token のみを指定してみました。

 すると、フラグメントではなく、パラメータで id_token が返ってきました。

 返ってきた id_token を BASE64 URL デコードしてみると、
{
 "typ":"JWT",
 "alg":"RS256",
 "x5t":"NGTFvdK-fythEuLwjpwAJOM9n-A"
}

{
 "aud":"<取得した client_id>",
 "iss":"https://sts.windows.net/<テナント ID>/",
 "nbf":1374284435,
 "exp":1374313235,
 "ver":"1.0",
 "tid":"<テナントID>",
 "oid":"<WAAD 上のユーザのオブジェクトID>",
 "upn":"xxx@<テナントドメイン>.onmicrosoft.com",
 "sub":"vqrPXdoNdGPRd5DBnH...(略)",
 "family_name":"富士榮",
 "given_name":"尚寛",
 "nonce":"hoge"
}

 という形になりました。
 sub に入っている値が何なのか、Graph API 等で探ってみたのですが、利用者に見えるところには出てこない識別子のようです。

まだ、これで何か出来るわけではありませんが、Office Web App の開発リファレンスを見ているとトークンのデコードや検証のためのサンプルコードが出ていたりするので、同じ仕組みを使うことが出来るようです。

今回、色々と課題はあるものの WAAD が着々と OAuth2.0 や OpenID Connect に対応してきていることが見えてきました。
今後は社内の Active Directory と AD FS ⇒ WAAD を経由して OpenID Connect RP への認証連携なども実現できるようになってきそうなので、ますますコンシューマ系のサービスとの接続が容易になってくるのかも知れません。

引き続き目が離せないところです。

0 件のコメント: