mirror of
https://github.com/heartcombo/devise.git
synced 2026-01-10 23:38:10 -05:00
Second version of token_authenticatable reflecting feedback: Nuked all hook-stuff. Should be easy to custom-reset authentication tokens by inheritance.
Signed-off-by: José Valim <jose.valim@gmail.com>
This commit is contained in:
committed by
José Valim
parent
e1440fb430
commit
4878bdb60b
@@ -18,7 +18,7 @@ class SessionsController < ApplicationController
|
||||
set_flash_message :notice, :signed_in
|
||||
sign_in_and_redirect(resource_name, resource, true)
|
||||
else
|
||||
set_now_flash_message :alert, (warden.message || :invalid)
|
||||
set_now_flash_message :alert, warden.message || :invalid
|
||||
build_resource
|
||||
render_with_scope :new
|
||||
end
|
||||
|
||||
@@ -132,17 +132,6 @@ module Devise
|
||||
mattr_accessor :mailer_sender
|
||||
@@mailer_sender
|
||||
|
||||
# Array of known events that should trigger a authentication token reset.
|
||||
#
|
||||
# == Valid events:
|
||||
#
|
||||
# Warden: :after_set_user, :before_logout
|
||||
# Authenticatable: :after_changed_password
|
||||
#
|
||||
# Note: If set to nil, authentication token will never be reset automatically.
|
||||
mattr_accessor :reset_authentication_token_on
|
||||
@@reset_authentication_token_on = nil
|
||||
|
||||
# Authentication token params key name of choice. E.g. /users/sign_in?some_key=...
|
||||
mattr_accessor :authentication_token_param_key
|
||||
@@authentication_token_param_key = :auth_token
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# After each Warden-sign-in: Ensure authentication token is set - if this is enabled.
|
||||
Warden::Manager.after_authentication do |record, warden, options|
|
||||
scope = options[:scope]
|
||||
puts "#"
|
||||
if Devise.mappings[scope].try(:token_authenticatable?) && warden.authenticated?(scope)
|
||||
Devise.reset_authentication_token_on ||= []
|
||||
|
||||
if Devise.reset_authentication_token_on.include?(:after_set_user)
|
||||
record.reset_authentication_token!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# After each Authenticatable-password-change: Ensure authentication token is re-set - if this is enabled.
|
||||
Devise.after_changed_password do |record, scope|
|
||||
if Devise.mappings[scope].try(:token_authenticatable?)
|
||||
Devise.reset_authentication_token_on ||= []
|
||||
|
||||
if Devise.reset_authentication_token_on.include?(:after_changed_password)
|
||||
record.reset_authentication_token!
|
||||
end
|
||||
end
|
||||
end if Devise.respond_to?(:after_changed_password)
|
||||
@@ -46,53 +46,6 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
# Creates events/hooks for Devise and for the given module.
|
||||
#
|
||||
# Devise::Models.events(Devise::Authenticable, :after_changed_password, :after_timeout_hooks)
|
||||
#
|
||||
# The line above creates:
|
||||
#
|
||||
# 1) Accessor for each hook holding any callback hooks (see +Devise::Models::config+), or explicit:
|
||||
#
|
||||
# Devise::Models.config(Devise::Authenticable, :after_changed_password_hooks, :after_timeout_hooks)
|
||||
#
|
||||
# 1) Setup module accessor hook holding any callback hooks (default fallback config that is):
|
||||
#
|
||||
# Devise.after_changed_password_hooks = []
|
||||
# Devise.after_timeout_hooks = []
|
||||
#
|
||||
# 2) Callback hooks: +Devise::Authenticable.after_changed_password_hooks+ and +Devise::Authenticable.on_timeout+,
|
||||
# used in same manner as +Warden::Manager::after_set_user+, etc.
|
||||
#
|
||||
# To add the class methods you need to have a module ClassMethods defined
|
||||
# inside the given class.
|
||||
#
|
||||
def self.events(mod, *events)
|
||||
::Devise::Models.config(mod, *events.collect { |event| :"#{event}_hooks" })
|
||||
|
||||
events.each do |event|
|
||||
::Devise.class_eval <<-METHOD, __FILE__, __LINE__
|
||||
mattr_accessor :#{event}_hooks
|
||||
@@#{event}_hooks = []
|
||||
|
||||
# Hook for changed password event.
|
||||
def self.#{event}(options = {}, &block)
|
||||
raise BlockNotGiven unless block_given?
|
||||
self.#{event}_hooks << [block, options]
|
||||
end
|
||||
METHOD
|
||||
end
|
||||
end
|
||||
|
||||
# Triggers a named event for a Devise model instance, or more explicitly
|
||||
# triggers all callback hooks for this event.
|
||||
#
|
||||
def self.event!(object, event, *args)
|
||||
object.class.send(:"#{event}_hooks").each { |hook| hook.first.call(*args[0..hook.first.arity]) }
|
||||
rescue
|
||||
# raise "An invalid event was triggered: #{event}. See Devise::Models::events() for usage."
|
||||
end
|
||||
|
||||
# Include the chosen devise modules in your model:
|
||||
#
|
||||
# devise :authenticatable, :confirmable, :recoverable
|
||||
|
||||
@@ -45,8 +45,6 @@ module Devise
|
||||
self.password_salt = self.class.encryptor_class.salt
|
||||
self.encrypted_password = password_digest(@password)
|
||||
end
|
||||
|
||||
::Devise::Models.event!(self, :after_changed_password, self, self.class.name.underscore.to_sym)
|
||||
end
|
||||
|
||||
# Verifies whether an incoming_password (ie from sign in) is the user password.
|
||||
@@ -83,14 +81,9 @@ module Devise
|
||||
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
|
||||
end
|
||||
|
||||
def password_changed?
|
||||
!valid_password?(params[:old_password])
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
Devise::Models.config(self, :pepper, :stretches, :encryptor, :authentication_keys)
|
||||
Devise::Models.events(self, :after_changed_password)
|
||||
|
||||
# Authenticate a user based on configured attribute keys. Returns the
|
||||
# authenticated user if it's valid or nil. Attributes are by default
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
require 'devise/strategies/token_authenticatable'
|
||||
require 'devise/hooks/token_authenticatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
@@ -30,13 +29,11 @@ module Devise
|
||||
end
|
||||
|
||||
# Generate authentication token unless already exists.
|
||||
#
|
||||
def ensure_authentication_token!
|
||||
self.reset_authentication_token!(false) if self.authentication_token.blank?
|
||||
end
|
||||
|
||||
# Generate new authentication token (a.k.a. "single access token").
|
||||
#
|
||||
def reset_authentication_token!(do_save = true)
|
||||
self.authentication_token = self.class.authentication_token
|
||||
self.save if do_save
|
||||
@@ -44,17 +41,15 @@ module Devise
|
||||
|
||||
# Verifies whether an +incoming_authentication_token+ (i.e. from single access URL)
|
||||
# is the user authentication token.
|
||||
#
|
||||
def valid_authentication_token?(incoming_auth_token)
|
||||
incoming_auth_token.present? && incoming_auth_token == self.authentication_token
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
::Devise::Models.config(self, :authentication_token_param_key, :reset_authentication_token_on)
|
||||
::Devise::Models.config(self, :authentication_token_param_key)
|
||||
|
||||
# Authenticate a user based on authentication token.
|
||||
#
|
||||
def authenticate_with_token(attributes = {})
|
||||
token = attributes[::Devise.authentication_token_param_key]
|
||||
resource = self.find_for_token_authentication(token)
|
||||
@@ -70,7 +65,8 @@ module Devise
|
||||
# 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
|
||||
# namedscope to filter records while authenticating.
|
||||
# Example:
|
||||
#
|
||||
# == Example:
|
||||
#
|
||||
# def self.find_for_token_authentication(token, conditions = {})
|
||||
# conditions = {:active => true}
|
||||
|
||||
@@ -22,6 +22,7 @@ module Devise
|
||||
|
||||
private
|
||||
|
||||
# Detect authentication token in params: scoped or not.
|
||||
def authentication_token(scope)
|
||||
if params[scope]
|
||||
params[scope][::Devise.authentication_token_param_key]
|
||||
|
||||
@@ -46,63 +46,6 @@ class TokenAuthenticationTest < ActionController::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
test "authentication token should not be reset - if not set to do so if enabled" do
|
||||
swap Devise, :reset_authentication_token_on => [] do
|
||||
User.expects(:authentication_token).returns(VALID_AUTHENTICATION_TOKEN)
|
||||
user = create_user
|
||||
assert_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
|
||||
|
||||
# after_set_user-event
|
||||
user = sign_in_as_existing_user_with_token(:auth_token => VALID_AUTHENTICATION_TOKEN)
|
||||
assert_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
|
||||
|
||||
# after_changed_password-event
|
||||
user.password = "new_pass"
|
||||
user.save
|
||||
assert_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
|
||||
end
|
||||
end
|
||||
|
||||
test "authentication token should be reset after changed password if enabled" do
|
||||
swap Devise, :reset_authentication_token_on => [:after_changed_password] do
|
||||
User.expects(:authentication_token).returns(VALID_AUTHENTICATION_TOKEN)
|
||||
user = create_user
|
||||
assert_not_blank user.authentication_token
|
||||
assert_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
|
||||
|
||||
# after_set_user-event
|
||||
user = sign_in_as_existing_user_with_token(:auth_token => VALID_AUTHENTICATION_TOKEN)
|
||||
assert_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
|
||||
|
||||
# after_changed_password-event
|
||||
User.expects(:authentication_token).returns("*** NEW TOKEN / CHANGED PASSWORD ***")
|
||||
user.password = "new_pass"
|
||||
user.save
|
||||
assert_not_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
|
||||
end
|
||||
end
|
||||
|
||||
# Problem: Warden::Manager.after_authenticate and/or Warden::Manager.after_set_user ignores my hook. Why? =(
|
||||
# See: lib/devise/hooks/token_authenticatable.rb
|
||||
test "authentication token should be reset after logging in if enabled" do
|
||||
swap Devise, :reset_authentication_token_on => [:after_set_user] do
|
||||
User.expects(:authentication_token).returns(VALID_AUTHENTICATION_TOKEN)
|
||||
user = create_user
|
||||
assert_not_blank user.authentication_token
|
||||
assert_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
|
||||
|
||||
# after_changed_password-event
|
||||
user.password = "new_pass"
|
||||
user.save
|
||||
assert_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
|
||||
|
||||
# FIXME: after_set_user-event
|
||||
User.expects(:authentication_token).returns("*** NEW TOKEN / SIGN IN ***")
|
||||
user = sign_in_as_existing_user_with_token(:auth_token => VALID_AUTHENTICATION_TOKEN)
|
||||
assert_not_equal VALID_AUTHENTICATION_TOKEN, user.authentication_token
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sign_in_as_new_user_with_token(options = {}, &block)
|
||||
@@ -115,12 +58,4 @@ class TokenAuthenticationTest < ActionController::IntegrationTest
|
||||
user
|
||||
end
|
||||
|
||||
def sign_in_as_existing_user_with_token(options = {}, &block)
|
||||
options[:auth_token_key] ||= Devise.authentication_token_param_key
|
||||
options[:auth_token] ||= VALID_AUTHENTICATION_TOKEN
|
||||
user = User.authenticate_with_token(options[:auth_token_key].to_sym => options[:auth_token])
|
||||
yield if block_given?
|
||||
user
|
||||
end
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user