SSO personalizado não funciona após secure_session ser adicionado como parâmetro

Olá! Desenvolvemos um plugin SSO personalizado para agrupar os dados de login da nossa empresa em um pacote que o Discourse pode usar para gerenciar logins e criar contas. Com a versão v2.7.0beta4, começamos a receber erros indicando que não estávamos fornecendo um novo parâmetro: secure_session. Não consegui encontrar nenhuma informação sobre qual deve ser o formato desse parâmetro ou o que ele deve conter. Existe alguma documentação adicional sobre essa atualização?

Obrigado!

1 curtida

Você sabe qual é a mensagem de erro exata que está aparecendo? Meu entendimento é que o Discourse agora vincula o parâmetro nonce do SSO à sessão do usuário. Isso significa que, se um aplicativo estiver gerando o nonce fazendo uma solicitação em segundo plano para /session/sso, o nonce não será válido. Possivelmente, esse é o problema que você está enfrentando.

2 curtidas

Com certeza! Aqui está o stack trace do erro que estamos vendo em nosso 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'

O arquivo service_gateway_current_user.rb faz parte do nosso plugin para construir o payload a ser enviado para DiscourseSingleSignOn com base nos cabeçalhos “Service Gateway” (sendo “Service Gateway” a estrutura interna da nossa empresa para determinar se você está logado em nosso sistema).

Para explicar essa parte do stack trace:

  • Nossa função current_user usa nossos cabeçalhos para buscar um SingleSignOnRecord onde o external_id corresponda ao ID do Usuário nos cabeçalhos. Se não for esse o caso, entramos na seção create_sso_record.
  • create_sso_record cria um hash – { external_id: sg_headers[:user_id], email: sg_headers[:email] } – e o envia para nossa função upsert_sso_record.
  • upsert_sso_record recebe esse hash (payload no contexto abaixo) e tenta criar um objeto 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

A chamada parse na terceira linha dessa função é onde parece estar ocorrendo o problema. Assim que tenta initialize o objeto, o valor secure_session que ela espera não está presente.

2 curtidas

Bump! Também estou curioso sobre isso!

Estou me perguntando se definir a nova configuração do site discourse_connect_csrf_protection como false resolverá o problema para você. Essa configuração do site está oculta, portanto precisa ser definida no console do Rails. Você pode encontrar detalhes sobre isso nas respostas a este tópico: DiscourseConnect flow no longer functions.

Infelizmente, não acho que essa nova configuração ajudará sozinha — os detalhes internos do código ainda exigirão a passagem de um objeto secure_session, mesmo que ele não seja utilizado.

Em geral, recomendamos o uso dos hooks oficiais para plugins de autenticação, em vez de substituir a implementação do DiscourseConnect do núcleo.

É difícil ter certeza sem ver o plugin inteiro, mas você pode tentar passar um valor nil para secure_session. Fazer isso, junto com ativar a nova configuração do site, pode ajudar a deixar as coisas um pouco mais próximas de funcionar.

5 curtidas

Depois de investigar um pouco mais o código da v2.7.0.beta4, vejo que o ApplicationController tem uma definição de secure_session. Alterar nosso código do plugin para o seguinte parece funcionar em nosso ambiente de Staging:

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

…É realmente tão simples? :thinking:

Parece que deveria funcionar - a sessão segura normalmente vem desse método no ApplicationController. :slight_smile:

2 curtidas

Maravilha! Obrigado por me deixar desabafar sobre esse problema. :duck: :metal:

2 curtidas