SalesforceをOPにしてOpenID Connectによるソーシャルログインが出来るということなので試してみた。

せっかくなのでSalesforceユーザではなく、コミュニティユーザでソーシャルサインオンをやってみます。

RP側はPython/Flaskで。

 

1. 接続アプリケーションの設定

いつもの接続アプリケーション。

今回はaccess_tokenを使ってUserInfo以外のAPIを叩かないのでid openid refresh_tokenをscopeに入れました。

connectapp-oidc

 

2. RP側プログラムの作成

pythonのバージョンは3.3系。暗号化ライブラリとしてPyCryptoを使ってます。

 

 

index.html

 

 

最初は通常のOAuth2.0と同じ。

scopeはid openid refresh_tokenを指定。

idはuserinfo取得用、openidはid_token取得用、refresh_tokenはJWS検証用

※本当はcodeのハッシュを検証に利用するのですが、現時点ではrefresh_tokenのハッシュになっているっぽいです。なのでコードもrefresh_tokenになっていますが、issueが解決されたらcodeのハッシュを取るようにしてください。

 

CSRF対策にSessionと紐付いたstate値とnonce値を入力。

(nonceはAuthorization Code Flowでは入れる必要は無いです。Implicit Flowでは必須。)

 

callbackで戻ってきたら、state値が合っているかを検証。

合っていればOAuth2.0と同じくcode値を使ってid_token+access_tokenを取得します。

 

レスポンスは以下のようになります。

 

取得したid_tokenはJWT形式なのでピリオド区切りで順にヘッダ、クレームセット、署名部分にそれぞれ分解。

ヘッダとクレームセットはjsonをbase64エンコードしたものなのでデコードします。

ヘッダ↓

クレームセット↓

 

クレームセット部分を使って現在のタイムスタンプ値とexp値を比較して期限が切れていないかとnonce値が合っているかをチェックします。

合っていればhttps://login.salesforce.com/id/keysに表示されている公開鍵情報からヘッダのkidに対応する鍵を取得します。

 

id-keys

 

対象の公開鍵を使って署名検証を行いOKであれば初めて認証成功となります。

Salesforceは現時点で署名方式が”RS256″なので

Sha256Hash(JWTヘッダ+ “.” + JWTクレームセット) = RSADecrypt(JWS)

となればOK。

 

ちなみに、一応access_tokenのレスポンス内のsignature検証もしていてこちらは

Sha256(id値 + issued_at値) = signature値

となっていればOK。

 

上記の処理内でAuthorizatoin Code FlowでClient Secretが機密にされているという理由で

検証不要な項目もあると思いますが、全部やろうとするとこんな感じになります。

 

あと、ソースコードは各エンドポイントやらissuer値がベタ書きですが、本当は以下のDiscoveryEndpointの情報を参照します。

https://login.salesforce.com/.well-known/openid-configuration

 

3. 実際の動き

flaskアプリを起動してhttp://localhost:5000とかにアクセスすると認証用リンクが出るのでクリックします。

auth-link

 

コミュニティ用のログイン画面が出るのでログインします。

 

oidc_login

いつもの認可画面

authorization_screen

許可するとリダイレクトしてid_tokenとaccess_tokenをして検証やら何やらをしてOKであれば画面にユーザ名が出ます。

successful-login-oidc

 

こんな感じで基本的にOAuth2.0に色々な検証が加わったものがOpenID Connectなので

OpenIDやSAMLよりかは設定や検証がだいぶ楽になってます。

個人的にハマったのは公開鍵部分ぐらいで、これも暗号化の仕組みわかってて慣れてる人からしたら

大したものじゃないと思います。

 

SFDCがOpenID ConnectのOPになれるということは既存アプリケーションと連携しやすくなるということで、

同業種の別の会社のWebサービスと自社のSFDCコミュニティがソーシャルサインオンで連携できるとか

そういうこともやりやすくなるなーと思ったり。