force.comのOAuthをJWT投げ入れるだけで出来るらしい(ヘルプ)ので、試してみた。

 

JWT投げ入れるだけでOAuth2.0でアクセス許可を得られると言っても

対象ユーザが既に認可しているか、管理者が事前にユーザを承認していなければ利用できません。

つまり、refresh_tokenの代替手段になります。

 

JWTではコンシューマの秘密(client_secret)の代わりに

x509証明書をアプリに登録して、Webアプリ側で登録したx509に基づく秘密鍵を使って

JWTのSignature生成を行うことで、なりすまし等の不正アクセスを防ぎます。

 

ということで、実際に進めてみます。

1. x509証明書を作成

linuxとかでこんな感じに作成します。

 

2. 接続アプリケーションの作成

サンプル↓

接続アプリケーション  OpenIDConnect ~ Salesforce - Developer Edition

 

デジタル署名を使用にチェックを付けて、ファイルには1で作成した証明書(server.crt)をアップロード。

また、選択したOAuth範囲に”ユーザに代わっていつでも要求を実行”を必ず入れてください。

これを入れないと、認可しても以下のエラーが出てトークンが発行できなくなります。

 

それ以外は、通常のOAuthアプリと同様に作成すればOKです。

 

3. Webアプリ側でJWTを生成する

JWTヘッダは{“alg”:”RS256″}

JWTクレームセットは

“iss” → SFDCアプリケーションのClientID
“prn” → SFDCのユーザ名
“aud” → https://login.salesforce.com or https://test.salesforce.com
“exp” → 発行したJWTの有効期限タイムスタンプ(5分以内)

で生成します。

 

pythonのサンプルはこんな感じ。

 

4. 既に認可しているユーザに対して生成したJWTをSalesforceに投げてaccess_tokenを取得

認可したユーザが存在しない場合は、通常のOAuth2.0のフローで事前に認可するか

接続アプリの設定で許可されているユーザを”管理者が承認したユーザは事前承認済み”にして、

対象ユーザのプロファイルを接続アプリに設定する必要があります。

接続アプリケーション  OpenIDConnect ~ Salesforce - Developer Edition (1)

 

認可されていれば、対象ユーザに対するJWTを3で作成し

https://[sfdcのドメイン]/services/oauth2/tokenに

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=[JWT token]

をPOSTしてあげればレスポンスとして

が返って来ます。

 

このフローではrefresh_tokenは返って来ません。

JWTが生成できればいつでもAccessTokenを取得できるので

ユーザ名とパスワードが予めわかっているパターンと同様にユーザの認証操作が必要ないためです。(多分)

 

 

JWTベアラートークンフローでのエラー

検証中は以下のエラーが出たので、簡単にご紹介。

{“error_description”:”expired authorization code”,”error”:”invalid_grant”}

→アプリ側サーバのクロックがズレているか、expタイムスタンプが5分以上の値に設定されていたり

とにかくexpタイムスタンプが不正の場合に発生するエラー。

 

{“error_description”:”invalid client credentials”,”error”:”invalid_client”}

→RSA/SHA256じゃなくて、RSAでSignature作ってたらこのエラーでハマりました。

client_idしかクレデンシャル無いのに何でだ!って思ってけど、”証明書のキーが不正ですよ”っていうエラーみたい。

 

{“error_description”:”user hasn’t approved this consumer”,”error”:”invalid_grant”}

→上述したとおり、refresh_tokenの許可をアプリ側で設定していない

あるいはユーザ自身が認可していないときに発生するエラー。

管理者がユーザを承認する場合は、対象ユーザのプロファイルが、接続アプリに対して許可されていればOK。

 

JWTベアラートークンフローの利点と活用法

・refreshトークンの管理が不要

・ユーザIDだけで認可可能

が大きいのかなと。

 

特に後者のユーザIDだけで認可可能という特性とfrontdoor.jspでログインさせる機能を使うと

シングルサインオン的な実装が容易になります。

管理者側でユーザ承認するアプリであれば、ログインIDだけで認可画面無しにログインできるし。

ログインIDだけで認証って言うと大丈夫なの?って感じだけど

セキュリティはx509証明書で担保しているから大丈夫なんですかね~。