Помогите мне устранить неполадки в SSO для Discourse

Приветствую, надеюсь на вашу помощь. Моя система единого входа (SSO) перестала работать на этой неделе. Я думал, что вчера всё исправил (работало, честное слово :slight_smile: Примечание: я посмотрел раздел «Новые пользователи» за вчера и сегодня — новые пользователи появлялись в оба дня (после моего исправления), но теперь снова всё сломано…). К сожалению, внесённые мной обновления сегодня не работают.

Проблема: Пользователи не могут создавать новые учётные записи, а пользователи, вышедшие из системы, не могут войти обратно.

Я заметил, что мой сервер Discourse возвращает ошибки 400 по следующим маршрутам:

403: GET : discourse-url/users/by-external/USER-ID.json?
Примечание: Недавно в документации API я обнаружил, что этот маршрут не существует? (хотя он работал). Похоже, правильный маршрут: https://discourse.example.com/u/by-external/{external_id}.json

404: POST: discourse-url/admin/users/sync_sso?

Знак вопроса ? в конце стоит потому, что в функции, генерирующей URL, у меня есть необязательный параметр. Для этих двух маршрутов все данные отправляются в теле формы или заголовках.

Я использую следующую библиотеку.

Что я обновил (и что, как я думал, исправит проблему):

Во всех своих запросах я передавал Api-Key и Api-Username через параметры запроса (query parameters). В течение последних нескольких месяцев в панели администратора я видел предупреждение о том, что в моих запросах используются устаревшие заголовки. Оно ссылалось на этот пост, и ключевые детали здесь:

:warning: Предупреждение об устаревании!
6 апреля 2020 года мы прекратили поддержку всей аутентификации, не основанной на HTTP-заголовках (за исключением некоторых маршрутов RSS, получения почты и ICS). Это означает, что API-запросы, содержащие api_key и api_username в параметрах запроса или в теле HTTP-запроса, скоро перестанут работать. Пожалуйста, ознакомьтесь с примером запроса cURL ниже, чтобы узнать, как обновить свои API-запросы для использования HTTP-заголовков в целях аутентификации.

Я обновил все свои запросы: теперь Api-Key и Api-Username передаются в заголовках, а тип контента установлен как multipart form data.

Если кто-то сможет подсказать, на что обратить внимание при отладке этой проблемы, я буду очень благодарен. Я почти на 100% уверен, что вчера в конце рабочего дня всё работало: я мог входить и выходить из своей учётной записи, а также создавать новые учётные записи.

Пожалуйста, дайте знать, если потребуется дополнительная информация. Спасибо!

Поля заголовков должны использовать дефисы (-), а не нижние подчеркивания (_). Попробуйте изменить имена полей на Api-Key и Api-Username.

Я не уверен, исправит ли это проблему с тем, что пользователи не могут войти на ваш сайт, но это устранит проблему с ошибками 400, которые вы видите.

@simon, спасибо за ответ! К сожалению, я не слишком хорошо оформил свой пост — в своих запросах я уже использую -, а не _.

Чтобы начать отладку, перейдите на страницу настроек вашего сайта Discourse и выполните поиск по запросу «sso», чтобы получить все параметры SSO. Убедитесь, что параметры «enable sso», «sso url» и «sso secret» настроены правильно. Затем включите параметр сайта «verbose sso logging». При включении этого параметра в журналы ошибок вашего сайта (доступны по пути Администрирование / Журналы / Журналы ошибок) будут добавлены дополнительные записи.

Попробуйте войти в систему через SSO. Затем проверьте журналы ошибок, чтобы увидеть, содержат ли они какие-либо подробности о проблеме. Если вы не видите ничего полезного, откройте веб-инспектор вашего браузера на вкладке «Network» (Сеть) с включённой галочкой «Preserve log» (Сохранять журнал). Просмотрите отправляемые запросы.

Если в процессе устранения проблемы вы заблокируете себе доступ к сайту, то как администратор вы можете обойти SSO, перейдя по адресу /u/admin-login и введя свой адрес электронной почты в форму. Вам будет отправлено письмо со ссылкой для входа.

@simon, спасибо за подсказку! Я изучаю логи, но не очень опытен в их чтении. У меня появляются два разных типа предупреждений и одна ошибка:

Вот предупреждение, которое я часто вижу:

Verbose SSO log: Started SSO process add_groups: admin: moderator: avatar_force_update: avatar_url: bio: card_background_url: email: external_id: groups: locale: locale_force_update: logo

А вот ошибка:

Job exception: The difference between the request time and the current time is too large.

Когда я пытаюсь войти под тестовым пользователем на своём сайте, из которого я вышел в Discourse, в панели сети я вижу следующее:

503 Service Unavailable: GET- https://my-site/auth/discourse_sso?sso=XXXX&sig=xxxx

К сожалению, я уперся в тупик и не знаю, как двигаться дальше.

