「[[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。 -[[戻る>JWTとOAuth2.0#f5007063]] * 目次 [#m5c50d67] #contents *概要 [#a089122f] -[[OAuth]] 2.0 を拡張するアサーションの仕様 -[[RFC 7521>#pae256bf]], [[7523>#i523cb7d]]によって構成されている。 -[[JWT]](JWS) Bearer Tokenを[[アサーション>トークン#xbeb945f]]として使用して、~ OAuth 2.0のAccess Tokenを要求する方法の定義。 **クライアント認証の有無 [#y8528205] クライアント認証はオプション。 -クライアント認証しない場合、 --事前に信頼関係を構築できるシステムからユーザ承認手順なしに直接Access Tokenを取得する。 --[[GoogleやMicrosoft、SalesforceなどのWebAPI認証の方式として採用されている>#xd03a507]]。 -クライアント認証する場合、 --Authorization Codeグラント種別でAccess Tokenを取得する(シナリオにあっている?) --Client Credentialsグラント種別でAccess Tokenを取得する **[[用例>#xd03a507]]の代表的なフロー [#n0c5feb0] -[[用例>#xd03a507]]ではクライアント認証を使用していないケースが多いが、 >どうも、 --クライアントの[[Self-Issued Assertion>#n8fdd9f7]]で、 --クライアントと事前に鍵交換して署名するので、 >クライアント認証をしないパターンが採用されているらしい。 -フロー --[[JWT]](JWS)作成のための証明書を生成 or 取得する。 --証明書を登録する。 ---Client側(秘密鍵) ---Resource Server側(公開鍵) --Clientで[[JWT]](JWS)を署名し、Resource Serverにリクエスト、 --Resource Serverで[[JWT]](JWS)を検証し、Access Token(Bearer Token)をレスポンス。 --Clientから、Access Token(Bearer Token)を使用してResource Serverにアクセスする。 *仕様(7521) [#pae256bf] -単体では利用できず、[[RFC 7522, 7523のサブ仕様>#c65d5829]]の共通部分を抽象化した仕様。 -ClientとResource Serverを統合するような状況下での利用が想定されている。 --Resource Ownerとしてのエンド・ユーザの介入を必要としない。 --client_secretを必要としない(Client Credentialsグラント種別の)代替メカニズム。 **フレームワーク [#v20f3211] ***Assertion Created by Third Party [#vf7e7da7] STSによってアサーションを取得する。 -フロー Relying Party Client Token Service | | | | | 1) Request Assertion | | |------------------------>| | | | | | 2) Assertion | | |<------------------------| | 3) Assertion | | |<-------------------------| | | | | | 4) OK or Failure | | |------------------------->| | | | | | | | -WS-Trust [OASIS.WS-Trust]などで利用されている。 ***Self-Issued Assertion [#n8fdd9f7] ローカルでアサーションを作成する。 -フロー Relying Party Client | | | | 1) Create | | Assertion | |--------------+ | | | | | 2) Assertion | | |<-------------+ | 3) Assertion | |<-------------------------| | | | 4) OK or Failure | |------------------------->| | | | | **アサーション [#h34941bb] これを使って[[アクセストークン・リクエスト>#a82c2f7a]]する。 ***文脈上 [#i1c8aa27] この文脈上でのアサーションは、 -Authorization Serversは、 --一般的に認可付与の短命表現で、~ アサーションの有効期間を越えるアクセストークンを発行すべきでない。 --アサーション許可要求に応答して ---リフレッシュトークンが発行せず、 ---アクセストークンを短い寿命で発行する。 -Clientは、 --同じアサーションを使用して新しいアサーションを要求したり、 --有効・若しくは新しいアサーションを使用して、~ 期限切れのアクセストークンをリフレッシュしたり、 >できる。 ***タイプ [#h0cefaa0] -Bearer Assertions --本仕様に適したタイプのアサーション --アサーションを所有しているすべてのエンティティは、 ---関連するリソースへのアクセスを取得するために(暗号鍵の所持を証明することなく)アサーションを使用できる。 ---誤用を防止するために、アサーションは、保管・移送における露見から保護する必要がある。 ---権限のない当事者にアサーションを漏らさないために、安全な通信チャネルを使用。 -Holder-of-Key Assertions --本仕様に適さないタイプのアサーション --アサーションを提示するエンティティは、 ---関連するリソースにアクセスするには、 ---追加の暗号資料の所持を証明する必要がある。 --従って、 ---Authorization Server(STS)は、アサーションにキー識別子をバインドする。 ---Clientは、アサーションを提示するときに、~ その識別子に対応するキーを知っていることをResource Serverに示す必要がある。 --鍵所有者アサーションシステムのベースラインとして使用することができるが、場合によっては、以下が必要になる。 ---(秘密鍵の所有証明をサポートするための)追加のメカニズム ---セキュリティモデルの変更(例えば、 オーディエンスの要件を緩和するため)。 ***クレームセット [#p574a133] 以下のクレームが必要。 [[IDトークン>OpenID Connect#ofb73c59]]が参考になる。 -必須 --Issuer ---[[Assertion Created by Third Party>#vf7e7da7]]の場合、~ Authorization Server(STS)のIDになる。 ---[[Self-Issued Assertion>#n8fdd9f7]]の場合、~ Audienceの値と同じになる。 --Subject~ ---[[サーバ信頼セキュリティ モデル]]~ Audienceの値と同じになる。 ---[[ベース クライアント セキュリティ モデル]]~ Resource OwnerのID --Audience~ Resource ServerのID = client_idの値 --Expires At -オプション --Issued At --Assertion ID ---アサーションの一意の識別子。他のエンティティが誤って同じ識別子を割り当てないことを保証しなくてはならない。 ---ワンタイム使用アサーションのメッセージ重複排除を必要とする実装によって使用される可能性がある。 ***署名 [#h4756c73] -署名またはメッセージ認証コードを生成する -アルゴリズムは任意(この仕様の範囲外) **パラメタ [#aed15519] -TLS(Transport Layer Security)が必須。 -アサーションの認可付与としての使用を定義。 ***grant_type [#eef72461] -クライアント認証なし~ urn:ietf:params:oauth:grant-type:* --urn:ietf:params:oauth:grant-type:saml2-bearer --urn:ietf:params:oauth:grant-type:jwt-bearer -クライアント認証あり --grant_type=client_credentials版 --grant_type=authorization_code版~ authorization_codeなのでcodeも必要(code=XXXX) ***assertion [#k4e1e004] [[RFC7523>#i523cb7d]]のアサーションを参照。 ***scope [#x0b3b1ff] -要求された範囲は、[[OAuth 2.0 [RFC6749]>OAuth#v698197b]]の3.3節に記述されているとおり。 -スターターでQueryStringにscopeが必要であれば指定が必要だと思うが、結果として、アサーションに同梱されれは良い。 ***client_id [#c3be6c2e] -パラメタに依存するクライアント認証の形式が使用されている場合にのみ必要。 -クライアント認証の用途では不要 --クライアント認証なし~ 不要 --クライアント認証あり~ 不要(クライアント認証がある場合、クライアントがアサーションで識別される) ***client_assertion_type [#y8e7d02b] -クライアント認証なし~ 不要 -クライアント認証あり~ urn:ietf:params:oauth:grant-type:* --urn:ietf:params:oauth:grant-type:saml2-bearer --urn:ietf:params:oauth:grant-type:jwt-bearer ***client_assertion [#d6680711] -クライアント認証なし~ 不要 -クライアント認証あり~ [[RFC7523>#i523cb7d]]のアサーションを参照。 **リクエスト・レスポンス [#u7d06247] ***アクセストークン・リクエスト [#a82c2f7a] -クライアント認証なし --ヘッダ POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded --ボディ grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3AX-bearer& assertion=SAML2 or JWT assertion -クライアント認証あり --grant_type=authorization_code版(シナリオにあっている?) ---ヘッダ POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded ---ボディ grant_type=authorization_code& code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4& client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3AX-bearer& client_assertion=SAML2 or JWT assertion --grant_type=client_credentials版 ---ヘッダ POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded ---ボディ grant_type=client_credentials& client_assertion_type=urn%3Aietf%3Aparams%3Aoauth %3Aclient-assertion-type%3AX-bearer& client_assertion=SAML2 or JWT assertion ***エラー・レスポンス [#u137f3a9] -[[OAuth 2.0 [RFC6749]>OAuth#v698197b]]で定義されているエラー応答を構成 --https://tools.ietf.org/html/rfc6749#section-5.2 -クライアント認証なし~ アサーションが有効でないか期限が切れた場合、 --Authorization Serverは、 ---"error"パラメータの値は "invalid_grant"エラーコードでなければならない。 ---"error_description"または "error_uri"パラメータを使用して、~ アサーションが無効とみなされた理由に関する追加情報を含めることができる。 --例 ---ヘッダ HTTP/1.1 400 Bad Request Content-Type: application/json Cache-Control: no-store ---ボディ { "error":"invalid_grant", "error_description":"Audience validation failed" } -クライアント認証あり --Authorization Serverは、 ~ アサーションが有効でないか複数のクライアント認証メカニズムが使用されている場合、 ---"error"パラメータの値は "invalid_client"エラーコードでなければならない。 ---"error_description"または "error_uri"パラメータを使用して、~ クライアントのアサーションが無効であると考えられた理由に関する追加情報を含めることができる。 --例 ---ヘッダ HTTP/1.1 400 Bad Request Content-Type: application/json Cache-Control: no-store ---ボディ { "error":"invalid_client" "error_description":"assertion has expired" } **セキュリティに関する考慮事項 [#c569fe33] -[[RFC 7522, 7523>#c65d5829]]などを使用すれば、大方問題ない。 -その他、 --SSL/TLSを使用する。 --Assertion IDを実装する。 *仕様(7523) [#i523cb7d] [[RFC 7521>#pae256bf]]のアサーションに[[JWT(JWS)アサーション>#s121ce30]]を使用したもの。 **[[JWT]](JWS)アサーション [#s121ce30] これを使って[[アクセストークン・リクエスト>#yf148536]]する。 ***ペイロード(クレームセット) [#od912bf1] -[[コチラ>#p574a133]]を参考に、 --必須(MUST) ---"iss" (issuer) claim ---"aud" (audience) claim ---"sub" (subject) claim ---"exp" (expiration time) claim~ --してもよい(MAY) ---"iat" (issued at) claim ---"jti" (JWT ID) claim~ = Assertion ID ---"nbf" (not before) claim~ トークンを受け入れてはならない前の時間を識別する。 -クライアント認証を行う場合、~ [[JWT]](JWS)アサーションを使用するが、その仕組み自体は定義されていない。 --と言いつつ、Subjectにclient_idを設定するという記述がある。 --また、[[用例>#xd03a507]]では、クライアントと鍵交換+署名で代替されているもよう。 ***[[JWT]](JWS)の例 [#f5ac0fc6] -以下、RFCの[[JWT]](JWS)~ --よくよく確認すると、 ---ヘッダが微妙。 ---scopeをどうやって渡すのか。 ---URLはなに?(Scheme?) --ヘッダ {"alg": "ES256"、 "kid": "16"} --ペイロード { "iss":"https://jwt-idp.example.com", "sub":"mailto:mike@example.com", "aud":"https://jwt-rp.example.net", "nbf":1300815780, "exp":1300819380, "http://claims.example.com/member":true } -以下、Googleの[[JWT]](JWS)。 --よくよく確認すると、 ---subが無かったりする。 ---scopeは当然ココだが、RFC中に明記が無い。 --ヘッダ { "alg": "RS256", "typ": "JWT" } --ペイロード { "iss":"サービスアカウントのメールアドレス", "scope":"利用するAPIのスコープ", "aud":"https://www.googleapis.com/oauth2/v3/token", "exp":"トークンの有効期限To", "iat":"トークンの有効期限From", } **パラメタ [#jab8a61d] -[[仕様(7521)のパラメタ>#aed15519]]と同じ。 -client_assertionだけ、以下のような注釈有リ。 --1つの[[JWT]](JWS)、複数の[[JWT]](JWS)を含んではならない。 **リクエスト・レスポンス [#ne5367ec] ***アクセストークン・リクエスト [#yf148536] -クライアント認証なし --ヘッダ POST /token.oauth2 HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded --ボディ grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer& assertion=...JWS... -クライアント認証あり --ヘッダ POST /token.oauth2 HTTP/1.1 Host: as.example.com Content-Type: application/x-www-form-urlencoded --ボディ grant_type=authorization_code& code=n0esc3NRze7LTCu7iYzS6a5acc3f0ogp4& client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer& client_assertion=...JWS... ***エラー・レスポンス [#n2b1c5ca] [[仕様(7521)のエラー・レスポンス>#u137f3a9]]と同じ。 *参考 [#uea38a81] **RFC 7521, 7522, 7523 [#c65d5829] -RFC 7521 - Assertion Framework for~ OAuth 2.0 Client Authentication and Authorization Grants~ https://tools.ietf.org/html/rfc7521 --RFC7522(SAMLアサーション) ---RFC 7522 - Security Assertion Markup Language (SAML) 2.0 Profile~ for OAuth 2.0 Client Authentication and Authorization Grants~ https://tools.ietf.org/html/rfc7522 --RFC7523(JWTアサーション) ---RFC 7523 - JSON Web Token (JWT) Profile~ for OAuth 2.0 Client Authentication and Authorization Grants~ https://tools.ietf.org/html/rfc7523 **用例 [#xd03a507] ***Googleの例 [#pe004c1a] 以下を見ると、 -C#とCoreTweetを使って簡単にTwitterへツイートするbotを作る - 酢ろぐ!~ http://blog.ch3cooh.jp/entry/20140808/1407464147 --Google Analytics API を使って前日の PV を取得するコードを C# で書いてみた - しばやん雑記~ http://blog.shibayan.jp/entry/20140803/1407059293 通常の[[OAuth]] 2.0の -[[Authorization Codeグラント種別>OAuth#yfeb403d]] -[[Implicitグラント種別>OAuth#m5c2d510]] 以外に、 [[クライアント証明書(pfx形式の電子証明書)>証明書#sd119f77]]を使って、~ サービスアカウントで認証する方法がある模様。 ちなみに、ここでは、Google.Apis.Analytics Client Libraryに~ 処理がラッピングされていたため。詳細が不明だったが、 以下を見ると、このClient Libraryの中では、[[JWT]]が使用されている模様。 -JWTを使ってGoogleAPIのアクセストークン取得する - Carpe Diem~ http://christina04.hatenablog.com/entry/2015/06/04/224159 -IdM実験室: [JWT/OAuth]Service Accountを使ってGoogle APIを利用する --http://idmlab.eidentity.jp/2015/01/jwtoauthservice-accountgoogle-api.html --http://idmlab.eidentity.jp/2015/01/jwtoauthservice-accountgoogle-api_5.html これが、 >「JWT bearer token authorizationグラント種別」 の用例である模様。 -GoogleのOAuth 2.0実装からみえたClientの扱い - r-weblife~ http://d.hatena.ne.jp/ritou/20121104/1352036133 上記のサイトには、 >Service Accounts = JWT Bearer Token Profile であることが明記されている。 ***Microsoft ([[AzureAD>Microsoft Azure Active Directory]]) の例 [#vdf678b9] [[Google>#pe004c1a]]と同様に、以下を見ると、 -Azure AD : ログインをしない Backend Server-Side アプリの開発 (Daemon など) – Tsmatz~ https://blogs.msdn.microsoft.com/tsmatsuz/2015/04/09/azure-ad-backend-server-side-deamon-service/ -Azure ADに登録されているAPI用のアクセストークンをJWTで取得するには | hrendoh's memo~ http://blog.hrendoh.com/active-directory-dotnet-daemon-certificate-credential/ --Authenticating to Azure AD in daemon apps with certificates | Microsoft Azure~ https://azure.microsoft.com/ja-jp/resources/samples/active-directory-dotnet-daemon-certificate-credential/ 通常の[[OAuth]] 2.0の -[[Authorization Codeグラント種別>OAuth#yfeb403d]] -[[Implicitグラント種別>OAuth#m5c2d510]] 以外に、 >「JWT bearer token authorizationグラント種別」 をサポートしている模様。 ただし、処理は、[[ADAL(Active Directory Authentication Library)>https://docs.microsoft.com/ja-jp/azure/active-directory/develop/active-directory-authentication-libraries]]~ にラップされているため[[JWT]]作成処理の詳細などを見ることは出来ない。 -active-directory-dotnet-daemon-certificate-credential/Program.cs~ at master · Azure-Samples/active-directory-dotnet-daemon-certificate-credential~ https://github.com/Azure-Samples/active-directory-dotnet-daemon-certificate-credential/blob/master/TodoListDaemonWithCert/Program.cs ***Salesforceの例 [#w40dd954] 以下のQiita記事を参照すると、Salesforceは、 -OAuth 2.0 JWT べアラートークンフロー -OAuth 2.0 SAML ベアラーアサーションフロー の2つのフローをサポートしている模様。 -OAuth2 JWT Bearer Token フローを使ってSalesforceへアクセスする - Qiita~ http://qiita.com/stomita/items/4542ce1b48e5fa849ef1 --help.salesforce. ---OAuth 2.0 JWT べアラートークンフロー~ https://help.salesforce.com/articleView?id=remoteaccess_oauth_jwt_flow.htm&language=ja&type=0 ---OAuth 2.0 SAML ベアラーアサーションフロー~ https://help.salesforce.com/articleView?id=remoteaccess_oauth_SAML_bearer_flow.htm&language=ja&type=0 >原理はほぼ同じで、[[SAML]]より[[JWT]]のほうが動作環境的な制約は少ないとのこと。 ---- Tags: [[:認証基盤]], [[:クレームベース認証]], [[:OAuth]]