既存ユーザーベースでのSAML導入

現在の Discourse のインストールでは、新規ユーザーの登録が無効化されており、LDAP プラグイン(https://github.com/jonmbake/discourse-ldap-auth)を介してログインを行っています。そのため、多くの社内ユーザーは既に異なるコンテンツを作成した状態で存在しています。

Okta と連携しているフローを統合するため、SAML へのインストール/移行を依頼されました。プラグイン(https://github.com/discourse/discourse-saml)を DISCOURSE_SAML_AUTO_CREATE_ACCOUNT: true オプション付きでインストールしました。要件は、ユーザーが存在しない場合は作成し、既存ユーザー(以前 LDAP で作成された場合など)の場合は同じユーザーを再利用することです。しかし、現在の動作では、既存のユーザー名に対して新規ユーザーの作成を試みるため、当然ながらエラーが発生します。自動作成オプションを無効にすると、ユーザー名が正しく入力済みですが、競合を避けるために数値プレフィックスが付いた登録情報編集ポップアップが表示されます。これは私のケースでは選択肢になりません。

何かご提案はありますでしょうか?

もしかするとこの古い投稿が関連しているかもしれませんが、回答はついていません。
https://meta.discourse.org/t/verify-if-user-is-already-logged-sso-with-saml2-discourse-saml/73213
(投稿にリンクを 2 つ以上含めることができないため、申し訳ありません)

あらかじめありがとうございます。
AB

通常、ユーザーはメールアドレスでマッチングされます。LDAP と SAML は同じメールアドレスを使用しないのでしょうか?

メールアドレスは同じようです。おそらく、SAML ペイロードに含まれている内容を確認する必要があります。

ヒントをありがとうございます。確認してみます。

以下のエラーが発生しています:

Started POST "/auth/saml" for 188.114.103.216 at 2020-08-04 16:46:20 +0000
(saml) Request phase initiated.
Started POST "/auth/saml/callback" for 188.114.103.216 at 2020-08-04 16:46:21 +0000
(saml) Callback phase initiated.
Processing by Users::OmniauthCallbacksController#complete as HTML
  Parameters: {"SAMLResponse"=>"........", "RelayState"=>"", "provider"=>"saml"}
Completed 422 Unprocessable Entity in 16ms (ActiveRecord: 0.0ms | Allocations: 4546)
ActiveRecord::RecordInvalid (Validation failed: Primary email is invalid.)
lib/distributed_mutex.rb:33:in `block in synchronize'
lib/distributed_mutex.rb:29:in `synchronize'
lib/distributed_mutex.rb:29:in `synchronize'
lib/distributed_mutex.rb:14:in `synchronize'
app/controllers/users/omniauth_callbacks_controller.rb:37:in `complete'
app/controllers/application_controller.rb:350:in `block in with_resolved_locale'
app/controllers/application_controller.rb:350:in `with_resolved_locale'
lib/middleware/omniauth_bypass_middleware.rb:47:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/anonymous_cache.rb:328:in `call'
config/initializers/100-quiet_logger.rb:19:in `call'
config/initializers/100-silence_logger.rb:31:in `call'
lib/middleware/enforce_hostname.rb:22:in `call'
lib/middleware/request_tracker.rb:176:in `call'
Failed to handle exception in exception app middleware : Validation failed: Primary email is invalid.

SAML レスポンスのペイロードを確認したところ、以下のようになっていました(明らかな理由により一部のデータは削除しています):

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="https://example.com/auth/saml/callback" ID="id123" IssueInstant="2020-08-04T16:39:45.888Z" Version="2.0">
   <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/xyz</saml2:Issuer>
   <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
      <ds:SignedInfo>
         <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
         <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
         <ds:Reference URI="#id123">
            <ds:Transforms>
               <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
               <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                  <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs" />
               </ds:Transform>
            </ds:Transforms>
            <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
            <ds:DigestValue>....</ds:DigestValue>
         </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue>...</ds:SignatureValue>
      <ds:KeyInfo>
         <ds:X509Data>
            <ds:X509Certificate>...</ds:X509Certificate>
         </ds:X509Data>
      </ds:KeyInfo>
   </ds:Signature>
   <saml2p:Status>
      <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
   </saml2p:Status>
   <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="id123" IssueInstant="2020-08-04T16:39:45.888Z" Version="2.0">
      <saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/xyz</saml2:Issuer>
      <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
         <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
            <ds:Reference URI="#id123">
               <ds:Transforms>
                  <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                  <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                     <ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs" />
                  </ds:Transform>
               </ds:Transforms>
               <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
               <ds:DigestValue>...</ds:DigestValue>
            </ds:Reference>
         </ds:SignedInfo>
         <ds:SignatureValue>...</ds:SignatureValue>
         <ds:KeyInfo>
            <ds:X509Data>
               <ds:X509Certificate>...</ds:X509Certificate>
            </ds:X509Data>
         </ds:KeyInfo>
      </ds:Signature>
      <saml2:Subject>
         <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">my.name</saml2:NameID>
         <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
            <saml2:SubjectConfirmationData NotOnOrAfter="2020-08-04T16:44:45.888Z" Recipient="https://example.com/auth/saml/callback" />
         </saml2:SubjectConfirmation>
      </saml2:Subject>
      <saml2:Conditions NotBefore="2020-08-04T16:34:45.888Z" NotOnOrAfter="2020-08-04T16:44:45.888Z">
         <saml2:AudienceRestriction>
            <saml2:Audience>https://example.com</saml2:Audience>
         </saml2:AudienceRestriction>
      </saml2:Conditions>
      <saml2:AuthnStatement AuthnInstant="2020-08-04T06:53:32.462Z" SessionIndex="id789">
         <saml2:AuthnContext>
            <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
         </saml2:AuthnContext>
      </saml2:AuthnStatement>
      <saml2:AttributeStatement>
         <saml2:Attribute Name="screenName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
            <saml2:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">my.name@example.com</saml2:AttributeValue>
         </saml2:Attribute>
      </saml2:AttributeStatement>
   </saml2:Assertion>
</saml2p:Response>

何か心当たりはありますか?

ありがとうございます、
AB

つまり、SAML がメールアドレスの末尾を正しく処理していないのか、それとも間違ったフィールドを確認しているのでしょうか?

問題は、私の Okta/SAML がこのフィールドにメールアドレスではなくユーザー名を送信していることです。

<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">my.name</saml2:NameID>

これを修正するために、email という新しい属性を追加し、プロジェクトをフォークして、この新しい属性(存在する場合)から result.mail を読み取るように設定しました。

プルリクエストを作成する予定です。

ありがとう
AB