sorcery 0.9.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sorcery might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +29 -104
- data/CHANGELOG.md +13 -1
- data/Gemfile +2 -16
- data/README.md +124 -272
- data/Rakefile +2 -2
- data/gemfiles/{mongoid-rails40.gemfile → active_record-rails42.gemfile} +1 -3
- data/lib/generators/sorcery/helpers.rb +4 -4
- data/lib/generators/sorcery/install_generator.rb +25 -19
- data/lib/generators/sorcery/templates/initializer.rb +27 -52
- data/lib/generators/sorcery/templates/migration/activity_logging.rb +2 -2
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +1 -1
- data/lib/generators/sorcery/templates/migration/core.rb +3 -3
- data/lib/generators/sorcery/templates/migration/external.rb +2 -2
- data/lib/generators/sorcery/templates/migration/remember_me.rb +2 -2
- data/lib/generators/sorcery/templates/migration/reset_password.rb +2 -2
- data/lib/generators/sorcery/templates/migration/user_activation.rb +2 -2
- data/lib/sorcery.rb +0 -28
- data/lib/sorcery/adapters/active_record_adapter.rb +7 -18
- data/lib/sorcery/controller.rb +19 -21
- data/lib/sorcery/controller/config.rb +20 -18
- data/lib/sorcery/controller/submodules/activity_logging.rb +7 -15
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +1 -2
- data/lib/sorcery/controller/submodules/external.rb +22 -14
- data/lib/sorcery/controller/submodules/http_basic_auth.rb +16 -19
- data/lib/sorcery/controller/submodules/remember_me.rb +15 -10
- data/lib/sorcery/controller/submodules/session_timeout.rb +7 -8
- data/lib/sorcery/crypto_providers/aes256.rb +15 -15
- data/lib/sorcery/crypto_providers/bcrypt.rb +19 -21
- data/lib/sorcery/crypto_providers/common.rb +1 -1
- data/lib/sorcery/crypto_providers/md5.rb +5 -5
- data/lib/sorcery/crypto_providers/sha1.rb +5 -5
- data/lib/sorcery/crypto_providers/sha256.rb +2 -2
- data/lib/sorcery/crypto_providers/sha512.rb +3 -3
- data/lib/sorcery/engine.rb +3 -8
- data/lib/sorcery/model.rb +24 -32
- data/lib/sorcery/model/config.rb +64 -49
- data/lib/sorcery/model/submodules/activity_logging.rb +31 -12
- data/lib/sorcery/model/submodules/brute_force_protection.rb +23 -23
- data/lib/sorcery/model/submodules/external.rb +3 -7
- data/lib/sorcery/model/submodules/remember_me.rb +19 -7
- data/lib/sorcery/model/submodules/reset_password.rb +32 -36
- data/lib/sorcery/model/submodules/user_activation.rb +38 -50
- data/lib/sorcery/model/temporary_token.rb +2 -2
- data/lib/sorcery/protocols/oauth.rb +3 -9
- data/lib/sorcery/protocols/oauth2.rb +0 -2
- data/lib/sorcery/providers/base.rb +4 -4
- data/lib/sorcery/providers/facebook.rb +5 -8
- data/lib/sorcery/providers/github.rb +5 -7
- data/lib/sorcery/providers/google.rb +3 -5
- data/lib/sorcery/providers/heroku.rb +6 -8
- data/lib/sorcery/providers/jira.rb +12 -17
- data/lib/sorcery/providers/linkedin.rb +6 -8
- data/lib/sorcery/providers/liveid.rb +4 -7
- data/lib/sorcery/providers/paypal.rb +60 -0
- data/lib/sorcery/providers/salesforce.rb +3 -5
- data/lib/sorcery/providers/slack.rb +45 -0
- data/lib/sorcery/providers/twitter.rb +4 -6
- data/lib/sorcery/providers/vk.rb +3 -5
- data/lib/sorcery/providers/wechat.rb +79 -0
- data/lib/sorcery/providers/xing.rb +7 -10
- data/lib/sorcery/test_helpers/internal.rb +10 -10
- data/lib/sorcery/test_helpers/internal/rails.rb +16 -8
- data/lib/sorcery/test_helpers/rails/controller.rb +1 -1
- data/lib/sorcery/test_helpers/rails/integration.rb +5 -6
- data/lib/sorcery/version.rb +1 -1
- data/sorcery.gemspec +25 -27
- data/spec/active_record/user_activation_spec.rb +2 -3
- data/spec/active_record/user_activity_logging_spec.rb +2 -4
- data/spec/active_record/user_brute_force_protection_spec.rb +3 -4
- data/spec/active_record/user_oauth_spec.rb +3 -4
- data/spec/active_record/user_remember_me_spec.rb +3 -4
- data/spec/active_record/user_reset_password_spec.rb +2 -3
- data/spec/active_record/user_spec.rb +7 -7
- data/spec/controllers/controller_activity_logging_spec.rb +13 -24
- data/spec/controllers/controller_brute_force_protection_spec.rb +6 -8
- data/spec/controllers/controller_http_basic_auth_spec.rb +19 -20
- data/spec/controllers/controller_oauth2_spec.rb +125 -100
- data/spec/controllers/controller_oauth_spec.rb +86 -66
- data/spec/controllers/controller_remember_me_spec.rb +35 -30
- data/spec/controllers/controller_session_timeout_spec.rb +14 -15
- data/spec/controllers/controller_spec.rb +77 -111
- data/spec/orm/active_record.rb +1 -1
- data/spec/rails_app/app/active_record/authentication.rb +1 -1
- data/spec/rails_app/app/active_record/user.rb +2 -2
- data/spec/rails_app/app/controllers/sorcery_controller.rb +89 -24
- data/spec/rails_app/app/mailers/sorcery_mailer.rb +16 -17
- data/spec/rails_app/config.ru +1 -1
- data/spec/rails_app/config/application.rb +7 -7
- data/spec/rails_app/config/boot.rb +1 -1
- data/spec/rails_app/config/environments/test.rb +1 -1
- data/spec/rails_app/config/initializers/compatible_legacy_migration.rb +11 -0
- data/spec/rails_app/config/initializers/session_store.rb +3 -3
- data/spec/rails_app/config/routes.rb +11 -1
- data/spec/rails_app/db/migrate/activation/20101224223622_add_activation_to_users.rb +4 -4
- data/spec/rails_app/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +8 -8
- data/spec/rails_app/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +5 -5
- data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +5 -5
- data/spec/rails_app/db/migrate/external/20101224223628_create_authentications_and_user_providers.rb +3 -3
- data/spec/rails_app/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +6 -6
- data/spec/rails_app/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +5 -5
- data/spec/shared_examples/user_activation_shared_examples.rb +99 -58
- data/spec/shared_examples/user_activity_logging_shared_examples.rb +47 -41
- data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +19 -24
- data/spec/shared_examples/user_oauth_shared_examples.rb +7 -10
- data/spec/shared_examples/user_remember_me_shared_examples.rb +90 -21
- data/spec/shared_examples/user_reset_password_shared_examples.rb +52 -54
- data/spec/shared_examples/user_shared_examples.rb +215 -118
- data/spec/sorcery_crypto_providers_spec.rb +63 -76
- data/spec/spec_helper.rb +17 -13
- metadata +28 -83
- data/gemfiles/mongo_mapper-rails40.gemfile +0 -9
- data/gemfiles/mongo_mapper-rails41.gemfile +0 -9
- data/gemfiles/mongoid-rails41.gemfile +0 -9
- data/gemfiles/mongoid3-rails32.gemfile +0 -9
- data/lib/sorcery/adapters/data_mapper_adapter.rb +0 -176
- data/lib/sorcery/adapters/mongo_mapper_adapter.rb +0 -110
- data/lib/sorcery/adapters/mongoid_adapter.rb +0 -97
- data/lib/sorcery/railties/tasks.rake +0 -6
- data/spec/data_mapper/user_activation_spec.rb +0 -10
- data/spec/data_mapper/user_activity_logging_spec.rb +0 -14
- data/spec/data_mapper/user_brute_force_protection_spec.rb +0 -9
- data/spec/data_mapper/user_oauth_spec.rb +0 -9
- data/spec/data_mapper/user_remember_me_spec.rb +0 -8
- data/spec/data_mapper/user_reset_password_spec.rb +0 -8
- data/spec/data_mapper/user_spec.rb +0 -27
- data/spec/mongo_mapper/user_activation_spec.rb +0 -9
- data/spec/mongo_mapper/user_activity_logging_spec.rb +0 -8
- data/spec/mongo_mapper/user_brute_force_protection_spec.rb +0 -8
- data/spec/mongo_mapper/user_oauth_spec.rb +0 -8
- data/spec/mongo_mapper/user_remember_me_spec.rb +0 -8
- data/spec/mongo_mapper/user_reset_password_spec.rb +0 -8
- data/spec/mongo_mapper/user_spec.rb +0 -37
- data/spec/mongoid/user_activation_spec.rb +0 -9
- data/spec/mongoid/user_activity_logging_spec.rb +0 -8
- data/spec/mongoid/user_brute_force_protection_spec.rb +0 -8
- data/spec/mongoid/user_oauth_spec.rb +0 -8
- data/spec/mongoid/user_remember_me_spec.rb +0 -8
- data/spec/mongoid/user_reset_password_spec.rb +0 -8
- data/spec/mongoid/user_spec.rb +0 -51
- data/spec/orm/data_mapper.rb +0 -48
- data/spec/orm/mongo_mapper.rb +0 -10
- data/spec/orm/mongoid.rb +0 -22
- data/spec/rails_app/app/data_mapper/authentication.rb +0 -8
- data/spec/rails_app/app/data_mapper/user.rb +0 -7
- data/spec/rails_app/app/mongo_mapper/authentication.rb +0 -6
- data/spec/rails_app/app/mongo_mapper/user.rb +0 -7
- data/spec/rails_app/app/mongoid/authentication.rb +0 -7
- data/spec/rails_app/app/mongoid/user.rb +0 -7
data/lib/sorcery/model/config.rb
CHANGED
@@ -4,43 +4,49 @@
|
|
4
4
|
module Sorcery
|
5
5
|
module Model
|
6
6
|
class Config
|
7
|
-
|
8
|
-
attr_accessor :username_attribute_names
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
7
|
+
# change default username attribute, for example, to use :email as the login.
|
8
|
+
attr_accessor :username_attribute_names
|
9
|
+
# change *virtual* password attribute, the one which is used until an encrypted one is generated.
|
10
|
+
attr_accessor :password_attribute_name
|
11
|
+
# change default email attribute.
|
12
|
+
attr_accessor :email_attribute_name
|
13
|
+
# downcase the username before trying to authenticate, default is false
|
14
|
+
attr_accessor :downcase_username_before_authenticating
|
15
|
+
# change default crypted_password attribute.
|
16
|
+
attr_accessor :crypted_password_attribute_name
|
17
|
+
# what pattern to use to join the password with the salt
|
18
|
+
attr_accessor :salt_join_token
|
19
|
+
# change default salt attribute.
|
20
|
+
attr_accessor :salt_attribute_name
|
21
|
+
# how many times to apply encryption to the password.
|
22
|
+
attr_accessor :stretches
|
23
|
+
# encryption key used to encrypt reversible encryptions such as AES256.
|
24
|
+
attr_accessor :encryption_key
|
25
|
+
# make this configuration inheritable for subclasses. Useful for ActiveRecord's STI.
|
26
|
+
attr_accessor :subclasses_inherit_config
|
27
|
+
# configured in config/application.rb
|
28
|
+
attr_accessor :submodules
|
29
|
+
# an array of method names to call before authentication completes. used internally.
|
30
|
+
attr_accessor :before_authenticate
|
31
|
+
# method to send email related
|
32
|
+
# options: `:deliver_later`, `:deliver_now`, `:deliver`
|
33
|
+
# Default: :deliver (Rails version < 4.2) or :deliver_now (Rails version 4.2+)
|
34
|
+
# method to send email related
|
35
|
+
attr_accessor :email_delivery_method
|
36
|
+
# an array of method names to call after configuration by user. used internally.
|
37
|
+
attr_accessor :after_config
|
38
|
+
|
39
|
+
# change default encryption_provider.
|
40
|
+
attr_reader :encryption_provider
|
41
|
+
# use an external encryption class.
|
42
|
+
attr_reader :custom_encryption_provider
|
43
|
+
# encryption algorithm name. See 'encryption_algorithm=' below for available options.
|
44
|
+
attr_reader :encryption_algorithm
|
39
45
|
|
40
46
|
def initialize
|
41
47
|
@defaults = {
|
42
48
|
:@submodules => [],
|
43
|
-
:@username_attribute_names
|
49
|
+
:@username_attribute_names => [:email],
|
44
50
|
:@password_attribute_name => :password,
|
45
51
|
:@downcase_username_before_authenticating => false,
|
46
52
|
:@email_attribute_name => :email,
|
@@ -49,25 +55,26 @@ module Sorcery
|
|
49
55
|
:@encryption_provider => CryptoProviders::BCrypt,
|
50
56
|
:@custom_encryption_provider => nil,
|
51
57
|
:@encryption_key => nil,
|
52
|
-
:@salt_join_token =>
|
58
|
+
:@salt_join_token => '',
|
53
59
|
:@salt_attribute_name => :salt,
|
54
60
|
:@stretches => nil,
|
55
61
|
:@subclasses_inherit_config => false,
|
56
62
|
:@before_authenticate => [],
|
57
|
-
:@after_config => []
|
63
|
+
:@after_config => [],
|
64
|
+
:@email_delivery_method => default_email_delivery_method
|
58
65
|
}
|
59
66
|
reset!
|
60
67
|
end
|
61
68
|
|
62
69
|
# Resets all configuration options to their default values.
|
63
70
|
def reset!
|
64
|
-
@defaults.each do |k,v|
|
65
|
-
instance_variable_set(k,v)
|
71
|
+
@defaults.each do |k, v|
|
72
|
+
instance_variable_set(k, v)
|
66
73
|
end
|
67
74
|
end
|
68
75
|
|
69
76
|
def username_attribute_names=(fields)
|
70
|
-
@username_attribute_names = fields.
|
77
|
+
@username_attribute_names = fields.is_a?(Array) ? fields : [fields]
|
71
78
|
end
|
72
79
|
|
73
80
|
def custom_encryption_provider=(provider)
|
@@ -77,20 +84,28 @@ module Sorcery
|
|
77
84
|
def encryption_algorithm=(algo)
|
78
85
|
@encryption_algorithm = algo
|
79
86
|
@encryption_provider = case @encryption_algorithm.to_sym
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
87
|
+
when :none then nil
|
88
|
+
when :md5 then CryptoProviders::MD5
|
89
|
+
when :sha1 then CryptoProviders::SHA1
|
90
|
+
when :sha256 then CryptoProviders::SHA256
|
91
|
+
when :sha512 then CryptoProviders::SHA512
|
92
|
+
when :aes256 then CryptoProviders::AES256
|
93
|
+
when :bcrypt then CryptoProviders::BCrypt
|
94
|
+
when :custom then @custom_encryption_provider
|
95
|
+
else raise ArgumentError, "Encryption algorithm supplied, #{algo}, is invalid"
|
89
96
|
end
|
90
97
|
end
|
91
98
|
|
92
|
-
|
99
|
+
private
|
100
|
+
|
101
|
+
def default_email_delivery_method
|
102
|
+
# Rails 4.2 deprecates #deliver
|
103
|
+
rails_version_bigger_than_or_equal?('4.2.0') ? :deliver_now : :deliver
|
104
|
+
end
|
93
105
|
|
106
|
+
def rails_version_bigger_than_or_equal?(version)
|
107
|
+
Gem::Version.new(version) <= Gem::Version.new(Rails.version)
|
108
|
+
end
|
109
|
+
end
|
94
110
|
end
|
95
111
|
end
|
96
|
-
|
@@ -12,12 +12,16 @@ module Sorcery
|
|
12
12
|
base.send(:include, InstanceMethods)
|
13
13
|
|
14
14
|
base.sorcery_config.class_eval do
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
# last login attribute name.
|
16
|
+
attr_accessor :last_login_at_attribute_name
|
17
|
+
# last logout attribute name.
|
18
|
+
attr_accessor :last_logout_at_attribute_name
|
19
|
+
# last activity attribute name.
|
20
|
+
attr_accessor :last_activity_at_attribute_name
|
21
|
+
# last activity login source
|
22
|
+
attr_accessor :last_login_from_ip_address_name
|
23
|
+
# how long since last activity is the user defined offline
|
24
|
+
attr_accessor :activity_timeout
|
21
25
|
end
|
22
26
|
|
23
27
|
base.sorcery_config.instance_eval do
|
@@ -45,18 +49,33 @@ module Sorcery
|
|
45
49
|
sorcery_adapter.update_attribute(sorcery_config.last_activity_at_attribute_name, time)
|
46
50
|
end
|
47
51
|
|
48
|
-
def
|
52
|
+
def set_last_ip_address(ip_address)
|
49
53
|
sorcery_adapter.update_attribute(sorcery_config.last_login_from_ip_address_name, ip_address)
|
50
54
|
end
|
51
|
-
end
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
56
|
+
# online method shows if user is active (logout action makes user inactive too)
|
57
|
+
def online?
|
58
|
+
return false if send(sorcery_config.last_activity_at_attribute_name).nil?
|
59
|
+
|
60
|
+
logged_in? && send(sorcery_config.last_activity_at_attribute_name) > sorcery_config.activity_timeout.seconds.ago
|
61
|
+
end
|
62
|
+
|
63
|
+
# shows if user is logged in, but it not show if user is online - see online?
|
64
|
+
def logged_in?
|
65
|
+
return false if send(sorcery_config.last_login_at_attribute_name).nil?
|
66
|
+
return true if send(sorcery_config.last_login_at_attribute_name).present? && send(sorcery_config.last_logout_at_attribute_name).nil?
|
67
|
+
|
68
|
+
send(sorcery_config.last_login_at_attribute_name) > send(sorcery_config.last_logout_at_attribute_name)
|
57
69
|
end
|
58
70
|
|
71
|
+
def logged_out?
|
72
|
+
!logged_in?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module ClassMethods
|
59
77
|
protected
|
78
|
+
|
60
79
|
def define_activity_logging_fields
|
61
80
|
sorcery_adapter.define_field sorcery_config.last_login_at_attribute_name, Time
|
62
81
|
sorcery_adapter.define_field sorcery_config.last_logout_at_attribute_name, Time
|
@@ -10,15 +10,15 @@ module Sorcery
|
|
10
10
|
base.sorcery_config.class_eval do
|
11
11
|
attr_accessor :failed_logins_count_attribute_name, # failed logins attribute name.
|
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
15
|
:login_lock_time_period, # how long the user should be banned.
|
16
|
-
|
16
|
+
# in seconds. 0 for permanent.
|
17
17
|
|
18
18
|
:unlock_token_attribute_name, # Unlock token attribute name
|
19
19
|
:unlock_token_email_method_name, # Mailer method name
|
20
20
|
:unlock_token_mailer_disabled, # When true, dont send unlock token via email
|
21
|
-
:unlock_token_mailer #
|
21
|
+
:unlock_token_mailer # Mailer class
|
22
22
|
end
|
23
23
|
|
24
24
|
base.sorcery_config.instance_eval do
|
@@ -43,14 +43,14 @@ module Sorcery
|
|
43
43
|
module ClassMethods
|
44
44
|
def load_from_unlock_token(token)
|
45
45
|
return nil if token.blank?
|
46
|
-
user = sorcery_adapter.find_by_token(sorcery_config.unlock_token_attribute_name,token)
|
46
|
+
user = sorcery_adapter.find_by_token(sorcery_config.unlock_token_attribute_name, token)
|
47
47
|
user
|
48
48
|
end
|
49
49
|
|
50
50
|
protected
|
51
51
|
|
52
52
|
def define_brute_force_protection_fields
|
53
|
-
sorcery_adapter.define_field sorcery_config.failed_logins_count_attribute_name, Integer, :
|
53
|
+
sorcery_adapter.define_field sorcery_config.failed_logins_count_attribute_name, Integer, default: 0
|
54
54
|
sorcery_adapter.define_field sorcery_config.lock_expires_at_attribute_name, Time
|
55
55
|
sorcery_adapter.define_field sorcery_config.unlock_token_attribute_name, String
|
56
56
|
end
|
@@ -58,39 +58,39 @@ module Sorcery
|
|
58
58
|
|
59
59
|
module InstanceMethods
|
60
60
|
# Called by the controller to increment the failed logins counter.
|
61
|
-
# Calls '
|
61
|
+
# Calls 'login_lock!' if login retries limit was reached.
|
62
62
|
def register_failed_login!
|
63
63
|
config = sorcery_config
|
64
|
-
return
|
64
|
+
return unless login_unlocked?
|
65
65
|
|
66
66
|
sorcery_adapter.increment(config.failed_logins_count_attribute_name)
|
67
67
|
|
68
|
-
if
|
69
|
-
|
68
|
+
if send(config.failed_logins_count_attribute_name) >= config.consecutive_login_retries_amount_limit
|
69
|
+
login_lock!
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
73
|
# /!\
|
74
74
|
# Moved out of protected for use like activate! in controller
|
75
75
|
# /!\
|
76
|
-
def
|
76
|
+
def login_unlock!
|
77
77
|
config = sorcery_config
|
78
|
-
attributes = {config.lock_expires_at_attribute_name => nil,
|
79
|
-
|
80
|
-
|
78
|
+
attributes = { config.lock_expires_at_attribute_name => nil,
|
79
|
+
config.failed_logins_count_attribute_name => 0,
|
80
|
+
config.unlock_token_attribute_name => nil }
|
81
81
|
sorcery_adapter.update_attributes(attributes)
|
82
82
|
end
|
83
83
|
|
84
|
-
def
|
85
|
-
!
|
84
|
+
def login_locked?
|
85
|
+
!login_unlocked?
|
86
86
|
end
|
87
87
|
|
88
88
|
protected
|
89
89
|
|
90
|
-
def
|
90
|
+
def login_lock!
|
91
91
|
config = sorcery_config
|
92
|
-
attributes = {config.lock_expires_at_attribute_name => Time.now.in_time_zone + config.login_lock_time_period,
|
93
|
-
|
92
|
+
attributes = { config.lock_expires_at_attribute_name => Time.now.in_time_zone + config.login_lock_time_period,
|
93
|
+
config.unlock_token_attribute_name => TemporaryToken.generate_random_token }
|
94
94
|
sorcery_adapter.update_attributes(attributes)
|
95
95
|
|
96
96
|
unless config.unlock_token_mailer_disabled || config.unlock_token_mailer.nil?
|
@@ -98,9 +98,9 @@ module Sorcery
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
def
|
101
|
+
def login_unlocked?
|
102
102
|
config = sorcery_config
|
103
|
-
|
103
|
+
send(config.lock_expires_at_attribute_name).nil?
|
104
104
|
end
|
105
105
|
|
106
106
|
def send_unlock_token_email!
|
@@ -113,10 +113,10 @@ module Sorcery
|
|
113
113
|
# Runs as a hook before authenticate.
|
114
114
|
def prevent_locked_user_login
|
115
115
|
config = sorcery_config
|
116
|
-
if !
|
117
|
-
|
116
|
+
if !login_unlocked? && config.login_lock_time_period != 0
|
117
|
+
login_unlock! if send(config.lock_expires_at_attribute_name) <= Time.now.in_time_zone
|
118
118
|
end
|
119
|
-
|
119
|
+
login_unlocked?
|
120
120
|
end
|
121
121
|
end
|
122
122
|
end
|
@@ -20,7 +20,6 @@ module Sorcery
|
|
20
20
|
:authentications_user_id_attribute_name,
|
21
21
|
:provider_attribute_name,
|
22
22
|
:provider_uid_attribute_name
|
23
|
-
|
24
23
|
end
|
25
24
|
|
26
25
|
base.sorcery_config.instance_eval do
|
@@ -34,12 +33,11 @@ module Sorcery
|
|
34
33
|
|
35
34
|
base.send(:include, InstanceMethods)
|
36
35
|
base.extend(ClassMethods)
|
37
|
-
|
38
36
|
end
|
39
37
|
|
40
38
|
module ClassMethods
|
41
39
|
# takes a provider and uid and finds a user by them.
|
42
|
-
def load_from_provider(provider,uid)
|
40
|
+
def load_from_provider(provider, uid)
|
43
41
|
config = sorcery_config
|
44
42
|
authentication = config.authentications_class.sorcery_adapter.find_by_oauth_credentials(provider, uid)
|
45
43
|
user = sorcery_adapter.find_by_id(authentication.send(config.authentications_user_id_attribute_name)) if authentication
|
@@ -57,7 +55,7 @@ module Sorcery
|
|
57
55
|
|
58
56
|
def create_from_provider(provider, uid, attrs)
|
59
57
|
user = new
|
60
|
-
attrs.each do |k,v|
|
58
|
+
attrs.each do |k, v|
|
61
59
|
user.send(:"#{k}=", v)
|
62
60
|
end
|
63
61
|
|
@@ -66,7 +64,7 @@ module Sorcery
|
|
66
64
|
end
|
67
65
|
|
68
66
|
sorcery_adapter.transaction do
|
69
|
-
user.sorcery_adapter.save(:
|
67
|
+
user.sorcery_adapter.save(validate: false)
|
70
68
|
sorcery_config.authentications_class.create!(
|
71
69
|
sorcery_config.authentications_user_id_attribute_name => user.id,
|
72
70
|
sorcery_config.provider_attribute_name => provider,
|
@@ -91,9 +89,7 @@ module Sorcery
|
|
91
89
|
|
92
90
|
user
|
93
91
|
end
|
94
|
-
|
95
92
|
end
|
96
|
-
|
97
93
|
end
|
98
94
|
end
|
99
95
|
end
|
@@ -9,13 +9,14 @@ module Sorcery
|
|
9
9
|
base.sorcery_config.class_eval do
|
10
10
|
attr_accessor :remember_me_token_attribute_name, # the attribute in the model class.
|
11
11
|
:remember_me_token_expires_at_attribute_name, # the expires attribute in the model class.
|
12
|
+
:remember_me_token_persist_globally, # persist a single token globally for all logins/logouts (supporting multiple simultaneous browsers)
|
12
13
|
:remember_me_for # how long in seconds to remember.
|
13
|
-
|
14
14
|
end
|
15
15
|
|
16
16
|
base.sorcery_config.instance_eval do
|
17
17
|
@defaults.merge!(:@remember_me_token_attribute_name => :remember_me_token,
|
18
18
|
:@remember_me_token_expires_at_attribute_name => :remember_me_token_expires_at,
|
19
|
+
:@remember_me_token_persist_globally => false,
|
19
20
|
:@remember_me_for => 7 * 60 * 60 * 24)
|
20
21
|
|
21
22
|
reset!
|
@@ -34,26 +35,37 @@ module Sorcery
|
|
34
35
|
sorcery_adapter.define_field sorcery_config.remember_me_token_attribute_name, String
|
35
36
|
sorcery_adapter.define_field sorcery_config.remember_me_token_expires_at_attribute_name, Time
|
36
37
|
end
|
37
|
-
|
38
38
|
end
|
39
39
|
|
40
40
|
module InstanceMethods
|
41
41
|
# You shouldn't really use this one yourself - it's called by the controller's 'remember_me!' method.
|
42
42
|
def remember_me!
|
43
43
|
config = sorcery_config
|
44
|
-
|
45
|
-
|
44
|
+
|
45
|
+
update_options = { config.remember_me_token_expires_at_attribute_name => Time.now.in_time_zone + config.remember_me_for }
|
46
|
+
|
47
|
+
unless config.remember_me_token_persist_globally && has_remember_me_token?
|
48
|
+
update_options[config.remember_me_token_attribute_name] = TemporaryToken.generate_random_token
|
49
|
+
end
|
50
|
+
|
51
|
+
sorcery_adapter.update_attributes(update_options)
|
46
52
|
end
|
47
53
|
|
48
54
|
def has_remember_me_token?
|
49
|
-
|
55
|
+
send(sorcery_config.remember_me_token_attribute_name).present?
|
50
56
|
end
|
51
57
|
|
52
58
|
# You shouldn't really use this one yourself - it's called by the controller's 'forget_me!' method.
|
59
|
+
# We only clear the token value if remember_me_token_persist_globally = true.
|
53
60
|
def forget_me!
|
61
|
+
sorcery_config.remember_me_token_persist_globally || force_forget_me!
|
62
|
+
end
|
63
|
+
|
64
|
+
# You shouldn't really use this one yourself - it's called by the controller's 'force_forget_me!' method.
|
65
|
+
def force_forget_me!
|
54
66
|
config = sorcery_config
|
55
|
-
|
56
|
-
|
67
|
+
sorcery_adapter.update_attributes(config.remember_me_token_attribute_name => nil,
|
68
|
+
config.remember_me_token_expires_at_attribute_name => nil)
|
57
69
|
end
|
58
70
|
end
|
59
71
|
end
|
@@ -12,26 +12,23 @@ module Sorcery
|
|
12
12
|
module ResetPassword
|
13
13
|
def self.included(base)
|
14
14
|
base.sorcery_config.class_eval do
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
:reset_password_time_between_emails # hammering protection, how long to wait
|
33
|
-
# before allowing another email to be sent.
|
34
|
-
|
15
|
+
# Reset password code attribute name.
|
16
|
+
attr_accessor :reset_password_token_attribute_name
|
17
|
+
# Expires at attribute name.
|
18
|
+
attr_accessor :reset_password_token_expires_at_attribute_name
|
19
|
+
# When was email sent, used for hammering protection.
|
20
|
+
attr_accessor :reset_password_email_sent_at_attribute_name
|
21
|
+
# Mailer class (needed)
|
22
|
+
attr_accessor :reset_password_mailer
|
23
|
+
# When true sorcery will not automatically email password reset details and allow you to
|
24
|
+
# manually handle how and when email is sent
|
25
|
+
attr_accessor :reset_password_mailer_disabled
|
26
|
+
# Reset password email method on your mailer class.
|
27
|
+
attr_accessor :reset_password_email_method_name
|
28
|
+
# How many seconds before the reset request expires. nil for never expires.
|
29
|
+
attr_accessor :reset_password_expiration_period
|
30
|
+
# Hammering protection, how long to wait before allowing another email to be sent.
|
31
|
+
attr_accessor :reset_password_time_between_emails
|
35
32
|
end
|
36
33
|
|
37
34
|
base.sorcery_config.instance_eval do
|
@@ -42,7 +39,7 @@ module Sorcery
|
|
42
39
|
:@reset_password_mailer_disabled => false,
|
43
40
|
:@reset_password_email_method_name => :reset_password_email,
|
44
41
|
:@reset_password_expiration_period => nil,
|
45
|
-
:@reset_password_time_between_emails => 5 * 60
|
42
|
+
:@reset_password_time_between_emails => 5 * 60)
|
46
43
|
|
47
44
|
reset!
|
48
45
|
end
|
@@ -53,7 +50,6 @@ module Sorcery
|
|
53
50
|
base.sorcery_config.after_config << :define_reset_password_fields
|
54
51
|
|
55
52
|
base.send(:include, InstanceMethods)
|
56
|
-
|
57
53
|
end
|
58
54
|
|
59
55
|
module ClassMethods
|
@@ -70,8 +66,8 @@ module Sorcery
|
|
70
66
|
# This submodule requires the developer to define his own mailer class to be used by it
|
71
67
|
# when reset_password_mailer_disabled is false
|
72
68
|
def validate_mailer_defined
|
73
|
-
|
74
|
-
raise ArgumentError,
|
69
|
+
message = 'To use reset_password submodule, you must define a mailer (config.reset_password_mailer = YourMailerClass).'
|
70
|
+
raise ArgumentError, message if @sorcery_config.reset_password_mailer.nil? && @sorcery_config.reset_password_mailer_disabled == false
|
75
71
|
end
|
76
72
|
|
77
73
|
def define_reset_password_fields
|
@@ -79,35 +75,36 @@ module Sorcery
|
|
79
75
|
sorcery_adapter.define_field sorcery_config.reset_password_token_expires_at_attribute_name, Time
|
80
76
|
sorcery_adapter.define_field sorcery_config.reset_password_email_sent_at_attribute_name, Time
|
81
77
|
end
|
82
|
-
|
83
78
|
end
|
84
79
|
|
85
80
|
module InstanceMethods
|
86
|
-
#
|
81
|
+
# Generates a reset code with expiration
|
87
82
|
def generate_reset_password_token!
|
88
83
|
config = sorcery_config
|
89
|
-
attributes = {config.reset_password_token_attribute_name => TemporaryToken.generate_random_token,
|
90
|
-
|
84
|
+
attributes = { config.reset_password_token_attribute_name => TemporaryToken.generate_random_token,
|
85
|
+
config.reset_password_email_sent_at_attribute_name => Time.now.in_time_zone }
|
91
86
|
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
|
92
87
|
|
93
|
-
|
88
|
+
sorcery_adapter.update_attributes(attributes)
|
94
89
|
end
|
95
90
|
|
96
|
-
#
|
91
|
+
# Generates a reset code with expiration and sends an email to the user.
|
97
92
|
def deliver_reset_password_instructions!
|
93
|
+
mail = false
|
98
94
|
config = sorcery_config
|
99
95
|
# hammering protection
|
100
|
-
return false if config.reset_password_time_between_emails.present? &&
|
96
|
+
return false if config.reset_password_time_between_emails.present? && send(config.reset_password_email_sent_at_attribute_name) && send(config.reset_password_email_sent_at_attribute_name) > config.reset_password_time_between_emails.seconds.ago.utc
|
101
97
|
self.class.sorcery_adapter.transaction do
|
102
98
|
generate_reset_password_token!
|
103
|
-
send_reset_password_email! unless config.reset_password_mailer_disabled
|
99
|
+
mail = send_reset_password_email! unless config.reset_password_mailer_disabled
|
104
100
|
end
|
101
|
+
mail
|
105
102
|
end
|
106
103
|
|
107
104
|
# Clears token and tries to update the new password for the user.
|
108
105
|
def change_password!(new_password)
|
109
106
|
clear_reset_password_token
|
110
|
-
|
107
|
+
send(:"#{sorcery_config.password_attribute_name}=", new_password)
|
111
108
|
sorcery_adapter.save
|
112
109
|
end
|
113
110
|
|
@@ -120,11 +117,10 @@ module Sorcery
|
|
120
117
|
# Clears the token.
|
121
118
|
def clear_reset_password_token
|
122
119
|
config = sorcery_config
|
123
|
-
|
124
|
-
|
120
|
+
send(:"#{config.reset_password_token_attribute_name}=", nil)
|
121
|
+
send(:"#{config.reset_password_token_expires_at_attribute_name}=", nil) if config.reset_password_expiration_period
|
125
122
|
end
|
126
123
|
end
|
127
|
-
|
128
124
|
end
|
129
125
|
end
|
130
126
|
end
|