- OpenID Connect Client Initiated Backchannel Authentication Flow - Core 1.0 draft-02
- OpenID Connect Discovery 1.0 incorporating errata set 1
- OpenID Connect Dynamic Client Registration 1.0 incorporating errata set 1
- OpenID Connect Extended Authentication Profile (EAP) ACR Values 1.0 - draft 00
ユーザーが利用するAuthentication Deviceとして、PC/AndroidのChromeあたりで動くWebアプリをADとして利用します。
URL : https://oidc-ciba-demo.gigalixirapp.com/
ただの OIDC + CIBA + DEMO だと思った?
OIDC
CIBA
AD
DEMO
ADも隠れていました。
続けます。
Firebase Cloud Messaging を利用します。サポートされていない環境では動きません。サポートされていても動かない場合があります...。
ログインにはGoogleアカウントを利用します。 Firebase Authentication 使おうかとも思いましたが、普通に Google の OIDC を利用しています。
このデモではユーザー識別子とメールアドレスを利用します。
次にプッシュ通知の設定を行います。Firebaseはここでしか使っていません。
ここでプッシュ通知許可のお願いです。 世の中のニュースサイトが突然プッシュ通知を要求してしまうせいで拒否するのが体に染み付いていらっしゃる方も多いでしょう。 今回だけはどうかお願いいたします。
これで最低限の準備ができました。
OpenID Connect と FIDO は補完関係です。
ということで、以下の手順でAuthenticatorを設定し、下記のリクエストにて acr_values
という値が指定されるとWebAuthnによる確認を求められるようにしました。
WebAuthnの登録フローに入ります。
準備ができました。
このデモをGoogleのOIDCのRPと捉えると、OIDC RP = FIDO RP のパターンとしても捉えられますね。 一方で、CIBAのプロトコルのOPと捉えると OIDC OP = FIDO RP というパターンとも捉えられます。
ということで両方の意味での組み合わせの例として利用できそうです。
話を戻して、CIBAの認証フロー、やっていきましょう。
デモなので、ログアウトしたらメアド、WebAuthnの公開鍵はDBから削除され、プッシュ通知も来なくなります。
Dynamic Client Registrationに対応しています。
(openid-configuration
からのメタデータの提供は後で対応します)
$ # curl -X GET "https://oidc-ciba-demo.gigalixirapp.com/.well-known/openid-configuration"
# TODO: Configuration Response
# "registration_endpoint":"https://oidc-ciba-demo.gigalixirapp.com/api/client"
(メタデータを参照できたつもりで)上記のClient登録用エンドポイントに name
を指定すると Client Credentials
を取得できます。
$ curl -X POST "https://oidc-ciba-demo.gigalixirapp.com/api/client" \
-H 'Content-Type: application/json' \
-d '{"name":"SECURE DEMO CLIENT"}'
{"client_id":"01DCXP0ZMT(masked)","client_secret":"01DCXP0ZPP(masked)","name":"SECURE DEMO CLIENT"}
Client
が何らかの方法で取得した login_hint
を使って認証要求を送ります。
$ curl -X POST "https://oidc-ciba-demo.gigalixirapp.com/api/backchannel" \
-u "01DCXP0ZMT(masked):01DCXP0ZPP(masked)" \
-H 'Content-Type: application/json' \
-d '{"scope":"openid", "login_hint":"(メールアドレス)"}'
{"auth_req_id":"01DD4M18NJKDA17GQ1NP53VWQS","expires_in":3600}
この時、うまくいっていれば Chrome の通知が送られるはずです。
こんな通知が来て、同意画面が出て来ます。
許可するとユーザーの処理はおしまいです。
ここまで終わったら、ClientはToken Endpoint に各種トークンを要求します。 実際は定期的に問い合わせ(ポーリング)をして結果が来たら処理するという感じです。 (とここまで書いてて、許可しないフローを実装するのを忘れてました。)
$ curl -X POST "https://oidc-ciba-demo.gigalixirapp.com/api/token" \
-u "01DCXP0ZMT(masked):01DCXP0ZPP(masked)" \
-H 'Content-Type: application/json' \
-d '{"grant_type":"urn:openid:params:grant-type:ciba", "auth_req_id":"01DD4M18NJKDA17GQ1NP53VWQS"}'
{
"access_token":"THISISDUMMYACCESSTOKEN",
"expires_in":3600,
"id_token":"(ID Token)",
"refresh_token":"THISISDUMMYREFRESHTOKEN",
"token_type":"Bearer"
}
ID Tokenをデコードして見ると中身はこんな感じです。
// Header
{
"alg": "RS256",
"kid": "rs256_201906",
"typ": "JWT"
}
// Payload
{
"acr": "",
"at_hash": "nT5n6bpBrdiOZaBp6IqwkQ",
"aud": "01DCXP0ZMT(masked)",
"email": "(メールアドレス)",
"exp": 1560305756,
"iat": 1560302156,
"iss": "https://oidc-ciba-demo.gigalixirapp.com",
"sub": "(ユーザーID)",
"urn:openid:params:jwt:claim:auth_req_id": "01DD4M18NJKDA17GQ1NP53VWQS",
"urn:openid:params:jwt:claim:rt_hash": "EsQ8Syr4u5hXmKxJ9mmiHQ"
}
acr
の値は空です。
オプションパラメータとして、
binding_message
: Client側とADで共に表示してトランザクションなどを識別できるようにする文字列acr_values
: 認証コンテキストの指定
をサポートしてみました。
$ curl -X POST "https://oidc-ciba-demo.gigalixirapp.com/api/backchannel" \
-u "01DCXP0ZMT(masked):01DCXP0ZPP(masked)" \
-H 'Content-Type: application/json' \
-d '{"scope":"openid", "binding_message":"W4SCT", "acr_values":"phrh", "login_hint":"[email protected]"}'
{"auth_req_id":"01DD7JY5JJ47T2Q51K7FPC9CZF","expires_in":3600}
通知を受け取ったら、最初にWebAuthnの確認が求められます。
同意画面には、binding_message
で指定された値が表示されます。
違いはこんなところです。
$ curl -X POST "https://oidc-ciba-demo.gigalixirapp.com/api/token" \
-u "01DCXP0ZMT(masked):01DCXP0ZPP(masked)" \
-H 'Content-Type: application/json' \
-d '{"grant_type":"urn:openid:params:grant-type:ciba", "auth_req_id":"01DD7JY5JJ47T2Q51K7FPC9CZF"}'
{
"access_token":"THISISDUMMYACCESSTOKEN",
"expires_in":3600,
"id_token":"(ID Tokenの値)",
"refresh_token":"THISISDUMMYREFRESHTOKEN",
"token_type":"Bearer"
}
ID Tokenの中身を見ると、acr
の値が phrh
になっています。
// Header
{
"alg": "RS256",
"kid": "rs256_201906",
"typ": "JWT"
}
// Payload
{
"acr": "phrh",
"at_hash": "nT5n6bpBrdiOZaBp6IqwkQ",
"aud": "01DCXP0ZMT(masked)",
"email": "(メールアドレス)",
"exp": 1560405260,
"iat": 1560401660,
"iss": "https://oidc-ciba-demo.gigalixirapp.com",
"sub": "(ユーザーID)",
"urn:openid:params:jwt:claim:auth_req_id": "01DD7JY5JJ47T2Q51K7FPC9CZF",
"urn:openid:params:jwt:claim:rt_hash": "EsQ8Syr4u5hXmKxJ9mmiHQ"
}
Client側からの認証コンテキスト指定を利用すれば WebAuthn/FIDO と組み合わせられるよーという感じが伝わると嬉しいです。
以上です。