2021年1月2日土曜日

モニターの入力切替が超絶使いにくいので物理的に解決した話

1 背景

自宅でPHILIPS 328P6VUBREB/11っていうモニターを使ってます。31.5inch 4Kとしては安いし結構重宝しているんですけど、まあとりあえず様々なレビュー見るとですね、


USB-C ドック搭載液晶モニター 328P6VUBREB/11 | Philips

本体操作用のタッチスイッチは、反応する部分の間隔が狭いと感じます。中々思ったように操作できないです。

本体下部のボタンがタッチ式のため、指をずらして押したいボタンを探すことができず、目視で押すボタンを見つける必要がある。暗いところでは扱いにくいばかりではなく、いちど画面から目を離す必要がありストレスとなる。頻繁に使う接続の切り替えだけでも素早くできるとありがたい。また、ボタンから指を離すときにも、タッチがあったと判定されることがよくある。

メニュー操作のタッチセンサーボタンは、慣れても使い勝手が悪いです、「入力切換」だけでも是非普通のボタンスイッチを希望します。

操作ボタン(物理ボタンか、リモコン希望)過敏すぎる

操作スイッチがタッチスイッチなので使いにくいです


Amazon | PHILIPS モニター ディスプレイ 328P6VUBREB/11 (31.5インチ/「Display HDR 600」認証/HDMI/USB Type-C/4K/5年保証) | Philips(フィリップス) | ディスプレイ 通販

操作性が悪すぎて入力切り替えやHDRの切り替えにも苦痛レベル この操作性で満足できるのは操作ボタン触らない人だけだろう あと右下の前面と下面がタッチセンサーになってるからマウスのケーブルが触れただけで反応するからたちが悪い

ディスプレー自体の各種設定が画面枠下部のタッチ式になっており、これがとても使いにくい。

設定ボタンは既出の通り、操作しずらいです。

皆さん言ってますが画面のスイッチが反応良すぎてとても使いにくい。 ボタンの境がわかりやすければもう少しマシなんでしょうけど、どこ押して反応してるのかわからない。

・操作性が悪い。タッチなのでどこを押せばいいのかわかりづらい。反応が遅いのかタッチに失敗したのかわかりづらい。ただ、操作することはほとんどないのでそこまで気になりません。

・メニュー操作、タッチパネルでも多分問題ないだろうと買ったけど、凄くやりずらい。

ほかのレビューでもあったと思いますが、物理ボタンがないことにより想像以上に画面右下での操作がしづらかったです。 特に私の使用環境では複数の入力をモニタで切り替えて運用しており、また夜は暗い中で操作することもあるため、同じような運用をされる方はリモコンがついている物を選んだ方がよいかもしれません。

タッチセンサーの問題もあるが、入力信号が出ていないと判断するのが早すぎるようで入力切替が一度で決まることが殆どない。HDMIとUSBーCの切り替え操作をあの忌まわしいタッチセンサー操作で数回行ってやっと切り替わるのでストレス溜まります。


とまあこんな感じで、とにかくタッチ式のスイッチが使いにくい。またレビューであまり触れられてないですが、普段は過敏なくせにたまに反応しなかったり、逆に過敏すぎて勝手に連打したことになったりして、入力切替の時はよく目的の入力を誤って指定してしまうことがあるのだけど、切り替わるのに3秒強かかるのはしょうがないとしても、切り替わった後に謎の5秒強の無敵時間(操作受付拒否時間)があるので1回ミスるだけで計10秒くらい待たされるのが一番ストレス。入力受付復活までの間はイライラしながらスイッチ連打してるし、高橋名人なら160発くらい撃ち込みしてる。

噂のあいつ

ってことで入力切替なんとかしなきゃってなりました。

2 入力切替方法案

2.1 HDMI CEC

昔、子供がすぐテレビの真ん前にかじりついて見はじめるので目に悪そうということでRaspberry Piと超音波距離センサを使って1m以内に近寄ったらテレビの電源を切って、離れたらまた電源を入れるというのを作ったことがあります。そのときはHDMI CECを使ってテレビの電源の制御を行ったので今回もそれでいけるかなと。一番最初に試そうとしたのがこれでだいぶ前なので詳細を覚えていないけど、そもそもPC用モニターでは動かなかったか、任意の入力切替はできなかったかで早々に没になった気がする。

ちなみに近づいたらテレビの電源を切るやつは、子供は結構面白がってわざと近づいたり遠ざかったりして遊んでいたので本来の目的外でそれなりの役目は果たしたけど、邪魔だったので既にご退場いただきました。寝室で普段使わないテレビとはいえ↓こんな感じだったので… センサ間はもう少し離した方がカバー範囲が広くていいけどまとまってた方が持ち運びしやすかったので密集してる。

近寄ったら消すぞ!

2.2 リレータッチボード

人間がやるから誤操作する。ならば人間を排除操作を機械にやらせようということで↓のような製品を使うことも考えました。

リレータッチボード(ドライバ有り) - スイッチサイエンス

これがこのモニタのタッチスイッチでうまくいくかはわからないけど、そもそも現在の入力と切り替え先の入力によってスイッチを押す回数が変わったりと処理が状態に依存するけど状態を取得するのは困難なのでせいぜいタッチスイッチの操作を目視で確認しながら指で直接の代わりにリレー経由でやるくらいにしかならなそうなので没 (少し長く触れてしまって連打状態になっちゃうとかを防止できるくらいはできそうという期待はあるけど)。

2.3 DDC/CI

