OpenID Connect Provider (OP or IdP) 開発とデバッグのために、いろいろな投げつけをするサンプル。
See https://www.nslabs.jp/identity-samples.rhtml
OmniAuth を使っていたのを止め、実装しなおした。
OpenID Connect Provider (OP) は Google と Yahoo JP, それに Rails OpenID Connect IdP AS
このサンプルは, Just-in-time User Provisioning (JIT Provisioning) の例にもなっている。あらかじめユーザ登録されていなくても、シングルサインオンで回ってくるユーザ情報で自サイトにも登録する。
(1) Authorization Code Flow with PKCE によるログイン
- ✅ Google 実装すみ
- ✅ Entra ID (旧 Azure AD) 実装すみ
- ✅ Rails OpenID Connect IdP AS 実装すみ
Yahoo! JAPANPPID しか返さず、認証 (本人確認) 目的には使いがたい
生の OAuth 2.0 の Implicit Flow を「認証」に使おうとすると、すごく巨大な穴が空く。OpenID Connect の Implicit Flow はその穴を塞いでいるので問題ない。しかし、巷の解説では混同しているものが非常に多い。
2024 年6月現在, OAuth 2.1 に向けた改訂作業が進んでいる。文言もだいぶ落ち着いてきて、もうすぐ最終化か? The OAuth 2.1 Authorization Framework Internet-Draft OAuth 2.1 は, 穴を塞ぐのではなく, 単に Implicit Flow を廃止にした。
今後は "public clients" も Authorization Code Flow でカバーしなければならず、Mobile & Desktop Apps では, nonce
必須, PKCE 必須。
(2) Implicit Flow によるログイン
OpenID Connect Implicit Client Implementer's Guide 1.0 を実装。
- ✅ Google 実装すみ
- ✅ Entra ID (旧 Azure AD) 実装すみ. 管理画面で Implicit Flow を有効にしている場合のみ (デフォルト無効)。
- ✅ Rails OpenID Connect IdP AS 実装すみ
omniauth_openid_connect
v0.4.0 は, response_type=id_token
しかサポートしていない。これはアクセストークンが得られず、妥当ではない。
仕様では, IdP は, アクセストークンを発行しない場合に限って id_token
レスポンスにユーザ情報を含めることになっている (Core 1.0: section 5.4) が、Yahoo! JAPAN ID 連携はこの仕様に適合せずユーザ情報を含めないので、動作しない。
ポータビリティのため, クライアントから id_token token
を投げたうえで, UserInfo エンドポイントからユーザ情報を取得する。
(3) OpenID Connect RP-Initiated Logout 1.0 によるシングルログアウト (SLO)
IdP が end_session_endpoint
をサポートしている場合、利用可能。
Azure AD v2 は、主に企業ユースで、シングルログアウトを必要とするユースケースがあるので、サポートしている。
シングルログアウトは, OpenID Connect (や他の OAuth2 上に作られたプロファイル) を使ったユースケースでは, 必要にならないことが多い。各サービス (Relying Party 側) がログアウトするときに Google とかもログアウトしたら、逆に困る。
-
Requirements
- Ruby >= 3.0
- Ruby on Rails v6.1
- openid_connect
このサンプルでは認証フレームワークは Sorcery を使っているが、何でも構わない. OmniAuth はメジャーだが、屋上屋になるため、omniauth-openid-connect は使用しない。
- Configuration
config/database.yml.sample
をdatabase.yml
にコピーし, 適宜修正.
$ rake db:migrate
config/auth/google.yml.sample
とconfig/auth/yahoojp.yml.sample
ファイルをコピーし, 適宜、編集してください。
client_id
を設定してください。
Implicit Flow では client_secret
を保存してはなりません。
- 実行!
Redirect URI は次のとおり;
http://localhost:3030/auth/google_codeflow/callback
http://localhost:3030/auth/google_implicit/callback
http://localhost:3030/auth/connect_op_sample/callback
Authorization Code Flow は, クライアントが client secret を安全に保持できない状況では、使ってはならなかった。 Implicit Flow は, このような状況でも使えるように, client secret を必要としない (保存してはならない)。
"response_type"
value は, id_token token
とする。id_token
は, Self-Issued OpenID Provider でのみ使われる。
Implicit Flow では, RP から OP に対する直接の問い合わせとレスポンスではなく, Webブラウザを介して id token と access token を得る。そのため、これらのトークンが正当なものか、必ず、検証しなければならない。
次のようなコードになる;
def decode_token response, nonce
id_token = OpenIDConnect::ResponseObject::IdToken.decode(
response['id_token'],
idp_public_keys)
r = id_token.verify!({
:issuer => config.issuer,
:nonce => nonce,
:client_id => options[:client_id]})
# さらに, access token を検証 (validation) しなければならない.
jwt = JSON::JWT.decode response['id_token'], :skip_verification
hash_length = jwt.alg[2, 3].to_i
if id_token.at_hash !=
left_half_hash_of(response['access_token'], hash_length)
raise "invalid access_token!!"
end
return id_token, response['access_token']
end
OpenID Foundationのガイドラインに沿ったRailsでのOIDC Implicit Flow実装
- Ruby on Rails による実装.
- OP (IdP) は Azure AD.
- アクセストークンの検証が必要だが、そもそも取得していない?
Rails+omniauth-google-oauth2でGoogleログイン(devise無し)
- omniauth-google-oauth2 のような IdP ごとに別パッケージを使うのではなく, OpenID Connect で統一的にシングルサインオンしたほうが、穴を作らない、と言う意味でもいい。
- Devise を使わないのはいいが、この例は, 自作のログインコード、ログアウトコードが雑すぎて、これを参考にするのはむしろ有害。こういう雑なサンプルは、止めてほしい。