Adotando SAML com uma base de usuários existente

Minha instalação atual do Discourse tem o registro de novos usuários desabilitado, e o login é feito por meio do plugin LDAP (GitHub - jonmbake/discourse-ldap-auth: Discourse plugin to enable LDAP/Active Directory authentication. · GitHub). Muitos dos usuários internos já existem, com conteúdos diferentes criados.

Fui solicitado a instalar/migrar para SAML para integrar o fluxo que temos com o Okta. Instalei o plugin (GitHub - discourse/discourse-saml: Support for SAML in Discourse · GitHub) com a opção DISCOURSE_SAML_AUTO_CREATE_ACCOUNT: true. O requisito é criar o usuário, caso ele não exista. Caso contrário, se o usuário já existir (porque foi criado anteriormente com o LDAP), o mesmo usuário deve ser reutilizado. O comportamento que tenho, no entanto, é que ele tenta criar um novo usuário com um nome de usuário já existente, o que obviamente causa erro. Se eu remover a opção de criação automática, aparece uma janela pop-up onde é possível editar as informações de registro com o nome de usuário pré-preenchido correto, mas com um prefixo numérico para evitar conflitos. Obviamente, isso não é uma opção no meu caso.

Você tem alguma sugestão?

Talvez esta postagem antiga esteja relacionada, mas sem nenhuma resposta.
https://meta.discourse.org/t/verify-if-user-is-already-logged-sso-with-saml2-discourse-saml/73213
(Não posso colocar mais de dois links na postagem, desculpe)

Obrigado antecipadamente.
AB

Os usuários geralmente são correspondidos por endereço de e-mail. O LDAP e o SAML não usam o mesmo endereço de e-mail?

O endereço de e-mail é o mesmo. Provavelmente, preciso verificar o que está vindo dentro do payload SAML.

Obrigado pela dica. Vou verificar.

Estou recebendo o seguinte erro:

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.

Verifiquei o payload da resposta SAML e ele parece com o seguinte (com alguns dados removidos por motivos óbvios):

<?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>

Alguma ideia?

Obrigado,
AB

Então parece que seu SAML não está finalizando o endereço de e-mail? Ou você está procurando no campo errado?

O problema é que meu Okta/SAML está enviando o nome de usuário e não o e-mail dentro deste campo

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

Eu corrigi adicionando um novo atributo chamado email e depois fazendo um fork do projeto para configurar o result.mail lendo-o desse novo atributo (se presente).

Vou criar um pull request.

Obrigado,
AB