devise 1.1.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +10 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.rdoc +94 -0
- data/Gemfile +24 -13
- data/Gemfile.lock +119 -75
- data/MIT-LICENSE +1 -1
- data/README.rdoc +144 -101
- data/Rakefile +3 -24
- data/app/controllers/devise/confirmations_controller.rb +1 -1
- data/app/controllers/devise/omniauth_callbacks_controller.rb +26 -0
- data/app/controllers/devise/passwords_controller.rb +1 -1
- data/app/controllers/devise/registrations_controller.rb +60 -7
- data/app/controllers/devise/sessions_controller.rb +6 -4
- data/app/controllers/devise/unlocks_controller.rb +1 -1
- data/app/helpers/devise_helper.rb +10 -2
- data/app/mailers/devise/mailer.rb +27 -10
- data/app/views/devise/confirmations/new.html.erb +1 -1
- data/app/views/devise/passwords/edit.html.erb +2 -2
- data/app/views/devise/passwords/new.html.erb +1 -1
- data/app/views/devise/registrations/edit.html.erb +1 -1
- data/app/views/devise/registrations/new.html.erb +1 -1
- data/app/views/devise/sessions/new.html.erb +1 -1
- data/app/views/devise/shared/_links.erb +6 -0
- data/app/views/devise/unlocks/new.html.erb +1 -1
- data/config/locales/en.yml +11 -2
- data/devise.gemspec +25 -0
- data/lib/devise/controllers/helpers.rb +119 -116
- data/lib/devise/controllers/internal_helpers.rb +29 -8
- data/lib/devise/controllers/rememberable.rb +52 -0
- data/lib/devise/controllers/scoped_views.rb +4 -6
- data/lib/devise/controllers/url_helpers.rb +3 -5
- data/lib/devise/encryptors/authlogic_sha512.rb +1 -1
- data/lib/devise/encryptors/base.rb +1 -1
- data/lib/devise/encryptors/restful_authentication_sha1.rb +4 -4
- data/lib/devise/failure_app.rb +46 -10
- data/lib/devise/hooks/activatable.rb +2 -2
- data/lib/devise/hooks/forgetable.rb +1 -3
- data/lib/devise/hooks/rememberable.rb +5 -42
- data/lib/devise/hooks/timeoutable.rb +1 -1
- data/lib/devise/mapping.rb +18 -7
- data/lib/devise/models/authenticatable.rb +73 -31
- data/lib/devise/models/confirmable.rb +16 -20
- data/lib/devise/models/database_authenticatable.rb +27 -37
- data/lib/devise/models/encryptable.rb +72 -0
- data/lib/devise/models/lockable.rb +27 -21
- data/lib/devise/models/omniauthable.rb +23 -0
- data/lib/devise/models/recoverable.rb +13 -3
- data/lib/devise/models/registerable.rb +13 -0
- data/lib/devise/models/rememberable.rb +39 -34
- data/lib/devise/models/timeoutable.rb +20 -3
- data/lib/devise/models/token_authenticatable.rb +22 -10
- data/lib/devise/models/validatable.rb +16 -4
- data/lib/devise/models.rb +4 -16
- data/lib/devise/modules.rb +15 -8
- data/lib/devise/omniauth/config.rb +18 -0
- data/lib/devise/omniauth/url_helpers.rb +33 -0
- data/lib/devise/omniauth.rb +32 -0
- data/lib/devise/orm/active_record.rb +2 -0
- data/lib/devise/orm/mongoid.rb +4 -2
- data/lib/devise/rails/routes.rb +67 -20
- data/lib/devise/rails/warden_compat.rb +101 -15
- data/lib/devise/rails.rb +33 -44
- data/lib/devise/schema.rb +16 -16
- data/lib/devise/strategies/authenticatable.rb +48 -7
- data/lib/devise/strategies/database_authenticatable.rb +1 -1
- data/lib/devise/strategies/rememberable.rb +6 -5
- data/lib/devise/strategies/token_authenticatable.rb +6 -2
- data/lib/devise/test_helpers.rb +13 -3
- data/lib/devise/version.rb +1 -1
- data/lib/devise.rb +162 -50
- data/lib/generators/active_record/devise_generator.rb +2 -2
- data/lib/generators/active_record/templates/migration.rb +2 -0
- data/lib/generators/devise/devise_generator.rb +3 -1
- data/lib/generators/devise/orm_helpers.rb +1 -1
- data/lib/generators/devise/views_generator.rb +8 -45
- data/lib/generators/mongoid/devise_generator.rb +2 -2
- data/lib/generators/templates/devise.rb +82 -39
- data/test/controllers/helpers_test.rb +78 -72
- data/test/controllers/internal_helpers_test.rb +29 -8
- data/test/controllers/url_helpers_test.rb +2 -1
- data/test/devise_test.rb +10 -0
- data/test/failure_app_test.rb +86 -22
- data/test/generators/active_record_generator_test.rb +24 -0
- data/test/generators/devise_generator_test.rb +33 -0
- data/test/generators/install_generator_test.rb +13 -0
- data/test/generators/mongoid_generator_test.rb +22 -0
- data/test/generators/views_generator_test.rb +35 -0
- data/test/indifferent_hash.rb +33 -0
- data/test/integration/authenticatable_test.rb +165 -62
- data/test/integration/database_authenticatable_test.rb +22 -0
- data/test/integration/http_authenticatable_test.rb +12 -2
- data/test/integration/omniauthable_test.rb +138 -0
- data/test/integration/recoverable_test.rb +39 -20
- data/test/integration/registerable_test.rb +60 -4
- data/test/integration/rememberable_test.rb +72 -29
- data/test/integration/timeoutable_test.rb +10 -1
- data/test/integration/token_authenticatable_test.rb +55 -6
- data/test/mailers/confirmation_instructions_test.rb +4 -0
- data/test/mailers/reset_password_instructions_test.rb +4 -0
- data/test/mailers/unlock_instructions_test.rb +4 -0
- data/test/mapping_test.rb +37 -3
- data/test/models/confirmable_test.rb +32 -15
- data/test/models/database_authenticatable_test.rb +14 -71
- data/test/models/encryptable_test.rb +65 -0
- data/test/models/lockable_test.rb +48 -11
- data/test/models/recoverable_test.rb +28 -2
- data/test/models/rememberable_test.rb +186 -125
- data/test/models/token_authenticatable_test.rb +19 -1
- data/test/models_test.rb +12 -5
- data/test/omniauth/url_helpers_test.rb +54 -0
- data/test/orm/mongoid.rb +3 -2
- data/test/rails_app/Rakefile +10 -0
- data/test/rails_app/app/active_record/admin.rb +4 -1
- data/test/rails_app/app/active_record/user.rb +5 -4
- data/test/rails_app/app/controllers/{sessions_controller.rb → admins/sessions_controller.rb} +1 -1
- data/test/rails_app/app/controllers/application_controller.rb +0 -1
- data/test/rails_app/app/controllers/home_controller.rb +9 -0
- data/test/rails_app/app/controllers/users/omniauth_callbacks_controller.rb +14 -0
- data/test/rails_app/app/mongoid/admin.rb +4 -1
- data/test/rails_app/app/mongoid/shim.rb +16 -3
- data/test/rails_app/app/mongoid/user.rb +5 -5
- data/test/rails_app/app/views/admins/index.html.erb +1 -0
- data/test/rails_app/app/views/admins/sessions/new.html.erb +2 -0
- data/test/rails_app/app/views/home/index.html.erb +1 -0
- data/test/rails_app/app/views/home/private.html.erb +1 -0
- data/test/rails_app/app/views/layouts/application.html.erb +24 -0
- data/test/rails_app/app/views/users/index.html.erb +1 -0
- data/test/rails_app/app/views/users/mailer/confirmation_instructions.erb +1 -0
- data/test/rails_app/app/views/users/sessions/new.html.erb +1 -0
- data/test/rails_app/config/application.rb +5 -0
- data/test/rails_app/config/boot.rb +2 -2
- data/test/rails_app/config/database.yml +18 -0
- data/test/rails_app/config/initializers/devise.rb +71 -31
- data/test/rails_app/config/routes.rb +14 -6
- data/test/rails_app/config.ru +4 -0
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +21 -17
- data/test/rails_app/db/schema.rb +17 -51
- data/test/rails_app/lib/shared_admin.rb +9 -0
- data/test/rails_app/lib/shared_user.rb +23 -0
- data/test/rails_app/public/404.html +26 -0
- data/test/rails_app/public/422.html +26 -0
- data/test/rails_app/public/500.html +26 -0
- data/test/rails_app/public/favicon.ico +0 -0
- data/test/rails_app/script/rails +10 -0
- data/test/routes_test.rb +42 -9
- data/test/schema_test.rb +33 -0
- data/test/support/integration.rb +4 -4
- data/test/support/locale/en.yml +4 -0
- data/test/support/webrat/integrations/rails.rb +11 -19
- data/test/test_helper.rb +8 -2
- data/test/test_helpers_test.rb +64 -2
- metadata +106 -30
- data/TODO +0 -3
- data/lib/devise/encryptors/bcrypt.rb +0 -19
- data/lib/generators/devise_install_generator.rb +0 -4
- data/lib/generators/devise_views_generator.rb +0 -4
- data/test/support/test_silencer.rb +0 -5
|
@@ -1,25 +1,18 @@
|
|
|
1
1
|
require 'devise/strategies/database_authenticatable'
|
|
2
|
+
require 'bcrypt'
|
|
2
3
|
|
|
3
4
|
module Devise
|
|
4
5
|
module Models
|
|
5
|
-
#
|
|
6
|
+
# Authenticatable Module, responsible for encrypting password and validating
|
|
6
7
|
# authenticity of a user while signing in.
|
|
7
8
|
#
|
|
8
|
-
#
|
|
9
|
+
# == Options
|
|
9
10
|
#
|
|
10
|
-
#
|
|
11
|
-
# using devise method or overwriting the respective instance method.
|
|
11
|
+
# DatabaseAuthenticable adds the following options to devise_for:
|
|
12
12
|
#
|
|
13
|
-
#
|
|
14
|
-
# password changes, it's gonna be encrypted again, and this key
|
|
15
|
-
# is added to the password and salt to create a secure hash.
|
|
16
|
-
# Always use `rake secret' to generate a new key.
|
|
13
|
+
# * +stretches+: the cost given to bcrypt.
|
|
17
14
|
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
# encryptor: the encryptor going to be used. By default :sha1.
|
|
21
|
-
#
|
|
22
|
-
# Examples:
|
|
15
|
+
# == Examples
|
|
23
16
|
#
|
|
24
17
|
# User.find(1).valid_password?('password123') # returns true/false
|
|
25
18
|
#
|
|
@@ -29,22 +22,20 @@ module Devise
|
|
|
29
22
|
included do
|
|
30
23
|
attr_reader :password, :current_password
|
|
31
24
|
attr_accessor :password_confirmation
|
|
25
|
+
before_save :downcase_keys
|
|
32
26
|
end
|
|
33
27
|
|
|
34
|
-
#
|
|
35
|
-
# and then trigger any "after_changed_password"-callbacks.
|
|
28
|
+
# Generates password encryption based on the given value.
|
|
36
29
|
def password=(new_password)
|
|
37
30
|
@password = new_password
|
|
38
|
-
|
|
39
|
-
if @password.present?
|
|
40
|
-
self.password_salt = self.class.password_salt
|
|
41
|
-
self.encrypted_password = password_digest(@password)
|
|
42
|
-
end
|
|
31
|
+
self.encrypted_password = password_digest(@password) if @password.present?
|
|
43
32
|
end
|
|
44
33
|
|
|
45
|
-
# Verifies whether an
|
|
46
|
-
def valid_password?(
|
|
47
|
-
|
|
34
|
+
# Verifies whether an password (ie from sign in) is the user password.
|
|
35
|
+
def valid_password?(password)
|
|
36
|
+
bcrypt = ::BCrypt::Password.new(self.encrypted_password)
|
|
37
|
+
password = ::BCrypt::Engine.hash_secret("#{password}#{self.class.pepper}", bcrypt.salt)
|
|
38
|
+
Devise.secure_compare(password, self.encrypted_password)
|
|
48
39
|
end
|
|
49
40
|
|
|
50
41
|
# Set password and password confirmation to nil
|
|
@@ -78,26 +69,25 @@ module Devise
|
|
|
78
69
|
def after_database_authentication
|
|
79
70
|
end
|
|
80
71
|
|
|
72
|
+
# A reliable way to expose the salt regardless of the implementation.
|
|
73
|
+
def authenticatable_salt
|
|
74
|
+
self.encrypted_password[0,29] if self.encrypted_password
|
|
75
|
+
end
|
|
76
|
+
|
|
81
77
|
protected
|
|
82
78
|
|
|
83
|
-
#
|
|
79
|
+
# Downcase case-insensitive keys
|
|
80
|
+
def downcase_keys
|
|
81
|
+
(self.class.case_insensitive_keys || []).each { |k| self[k].try(:downcase!) }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Digests the password using bcrypt.
|
|
84
85
|
def password_digest(password)
|
|
85
|
-
|
|
86
|
-
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
|
|
87
|
-
end
|
|
86
|
+
::BCrypt::Password.create("#{password}#{self.class.pepper}", :cost => self.class.stretches).to_s
|
|
88
87
|
end
|
|
89
88
|
|
|
90
89
|
module ClassMethods
|
|
91
|
-
Devise::Models.config(self, :pepper, :stretches
|
|
92
|
-
|
|
93
|
-
# Returns the class for the configured encryptor.
|
|
94
|
-
def encryptor_class
|
|
95
|
-
@encryptor_class ||= ::Devise::Encryptors.const_get(encryptor.to_s.classify)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def password_salt
|
|
99
|
-
self.encryptor_class.salt(self.stretches)
|
|
100
|
-
end
|
|
90
|
+
Devise::Models.config(self, :pepper, :stretches)
|
|
101
91
|
|
|
102
92
|
# We assume this method already gets the sanitized values from the
|
|
103
93
|
# DatabaseAuthenticatable strategy. If you are using this method on
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require 'devise/strategies/database_authenticatable'
|
|
2
|
+
|
|
3
|
+
module Devise
|
|
4
|
+
module Models
|
|
5
|
+
# Encryptable Module adds support to several encryptors.
|
|
6
|
+
#
|
|
7
|
+
# == Options
|
|
8
|
+
#
|
|
9
|
+
# Encryptable adds the following options to devise_for:
|
|
10
|
+
#
|
|
11
|
+
# * +pepper+: a random string used to provide a more secure hash.
|
|
12
|
+
#
|
|
13
|
+
# * +encryptor+: the encryptor going to be used. By default is nil.
|
|
14
|
+
#
|
|
15
|
+
# == Examples
|
|
16
|
+
#
|
|
17
|
+
# User.find(1).valid_password?('password123') # returns true/false
|
|
18
|
+
#
|
|
19
|
+
module Encryptable
|
|
20
|
+
extend ActiveSupport::Concern
|
|
21
|
+
|
|
22
|
+
included do
|
|
23
|
+
attr_reader :password, :current_password
|
|
24
|
+
attr_accessor :password_confirmation
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Generates password salt.
|
|
28
|
+
def password=(new_password)
|
|
29
|
+
self.password_salt = self.class.password_salt if new_password.present?
|
|
30
|
+
super
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def authenticatable_salt
|
|
34
|
+
self.password_salt
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Verifies whether an incoming_password (ie from sign in) is the user password.
|
|
38
|
+
def valid_password?(incoming_password)
|
|
39
|
+
Devise.secure_compare(password_digest(incoming_password), self.encrypted_password)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
protected
|
|
43
|
+
|
|
44
|
+
# Digests the password using the configured encryptor.
|
|
45
|
+
def password_digest(password)
|
|
46
|
+
if self.password_salt.present?
|
|
47
|
+
self.class.encryptor_class.digest(password, self.class.stretches, self.password_salt, self.class.pepper)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
module ClassMethods
|
|
52
|
+
Devise::Models.config(self, :encryptor)
|
|
53
|
+
|
|
54
|
+
# Returns the class for the configured encryptor.
|
|
55
|
+
def encryptor_class
|
|
56
|
+
@encryptor_class ||= case encryptor
|
|
57
|
+
when :bcrypt
|
|
58
|
+
raise "In order to use bcrypt as encryptor, simply remove :encryptable from your devise model"
|
|
59
|
+
when nil
|
|
60
|
+
raise "You need to give an :encryptor as option in order to use :encryptable"
|
|
61
|
+
else
|
|
62
|
+
::Devise::Encryptors.const_get(encryptor.to_s.classify)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def password_salt
|
|
67
|
+
self.encryptor_class.salt(self.stretches)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -7,20 +7,22 @@ module Devise
|
|
|
7
7
|
# will unlock the user automatically after some configured time (ie 2.hours).
|
|
8
8
|
# It's also possible to setup lockable to use both email and time strategies.
|
|
9
9
|
#
|
|
10
|
-
#
|
|
10
|
+
# == Options
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
12
|
+
# Lockable adds the following options to devise_for:
|
|
13
|
+
#
|
|
14
|
+
# * +maximum_attempts+: how many attempts should be accepted before blocking the user.
|
|
15
|
+
# * +lock_strategy+: lock the user account by :failed_attempts or :none.
|
|
16
|
+
# * +unlock_strategy+: unlock the user account by :time, :email, :both or :none.
|
|
17
|
+
# * +unlock_in+: the time you want to lock the user after to lock happens. Only available when unlock_strategy is :time or :both.
|
|
18
|
+
# * +unlock_keys+: the keys you want to use when locking and unlocking an account
|
|
17
19
|
#
|
|
18
20
|
module Lockable
|
|
19
21
|
extend ActiveSupport::Concern
|
|
20
22
|
|
|
21
23
|
delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
|
|
22
24
|
|
|
23
|
-
# Lock
|
|
25
|
+
# Lock a user setting it's locked_at to actual time.
|
|
24
26
|
def lock_access!
|
|
25
27
|
self.locked_at = Time.now
|
|
26
28
|
|
|
@@ -32,14 +34,12 @@ module Devise
|
|
|
32
34
|
save(:validate => false)
|
|
33
35
|
end
|
|
34
36
|
|
|
35
|
-
# Unlock
|
|
37
|
+
# Unlock a user by cleaning locket_at and failed_attempts.
|
|
36
38
|
def unlock_access!
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
save(:validate => false)
|
|
42
|
-
end
|
|
39
|
+
self.locked_at = nil
|
|
40
|
+
self.failed_attempts = 0 if respond_to?(:failed_attempts=)
|
|
41
|
+
self.unlock_token = nil if respond_to?(:unlock_token=)
|
|
42
|
+
save(:validate => false)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
# Verifies whether a user is locked or not.
|
|
@@ -57,9 +57,9 @@ module Devise
|
|
|
57
57
|
if_access_locked { send_unlock_instructions }
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
# Overwrites
|
|
61
|
-
# by verifying whether
|
|
62
|
-
def
|
|
60
|
+
# Overwrites active_for_authentication? from Devise::Models::Activatable for locking purposes
|
|
61
|
+
# by verifying whether a user is active to sign in or not based on locked?
|
|
62
|
+
def active_for_authentication?
|
|
63
63
|
super && !access_locked?
|
|
64
64
|
end
|
|
65
65
|
|
|
@@ -70,16 +70,21 @@ module Devise
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
# Overwrites valid_for_authentication? from Devise::Models::Authenticatable
|
|
73
|
-
# for verifying whether
|
|
73
|
+
# for verifying whether a user is allowed to sign in or not. If the user
|
|
74
74
|
# is locked, it should never be allowed.
|
|
75
75
|
def valid_for_authentication?
|
|
76
76
|
return super unless persisted? && lock_strategy_enabled?(:failed_attempts)
|
|
77
77
|
|
|
78
|
+
# Unlock the user if the lock is expired, no matter
|
|
79
|
+
# if the user can login or not (wrong password, etc)
|
|
80
|
+
unlock_access! if lock_expired?
|
|
81
|
+
|
|
78
82
|
case (result = super)
|
|
79
83
|
when Symbol
|
|
80
84
|
return result
|
|
81
85
|
when TrueClass
|
|
82
86
|
self.failed_attempts = 0
|
|
87
|
+
save(:validate => false)
|
|
83
88
|
when FalseClass
|
|
84
89
|
# PostgreSQL uses nil as the default value for integer columns set to 0
|
|
85
90
|
self.failed_attempts ||= 0
|
|
@@ -87,10 +92,11 @@ module Devise
|
|
|
87
92
|
if attempts_exceeded?
|
|
88
93
|
lock_access!
|
|
89
94
|
return :locked
|
|
95
|
+
else
|
|
96
|
+
save(:validate => false)
|
|
90
97
|
end
|
|
91
98
|
end
|
|
92
99
|
|
|
93
|
-
save(:validate => false) if changed?
|
|
94
100
|
result
|
|
95
101
|
end
|
|
96
102
|
|
|
@@ -131,7 +137,7 @@ module Devise
|
|
|
131
137
|
# with an email not found error.
|
|
132
138
|
# Options must contain the user email
|
|
133
139
|
def send_unlock_instructions(attributes={})
|
|
134
|
-
lockable =
|
|
140
|
+
lockable = find_or_initialize_with_errors(unlock_keys, attributes, :not_found)
|
|
135
141
|
lockable.resend_unlock_token if lockable.persisted?
|
|
136
142
|
lockable
|
|
137
143
|
end
|
|
@@ -160,7 +166,7 @@ module Devise
|
|
|
160
166
|
Devise.friendly_token
|
|
161
167
|
end
|
|
162
168
|
|
|
163
|
-
Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in)
|
|
169
|
+
Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in, :unlock_keys)
|
|
164
170
|
end
|
|
165
171
|
end
|
|
166
172
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'devise/omniauth'
|
|
2
|
+
|
|
3
|
+
module Devise
|
|
4
|
+
module Models
|
|
5
|
+
# Adds OmniAuth support to your model.
|
|
6
|
+
#
|
|
7
|
+
# == Options
|
|
8
|
+
#
|
|
9
|
+
# Oauthable adds the following options to devise_for:
|
|
10
|
+
#
|
|
11
|
+
# * +omniauth_providers+: Which providers are avaialble to this model. It expects an array:
|
|
12
|
+
#
|
|
13
|
+
# devise_for :database_authenticatable, :omniauthable, :omniauth_providers => [:twitter]
|
|
14
|
+
#
|
|
15
|
+
module Omniauthable
|
|
16
|
+
extend ActiveSupport::Concern
|
|
17
|
+
|
|
18
|
+
module ClassMethods
|
|
19
|
+
Devise::Models.config(self, :omniauth_providers)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
module Devise
|
|
2
2
|
module Models
|
|
3
3
|
|
|
4
|
-
# Recoverable takes care of reseting the user password and send reset instructions
|
|
5
|
-
#
|
|
4
|
+
# Recoverable takes care of reseting the user password and send reset instructions.
|
|
5
|
+
#
|
|
6
|
+
# ==Options
|
|
7
|
+
#
|
|
8
|
+
# Recoverable adds the following options to devise_for:
|
|
9
|
+
#
|
|
10
|
+
# * +reset_password_keys+: the keys you want to use when recovering the password for an account
|
|
11
|
+
#
|
|
12
|
+
# == Examples
|
|
6
13
|
#
|
|
7
14
|
# # resets the user password and save the record, true if valid passwords are given, otherwise false
|
|
8
15
|
# User.find(1).reset_password!('password123', 'password123')
|
|
@@ -13,6 +20,7 @@ module Devise
|
|
|
13
20
|
#
|
|
14
21
|
# # creates a new token and send it with instructions about how to reset the password
|
|
15
22
|
# User.find(1).send_reset_password_instructions
|
|
23
|
+
#
|
|
16
24
|
module Recoverable
|
|
17
25
|
extend ActiveSupport::Concern
|
|
18
26
|
|
|
@@ -55,7 +63,7 @@ module Devise
|
|
|
55
63
|
# with an email not found error.
|
|
56
64
|
# Attributes must contain the user email
|
|
57
65
|
def send_reset_password_instructions(attributes={})
|
|
58
|
-
recoverable =
|
|
66
|
+
recoverable = find_or_initialize_with_errors(reset_password_keys, attributes, :not_found)
|
|
59
67
|
recoverable.send_reset_password_instructions if recoverable.persisted?
|
|
60
68
|
recoverable
|
|
61
69
|
end
|
|
@@ -75,6 +83,8 @@ module Devise
|
|
|
75
83
|
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation]) if recoverable.persisted?
|
|
76
84
|
recoverable
|
|
77
85
|
end
|
|
86
|
+
|
|
87
|
+
Devise::Models.config(self, :reset_password_keys)
|
|
78
88
|
end
|
|
79
89
|
end
|
|
80
90
|
end
|
|
@@ -3,6 +3,19 @@ module Devise
|
|
|
3
3
|
# Registerable is responsible for everything related to registering a new
|
|
4
4
|
# resource (ie user sign up).
|
|
5
5
|
module Registerable
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
# A convenience method that receives both parameters and session to
|
|
10
|
+
# initialize a user. This can be used by OAuth, for example, to send
|
|
11
|
+
# in the user token and be stored on initialization.
|
|
12
|
+
#
|
|
13
|
+
# By default discards all information sent by the session by calling
|
|
14
|
+
# new with params.
|
|
15
|
+
def new_with_session(params, session)
|
|
16
|
+
new(params)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
6
19
|
end
|
|
7
20
|
end
|
|
8
21
|
end
|
|
@@ -11,24 +11,27 @@ module Devise
|
|
|
11
11
|
# You probably wouldn't use rememberable methods directly, they are used
|
|
12
12
|
# mostly internally for handling the remember token.
|
|
13
13
|
#
|
|
14
|
-
#
|
|
14
|
+
# == Options
|
|
15
15
|
#
|
|
16
|
-
#
|
|
17
|
-
# asking for credentials. After this time the user will be
|
|
18
|
-
# blocked and will have to enter his credentials again.
|
|
19
|
-
# This configuration is also used to calculate the expires
|
|
20
|
-
# time for the cookie created to remember the user.
|
|
21
|
-
# 2.weeks by default.
|
|
16
|
+
# Rememberable adds the following options in devise_for:
|
|
22
17
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
18
|
+
# * +remember_for+: the time you want the user will be remembered without
|
|
19
|
+
# asking for credentials. After this time the user will be blocked and
|
|
20
|
+
# will have to enter his credentials again. This configuration is also
|
|
21
|
+
# used to calculate the expires time for the cookie created to remember
|
|
22
|
+
# the user. By default remember_for is 2.weeks.
|
|
26
23
|
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
24
|
+
# * +remember_across_browsers+: if a valid remember token can be re-used
|
|
25
|
+
# between multiple browsers. By default remember_across_browsers is true
|
|
26
|
+
# and cannot be turned off if you are using password salt instead of remember
|
|
27
|
+
# token.
|
|
30
28
|
#
|
|
31
|
-
#
|
|
29
|
+
# * +extend_remember_period+: if true, extends the user's remember period
|
|
30
|
+
# when remembered via cookie. False by default.
|
|
31
|
+
#
|
|
32
|
+
# * +cookie_options+: configuration options passed to the created cookie.
|
|
33
|
+
#
|
|
34
|
+
# == Examples
|
|
32
35
|
#
|
|
33
36
|
# User.find(1).remember_me! # regenerating the token
|
|
34
37
|
# User.find(1).forget_me! # clearing the token
|
|
@@ -41,15 +44,12 @@ module Devise
|
|
|
41
44
|
module Rememberable
|
|
42
45
|
extend ActiveSupport::Concern
|
|
43
46
|
|
|
44
|
-
|
|
45
|
-
# Remember me option available in after_authentication hook.
|
|
46
|
-
attr_accessor :remember_me
|
|
47
|
-
end
|
|
47
|
+
attr_accessor :remember_me, :extend_remember_period
|
|
48
48
|
|
|
49
49
|
# Generate a new remember token and save the record without validations
|
|
50
50
|
# unless remember_across_browsers is true and the user already has a valid token.
|
|
51
51
|
def remember_me!(extend_period=false)
|
|
52
|
-
self.remember_token = self.class.remember_token if generate_remember_token?
|
|
52
|
+
self.remember_token = self.class.remember_token if respond_to?(:remember_token) && generate_remember_token?
|
|
53
53
|
self.remember_created_at = Time.now.utc if generate_remember_timestamp?(extend_period)
|
|
54
54
|
save(:validate => false)
|
|
55
55
|
end
|
|
@@ -57,16 +57,14 @@ module Devise
|
|
|
57
57
|
# Removes the remember token only if it exists, and save the record
|
|
58
58
|
# without validations.
|
|
59
59
|
def forget_me!
|
|
60
|
-
if remember_token
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
save(:validate => false)
|
|
64
|
-
end
|
|
60
|
+
self.remember_token = nil if respond_to?(:remember_token=)
|
|
61
|
+
self.remember_created_at = nil
|
|
62
|
+
save(:validate => false)
|
|
65
63
|
end
|
|
66
64
|
|
|
67
65
|
# Remember token should be expired if expiration time not overpass now.
|
|
68
66
|
def remember_expired?
|
|
69
|
-
remember_created_at
|
|
67
|
+
remember_created_at.nil? || (remember_expires_at <= Time.now.utc)
|
|
70
68
|
end
|
|
71
69
|
|
|
72
70
|
# Remember token expires at created time + remember_for configuration
|
|
@@ -74,12 +72,20 @@ module Devise
|
|
|
74
72
|
remember_created_at + self.class.remember_for
|
|
75
73
|
end
|
|
76
74
|
|
|
77
|
-
def
|
|
78
|
-
|
|
75
|
+
def rememberable_value
|
|
76
|
+
if respond_to?(:remember_token)
|
|
77
|
+
remember_token
|
|
78
|
+
elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt)
|
|
79
|
+
salt
|
|
80
|
+
else
|
|
81
|
+
raise "The #{self.class.name} class does not respond to remember_token and " <<
|
|
82
|
+
"authenticatable_salt returns nil. In order to use rememberable, you must " <<
|
|
83
|
+
"add a remember_token field to your model or ensure a password is always set."
|
|
84
|
+
end
|
|
79
85
|
end
|
|
80
86
|
|
|
81
|
-
def
|
|
82
|
-
self.class.
|
|
87
|
+
def cookie_options
|
|
88
|
+
self.class.cookie_options
|
|
83
89
|
end
|
|
84
90
|
|
|
85
91
|
protected
|
|
@@ -99,14 +105,13 @@ module Devise
|
|
|
99
105
|
module ClassMethods
|
|
100
106
|
# Create the cookie key using the record id and remember_token
|
|
101
107
|
def serialize_into_cookie(record)
|
|
102
|
-
[record.
|
|
108
|
+
[record.to_key, record.rememberable_value]
|
|
103
109
|
end
|
|
104
110
|
|
|
105
111
|
# Recreate the user based on the stored cookie
|
|
106
112
|
def serialize_from_cookie(id, remember_token)
|
|
107
|
-
|
|
108
|
-
record
|
|
109
|
-
record if record && !record.remember_expired?
|
|
113
|
+
record = to_adapter.get(id)
|
|
114
|
+
record if record && record.rememberable_value == remember_token && !record.remember_expired?
|
|
110
115
|
end
|
|
111
116
|
|
|
112
117
|
# Generate a token checking if one does not already exist in the database.
|
|
@@ -115,7 +120,7 @@ module Devise
|
|
|
115
120
|
end
|
|
116
121
|
|
|
117
122
|
Devise::Models.config(self, :remember_for, :remember_across_browsers,
|
|
118
|
-
:extend_remember_period, :
|
|
123
|
+
:extend_remember_period, :cookie_options)
|
|
119
124
|
end
|
|
120
125
|
end
|
|
121
126
|
end
|
|
@@ -7,17 +7,34 @@ module Devise
|
|
|
7
7
|
# will be asked for credentials again, it means, he/she will be redirected
|
|
8
8
|
# to the sign in page.
|
|
9
9
|
#
|
|
10
|
-
#
|
|
10
|
+
# == Options
|
|
11
|
+
#
|
|
12
|
+
# Timeoutable adds the following options to devise_for:
|
|
13
|
+
#
|
|
14
|
+
# * +timeout_in+: the interval to timeout the user session without activity.
|
|
15
|
+
#
|
|
16
|
+
# == Examples
|
|
17
|
+
#
|
|
18
|
+
# user.timedout?(30.minutes.ago)
|
|
11
19
|
#
|
|
12
|
-
# timeout_in: the time you want to timeout the user session without activity.
|
|
13
20
|
module Timeoutable
|
|
14
21
|
extend ActiveSupport::Concern
|
|
15
22
|
|
|
16
23
|
# Checks whether the user session has expired based on configured time.
|
|
17
24
|
def timedout?(last_access)
|
|
25
|
+
return false if remember_exists_and_not_expired?
|
|
26
|
+
|
|
18
27
|
last_access && last_access <= self.class.timeout_in.ago
|
|
19
28
|
end
|
|
20
|
-
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def remember_exists_and_not_expired?
|
|
33
|
+
return false unless respond_to?(:remember_expired?)
|
|
34
|
+
|
|
35
|
+
remember_created_at && !remember_expired?
|
|
36
|
+
end
|
|
37
|
+
|
|
21
38
|
module ClassMethods
|
|
22
39
|
Devise::Models.config(self, :timeout_in)
|
|
23
40
|
end
|
|
@@ -5,15 +5,27 @@ module Devise
|
|
|
5
5
|
# The TokenAuthenticatable module is responsible for generating an authentication token and
|
|
6
6
|
# validating the authenticity of the same while signing in.
|
|
7
7
|
#
|
|
8
|
-
# This module only provides a few helpers to help you manage the token
|
|
9
|
-
#
|
|
8
|
+
# This module only provides a few helpers to help you manage the token, but it is up to you
|
|
9
|
+
# to choose how to use it. For example, if you want to have a new token every time the user
|
|
10
|
+
# saves his account, you can do the following:
|
|
10
11
|
#
|
|
11
|
-
#
|
|
12
|
+
# before_save :reset_authentication_token
|
|
12
13
|
#
|
|
13
|
-
#
|
|
14
|
-
# using devise method, or overwriting the respective instance method.
|
|
14
|
+
# On the other hand, if you want to generate token unless one exists, you should use instead:
|
|
15
15
|
#
|
|
16
|
-
#
|
|
16
|
+
# before_save :ensure_authentication_token
|
|
17
|
+
#
|
|
18
|
+
# If you want to delete the token after it is used, you can do so in the
|
|
19
|
+
# after_token_authentication callback.
|
|
20
|
+
#
|
|
21
|
+
# == Options
|
|
22
|
+
#
|
|
23
|
+
# TokenAuthenticatable adds the following options to devise_for:
|
|
24
|
+
#
|
|
25
|
+
# * +token_authentication_key+: Defines name of the authentication token params key. E.g. /users/sign_in?some_key=...
|
|
26
|
+
#
|
|
27
|
+
# * +stateless_token+: By default, when you sign up with a token, Devise will store the user in session
|
|
28
|
+
# as any other authentication strategy. You can set stateless_token to true to avoid this.
|
|
17
29
|
#
|
|
18
30
|
module TokenAuthenticatable
|
|
19
31
|
extend ActiveSupport::Concern
|
|
@@ -26,17 +38,17 @@ module Devise
|
|
|
26
38
|
# Generate new authentication token and save the record.
|
|
27
39
|
def reset_authentication_token!
|
|
28
40
|
reset_authentication_token
|
|
29
|
-
|
|
41
|
+
save(:validate => false)
|
|
30
42
|
end
|
|
31
43
|
|
|
32
44
|
# Generate authentication token unless already exists.
|
|
33
45
|
def ensure_authentication_token
|
|
34
|
-
|
|
46
|
+
reset_authentication_token if authentication_token.blank?
|
|
35
47
|
end
|
|
36
48
|
|
|
37
49
|
# Generate authentication token unless already exists and save the record.
|
|
38
50
|
def ensure_authentication_token!
|
|
39
|
-
|
|
51
|
+
reset_authentication_token! if authentication_token.blank?
|
|
40
52
|
end
|
|
41
53
|
|
|
42
54
|
# Hook called after token authentication.
|
|
@@ -53,7 +65,7 @@ module Devise
|
|
|
53
65
|
generate_token(:authentication_token)
|
|
54
66
|
end
|
|
55
67
|
|
|
56
|
-
::Devise::Models.config(self, :token_authentication_key)
|
|
68
|
+
::Devise::Models.config(self, :token_authentication_key, :stateless_token)
|
|
57
69
|
end
|
|
58
70
|
end
|
|
59
71
|
end
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
module Devise
|
|
2
2
|
module Models
|
|
3
|
-
|
|
4
3
|
# Validatable creates all needed validations for a user email and password.
|
|
5
4
|
# It's optional, given you may want to create the validations by yourself.
|
|
6
5
|
# Automatically validate if the email is present, unique and it's format is
|
|
7
|
-
# valid. Also tests presence of password, confirmation and length
|
|
6
|
+
# valid. Also tests presence of password, confirmation and length.
|
|
7
|
+
#
|
|
8
|
+
# == Options
|
|
9
|
+
#
|
|
10
|
+
# Validatable adds the following options to devise_for:
|
|
11
|
+
#
|
|
12
|
+
# * +email_regexp+: the regular expression used to validate e-mails;
|
|
13
|
+
# * +password_length+: a range expressing password length. Defaults to 6..20.
|
|
14
|
+
#
|
|
8
15
|
module Validatable
|
|
9
16
|
# All validations used by this module.
|
|
10
17
|
VALIDATIONS = [ :validates_presence_of, :validates_uniqueness_of, :validates_format_of,
|
|
@@ -15,8 +22,9 @@ module Devise
|
|
|
15
22
|
assert_validations_api!(base)
|
|
16
23
|
|
|
17
24
|
base.class_eval do
|
|
18
|
-
validates_presence_of :email
|
|
19
|
-
validates_uniqueness_of :email, :scope => authentication_keys[1..-1],
|
|
25
|
+
validates_presence_of :email, :if => :email_required?
|
|
26
|
+
validates_uniqueness_of :email, :scope => authentication_keys[1..-1],
|
|
27
|
+
:case_sensitive => (case_insensitive_keys != false), :allow_blank => true
|
|
20
28
|
validates_format_of :email, :with => email_regexp, :allow_blank => true
|
|
21
29
|
|
|
22
30
|
with_options :if => :password_required? do |v|
|
|
@@ -45,6 +53,10 @@ module Devise
|
|
|
45
53
|
!persisted? || !password.nil? || !password_confirmation.nil?
|
|
46
54
|
end
|
|
47
55
|
|
|
56
|
+
def email_required?
|
|
57
|
+
true
|
|
58
|
+
end
|
|
59
|
+
|
|
48
60
|
module ClassMethods
|
|
49
61
|
Devise::Models.config(self, :email_regexp, :password_length)
|
|
50
62
|
end
|