sorcery 0.7.4 → 0.8.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/.travis.yml +3 -0
- data/Gemfile +9 -4
- data/Gemfile.lock +103 -62
- data/README.rdoc +33 -8
- data/Rakefile +6 -7
- data/VERSION +1 -1
- data/lib/generators/sorcery/install_generator.rb +15 -10
- data/lib/generators/sorcery/templates/initializer.rb +343 -125
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +2 -0
- data/lib/generators/sorcery/templates/migration/reset_password.rb +1 -1
- data/lib/sorcery/controller/submodules/activity_logging.rb +3 -3
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +1 -2
- data/lib/sorcery/controller/submodules/external/protocols/oauth2.rb +19 -19
- data/lib/sorcery/controller/submodules/external/providers/facebook.rb +20 -5
- data/lib/sorcery/controller/submodules/external/providers/github.rb +15 -4
- data/lib/sorcery/controller/submodules/external/providers/google.rb +90 -0
- data/lib/sorcery/controller/submodules/external/providers/linkedin.rb +101 -0
- data/lib/sorcery/controller/submodules/external/providers/liveid.rb +91 -0
- data/lib/sorcery/controller/submodules/external/providers/twitter.rb +2 -1
- data/lib/sorcery/controller/submodules/external/providers/vkontakte.rb +94 -0
- data/lib/sorcery/controller/submodules/external.rb +89 -15
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +1 -1
- data/lib/sorcery/controller/submodules/remember_me.rb +11 -2
- data/lib/sorcery/controller.rb +14 -6
- data/lib/sorcery/crypto_providers/bcrypt.rb +1 -0
- data/lib/sorcery/model/adapters/active_record.rb +21 -1
- data/lib/sorcery/model/adapters/mongo_mapper.rb +22 -15
- data/lib/sorcery/model/adapters/mongoid.rb +20 -3
- data/lib/sorcery/model/submodules/activity_logging.rb +4 -4
- data/lib/sorcery/model/submodules/brute_force_protection.rb +46 -15
- data/lib/sorcery/model/submodules/remember_me.rb +4 -6
- data/lib/sorcery/model/submodules/reset_password.rb +18 -12
- data/lib/sorcery/model/submodules/user_activation.rb +15 -8
- data/lib/sorcery/model.rb +57 -43
- data/lib/sorcery/railties/tasks.rake +2 -0
- data/lib/sorcery.rb +5 -1
- data/sorcery.gemspec +33 -21
- data/spec/Gemfile +1 -1
- data/spec/Gemfile.lock +22 -21
- data/spec/README.md +8 -8
- data/spec/rails3/Gemfile +3 -3
- data/spec/rails3/Gemfile.lock +55 -33
- data/spec/rails3/app/controllers/application_controller.rb +85 -2
- data/spec/rails3/app/mailers/sorcery_mailer.rb +7 -0
- data/spec/rails3/app/views/sorcery_mailer/send_unlock_token_email.text.erb +1 -0
- data/spec/rails3/config/environments/in_memory.rb +35 -0
- data/spec/rails3/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +2 -0
- data/spec/rails3/spec/controller_activity_logging_spec.rb +10 -0
- data/spec/rails3/spec/controller_brute_force_protection_spec.rb +23 -1
- data/spec/rails3/spec/controller_oauth2_spec.rb +260 -22
- data/spec/rails3/spec/controller_oauth_spec.rb +111 -6
- data/spec/rails3/spec/controller_spec.rb +37 -2
- data/spec/rails3/spec/integration_spec.rb +15 -15
- data/spec/rails3/spec/spec_helper.rb +1 -1
- data/spec/rails3_mongo_mapper/Gemfile +2 -1
- data/spec/rails3_mongo_mapper/Gemfile.lock +40 -42
- data/spec/rails3_mongo_mapper/app/controllers/application_controller.rb +14 -0
- data/spec/rails3_mongo_mapper/spec/controller_spec.rb +41 -1
- data/spec/rails3_mongoid/Gemfile +1 -0
- data/spec/rails3_mongoid/Gemfile.lock +30 -27
- data/spec/rails3_mongoid/app/controllers/application_controller.rb +19 -0
- data/spec/rails3_mongoid/config/mongoid.yml +1 -1
- data/spec/rails3_mongoid/spec/controller_activity_logging_spec.rb +18 -11
- data/spec/rails3_mongoid/spec/controller_spec.rb +41 -1
- data/spec/shared_examples/controller_oauth2_shared_examples.rb +20 -1
- data/spec/shared_examples/controller_oauth_shared_examples.rb +18 -0
- data/spec/shared_examples/user_activation_shared_examples.rb +71 -41
- data/spec/shared_examples/user_reset_password_shared_examples.rb +80 -27
- data/spec/sorcery_crypto_providers_spec.rb +14 -1
- metadata +74 -46
|
@@ -8,6 +8,15 @@ module Sorcery
|
|
|
8
8
|
module RememberMe
|
|
9
9
|
def self.included(base)
|
|
10
10
|
base.send(:include, InstanceMethods)
|
|
11
|
+
Config.module_eval do
|
|
12
|
+
class << self
|
|
13
|
+
attr_accessor :remember_me_httponly
|
|
14
|
+
def merge_remember_me_defaults!
|
|
15
|
+
@defaults.merge!(:@remember_me_httponly => true)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
merge_remember_me_defaults!
|
|
19
|
+
end
|
|
11
20
|
Config.login_sources << :login_from_cookie
|
|
12
21
|
Config.after_login << :remember_me_if_asked_to
|
|
13
22
|
Config.after_logout << :forget_me!
|
|
@@ -60,7 +69,7 @@ module Sorcery
|
|
|
60
69
|
cookies.signed[:remember_me_token] = {
|
|
61
70
|
:value => user.send(user.sorcery_config.remember_me_token_attribute_name),
|
|
62
71
|
:expires => user.send(user.sorcery_config.remember_me_token_expires_at_attribute_name),
|
|
63
|
-
:httponly =>
|
|
72
|
+
:httponly => Config.remember_me_httponly,
|
|
64
73
|
:domain => Config.cookie_domain
|
|
65
74
|
}
|
|
66
75
|
end
|
|
@@ -69,4 +78,4 @@ module Sorcery
|
|
|
69
78
|
end
|
|
70
79
|
end
|
|
71
80
|
end
|
|
72
|
-
end
|
|
81
|
+
end
|
data/lib/sorcery/controller.rb
CHANGED
|
@@ -21,19 +21,22 @@ module Sorcery
|
|
|
21
21
|
# If all attempts to auto-login fail, the failure callback will be called.
|
|
22
22
|
def require_login
|
|
23
23
|
if !logged_in?
|
|
24
|
-
session[:return_to_url] = request.url if Config.save_return_to_url
|
|
24
|
+
session[:return_to_url] = request.url if Config.save_return_to_url && request.get?
|
|
25
25
|
self.send(Config.not_authenticated_action)
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
# Takes credentials and returns a user on successful authentication.
|
|
30
30
|
# Runs hooks after login or failed login.
|
|
31
|
-
|
|
31
|
+
def login(*credentials)
|
|
32
|
+
@current_user = nil
|
|
32
33
|
user = user_class.authenticate(*credentials)
|
|
33
34
|
if user
|
|
34
|
-
|
|
35
|
+
old_session = session.dup
|
|
35
36
|
reset_session # protect from session fixation attacks
|
|
36
|
-
|
|
37
|
+
old_session.to_hash.each_pair do |k,v|
|
|
38
|
+
session[k.to_sym] = v
|
|
39
|
+
end
|
|
37
40
|
auto_login(user)
|
|
38
41
|
after_login!(user, credentials)
|
|
39
42
|
current_user
|
|
@@ -71,6 +74,7 @@ module Sorcery
|
|
|
71
74
|
# and we want to return him back to the page he originally wanted.
|
|
72
75
|
def redirect_back_or_to(url, flash_hash = {})
|
|
73
76
|
redirect_to(session[:return_to_url] || url, :flash => flash_hash)
|
|
77
|
+
session[:return_to_url] = nil
|
|
74
78
|
end
|
|
75
79
|
|
|
76
80
|
# The default action for denying non-authenticated users.
|
|
@@ -108,10 +112,14 @@ module Sorcery
|
|
|
108
112
|
end
|
|
109
113
|
|
|
110
114
|
def login_from_session
|
|
111
|
-
@current_user = (user_class.
|
|
115
|
+
@current_user = (user_class.find(session[:user_id]) if session[:user_id]) || false
|
|
116
|
+
rescue => exception
|
|
117
|
+
return false if defined?(Mongoid) and exception.is_a?(Mongoid::Errors::DocumentNotFound)
|
|
118
|
+
return false if defined?(ActiveRecord) and exception.is_a?(ActiveRecord::RecordNotFound)
|
|
119
|
+
raise exception
|
|
112
120
|
end
|
|
113
121
|
|
|
114
|
-
def after_login!(user, credentials)
|
|
122
|
+
def after_login!(user, credentials = [])
|
|
115
123
|
Config.after_login.each {|c| self.send(c, user, credentials)}
|
|
116
124
|
end
|
|
117
125
|
|
|
@@ -4,11 +4,31 @@ module Sorcery
|
|
|
4
4
|
module ActiveRecord
|
|
5
5
|
def self.included(klass)
|
|
6
6
|
klass.extend ClassMethods
|
|
7
|
+
klass.send(:include, InstanceMethods)
|
|
7
8
|
end
|
|
8
9
|
|
|
10
|
+
module InstanceMethods
|
|
11
|
+
def update_many_attributes(attrs)
|
|
12
|
+
attrs.each do |name, value|
|
|
13
|
+
self.send(:"#{name}=", value)
|
|
14
|
+
end
|
|
15
|
+
primary_key = self.class.primary_key
|
|
16
|
+
self.class.where(:"#{primary_key}" => self.send(:"#{primary_key}")).update_all(attrs)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update_single_attribute(name, value)
|
|
20
|
+
update_many_attributes(name => value)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
9
24
|
module ClassMethods
|
|
25
|
+
def column_name(attribute)
|
|
26
|
+
return "LOWER(#{attribute})" if (@sorcery_config.downcase_username_before_authenticating)
|
|
27
|
+
return "#{attribute}"
|
|
28
|
+
end
|
|
29
|
+
|
|
10
30
|
def find_by_credentials(credentials)
|
|
11
|
-
sql = @sorcery_config.username_attribute_names.map{|attribute|
|
|
31
|
+
sql = @sorcery_config.username_attribute_names.map{|attribute| column_name(attribute) + " = :login"}
|
|
12
32
|
where(sql.join(' OR '), :login => credentials[0]).first
|
|
13
33
|
end
|
|
14
34
|
|
|
@@ -3,42 +3,49 @@ module Sorcery
|
|
|
3
3
|
module Adapters
|
|
4
4
|
module MongoMapper
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
included do
|
|
8
8
|
include Sorcery::Model
|
|
9
9
|
end
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
|
|
11
|
+
def increment(attr)
|
|
12
|
+
self.class.increment(id, attr => 1)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def save!(options = {})
|
|
16
|
+
save(options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update_many_attributes(attrs)
|
|
20
|
+
update_attributes(attrs)
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
module ClassMethods
|
|
24
|
+
def credential_regex(credential)
|
|
25
|
+
return { :$regex => /^#{credential}$/i } if (@sorcery_config.downcase_username_before_authenticating)
|
|
26
|
+
return credential
|
|
27
|
+
end
|
|
28
|
+
|
|
22
29
|
def find_by_credentials(credentials)
|
|
23
30
|
@sorcery_config.username_attribute_names.each do |attribute|
|
|
24
|
-
@user = where(attribute => credentials[0]).first
|
|
31
|
+
@user = where(attribute => credential_regex(credentials[0])).first
|
|
25
32
|
break if @user
|
|
26
33
|
end
|
|
27
34
|
@user
|
|
28
35
|
end
|
|
29
|
-
|
|
36
|
+
|
|
30
37
|
def find_by_id(id)
|
|
31
38
|
find(id)
|
|
32
39
|
end
|
|
33
|
-
|
|
40
|
+
|
|
34
41
|
def find_by_activation_token(token)
|
|
35
42
|
where(sorcery_config.activation_token_attribute_name => token).first
|
|
36
43
|
end
|
|
37
|
-
|
|
44
|
+
|
|
38
45
|
def transaction(&blk)
|
|
39
46
|
tap(&blk)
|
|
40
47
|
end
|
|
41
|
-
|
|
48
|
+
|
|
42
49
|
def find_by_sorcery_token(token_attr_name, token)
|
|
43
50
|
where(token_attr_name => token).first
|
|
44
51
|
end
|
|
@@ -11,12 +11,29 @@ module Sorcery
|
|
|
11
11
|
def increment(attr)
|
|
12
12
|
self.inc(attr,1)
|
|
13
13
|
end
|
|
14
|
+
|
|
15
|
+
def update_many_attributes(attrs)
|
|
16
|
+
attrs.each do |name, value|
|
|
17
|
+
attrs[name] = value.utc if value.is_a?(ActiveSupport::TimeWithZone)
|
|
18
|
+
self.send(:"#{name}=", value)
|
|
19
|
+
end
|
|
20
|
+
self.class.where(:_id => self.id).update_all(attrs)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def update_single_attribute(name, value)
|
|
24
|
+
update_many_attributes(name => value)
|
|
25
|
+
end
|
|
14
26
|
end
|
|
15
27
|
|
|
16
28
|
module ClassMethods
|
|
29
|
+
def credential_regex(credential)
|
|
30
|
+
return { :$regex => /^#{credential}$/i } if (@sorcery_config.downcase_username_before_authenticating)
|
|
31
|
+
return credential
|
|
32
|
+
end
|
|
33
|
+
|
|
17
34
|
def find_by_credentials(credentials)
|
|
18
35
|
@sorcery_config.username_attribute_names.each do |attribute|
|
|
19
|
-
@user = where(attribute => credentials[0]).first
|
|
36
|
+
@user = where(attribute => credential_regex(credentials[0])).first
|
|
20
37
|
break if @user
|
|
21
38
|
end
|
|
22
39
|
@user
|
|
@@ -61,8 +78,8 @@ module Sorcery
|
|
|
61
78
|
def get_current_users
|
|
62
79
|
config = sorcery_config
|
|
63
80
|
where(config.last_activity_at_attribute_name.ne => nil) \
|
|
64
|
-
.
|
|
65
|
-
.
|
|
81
|
+
.where("this.#{config.last_logout_at_attribute_name} == null || this.#{config.last_activity_at_attribute_name} > this.#{config.last_logout_at_attribute_name}") \
|
|
82
|
+
.where(config.last_activity_at_attribute_name.gt => config.activity_timeout.seconds.ago.utc).order_by([:_id,:asc])
|
|
66
83
|
end
|
|
67
84
|
end
|
|
68
85
|
end
|
|
@@ -39,12 +39,12 @@ module Sorcery
|
|
|
39
39
|
protected
|
|
40
40
|
|
|
41
41
|
def define_activity_logging_mongoid_fields
|
|
42
|
-
field sorcery_config.last_login_at_attribute_name, :type =>
|
|
43
|
-
field sorcery_config.last_logout_at_attribute_name, :type =>
|
|
44
|
-
field sorcery_config.last_activity_at_attribute_name, :type =>
|
|
42
|
+
field sorcery_config.last_login_at_attribute_name, :type => Time
|
|
43
|
+
field sorcery_config.last_logout_at_attribute_name, :type => Time
|
|
44
|
+
field sorcery_config.last_activity_at_attribute_name, :type => Time
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
|
-
end
|
|
50
|
+
end
|
|
@@ -12,15 +12,25 @@ module Sorcery
|
|
|
12
12
|
:lock_expires_at_attribute_name, # this field indicates whether user
|
|
13
13
|
# is banned and when it will be active again.
|
|
14
14
|
:consecutive_login_retries_amount_limit, # how many failed logins allowed.
|
|
15
|
-
:login_lock_time_period
|
|
15
|
+
:login_lock_time_period, # how long the user should be banned.
|
|
16
16
|
# in seconds. 0 for permanent.
|
|
17
|
+
|
|
18
|
+
:unlock_token_attribute_name, # Unlock token attribute name
|
|
19
|
+
:unlock_token_email_method_name, # Mailer method name
|
|
20
|
+
:unlock_token_mailer_disabled, # When true, dont send unlock token via email
|
|
21
|
+
:unlock_token_mailer # Mailer class
|
|
17
22
|
end
|
|
18
23
|
|
|
19
24
|
base.sorcery_config.instance_eval do
|
|
20
25
|
@defaults.merge!(:@failed_logins_count_attribute_name => :failed_logins_count,
|
|
21
26
|
:@lock_expires_at_attribute_name => :lock_expires_at,
|
|
22
27
|
:@consecutive_login_retries_amount_limit => 50,
|
|
23
|
-
:@login_lock_time_period => 60 * 60
|
|
28
|
+
:@login_lock_time_period => 60 * 60,
|
|
29
|
+
|
|
30
|
+
:@unlock_token_attribute_name => :unlock_token,
|
|
31
|
+
:@unlock_token_email_method_name => :send_unlock_token_email,
|
|
32
|
+
:@unlock_token_mailer_disabled => false,
|
|
33
|
+
:@unlock_token_mailer => nil)
|
|
24
34
|
reset!
|
|
25
35
|
end
|
|
26
36
|
|
|
@@ -34,16 +44,24 @@ module Sorcery
|
|
|
34
44
|
end
|
|
35
45
|
|
|
36
46
|
module ClassMethods
|
|
47
|
+
def load_from_unlock_token(token)
|
|
48
|
+
return nil if token.blank?
|
|
49
|
+
user = find_by_sorcery_token(sorcery_config.unlock_token_attribute_name,token)
|
|
50
|
+
user
|
|
51
|
+
end
|
|
52
|
+
|
|
37
53
|
protected
|
|
38
54
|
|
|
39
55
|
def define_brute_force_protection_mongoid_fields
|
|
40
|
-
field sorcery_config.failed_logins_count_attribute_name, :type => Integer
|
|
41
|
-
field sorcery_config.lock_expires_at_attribute_name, :type =>
|
|
56
|
+
field sorcery_config.failed_logins_count_attribute_name, :type => Integer, :default => 0
|
|
57
|
+
field sorcery_config.lock_expires_at_attribute_name, :type => Time
|
|
58
|
+
field sorcery_config.unlock_token_attribute_name, :type => String
|
|
42
59
|
end
|
|
43
60
|
|
|
44
61
|
def define_brute_force_protection_mongo_mapper_fields
|
|
45
|
-
key sorcery_config.failed_logins_count_attribute_name, Integer
|
|
46
|
-
key sorcery_config.lock_expires_at_attribute_name,
|
|
62
|
+
key sorcery_config.failed_logins_count_attribute_name, Integer, :default => 0
|
|
63
|
+
key sorcery_config.lock_expires_at_attribute_name, Time
|
|
64
|
+
key sorcery_config.unlock_token_attribute_name, String
|
|
47
65
|
end
|
|
48
66
|
end
|
|
49
67
|
|
|
@@ -54,29 +72,42 @@ module Sorcery
|
|
|
54
72
|
config = sorcery_config
|
|
55
73
|
return if !unlocked?
|
|
56
74
|
self.increment(config.failed_logins_count_attribute_name)
|
|
57
|
-
|
|
75
|
+
self.update_many_attributes(config.failed_logins_count_attribute_name => self.send(config.failed_logins_count_attribute_name))
|
|
58
76
|
self.lock! if self.send(config.failed_logins_count_attribute_name) >= config.consecutive_login_retries_amount_limit
|
|
59
77
|
end
|
|
60
78
|
|
|
79
|
+
# /!\
|
|
80
|
+
# Moved out of protected for use like activate! in controller
|
|
81
|
+
# /!\
|
|
82
|
+
def unlock!
|
|
83
|
+
config = sorcery_config
|
|
84
|
+
attributes = {config.lock_expires_at_attribute_name => nil,
|
|
85
|
+
config.failed_logins_count_attribute_name => 0}
|
|
86
|
+
attributes[config.unlock_token_attribute_name] = nil unless config.unlock_token_mailer_disabled or config.unlock_token_mailer.nil?
|
|
87
|
+
self.update_many_attributes(attributes)
|
|
88
|
+
end
|
|
89
|
+
|
|
61
90
|
protected
|
|
62
91
|
|
|
63
92
|
def lock!
|
|
64
93
|
config = sorcery_config
|
|
65
|
-
|
|
66
|
-
self.save!(validate: false)
|
|
67
|
-
end
|
|
94
|
+
attributes = {config.lock_expires_at_attribute_name => Time.now.in_time_zone + config.login_lock_time_period}
|
|
68
95
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
self.
|
|
96
|
+
unless config.unlock_token_mailer_disabled || config.unlock_token_mailer.nil?
|
|
97
|
+
attributes[config.unlock_token_attribute_name] = TemporaryToken.generate_random_token
|
|
98
|
+
send_unlock_token_email!
|
|
99
|
+
end
|
|
100
|
+
self.update_many_attributes(attributes)
|
|
74
101
|
end
|
|
75
102
|
|
|
76
103
|
def unlocked?
|
|
77
104
|
config = sorcery_config
|
|
78
105
|
self.send(config.lock_expires_at_attribute_name).nil?
|
|
79
106
|
end
|
|
107
|
+
|
|
108
|
+
def send_unlock_token_email!
|
|
109
|
+
generic_send_email(:unlock_token_email_method_name, :unlock_token_mailer) unless sorcery_config.unlock_token_email_method_name.nil? or sorcery_config.unlock_token_mailer_disabled == true
|
|
110
|
+
end
|
|
80
111
|
|
|
81
112
|
# Prevents a locked user from logging in, and unlocks users that expired their lock time.
|
|
82
113
|
# Runs as a hook before authenticate.
|
|
@@ -49,17 +49,15 @@ module Sorcery
|
|
|
49
49
|
# You shouldn't really use this one yourself - it's called by the controller's 'remember_me!' method.
|
|
50
50
|
def remember_me!
|
|
51
51
|
config = sorcery_config
|
|
52
|
-
self.
|
|
53
|
-
|
|
54
|
-
self.save!(:validate => false)
|
|
52
|
+
self.update_many_attributes(config.remember_me_token_attribute_name => TemporaryToken.generate_random_token,
|
|
53
|
+
config.remember_me_token_expires_at_attribute_name => Time.now.in_time_zone + config.remember_me_for)
|
|
55
54
|
end
|
|
56
55
|
|
|
57
56
|
# You shouldn't really use this one yourself - it's called by the controller's 'forget_me!' method.
|
|
58
57
|
def forget_me!
|
|
59
58
|
config = sorcery_config
|
|
60
|
-
self.
|
|
61
|
-
|
|
62
|
-
self.save!(:validate => false)
|
|
59
|
+
self.update_many_attributes(config.remember_me_token_attribute_name => nil,
|
|
60
|
+
config.remember_me_token_expires_at_attribute_name => nil)
|
|
63
61
|
end
|
|
64
62
|
end
|
|
65
63
|
end
|
|
@@ -18,6 +18,11 @@ module Sorcery
|
|
|
18
18
|
# protection.
|
|
19
19
|
|
|
20
20
|
:reset_password_mailer, # mailer class. Needed.
|
|
21
|
+
|
|
22
|
+
:reset_password_mailer_disabled, # when true sorcery will not automatically
|
|
23
|
+
# email password reset details and allow you to
|
|
24
|
+
# manually handle how and when email is sent
|
|
25
|
+
|
|
21
26
|
:reset_password_email_method_name, # reset password email method on your
|
|
22
27
|
# mailer class.
|
|
23
28
|
|
|
@@ -34,6 +39,7 @@ module Sorcery
|
|
|
34
39
|
:@reset_password_token_expires_at_attribute_name => :reset_password_token_expires_at,
|
|
35
40
|
:@reset_password_email_sent_at_attribute_name => :reset_password_email_sent_at,
|
|
36
41
|
:@reset_password_mailer => nil,
|
|
42
|
+
:@reset_password_mailer_disabled => false,
|
|
37
43
|
:@reset_password_email_method_name => :reset_password_email,
|
|
38
44
|
:@reset_password_expiration_period => nil,
|
|
39
45
|
:@reset_password_time_between_emails => 5 * 60 )
|
|
@@ -64,21 +70,21 @@ module Sorcery
|
|
|
64
70
|
|
|
65
71
|
protected
|
|
66
72
|
|
|
67
|
-
# This submodule requires the developer to define his own mailer class to be used by it
|
|
73
|
+
# This submodule requires the developer to define his own mailer class to be used by it
|
|
74
|
+
# when reset_password_mailer_disabled is false
|
|
68
75
|
def validate_mailer_defined
|
|
69
76
|
msg = "To use reset_password submodule, you must define a mailer (config.reset_password_mailer = YourMailerClass)."
|
|
70
|
-
raise ArgumentError, msg if @sorcery_config.reset_password_mailer == nil
|
|
77
|
+
raise ArgumentError, msg if @sorcery_config.reset_password_mailer == nil and @sorcery_config.reset_password_mailer_disabled == false
|
|
71
78
|
end
|
|
72
79
|
|
|
73
80
|
def define_reset_password_mongoid_fields
|
|
74
81
|
field sorcery_config.reset_password_token_attribute_name, :type => String
|
|
75
|
-
field sorcery_config.reset_password_token_expires_at_attribute_name, :type =>
|
|
76
|
-
field sorcery_config.reset_password_email_sent_at_attribute_name, :type =>
|
|
82
|
+
field sorcery_config.reset_password_token_expires_at_attribute_name, :type => Time
|
|
83
|
+
field sorcery_config.reset_password_email_sent_at_attribute_name, :type => Time
|
|
77
84
|
end
|
|
78
85
|
|
|
79
86
|
def define_reset_password_mongo_mapper_fields
|
|
80
87
|
key sorcery_config.reset_password_token_attribute_name, String
|
|
81
|
-
# no DateTime in MM
|
|
82
88
|
key sorcery_config.reset_password_token_expires_at_attribute_name, Time
|
|
83
89
|
key sorcery_config.reset_password_email_sent_at_attribute_name, Time
|
|
84
90
|
end
|
|
@@ -89,13 +95,13 @@ module Sorcery
|
|
|
89
95
|
def deliver_reset_password_instructions!
|
|
90
96
|
config = sorcery_config
|
|
91
97
|
# hammering protection
|
|
92
|
-
return if config.reset_password_time_between_emails && self.send(config.reset_password_email_sent_at_attribute_name) && self.send(config.reset_password_email_sent_at_attribute_name) > config.reset_password_time_between_emails.ago.utc
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
98
|
+
return false if config.reset_password_time_between_emails && self.send(config.reset_password_email_sent_at_attribute_name) && self.send(config.reset_password_email_sent_at_attribute_name) > config.reset_password_time_between_emails.ago.utc
|
|
99
|
+
attributes = {config.reset_password_token_attribute_name => TemporaryToken.generate_random_token,
|
|
100
|
+
config.reset_password_email_sent_at_attribute_name => Time.now.in_time_zone}
|
|
101
|
+
attributes[config.reset_password_token_expires_at_attribute_name] = Time.now.in_time_zone + config.reset_password_expiration_period if config.reset_password_expiration_period
|
|
96
102
|
self.class.transaction do
|
|
97
|
-
self.
|
|
98
|
-
generic_send_email(:reset_password_email_method_name, :reset_password_mailer)
|
|
103
|
+
self.update_many_attributes(attributes)
|
|
104
|
+
generic_send_email(:reset_password_email_method_name, :reset_password_mailer) unless config.reset_password_mailer_disabled
|
|
99
105
|
end
|
|
100
106
|
end
|
|
101
107
|
|
|
@@ -119,4 +125,4 @@ module Sorcery
|
|
|
119
125
|
end
|
|
120
126
|
end
|
|
121
127
|
end
|
|
122
|
-
end
|
|
128
|
+
end
|
|
@@ -20,7 +20,13 @@ module Sorcery
|
|
|
20
20
|
:activation_token_expiration_period, # how many seconds before the activation code
|
|
21
21
|
# expires. nil for never expires.
|
|
22
22
|
|
|
23
|
-
:user_activation_mailer, # your mailer class. Required
|
|
23
|
+
:user_activation_mailer, # your mailer class. Required when
|
|
24
|
+
# activation_mailer_disabled == false.
|
|
25
|
+
|
|
26
|
+
:activation_mailer_disabled, # when true sorcery will not automatically
|
|
27
|
+
# email activation details and allow you to
|
|
28
|
+
# manually handle how and when email is sent
|
|
29
|
+
|
|
24
30
|
:activation_needed_email_method_name, # activation needed email method on your
|
|
25
31
|
# mailer class.
|
|
26
32
|
|
|
@@ -37,6 +43,7 @@ module Sorcery
|
|
|
37
43
|
:@activation_token_expires_at_attribute_name => :activation_token_expires_at,
|
|
38
44
|
:@activation_token_expiration_period => nil,
|
|
39
45
|
:@user_activation_mailer => nil,
|
|
46
|
+
:@activation_mailer_disabled => false,
|
|
40
47
|
:@activation_needed_email_method_name => :activation_needed_email,
|
|
41
48
|
:@activation_success_email_method_name => :activation_success_email,
|
|
42
49
|
:@prevent_non_active_users_to_login => true)
|
|
@@ -47,7 +54,7 @@ module Sorcery
|
|
|
47
54
|
# don't setup activation if no password supplied - this user is created automatically
|
|
48
55
|
before_create :setup_activation, :if => Proc.new { |user| user.send(sorcery_config.password_attribute_name).present? }
|
|
49
56
|
# don't send activation needed email if no crypted password created - this user is external (OAuth etc.)
|
|
50
|
-
after_create :send_activation_needed_email!, :if => Proc.new { |user| !user.external?}
|
|
57
|
+
after_create :send_activation_needed_email!, :if => Proc.new { |user| !user.external? }
|
|
51
58
|
end
|
|
52
59
|
|
|
53
60
|
base.sorcery_config.after_config << :validate_mailer_defined
|
|
@@ -74,17 +81,18 @@ module Sorcery
|
|
|
74
81
|
|
|
75
82
|
protected
|
|
76
83
|
|
|
77
|
-
# This submodule requires the developer to define his own mailer class to be used by it
|
|
84
|
+
# This submodule requires the developer to define his own mailer class to be used by it
|
|
85
|
+
# when activation_mailer_disabled is false
|
|
78
86
|
def validate_mailer_defined
|
|
79
87
|
msg = "To use user_activation submodule, you must define a mailer (config.user_activation_mailer = YourMailerClass)."
|
|
80
|
-
raise ArgumentError, msg if @sorcery_config.user_activation_mailer == nil
|
|
88
|
+
raise ArgumentError, msg if @sorcery_config.user_activation_mailer == nil and @sorcery_config.activation_mailer_disabled == false
|
|
81
89
|
end
|
|
82
90
|
|
|
83
91
|
def define_user_activation_mongoid_fields
|
|
84
92
|
self.class_eval do
|
|
85
93
|
field sorcery_config.activation_state_attribute_name, :type => String
|
|
86
94
|
field sorcery_config.activation_token_attribute_name, :type => String
|
|
87
|
-
field sorcery_config.activation_token_expires_at_attribute_name, :type =>
|
|
95
|
+
field sorcery_config.activation_token_expires_at_attribute_name, :type => Time
|
|
88
96
|
end
|
|
89
97
|
end
|
|
90
98
|
|
|
@@ -92,7 +100,6 @@ module Sorcery
|
|
|
92
100
|
self.class_eval do
|
|
93
101
|
key sorcery_config.activation_state_attribute_name, String
|
|
94
102
|
key sorcery_config.activation_token_attribute_name, String
|
|
95
|
-
# no DateTime in MM
|
|
96
103
|
key sorcery_config.activation_token_expires_at_attribute_name, Time
|
|
97
104
|
end
|
|
98
105
|
end
|
|
@@ -120,11 +127,11 @@ module Sorcery
|
|
|
120
127
|
|
|
121
128
|
# called automatically after user initial creation.
|
|
122
129
|
def send_activation_needed_email!
|
|
123
|
-
generic_send_email(:activation_needed_email_method_name, :user_activation_mailer) unless sorcery_config.activation_needed_email_method_name.nil?
|
|
130
|
+
generic_send_email(:activation_needed_email_method_name, :user_activation_mailer) unless sorcery_config.activation_needed_email_method_name.nil? or sorcery_config.activation_mailer_disabled == true
|
|
124
131
|
end
|
|
125
132
|
|
|
126
133
|
def send_activation_success_email!
|
|
127
|
-
generic_send_email(:activation_success_email_method_name, :user_activation_mailer) unless sorcery_config.activation_success_email_method_name.nil?
|
|
134
|
+
generic_send_email(:activation_success_email_method_name, :user_activation_mailer) unless sorcery_config.activation_success_email_method_name.nil? or sorcery_config.activation_mailer_disabled == true
|
|
128
135
|
end
|
|
129
136
|
|
|
130
137
|
def prevent_non_active_login
|