Иногда возникают ошибки OAuth

Мы используем внешний OAuth для аутентификации пользователей. Периодически пользователи получают ошибку 500 при входе на платформу. Фрагмент из лога ошибок:

Started GET "/auth/oauth2_basic/callback?code=[coderemoved]&state=[stateremoved]" for [IP] at [timestamp]
(oauth2_basic) Setup endpoint detected, running now.
(oauth2_basic) Callback phase initiated.
Faraday::TimeoutError (Timeout::Error)
lib/final_destination/resolver.rb:31:in `block in lookup'
lib/final_destination/resolver.rb:8:in `synchronize'
lib/final_destination/resolver.rb:8:in `lookup'
lib/final_destination/ssrf_detector.rb:127:in `lookup_ips'
lib/final_destination/ssrf_detector.rb:95:in `lookup_and_filter_ips'
lib/final_destination/http.rb:13:in `connect'
lib/middleware/omniauth_bypass_middleware.rb:43:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/anonymous_cache.rb:387:in `call'
lib/middleware/gtm_script_nonce_injector.rb:10:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
lib/middleware/enforce_hostname.rb:24:in `call'
lib/middleware/request_tracker.rb:233:in `call'

Если пользователь просто перезагрузит страницу, всё работает. Вот соответствующая информация из лога:

Started GET "/auth/oauth2_basic/callback?code=[coderemoved]&state=[stateremoved]" for [IP] at [timestamp]
(oauth2_basic) Setup endpoint detected, running now.
(oauth2_basic) Callback phase initiated.
Processing by Users::OmniauthCallbacksController#complete as HTML
  Parameters: {"code"=>"[coderemoved]", "state"=>"[stateremoved]", "provider"=>"oauth2_basic"}
Deprecation notice: `SiteSetting.anonymous_posting_min_trust_level` has been deprecated. Please use `SiteSetting.anonymous_posting_allowed_groups` instead. (removal in Discourse 3.3) 
At /var/www/discourse/lib/site_setting_extension.rb:160:in `public_send`
start
Redirected to https://[pageremoved]
Completed 302 Found in 83ms (ActiveRecord: 0.0ms | Allocations: 11138)

К сожалению, шагов для воспроизведения проблемы нет. Обычно это происходит с пользователями, которые отсутствовали длительное время, но я не могу подтвердить это с уверенностью. Возможно, с момента их последнего визита произошло обновление платформы.
Есть ли какие-либо предложения или дополнительная информация, которую я мог бы предоставить?

Поднимаю эту тему. У меня возникают точно такие же проблемы.

Ошибка тайм-аута указывает на проблему с сетью. Возможно, это просто временный сбой сети.

Я так и думал, но ошибка возникает слишком быстро, чтобы это было нормальным поведением. Мне кажется, проблема может быть в чрезмерно строгом тайм-ауте DNS-запроса где-то в системе:

  1. Ошибка находится в файле “resolver.rb”.
  2. Она временно устраняется при обновлении страницы — когда DNS-запрос кэшируется.
  3. По какой-то совершенно необъяснимой причине я не могу заставить систему прочитать документ обнаружения OIDC ни с одного URL, использующего наш собственный DNS. При этом я без проблем могу вручную получить этот файл через curl внутри контейнера Docker. Я исключил множество различных переменных, и DNS остаётся единственным общим фактором.

Важно отметить, что сервер Discourse всё ещё способен связываться с сервером OIDC, даже когда возникает такая ошибка. Судя по журналам доступа, при ошибке выполняется один запрос:

21/Jan/2024:23:10:21 +0000] "POST /application/o/token/ HTTP/1.1" 200 7998 "-" "Faraday v2.9.0"

а при успешной работе — два запроса:

[21/Jan/2024:23:21:03 +0000] "POST /application/o/token/ HTTP/1.1" 200 7998 "-" "Faraday v2.9.0"
[21/Jan/2024:23:21:05 +0000] "GET /application/o/userinfo/ HTTP/1.1" 200 5254 "-" "Faraday v2.9.0"

В любом случае процесс никогда не занимает более 5 секунд. Я ещё не пробовал настроить прокси для сервера OIDC с использованием DNS Cloudflare, но это будет следующим шагом.

Общепринятое мнение гласит, что проблема всегда в DNS.

Что ж, это точно DNS. Вместо настройки прокси я просто добавил свой OIDC-сервер в файл hosts внутри контейнера Docker, и теперь всё работает. Однако это хрупкое и неоптимальное решение; думаю, разработчикам нужно исправить таймаут, чтобы он был разумным. Этот случай напоминает мне историю про письмо на 500 миль.

Вы можете добавить необходимые записи в файл app.yml, чтобы обновить /etc/hosts при пересборке. Посмотрите примеры в других шаблонах.

Возможно, но у многих проблем нет. Не перегружен ли иногда ваш DNS-сервер с собственным хостингом?

Не знаю, где и как изменить таймаут. Не помню, чтобы когда-либо это делал.

В моём случае IdP и виртуальные машины Discourse расположены рядом друг с другом, и хотя никто не может полностью исключить возможные проблемы с сетью, ни один другой сервис с ними не сталкивается.