カスタムSSOがパラメータとしてsecure_sessionを追加した後に機能しない

こんにちは!当社は、Discourse がログイン処理やアカウント作成に利用できるよう、自社のログイン情報をパッケージ化するためのカスタム SSO プラグインを作成しました。v2.7.0beta4 から、新しいパラメータ「secure_session」を提供していないことによるエラーが発生するようになりました。このパラメータの形式や内容に関する詳細をどこにも見つけることができません。この更新に関する追加ドキュメントは存在しますか?

よろしくお願いいたします。

「いいね!」 1

表示されている正確なエラーメッセージはわかりますか?私の理解では、Discourse は現在、SSO の nonce パラメータをユーザーのセッションに紐付けています。つまり、アプリがバックグラウンドで /session/sso へのリクエストを行って nonce を生成している場合、その nonce は無効になります。これがあなたの直面している問題である可能性があります。

「いいね!」 2

もちろん、APM で表示されているエラーのスタックは以下の通りです:

ArgumentError: missing keyword: :secure_session
…r/www/discourse/app/models/discourse_single_sign_on.rb:   28:in `initialize'
               /var/www/discourse/lib/single_sign_on.rb:   65:in `new'
               /var/www/discourse/lib/single_sign_on.rb:   65:in `parse'
…ourse_account_auth/lib/service_gateway_current_user.rb:   72:in `upsert_sso_record'
…ourse_account_auth/lib/service_gateway_current_user.rb:   53:in `create_sso_record'
…ourse_account_auth/lib/service_gateway_current_user.rb:   28:in `current_user'
                 /var/www/discourse/lib/current_user.rb:   36:in `current_user'

service_gateway_current_user.rb は、当社のプラグインの一部であり、「Service Gateway」ヘッダー(当社の社内システムへのログイン状態を判定するための内部構造)に基づいて DiscourseSingleSignOn に送信するペイロードを構築する役割を果たしています。

スタックの該当部分の説明:

  • 当社の current_user 関数は、ヘッダーを使用して external_id がヘッダー内のユーザー ID と一致する SingleSignOnRecord を検索します。一致しない場合は、create_sso_record セクションに進みます。
  • create_sso_record はハッシュ { external_id: sg_headers[:user_id], email: sg_headers[:email] } を作成し、それを upsert_sso_record 関数に送信します。
  • upsert_sso_record はそのハッシュ(以下のコンテキストでは payload)を受け取り、DiscourseSingleSignOn オブジェクトの作成を試みます:
def upsert_sso_record(payload)
  encoded_query = Base64.encode64(payload.to_query)
  sig = OpenSSL::HMAC.hexdigest('sha256', ENV['SSO_SECRET'], encoded_query)
  sso = DiscourseSingleSignOn.parse({ sso: encoded_query, sig: sig }.to_query)

  if SiteSetting.verbose_sso_logging
    Rails.logger.warn("Verbose SSO log: Started SSO process\n\n#{sso.diagnostics}")
    Rails.logger.warn("SSO Payload:\n\n#{payload}")
  end

  begin
    user = sso.lookup_or_create_user(@request.ip)
  rescue ActiveRecord::RecordInvalid => ex
    Rails.logger.error "Unable to find/create sso user #{ex}"
  end
  user
end

この関数の 3 行目にある parse の呼び出しが問題の発生箇所のようです。オブジェクトの initialize を試みると、期待される secure_session の値が存在しないことが原因です。

「いいね!」 2

バンプ!私もこれについて気になっています!

discourse_connect_csrf_protection という新しいサイト設定を false に設定することで、ご自身の環境での問題が解決するかどうか気になります。このサイト設定は非表示になっているため、Rails コンソールから設定する必要があります。詳細については、以下のトピックの返信をご覧ください:https://meta.discourse.org/t/discourseconnect-flow-no-longer-functions/182844。

残念ながら、その新しい設定だけでは解決しないと思います。コード内部では、実際に使われていなくても、secure_session オブジェクトを渡す必要があります。

一般的には、認証プラグインには DiscourseConnect の実装をオーバーライドするのではなく、公式のフック を使用することを推奨しています。

プラグイン全体を見ないことには確実なことは言えませんが、secure_sessionnil を渡してみることをお勧めします。それに加え、新しいサイト設定を切り替えることで、動作が少し改善するかもしれません。

「いいね!」 5

v2.7.0.beta4 のコードをさらに詳しく調べてみたところ、ApplicationControllersecure_session の定義があることがわかりました。プラグインのコードを以下のように変更すると、Staging 環境で動作するようです。

sso = DiscourseSingleSignOn.parse({ sso: encoded_query, sig: sig }.to_query, secure_session: secure_session)

…本当にそれだけ簡単なのでしょうか?:thinking:

それは動作するはずです。セキュアなセッションは通常、ApplicationController のそのメソッドから取得されます。:slight_smile:

「いいね!」 2

素晴らしい!この問題をラバーダッキングで共有してくれてありがとう。:duck: :metal:

「いいね!」 2