LoginSignup
4
6

More than 5 years have passed since last update.

OpenAMから認可コードフローを使ってID連携を試す

Last updated at Posted at 2016-12-09

はじめに

昨日はOpenAMをOpenID Providerにしてみました。今日はOpenID Connectのエンドポイントを少したたいてみて、その動きを見ていきたいと思います。

目標はシンプル

わたしがOpenID Connectを使いたい理由って結構シンプルなんです。

  • 会社のアプリにシングルサインオンしたい(クロスドメインのアプリを含む)
  • そのためにアプリにID Federation(ID連携)したい
  • ID連携の情報の中にはOpenAMで誰々さんが認証成功したよっていう情報と認証した誰々さんの属性情報(プロフィール)を含みたい

これだけっちゃーこれだけなので、いろんなドキュメントをリファレンスしながら、試してみましょう。

ID Token

いろいろ試す前に、ID Tokenの説明は欠かせません。
ID Tokenとは、認証時のAssertion情報を含んだトークンです。ふわ~っと表現すると、先ほどのOpenAMで認証したよという情報と要求に応じて付加することのできる認証したユーザーの属性情報とかを含みます。
ID Tokenは、JSON Web Tokenという形式で表現されています。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJpc3MiOiJodHRwczovL3NlcnZlci5leGFtcGxlLmNvbSIsInN1YiI6IjI0NDAwMzIwIiwiYXVkIjoiczZCaGRSa3F0MyIsIm5vbmNlIjoibi0wUzZfV3pBMk1qIiwiZXhwIjoxMzExMjgxOTcwLCJpYXQiOjEzMTEyODA5NzAsImF1dGhfdGltZSI6MTMxMTI4MDk2OSwiYWNyIjoidXJuOm1hY2U6aW5jb21tb246aWFwOnNpbHZlciJ9.
kz_LR9UOUnhlCft8CzJHJ58gvu5FI8OoLnAuxt1GFa8

わかりませんね。このトークンは以下のような構成になっています。

BASE64URL (UTF-8 (Header))
.
BASE64URL (UTF-8 (Payload))
.
Base64url (UTF-8 (Signature))

なので、.でsplitとbase64UrlDecodeするとPayload部の抽出ができます。
こんなかんじ。

{
   "iss": "https://server.example.com",
   "sub": "24400320",
   "aud": "s6BhdRkqt3",
   "nonce": "n-0S6_WzA2Mj",
   "exp": 1311281970,
   "iat": 1311280970,
   "auth_time": 1311280969,
   "acr": "urn:mace:incommon:iap:silver"
}

