OpenID Connect プラグインのリファクタリング

皆さん、こんにちは。

セキュリティ体制を強化したいと考えており、その一環として、可能な限りシークレット認証情報を使用しないようにする必要があります。
残念ながら、OIDCプラグインは /userinfo エンドポイントにアクセスするためにクライアントシークレット認証情報を必要とし、有効にした状態でフォーラムを設定することができませんでした。

幸いなことに、OIDC仕様は、シークレットトークンを使用する必要がないように定義されています。
id_token フローに従えば、IdPは、IdPに再度問い合わせることなくユーザーを認証するために必要なすべての情報を送信します。

これは、リダイレクトがIdPで設定されており、ベアラートークンが誤った宛先に転送される心配がないため安全です。

OIDCプラグインに id_token フローをサポートするパッチを作成し、ここにプルリクエストを提出しました。

PRはまだ単体テストが必要なため、完全ではありませんが、ほぼ完了しており、Azure AD (Entra ID) で正常に動作することを確認しました。

参考までに、OIDCプラグインのドキュメントはこちらです。

「いいね!」 1

ここでお話しされているのは、サーバー間の通信を必要としない OpenID Connect の “Implicit Flow” だと思われます。そのため、共有シークレットは不要です。代わりに、すべての情報は HTTP リダイレクト経由で送信され、ID トークンは Discovery Document の公開鍵を使用して暗号的に検証されます。

それは問題なく、有効な機能リクエストだと思います。しかし、これは共有シークレットを使用したサーバー間の通信を利用する、現在のプラグインのフローとは大きく異なるシステムです。そのため、ID トークンの暗号検証は不要です。これは、ある点ではよりシンプルですが、他の点ではより複雑です。

重要:プラグインのデフォルト実装を単純に変更することはできません。認可コードフローを使用しているサイトは、それを使い続ける必要があります。私の記憶が正しければ、多くの ID プロバイダーはインプリシットフローをサポートしていません。

そのため、ここには 2 つの進むべき道があると思います。

  1. OIDC プラグインで「インプリシットフロー」のサポートを追加しますが、これはオプトイン機能とします。OpenID Connect gem を Discourse コアの依存関係として導入するプルリクエストは受け入れられない可能性が高いので、現在の戦略内で実装する必要があります。

    discourse-lti (学習ツール連携) プラグインは、LTI プロトコルが OIDC インプリシットフローに基づいているため、参考になるかもしれません。ID トークンのデコードロジックは こちら にあります。

または

  1. インプリシットフローをまったく新しいプラグインとして構築します。この場合、実装に関して好きなように自由に実装できます(ただし、自分で保守する必要があります)。

また、OIDCの「Implicit Flow」はCSRF攻撃やトークン漏洩の表面積を増大させることも注目に値します。

状況によっては依然として意味があると思いますが、OIDCを使用する上で最も推奨される方法は、Authorization Code Flow(Discourseのデフォルト)とPKCE(Discourseではオプション)のようです。

詳細なご返信ありがとうございます!

いくつかの状況では、それでも意味があると思います。しかし、PKCE(Discourseではオプション)を使用したAuthorization Codeフロー(Discourseのデフォルト)が、OIDCを使用するための最も推奨される方法のようです。

これは非常に興味深いですね。PKCEについて、これまで完全に理解していませんでした。Auth0のドキュメントを読んだ限りでは、このフローは(特定の構成では)インプリシットフローの利点(クライアントシークレットなし)を持ち、その欠点はすべて解消されているようです。

これはおそらく、代わりに実行できることでしょうか? /token エンドポイントからクライアントシークレットパラメータを削除するだけで簡単なようです。

そして最終的に、私の主な懸念はクライアントシークレットの要件をなくすことだけです :slight_smile:

これで、以下の構成で動作します。

"DISCOURSE_OPENID_CONNECT_ENABLED": "true",
"DISCOURSE_OPENID_CONNECT_DISCOVERY_DOCUMENT": "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration",
"DISCOURSE_OPENID_CONNECT_CLIENT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"DISCOURSE_OPENID_CONNECT_CLIENT_SECRET": "",
"DISCOURSE_OPENID_CONNECT_VERBOSE_LOGGING": "true",
"DISCOURSE_OPENID_CONNECT_USE_PKCE": "true"

および、コードに以下の変更を加えます。

diff --git a/plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb b/plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb
index 410a88f46dc..e74ee360aae 100644
--- a/plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb
+++ b/plugins/discourse-openid-connect/lib/omniauth_open_id_connect.rb
@@ -73,6 +73,11 @@ module OmniAuth
              )
           options[:client_options][:auth_scheme] = :request_body
         end
+
+        # PKCE を使用し、かつ client_secret が空の場合は、request_body 認証スキームを使用します。
+        if options[:pkce] && options[:client_secret].empty?
+          options[:client_options][:auth_scheme] = :request_body
+        end
       end
 
       def request_phase

リダイレクト URI は、Azure コントロール パネルで次のように構成されています。