DEV: Only run omniauth strategies for enabled authenticators (#24094)

Previously, we would build the stack of omniauth authenticators once on boot. That meant that all strategies had to be included, even if they were disabled. We then used the `before_request_phase` to ensure disabled strategies could not be used. This works well, but it means that omniauth is often doing unnecessary work running logic in disabled strategies.

This commit refactors things so that we build the stack of strategies on each request. That means we only need to include the enabled strategies in the stack - disabled strategies are totally ignored. Building the stack on-demand like this does add some overhead to auth requests, but on the majority of sites that will be significantly outweighed by the fact we're now skipping logic for disabled authenticators.

As well as the slight performance improvement, this new approach means that:

- Broken (i.e. exception-raising) strategies cannot cause issues on a site if they're disabled

- `other_phase` of disabled strategies will never appear in the backtrace of other authentication errors
This commit is contained in:
David Taylor
2023-10-25 13:52:33 +01:00
committed by GitHub
parent 0e37ceeeb9
commit 5c38e55dc9
2 changed files with 55 additions and 17 deletions

View File

@ -13,27 +13,12 @@ class Middleware::OmniauthBypassMiddleware
Discourse.plugins.each(&:notify_before_auth)
# if you need to test this and are having ssl issues see:
# http://stackoverflow.com/questions/6756460/openssl-error-using-omniauth-specified-ssl-path-but-didnt-work
# OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE if Rails.env.development?
@omniauth =
OmniAuth::Builder.new(app) do
Discourse.authenticators.each { |authenticator| authenticator.register_middleware(self) }
end
@omniauth.before_request_phase do |env|
OmniAuth.config.before_request_phase do |env|
request = ActionDispatch::Request.new(env)
# Check for CSRF token in POST requests
CSRFTokenVerifier.new.call(env) if request.request_method.downcase.to_sym != :get
# Check whether the authenticator is enabled
if !Discourse.enabled_authenticators.any? { |a|
a.name.to_sym == env["omniauth.strategy"].name.to_sym
}
raise AuthenticatorDisabled
end
# If the user is trying to reconnect to an existing account, store in session
request.session[:auth_reconnect] = !!request.params["reconnect"]
@ -50,7 +35,14 @@ class Middleware::OmniauthBypassMiddleware
!SiteSetting.enable_local_logins && Discourse.enabled_authenticators.length == 1
OmniAuth.config.allowed_request_methods = only_one_provider ? %i[get post] : [:post]
@omniauth.call(env)
omniauth =
OmniAuth::Builder.new(@app) do
Discourse.enabled_authenticators.each do |authenticator|
authenticator.register_middleware(self)
end
end
omniauth.call(env)
rescue AuthenticatorDisabled => e
# Authenticator is disabled, pretend it doesn't exist and pass request to app
@app.call(env)