Думаю, это сообщение об ошибке исходит от Amazon S3. Возможно, в этой теме есть полезные детали о том, как исправить проблему: Backups have started failing due to server time being wrong. Дополнительную информацию можно найти здесь: https://stackoverflow.com/questions/4770635/s3-error-the-difference-between-the-request-time-and-the-current-time-is-too-la.

@simon спасибо за помощь! Время на моём сервере было рассинхронизировано, я исправил это, и теперь резервные копии снова работают!

Теперь я периодически получаю новую ошибку:

В разделе логов я случайно вижу следующие предупреждения (я получил их только 2 раза):

MaxMindDB (/var/www/discourse/vendor/data/GeoLite2-City.mmdb) не найден: No such file or directory @ rb_sysopen - /var/www/discourse/vendor/data/GeoLite2-City.mmdb

и

MaxMindDB (/var/www/discourse/vendor/data/GeoLite2-ASN.mmdb) не найден: No such file or directory @ rb_sysopen - /var/www/discourse/vendor/data/GeoLite2-ASN.mmdb

Я сейчас ищу, как исправить эту проблему. Я попробовал пересобрать приложение, но не на 100% уверен, что пересборка прошла успешно. Я всё ещё случайно получаю ошибки MaxMindDB не найден, а также ошибки 400 и 503, которые были у меня ранее.

Я занимался этим большую часть раннего утра, но значительного прогресса не добился. Думаю, я устранил ошибки MaxMindDB (раньше они возникали спорадически и непоследовательно, но уже 3 часа мне не удавалось их воспроизвести), и я несколько раз успешно пересобрал своё приложение.

Вот на каком этапе прерывается конвейер SSO:

  • Пользователь посещает Discourse.
  • Так как активная сессия отсутствует, пользователь перенаправляется на discourse/session/sso_login.
  • Затем пользователь перенаправляется на my-site/discourse_sso?sso=XXXX&sig=XXXX.
  • При срабатывании предыдущего маршрута на моём сайте я отправляю GET-запрос к /users/by-external/userId.json.
    • В ответ приходит 403 Forbidden.
  • Сразу после этого отправляется POST-запрос к /admin/users/sync_sso.
    • Это приводит к ошибке 404 «No route matches [POST] /admin/users/sync_sso».
  • В конечном итоге мой сайт возвращает сообщение 503 Forbidden (мне нужно почистить некоторые сообщения об ошибках на своей стороне).

Мне кажется, что проблема на стороне Rails-приложения (поправьте меня, если я ошибаюсь). Одна из причин, по которой я так думаю, заключается в том, что в конце пятницы всё работало: есть подтверждение, так как между вечерней пятницы и субботой несколько новых пользователей зарегистрировались (а именно вход в систему или создание нового пользователя были нерабочими). Как я уже упоминал в предыдущих сообщениях, я думал, что тогда всё исправил, однако, когда я начал работу в субботу, заметил, что проблема вернулась.

Не совсем понятно, зачем вы отправляете запросы к /users/by-external/<external_id>.json и /admin/users/sync_sso. Обычный сценарий — просто перенаправить пользователя на /session/sso_login, передав SSO-нагрузку в виде параметров запроса в URL. Подробно о назначении маршрута sync_sso можно прочитать здесь: Sync DiscourseConnect user data with the sync_sso route.

Запрос к /users/by-external/<external_id> с external_id, который ещё не связан с пользователем Discourse, должен возвращать ошибку 404 (не найдено). Если же external_id уже связан с пользователем Discourse, должен быть возвращён сам пользователь.

@simon, Запрос к /users/by-external/USER-ID.json используется для проверки, есть ли у пользователя уже учётная запись в моём Discourse. Если пользователь с таким ID найден, он добавляется или удаляется из групп Discourse, связанных с моим сайтом, с помощью PUT-запроса к /admin/groups/groupId/members.json, после чего происходит перенаправление на my-discourse/session/sso_login.

Если у пользователя нет учётной записи, она создаётся через POST-запрос к /admin/users/sync_sso. После создания пользователя (и добавления его в соответствующие группы Discourse) он перенаправляется на my-discourse/session/sso_login.

Я продолжу работу и ещё раз изучу документацию, которую вы указали (спасибо!). Этот процесс работал без сбоев с начала 2015 года (и Discourse с опцией SSO стал для нас очень ценным инструментом!), поэтому странно, что он внезапно перестал работать на прошлой неделе.

@simon, я очень ценю вашу помощь! Я решил проблему. Api-Username, который мы использовали, был «деактивирован» на прошлой неделе (из-за неактивности). Я изначально предполагал, что это могло быть причиной. Я повторно активировал пользователя в пятницу, и, скорее всего, именно это всё исправило в тот же день (я сначала думал, что дело в перемещении Api-Username и Api-Key в заголовки).

Discourse снова деактивировал того же пользователя в субботу утром, что объясняет, почему всё работало, а затем внезапно перестало. Я не думал, что пользователь будет снова деактивирован так скоро из-за неактивности.

Теперь я изменил Api-Username на «system», чтобы в будущем избежать подобных сбоев. Ещё раз спасибо за помощь! В процессе отладки мои резервные логи снова начали работать, и я точно многому научился!