Class: Middleware::OmniauthBypassMiddleware

Inherits:
Object
  • Object
show all
Defined in:
lib/middleware/omniauth_bypass_middleware.rb

Overview

omniauth loves spending lots cycles in its magic middleware stack this middleware bypasses omniauth middleware and only hits it when needed

Defined Under Namespace

Classes: AuthenticatorDisabled

Instance Method Summary collapse

Constructor Details

#initialize(app, options = {}) ⇒ OmniauthBypassMiddleware

Returns a new instance of OmniauthBypassMiddleware.



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/middleware/omniauth_bypass_middleware.rb', line 11

def initialize(app, options = {})
  @app = app

  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

    # If the user is trying to reconnect to an existing account, store in session
    request.session[:auth_reconnect] = !!request.params["reconnect"]

    # If the client provided an origin, store in session to redirect back
    request.session[:destination_url] = request.params["origin"]
  end
end

Instance Method Details

#call(env) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/middleware/omniauth_bypass_middleware.rb', line 28

def call(env)
  if env["PATH_INFO"].start_with?("/auth")
    begin
      # When only one provider is enabled, assume it can be completely trusted, and allow GET requests
      only_one_provider =
        !SiteSetting.enable_local_logins && Discourse.enabled_authenticators.length == 1
      OmniAuth.config.allowed_request_methods = only_one_provider ? %i[get post] : [:post]

      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)
    rescue OAuth::Unauthorized => e
      # OAuth1 (i.e. Twitter) makes a web request during the setup phase
      # If it fails, Omniauth does not handle the error. Handle it here
      env["omniauth.error.type"] ||= "request_error"
      Rails.logger.error "Authentication failure! request_error: #{e.class}, #{e.message}"
      OmniAuth::FailureEndpoint.call(env)
    rescue JWT::InvalidIatError => e
      # Happens for openid-connect (including google) providers, when the server clock is wrong
      env["omniauth.error.type"] ||= "invalid_iat"
      Rails.logger.error "Authentication failure! invalid_iat: #{e.class}, #{e.message}"
      OmniAuth::FailureEndpoint.call(env)
    rescue CSRFTokenVerifier::InvalidCSRFToken => e
      # Happens when CSRF token is missing from request
      env["omniauth.error.type"] ||= "csrf_detected"
      OmniAuth::FailureEndpoint.call(env)
    end
  else
    @app.call(env)
  end
end