Windows Azure Active Directory をアプリケーションから利用する際、 Windows プラットフォームであれば、Windows Azure Authentication Library(AAL)を利用することになると思いますが、折角 RESTful な Graph API があるので、汎用 REST Client を使って API へアクセスしてみたいと思います。
■準備
TenantContextID、AppPrincipalId、SymmetricKey が必要となります。前回同様、CreateServicePrincipal.ps1を使って必要な値を取得します。
用意が出来たらいよいよアクセスしますが、今回やろうとしていることの全体像を簡単に図にしておきます。
まず Graph API を利用するために必要な認可を ACS で受け、ACS から取得した Access Token を持って Graph API を利用する、という流れになります。
実際にやってみると以下のような手順になります。
■Graph API を利用するための Access Token を取得する(REST Client ⇒ ACS)
初めに、Graph API へのアクセスを行うために必要な Access Token を ACS から取得する必要があります。
そのためには ACS へ JSON Web Token(JWT)形式でリクエストを投げる必要があります。
リクエスト先および内容は以下の通りです。
Target Endpoint | https://accounts.accesscontrol.windows.net/tokens/OAuth/2 | |
---|---|---|
Method | POST | |
Request Header | Content type | application/x-www-form-urlencoded |
Request Body | grant_type | http://oauth.net/grant_type/jwt/1.0/bearer |
assertion (実際は Symmetric Key でデジタル署名したもの) | { "alg": "HS256", "typ": "JWT" } { "aud": "00000001-0000-0000-c000-000000000000/accounts.accesscontrol.windows.net@[TenantContextId]", "iss": "[AppPrincipalId]@[TenantContextId]", "nbf": "[UNIX 時間で現在の時刻]", "exp": "[UNIX 時間でTokenの有効期限]" } | |
resource | resource : 00000002-0000-0000-c000-000000000000/directory.windows.net@[テナントID] |
Assertion の部分を作り方は少々面倒ですが、下記の通りです。
・ヘッダ部分を Base64 でエンコード
文字列「{"alg": "HS256","typ": "JWT"}」をこのあたりのツールで Base64 URL エンコードします。
結果、「eyJhbGciOiAiSFMyNTYiLCJ0eXAiOiAiSldUIn0」という文字列が得られます。
・ボディ部分を作成
JWT を構成する、nbf(Not Before / 有効開始時刻)、exp(Expiration Time)クレームは UNIX 時刻(1970年からの経過秒数)で表すため、このあたりのツールを使って現在時刻および現在時刻+1時間を変換した値を取得します。
例えば、2012年9月25日23時00分00秒~2012年9月26日00時00分00秒まで有効なトークンを作成するには、
"nbf" : "1348581600",
"exp" : "1348585200"
というクレームを設定します。
結果、以下の様な JWT ボディを作成します。
{
"aud": "00000001-0000-0000-c000-000000000000/accounts.accesscontrol.windows.net@[TenantContextId]",
"iss": "[AppPrincipalId]@[TenantContextId]",
"nbf": "1348581600",
"exp": "1348585200"
}
・ボディ部分を Base64 でエンコード
先ほどのヘッダ部分と同様に生成した JWT のボディも Base64 URL エンコードします。
結果、「eyJleHAiOiIxMzQ4NTU5MTY4IiwiYXVkIjoiM(以下略)」といった文字列が得られます。
・ヘッダ+ボディを連結した raw token と SymmetricKey でデジタル署名を生成
ヘッダ部分とボディ部分を"."(ピリオド)で連結した raw token を作成し、SymmetricKey を Base64 デコードした文字列を使ってデジタル署名を生成します。
良いオンラインツールがなかったので、以下の Java コードを作成し、署名を生成しました。
※Java であることに深い意味はありません。手元に eclipse が起動していた&Java のサンプルがあった、というだけです。
※どなたか良いオンラインツールがあれば教えてください。
import javax.crypto.spec.SecretKeySpec; import javax.crypto.Mac; import org.apache.commons.codec.binary.Base64; public class GenerateSignature { private static byte[] signData(String signingKey, String rawToken) { SecretKeySpec secretKey = null; secretKey = new SecretKeySpec(Base64.decodeBase64(signingKey), "HmacSHA256"); Mac mac; byte[] signedData = null; try { mac = Mac.getInstance("HmacSHA256"); mac.init(secretKey); mac.update(rawToken.getBytes("UTF-8")); signedData = mac.doFinal(); } catch (Exception e) { System.out.println("signData error"); } return signedData; } /** * @param args */ public static void main(String[] args) { String signingkey = "Li7Awy53cq(以下略。SymmetricKey文字列)"; String rawToken = "eyJhbGciOiJ(以下略。ヘッダ部分)).eyJleHAiOiIxMzQ4(以下略。ボディ部分)"; String signature = Base64.encodeBase64String(signData(signingkey,rawToken)); System.out.println(signature); } }
・Assertion の生成
生成した署名文字列を先ほどの raw token の後に同じく"."(ピリオド)で連結します。
このようにして作成した Assertion を他のパラメータと一緒に ACS へ POST します。
リクエストの POST は Chrome Extension の Advanced Rest Client を使いました。
以下の様にパラメータをセットし、[Send request]ボタンをクリックします。
うまくいくと、HTTP 200 が返ってきて、JSON 形式で Access Token が取得できます。
■取得した Access Token で Graph API を利用する(REST Client ⇒ Graph API)
いよいよ Graph API を使います。
リクエスト先および内容は以下の通りです。
Target Endpoint | https://directory.windows.net/[テナントドメイン名].onmicrosoft.com/Users | |
---|---|---|
Method | GET | |
Request Header | Authorization | 取得した Access Token 文字列(bearer 以降) |
x-ms-dirapi-data-contract-version | 0.8 |
先ほどと同様に Advanced Rest Client にパラメータをセットして、[Send request]ボタンをクリックします。
うまくいくと、HTTP 200 が返ってきて、ユーザ一覧が取得できます。
尚、書き込みを行う場合はロール設定が必要になるので、このあたりは次回以降で。。
Base64ではなく、Base64url が正式です。なので、 = パディングは行われません。
返信削除> natさん
返信削除本当ですね。ご指摘ありがとうございます。
確認、修正しておきます。