OIDC CIBA の拡張として OAuth 2.0 Device AuthZ Grant を使う仕様を考えてみた

おはようございます。ritou です。

なんか急に寒くなりましたね。私は先週末、風邪をひきました。

何の話?

OpenID Connect の CIBA と OAuth 2.0 Device AuthZ Grant は手元の端末を用いてユーザーがID連携やリソースアクセスを許可することから似ている面があるものの、プロトコルとしては結構な違いがあります。

ritou.hatenablog.com

tools.ietf.org

あまり深く考えずにこれらの標準化仕様を弄ってどうこうするのはお勧めできないわけですが、今回は特定の条件下においてこの2つを組み合わせられるのでは?というのを考えてみました。

それぞれの特徴

リクエストやらエンドポイントやらのプロトコルの詳細は一旦おいておいて、ざっくり

  • CIBA
    • RPがOP上のユーザーに紐づく情報を知っている必要がある
    • 事前にユーザーと Authentication Device (AD) の紐付けが存在し、AD上でID連携を許可する。紐付け方については仕様範囲外
  • Device AuthZ Grant
    • Clientは事前にユーザーを知らなくても良い
    • ClientがURL+User Code や QRコード を表示して、ユーザーが自らが利用する端末のブラウザを利用してリソースアクセスを許可する。

のように整理できます。

こう書くと結構な違いがありますが、一方で綺麗に仕様が分かれているようにも感じられるのではないでしょうか。

組み合わせの可能性

FAPIとかのガチなユースケースでは変なこと考えない方が良いと思いますが、C向けの比較的ライトウェイトなサービスとかでは既存の仕様を弄り回すのも頭の体操ぐらいにはなりそうです。

自分でPWAを用いたCIBAのデモを作ってみたりして気付いたんですが、CIBAで前提となっているもののその部分自体は未定義である「ADとユーザーの紐付け」や「RPとの最初のID連携」の部分を簡単にやれるといいなーという思いが出てきました。

そんな中、この2つの仕様が交わるユースケースを考えてみたところ、例えば PWA なWebアプリやモバイルアプリなどで

  • OIDC CIBA のように AD が Push を受けられる
  • OAuth 2.0 Device AuthZ Grant のように URL や QRコードで起動できる

という2つの要件を満たせるならば 「OIDC CIBA で RP とユーザーの紐付けがない状態の時だけ Device AuthZ Grant っぽく」みたいなのができて上記の課題を解決できるのでは?と思ってきました。 そこで、OIDC CIBA の拡張として OAuth 2.0 Device AuthZ Grant を使う仕様 を考えてみたわけです。

OIDC CIBA Dynamic AD Enrollment Extension(仮)

ここからが本番です。いきなりまとめると

  • CIBA の Backchannel Authentication Endpoint への Authentication Request で指定した *hint が空だったり OP 側で紐付けがない/切れた場合に OAuth 2.0 Device AuthZ Grant の Device Authorization Response を返す
  • それにより、動的なAD紐付けが可能になる

みたいな感じです。わかりますか?わかりませんよね。 もうちょっと詳しく説明してみます。

動的なAD紐付け(拡張)

OP上でユーザーとADの紐付けが行われていないもしくはリセットされたような状態からの動的な紐付けを行うケースを想定します。 あとはADが複数存在する場合にRPに対して利用するADを選択するようなケースとかでも使えそうです。

f:id:ritou:20201019005740j:plain

図ではCIBAのPoll modeを想定していますが他のmodeでもあまり変わりません。

1. Authentication Request

RPはOPに対して Authentication Request を送ります。

  POST /bc-authorize HTTP/1.1
   Host: server.example.com
   Content-Type: application/x-www-form-urlencoded

   scope=openid%20email%20example-scope&
   client_notification_token=8d67dc78-7faa-4d41-aabd-67707b374255&
   binding_message=W4SCT&
   login_hint_token=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJ
   zdWJfaWQiOnsic3ViamVjdF90eXBlIjoicGhvbmUiLCJwaG9uZSI6IisxMzMwMjg
   xODAwNCJ9fQ.Kk8jcUbHjJAQkRSHyDuFQr3NMEOSJEZc85VfER74tX6J9CuUllr8
   9WKUHUR7MA0-mWlptMRRhdgW1ZDt7g1uwQ&
   client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3A
   client-assertion-type%3Ajwt-bearer&
   client_assertion=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJ
   pc3MiOiJzNkJoZFJrcXQzIiwic3ViIjoiczZCaGRSa3F0MyIsImF1ZCI6Imh0dHB
   zOi8vc2VydmVyLmV4YW1wbGUuY29tIiwianRpIjoiYmRjLVhzX3NmLTNZTW80RlN
   6SUoyUSIsImlhdCI6MTUzNzgxOTQ4NiwiZXhwIjoxNTM3ODE5Nzc3fQ.Ybr8mg_3
   E2OptOSsA8rnelYO_y1L-yFaF_j1iemM3ntB61_GN3APe5cl_-5a6cvGlP154XAK
   7fL-GaZSdnd9kg

