Thiago Ururay
Thiago Ururay

Reputation: 462

Warden skips strategy

I have two warden strategies in a Rails API app, for basic authentication and for token authentication.

initializers/warden.rb

Warden::Strategies.add(:auth_token, AuthTokenStrategy)
Warden::Strategies.add(:basic_auth, BasicAuthStrategy)

config/application.rb

config.middleware.insert_after ActionDispatch::Callbacks, Warden::Manager do |manager|
  manager.default_strategies :auth_token, :basic_auth
  manager.failure_app = UnauthorizedController
end

And both strategies implements #valid?

class BasicAuthStrategy < ::Warden::Strategies::Base
  def valid?
    auth.provided? && auth.basic?
  end
  ...
end

and

class AuthTokenStrategy < ::Warden::Strategies::Base
  def valid?
    auth.provided? && !auth.basic? && headers['HTTP_AUTHORIZATION'].start_with?('Bearear')
  end
  ...
end

I imagine making a request with token, warden tries BasicAuthStrategy and then it tries AuthTokenStrategy mas it ends up after the first. It ignores one strategy. Why?

PS: I'm not using devise.

Upvotes: 1

Views: 1038

Answers (1)

Justin Smestad
Justin Smestad

Reputation: 31

First I will assume that auth.provided? and auth.basic? are defined and working correctly. The sample you provided is not showing what the authenticate! method looks like so I'll put in some pseudo-code.

class AuthTokenStrategy < ::Warden::Strategies::Base
  def valid?
    request.headers['HTTP_AUTHORIZATION'].start_with?('Bearear')
  end

  def authenticate!
    bearer_token = request.headers['HTTP_AUTHORIZATION'].split(' ')
    if user = User.find_by(bearer_token: auth_token)
      success!(user)
    end
  end
end

class BasicAuthStrategy < ::Warden::Strategies::Base
  def valid?
    not request.headers['HTTP_AUTHORIZATION'].nil?
  end

  def authenticate!
    auth_token = request.headers['HTTP_AUTHORIZATION']
    if user = User.find_by(auth_token: auth_token)
      success!(user)
    end
  end
end

Warden::Strategies.add(:auth_token, AuthTokenStrategy)
Warden::Strategies.add(:basic_auth, BasicAuthStrategy)

Rails.application.config.middleware.use Warden::Manager do |manager|
  manager.default_strategies %i[auth_token basic_auth]
  # manager.failure_app = lambda { |env|
  #  SessionsController.action(:failure).call(env)
  #}
end

It is worth noting that in your case the valid? definition may be optional. Warden will stop running strategies when one returns success!.

Upvotes: 1

Related Questions