各行の意味は以下のような感じ。このPayloadはOpenID ConnectのSpecからぱくってきました(´ρ`)

param desc e.g.
iss トークンの発行者で、ようはOpenAM https://server.example.com
sub OpenAM内でのユーザーの識別子 24400320
aud どのアプリに向けて発行したか s6BhdRkqt3
nonce IDトークンくれっ!って要求をIDトークンに関連付けるための情報 n-0S6_WzA2Mj
exp IDトークンの有効期限 1311281970
iat IDトークンをつくった時間 1311280970
auth_time ユーザーが認証した時間 1311280969
acr どんなコンテキストで認証したか? urn:mace:incommon:iap:silver

他にもパラメータがあります。詳しくはこのPayloadのパクり元をご参照ください。

Authorization Code Flow

Authorization Code Flow(認可コードフロー)というものを試してみます。
Authorization Code Flowとは、フロント側ではcodeという情報を持ちまわって、ID Tokenをバックチャネルで取得するフローです。OpenID Connectには他にもImplicit Flowがありますが、それと比べて以下のような特性があります。

  • User-AgentにID Tokenを公開しなくてもよいので安全
  • ID Tokenを発行するときに、ID Tokenを欲しているアプリ(Relying Party)の認証をすることができる
  • 上述の認証をするためのシークレット情報を安全に維持できるアプリに適する(Webアプリとか)

Authorization Code Flowは以下のような感じです。

001.jpg

  1. Relying Partyは認可リクエストをおくる準備をする
  2. 認可リクエストをOpenID Providerに送信する
  3. OpenID Providerはユーザー認証する
  4. OpenID ProviderはRelying PartyにID連携することの同意をユーザーから得る
  5. OpenID ProviderはAuthorization CodeをRelying Partyに返却する
  6. Relying PartyはAuthorization CodeをOpenID Providerに送る
  7. OpenID ProviderはID TokenとAccess TokenをRelying Partyに返却する
  8. Relying PartyはID Tokenの検証をする

OpenAMにRelying Partyを登録する

ではやっていきましょう!

OpenAMに管理者アカウント(ユーザー名はamadmin)でサインインします。

Applications => OAuth 2.0 => 新規をクリックします。

002.JPG

以下のパラメータを入力します。

  • 名前(client id)
    • relying party
  • パスワード(client secret)
    • password

003.JPG

この設定だけだと何もできないので、先ほど作成したrelyingpartyの設定を開き、以下のパラメータを入力します。

004.JPG

試してみる

本当はちゃんとRelying Partyを用意してやってみたらいいんだけど、今日はお試しです。ブラウザ上で疑似Relying Partyみたいなことをしてみます。
先ほどの1.~8.に沿ってやっていきましょう。

1. Relying Partyは認可リクエストをおくる準備をする

リクエストパラメータをつくります。(パクりもとはこのへん

param desc e.g.
response_type フローを指定 code
scope 要求する情報の範囲を指定 openid profile
client_id Relying Partyの識別子を指定 relyingparty
state 2.5.を紐づけるコード af0ifjsldkj
redirect_uri Authorization Codeを返却するコールバックURI https%3A%2F%2Flocalhost:443%2Fcb

説明にもあるとおり、stateは本来は後で検証に使うので、Relying Party側で保持しておく必要があります。

2. 認可リクエストをOpenID Providerに送信する

本当はRelying Partyからの302 FoundのLocation Headerで送信されたりしますが、本日はお試しなのでブラウザから送信します。

https://iam.example.com/openam/oauth2/authorize?
    response_type=code&
    scope=openid%20profile&
    client_id=relyingparty&
    state=af0ifjsldkj&
    redirect_uri=https%3A%2F%2Flocalhost:443%2Fcb

3. OpenID Providerはユーザー認証する

OpenAMのサインイン画面が表示されるので、本連載記事の検証用アカウント(ユーザー名はjohnd)でサインインします。

005.JPG

4. OpenID ProviderはRelying PartyにID連携することの同意をユーザーから得る

OAuth 2.0でもそうですが、OpenID Connectでは、Client(Relying Party)に対し、ID情報(ID Tokenやプロフィール情報)を連携する同意を求められます。OpenAMでは以下のように、実際に連携するプロフィールが表示されるようになっています。

006.JPG

5. OpenID ProviderはAuthorization CodeをRelying Partyに返却する

連携を許可すると、Relying PartyにAuthorization Codeをコールバックに返却します。
Query Stringに載っているので、コピペします。

https://localhost/cb?
    code=95a103d8-c849-41cc-9968-51d4b10c1661&
    scope=openid%20profile&
    iss=https%3A%2F%2Fiam.example.com%3A443%2Fopenam%2Foauth2&
    state=af0ifjsldkj&
    client_id=relyingparty

6. Relying PartyはAuthorization CodeをOpenID Providerに送る

先ほどコピペしたAuthorization CodeをPOSTのリクエストに載せて、ID Tokenを要求します。
要求する際にはRelying Partyを認証しますので、Authorization Headerにclient idclient secret:で繋げてbase64encodeしたものを載せておきます。

$ curl -k
    -H "Content-Type: application/x-www-form-urlencoded"
    -H "Authorization: Basic cmVseWluZ3BhcnR5OnBhc3N3b3Jk"
    -d "grant_type=authorization_code"
    -d "code=95a103d8-c849-41cc-9968-51d4b10c1661"
    -d "redirect_uri=https%3A%2F%2Flocalhost:443%2Fcb"
    https://iam.example.com/openam/oauth2/access_token

7. OpenID ProviderはID TokenとAccess TokenをRelying Partyに返却する

レスポンスは以下のようなJSONが返ってきます。
ID Tokenがきちんと返却されていますね。

{  
   "access_token":"601a0158-1aac-45d2-95d5-579068502d5a",
   "scope":"openid profile",
   "id_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdF9oYXNoIjoiZXpLXzBDM3BFSTYxUnkwMmJQMnNBdyIsInN1YiI6ImpvaG5kIiwiYXVkaXRUcmFja2luZ0lkIjoiZDcxNDQ0ODEtNmY3Ny00OTM5LTk0ZDYtYzViZjEzYzZiMmRkLTM1MjEiLCJpc3MiOiJodHRwczovL2lhbS5leGFtcGxlLmNvbTo0NDMvb3BlbmFtL29hdXRoMiIsInRva2VuTmFtZSI6ImlkX3Rva2VuIiwiYXVkIjoicmVseWluZ3BhcnR5IiwiY19oYXNoIjoiXzFBVTZ4ZFI1RUVFTVlwb0JKXzA0USIsIm9yZy5mb3JnZXJvY2sub3BlbmlkY29ubmVjdC5vcHMiOiJhYTVhZWVkZS1hZDk0LTRiNDMtYjBhYi0xZjQ1YjE2N2Q2MTYiLCJhenAiOiJyZWx5aW5ncGFydHkiLCJhdXRoX3RpbWUiOjE0ODEyOTIwOTgsInJlYWxtIjoiLyIsImV4cCI6MTQ4MTI5NzE2NiwidG9rZW5UeXBlIjoiSldUVG9rZW4iLCJpYXQiOjE0ODEyOTM1NjZ9.ZleIKGdHeUhx1ZYkekK5dnHm77h_BugcrxeOnsyiXD0",
   "token_type":"Bearer",
   "expires_in":3599
}

decodeすると以下のような感じです。
なんだか、OpenAM独自のパラメータがセットされていますね~。まぁいっか。

{
  "at_hash": "ezK_0C3pEI61Ry02bP2sAw",
  "sub": "johnd",
  "auditTrackingId": "d7144481-6f77-4939-94d6-c5bf13c6b2dd-3521",
  "iss": "https://iam.example.com:443/openam/oauth2",
  "tokenName": "id_token",
  "aud": "relyingparty",
  "c_hash": "_1AU6xdR5EEEMYpoBJ_04Q",
  "org.forgerock.openidconnect.ops": "aa5aeede-ad94-4b43-b0ab-1f45b167d616",
  "azp": "relyingparty",
  "auth_time": 1481292098,
  "realm": "/",
  "exp": 1481297166,
  "tokenType": "JWTToken",
  "iat": 1481293566
}

8. Relying PartyはID Tokenの検証をする

ID Tokenを受け取ったRelying Partyは本当にID Tokenが正しいかどうかを検証する必要があります(MUST)
詳しくはOpenID Connect CoreのID Token Validationを参照ください。

ざっくり検証ってどんなことするの?をピックアップすると、

  • 公開鍵を使って署名検証する
  • issがRelying Partyが期待していたOpenID Providerであるかどうか?
  • audがRelying Party(自分)かどうか?
  • iatが昔すぎないか?
  • expがまだ切れていないか?

などなど。

こんだけの情報がRelying Partyに連携できると、その情報を信頼してほな、うちでも認証できたことにしたる!ってできそうですね。(シングルサインオン)

今日のまとめ

  • OpenAMにRelying Partyの登録をすると、すぐにID Tokenを要求するフローを開始できる
  • ID TokenはJSON Web Tokenとよばれる形式で表現される
  • Authorization Code Flowはフロントで紐づけの情報(Authorization Code)を持ちまわって、バックチャネルでID連携する

明日こそRelying Partyのセットアップをする。

ばい!

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6