OIDC CIBAで定義されていいるそのまま載せましたが、今回の拡張を利用するための追加のパラメータが必要になるかもしれません。

CIBAでは*_hintパラメータで指定されたユーザーを特定し、存在しない場合やユーザーが管理しているADと通信できないなどの場合はエラーとして扱いますが、今回の案ではエラーではなく「OAuth 2.0 Device AuthZ Grant」風のレスポンスを返すものとします。

      HTTP/1.1 200 OK
      Content-Type: application/json
      Cache-Control: no-store

      {
        # CIBAのauth_req_id は OAuth 2.0 Device AuthZ Grant の device code 相当
        "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",

        # ここから下が OAuth 2.0 Device AuthZ Grant のレスポンス
        "user_code": "WDJB-MJHT",
        "verification_uri": "https://example.com/device",
        "verification_uri_complete":
            "https://example.com/device?user_code=WDJB-MJHT",

        # 有効期限とインターバルの間隔
        "expires_in": 1800,
        "interval": 5
      }

2. User Interaction

RPは受け取ったverification_uri + user_code や verification_uri_complete をユーザーに提示し、ユーザーはそこにアクセスします。 CIBAのユースケースとしてPOS端末での利用がありましたが、例えばポイントカードを持っていたらスーパーのATMやサービスカウンターにある端末などで最初にこの辺りの設定をする、とかでも良いでしょう。

3. AD Enrollment & Consent

ここで

  • ADとしての登録 (AD Enrollment)
  • RPにユーザー情報を提供することへの同意 (Consent)

などが行われます。

4. Polling Request / Response(NG)

3 が完了するまでは、RPからのPolling Requestに対してOPはエラーを返します。

5. Polling Request / Response(OK)

3 が完了すると、RPからのPolling Requestに対してOPは成功レスポンスを返します。

通常のCIBAフロー

ユーザーとADが紐付けられていて、RPからのAuthentication Requestでユーザーを特定できた場合は通常のCIBAのフローになります。

f:id:ritou:20201019005237j:plain

GNAP, 3D Secure 2.0

以前、XYZとして紹介したドラフト仕様を覚えているでしょうか?

ritou.hatenablog.com

現在はGrant Negotiation and Authorization Protocol(GNAP)として仕様策定が進められています。

tools.ietf.org

これ、最初の頃から

  • バックチャンネルでリソースアクセスを要求
  • 必要であればユーザーインタラクションが発生

という流れになっていました。

OAuth 2.0に求められるユースケース毎の要件を整理し、OAuth 1.0の時のようなバックチャンネルのリクエスト中心のプロトコルとして書き直した感じです。

なので今回紹介したやつとほとんど一緒です。

さらに、XYZの紹介記事でちょっと触れた様に 3D Secure 2.0 のフローにも似ています。

3dsecure2.com

この辺りは細かいパラメータなどは異なるにせよ、大まかな仕組みとしては似ているところに落ち着いていきそうな気がします。

まとめ

  • OIDC CIBA と OAuth 2.0 Device AuthZ Grant の組み合わせを考えてみた
  • OIDC CIBA の仕様外である「ADの登録」のところに OAuth 2.0 Device AuthZ Grant の「動的なリソースアクセス許可」 を適用することで「動的なAD登録」みたいなのが実現できそう
  • XYZ(GNAP)とかと似てる

せっかく仕組み考えたので、次回はこれを使った 「OIDC CIBA as a MFA」 みたいな話を書こうかと思っています。 ではまた!

f:id:ritou:20201017234812p:plain