Ошибка при использовании плагина discourse-oauth2-basic с NeonCRM

Я пытаюсь настроить плагин discourse-oauth2-basic, чтобы наши пользователи могли входить на наш форум Discourse, используя учетные данные, созданные и хранящиеся в NeonCRM.

Техподдержка NeonCRM объяснила мне, что я могу вручную создать URL авторизации, используя следующий формат:

https://{{Org ID}}.z2systems.com/np/oauth/auth?response_type=code&client_id={{Client ID}}&redirect_uri={{Redirect URL}}

В Discourse я установил следующие параметры для плагина:

oauth2 client id: MY-CLIENT-ID
oauth2 client secret: MY-CLIENT-SECRET
oauth2 authorize url: https://MY-NEON-ID.z2systems.com/np/oauth/auth
oauth2 token url: https://www.z2systems.com/np/oauth/token

Таким образом, я вручную создал этот URL (который я затем скрыл):

https://MY-NEON-ID.z2systems.com/np/oauth/auth?response_type=code&client_id=MY-CLIENT-ID&redirect_uri=https://MY-FORUM.COM/auth/oauth2_basic/callback

Когда я ввожу этот URL в браузере, я получаю страницу Discourse со следующим сообщением:

А в логах указано:

(oauth2_basic) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected

Почему это происходит?

Итак, если я использую этот URL вместо:

https://MY-NEON-ID.z2systems.com/np/oauth/auth?response_type=code&client_id=MY-CLIENT-ID&redirect_uri=https://MY-FORUM.COM/

(Я убрал часть с обратным вызовом в конце моего redirect_uri)

Я действительно попадаю на страницу входа NeonCRM, после чего ввожу данные тестового пользователя и вхожу в систему. Затем меня перенаправляют на MY-FORUM.COM. Но как только я там оказываюсь, я вообще не авторизован. Если я нажму кнопку «Войти» в верхней части страницы и затем нажму серую кнопку «Войти через OAuth2», откроется новое окно с следующим сообщением:

И в моих логах появляются две ошибки:

ArgumentError (Неверный URI: )

/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/excon-0.64.0/lib/excon.rb:126:in `new’

и

Не удалось обработать исключение в промежуточном ПО обработки исключений: Неверный URI:

Этот redirect_uri указан неверно. Чтобы процесс работал корректно, его необходимо настроить правильно.

В документации к плагину это первый шаг в разделе базовая настройка.

NeonCRM также описывает, как настроить это в своей документации.

Спасибо, @Falco!

Я пытался установить redirect_uri в:

https://MY-FORUM.COM/auth/oauth2_basic/callback

Но это не сработало. См. мой оригинальный пост (я только что отредактировал его, чтобы было понятнее, извините, если вы его пропустили).

Работает ли ваш форум по протоколу HTTPS?

Да, это @Falco.

https://forum.efao.ca/

Вы включили настройку force_https?

@Falco, я нашёл инструкции по включению force_https и установил его в true.

Тем не менее ошибка остаётся прежней.

Я интегрировал виджет, который NeonCRM рекомендует использовать в верхней части форума (так что вы можете попробовать его сами, если захотите), по адресу

https://forum.efao.ca/

При использовании виджета я получаю тот же результат, что и в моем первоначальном сообщении.

(oauth2_basic) Ошибка аутентификации! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | Обнаружен CSRF

Кто-нибудь? @david или @Falco?

Единственное место, где мы используем Excon в плагине oauth2, находится здесь:

Какое значение установлено для oauth2_user_json_url? Я подозреваю, что оно пустое. Если так, вам также следует отключить oauth2_fetch_user_details, чтобы Discourse не пытался обратиться к пустому URL.

@david, действительно пусто.

Я не знаю, что указать в качестве oauth2_user_json_url. К сожалению, мне не удалось получить помощь от NeonCRM через их техническую поддержку, чтобы разобраться в этом.

Если я попытаюсь отключить это, появится сообщение о том, что необходимо задать oauth2 callback user id path, но, как я уже сказал выше, я не знаю, каким должно быть это значение.

У меня нет установленной версии NeonCRM для тестирования, но я думаю, что установка значения access_token должна сработать. Можете ли вы попробовать это?

Из документации, на которую ссылался Фалко выше:

Та же ошибка:

(oauth2_basic) Ошибка аутентификации! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | Обнаружен CSRF

Стек вызовов:

 /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.3.2/lib/logster/logger.rb:110:in `report_to_store'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.3.2/lib/logster/logger.rb:101:in `add_with_opts'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.3.2/lib/logster/logger.rb:52:in `add'
/usr/local/lib/ruby/2.6.0/logger.rb:543:in `error'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:163:in `log'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:486:in `fail!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-oauth2-1.6.0/lib/omniauth/strategies/oauth2.rb:71:in `callback_phase'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:238:in `callback_call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:189:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:192:in `call!'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/strategy.rb:169:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/omniauth-1.9.0/lib/omniauth/builder.rb:64:in `call'
/var/www/discourse/lib/middleware/omniauth_bypass_middleware.rb:30:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/tempfile_reaper.rb:15:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/conditional_get.rb:25:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/head.rb:12:in `call'
/var/www/discourse/lib/content_security_policy/middleware.rb:12:in `call'
/var/www/discourse/lib/middleware/anonymous_cache.rb:218:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/session/abstract/id.rb:232:in `context'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/session/abstract/id.rb:226:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/cookies.rb:670:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/callbacks.rb:28:in `block in call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activesupport-5.2.3/lib/active_support/callbacks.rb:98:in `run_callbacks'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/debug_exceptions.rb:61:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/logster-2.3.2/lib/logster/middleware/reporter.rb:43:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-5.2.3/lib/rails/rack/logger.rb:38:in `call_app'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-5.2.3/lib/rails/rack/logger.rb:28:in `call'
/var/www/discourse/config/initializers/100-quiet_logger.rb:18:in `call'
/var/www/discourse/config/initializers/100-silence_logger.rb:31:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/request_id.rb:27:in `call'
/var/www/discourse/lib/middleware/enforce_hostname.rb:17:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/method_override.rb:22:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/actionpack-5.2.3/lib/action_dispatch/middleware/executor.rb:14:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/sendfile.rb:111:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-mini-profiler-1.1.0/lib/mini_profiler/profiler.rb:184:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/message_bus-2.2.0/lib/message_bus/rack/middleware.rb:57:in `call'
/var/www/discourse/lib/middleware/request_tracker.rb:163:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-5.2.3/lib/rails/engine.rb:524:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-5.2.3/lib/rails/railtie.rb:190:in `public_send'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/railties-5.2.3/lib/rails/railtie.rb:190:in `method_missing'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/urlmap.rb:68:in `block in call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/urlmap.rb:53:in `each'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rack-2.0.7/lib/rack/urlmap.rb:53:in `call'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.1/lib/unicorn/http_server.rb:605:in `process_client'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.1/lib/unicorn/http_server.rb:700:in `worker_loop'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.1/lib/unicorn/http_server.rb:548:in `spawn_missing_workers'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.1/lib/unicorn/http_server.rb:144:in `start'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/unicorn-5.5.1/bin/unicorn:128:in `<top (required)>'
/var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `load'
/var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `<main>'