仕方ないのでモニター関連で色々調べてみるとVESA標準のDisplay Data Channel Command Interface (DDC/CI) というのでホストからモニタにコマンドが送れることが分かりました。また登録は必要だけどVESAのサイトからドキュメントがダウンロードできるのもいいですね ( https://vesa.org/vesa-standards/ )。そしてそのコマンドについて規定している別のVESA標準であるMonitor Control Command Set (MCCS)のドキュメントを見ると Input Select というそのもののコマンドが定義されていました(p.81, Table 8-13: Miscellaneous Functions VCP Codes, Code 60h)。

また自分でプロトコルから実装しなくてもddcutil っていうCLIで使えるツールがaptでインストールできるし、これは余裕で勝てる、…ってこの時はまだ思ってました。

3 立ちはだかるRaspberry Pi Zero / 4の問題

早速 ddcutil を実行してみると…

$ ddcutil detect
No displays found

うん、これが「スンッ」ってやつか…

どうもddcutilのissue 「ddcutil not working on Raspberry Pi 4 ・ Issue #97 ・ rockowitz/ddcutil」 を見てみると、Raspberry Pi 4側の既知の問題(ユーザ空間からDDC/CIで使われている/dev/i2c-2にアクセスできない)で動かないらしい。 今回はまずはRaspberry Pi Zeroで動かしたけどZeroでも4でも同じ結果になったので多分同じ現象っぽい。

Rasberry Piの方でもissue 「RPi4 I2C HDMI interface (/dev/i2c-2) not working from userspace ・ Issue #3152 ・ raspberrypi/linux」 が立っていて、そのissueにHDMIケーブルを改造すれば行けるよっていう コメント がありました。DDCで使っているI2C関連のラインだけをHDMIケーブルから分離してRaspberry Piの汎用のI2Cのピンに接続して制御しようという力こそパワー感あふれるソリューションだった。しかし面倒そうだし手は出さずにしばらくこのissueをウォッチしてたけど結局一向にRaspberry Pi側の改修がされる様子がなかったのでしばらく経ってからようやくケーブル改造することにした (現在はその後の同issueの様子を見ると改修が大体完了したっぽい)。

3.1 HDMIケーブル改造

まずはHDMIケーブルの調達。Raspberry Pi 4がMini HDMI、Raspberry Pi ZeroがMicro HDMIとコネクタが異なる点と、コネクタが小さいと加工が大変なことから通常のHDMIのを購入。安さと失敗したときの再調達のしやすさの観点から↓のAmazonベーシックのにした。

Amazon | Amazonベーシック ハイスピードHDMIケーブル - 3.0m (タイプAオス - タイプAオス) | Amazonベーシック(AmazonBasics) | HDMIケーブル

このHDMIケーブルが思った以上に頑丈(下記の完成版ではいじってないけど特にコネクタ部分)&精緻で調査&加工にはだいぶ苦労しました。 テスターでちまちま調べたところ、このケーブルの場合は下記のような割当でした。内部の配線の色には決まりがないらしいのであくまでもこのケーブルの場合はこうだったという程度の参考情報です。太字の部分がDDCに関わる部分で本来のHDMIケーブルから分離してRaspberry PiのI2C関連のピンに接続する線です。

Pin # Signal Amazon cable color
1 TMDS Data2+ メタリックゴールド内?
2 TMDS Data2 Shield メタリックゴールド内?
3 TMDS Data2- メタリックゴールド内?
4 TMDS Data1+ メタリックブルー内?
5 TMDS Data1 Shield メタリックブルー内?
6 TMDS Data1- メタリックブルー内?
7 TMDS Data0+ メタリックシルバー内?
8 TMDS Data0 Shield メタリックシルバー内?
9 TMDS Data0- メタリックシルバー内?
10 TMDS Clock+ メタリックグリーン内?
11 TMDS Clock Shield メタリックグリーン内?
12 TMDS Clock- メタリックグリーン内?
13 CEC
14 - Reserved (HDMI 1.0-1.3a)
- Utility/HEAC+ (HDMI 1.4+, optional,HDMI Ethernet Channel and Audio Return Channel)
メタリックピンク内の白
15 SCL (I2C serial clock for DDC)
16 SDA (I2C serial data for DDC)
17 Ground (for DDC, CEC, ARC, and HEC) メタリックピンク内のベアケーブル
18 +5 V (min. 0.055 A)[3]
19 - Hot Plug Detect (all versions)
- HEAC- (HDMI 1.4+, optional, HDMI Ethernet Channel and Audio Return Channel)
メタリックピンク内の青

PinとSignalの対応は↓から引用。

HDMI - Wikipedia

実際の作業の様子は下記のような感じ。

ひん剥いて
ぶった切って
電圧変換して
接続する

よしこれで完璧! やってみると、

$ i2cdetect -l
i2c-1   i2c             bcm2835 (i2c@7e804000)                  I2C adapter

$ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- 37 -- -- 3a -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- 49 4a -- -- -- -- --
50: 50 -- -- -- 54 -- -- -- -- 59 -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

$ ddcutil detect
Display 1
   I2C bus:             /dev/i2c-1
   EDID synopsis:
      Mfg id:           PHL
      Model:            PHL 328P6VU
      Serial number:    Unspecified
      Manufacture year: 2019
      EDID version:     1.3
   VCP version:         3.0

これは行ける!

$ ddcutil getvcp 0x60
VCP code 0x60 (Input Source                  ): Unsupported feature code (DDC NULL Message)
$ ddcutil setvcp 0x60 0x12
Invalid hex value

なんでよ…

4 さらば ddcutil、ようこそddcci

Raspberry Pi 4/Zeroの問題なのか、モニターの問題なのか、ddcutilの問題なのかよくわからなかったので、切り分けのために他の実装がないか探してみたら、 ddcci というのを見つけた。

$ ddcci-tool -r 0x60 /dev/i2c-1
ddcci-tool version 0.03

Using ddc/ci : 0x37@/dev/i2c-1

Reading 0x60(Input Source Select)
Control 0x60: +/15/8206 [Input Source Select]

こいつ…動くぞ! ちゃんとDisplayPort-1を表す 15 (0x0f) が得られている。

$ ddcci-tool -r 0x60 -w 0x12 /dev/i2c-1
ddcci-tool version 0.03

Using ddc/ci : 0x37@/dev/i2c-1

Writing 0x60(Input Source Select), 0x12(18)
Control 0x60: +/18/8206 [Input Source Select]

$ ddcci-tool -r 0x60 /dev/i2c-1
ddcci-tool version 0.03

Using ddc/ci : 0x37@/dev/i2c-1

Reading 0x60(Input Source Select)
Control 0x60: +/18/8206 [Input Source Select]

ちゃんとHDMI-2を表す 18 (0x12) に画面も切り替わりました。 よし、これでddcutilの問題っぽいことが分かったので調査しよう、 …と思ったけどddcciはシンプルでわかりやすいし、今回の目的の範囲では機能も十分なのでこのままでいい気がしました。 ということであとは物理スイッチをつけるだけ。

5 物理スイッチ

今回のモニターは4つの入力ソースを受け付けるので↓の薄膜パネルスイッチを使うことにしました。

★特売品★薄膜パネルスイッチ - aitendo

薄膜パネルスイッチ

マニュアルとかデータシートとかは特に見当たらなかったけどどうも配線がスイッチの順番とだいぶ違うように見えたので適当にテスターでちまちま配線を調べる。調べた結果は下記の通り。

  • aitendoの商品写真とは違ってパネルに数字は書いてない。 でもちょうど数字の向きとは上下逆に使おうと思うのでこれはこれでよし。
  • ここでは前述のとおり上下逆に使うので、ケーブルを下側、パネルを表側にする。
    • スイッチ部を左から、sw1,sw2,sw3,sw4とする (下記のfritzingの配線図上の数字とは逆順)

    • このときケーブル部の配線は左から、sw2, sw1, sw4, sw3, 共通(GND)となっていた

    • ピッチはRaspberry Piのピンと同一なのでそのままコネクタ毎挿せるようにGPIOが4つ連続になっているところを使うと、ピン番号やGPIO番号との対応表は下記のような感じ

      line_no role pin_no gpio_no
      1 sw2 31 6
      2 sw1 33 13
      3 sw4 35 19
      4 sw3 37 26
      5 gnd 39 -

後から気づいたけど実はこのスイッチの裏面は両面テープになってて剥離紙を剥がしたら配線が露わになりました。そして配線とスイッチの謎の順番になるほどって顔になりました。

ご納得

全体の配線図は以下の通り。 図上でHDMIケーブルの線が繋がれていないピンについてはRaspberry Pi ZeroのMini HDMIコネクタにそのまま接続。

配線図

あとはこれに従って簡単なプログラムを書いて完成。 ddcci版のプログラムはこれ

完成!快適! モニターのタッチパネルでの操作の時と違って切り替えた後の5秒強の無敵時間もないので次々に切り替えられるのがいい。

6 おかえり ddcutil

ということで目的は達成できたのでしばらくこの構成で使っていましたが、ddcutilが動かなかった件が気になったのでちょっと調査をしてみた。 詳細はissue 「getvcp/setvcp 0x60 failed with Philips 328P6VUBREB/11 ・ Issue #162 ・ rockowitz/ddcutil」 で報告したのでそっちを参照してもらうとして、結論から言うとこのPhilipsのモニターが本来とは異なるVCP(MCCS)のバージョンをホスト側に回答してくるため、バージョンに応じて適切に処理を行おうとしていたddcutilがうまく動かないという感じでした。報告後、あっという間に作者の人が対応方法を実装してくれたので無事動くようになった。

対応もしてもらったし、ddcutilは下記のような利点があるのでプログラムをddcutil向けに修正した。

  • 現在もアクティブに開発中
  • 機能も充実
  • ドキュメントも充実
  • ライセンスも明記
  • Raspberry Piのaptリポジトリからインストール可 (今回は最新版が必要なのでgithubのをコンパイルしているけど)

ddcutil版に修正したプログラムはこれ

7 設置

モニターのベゼルにつけてもいい気がするけどより手元に近いデスクにパネルスイッチを設置して完了。超快適。

最終形
机の下

2020年中にまとめようと思ってたけど気づいたら年明けてたし、休みもあっという間に終わりそう。

2015年11月3日火曜日

いまさらながらのFIDO U2F

よーし、今更ながらFIDO U2Fについて書いちゃうぞー
そろそろFIDO 2.0の仕様も公開されるんじゃないかっていうこのご時世にな!
思い立って書き始めたのに大した理由はないけど、先日買ったスマホが初めてのUAF対応のやつだったし、じゃあついでにU2Fも、くらいの勢いで。

そういえばブログ書くの2年半ぶりくらいで、ちょうどその2年半前の投稿でFIDOのことを触れていました。そのときは仕様もまだ公開前で全く盛り上がってもいなかったなあと思いつつも、今も盛り上がってるのは一部だけだったりするようなしないような。

とは言え、11/10(火)のOpenID Summit Tokyo 2015ではFIDO 2.0のセッションがあったり、11/20(金)には第2回 FIDOアライアンス東京セミナーがあったりと、盛り上がってる感はありますね。仕事がどうなるか見えないところですが、意地でも両方ともなんとかして参加したいところです。前者は思わず個人スポンサーにもなってしまったし。

FIDO概要

FIDOとはFast IDentity Onlineの略でFIDO Allianceという団体で仕様策定されており、UAFとU2Fという2つの仕様を現在公開しています。現在公開されているこれらの仕様は総称してFIDO 1.0とか呼ばれたりします。

これらの仕様のうちこの記事で触れるU2FとはUniversal 2nd Factorの略で、その名の通り二要素認証における第二要素を標準化しようというものです。そう第一要素は典型的なユーザ識別子とパスワードによる認証を使うというのが前提です。ただプロトコル上に明に第一要素だとかパスワードが現れてくるわけではないです。しかし実装上は第一要素としてパスワードはともかくユーザ識別子は必要となるかと思います(後述)。

もう一つの仕様であるUAF (Universal Authntication Framework)はパスワードレスを目指しているのでそこが大きな違いです。そしてFIDOはどうしてもパスワードレスの文脈で語られることが多いので、UAFの方が注目されちゃいますね。普及度ではU2Fの方な気がしますけど、どっちもそれほど普及しているわけでもないですねw

まあ普及に関してはそろそろ仕様公開されるんじゃないかというFIDO 2.0に期待です。SAMLもOpenIDもOAuthも広く普及したのは2.0ですし。UAFとU2Fに別れてしまったFIDO 1.0とは異なり、FIDO 2.0ではこういう区別はなくなるらしいのもいいですね。1.0からまとめとけよという気がしますが標準化には色々あるんでしょうね。そういう視点で見るとUAFを推している会社とU2Fを推している会社は綺麗に別れているのが各仕様のドキュメント群の著者からも見て取れます。前者がNok Nok LabsとPayPal、後者がYubicoとGoogleのようですね。そしてFIDO 2.0はMicrosoftの存在が大きくなるんだと思われます。

FIDO U2F仕様

シーケンス

じゃあ早速U2F仕様をシーケンス面から見てみましょう。UAFと違ってU2Fは全般的にそっけない記述なのでシーケンスすら仕様には載ってませんが、大体次の図のようになるでしょう。
FIDO U2F 基本シーケンス例
特に難しいところはないですね。普通の二要素認証とか二段階認証と呼ばれるやつの典型的なシーケンスです。

なおU2F TokenはU2F Deviceと言われたりもします。またこれはどっちかというとUAF側の用語の色が濃いですがまれにU2FでもAuthenticatorと呼ばれる場合もあります。UAFとU2F間で用語がまちまちなのはもちろん、U2F内だけでもまちまちです。フィーリングで読んでください。またU2Fのドキュメント一式の中にFIDO Technical Glossaryという用語集がありますが、これは全体的になんとなくUAF寄りの説明になっているように見えます。このドキュメントは更新のタイミングで多少差分が出る場合がありますが、基本的にUAFと同一のものとなっており、なぜUAF寄りに見えるかというと、著者の所属を見ると…もうおわかりですね?

インタフェース概要

前述のシーケンスの要求と応答と書いてあるところをインタフェースに注目してもう少し分解すると次の図のような感じになります。

FIDO U2F インタフェース

(1)から(4)が要求、(5)から(8)が応答です。

Relying PartyはClient-SideとServer-Sideに分けて書いてみました。前者は要はウェブブラウザ上で動作するJavaScriptです。そして(1)と(8)とRelying Party (Server-Side)を点線にしたのはU2Fの仕様上はここは仕様範囲外だからです。なので仕様上、UAFとは違ってU2F Serverというのは登場しないはずです。まあもちろん○○ Serverと言っても、TCPとかでのServerである必要はないので、Relying Party (特に上図でいうClient-Side) をU2F Serverと定義してもおかしくはないですが、U2F仕様上はRelying Partyで統一されています。といいつつ極一部の本編以外のドキュメントにU2F Serverという記述が出てくることもありますが、前述のようにフィーリングで(ry

(2)と(7)のHigh-level JavaScript APIと、(3)と(6)のLow-level MessagePort APIは、FIDO U2F Javascript APIというドキュメントに仕様が記載されています。後者はU2F Clientが必ず実装しないといけないAPIですが、前者はオプションです。なので上図ではRelying PartyがHigh-level JavaScript APIを叩いていますが、直接Low-level MessagePort APIを叩く場合もあります。

(4)と(5)はU2F ClientとU2F Tokenの間のインタフェースになりますが、ここはRaw Messageと呼ばれるデータをデバイス(U2F Token)に合わせて様々なトランスポートに載せてやりとりをすることになります。現在トランスポートとして、USB-HIDBluetoothNFCが定義されています。

図中に「raw」と書かれた箱がいくつか出てきますが、これがRaw Messageです。FIDO U2F Raw Message Formatsというドキュメントに仕様が記載されています。本来はU2F ClientとU2F Tokenの間のためのデータ書式と言えますが、署名とかがある関係上、当然署名検証を行うRelying Partyでも意識する必要が有ります。そしてRaw Messageは計算資源が非常に限られることも多いU2F Tokenに合わせて設計されていると思われるため、みんな大好きバイナリフォーマットです。そんなに複雑ではないですがちょっと面倒ですね。

インタフェース詳細

ではもう少し中身を見てみましょう。
その前にこれまでの図では区別してませんでしたが、実はシーケンスの要求-応答のところは、High-level JavaScript APIやLow-level MessagePort APIの名称でいうと、registerとsignの2種類のタイプがあります。前者がU2F Tokenを登録するときで、後者がそれ以降の認証のときです。

なお、以降で出てくるWebIDLで記述されたinterfaceやdictionary、Raw Messageの構成図はいずれもFIDO U2F仕様のドキュメントからの引用です。

また以降でいくつかJSON形式のデータの具体例が出てきますが、読みやすいように適宜、改行や空白を入れています。

登録時の(2)

で、まずは登録時の(2)のところですが、WebIDLで記述されたインタフェースは下記のようになります。


interface u2f {
    void register (RegisterRequest[] registerRequests, SignRequest[] signRequests, function(RegisterResponse or Error) callback, optional int? opt_timeoutSeconds);
    void sign (SignRequest[] signRequests, function(SignResponse or Error) callback, optional int? opt_timeoutSeconds);
};

登録に関係あるのは、u2f.registerの方で、RegisterRequest[]が登録に関するメインのデータですね。詳細な仕様を載せるとわかりにくくなるのでそれはU2Fのドキュメントを見てもらうとして、その具体例で示すと下記のような感じになります。

[
    {
        "version": "U2F_V2",
        "challenge": "aubUD228hfCtApQ6DDpD9srlidsusUegcWrAcyFIMfU",
        "appId": "https://centos6.toke.jp"
    }
]

appIdの詳細はFIDO AppID and Facet Specificationを見ていただくとして、とりあえずWebアプリケーションの場合はオリジンと思ってください。challengeやversionはまんまですね。

登録時の(3)

こちらもそのまま引用します。Low-level MessagePort APIでは下記のようなRequestというdictionaryが定義されています。dictionaryはJavaScriptに束縛するとオブジェクトになって、dictionaryのメンバがオブジェクトのプロパティになります。このオブジェクトをpostMessaageでウェブブラウザのU2F機能に送りつけることになります。

dictionary Request {
    DOMString          type;
    SignRequest[]      signRequests;
    RegisterRequest[]? registerRequests;
    int?               timeoutSeconds;
    optional int?      requestId;
};

これも具体例を見てみましょう。基本的にu2f.registerで指定されたパラメータを結合して、typeをつけたようなレベルですね。このRequest dictionaryは登録時も認証時も用いるので、typeでそれを区別しています。"u2f_register_request" か "u2f_sign_request" が指定されます。

{
    "type": "u2f_register_request",
    "signRequests": [],
    "registerRequests": [
        {
            "version": "U2F_V2",
            "challenge": "aubUD228hfCtApQ6DDpD9srlidsusUegcWrAcyFIMfU",
            "appId": "https://centos6.toke.jp"
        }
    ],
    "timeoutSeconds": 30,
    "requestId": 1
}

登録時の(4)

ここは前述のようにRaw Messageを様々なトランスポートに載せてU2F Client (Low-level) とU2F Tokenの間で要求-応答の通信を行います。Relying Partyを作る上ではあまり意識する必要はないところですね。ただRaw Message自体は前述のようにRelying Partyでも意識する必要があるので簡単に触れておきます。ここでやり取りされるRaw Registration Request Messageは下記のようなデータになっています。

Raw Registration Request Message

challenge parameterはその名の通りRelying Partyから送られてきたチャレンジに相当しますが、実際には下記のClient Dataと呼ばれるもののSHA-256ハッシュ値になります。


dictionary ClientData {
    DOMString             typ;
    DOMString             challenge;
    DOMString             origin;
    (DOMString or JwkKey) cid_pubkey;
};

Client Dataの具体例は下記のような感じになります。

{
    "typ": "navigator.id.finishEnrollment",
    "challenge": "aubUD228hfCtApQ6DDpD9srlidsusUegcWrAcyFIMfU",
    "origin": "https://centos6.toke.jp",
    "cid_pubkey": ""
}
typは登録時は 'navigator.id.finishEnrollment' になります。cid_pubkeyはTLSチャネルIDをブラウザやサポートしているときのみ使用されます。

登録時の(5)

(4)のあとU2F Token内で鍵ペアが生成されて、下記のRaw Registration Response MessageがU2F Clientに返されます。このRaw MessageがこのあとRelying Partyまで伝えられ、署名検証されることになります。ここで署名検証に用いられる公開鍵は図中のattestation certificateに含まれているもので、user public keyはここでは単に伝送されるだけの単なるデータの一部です。user public keyは登録時ではなく認証時の署名検証に用いられます。key handleはこのuser public keyに対応する鍵ペアを識別する値で、これも認証時に用いられます。

Raw Registration Response Message

このattestation certificateはX.509のDER形式の証明書になります。自分の使っているYubicoのU2F Tokenの場合、Issuer, Validity, Subjectは下記のような感じになっています。

Issuer: CN=Yubico U2F Root CA Serial 457200631
Validity
    Not Before: Aug  1 00:00:00 2014 GMT
    Not After : Sep  4 00:00:00 2050 GMT
Subject: CN=Yubico U2F EE Serial nnnnnnnn

Subjectの方のnnnnnnnnはU2F Tokenのシリアル番号と思われます。user public keyはRelying Party毎に生成されることになるかと思いますが、このattestation certificateはU2F Token製造時に発行されて格納されて、多分その後ずっと共通のものが使用されると思われるので、この情報を使って実質的にRelying Party横断の名寄せに使えちゃいそうですね。具体例を全部載せていないのはそういうことですw

登録時の(6)

ここは登録時の(3)に対する応答ということで、Responseというdictionaryが定義されています。また登録時の応答用にRegisterResponseというdictionaryも定義されています。


dictionary Response {
    DOMString                                   type;
    (Error or RegisterResponse or SignResponse) responseData;
    int?                                        requestId;
};


dictionary RegisterResponse {
    DOMString registrationData;
    DOMString clientData;
};

これも具体例を見てみましょう。
{
    "data": {
        "type": "u2f_register_response",
        "requestId": 1,
        "responseData": {
            "registrationData": "【websafe-base64エンコーディングされたRaw MessageのRegistration Response Message】",
            "version": "U2F_V2",
            "challenge": "aubUD228hfCtApQ6DDpD9srlidsusUegcWrAcyFIMfU",
            "appId": "https://centos6.toke.jp",
            "clientData": "eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZmluaXNoRW5yb2xsbWVudCIsImNoYWxsZW5nZSI6ImF1YlVEMjI4aGZDdEFwUTZERHBEOXNybGlkc3VzVWVnY1dyQWN5RklNZlUiLCJvcmlnaW4iOiJodHRwczovL2NlbnRvczYudG9rZS5qcCIsImNpZF9wdWJrZXkiOiIifQ"
        }
    }
}

clientDataのところで出てきましたねeyJ。もちろんここはみなさん迷わずbase64デコードするところだと思いますが、これの中身は既に登録時の(4)のところで見ましたね。ちなみにU2Fのドキュメントではwebase-base64が使われていると書かれていますが、このwebsafe-base64とはJSON Webなんとかでおなじみのいわゆるbase64urlのことです。'+'の代わりに'-'、'/'の代わりに'_'を使うアレです。

registrationDataは元データがJSONじゃないのでeyJしてませんが、同様にwebsafe-base64エンコードされています。元データは登録時の(5)で出てきたRaw Registration Response Messageです。

登録時の(7)

いよいよ最後です。とは言っても登録時の(2)で指定したcallback関数に登録時の(6)で出てきた responseDataが渡されるくるだけです。

認証時の(2)

interfaceは登録時の(2)で認証時に用いるu2f.signも載せましたね。認証時の場合は、SignRequest[]がメインのデータですね。その具体例で示すと下記のような感じになります。

[
    {
        "version": "U2F_V2",
        "challenge": "CAkFgYNpVySxIduggCxxB06_0Da47LUvpUWPH3_--JE",
        "keyHandle": "ZPWBYmapVxKnk4oKWotihGT2TPsXV-_w9FREk3vhfx7wCGjzRRWlyT1m9borfU6ZpXqbiR36CzIF30ybhI-_-w",
        "appId": "https://centos6.toke.jp"
    }
]

ここでRelying Partyから認証要求するときにkeyHandleが指定されています。このkeyHandleは登録時にユーザの所持するU2F Token内で生成された鍵ペアを識別する値でしたね。これが何を意味するかというと、Rerying PartyがFIDO U2Fの認証要求を行うときは既に、そのユーザを認証もしくは最低限でも識別をしている必要があることになるわけです。識別をしたユーザに対応するkeyHandleをRelying Partyの登録ユーザDB等から取り出して認証要求に埋め込む必要があるわけなので。めんどくさい仕様だなあと思いますけどUniversal 2nd Factorですからね。

認証時の(3)

前述の通り登録時の(3)と同じRequest dictionaryを用います。具体例は下記です。typeがu2f_sign_requestになっている以外、特筆するところはなさそうですね。

{
    "type": "u2f_sign_request",
    "signRequests": [
        {
            "version": "U2F_V2",
            "challenge": "CAkFgYNpVySxIduggCxxB06_0Da47LUvpUWPH3_--JE",
            "keyHandle": "ZPWBYmapVxKnk4oKWotihGT2TPsXV-_w9FREk3vhfx7wCGjzRRWlyT1m9borfU6ZpXqbiR36CzIF30ybhI-_-w",
            "appId": "https://centos6.toke.jp"
        }
    ],
    "timeoutSeconds": 30,
    "requestId": 1
}

認証時の(4)

ここでやりとりされるRaw MessageであるAuthentication Request Messageは下記のようなデータになっています。あまり見るべきところはないですが、control byteの値によって指定されたkey handleが登録済みかどうかをチェックするモードか、通常の認証処理を行うモードかを指定できます。

Raw Authentication Request Message

認証時の(5)

下記の図で表されるRaw Authentication Response Messageが返却されます。

Raw Authentication Response Message

前述のように認証時のsignatureはkey handleで識別される鍵ペアの秘密鍵で生成された署名です。この鍵ペアの公開鍵に対応するのが登録時の(5)で出てきたuser public keyです。

user presenceは、その名の通りユーザが存在していたかを示します。ユーザの存在はU2F Tokenについているボタンにユーザがタッチしたかとかで確認するのだと思います。いずれにせよ存在せずに成功させることは現バージョンでは想定していないと思うのでここのバイトは0x01固定になります。

counterはU2F Tokenの複製を検出するために使われるカウンタ値を示します。U2F Tokenは内部で認証のたびにインクリメントされるカウンタを持っていて、その値をこのcounterに埋め込みます。Relying Party側では前回の認証時のカウンタ値を保持しておき、このcounterで示されるカウンタ値が前回のカウンタ値と同じだったり、小さかったりしたら、何かがおかしいということでカウンタ検証エラーとするわけです。現実的な脅威に対してどの程度有効なのかはよくわかりません。なおカウンタはU2F Token内で要求のapplication parameter (≒Relying Party)毎に持つか、application parameter横断でグローバルに持つかは計算資源等を考慮して実装に任されています。自分の持っているYubicoの製品はグローバルカウンタでした。

認証時の(6)

登録時の(6)と同じResponse dictionaryが返されます。その中に含まれるSignResponse dictionaryの定義は下記になります。


dictionary SignResponse {
    DOMString keyHandle;
    DOMString signatureData;
    DOMString clientData;
};

具体例で示すと下記のような感じになります。

{
    "data": {
        "type": "u2f_sign_response",
        "requestId": 1,
        "responseData": {
            "keyHandle": "ZPWBYmapVxKnk4oKWotihGT2TPsXV-_w9FREk3vhfx7wCGjzRRWlyT1m9borfU6ZpXqbiR36CzIF30ybhI-_-w",
            "clientData": "eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZ2V0QXNzZXJ0aW9uIiwiY2hhbGxlbmdlIjoiQ0FrRmdZTnBWeVN4SWR1Z2dDeHhCMDZfMERhNDdMVXZwVVdQSDNfLS1KRSIsIm9yaWdpbiI6Imh0dHBzOi8vY2VudG9zNi50b2tlLmpwIiwiY2lkX3B1YmtleSI6IiJ9",
            "signatureData": "AQAAAHcwRAIgK2Gu2C57S3V8iNQFmUGZrOrI0a5gCntFMqibdKJVL1oCIG121eeePR18fQLxkGpIcX0fyAsQFnPADYa3LieZWoYj"
        }
    }
}

このsignatureDataは認証時の(5)のRaw Authentication Response Messageをwebsafe-base64エンコードしたものです。

認証時の(7)

いよいよ最後です。とは言っても認証時の(2)で指定したcallback関数に認証時の(6)で出てきた responseDataが渡されるくるだけです。

あー疲れたw

FIDO U2F実装

Client

Linuxとかのログインに使えるpam-u2fのようなのもあるけど、基本的なユースケースはWebブラウザだろうし、実質的にはGoogle Chromeのみといった感じでしょうか。

Google Chromeではバージョン38以降で使用できますが、使えるのはLow-level MessagePort APIだけです(後述)。なおFIDO U2F (Universal 2nd Factor) extensionを使った例をサンプルプログラムとかでよく見かけたんですが、このextension相当の機能がChrome本体に入っているのでこのextenstionをインストールする必要はありません。このextensionを使っている場合は、クライアントサイドのコード中にextention IDとして「pfboblefjcgdjicmnffhdgionmgcdmne」が出てくることになります。Chrome本体の同等の機能は「CryptoToken Component Extension」と呼ばれているようで、「kmendfapggjehodndflmmgagdbamhnfd」というextension IDが使われています。余談ながら、このComponet Extensionと呼ばれる(?)拡張機能相当の機能は通常はChromeのextention(拡張機能)一覧に見えませんが、例えばMacの場合は下記のようにオプションをつけて起動すれば存在を確認することができます。

$ open "/Applications/Google Chrome.app" --args --show-component-extension-options

CryptoToken Component Extension

しかしどういうわけか、このChrome本体に取り込まれているU2F機能はLow-level MessagePort APIの実装部分だけで、High-level JavaScript APIの実装部分は前述のFIDO U2F extensionには含まれているのに、Chrome本体には含まれていません。なのでHigh-level JavaScript APIを使いたいRelying Partyは、このFIDO U2F extensionのHigh-level JavaScript APIのファイルを自サーバに配置することになるでしょう。その際、同ファイル内に出てくるextension IDの「pfboblefjcgdjicmnffhdgionmgcdmne」を「kmendfapggjehodndflmmgagdbamhnfd」に書き換えることをお忘れなく。

Firefoxもずっと前から実装しよう話は出てたのですが、ついに先日extensionが出ましたね。Mac版 Firefox 41.0.2 / U2F Support Add-on 0.0.2 / Yubico FIDO U2F SPECIAL SECURITY KEY の組み合わせで問題なく動いているように見えました。High-level JavaScript APIも動いています。

Token

一番メジャーなのはYubicoの製品群だと思いますが、FIDO AllianceのサイトFIDO Certifiedのページを見ると他にも色々あるようです。自分もYubicoの青いやつ (FIDO U2F SPECIAL SECURITY KEY) を使ってます。
Yubicoの青いやつ

写真の真ん中に金色の部分がありますが、登録・認証時はこの部分の鍵マークが青く光り、その部分に指でタッチするとuser presenceが確認できたということになります。

Relying Party

メジャーどころで知っているのは下記の3つです。自分も一応3つとも設定していますが、普段使っているのはいずれもソフトウェアトークン(TOTP)による二段階認証です。U2F Token持ち歩くの面倒だし、なくしそうだしw


上記の内、DropboxとGitHubはHigh-level JavaScript APIを使っていますが、GoogleはLow-level MessagePort APIを使っています。Googleは余計なものは要らないってポリシーでChrome本体にも前者のAPIが含まれていないんですかね。

FIDO 2.0が控えている状況ではこれ以上Relying Partyはそう増えないかもですね。あの多要素認証の方式を貪欲に増やしていくLastPassですら対応してくれないしw でもFirefoxでもU2F使えるようになってきたし、この対応しない理由を見るとLastPassもそのうち対応するんですかね。

貪欲

自分のサイトをFIDO U2F対応Relying Partyにするには?

YubicoとかGoogleがRelying Party向け(だけではないけど)ライブラリとかの実装をサンプルとともに公開しているのでそれ使ってください。上で色々仕様書いてきたけど、こんなこと知らなくてもあっさり作れます。超簡単。
結局のところ、結論は、

             /)
           ///)
          /,.=゙''"/
   /     i f ,.r='"-‐'つ____   こまけぇこたぁいいんだよ!!
  /      /   _,.-‐'~/⌒  ⌒\
    /   ,i   ,二ニ⊃( ●). (●)\
   /    ノ    il゙フ::::::⌒(__人__)⌒::::: \
      ,イ「ト、  ,!,!|     |r┬-|     |
     / iトヾヽ_/ィ"\      `ー'´     /

2013年4月22日月曜日

多要素認証とか二要素認証とか二段階認証とか

多要素認証とか二要素認証とか二段階認証について少し調べてみた (以下、多要素認証に統一)。
↓色々所感

  • 名称はTwo-step verification (二段階認証)派が多い。Googleの影響?
  • 一度多要素認証成功した端末について、その後二段階目の認証をスキップすることができるようになっていることが多い(端末登録)。
  • Googleは当初、二段階目をスキップする手段を用意していなかったけど、ユーザに不評で後から端末登録の仕組みを入れたとか伝聞で聞いたことあるけど、Web上でその情報を見つけられなかった。
  • Appleはよくわからないけど端末登録はできなさげ? MacOSやiOSでアプリ入れるときも確か毎回パスワード入れさせるよね? 面倒にすればするほどユーザーは脆弱な運用するようになるんじゃないだろうか…
  • リスクベース認証も調べようと思ったけど、どのサービスもほとんど情報がない。Googleとかやってるけど、多要素認証を有効にして、登録されている端末でやってるときも、リスク大と見なされて二段階目の認証が走ることはあるのだろうか…
  • 米Yahoo!は公式情報じゃないけど、多要素認証を有効にした状態での二段階目の認証実施はリスクベースでやってるみたいで珍しいパターン。
  • まあ、とりあえずS/W OTPトークンでのTOTPで、端末登録があればトレンド的にはOKそう? 
  • S/W OTPトークンをインストールできない/したくない人向けにモバイル端末へのEメール/SMS/音声通話を使ったワンタイムパスワード通知も不可欠か…
  • 全てのユーザーが多要素認証を有効にしてくれることはあり得ないから、やっぱりリスクベース認証もがんばらないとだめ?
  • 既存のIDパスワード認証のあるWebサイトにリバースプロクシとかで多要素認証とかリスクベース認証だけを追加してくれるようなアプライアンスとかソフトウェアってあるのかな…
  • モバイル端末へワンタイムパスワードを送信するタイプもやっぱりTOTP使っているんだろうか。
  • Yahoo! JAPANだけEメールで通知するワンタイムパスワードは10分間有効としてるけど他社も30秒より長くしていることあるのだろうか。それとも他社はSMSや音声通知で遅延がないからやはり30秒なのだろうか。その場合、S/W OTPトークンのと同じシークレットが共用されているのだろうか (イラストとかを見ると同じ6桁の数字が表示されていたりするけどあくまで例かもしれないし)。
  • FIDO (Fast IDentity Online) Alliance も一応注目しておいた方がいい?
  • 銀行系は切りがないので見なかったことにした。
  • オンラインゲームとかでも使われてるんだっけ?見なかったことにするけど。
  • 各サービスのパスワード忘れとかS/W OTPインストール端末紛失時のリカバリ方法とかも調べてみたけど多種多様すぎるし疲れたのでやめた。
  • 脚注へのリンクも面倒なのでやめた…。なんか楽に作る方法ないだろうか…
などなど…
サービス名 認証名称 開始時期 二段階目認証方式 二段階目省略用端末登録
PayPal/eBay アカウント PayPal Security Key [PP1] ・2007.01.?? (H/W OTP) [PP2]
・2008.11.24 (SMS) [PP3]
・H/W OTPトークン…6-digit 30sec (Verisign) [PP1] [PP4]
・SMSでの通知…6-digit [PP1]
×?
LastPassアカウント Two-factor or multifactor authentication [LP1] ・2009.03.20? (YubiKey)
・2009.06.09 (Sesame)
・2009.12.02 (Grid)
・2011.01.20 (Fingerprint, Smart card)
・2011.06.21 (Windows Biometric Framework)
・2011.12.04 (Google Authenticator)
[LP2] [LP3] [LP4]
・Google Authenticator
・Grid
・Sesame
・YubiKey
・Fingerprint
・Smartcard
・Windows biometric framework
[LP1]
○ [LP5]
AWSアカウント
IAMユーザー
AWS Multi-Factor Authentication [AW1] ・2009.08.24 (H/W OTPサポート) [AW2]
・2011.11.02 (Virtual MFAサポート) [AW3]
・H/W OTPトークン…TOTP 6-digit 30sec [AW4]
・S/W OTPトークン…H/Wと同様?
× [AW5]
Googleアカウント
Google Appsアカウント
Two-step verification [GG1]
2段階認証プロセス [GG2]
・2010.09.20 (Google Appsアカウント) [GG3]
・2011.02.10 (Google アカウント) [GG4]
・SMS、音声通話でのコード通知
・S/W OTPトークン…TOTP 6digit 30sec [GG5]
○ [GG6]
Facebookアカウント Login approvals [FB1]
ログイン承認 [FB1]
・2011.04.19 [FB2] ・Facebookアプリ内蔵トークン…TOTP? 6digit 30sec [FB3]
・SMSでのコード通知
○ [FB1]
Yahoo! Account Second Sign-in Verification [YI1] ・2011.12.06 [YI2] ・秘密の質問
・Eメールへの確認コード [YI1] [YI3] [YI4]
×?
[YI5] [YI6]
Yahoo! JAPAN ID ワンタイムパスワード [YJ1] ・2012.08.20 (Eメール) [YJ2]
・2013.03.25 (S/W OTP) [YJ1]
・Eメールでの通知…10分間有効6桁のワンタイムパスワード [YJ1] [YJ3]
・S/W OTP…TOTP 6digit 30sec [YJ4] [YJ5]
○ [YJ6]
Dropboxアカウント Two-step verification [DB1]
2段階認証 [DB2]
・2012.08.27 [DB3] ・S/W OTP…TOTP 6-digit 30sec(?) [DB2]
・SMSでの通知…6-digit [DB2]
○ [DB2]
Apple ID Two-step verification [AP1] ・2013.03.21 [AP1] ・Find My iPhone notificationまたはSMSでの通知…4-digit verification code [AP1] ×?
Microsoftアカウント Two-step verification [MS1] ・2013.04.17 [MS1] ・SMS、音声通話でのコード通知? [MS1]
・S/W OTPトークン…TOTP 6digit 30sec? [MS2]
○ (*1)
Evernoteアカウント Two-factor authentication ? [EN1] ・2013年予定 [EN1]
[PP1] https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/Marketing_CommandDriven/securitycenter/PayPalSecurityKey-outside
[PP2] https://www.paypal-media.com/history
[PP3] https://www.paypal-media.com/press-releases/20081124005438
[PP4] https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/Marketing_CommandDriven/securitycenter/PayPalSecurityKeyFAQ-outside#whySecurityKey
[LP1] https://lastpass.com/support.php?cmd=showfaq&id=1696
[LP2] http://www.pcmag.com/article2/0,2817,2343562,00.asp
[LP3] https://lastpass.com/upgrade.php?fromwebsite=1&releasenotes=1
[LP4] https://lastpass.com/upgrade.php?older=1&releasenotes=1
[LP5] https://helpdesk.lastpass.com/account-settings/trusted-computers/
[AW1] http://aws.amazon.com/jp/mfa/
[AW2] http://phx.corporate-ir.net/phoenix.zhtml?c=176060&p=irol-newsArticle_Print&ID=1334509
[AW3] http://aws.amazon.com/jp/about-aws/whats-new/2011/11/02/Announcing-virtual-mfa-support/
[AW4] http://onlinenoram.gemalto.com/
[AW5] http://aws.amazon.com/jp/mfa/faqs/#If_I_enable_AWS_MFA_will_I_need_an
[GG1] http://support.google.com/accounts/bin/answer.py?hl=en&answer=180744&rd=1
[GG2] http://support.google.com/accounts/bin/answer.py?hl=jp&answer=180744&rd=1
[GG3] http://googleenterprise.blogspot.jp/2010/09/more-secure-cloud-for-millions-of.html
[GG4] http://googleblog.blogspot.jp/2011/02/advanced-sign-in-security-for-your.html
[GG5] https://code.google.com/p/google-authenticator/
[GG6] http://support.google.com/accounts/bin/answer.py?hl=ja&answer=1085463&topic=1099588&ctx=topic
[FB1] https://www.facebook.com/help/148233965247823
[FB2] http://blog.facebook.com/blog.php?post=10150153272607131
[FB3] https://www.facebook.com/help/270942386330392/
[YI1] http://help.yahoo.com/kb/index?locale=en_US&page=content&id=SLN6282&y=PROD_ACCT
[YI2] http://developer.yahoo.com/blogs/ydn/yahoo-introduces-stronger-user-authentication-second-sign-verification-52121.html
[YI3] 「秘密の質問への回答または代替メールアドレスへ送信された確認コードの入力のどちらかを実行時に選択」か、「代替メールアドレスへ送信された確認コードの入力」のどちらかを設定で選択可能
[YI4] いずれの設定にするにせよ、初期登録時に確認コード受け取りのためSMSが必要
[YI5] ただし[YI6]の記事によるとリスクベース認証で必要な場合のみ二段階目が実施されるらしい?
[YI6] http://www.ghacks.net/2011/12/09/yahoo-improves-account-security-with-second-sign-in-verification/
[YJ1] http://id.yahoo.co.jp/security/otp.html
[YJ2] http://pr.yahoo.co.jp/release/2012/0820a.html
[YJ3] http://www.yahoo-help.jp/app/answers/detail/a_id/41952/p/544
[YJ4] https://play.google.com/store/apps/details?id=jp.co.yahoo.android.yjotp&hl=ja
[YJ5] 上記ページではHOTPとなっているが時刻同期してるのでTOTPとした。
[YJ6] http://www.yahoo-help.jp/app/answers/detail/a_id/41956/p/544
[DB1] https://www.dropbox.com/help/363/en
[DB2] https://www.dropbox.com/help/363/ja
[DB3] https://blog.dropbox.com/2012/08/another-layer-of-security-for-your-dropbox-account/
[AP1] http://support.apple.com/kb/HT5570?viewlocale=en_US&locale=en_US
[MS1] http://blogs.technet.com/b/microsoft_blog/archive/2013/04/17/microsoft-account-gets-more-secure.aspx
[MS2] http://www.windowsphone.com/ja-jp/store/app/authenticator/e7994dbc-2336-4950-91ba-ca22d653759b?appid=e7994dbc-2336-4950-91ba-ca22d653759b
[EN1] http://www.informationweek.com/security/management/evernote-were-adding-two-factor-authenti/240150023

2013年2月18日月曜日

OpenID Connect Implicit Client Profile 1.0 - draft 06 日本語私訳

Draft: OpenID Connect Implicit Client Profile 1.0 - draft 06
 TOC 
DraftN. Sakimura
 NRI
 J. Bradley
 Ping Identity
 M. Jones
 Microsoft
 B. de Medeiros
 Google
 C. Mortimore
 Salesforce
 E. Jay
 Illumila
 January 22, 2013


OpenID Connect Implicit Client Profile 1.0 - draft 06

Abstract

OpenID Connect 1.0は、OAuth 2.0上に作られたシンプルなアイデンティティ層である。そして、相互運用可能でRESTfulな方法により、エンドユーザに関する基本的なプロファイル情報の取得と同様に、認可サーバによる認証に基づくエンドユーザのアイデンティティの検証も、クライアントに対し可能とする。

OpenID Connect Implicit Client Profile 1.0 は、OpenID Connect Standard 1.0仕様の一プロファイ ルであり、OAuthインプリシットグラントタイプを用いた基本的なウェブベースのリライイングパーティについて、理解と実装を容易にすることを狙いとしている。 OpenIDプロバイダに関しては、Standard仕様を参照すること。当プロファイルはOpenIDプロバイダの実装とセキュリティに関する考慮事項については除外している。



Table of Contents

1.   はじめに
    1.1.  要求記法および規則
    1.2.  用語
2.   プロトコルフロー
    2.1.  OpenID Connect Scope値
    2.2.   インプリシットフロー
        2.2.1.   クライアントによる認可要求の準備
        2.2.2.   クライアントによる認可サーバへの要求の送信
        2.2.3.   認可サーバによるエンドユーザの認証
        2.2.4.   認可サーバによるエンドユーザの同意/承認の取得
        2.2.5.   認可サーバによるエンドユーザのクライアントへの返却
            2.2.5.1.   エンドユーザによる認可の許可
            2.2.5.2.   エンドユーザによる認可の拒否または無効な要求
            2.2.5.3.   リダイレクトURI応答の例
    2.3.   IDトークン
        2.3.1.   IDトークンの検証
        2.3.2.  アクセストークンの検証
    2.4.   ユーザ情報エンドポイント
        2.4.1.   ユーザ情報要求
        2.4.2.   ユーザ情報応答
            2.4.2.1.  住所クレーム
            2.4.2.2.   クレームの不変性と一意性
        2.4.3.   ユーザ情報エラー応答
3.   自己発行OpenIDプロバイダ
    3.1.   自己発行OpenIDプロバイダディスカバリ
    3.2.   自己発行OpenIDプロバイダへのクライアント登録
    3.3.   自己発行OpenIDプロバイダ要求
    3.4.   自己発行OpenIDプロバイダ応答
    3.5.   自己発行IDトークン検証
4.   シリアライゼーション
    4.1.  クエリストリングシリアライゼーション
    4.2.  フォームシリアライゼーション
5.   文字列操作
6.   実装に関する考慮事項
    6.1.    ディスカバリと登録
7.   セキュリティに関する考慮事項
8.   プライバシーに関する考慮事項
9.  IANAに関する考慮事項
10.   文献
    10.1.   規定文献
    10.2.   参考文献
Appendix A.  謝辞
Appendix B.   通知
Appendix C.   文書履歴
§  著者のアドレス




 TOC 

1. はじめに

OpenID Connect Implicit Clinet Profileは、OpenID Connect Standard 1.0 仕様 (Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., Mortimore, C., and E. Jay, “OpenID Connect Standard 1.0,” January 2013.) [OpenID.Standard] の一プロファイルであり、OAuthインプリシットグラントタイプを用いた基本的なウェブベースのリライイングパーティについて、実装が容易になるよう作成されている。OAuth認可コードグラントタイプを用いた基本的なウェブベースのリライイングパーティのためのプロファイルについては、OpenID Connect Basic Client Profile 1.0 (Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and C. Mortimore, “OpenID Connect Basic Client Profile 1.0,” January 2013.) [OpenID.Basic]を参照すること。OpenIDプロバ イダおよび非ウェブベースのアプリケーションについてはStandard仕様を参照すること。 当プロファイルはOpenIDプロバイダの実装とセキュリティに関する考慮事項については除外している。



 TOC 

1.1. 要求記法および規則

本文書で用いられる各キーワード「MUST (しなければならない)」、「MUST NOT (してはならない)」、「REQUIRED (必須である)」、「SHALL (するものとする)」、「SHALL NOT (しないものとする)」、「SHOULD (すべきである)」、「SHOULD NOT (すべきではない)」、「RECOMMENDED (推奨される)」、「MAY (してもよい)」、「OPTIONAL (任意である)」は [RFC2119] (Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels,” March 1997.) で述べられている通りに解釈されるべきものである。

本文書では、書いてあるままに解釈されるべき値は引用符 ("") で囲んで示している。プロトコルメッセージの中でこれらの値を使用する場合は、値の一部として引用符を用いてはならない (MUST NOT)。



 TOC 

1.2. 用語

当仕様は、OAuth 2.0 (Hardt, D., “The OAuth 2.0 Authorization Framework,” October 2012.) [RFC6749]で定義されている、「アクセストークン」、「リフレッシュトークン」、「認可コード」、「認可グラント」、「認可サーバ」、「認可エンドポイント」、「クライアント」、「クライアント識別子」、「クライアントシークレット」、「保護リソース」、「リソース所有者」、「リソースサーバ」、「トークンエンドポイント」という用語を用いる。また当仕様では、以下の用語についても定義する。

リライイングパーティ (Relying Party (RP))
OpenIDプロバイダからクレームを要求するアプリケーション
OpenIDプロバイダ (OpenID Provider (OP))
リライイングパーティに対し、クレームを提供する能力を持つサービス。
クレーム (Claim)
クレームプロバイダが、あるエンティティについて主張する、そのエンティティに関する情報の一部
クレームプロバイダ (Claims Provider)
エンティティに関するクレームを返すことが可能なサーバ
エンドユーザ (End-User)
リソースオーナーである人
エンティティ (Entity)
独立した別個の存在を持ち、あるコンテキストの中で識別することが可能な何か。エンドユーザはエンティティの一例である。
個人識別情報 (Personally Identifiable Information (PII))
(a) その情報に関連する自然人を識別するのに用いられる情報。(b)その情報に関連する自然人に直接的・間接的に関連付けられているかもしれない情報。
仮名識別子 (Pairwise Pseudonymous Identifier (PPID))
他のリライイングパーティにおけるエンティティのPPIDとは関連付けることができない、一つのリライイングパーティに対して用いられるエンティティを識別する識別子
IDトークン
JSON Web Token (JWT) (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Token (JWT),” December 2012.) 認証イベントに関するクレームが含まれている[JWT]

発行元 (Issuer)
クレームのセットを発行するエンティティ
発行元識別子
発行元を検証可能な識別子として機能するHTTPS URL
ユーザ情報エンドポイント
クライアントがアクセストークンを提示した際に、対応する認可グラントによって表される、エンドユーザに関して認可された情報を返す、保護リソース



 TOC 

2. プロトコルフロー

認可要求は、インプリシットフローと認可コードフローの二種類のうちのいずれか一つを用いる。認可コードフローはクライアントと認可サーバ間で用いられるクライアントシークレットを安全に保持することが可能なクライアントに適している。一方、インプリシットフローはそれが不可能なクライアントに適している。TLSをサポートしていないクライアントは、アクセストークンの盗聴を防ぐために認可コードフローを用いなければならない(MUST)。

当仕様はインプリシットフローを用いるクライアントについてのみ文書化する。OpenIDプロバイダは両方のフローをサポートしなければならない(MUST)。認可コードフローを使用するクライアントとOpenIDプロバイダは、OpenID Connect Standard 1.0 (Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., Mortimore, C., and E. Jay, “OpenID Connect Standard 1.0,” January 2013.) [OpenID.Standard] 仕様を参照すべきである。



 TOC 

2.1.OpenID Connect Scope値

OpenID Connectのクライアントは、OAuth 2.0 (Hardt, D., “The OAuth 2.0 Authorization Framework,” October 2012.) [RFC6749]の3.3節で定義されているscope値を、アクセストークンに要求するアクセス権限を示すのに用いる。アクセストークンに関連付けられたスコープは、OAuth 2.0によって保護されているエンドポイントへアクセスする際にどんなリソースを利用することができるかを決定する。OpenID Connectのスコープは、ユーザ情報エンドポイントで利用可能な情報のセットを要求するために用いられる。OAuth 2.0は、拡張機能として、追加のスコープ値を指定することができる。当仕様では、OpenID Connectで利用されるscope値のみ記載している。

以下のスコープで要求されたクレームは、認可サーバに任意として扱われる。

OpenID Request Object (Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., Mortimore, C., and E. Jay, “OpenID Connect Messages 1.0,” January 2013.) [OpenID.Messages] を用いることにより、クレームは必須として扱われることができる。

OpenID Connectでは、以下のscope値が定義されている。

openid
必須 (REQUIRED)。クライアントは、認可サーバに対し、OpenID Connect要求を行っていることを通知する。もしopenidスコープ値が存在しなかった場合、その要求はOpenID Connect要求として扱ってはならない(MUST NOT)。
profile
任意 (OPTIONAL)。このスコープ値は、発行されたアクセストークンによって与えられる、ユーザ情報エンドポイントでのエンドユーザのデフォルトのprofile クレーム (Reserved Member Definitions)アクセスを要求する。これらのクレームは以下の通り: namefamily_namegiven_namemiddle_namenicknamepreferred_usernameprofilepicturewebsitegenderbirthdatezoneinfolocaleupdated_time
email
任意 (OPTIONAL)。このスコープ値は、発行されたアクセストークンによって与えられる、ユーザ情報エンドポイントに対する、emailemail_verifiedクレームへのアクセスを要求する。
address
任意 (OPTIONAL)。このスコープ値は、発行されたアクセストークンによって与えられる、ユーザ情報エンドポイントに対する、addressクレームへのアクセスを要求する。
phone
任意 (OPTIONAL)。このスコープ値は、発行されたアクセストークンによって与えられる、ユーザ情報エンドポイントに対する、phone_numberクレームへのアクセスを要求する。
offline_access
このスコープ値は、OpenID Connect Implicit Client Profile 1.0では使用されないだろう (MAY NOT)。使用方法についてはOpenID Connect Basic Client Profile 1.0 (Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and C. Mortimore, “OpenID Connect Basic Client Profile 1.0,” January 2013.) [OpenID.Basic]を参照すること。

ASCIIの大文字小文字を区別したスコープ値をスペース区切りでリスト化することにより、複数のスコープ値が使用されるかもしれない (MAY)。

いくつかのケースでは、エンドユーザーは、クライアントによって要求された一部またはすべての情報の提供をOpenIDプロバイダに拒否させるためのオプションが表示される。ユーザが開示を求められる情報量を最小化するために、クライアントは、ユーザ情報エンドポイントから入手可能な情報のサブセットのみを要求することを選択するかもしれない。

以下は、 scope要求の参考例である。

  scope=openid profile email phone


 TOC 

2.2. インプリシットフロー

インプリシットフローは以下の手順で構成される:

  1. クライアントは、希望する要求パラメータを含む認可要求を準備する。
  2. クライアントは、認可サーバに要求を送信する。
  3. 認可サーバはエンドユーザーを認証する。
  4. 認可サーバは、エンドユーザーの同意/承認を取得する。
  5. 認可サーバは、アクセストークンおよびIDトークンと共にエンドユーザをクライアントに送り戻す。



 TOC 

2.2.1. クライアントによる認可要求の準備

エンドユーザが保護リソースにアクセスしようとした際に、エンドユーザーの認可をまだ取得していない場合、クライアントは、認可エンドポイントへの認可要求の準備をする。

認可エンドポイントURLで使用されるスキームは、HTTPSでなければならない (MUST)。

クライアントは RFC 2616 (Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, “Hypertext Transfer Protocol -- HTTP/1.1,” June 1999.) [RFC2616] で定義されているHTTP GET またはHTTP POST を用いて要求を構築してもよい (MAY)。

HTTP GETメソッドを用いる場合、要求パラメータは クエリストリングシリアライゼーション (Query String Serialization)によってシリアライゼーションされる。HTTP POST メソッドを用いた場合、要求パラメータは、[W3C.REC‑html401‑19991224] (Hors, A., Raggett, D., and I. Jacobs, “HTML 4.01 Specification,” December 1999.) で定義されている application/x-www-form-urlencoded フォーマットを用いてHTTP要求エンティティボディに追加される。

このプロファイルは、さらに以下の要求パラメータを規定する。

response_type
この値は、スペース区切りのリストとして、 tokenid_tokenを含まなければならない (MUST)。これはアクセストークンとIDトークンの両方がレスポンスのURLフラグメントとして返されることを要求する。

要求内の他の必須 (REQUIRED) パラメータは以下の通り。

client_id
OAuth 2.0クライアント識別子。
scope
OAuth 2.0 scope 値。これは、スペースで区切られたASCII文字列の一つとしてopenidを含まなければならない (MUST)。任意 (OPTIONAL) scope値として profileemailaddressphoneoffline_accessも定義されている。
redirect_uri
応答が送信されるリダイレクト先のURI。これは、プロバイダと共にあらかじめ登録しなければならない (MUST)。

要求は、下記の任意の、時には必須のパラメータを含めることができる (MAY)。

nonce
必須 (REQUIRED)。IDトークンを持つクライアントセッションを関連付けるためと、リプレイ攻撃を軽減するために使用される文字列値。値は変更されずにそのままIDトークンに渡されます。これを達成する一つの方法は、署名されたセッションクッキーとしてランダムな値を格納して、 nonceパラメータの値を渡すことである。その場合には、返されたIDトークンのnonceは、第三者によるIDトークンリプレイを検出するために署名されたセッションクッキーと比較される。
state
推奨 (RECOMMENDED)。要求とコールバック間で状態を維持するために使用する不明瞭な値は、XSRF攻撃に対する保護の役割を果たす。
display
認可サーバがエンドユーザに対して、認証と同意のユーザインタフェース画面を表示する方法を指定するASCII文字列値。次の値がサポートされている。
page
認可サーバは、ユーザエージェントの(ポップアップとかではない)完全な画面として認証と同意のUIを表示すべきである (SHOULD)。displayパラメータが指定されていない場合、これがデフォルトの表示モードである。
popup
認可サーバは、ユーザエージェントのポップアップウィンドウとして認証と同意のUIを表示すべきである (SHOULD)。ポップアップユーザエージェントウィンドウは幅450ピクセル、高さ500ピクセルであるべきである (SHOULD)。
touch
認可サーバは、タッチインタフェースを活用したデバイス向けのUIを表示すべきである (SHOULD)。認可サーバは、タッチデバイスの検出を試み、さらにインターフェースをカスタマイズしてもよい (MAY)。
wap
認可サーバは、フィーチャーフォンの画面向けの認証と同意のUIを表示すべきである (SHOULD)。
prompt
認可サーバが再認証と同意のためにエンドユーザに対しプロンプトを表示するかどうかを指定する、スペース区切りの大文字小文字を区別したASCII文字列値のリスト。設定可能な値は以下のとおり。
none
認可サーバは、認証も同意もユーザインタフェース画面を表示してはならない(MUST NOT)。エンドユーザがまだ認証されていないか、またはクライアントが要求されたクレームに対して事前設定された同意を保持していない場合は、エラーが返される。これは、既存の認証および/または同意が存在するかを確認するための手段として使用することができる。
login
認可サーバは、再認証のためにエンドユーザにプロンプトを表示しなければならない。
consent
認可サーバは、クライアントに情報を返す前にエンドユーザに同意のためのプロンプトを表示しなければならない (MUST)。
select_account
認可サーバは、エンドユーザにユーザアカウントを選択するためのプロンプトを表示しなければならない (MUST)。これは、認可サーバで複数のアカウントを持つユーザは、彼らが現在のセッションを持っているかもしれない複数のアカウントの間で選択することを許可する。
promptパラメータは、エンドユーザが現在のセッションのためにまだ存在していることを確認するためか、または要求に注意を喚起するためにクライアントで使用することができる。
login_hint
(必要に応じて) ユーザが認可サービスでの認証に用いるかもしれないログイン識別子に関して、認可サービスに対して与えるヒント。 このヒントは、ユーザに対して初めにユーザのEメールアドレス (またはその他の識別子) を求め、それをディスカバリした認可サービスに対しヒントとして受け渡す場合に、RPによって用いられる。ヒント値はディスカバリに用いた値とマッチしていることが推奨される。このパラメータの使用はOPの裁量に任されている。

以下は、認可要求のURL(表示目的のみのための行の折り返しが含まれる)の参考例を示す。

  https://server.example.com/authorize?
    response_type=token%20id_token
    &client_id=s6BhdRkqt3
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
    &scope=openid%20profile
    &state=af0ifjsldkj
    &nonce=n-0S6_WzA2Mj


 TOC 

2.2.2. クライアントによる認可サーバへの要求の送信

認可要求を構築した後、クライアントはそれをHTTPS認可エンドポイントに送信する。これは、HTTPSリダイレクト、ハイパーリンク、またはユーザエージェントをそのURLへ導く他の安全な手段を介して行ってもよい (MAY)。

以下は、HTTPリダイレクトを使用した参考例である(表示上だけの行折り返りを含む):

  HTTP/1.1 302 Found
  Location: https://server.example.com/authorize?
    response_type=token%20id_token
    &client_id=s6BhdRkqt3
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
    &scope=openid%20profile
    &state=af0ifjsldkj
    &nonce=n-0S6_WzA2Mj


 TOC 

2.2.3. 認可サーバによるエンドユーザの認証

認可サーバは、同意が正しいパーティからのものであるかを確認するために、リソースオーナーを認証する。 認証が実行される方法の正確な方法はこの仕様の範囲外である。



 TOC 

2.2.4. 認可サーバによるエンドユーザの同意/認可の取得

認可サーバは、要求されたクレームに対して、認可決定を取得する。 これは、エンドユーザに対し、同意の内容を認識させた上で同意を得るための対話をエンドユーザーに提示することによって行うか、または他の手段(例えば、事前に管理上の手段による同意を経由)を介して同意を確立することによって、実施できる。

openid スコープ値は、このOAuth 2.0要求がOpenID Connect要求であることを宣言する。その他の全てのスコープ値の使用は任意 (OPTIONAL) である。



 TOC 

2.2.5. 認可サーバによるエンドユーザのクライアントへの返却

認可が決定されると、認可サーバは、正常応答またはエラー応答を返す。



 TOC 

2.2.5.1. エンドユーザによる認可の許可

リソースオーナがアクセス要求を許可したとき、認可サーバはアクセストークンを発行し、 OAuth 2.0 (Hardt, D., “The OAuth 2.0 Authorization Framework,” October 2012.) [RFC6749]の4.2.2節と、OAuth 2.0 Multiple Response Type Encoding Practices (de Medeiros, B., Scurtescu, M., and P. Tarjan, “OAuth 2.0 Multiple Response Type Encoding Practices,” November 2012.) [OAuth.Responses] の定義に従い、 application/x-www-form-urlencoded を用いて、リダイレクトURIのフラグメントコンポーネントに以下のパラメータを追加し、クライアントへ導く。

インプリシットフローでは、全体の応答は、OAuth 2.0 (Hardt, D., “The OAuth 2.0 Authorization Framework,” October 2012.) [RFC6749] の4.2.2節で定義されたリダイレクトURLのフラグメントコンポーネントとして返される。

access_token
必須 (REQUIRED)。ユーザ情報エンドポイントのためのアクセストークン。
token_type
必須 (REQUIRED)。OAuth 2.0のトークンタイプ値。この値は "bearer" か、クライアントが認可サーバとネゴシエートしたその他の token_type でなければならない (MUST)。このプロファイルを実装するクライアントは、OAuth 2.0 Bearer Token Usage (Jones, M. and D. Hardt, “The OAuth 2.0 Authorization Framework: Bearer Token Usage,” October 2012.) [RFC6750] 仕様をサポートしなければならない (MUST)。当プロファイルではベアラトークンの仕様についてのみ記述する。
id_token
必須 (REQUIRED)。IDトークン。
state
OAuth 2.0 scope 値。stateパラメータは、クライアントの認可要求に存在した場合は必須。クライアントは、 state値が認可要求のstateパラメータと正確に一致することを確認しなければならない(MUST)。
expires_in
任意 (OPTIONAL)。アクセストークンの秒単位の有効期限。

クライアントは、リソースサーバ上の保護リソースにアクセスするためにアクセストークンを使用することができる。

以下は、参考例である(表示上だけの行折り返しを含む):

  HTTP/1.1 302 Found
  Location: https://client.example.org/cb#
    access_token=SlAV32hkKG
    &token_type=bearer
    &id_token=eyJ0 ... NiJ9.eyJ1c ... I6IjIifX0.DeWt4Qu ... ZXso
    &expires_in=3600
    &state=af0ifjsldkj


 TOC 

2.2.5.2. エンドユーザによる認可の拒否または無効な要求

エンドユーザーが認可を拒否するか、またはエンドユーザーの認証が失敗した場合、認可サーバは、OAuth 2.0 (Hardt, D., “The OAuth 2.0 Authorization Framework,” October 2012.) [RFC6749] の4.1.2.1節に定義されているエラー認可応答を返さなければならない(MUST)。その他のパラメータは返されるべきではない(SHOULD)。



 TOC 

2.2.5.3. リダイレクトURI応答の例

クライアントは、ユーザーエージェントのために、フラグメントエンコードされた応答を解析し、検証用のWebサーバクライアントにそれをPOSTする方法を提供しなければならない。

以下は、クライアントがそのredirect_uriでホストする可能性のあるJavaScriptファイルの例である。これは、認可サーバからのリダイレクトによってロードされます。フラグメントは解析され、受信した情報を検証するURIにPOSTで送信される。

以下は、 リダイレクトURI応答の参考例である。

  GET /cb HTTP/1.1
  Host: client.example.org

  HTTP/1.1 200 OK
  Content-Type: text/html

  <script type="text/javascript">

  // First, parse the query string
  var params = {}, postBody = location.hash.substring(1),
      regex = /([^&=]+)=([^&]*)/g, m;
  while (m = regex.exec(postBody)) {
    params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  }

  // And send the token over to the server
  var req = new XMLHttpRequest();
  // using POST so query isn't logged
  req.open('POST', 'https://' + window.location.host +
                   '/catch_response', true);
  req.setRequestHeader('Content-Type',
                       'application/x-www-form-urlencoded');

  req.onreadystatechange = function (e) {
    if (req.readyState == 4) {
      if (req.status == 200) {
  // If the response from the POST is 200 OK, redirect the user
        window.location = 'https://'
          + window.location.host + '/redirect_after_login'
      }
  // if the OAuth response is invalid, generate an error message
      else if (req.status == 400) {
        alert('There was an error processing the token')
      } else {
        alert('Something other than 200 was returned')
      }
    }
  };
  req.send(postBody);


 TOC 

2.3. IDトークン

IDトークンは、認証イベントおよび他の要求されたクレームに関するクレームを含むセキュリティトークンである。IDトークンはJSON Web Token (JWT) (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Token (JWT),” December 2012.) [JWT] として表される。

IDトークンは、認証イベントおよびユーザ識別子を管理するために使用され、aud (audience) および nonce クレームを介して特定のクライアントをスコープとしている。

以下のクレームは、IDトークン内で必須である (REQUIRED)。

iss
必須 (REQUIRED)。応答の発行元の発行元識別子。
sub
必須 (REQUIRED)。主体の識別子。クライアントによって消費されることを意図している、発行元内でローカルユニークな再割り当てされないエンドユーザの識別子。 例: 24400320 または AItOawmwtWwcT0k51BayewNvutrJUqsvl6qs7A4 。 長さはASCIIで255文字を超えてはならない(MUST NOT)。
aud
必須 (REQUIRED)。このIDトークンが意図している聴衆。それはクライアントのOAuth 2.0のclient_id でなければならない (MUST)。
azp
任意 (OPTIONAL)。認可された当事者。IDトークンを要求したクライアントとは異なる場合、このメンバーは、OAuthアクセストークンとしてこのIDトークンを使用するよう認可されたOAuth 2.0クライアントを識別する。認可された当事者のclient_idを含まなければならない (MUST)。
exp
必須 (REQUIRED)。それ以降はIDトークンを処理のために受け入れてはならない(MUST NOT)ことを示す有効期限。このパラメータの処理は、現在の日時が、記載されている有効期限の日時より前でなければならない (MUST) ことが要求される。実装者は、クロックスキューを考慮するために、通常数分を超えない程度のずれを許容してもよい(MAY)。値は、UTCの1970-01-01T0:0:0Zから要望する日時までの秒数である。一般に日時についての詳細、特にUTCに関しては、RFC 3339 (Klyne, G., Ed. and C. Newman, “Date and Time on the Internet: Timestamps,” July 2002.) [RFC3339] 参照すること。
iat
必須 (REQUIRED)。 JWTが発行された時刻。値は、UTCの1970-01-01T0:0:0Zから要望する日時までの秒数である。一般に日時についての詳細、特にUTCに関しては、RFC 3339 (Klyne, G., Ed. and C. Newman, “Date and Time on the Internet: Timestamps,” July 2002.) [RFC3339] を参照すること。
auth_time
UTCの1970-01-01T0:0:0Zから、エンドユーザー認証が発生した日時までの秒数である。
nonce
必須 (REQUIRED)。IDトークンを持つクライアントセッションを関連付けるためと、リプレイ攻撃を軽減するために使用される文字列値。値は変更されずにそのまま認可要求からIDトークンへ渡されます。クライアントは nonce クレーム値が認可要求で送信した nonce パラメータの値と等しいかを検証しなければならない (MUST)。認可要求に存在する場合、認可サーバは、認可要求で送信されたナンス値を nonce クレームの値としてIDトークン (ID Token)に含めなければならない (MUST)。インプリシットフローではnonceは必須 (REQUIRED) である。コードフローでは任意 (OPTIONAL) である。
at_hash
任意 (OPTIONAL)。アクセストークンのハッシュ値。インプリシットフローでIDトークンがaccess_tokenと共に発行される場合、必須 (REQUIRED)。この値は、JWS (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Signature (JWS),” December 2012.) [JWS] ヘッダ内のalgパラメータに指定された JWA (Jones, M., “JSON Web Algorithms (JWA),” December 2012.) [JWA] で規定されているハッシュアルゴリズムを使用してaccess_tokenをハッシュ化することによって作成されたハッシュの左から半分をbase64urlエンコードすることによって生成される。例えば、algRS256の場合、SHA-256でaccess_tokenをハッシュ化し、その左から128bitに対しbase64urlエンコードを行う。
sub_jwk
任意 (OPTIONAL)。Section 3 (Self-Issued OpenID Provider)に規定されている、自己発行OpenIDプロバイダによって発行されたIDトークンの署名のチェックに用いられる公開鍵値。鍵はJWK形式である。OPが自己発行OPのときsub_jwkクレームの使用は必須 (REQUIRED) であり、OPが自己発行OPでないときの使用は推奨されない (NOT RECOMMENDED)。

JWTは、それを利用している全ての当事者によって認識されるその他のクレームを含むかもしれない (MAY)。

IDトークンはJWS (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Signature (JWS),” December 2012.) [JWS]によって署名されなければならない (MUST)。そして必要に応じて (OPTIONALLY) JWS (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Signature (JWS),” December 2012.) [JWS] と JWE (Jones, M., Rescorla, E., and J. Hildebrand, “JSON Web Encryption (JWE),” December 2012.) [JWE]を用いて署名と暗号化の両方をそれぞれ実施する。これによって、認証、完全性、否認防止、および必要に応じて機密性を提供する。

クライアントは、IDトークンの検証 (ID Token Verification)により、IDトークンの妥当性を直接検証しなければならない (MUST)。

以下は、base64urlデコードされたIDトークンの参考例である(表示上だけの行折り返しを含む):

  {
   "iss": "https://server.example.com",
   "sub": "24400320",
   "aud": "s6BhdRkqt3",
   "nonce": "n-0S6_WzA2Mj",
   "exp": 1311281970,
   "iat": 1311280970,
   "at_hash": "MTIzNDU2Nzg5MDEyMzQ1Ng"
  }


 TOC 

2.3.1. IDトークンの検証

認可応答におけるIDトークンの妥当性を検証するために、クライアントは以下を行わなければならない (MUST)。

  1. クライアントは、iss (issuer)クレームの値によって識別される発行元が聴衆として登録したclient_idが、aud (audience) クレームに含まれていることを検証しなければならない (MUST)。IDトークンにそのクライアントが有効な聴衆であると列挙されていないか、そのクライアントが信頼していない追加の聴衆が含まれていた場合、IDトークンを拒絶しなければならない (MUST)。
  2. クライアントは、JWTヘッダのalgパラメータに指定されたアルゴリズムを用いて、JWS (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Signature (JWS),” December 2012.) [JWS]に従ってIDトークンの署名を検証しなければならない (MUST)。
  3. algの値はRS256であるべきである (SHOULD)。他の署名アルゴリズムを用いたトークンの妥当性検証は、OpenID Connect Messages (Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., Mortimore, C., and E. Jay, “OpenID Connect Messages 1.0,” January 2013.) [OpenID.Messages]仕様に記述されている。
  4. クライアントは、発行元によるディスカバリの中で提供される署名キーを使用しなければならない (MUST)。発行元は、iss (issuer)クレームの値と正確に一致しなければならない。
  5. 現在の時刻は exp クレームの値より小さくなければならない(場合により、クロックスキューのため、多少のズレを許可する)。
  6. iat クレームは、攻撃対策のために保存しているナンスの保存時間の上限を制限するために、現在時刻からあまりにも大きく乖離しているときはトークンを拒絶したいといった場合に用いられることができる。許容範囲は、クライアント次第である。
  7. nonceクレームの値は、認可要求で送信されたものと同じ値であることを検証するためにチェックしなければならない (MUST)。クライアントはリプレイ攻撃のためにnonce値をチェックすべきである (SHOULD)。リプレイ攻撃を検出するための詳細な方法は、クライアント固有のものである。
  8. acrクレームが要求された場合、クライアントは、主張されているクレームの値が適切であることを確認すべきである(SHOULD)。acrクレームの値の意味と処理は、この仕様の範囲外である。 (※訳注:acrの詳細は「OpenID Connect Messages 1.0」を参照)
  9. auth_timeクレームが要求されていた場合、クライアントは、最後のユーザ認証から経過した時間があまりに大きいと判断した場合、値の検証と再認証の要求を行うべきである(SHOULD)。



 TOC 

2.3.2. アクセストークンの検証

インプリシットフローでIDトークンと共に発行されたアクセストークンの妥当性を検証するために、クライアントは以下を行うべきである (SHOULD)。

  1. IDトークンの JWS (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Signature (JWS),” December 2012.) [JWS] ヘッダ内の alg パラメータとして JWA (Jones, M., “JSON Web Algorithms (JWA),” December 2012.) [JWA] 内に指定されたハッシュアルゴリズムで access_token をハッシュする。
  2. ハッシュの左半分を取り、それをbase64urlエンコーディングする。
  3. at_hashがIDトークンに存在する場合、その値は、前段の手順で生成された値と一致しなければならない (MUST)。


 TOC 

2.4. ユーザ情報エンドポイント

追加の属性とトークンを取得するには、クライアントはユーザ情報エンドポイントへのGETまたはPOST要求を行う。

ユーザ情報エンドポイントサーバはトランスポート層セキュリティ機構の使用を必須としなければならない (MUST)。ユーザ情報エンドポイントサーバはTLS 1.2 RFC 5246 (Dierks, T. and E. Rescorla, “The Transport Layer Security (TLS) Protocol Version 1.2,” August 2008.) [RFC5246] および/または TLS 1.0 [RFC2246] (Dierks, T. and C. Allen, “The TLS Protocol Version 1.0,” January 1999.) をサポートしなければならない (MUST)。また、同等のセキュリティを持つ、他のトランスポート層セキュリティ機構をサポートしてもよい (MAY)。

注:ユーザ情報エンドポイント応答が、IDトークンの sub (subject) 要素によって識別される対話を行ったユーザに関するものなのかについては保証されてない。ユーザ情報エンドポイント応答内の sub クレームは、追加のユーザ情報エンドポイントのクレームを使用する前に、IDトークン内の sub クレームと正確に一致していなければならない(MUST)。



 TOC 

2.4.1. ユーザ情報要求

クライアントは、エンドユーザの詳細情報を取得するためにユーザ情報エンドポイントに以降のパラメータを使用して要求を送るかもしれない (MAY)。ユーザ情報エンドポイントは、OAuth 2.0 Bearer Token Usage (Jones, M. and D. Hardt, “The OAuth 2.0 Authorization Framework: Bearer Token Usage,” October 2012.) [RFC6750] 仕様に準拠したOAuth 2.0 (Hardt, D., “The OAuth 2.0 Authorization Framework,” October 2012.) [RFC6749]の保護リソースである。このように、アクセストークンは、HTTP Authorizationヘッダを使用して指定する必要があります (SHOULD)。

access_token
アクセストークンは、OpenID Connectの認証要求から取得されます。このパラメータは、HTTP AuthorizationヘッダーまたはフォームエンコードされたHTTP POSTのボディ·パラメータのいずれかを介して1つのメソッドを使って送らなければなりません。
schema
必須。返されるデータのスキーマ。 唯一の定義されたschema値は openid である。
id
この識別子は予約されている。 これは、openid スキーマが使用されているときは、エンドポイントで無視しなければならない (MUST)。

以下は、 参考例である。

  GET /userinfo?schema=openid HTTP/1.1
  Host: server.example.com
  Authorization: Bearer SlAV32hkKG


 TOC 

2.4.2. ユーザ情報応答

要求されたスキーマがopenidの場合、ユーザ情報クレームがJSONオブジェクトのメンバーとして返却されなければならない (MUST)。応答ボディはUTF-8を用いてエンコードされるべきである (SHOULD)。下記で定義されたクレームが返されるかもしれないし、(以下に定義されていない) 追加のクレームが返されるかもしれない。

クレームが返されない場合、そのクレームの名前は、クレームのセットを表すJSONオブジェクトから省略されるべきであり (SHOULD)、nullまたは空の文字列値を持つべきではない (SHOULD NOT)。

メンバは複数の言語とスクリプトで表されるかもしれない (MAY)。言語とスクリプトを指定するため、BCP47 (Phillips, A. and M. Davis, “Tags for Identifying Languages,” September 2009.) [RFC5646] 言語タグに対し、区切られた各メンバ名を # で区切って加えなければならない (MUST)。例えば、日本語のカタカナで家族名を表現するには family_name#ja-Kana-JP と指定する。これは、 family_name#ja-Hani-JP として表現される漢字表記に対する発音に基づいたインデックスとして一般的に用いられる。



メンバ説明
sub 文字列 発行元内でエンドユーザを示す必須識別子。sub (subject) クレームは、ユーザ情報応答に必ず含まれなければならない (MUST)。
name 文字列 エンドユーザのロケールと設定に応じて順序づけられた、エンドユーザのすべての名前のパートを含む表示可能な形式でのフルネーム。
given_name 文字列 エンドユーザの名。
family_name 文字列 エンドユーザの姓。
middle_name 文字列 エンドユーザのミドルネーム。
nickname 文字列 エンドユーザのカジュアルな名前。given_name と同じであるかもしれないし、同じではないかもしれない (MAY)。例えば、 Mike という nickname 値 が、Michael という given_name 値と一緒に返される可能性がある。
preferred_username 文字列 janedoej.doe のような、エンドユーザーがRP側で希望する、簡略化された名前。この値は @/ や空白のような特殊文字を含む任意の有効なJSON文字列であるかもしれない (MAY)。RPは、この値の一意性に依存してはならない (MUST NOT)。 (Section 2.4.2.2 (Claim Stability and Uniqueness)参照)
profile 文字列 エンドユーザのプロファイルページのURL。
picture 文字列 エンドユーザのプロファイル画像のURL。
website 文字列 エンドユーザのウェブページまたはブログのURL。
email 文字列 エンドユーザの優先電子メールアドレス。RPは、この値の一意性に依存してはならない (MUST NOT)。 (Section 2.4.2.2 (Claim Stability and Uniqueness)参照)
email_verified 真偽値 エンドユーザの電子メールアドレスが検証されている場合はtrue、それ以外の場合はfalse。
gender 文字列 エンドユーザの性別。この仕様で定義されている値は femalemale である。定義されている値のいずれも適用できない場合は他の値が使用されるかもしれない (MAY)。
birthdate 文字列 ISO 8601:2004 (International Organization for Standardization, “ISO 8601:2004. Data elements and interchange formats - Information interchange - Representation of dates and times,” 2004.) [ISO8601‑2004] YYYY-MM-DD フォーマットで表されたエンドユーザの誕生日。省略されていることを示すため、年には 9999 が指定されるかもしれない (MAY)。年のみを表現するために、YYYYフォーマットが許可される。プラットフォームの日付関連関数に依存している場合、年のみを指定することは様々な月日となってしまう可能性があるため、実装者は正確に日付を処理するためにこの要因を考慮するべきという点に注意すること。
zoneinfo 文字列 エンドユーザのタイムゾーンを表したゾーン情報 [zoneinfo] (Public Domain, “The tz database,” June 2011.) タイムゾーンデータベースに示された文字列。例: Europe/ParisAmerica/Los_Angeles
locale 文字列 エンドユーザのロケール。BCP47 (Phillips, A. and M. Davis, “Tags for Identifying Languages,” September 2009.) の言語タグとして表現される。これは通常、ダッシュで区切られた、 ISO 639-1 Alpha-2 (International Organization for Standardization, “ISO 639-1:2002. Codes for the representation of names of languages -- Part 1: Alpha-2 code,” 2002.) [ISO639‑1] 言語コードの小文字表記と、 ISO 3166-1 Alpha-2 (International Organization for Standardization, “ISO 3166-1:1997. Codes for the representation of names of countries and their subdivisions -- Part 1: Country codes,” 1997.) [ISO3166‑1] 国コードの大文字表記である。例: en-USfr-CA。 互換性の注意点として、いくつかの実装では、例えば、en_USのように、ダッシュ以外の区切り文字としてアンダースコアを使用している。実装は、同様にこのロケールの構文を受け入れることを選んでもよい (MAY)。
phone_number 文字列 エンドユーザの優先電話番号。このクレームのフォーマットは E.164 (International Telecommunication Union, “E.164: The international public telecommunication numbering plan,” 2010.) [E.164] を推奨 (RECOMMENDED)。例: +1 (425) 555-1212+56 (2) 687 2400
address JSONオブジェクト エンドユーザの優先アドレス。address メンバの値は、 JSON (Crockford, D., “The application/json Media Type for JavaScript Object Notation (JSON),” July 2006.) [RFC4627] の Section 2.5.2.1 (Address Claim) に定義されているメンバのいくつか、またはすべてを含むJSON構造体である。
updated_time 文字列 RFC 3339 (Klyne, G., Ed. and C. Newman, “Date and Time on the Internet: Timestamps,” July 2002.) [RFC3339] で定義された日時で表された、エンドユーザの情報の最終更新日時。例: 2011-01-03T23:58:42+0000

表1: 予約済みメンバの定義

以下は、 応答の参考例である。

  {
   "sub": "248289761001",
   "name": "Jane Doe",
   "given_name": "Jane",
   "family_name": "Doe",
   "preferred_username": "j.doe",
   "email": "janedoe@example.com",
   "picture": "http://example.com/janedoe/me.jpg"
  }

[OpenID.Registration] (Sakimura, N., Bradley, J., and M. Jones, “OpenID Connect Dynamic Client Registration 1.0,” January 2013.) で異なるフォーマットが規定されない限り、ユーザ情報エンドポイントは、JSONフォーマットでクレームを返さなければならない (MUST)。ユーザ情報エンドポイントは、フォーマットを示すためにContent-Typeヘッダーを返さなければならない (MUST)。以下は、受け入れられるコンテントタイプである。

Content-Type返されるフォーマット
application/json plain text JSON object
application/jwt JSON Web Token (JWT)



 TOC 

2.4.2.1. 住所クレーム

物理的な郵送先住所のコンポーネント。 実装では、入手可能な情報とエンドユーザのプライバシー設定に応じて、 addressのフィールドのサブセットのみを返すかもしれない (MAY)。たとえば、 countryregionは、より詳細なアドレス情報なしで、返されるかもしれない。

実装では、formatted サブフィールド中に単一の文字列だけで完全なアドレスを返してもよい (MAY)、またはその他のサブフィールドを用いて、個々のコンポーネントのフィールドを返してもよい (MAY)、またはそれらの両方を返すかもしれない (MAY)。両方の変数が返された場合、formattedアドレスは複数のコンポーネントフィールドをどのように組み合わせるべき (SHOULD) かを示し、双方は同等のアドレスを示しているべきである (SHOULD)。

formatted
表示や宛名ラベルで使用するためにフォーマットされた完全な住所。このフィールドは改行を含むかもしれない (MAY)。 これは、このフィールドにおける、並べ替えやフィルタリングに用いられる際の最優先のサブフィールドである。
street_address
家番号、ストリート名、私書箱、複数行の拡張された住所情報を含むことができる完全な住所コンポーネント。 このフィールドは改行を含むかもしれない (MAY)。
locality
都市や地域のコンポーネント。
region
州、地方、県や地域のコンポーネント。
postal_code
ZIPコードまたは郵便番号コンポーネント。
country
国の名前のコンポーネント。



 TOC 

2.4.2.2. クレームの不変性と一意性

sub (subject) クレームは、2.3 (ID Token) 節の記述のとおり、ある特定のエンドユーザに対し、ローカルユニークでかつ、決して再割り当てされない (MUST) ため、クライアントが不変であるという前提を置ける唯一のクレームである。

したがって、ある特定のエンドユーザに対し、一意性が保証された唯一の識別子は、発行元の識別子と sub クレームの組み合わせであり、preferred_usernameemailなどの他のフィールドは、ある特定のエンドユーザに対する一意の識別子として使用してはならない (MUST NOT)。

他のすべてのクレームは、異なる発行元間で不変性またはユーザ間での一意性の保証はできない。そして発行元は、ローカルな制限とポリシーを適用することが許される。 たとえば、発行元は、異なる時点の異なるエンドユーザ間で、与えられたpreferred_usernameまたはemail アドレスクレームを再利用するかもしれない (MAY)。そして、ある特定のエンドユーザについて、主張したpreferred_usernameemailアドレスが変わるかもしれない (MAY)。



 TOC 

2.4.3. ユーザ情報エラー応答

エラー状態が発生した際、ユーザ情報エンドポイントは OAuth 2.0 Bearer Token Usage (Jones, M. and D. Hardt, “The OAuth 2.0 Authorization Framework: Bearer Token Usage,” October 2012.) [RFC6750] の3節で定義されているエラー応答を返す。

OAuth 2.0 Bearer Token Usage (Jones, M. and D. Hardt, “The OAuth 2.0 Authorization Framework: Bearer Token Usage,” October 2012.) [RFC6750] の3.1節に定義されているエラーコードに加え、当仕様では以下のエラーコードを定義する:

invalid_schema
要求されたスキーマは無効またはサポートされていない。



 TOC 

3. 自己発行OpenIDプロバイダ

自己署名IDトークンを発行するパーソナルOPを使用するユーザを示す特殊な発行元"https://self-issued.me"がある。



 TOC 

3.1. 自己発行OpenIDプロバイダディスカバリ

入力された識別子がドメインself-issued.meを含む場合、動的ディスカバリは実行されない。以下の静的構成値が使用される。

  {
   "authorization_endpoint":
     "openid:",
   "issuer":
     "https://self-issued.me",
   "scopes_supported":
     ["openid", "profile", "email", "address", "phone"],
   "response_types_supported":
     ["id_token"],
   "subject_types_supported":
     ["pairwise"],
   "id_token_signing_alg_values_supported":
     ["RS256"],
   "request_object_signing_alg_values_supported":
     ["none", "RS256"]
   }

注: クライアントが自己発行OPのディスカバリに対し特殊扱いが不要となるように、OpenID Foundationは、上記の静的構成ファイルを返すサイト https://self-issued.me/ をホスティングすることを検討するかもしれません。



 TOC 

3.2. 自己発行アイデンティティプロバイダへのクライアント登録

自己発行OPを使用している場合、クライアントはOPに登録され、以下のクライアント登録応答を取得したものとみなされます。

client_id
クライアントのredirect_uri
expires_at
0。

注: クライアントが自己発行OPの登録に対し特殊処理が不要となるように、OpenID Foundationは、上記の応答を返す(ステートレス)エンドポイント https://self-issued.me/registration/1.0/ をホスティングすることを検討するかもしれません。



 TOC 

3.3. 自己発行OpenIDプロバイダ要求

クライアントは、以下の必須 (REQUIRED) パラメータを使用して認可エンドポイントへ認可要求を送信する。

response_type
必須 (REQUIRED)。文字列定数値 id_token
client_id
必須 (REQUIRED)。クライアントのredirect_uriredirect_uriと同じであるため、redirect_uriを要求で送信する必要がないことに注意。
scope
必須 (REQUIRED)。Section 2.1 (OpenID Connect Scope Values)に定義されているとおりのscopeパラメータ値。
policy_url
必須 (REQUIRED)。受信した属性の使用方法をクライアントがエンドユーザに提供するページのURL。OPはエンドユーザにこのURLを表示すべきである (SHOULD)。標準のOPのケースとは異なり、自己発行OPは、登録時にこの値を受け取ることができないため、認可要求の一部として提供される必要がある。
request
任意 (OPTIONAL)。OpenID Connect Messages 1.0 (Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., Mortimore, C., and E. Jay, “OpenID Connect Messages 1.0,” January 2013.) [OpenID.Messages] の Section 2.1.1.1 に定義されている通りのOpenID要求オブジェクト値。OpenID要求オブジェクトは、クライアントによってJWEで暗号化されているかもしれない。IDトークンの sub (subject) は、JWEの kid (Key ID) として送信されなければならない (MUST)。
id_token_hint
任意 (OPTIONAL)。クライアントとユーザの現在または過去の認証セッションに関するヒントとして、認可サーバから渡されたIDトークン (ID Token)prompt=noneが送信されたとき、これは存在するべきである (SHOULD)。この値は、発行元によって署名された JWS (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Signature (JWS),” December 2012.) [JWS] エンコードされたIDトークンである。この JWS (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Signature (JWS),” December 2012.) [JWS] は、機密性の追加のために、発行元の公開鍵により JWE (Jones, M., Rescorla, E., and J. Hildebrand, “JSON Web Encryption (JWE),” December 2012.) [JWE] 暗号化されるかもしれない。RPによって受信されたIDトークンが暗号化されていた場合、クライアントは署名されたIDトークンを復号しなければならない (MUST)。クライアントは、サーバが復号可能な鍵を用いて再暗号化するかもしれない (MAY)。自己発行されたIDトークンの sub (subject) は、JWEの kid (Key ID) として送信されなければならない (MUST)。

他のパラメータも送られるかもしれない (MAY)。全てのクレームはIDトークンで返されることに注意。

URL全体は、2048バイトを超えてはならない (MUST NOT)。

以下は、参考例である(表示上だけの行折り返しを含む):

  HTTP/1.1 302 Found
  Location: openid://
    ?response_type=id_token
    &client_id=https%3A%2F%2Fclient.example.org%2Fcb
    &scope=openid%20profile
    &policy_url=https%3A%2F%2Fclient.example.org%2Fusage%2F
    &state=af0ifjsldkj&nonce=n-0S6_WzA2Mj


 TOC 

3.4. 自己発行OpenIDプロバイダ応答

自己発行OpenIDプロバイダ応答は、以下の微修正を加えた通常のインプリシットフロー応答と同等である。インプリシットフロー応答であるため、応答パラメータはフラグメントで返されることになる。

  1. iss (issuer) クレーム値は https://self-issued.me である。
  2. IDトークンの署名をチェックするのに用いる公開鍵値を値として持つ sub_jwk クレームが存在する。
  3. sub (subject) クレーム値は、sub_jwk クレーム内のbase64urlエンコードされた鍵値のUTF-8表現バイト列のSHA-256ハッシュをbase64urlエンコードした値である。kty値がRSAの場合、鍵値neが、この順序で連結される。kty値がECの場合、鍵値crvxyが、この順序で連結される。
  4. ユーザ情報エンドポイントにアクセスするためのアクセストークンは返されないため、全てのクレームはIDトークン内に含めて返さなければならない。


 TOC 

3.5. 自己発行IDトークン検証

認可応答あるいはトークンエンドポイント応答におけるIDトークンの妥当性を検証するために、クライアントは以下を行わなければならない (MUST)。

  1. クライアントは、iss (issuer)クレームの値がhttps://self-isued.meであることを検証しなければならない (MUST)。iss に異なる値が含まれていた場合、IDトークンは自己発行されたものではなく、代わりに Section 2.3.1 (ID Token Validation) に従って検証しなければならない (MUST)。
  2. クライアントは、聴衆としてクライアントが認証要求で送ったredirect_uriの値がaud (audience)クレームに含まれていることを検証しなければならない (MUST)。
  3. クライアントは、sub_jwk クレームの中のJWKフォーマットの鍵のJWTヘッダ [JWT] (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Token (JWT),” December 2012.) 内にある alg パラメータで示されたアルゴリズムを用いて、JWS (Jones, M., Bradley, J., and N. Sakimura, “JSON Web Signature (JWS),” December 2012.) [JWS] に従ってIDトークンの署名を検証しなければならない (MUST)。
  4. algの値はRS256のデフォルトであるべきである (SHOULD)。また、ES256かもしれない。
  5. クライアントは、sub (subject) クレーム値が、sub_jwk クレーム内のbase64urlエンコードされた鍵値のUTF-8表現バイト列のSHA-256ハッシュをbase64urlエンコードした値であることを検証しなければならない (MUST)。 kty値がRSAの場合、鍵値neが、この順序で連結される。kty値がECの場合、鍵値crvxyが、この順序で連結される。
  6. 現在の時刻は exp クレームの値より小さくなければならない(場合により、クロックスキューのため、多少のズレを許可する)。
  7. iat クレームは、攻撃対策のために保存しているナンスの保存時間の上限を制限するために、現在時刻からあまりにも大きく乖離しているときはトークンを拒絶したいといった場合に用いられることができる。許容範囲は、クライアント次第である。
  8. ナンス値が認可要求で送信されていた場合、nonceクレームの値が存在している、かつ認可要求で送信されたものと同じ値であることを検証しなければならない (MUST)。クライアントはリプレイ攻撃に対応するためにnonce値をチェックすべきである (SHOULD)。リプレイ攻撃を検出するための詳細な方法は、クライアント固有のものである。

以下は、base64urlデコードされた自己発行IDトークンの参考例である(表示上だけの行折り返しを含む):

  {
   "iss": "https://self-issued.me",
   "sub": "wBy8QvHbPzUnL0x63h13QqvUYcOur1X0cbQpPVRqX5k",
   "aud": "https://client.example.org/cb",
   "nonce": "n-0S6_WzA2Mj",
   "exp": 1311281970,
   "iat": 1311280970,
   "sub_jwk": {
     "kty":"RSA",
     "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx
     4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs
     tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2
     QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI
     SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqb
     w0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
     "e":"AQAB"
    }
  }


 TOC 

4. シリアライゼーション

要求メッセージは、以下の方法の一つを用いてシリアライゼーションされるかもしれない (MAY)。

  1. クエリストリングシリアライゼーション
  2. フォームシリアライゼーション



 TOC 

4.1.クエリストリングシリアライゼーション

クエリストリングシリアライゼーションを用いてパラメータをシリアライゼーションするために、クライアントは、[W3C.REC‑html401‑19991224] (Hors, A., Raggett, D., and I. Jacobs, “HTML 4.01 Specification,” December 1999.)に定義されたapplication/x-www-form-urlencodedフォーマットを用いて、URLのクエリコンポーネントにパラメータと値を追加して文字列を構築する。クエリストリングのシリアライゼーションは、通常、HTTP GET要求に用いられる。

以下は、 このようなシリアライゼーションの参考例である。

  GET /authorize?scope=openid&response_type=code
    &client_id=s6BhdRkqt3
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
  Host: server.example.com



 TOC 

4.2.フォームシリアライゼーション

パラメータと値は、[W3C.REC‑html401‑19991224] (Hors, A., Raggett, D., and I. Jacobs, “HTML 4.01 Specification,” December 1999.)に定義されたapplication/x-www-form-urlencodedフォーマットを用いて、HTTP要求のエンティティボディにパラメータと値を追加することによってフォームシリアライゼーションされる。フォームのシリアライゼーションは、通常、HTTP POST要求で使用されます。

以下は、このようなシリアライゼーションの参考例である。

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

  scope=openid&response_type=code
    &client_id=s6BhdRkqt3
    &redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb


 TOC 

5. 文字列操作

いくつかのOpenID Connectメッセージを処理すると、既知の値とメッセージの値を比較する必要がある。たとえば、ユーザ情報エンドポイントによって返されたクレームの名前は、sub のような特定のクレームの名前と比較されることがある。しかし、Unicode文字列を比較すると、重要なセキュリティ上の影響がある。

そのため、JSON文字列や他のUnicode文字列の比較は以下のように実施しなければならない (MUST):

  1. Unicodeコードポイントの配列を生成するエスケープが適用されているJSONを削除する。
  2. Unicode Normalization (Davis, M., Whistler, K., and M. Dürst, “Unicode Normalization Forms,” 09 2009.) [USA15] は、JSON文字列とその比較対象の文字列のいずれにも適用されない (MUST NOT)。
  3. 二つの文字列の比較は、Unicodeコードポイントとしての等価比較を行わなければならない (MUST)。

いくつかの場所で、この仕様は、文字列のスペース区切りリストを使用します。 全てのそのようなケースで、ASCII空白文字(0x20)のみが、この目的のために使用されるかもしれません (MAY)。



 TOC 

6. 実装に関する考慮事項

当仕様では、OAuthインプリシットグラントタイプを用いたリライイングパーティによって使用される機能を定義する。これらのリライイングパーティはいずれも、当仕様で必須 (REQUIRED) または MUSTと記述されている機能を実装しなければならない (MUST)。



 TOC 

6.1. ディスカバリと登録

いくつかのOpenID Connect環境では、OpenIDプロバイダ、および/またはリライイングパーティの事前設定済みのセットを使用することができる。これらのケースでは、アイデンティティやサービス、またはクライアントの動的登録に関する情報の動的ディスカバリをサポートする必要はない。

しかし、事前設定で連携されていないリライイングパーティとOpenIDプロバイダ間で、予定していなかった対話をサポートすることを選択する場合、OpenID Connect Discovery 1.0 (Sakimura, N., Bradley, J., Jones, M., and E. Jay, “OpenID Connect Discovery 1.0,” May 2012.) [OpenID.Discovery] および OpenID Connect Dynamic Client Registration 1.0 (Sakimura, N., Bradley, J., and M. Jones, “OpenID Connect Dynamic Client Registration 1.0,” May 2012.) [OpenID.Registration] に定義されている機能を実装すべきである (SHOULD)。



 TOC 

7. セキュリティに関する考慮事項

セキュリティに関する考慮事項については、OpenID Connect Standard 1.0 仕様 (Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., Mortimore, C., and E. Jay, “OpenID Connect Standard 1.0,” January 2013.) [OpenID.Standard] を参照すること。



 TOC 

8. プライバシーに関する考慮事項

ユーザ情報応答は、通常、個人識別情報 (PII) が含まれている。このように、指定目的のための情報リリースに対するエンドユーザーの同意は、該当する規則に従って認可時または事前に取得するべきである (SHOULD)。 使用目的は通常 redirect_uri に関連付けて登録されている。

必要なユーザ情報データのみがクライアントに格納されているべきであり (SHOULD)、クライアントは使用目的の宣言と受信したデータを関連付けておくべきである (SHOULD)。

エンドユーザが自分のデータに誰がアクセスしたかを監視できるように、リソースサーバはエンドユーザに対し、ユーザ情報アクセスログを利用できるようにすべきである (SHOULD)。

クライアント間の相関関係の危険性からエンドユーザを保護するために sub (subject) として、仮名識別子(PPID)の使用を考慮する必要がある。



 TOC 

9. IANAに関する考慮事項

この文書ではIANAへの要求はない。



 TOC 

10. 文献



 TOC 

10.1. 規定文献

[E.164] International Telecommunication Union, “E.164: The international public telecommunication numbering plan,” 2010.
[ISO3166-1] International Organization for Standardization, “ISO 3166-1:1997. Codes for the representation of names of countries and their subdivisions -- Part 1: Country codes,” 1997.
[ISO639-1] International Organization for Standardization, “ISO 639-1:2002. Codes for the representation of names of languages -- Part 1: Alpha-2 code,” 2002.
[ISO8601-2004] International Organization for Standardization, “ISO 8601:2004. Data elements and interchange formats - Information interchange - Representation of dates and times,” 2004.
[JWA] Jones, M., “JSON Web Algorithms (JWA),” draft-ietf-jose-json-web-algorithms (work in progress), December 2012 (HTML).
[JWE] Jones, M., Rescorla, E., and J. Hildebrand, “JSON Web Encryption (JWE),” draft-ietf-jose-json-web-encryption (work in progress), December 2012 (HTML).
[JWS] Jones, M., Bradley, J., and N. Sakimura, “JSON Web Signature (JWS),” draft-ietf-jose-json-web-signature (work in progress), December 2012 (HTML).
[JWT] Jones, M., Bradley, J., and N. Sakimura, “JSON Web Token (JWT),” draft-ietf-oauth-json-web-token (work in progress), December 2012 (HTML).
[OAuth.Responses] de Medeiros, B., Scurtescu, M., and P. Tarjan, “OAuth 2.0 Multiple Response Type Encoding Practices,” November 2012.
[OpenID.Discovery] Sakimura, N., Bradley, J., Jones, M., and E. Jay, “OpenID Connect Discovery 1.0,” January 2013.
[OpenID.Messages] Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., Mortimore, C., and E. Jay, “OpenID Connect Messages 1.0,” January 2013.
[OpenID.Registration] Sakimura, N., Bradley, J., and M. Jones, “OpenID Connect Dynamic Client Registration 1.0,” January 2013.
[OpenID.Standard] Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., Mortimore, C., and E. Jay, “OpenID Connect Standard 1.0,” January 2013.
[RFC2119] Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels,” BCP 14, RFC 2119, March 1997 (TXT, HTML, XML).
[RFC2246] Dierks, T. and C. Allen, “The TLS Protocol Version 1.0,” RFC 2246, January 1999 (TXT).
[RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, “Hypertext Transfer Protocol -- HTTP/1.1,” RFC 2616, June 1999 (TXT, PS, PDF, HTML, XML).
[RFC3339] Klyne, G., Ed. and C. Newman, “Date and Time on the Internet: Timestamps,” RFC 3339, July 2002 (TXT, HTML, XML).
[RFC4627] Crockford, D., “The application/json Media Type for JavaScript Object Notation (JSON),” RFC 4627, July 2006 (TXT).
[RFC5246] Dierks, T. and E. Rescorla, “The Transport Layer Security (TLS) Protocol Version 1.2,” RFC 5246, August 2008 (TXT).
[RFC5646] Phillips, A. and M. Davis, “Tags for Identifying Languages,” BCP 47, RFC 5646, September 2009 (TXT).
[RFC6749] Hardt, D., “The OAuth 2.0 Authorization Framework,” RFC 6749, October 2012 (TXT).
[RFC6750] Jones, M. and D. Hardt, “The OAuth 2.0 Authorization Framework: Bearer Token Usage,” RFC 6750, October 2012 (TXT).
[USA15] Davis, M., Whistler, K., and M. Dürst, “Unicode Normalization Forms,” Unicode Standard Annex 15, 09 2009.
[W3C.REC-html401-19991224] Hors, A., Raggett, D., and I. Jacobs, “HTML 4.01 Specification,” World Wide Web Consortium Recommendation REC-html401-19991224, December 1999 (HTML).
[zoneinfo] Public Domain, “The tz database,” June 2011.


 TOC 

10.2. 参考文献

[OpenID.Basic] Sakimura, N., Bradley, J., Jones, M., de Medeiros, B., and C. Mortimore, “OpenID Connect Basic Client Profile 1.0,” January 2013.


 TOC 

Appendix A. 謝辞

The OpenID Community would like to thank the following people for the work they've done in the drafting and editing of this specification.

Andreas Akre Solberg (andreas.solberg@uninett.no), UNINET

Anthony Nadalin (tonynad@microsoft.com), Microsoft

Axel Nennker (axel.nennker@telekom.de), Deutsche Telekom

Breno de Medeiros (breno@gmail.com), Google

Casper Biering (cb@peercraft.com), Peercraft

Chuck Mortimore (cmortimore@salesforce.com), Salesforce

David Recordon (dr@fb.com), Facebook

Edmund Jay (ejay@mgi1.com), Illumila

George Fletcher (george.fletcher@corp.aol.com), AOL

Hideki Nara (hideki.nara@gmail.com), Takt Communications

John Bradley (ve7jtb@ve7jtb.com), Ping Identity

Johnny Bufu (jbufu@janrain.com), Janrain

Justin Richer (jricher@mitre.org), Mitre

Luke Shepard (lshepard@fb.com), Facebook

Michael B. Jones (mbj@microsoft.com), Microsoft

Nat Sakimura (n-sakimura@nri.co.jp), Nomura Research Institute, Ltd.

Nov Matake (nov@matake.jp), Independent

Pamela Dingle (pdingle@pingidentity.com), Ping Identity

Paul Tarjan (pt@fb.com), Facebook

Roland Hedberg (roland.hedberg@adm.umu.se), Independent

Ryo Ito (ryo.ito@mixi.co.jp), mixi, Inc.

Torsten Lodderstedt (t.lodderstedt@telekom.de), Deutsche Telekom



 TOC 

Appendix B. 通知

Copyright (c) 2013 The OpenID Foundation.

The OpenID Foundation (OIDF) grants to any Contributor, developer, implementer, or other interested party a non-exclusive, royalty free, worldwide copyright license to reproduce, prepare derivative works from, distribute, perform and display, this Implementers Draft or Final Specification solely for the purposes of (i) developing specifications, and (ii) implementing Implementers Drafts and Final Specifications based on such documents, provided that attribution be made to the OIDF as the source of the material, but that such attribution does not indicate an endorsement by the OIDF.

The technology described in this specification was made available from contributions from various sources, including members of the OpenID Foundation and others. Although the OpenID Foundation has taken steps to help ensure that the technology is available for distribution, it takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this specification or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any independent effort to identify any such rights. The OpenID Foundation and the contributors to this specification make no (and hereby expressly disclaim any) warranties (express, implied, or otherwise), including implied warranties of merchantability, non-infringement, fitness for a particular purpose, or title, related to this specification, and the entire risk as to implementing this specification is assumed by the implementer. The OpenID Intellectual Property Rights policy requires contributors to offer a patent promise not to assert certain patent claims against other contributors and against implementers. The OpenID Foundation invites any interested party to bring to its attention any copyrights, patents, patent applications, or other proprietary rights that may cover technology that may be required to practice this specification.



 TOC 

Appendix C. 文書履歴

[[ To be removed from the final specification ]]

-06

  • Fixed #637 removed requirement for hash of at_token and code to be SHA2 in Section 2.1.2.1 and Section 5.2.
  • Added Section 2.5 Access Token Validation.
  • Fixed #620 - Update Section 2.2.5.1 to allow for other token types, but make bearer mandatory to support for implicit clients.
  • Fixed #657 - Update Section 3.3 to say that the sub is sent as the kid if the id_token is encrypted in the request.
  • Added Implementation Considerations section.
  • Fixed #698 - Inconsistent use of articles.
  • Updated Scopes description.
  • Added auth_time definition to ID Token schema.
  • Fixed #655 - Specify UTF-8 as encoding scheme whenever necessary.
  • Renamed the user_jwk Claim to sub_jwk, paralleling the change from user_id to sub.
  • Defined the sub_jwk claim.
  • Clarified that the offline_access scope value MAY NOT be used with the Implicit Client Profile.
  • To remove ambiguity in the self-issued sub computation, changed the text "the concatenation of the key values" to "the concatenation of the bytes of the UTF-8 representations of the base64url encoded key values".
  • Tracked JWK parameter name changes alg -> kty, mod -> n, exp -> e.

-05

  • Fixed #687 - Inconsistency between user_id and prn claims. The fix changed these names: user_id -> sub, user_id_types_supported -> subject_types_supported, user_id_type -> subject_type, and prn -> sub.
  • Fixed #689 - Track JWT change that allows JWTs to have multiple audiences.
  • Fixed #660 - Clarified that returning the sub value from the UserInfo endpoint is mandatory.
  • Fixed #636 - ID Token authorized party claim.
  • Fixed #689 - Add caution about multiple audiences.
  • Fixed #694 - Add login_hint

-04

  • Make it clear that nonce is REQUIRED for implicit
  • RE #607 add example decoded id_token for non self-issued.
  • Fixed #614 - Discovery - 3.2 Distinguishing between signature and integrity parameters for HMAC algorithms. This fix tracks the parameter changes made to the JWE spec in draft-ietf-jose-json-web-encryption-06. It deletes the parameters {userinfo,id_token}_encrypted_response_int. It replaces the parameters {userinfo,id_token,request_object,token_endpoint}_algs_supported with {userinfo,id_token,request_object,token_endpoint}_signing_alg_values_supported and {userinfo,id_token,request_object,token_endpoint}_encryption_{alg,enc}_values_supported.
  • Fixed #666 - JWS signature validation vs. verification.
  • Fixed #682 - Change remaining uses of "birthday" to "birthdate".
  • Referenced OAuth 2.0 RFCs -- RFC 6749 and RFC 6750.

-03

  • Defined means of using a self-issued OP

-02

  • Added preferred_username claim under profile scope
  • Added ID Token section to describe required claims
  • Added section on claim stability

-01

  • Removed claims_in_id_token scope value, per decision on June 15, 2012 special working group call

-00

  • Initial version, based upon Basic Client specification version -17
  • Renamed from Basic Client to Implicit Client, per issue #567
  • Changed verified to email_verified, per issue #564
  • Removed Check ID Endpoint and added ID token signature verification text, per issue #570
  • Changed client.example.com to client.example.org, per issue #251
  • Added claims_in_id_token scope definition to Basic and Implicit, per issue #594
  • Use standards track version of JSON Web Token spec (draft-ietf-oauth-json-web-token)



 TOC 

著者アドレス

  Nat Sakimura
  Nomura Research Institute, Ltd.
Email:  n-sakimura@nri.co.jp
  
  John Bradley
  Ping Identity
Email:  ve7jtb@ve7jtb.com
  
  Michael B. Jones
  Microsoft
Email:  mbj@microsoft.com
  
  Breno de Medeiros
  Google
Email:  breno@google.com
  
  Chuck Mortimore
  Salesforce
Email:  cmortimore@salesforce.com
  
  Edmund Jay
  Illumila
Email:  ejay@mgi1.com