Здравствуйте! Мы разработали собственный плагин SSO, чтобы объединить данные для входа нашей компании в пакет, который Discourse может использовать для обработки входа и создания учётных записей. Начиная с версии v2.7.0beta4, мы начали получать ошибки, указывающие на то, что мы не передаём новый параметр secure_session. Нигде не удалось найти подробностей о том, какой должен быть формат этого параметра и что он должен содержать. Есть ли какая-либо дополнительная документация по этому обновлению?
Вы знаете точный текст сообщения об ошибке, которое вы видите? Насколько я понимаю, Discourse теперь привязывает параметр SSO nonce к сессии пользователя. Это означает, что если приложение генерирует nonce, выполняя фоновый запрос к /session/sso, то nonce будет недействительным. Возможно, именно с этой проблемой вы столкнулись.
Файл service_gateway_current_user.rb является частью нашего плагина для формирования полезной нагрузки, отправляемой в DiscourseSingleSignOn, на основе заголовков «Service Gateway» («Service Gateway» — это внутренняя структура нашей компании для определения, авторизован ли пользователь в нашей системе).
Чтобы пояснить эту часть стека вызовов:
Наша функция current_user использует заголовки для поиска SingleSignOnRecord, где external_id совпадает с идентификатором пользователя в заголовках. Если совпадения нет, мы переходим к секции 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
Вызов parse на третьей строке этой функции, по-видимому, является местом возникновения проблемы. Как только он пытается инициализировать объект, ожидаемое значение secure_session отсутствует.
Мне интересно, поможет ли отключение новой настройки сайта discourse_connect_csrf_protection (установив её значение в false) решить вашу проблему. Эта настройка скрыта, поэтому её необходимо изменить через консоль Rails. Подробную информацию об этом можно найти в ответах на эту тему: DiscourseConnect flow no longer functions.
К сожалению, я не думаю, что новый параметр сам по себе поможет — внутренняя часть кода всё равно потребует передачи объекта secure_session, даже если он не используется.
В целом мы рекомендуем использовать официальные хуки для плагинов аутентификации, а не переопределять реализацию DiscourseConnect в ядре.
Без просмотра всего плагина точно сказать сложно, но можно попробовать передать nil для secure_session. Это действие, в сочетании с включением нового параметра сайта, может помочь приблизить ситуацию к рабочей.
После более детального изучения кода версии v2.7.0.beta4 я заметил, что в ApplicationController есть определение secure_session. Изменение кода нашего плагина следующим образом, похоже, работает в нашей тестовой среде:
sso = DiscourseSingleSignOn.parse({ sso: encoded_query, sig: sig }.to_query, secure_session: secure_session)