mirror of
https://github.com/heartcombo/devise.git
synced 2026-01-10 07:18:14 -05:00
:activatable is included by default in your models. If you are building a strategy for devise, you now need to call validate(resource), since Devise has now a default API to validate resources before and after signing them in. You can still use other Warden::Strategies with Devise, but they won't work with a few modules like unlockable (they never did, but now we have a single point to make it work).
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
* TokenAuthenticatable now works with HTTP Basic Auth.
|
||||
* Allow :unlock_strategy to be :none and add :lock_strategy which can be :failed_attempts or none. Setting those values to :none means that you want to handle lock and unlocking by yourself.
|
||||
* No need to append ?unauthenticated=true in URLs anymore since Flash was moved to a middleware in Rails 3.
|
||||
* :activatable is included by default in your models.
|
||||
|
||||
* deprecations
|
||||
* Rails 3 compatible only.
|
||||
|
||||
@@ -19,7 +19,6 @@ Right now it's composed of 11 modules:
|
||||
* Timeoutable: expires sessions that have no activity in a specified period of time.
|
||||
* Validatable: provides validations of email and password. It's optional and can be customized, so you're able to define your own validations.
|
||||
* Lockable: locks an account after a specified number of failed sign-in attempts. Can unlock via email or after a specified time period.
|
||||
* Activatable: use this module if you need to activate accounts by means other than confirmation.
|
||||
|
||||
== Examples
|
||||
|
||||
|
||||
1
TODO
1
TODO
@@ -1,3 +1,2 @@
|
||||
* Extract Activatable tests from Confirmable
|
||||
* Move integration tests to Capybara
|
||||
* Better ORM integration
|
||||
|
||||
@@ -5,23 +5,4 @@ Warden::Manager.after_set_user do |record, warden, options|
|
||||
warden.logout(scope)
|
||||
throw :warden, :scope => scope, :message => record.inactive_message
|
||||
end
|
||||
end
|
||||
|
||||
module Devise
|
||||
module Hooks
|
||||
# Overwrite Devise base strategy to only authenticate an user if it's active.
|
||||
# If you have an strategy that does not use Devise::Strategy::Base, don't worry
|
||||
# because the hook above will still avoid it to authenticate.
|
||||
module Activatable
|
||||
def success!(resource)
|
||||
if resource.respond_to?(:active?) && !resource.active?
|
||||
fail!(resource.inactive_message)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Devise::Strategies::Base.send :include, Devise::Hooks::Activatable
|
||||
end
|
||||
10
lib/devise/hooks/forgetable.rb
Normal file
10
lib/devise/hooks/forgetable.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
# Before logout hook to forget the user in the given scope, if it responds
|
||||
# to forget_me! Also clear remember token to ensure the user won't be
|
||||
# remembered again. Notice that we forget the user unless the record is frozen.
|
||||
# This avoids forgetting deleted users.
|
||||
Warden::Manager.before_logout do |record, warden, scope|
|
||||
if record.respond_to?(:forget_me!)
|
||||
record.forget_me! unless record.frozen?
|
||||
warden.cookies.delete "remember_#{scope}_token"
|
||||
end
|
||||
end
|
||||
@@ -1,19 +1,9 @@
|
||||
# Before logout hook to forget the user in the given scope, if it responds
|
||||
# to forget_me! Also clear remember token to ensure the user won't be
|
||||
# remembered again. Notice that we forget the user unless the record is frozen.
|
||||
# This avoids forgetting deleted users.
|
||||
Warden::Manager.before_logout do |record, warden, scope|
|
||||
if record.respond_to?(:forget_me!)
|
||||
record.forget_me! unless record.frozen?
|
||||
warden.cookies.delete "remember_#{scope}_token"
|
||||
end
|
||||
end
|
||||
|
||||
module Devise
|
||||
module Hooks
|
||||
# Overwrite success! in authentication strategies allowing users to be remembered.
|
||||
# We choose to implement this as an strategy hook instead of a Devise hook to avoid users
|
||||
# giving a remember_me access in strategies that should not create remember me tokens.
|
||||
# We choose to implement this as an strategy hook instead of a warden hook to allow a specific
|
||||
# strategy (like token authenticatable or facebook authenticatable) to turn off remember_me?
|
||||
# cookies.
|
||||
module Rememberable #:nodoc:
|
||||
def success!(resource)
|
||||
super
|
||||
@@ -29,7 +19,7 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
protected
|
||||
|
||||
def remember_me?
|
||||
valid_params? && Devise::TRUE_VALUES.include?(params_auth_hash[:remember_me])
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'devise/models/authenticatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# Creates configuration values for Devise and for the given module.
|
||||
@@ -45,7 +47,7 @@ module Devise
|
||||
# for a complete description on those values.
|
||||
#
|
||||
def devise(*modules)
|
||||
raise "You need to give at least one Devise module" if modules.empty?
|
||||
include Devise::Models::Authenticatable
|
||||
options = modules.extract_options!
|
||||
|
||||
if modules.delete(:authenticatable)
|
||||
@@ -53,6 +55,10 @@ module Devise
|
||||
modules << :database_authenticatable
|
||||
end
|
||||
|
||||
if modules.delete(:activatable)
|
||||
ActiveSupport::Deprecation.warn ":activatable as module is deprecated. It's included in your model by default.", caller
|
||||
end
|
||||
|
||||
if modules.delete(:http_authenticatable)
|
||||
ActiveSupport::Deprecation.warn ":http_authenticatable as module is deprecated and is on by default. Revert by setting :http_authenticatable => false.", caller
|
||||
end
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
require 'devise/hooks/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# This module implements the default API required in activatable hook.
|
||||
module Activatable
|
||||
def active?
|
||||
true
|
||||
end
|
||||
|
||||
def inactive_message
|
||||
:inactive
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,10 @@
|
||||
require 'devise/hooks/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
# Authenticable module. Holds common settings for authentication.
|
||||
#
|
||||
# Configuration:
|
||||
# == Configuration:
|
||||
#
|
||||
# You can overwrite configuration values by setting in globally in Devise,
|
||||
# using devise method or overwriting the respective instance method.
|
||||
@@ -15,13 +17,47 @@ module Devise
|
||||
# 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.
|
||||
#
|
||||
# == Active?
|
||||
#
|
||||
# Before authenticating an user and in each request, Devise checks if your model is active by
|
||||
# calling model.active?. This method is overwriten by other devise modules. For instance,
|
||||
# :confirmable overwrites .active? to only return true if your model was confirmed.
|
||||
#
|
||||
# You overwrite this method yourself, but if you do, don't forget to call super:
|
||||
#
|
||||
# def active?
|
||||
# super && special_condition_is_valid?
|
||||
# end
|
||||
#
|
||||
# Whenever active? returns false, Devise asks the reason why your model is inactive using
|
||||
# the inactive_message method. You can overwrite it as well:
|
||||
#
|
||||
# def inactive_message
|
||||
# special_condition_is_valid? ? super : :special_condition_is_not_valid
|
||||
# end
|
||||
#
|
||||
module Authenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# Yields the given block. This method is overwritten by other modules to provide
|
||||
# hooks around authentication.
|
||||
# Check if the current object is valid for authentication. This method and find_for_authentication
|
||||
# are the methods used in a Warden::Strategy to check if a model should be signed in or not.
|
||||
#
|
||||
# However, you should not need to overwrite this method, you should overwrite active? and
|
||||
# inactive_message instead.
|
||||
def valid_for_authentication?
|
||||
yield
|
||||
if active?
|
||||
block_given? ? yield : true
|
||||
else
|
||||
inactive_message
|
||||
end
|
||||
end
|
||||
|
||||
def active?
|
||||
true
|
||||
end
|
||||
|
||||
def inactive_message
|
||||
:inactive
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
require 'devise/models/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
|
||||
# Confirmable is responsible to verify if an account is already confirmed to
|
||||
# sign in, and to send emails with confirmation instructions.
|
||||
# Confirmation instructions are sent to the user email after creating a
|
||||
@@ -30,7 +27,6 @@ module Devise
|
||||
# User.find(1).resend_confirmation! # generates a new token and resent it
|
||||
module Confirmable
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Activatable
|
||||
|
||||
included do
|
||||
before_create :generate_confirmation_token, :if => :confirmation_required?
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
require 'devise/models/authenticatable'
|
||||
require 'devise/strategies/database_authenticatable'
|
||||
|
||||
module Devise
|
||||
@@ -25,8 +24,7 @@ module Devise
|
||||
# User.find(1).valid_password?('password123') # returns true/false
|
||||
#
|
||||
module DatabaseAuthenticatable
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Authenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
attr_reader :password, :current_password
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
require 'devise/models/activatable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
|
||||
# Handles blocking a user access after a certain number of attempts.
|
||||
# Lockable accepts two different strategies to unlock a user after it's
|
||||
# blocked: email and time. The former will send an email to the user when
|
||||
@@ -20,7 +17,6 @@ module Devise
|
||||
#
|
||||
module Lockable
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Activatable
|
||||
|
||||
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
|
||||
|
||||
@@ -77,15 +73,15 @@ module Devise
|
||||
# for verifying whether an user is allowed to sign in or not. If the user
|
||||
# is locked, it should never be allowed.
|
||||
def valid_for_authentication?
|
||||
return :locked if access_locked?
|
||||
return super unless persisted?
|
||||
return super unless lock_strategy_enabled?(:failed_attempts)
|
||||
return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
|
||||
|
||||
if result = super
|
||||
case (result = super)
|
||||
when Symbol
|
||||
return result
|
||||
when TrueClass
|
||||
self.failed_attempts = 0
|
||||
else
|
||||
when FalseClass
|
||||
self.failed_attempts += 1
|
||||
|
||||
if attempts_exceeded?
|
||||
lock_access!
|
||||
return :locked
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'devise/strategies/rememberable'
|
||||
require 'devise/hooks/rememberable'
|
||||
require 'devise/hooks/forgetable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
|
||||
@@ -16,8 +16,7 @@ module Devise
|
||||
# +token_authentication_key+ - Defines name of the authentication token params key. E.g. /users/sign_in?some_key=...
|
||||
#
|
||||
module TokenAuthenticatable
|
||||
extend ActiveSupport::Concern
|
||||
include Devise::Models::Authenticatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
# Generate new authentication token (a.k.a. "single access token").
|
||||
def reset_authentication_token
|
||||
|
||||
@@ -14,7 +14,6 @@ Devise.with_options :model => true do |d|
|
||||
d.add_module :validatable
|
||||
|
||||
# The ones which can sign out after
|
||||
d.add_module :activatable
|
||||
d.add_module :confirmable, :controller => :confirmations, :route => :confirmation
|
||||
d.add_module :lockable, :controller => :unlocks, :route => :unlock
|
||||
d.add_module :timeoutable
|
||||
|
||||
@@ -14,18 +14,6 @@ module Devise
|
||||
|
||||
private
|
||||
|
||||
# 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
|
||||
|
||||
# Check if this is strategy is valid for http authentication.
|
||||
def valid_for_http_auth?
|
||||
http_authenticatable? && request.authorization &&
|
||||
|
||||
@@ -11,9 +11,23 @@ module Devise
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def succeeded?
|
||||
@result == :success
|
||||
end
|
||||
|
||||
# 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
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -16,7 +16,9 @@ module Devise
|
||||
# the record in the database. If the attempt fails, we pass to another
|
||||
# strategy handle the authentication.
|
||||
def authenticate!
|
||||
if resource = mapping.to.serialize_from_cookie(*remember_cookie)
|
||||
resource = mapping.to.serialize_from_cookie(*remember_cookie)
|
||||
|
||||
if validate(resource)
|
||||
success!(resource)
|
||||
else
|
||||
cookies.delete(remember_key)
|
||||
|
||||
@@ -11,7 +11,9 @@ module Devise
|
||||
# you can pass anything and it will simply be ignored.
|
||||
class TokenAuthenticatable < Authenticatable
|
||||
def authenticate!
|
||||
if resource = mapping.to.find_for_token_authentication(authentication_hash)
|
||||
resource = mapping.to.find_for_token_authentication(authentication_hash)
|
||||
|
||||
if validate(resource)
|
||||
resource.after_token_authentication
|
||||
success!(resource)
|
||||
else
|
||||
|
||||
@@ -7,6 +7,7 @@ class LockableTest < ActiveSupport::TestCase
|
||||
|
||||
test "should respect maximum attempts configuration" do
|
||||
user = create_user
|
||||
user.confirm!
|
||||
swap Devise, :maximum_attempts => 2 do
|
||||
3.times { user.valid_for_authentication?{ false } }
|
||||
assert user.reload.access_locked?
|
||||
@@ -15,6 +16,7 @@ class LockableTest < ActiveSupport::TestCase
|
||||
|
||||
test "should clear failed_attempts on successfull validation" do
|
||||
user = create_user
|
||||
user.confirm!
|
||||
user.valid_for_authentication?{ false }
|
||||
assert_equal 1, user.reload.failed_attempts
|
||||
user.valid_for_authentication?{ true }
|
||||
@@ -23,6 +25,7 @@ class LockableTest < ActiveSupport::TestCase
|
||||
|
||||
test "should not touch failed_attempts if lock_strategy is none" do
|
||||
user = create_user
|
||||
user.confirm!
|
||||
swap Devise, :lock_strategy => :none, :maximum_attempts => 2 do
|
||||
3.times { user.valid_for_authentication?{ false } }
|
||||
assert !user.access_locked?
|
||||
|
||||
Reference in New Issue
Block a user