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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/middleware/omniauth_bypass_middleware.rb', line 11

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

  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|
    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"]

    # 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



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/middleware/omniauth_bypass_middleware.rb', line 45

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.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