mirror of
https://github.com/heartcombo/devise.git
synced 2026-04-28 03:00:29 -04:00
TokenAuthenticatable now works with HTTP Basic Auth by default (take a look at Highrise API for a good example). This basically allows you to pass the authentication token as HTTP Basic Auth username.
This commit is contained in:
@@ -64,6 +64,10 @@ module Devise
|
||||
mattr_accessor :http_authenticatable
|
||||
@@http_authenticatable = true
|
||||
|
||||
# If params authenticatable is enabled by default.
|
||||
mattr_accessor :params_authenticatable
|
||||
@@params_authenticatable = true
|
||||
|
||||
# The realm used in Http Basic Authentication.
|
||||
mattr_accessor :http_authentication_realm
|
||||
@@http_authentication_realm = "Application"
|
||||
|
||||
@@ -10,6 +10,10 @@ module Devise
|
||||
# authentication_keys: parameters used for authentication. By default [:email].
|
||||
#
|
||||
# http_authenticatable: if this model allows http authentication. By default true.
|
||||
# It also accepts an array specifying the strategies that should allow http.
|
||||
#
|
||||
# params_authenticatable: if this model allows authentication through request params. By default true.
|
||||
# It also accepts an array specifying the strategies that should allow params authentication.
|
||||
#
|
||||
module Authenticatable
|
||||
extend ActiveSupport::Concern
|
||||
@@ -21,9 +25,17 @@ module Devise
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
Devise::Models.config(self, :authentication_keys, :http_authenticatable)
|
||||
Devise::Models.config(self, :authentication_keys, :http_authenticatable, :params_authenticatable)
|
||||
|
||||
alias :http_authenticatable? :http_authenticatable
|
||||
def params_authenticatable?(strategy)
|
||||
params_authenticatable.is_a?(Array) ?
|
||||
params_authenticatable.include?(strategy) : params_authenticatable
|
||||
end
|
||||
|
||||
def http_authenticatable?(strategy)
|
||||
http_authenticatable.is_a?(Array) ?
|
||||
http_authenticatable.include?(strategy) : http_authenticatable
|
||||
end
|
||||
|
||||
# Find first record based on conditions given (ie by the sign in form).
|
||||
# Overwrite to add customized conditions, create a join, or maybe use a
|
||||
|
||||
@@ -18,7 +18,8 @@ module Devise
|
||||
# User.find(1).valid_authentication_token?('rI1t6PKQ8yP7VetgwdybB') # returns true/false
|
||||
#
|
||||
module TokenAuthenticatable
|
||||
extend ActiveSupport::Concern
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Authenticatable
|
||||
|
||||
included do
|
||||
before_save :ensure_authentication_token
|
||||
|
||||
@@ -26,45 +26,72 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
# Check if this is strategy is valid for http authentication.
|
||||
def valid_for_http_auth?
|
||||
mapping.to.http_authenticatable? && request.authorization && set_http_auth_hash
|
||||
http_authenticatable? && request.authorization && with_authentication_hash(http_auth_hash)
|
||||
end
|
||||
|
||||
# Check if this is strategy is valid for params authentication.
|
||||
def valid_for_params_auth?
|
||||
valid_controller? && valid_params? && set_params_auth_hash
|
||||
params_authenticatable? && valid_controller? &&
|
||||
valid_params? && with_authentication_hash(params_auth_hash)
|
||||
end
|
||||
|
||||
# Check if the model accepts this strategy as http authenticatable.
|
||||
def http_authenticatable?
|
||||
mapping.to.http_authenticatable?(authenticatable_name)
|
||||
end
|
||||
|
||||
# Check if the model accepts this strategy as params authenticatable.
|
||||
def params_authenticatable?
|
||||
mapping.to.params_authenticatable?(authenticatable_name)
|
||||
end
|
||||
|
||||
# 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
|
||||
keys = [authentication_keys.first, :password]
|
||||
Hash[*keys.zip(decode_credentials).flatten]
|
||||
end
|
||||
|
||||
# Check if the controller is valid for params authentication.
|
||||
def valid_controller?
|
||||
mapping.controllers[:sessions] == params[:controller]
|
||||
end
|
||||
|
||||
# Check if the params_auth_hash is valid for params authentication.
|
||||
def valid_params?
|
||||
params[scope].is_a?(Hash)
|
||||
end
|
||||
|
||||
def set_http_auth_hash
|
||||
keys = [authentication_keys.first, :password]
|
||||
with_authentication_hash Hash[*keys.zip(decode_credentials).flatten]
|
||||
params_auth_hash.is_a?(Hash)
|
||||
end
|
||||
|
||||
# Helper to decode credentials from HTTP.
|
||||
def decode_credentials
|
||||
username_and_password = request.authorization.split(' ', 2).last || ''
|
||||
ActiveSupport::Base64.decode64(username_and_password).split(/:/, 2)
|
||||
end
|
||||
|
||||
def set_params_auth_hash
|
||||
with_authentication_hash params[scope]
|
||||
end
|
||||
|
||||
# Sets the authentication hash and the password from params_auth_hash or http_auth_hash.
|
||||
def with_authentication_hash(hash)
|
||||
self.authentication_hash = hash.slice(*authentication_keys)
|
||||
self.password = hash[:password]
|
||||
authentication_keys.all?{ |k| authentication_hash[k].present? } && password.present?
|
||||
authentication_keys.all?{ |k| authentication_hash[k].present? }
|
||||
end
|
||||
|
||||
# Holds the authentication keys.
|
||||
def authentication_keys
|
||||
@authentication_keys ||= mapping.to.authentication_keys
|
||||
end
|
||||
|
||||
# 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
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,33 +2,42 @@ require 'devise/strategies/base'
|
||||
|
||||
module Devise
|
||||
module Strategies
|
||||
# Strategy for signing in a user, based on a authenticatable token.
|
||||
# Redirects to sign_in page if it's not authenticated.
|
||||
class TokenAuthenticatable < Base
|
||||
def valid?
|
||||
authentication_token(scope).present?
|
||||
end
|
||||
|
||||
# Authenticate a user based on authenticatable token params, returning to warden
|
||||
# success and the authenticated user if everything is okay. Otherwise redirect
|
||||
# to sign in page.
|
||||
# Strategy for signing in a user, based on a authenticatable token. This works for both params
|
||||
# and http. For the former, all you need to do is to pass the params in the URL:
|
||||
#
|
||||
# http://myapp.example.com/?user_token=SECRET
|
||||
#
|
||||
# For HTTP, you can pass the token as username. Since some clients may require a password,
|
||||
# you can pass anything and it will simply be ignored.
|
||||
class TokenAuthenticatable < Authenticatable
|
||||
def authenticate!
|
||||
if resource = mapping.to.authenticate_with_token(params[scope] || params)
|
||||
if resource = mapping.to.authenticate_with_token(authentication_hash)
|
||||
success!(resource)
|
||||
else
|
||||
fail!(:invalid_token)
|
||||
fail(:invalid_token)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Detect authentication token in params: scoped or not.
|
||||
def authentication_token(scope)
|
||||
if params[scope]
|
||||
params[scope][mapping.to.token_authentication_key]
|
||||
else
|
||||
params[mapping.to.token_authentication_key]
|
||||
end
|
||||
# TokenAuthenticatable params can be given to any controller.
|
||||
def valid_controller?
|
||||
true
|
||||
end
|
||||
|
||||
# Do not use remember_me behavir with token.
|
||||
def remember_me?
|
||||
false
|
||||
end
|
||||
|
||||
# Try both scoped and non scoped keys.
|
||||
def params_auth_hash
|
||||
params[scope] || params
|
||||
end
|
||||
|
||||
# Overwrite authentication keys to use token_authentication_key.
|
||||
def authentication_keys
|
||||
@authentication_keys ||= [mapping.to.token_authentication_key]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user