2010-03-29 20:52:34 +02:00
|
|
|
require 'devise/strategies/base'
|
|
|
|
|
|
|
|
module Devise
|
|
|
|
module Strategies
|
2010-03-29 23:44:47 +02:00
|
|
|
# This strategy should be used as basis for authentication strategies. It retrieves
|
|
|
|
# parameters both from params or from http authorization headers. See database_authenticatable
|
|
|
|
# for an example.
|
2010-03-29 20:52:34 +02:00
|
|
|
class Authenticatable < Base
|
|
|
|
attr_accessor :authentication_hash, :password
|
|
|
|
|
|
|
|
def valid?
|
|
|
|
valid_for_http_auth? || valid_for_params_auth?
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2010-07-23 23:57:31 +02:00
|
|
|
# Simply invokes valid_for_authentication? with the given block and deal with the result.
|
|
|
|
def validate(resource, &block)
|
|
|
|
result = resource && resource.valid_for_authentication?(&block)
|
|
|
|
|
|
|
|
case result
|
|
|
|
when Symbol, String
|
|
|
|
fail!(result)
|
|
|
|
else
|
|
|
|
result
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-05-16 14:13:43 +02:00
|
|
|
# Check if this is strategy is valid for http authentication by:
|
|
|
|
#
|
|
|
|
# * Validating if the model allows params authentication;
|
|
|
|
# * If any of the authorization headers were sent;
|
|
|
|
# * If all authentication keys are present;
|
|
|
|
#
|
2010-03-29 20:52:34 +02:00
|
|
|
def valid_for_http_auth?
|
2010-04-06 22:36:41 +02:00
|
|
|
http_authenticatable? && request.authorization && with_authentication_hash(http_auth_hash)
|
2010-03-29 20:52:34 +02:00
|
|
|
end
|
|
|
|
|
2010-05-16 14:13:43 +02:00
|
|
|
# Check if this is strategy is valid for params authentication by:
|
|
|
|
#
|
|
|
|
# * Validating if the model allows params authentication;
|
|
|
|
# * If the request hits the sessions controller through POST;
|
|
|
|
# * If the params[scope] returns a hash with credentials;
|
|
|
|
# * If all authentication keys are present;
|
|
|
|
#
|
2010-03-29 20:52:34 +02:00
|
|
|
def valid_for_params_auth?
|
2010-04-06 22:36:41 +02:00
|
|
|
params_authenticatable? && valid_request? &&
|
|
|
|
valid_params? && with_authentication_hash(params_auth_hash)
|
2010-03-29 20:52:34 +02:00
|
|
|
end
|
|
|
|
|
2010-04-01 19:09:33 +02:00
|
|
|
# Check if the model accepts this strategy as http authenticatable.
|
|
|
|
def http_authenticatable?
|
|
|
|
mapping.to.http_authenticatable?(authenticatable_name)
|
2010-03-29 20:52:34 +02:00
|
|
|
end
|
|
|
|
|
2010-04-01 19:09:33 +02:00
|
|
|
# Check if the model accepts this strategy as params authenticatable.
|
|
|
|
def params_authenticatable?
|
|
|
|
mapping.to.params_authenticatable?(authenticatable_name)
|
2010-03-29 20:52:34 +02:00
|
|
|
end
|
|
|
|
|
2010-04-01 19:09:33 +02:00
|
|
|
# Extract the appropriate subhash for authentication from params.
|
|
|
|
def params_auth_hash
|
|
|
|
params[scope]
|
|
|
|
end
|
|
|
|
|
|
|
|
# Extract a hash with attributes:values from the http params.
|
|
|
|
def http_auth_hash
|
2010-03-29 20:52:34 +02:00
|
|
|
keys = [authentication_keys.first, :password]
|
2010-04-01 19:09:33 +02:00
|
|
|
Hash[*keys.zip(decode_credentials).flatten]
|
|
|
|
end
|
|
|
|
|
2010-04-01 22:11:59 +02:00
|
|
|
# By default, a request is valid if the controller is allowed and the VERB is POST.
|
|
|
|
def valid_request?
|
|
|
|
valid_controller? && valid_verb?
|
|
|
|
end
|
|
|
|
|
2010-05-16 14:13:43 +02:00
|
|
|
# Check if the controller is the one registered for authentication.
|
2010-04-01 19:09:33 +02:00
|
|
|
def valid_controller?
|
|
|
|
mapping.controllers[:sessions] == params[:controller]
|
2010-03-29 20:52:34 +02:00
|
|
|
end
|
|
|
|
|
2010-05-16 14:13:43 +02:00
|
|
|
# Check if it was a POST request.
|
2010-04-01 22:11:59 +02:00
|
|
|
def valid_verb?
|
|
|
|
request.post?
|
|
|
|
end
|
|
|
|
|
|
|
|
# If the request is valid, finally check if params_auth_hash returns a hash.
|
2010-04-01 19:09:33 +02:00
|
|
|
def valid_params?
|
|
|
|
params_auth_hash.is_a?(Hash)
|
|
|
|
end
|
|
|
|
|
2010-05-16 14:13:43 +02:00
|
|
|
# Check if password is present and is not equal to "X" (default value for token).
|
|
|
|
def valid_password?
|
|
|
|
password.present? && password != "X"
|
|
|
|
end
|
|
|
|
|
2010-04-01 19:09:33 +02:00
|
|
|
# Helper to decode credentials from HTTP.
|
2010-03-29 20:52:34 +02:00
|
|
|
def decode_credentials
|
|
|
|
username_and_password = request.authorization.split(' ', 2).last || ''
|
|
|
|
ActiveSupport::Base64.decode64(username_and_password).split(/:/, 2)
|
|
|
|
end
|
|
|
|
|
2010-04-01 19:09:33 +02:00
|
|
|
# Sets the authentication hash and the password from params_auth_hash or http_auth_hash.
|
2010-03-29 20:52:34 +02:00
|
|
|
def with_authentication_hash(hash)
|
|
|
|
self.authentication_hash = hash.slice(*authentication_keys)
|
|
|
|
self.password = hash[:password]
|
2010-04-01 19:09:33 +02:00
|
|
|
authentication_keys.all?{ |k| authentication_hash[k].present? }
|
2010-03-29 20:52:34 +02:00
|
|
|
end
|
|
|
|
|
2010-04-01 19:09:33 +02:00
|
|
|
# Holds the authentication keys.
|
2010-03-29 20:52:34 +02:00
|
|
|
def authentication_keys
|
|
|
|
@authentication_keys ||= mapping.to.authentication_keys
|
|
|
|
end
|
2010-04-01 19:09:33 +02:00
|
|
|
|
|
|
|
# Holds the authenticatable name for this class. Devise::Strategies::DatabaseAuthenticatable
|
|
|
|
# becomes simply :database.
|
|
|
|
def authenticatable_name
|
|
|
|
@authenticatable_name ||=
|
|
|
|
self.class.name.split("::").last.underscore.sub("_authenticatable", "").to_sym
|
|
|
|
end
|
2010-03-29 20:52:34 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|