Интересно… трассировка стека указывает на то, что ошибка возникает в этом месте библиотеки OAuth2. Это означает, что параметр state не сопоставляется корректно.

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

Это указывает на проблему на стороне сервера. Как размещён ваш сайт? Вы следовали нашей стандартной процедуре?

Также, @david, и я не знаю, связано ли это, но у меня в логах есть отдельная запись:

Исключение в задаче: SSL_connect вернул=1 errno=0 state=error: проверка сертификата не удалась (самоподписанный сертификат)

Мы используем Let’s Encrypt для нашего SSL-сертификата.

Есть ли к этой ошибке приложен трассировка стека?

Да, forum.efao.ca — это наш продакшн-сайт. Мы размещены на Digital Ocean, и установка была выполнена по стандартной процедуре.

/usr/local/lib/ruby/2.6.0/net/protocol.rb:44:in `connect_nonblock'
/usr/local/lib/ruby/2.6.0/net/protocol.rb:44:in `ssl_socket_connect'
/usr/local/lib/ruby/2.6.0/net/pop.rb:553:in `do_start'
/usr/local/lib/ruby/2.6.0/net/pop.rb:531:in `start'
/var/www/discourse/app/jobs/scheduled/poll_mailbox.rb:43:in `poll_pop3'
/var/www/discourse/app/jobs/scheduled/poll_mailbox.rb:18:in `execute'
/var/www/discourse/app/jobs/base.rb:232:in `block (2 levels) in perform'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.0.7/lib/rails_multisite/connection_management.rb:63:in `with_connection'
/var/www/discourse/app/jobs/base.rb:221:in `block in perform'
/var/www/discourse/app/jobs/base.rb:217:in `each'
/var/www/discourse/app/jobs/base.rb:217:in `perform'
/var/www/discourse/app/jobs/base.rb:279:in `perform'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/mini_scheduler-0.11.0/lib/mini_scheduler/manager.rb:83:in `process_queue'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/mini_scheduler-0.11.0/lib/mini_scheduler/manager.rb:34:in `block in initialize'

Боюсь, что без доступа к серверу я не смогу сделать больше для диагностики проблемы. У нас много людей используют плагин oauth2 без каких-либо проблем, поэтому, думаю, это проблема с конфигурацией где-то в настройках. Единственное, что может помочь — это обновиться до последней версии Discourse, вместо использования стабильной ветки.

Возможно, кто-то ещё из сообщества подключится к обсуждению, но если нет, вы можете попробовать получить помощь в канале Marketplace.