Skip to content
Daiki Kudo edited this page Sep 1, 2020 · 3 revisions

Warden uses the concept of cascading strategies to determine if a request should be authenticated. Warden will try strategies one after another until either,

  • One succeeds
  • No Strategies are found relevant
  • A strategy Fails

What is a Strategy

Conceptually a strategy is where you put the logic for authenticating a request. Practically it's a descendant of Warden::Strategies::Base.

Many strategies can be defined and selectively used.

Lets take a look at defining one:

Warden::Strategies.add(:password) do
  def valid?
    params['username'] || params['password']
  end

  def authenticate!
    u = User.authenticate(params['username'], params['password'])
    u.nil? ? fail!("Could not log in") : success!(u)
  end
end

This declares a strategy called :password. The two things to note are the #authenticate! and #valid? methods.

#valid?

The valid? method acts as a guard for the strategy. It's optional to declare a valid? method, and if you don't declare it, the strategy will always be run. If you do declare it though, the strategy will only be tried if #valid? evaluates to true.

The strategy above is reasoning that if there's either a 'username' or a 'password' param, then the user is trying to login. If there's only one of them, then the User.authenticate call will fail, but it was still the desired (valid) strategy.

#authenticate!

This is where the work of actually authenticating the request steps in. Here's where the logic for authenticating your requests occurs.

You have a number of request related methods available.

  • request - Rack::Request object
  • session - The session object for the request
  • params - The parameters of the request
  • env - The Rack env object

There are also a number of actions you can take in your strategy.

  • halt! - halts cascading of strategies. Makes this one the last one processed.
  • pass - ignore this strategy. It is not required to call this and this is only sugar.
  • success! - Supply success! with a user object to log in a user. Causes a halt!.
  • fail! - Sets the strategy to fail. Causes a halt!.
  • redirect! - redirect to another url. You can supply it with params to be encoded and also options. Causes a halt!.
  • custom! - return a custom rack array to be handed back untouched. Causes a halt!.

There are a couple of misc things to do, too:

  • headers - set headers to respond with relevant to the strategy.
  • errors - provides access to an errors object. Here you can put in errors relating to authentication.

Using Strategies

To use a strategy, refer to it via the label that it was given when it was declared:

env['warden'].authenticate(:password)

to use the :password strategy. You can use multiple strategies, and each one will be tried in order until either one is halted or none have been.

env['warden'].authenticate(:password, :basic)

This will use the :password, and failing that, the :basic strategies.

Sharing Strategies

It is possible to share strategies with any other application that uses Warden. The benefit from doing this of course depends on your individual situation.

For some things like OpenID, Facebook or Google, a strategy may be useful to share if they're flexible. However, this kind of community sharing may not fit your needs exactly. Good strategies can be written and hopefully there will be many that come to light.

Declaring a strategy has been made as simple as possible whilst remaining flexible.

The most obvious wins to be had from sharing strategies between application instances are by multiple applications run by the same company. Many small applications can all be given the same authentication. For example, you may want to throw up a quick test application in Sinatra or straight Rack. Using Warden you can share the same strategies from your main application and provide consistent, company-wide authentication requirements.

Clone this wiki locally