sorcery 0.8.5 → 0.9.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.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/.travis.yml +122 -5
- data/CHANGELOG.md +37 -1
- data/Gemfile +10 -18
- data/README.md +159 -88
- data/gemfiles/active_record-rails40.gemfile +7 -0
- data/gemfiles/active_record-rails41.gemfile +7 -0
- data/gemfiles/mongo_mapper-rails40.gemfile +9 -0
- data/gemfiles/mongo_mapper-rails41.gemfile +9 -0
- data/gemfiles/mongoid-rails40.gemfile +9 -0
- data/gemfiles/mongoid-rails41.gemfile +9 -0
- data/gemfiles/mongoid3-rails32.gemfile +9 -0
- data/lib/generators/sorcery/USAGE +1 -1
- data/lib/generators/sorcery/install_generator.rb +19 -5
- data/lib/generators/sorcery/templates/initializer.rb +34 -9
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +3 -1
- data/lib/generators/sorcery/templates/migration/core.rb +2 -2
- data/lib/generators/sorcery/templates/migration/external.rb +3 -1
- data/lib/sorcery/adapters/active_record_adapter.rb +120 -0
- data/lib/sorcery/adapters/base_adapter.rb +30 -0
- data/lib/sorcery/adapters/data_mapper_adapter.rb +176 -0
- data/lib/sorcery/adapters/mongo_mapper_adapter.rb +110 -0
- data/lib/sorcery/adapters/mongoid_adapter.rb +97 -0
- data/lib/sorcery/controller/config.rb +65 -0
- data/lib/sorcery/controller/submodules/activity_logging.rb +16 -21
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +6 -6
- data/lib/sorcery/controller/submodules/external.rb +35 -40
- data/lib/sorcery/controller/submodules/remember_me.rb +4 -4
- data/lib/sorcery/controller/submodules/session_timeout.rb +10 -6
- data/lib/sorcery/controller.rb +10 -74
- data/lib/sorcery/model/config.rb +96 -0
- data/lib/sorcery/model/submodules/activity_logging.rb +30 -13
- data/lib/sorcery/model/submodules/brute_force_protection.rb +21 -21
- data/lib/sorcery/model/submodules/external.rb +53 -9
- data/lib/sorcery/model/submodules/remember_me.rb +15 -19
- data/lib/sorcery/model/submodules/reset_password.rb +33 -34
- data/lib/sorcery/model/submodules/user_activation.rb +36 -47
- data/lib/sorcery/model/temporary_token.rb +4 -4
- data/lib/sorcery/model.rb +73 -173
- data/lib/sorcery/protocols/oauth.rb +42 -0
- data/lib/sorcery/protocols/oauth2.rb +47 -0
- data/lib/sorcery/providers/base.rb +38 -0
- data/lib/sorcery/providers/facebook.rb +63 -0
- data/lib/sorcery/providers/github.rb +51 -0
- data/lib/sorcery/providers/google.rb +51 -0
- data/lib/sorcery/providers/heroku.rb +57 -0
- data/lib/sorcery/providers/jira.rb +77 -0
- data/lib/sorcery/providers/linkedin.rb +66 -0
- data/lib/sorcery/providers/liveid.rb +53 -0
- data/lib/sorcery/providers/salesforce.rb +50 -0
- data/lib/sorcery/providers/twitter.rb +59 -0
- data/lib/sorcery/providers/vk.rb +63 -0
- data/lib/sorcery/providers/xing.rb +64 -0
- data/lib/sorcery/test_helpers/internal/rails.rb +14 -3
- data/lib/sorcery/test_helpers/internal.rb +7 -3
- data/lib/sorcery/test_helpers/rails/controller.rb +21 -0
- data/lib/sorcery/test_helpers/rails/integration.rb +26 -0
- data/lib/sorcery/version.rb +3 -0
- data/lib/sorcery.rb +82 -58
- data/sorcery.gemspec +19 -19
- data/spec/active_record/user_activation_spec.rb +1 -1
- data/spec/active_record/user_activity_logging_spec.rb +10 -1
- data/spec/active_record/user_brute_force_protection_spec.rb +1 -1
- data/spec/active_record/user_oauth_spec.rb +1 -1
- data/spec/active_record/user_remember_me_spec.rb +1 -1
- data/spec/active_record/user_reset_password_spec.rb +1 -1
- data/spec/active_record/user_spec.rb +7 -8
- data/spec/controllers/controller_activity_logging_spec.rb +124 -0
- data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
- data/spec/controllers/controller_http_basic_auth_spec.rb +68 -0
- data/spec/controllers/controller_oauth2_spec.rb +414 -0
- data/spec/controllers/controller_oauth_spec.rb +240 -0
- data/spec/controllers/controller_remember_me_spec.rb +117 -0
- data/spec/controllers/controller_session_timeout_spec.rb +80 -0
- data/spec/controllers/controller_spec.rb +218 -0
- data/spec/data_mapper/user_activation_spec.rb +10 -0
- data/spec/data_mapper/user_activity_logging_spec.rb +14 -0
- data/spec/data_mapper/user_brute_force_protection_spec.rb +9 -0
- data/spec/data_mapper/user_oauth_spec.rb +9 -0
- data/spec/data_mapper/user_remember_me_spec.rb +8 -0
- data/spec/data_mapper/user_reset_password_spec.rb +8 -0
- data/spec/data_mapper/user_spec.rb +27 -0
- data/spec/mongo_mapper/user_activation_spec.rb +1 -2
- data/spec/mongo_mapper/user_activity_logging_spec.rb +1 -1
- data/spec/mongo_mapper/user_brute_force_protection_spec.rb +1 -1
- data/spec/mongo_mapper/user_oauth_spec.rb +1 -1
- data/spec/mongo_mapper/user_remember_me_spec.rb +1 -1
- data/spec/mongo_mapper/user_reset_password_spec.rb +1 -1
- data/spec/mongo_mapper/user_spec.rb +7 -8
- data/spec/mongoid/user_activation_spec.rb +1 -2
- data/spec/mongoid/user_activity_logging_spec.rb +1 -2
- data/spec/mongoid/user_brute_force_protection_spec.rb +1 -2
- data/spec/mongoid/user_oauth_spec.rb +1 -2
- data/spec/mongoid/user_remember_me_spec.rb +1 -2
- data/spec/mongoid/user_reset_password_spec.rb +1 -2
- data/spec/mongoid/user_spec.rb +21 -9
- data/spec/orm/active_record.rb +14 -0
- data/spec/orm/data_mapper.rb +48 -0
- data/spec/orm/mongo_mapper.rb +1 -1
- data/spec/orm/mongoid.rb +5 -0
- data/spec/rails_app/app/controllers/sorcery_controller.rb +125 -59
- data/spec/rails_app/app/data_mapper/authentication.rb +8 -0
- data/spec/rails_app/app/data_mapper/user.rb +7 -0
- data/spec/rails_app/app/mongo_mapper/user.rb +2 -0
- data/spec/rails_app/config/routes.rb +27 -13
- data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +2 -2
- data/spec/shared_examples/user_activation_shared_examples.rb +108 -91
- data/spec/shared_examples/user_activity_logging_shared_examples.rb +83 -15
- data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +140 -21
- data/spec/shared_examples/user_oauth_shared_examples.rb +21 -16
- data/spec/shared_examples/user_remember_me_shared_examples.rb +36 -24
- data/spec/shared_examples/user_reset_password_shared_examples.rb +138 -117
- data/spec/shared_examples/user_shared_examples.rb +297 -150
- data/spec/sorcery_crypto_providers_spec.rb +28 -28
- data/spec/spec_helper.rb +12 -18
- metadata +99 -165
- data/Gemfile.rails4 +0 -24
- data/VERSION +0 -1
- data/lib/sorcery/controller/submodules/external/protocols/oauth1.rb +0 -46
- data/lib/sorcery/controller/submodules/external/protocols/oauth2.rb +0 -50
- data/lib/sorcery/controller/submodules/external/providers/base.rb +0 -21
- data/lib/sorcery/controller/submodules/external/providers/facebook.rb +0 -99
- data/lib/sorcery/controller/submodules/external/providers/github.rb +0 -93
- data/lib/sorcery/controller/submodules/external/providers/google.rb +0 -92
- data/lib/sorcery/controller/submodules/external/providers/linkedin.rb +0 -103
- data/lib/sorcery/controller/submodules/external/providers/liveid.rb +0 -93
- data/lib/sorcery/controller/submodules/external/providers/twitter.rb +0 -94
- data/lib/sorcery/controller/submodules/external/providers/vk.rb +0 -101
- data/lib/sorcery/controller/submodules/external/providers/xing.rb +0 -98
- data/lib/sorcery/model/adapters/active_record.rb +0 -49
- data/lib/sorcery/model/adapters/mongo_mapper.rb +0 -56
- data/lib/sorcery/model/adapters/mongoid.rb +0 -88
- data/lib/sorcery/test_helpers/rails.rb +0 -16
- data/lib/sorcery/test_helpers.rb +0 -5
- data/spec/active_record/controller_activity_logging_spec.rb +0 -140
- data/spec/active_record/controller_brute_force_protection_spec.rb +0 -136
- data/spec/active_record/controller_http_basic_auth_spec.rb +0 -59
- data/spec/active_record/controller_oauth2_spec.rb +0 -417
- data/spec/active_record/controller_oauth_spec.rb +0 -212
- data/spec/active_record/controller_remember_me_spec.rb +0 -96
- data/spec/active_record/controller_session_timeout_spec.rb +0 -55
- data/spec/active_record/controller_spec.rb +0 -182
- data/spec/active_record/integration_spec.rb +0 -23
- data/spec/mongo_mapper/controller_spec.rb +0 -175
- data/spec/mongoid/controller_activity_logging_spec.rb +0 -111
- data/spec/mongoid/controller_spec.rb +0 -186
- data/spec/rails_app/public/404.html +0 -26
- data/spec/rails_app/public/422.html +0 -26
- data/spec/rails_app/public/500.html +0 -26
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/public/images/rails.png +0 -0
- data/spec/rails_app/public/javascripts/application.js +0 -2
- data/spec/rails_app/public/javascripts/controls.js +0 -965
- data/spec/rails_app/public/javascripts/dragdrop.js +0 -974
- data/spec/rails_app/public/javascripts/effects.js +0 -1123
- data/spec/rails_app/public/javascripts/prototype.js +0 -6001
- data/spec/rails_app/public/javascripts/rails.js +0 -175
- data/spec/rails_app/public/robots.txt +0 -5
- data/spec/rails_app/public/stylesheets/.gitkeep +0 -0
- data/spec/shared_examples/controller_oauth2_shared_examples.rb +0 -56
- data/spec/shared_examples/controller_oauth_shared_examples.rb +0 -69
- /data/lib/sorcery/{controller/submodules/external/protocols → protocols}/certs/ca-bundle.crt +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Each class which calls 'activate_sorcery!' receives an instance of this class.
|
|
2
|
+
# Every submodule which gets loaded may add accessors to this class so that all
|
|
3
|
+
# options will be configured from a single place.
|
|
4
|
+
module Sorcery
|
|
5
|
+
module Model
|
|
6
|
+
class Config
|
|
7
|
+
|
|
8
|
+
attr_accessor :username_attribute_names, # change default username attribute, for example, to use :email
|
|
9
|
+
# as the login.
|
|
10
|
+
|
|
11
|
+
:password_attribute_name, # change *virtual* password attribute, the one which is used
|
|
12
|
+
# until an encrypted one is generated.
|
|
13
|
+
|
|
14
|
+
:email_attribute_name, # change default email attribute.
|
|
15
|
+
|
|
16
|
+
:downcase_username_before_authenticating, # downcase the username before trying to authenticate, default is false
|
|
17
|
+
|
|
18
|
+
:crypted_password_attribute_name, # change default crypted_password attribute.
|
|
19
|
+
:salt_join_token, # what pattern to use to join the password with the salt
|
|
20
|
+
:salt_attribute_name, # change default salt attribute.
|
|
21
|
+
:stretches, # how many times to apply encryption to the password.
|
|
22
|
+
:encryption_key, # encryption key used to encrypt reversible encryptions such as
|
|
23
|
+
# AES256.
|
|
24
|
+
|
|
25
|
+
:subclasses_inherit_config, # make this configuration inheritable for subclasses. Useful for
|
|
26
|
+
# ActiveRecord's STI.
|
|
27
|
+
|
|
28
|
+
:submodules, # configured in config/application.rb
|
|
29
|
+
:before_authenticate, # an array of method names to call before authentication
|
|
30
|
+
# completes. used internally.
|
|
31
|
+
|
|
32
|
+
:after_config # an array of method names to call after configuration by user.
|
|
33
|
+
# used internally.
|
|
34
|
+
|
|
35
|
+
attr_reader :encryption_provider, # change default encryption_provider.
|
|
36
|
+
:custom_encryption_provider, # use an external encryption class.
|
|
37
|
+
:encryption_algorithm # encryption algorithm name. See 'encryption_algorithm=' below
|
|
38
|
+
# for available options.
|
|
39
|
+
|
|
40
|
+
def initialize
|
|
41
|
+
@defaults = {
|
|
42
|
+
:@submodules => [],
|
|
43
|
+
:@username_attribute_names => [:email],
|
|
44
|
+
:@password_attribute_name => :password,
|
|
45
|
+
:@downcase_username_before_authenticating => false,
|
|
46
|
+
:@email_attribute_name => :email,
|
|
47
|
+
:@crypted_password_attribute_name => :crypted_password,
|
|
48
|
+
:@encryption_algorithm => :bcrypt,
|
|
49
|
+
:@encryption_provider => CryptoProviders::BCrypt,
|
|
50
|
+
:@custom_encryption_provider => nil,
|
|
51
|
+
:@encryption_key => nil,
|
|
52
|
+
:@salt_join_token => "",
|
|
53
|
+
:@salt_attribute_name => :salt,
|
|
54
|
+
:@stretches => nil,
|
|
55
|
+
:@subclasses_inherit_config => false,
|
|
56
|
+
:@before_authenticate => [],
|
|
57
|
+
:@after_config => []
|
|
58
|
+
}
|
|
59
|
+
reset!
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Resets all configuration options to their default values.
|
|
63
|
+
def reset!
|
|
64
|
+
@defaults.each do |k,v|
|
|
65
|
+
instance_variable_set(k,v)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def username_attribute_names=(fields)
|
|
70
|
+
@username_attribute_names = fields.kind_of?(Array) ? fields : [fields]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def custom_encryption_provider=(provider)
|
|
74
|
+
@custom_encryption_provider = @encryption_provider = provider
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def encryption_algorithm=(algo)
|
|
78
|
+
@encryption_algorithm = algo
|
|
79
|
+
@encryption_provider = case @encryption_algorithm.to_sym
|
|
80
|
+
when :none then nil
|
|
81
|
+
when :md5 then CryptoProviders::MD5
|
|
82
|
+
when :sha1 then CryptoProviders::SHA1
|
|
83
|
+
when :sha256 then CryptoProviders::SHA256
|
|
84
|
+
when :sha512 then CryptoProviders::SHA512
|
|
85
|
+
when :aes256 then CryptoProviders::AES256
|
|
86
|
+
when :bcrypt then CryptoProviders::BCrypt
|
|
87
|
+
when :custom then @custom_encryption_provider
|
|
88
|
+
else raise ArgumentError.new("Encryption algorithm supplied, #{algo}, is invalid")
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
@@ -3,22 +3,23 @@ module Sorcery
|
|
|
3
3
|
module Submodules
|
|
4
4
|
# This submodule keeps track of events such as login, logout, and last activity time, per user.
|
|
5
5
|
# It helps in estimating which users are active now in the site.
|
|
6
|
-
# This cannot be determined absolutely because a user might be reading a page without clicking anything
|
|
6
|
+
# This cannot be determined absolutely because a user might be reading a page without clicking anything
|
|
7
7
|
# for a while.
|
|
8
8
|
# This is the model part of the submodule, which provides configuration options.
|
|
9
9
|
module ActivityLogging
|
|
10
10
|
def self.included(base)
|
|
11
11
|
base.extend(ClassMethods)
|
|
12
|
+
base.send(:include, InstanceMethods)
|
|
12
13
|
|
|
13
14
|
base.sorcery_config.class_eval do
|
|
14
15
|
attr_accessor :last_login_at_attribute_name, # last login attribute name.
|
|
15
16
|
:last_logout_at_attribute_name, # last logout attribute name.
|
|
16
17
|
:last_activity_at_attribute_name, # last activity attribute name.
|
|
17
18
|
:last_login_from_ip_address_name, # last activity login source
|
|
18
|
-
:activity_timeout # how long since last activity is
|
|
19
|
+
:activity_timeout # how long since last activity is
|
|
19
20
|
#the user defined logged out?
|
|
20
21
|
end
|
|
21
|
-
|
|
22
|
+
|
|
22
23
|
base.sorcery_config.instance_eval do
|
|
23
24
|
@defaults.merge!(:@last_login_at_attribute_name => :last_login_at,
|
|
24
25
|
:@last_logout_at_attribute_name => :last_logout_at,
|
|
@@ -28,23 +29,39 @@ module Sorcery
|
|
|
28
29
|
reset!
|
|
29
30
|
end
|
|
30
31
|
|
|
31
|
-
base.sorcery_config.after_config << :
|
|
32
|
+
base.sorcery_config.after_config << :define_activity_logging_fields
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module InstanceMethods
|
|
36
|
+
def set_last_login_at(time)
|
|
37
|
+
sorcery_adapter.update_attribute(sorcery_config.last_login_at_attribute_name, time)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def set_last_logout_at(time)
|
|
41
|
+
sorcery_adapter.update_attribute(sorcery_config.last_logout_at_attribute_name, time)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def set_last_activity_at(time)
|
|
45
|
+
sorcery_adapter.update_attribute(sorcery_config.last_activity_at_attribute_name, time)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def set_last_ip_addess(ip_address)
|
|
49
|
+
sorcery_adapter.update_attribute(sorcery_config.last_login_from_ip_address_name, ip_address)
|
|
50
|
+
end
|
|
32
51
|
end
|
|
33
|
-
|
|
52
|
+
|
|
34
53
|
module ClassMethods
|
|
35
54
|
# get all users with last_activity within timeout
|
|
36
55
|
def current_users
|
|
37
|
-
|
|
38
|
-
get_current_users
|
|
56
|
+
sorcery_adapter.get_current_users
|
|
39
57
|
end
|
|
40
58
|
|
|
41
59
|
protected
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
field sorcery_config.last_login_from_ip_address_name, :type => String
|
|
60
|
+
def define_activity_logging_fields
|
|
61
|
+
sorcery_adapter.define_field sorcery_config.last_login_at_attribute_name, Time
|
|
62
|
+
sorcery_adapter.define_field sorcery_config.last_logout_at_attribute_name, Time
|
|
63
|
+
sorcery_adapter.define_field sorcery_config.last_activity_at_attribute_name, Time
|
|
64
|
+
sorcery_adapter.define_field sorcery_config.last_login_from_ip_address_name, String
|
|
48
65
|
end
|
|
49
66
|
end
|
|
50
67
|
end
|
|
@@ -35,10 +35,7 @@ module Sorcery
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
base.sorcery_config.before_authenticate << :prevent_locked_user_login
|
|
38
|
-
base.sorcery_config.after_config << :
|
|
39
|
-
if defined?(MongoMapper) and base.ancestors.include?(MongoMapper::Document)
|
|
40
|
-
base.sorcery_config.after_config << :define_brute_force_protection_mongo_mapper_fields
|
|
41
|
-
end
|
|
38
|
+
base.sorcery_config.after_config << :define_brute_force_protection_fields
|
|
42
39
|
base.extend(ClassMethods)
|
|
43
40
|
base.send(:include, InstanceMethods)
|
|
44
41
|
end
|
|
@@ -46,22 +43,16 @@ module Sorcery
|
|
|
46
43
|
module ClassMethods
|
|
47
44
|
def load_from_unlock_token(token)
|
|
48
45
|
return nil if token.blank?
|
|
49
|
-
user =
|
|
46
|
+
user = sorcery_adapter.find_by_token(sorcery_config.unlock_token_attribute_name,token)
|
|
50
47
|
user
|
|
51
48
|
end
|
|
52
49
|
|
|
53
50
|
protected
|
|
54
51
|
|
|
55
|
-
def
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def define_brute_force_protection_mongo_mapper_fields
|
|
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
|
|
52
|
+
def define_brute_force_protection_fields
|
|
53
|
+
sorcery_adapter.define_field sorcery_config.failed_logins_count_attribute_name, Integer, :default => 0
|
|
54
|
+
sorcery_adapter.define_field sorcery_config.lock_expires_at_attribute_name, Time
|
|
55
|
+
sorcery_adapter.define_field sorcery_config.unlock_token_attribute_name, String
|
|
65
56
|
end
|
|
66
57
|
end
|
|
67
58
|
|
|
@@ -71,9 +62,12 @@ module Sorcery
|
|
|
71
62
|
def register_failed_login!
|
|
72
63
|
config = sorcery_config
|
|
73
64
|
return if !unlocked?
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
|
|
66
|
+
sorcery_adapter.increment(config.failed_logins_count_attribute_name)
|
|
67
|
+
|
|
68
|
+
if self.send(config.failed_logins_count_attribute_name) >= config.consecutive_login_retries_amount_limit
|
|
69
|
+
lock!
|
|
70
|
+
end
|
|
77
71
|
end
|
|
78
72
|
|
|
79
73
|
# /!\
|
|
@@ -84,7 +78,11 @@ module Sorcery
|
|
|
84
78
|
attributes = {config.lock_expires_at_attribute_name => nil,
|
|
85
79
|
config.failed_logins_count_attribute_name => 0,
|
|
86
80
|
config.unlock_token_attribute_name => nil}
|
|
87
|
-
|
|
81
|
+
sorcery_adapter.update_attributes(attributes)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def locked?
|
|
85
|
+
!unlocked?
|
|
88
86
|
end
|
|
89
87
|
|
|
90
88
|
protected
|
|
@@ -93,7 +91,7 @@ module Sorcery
|
|
|
93
91
|
config = sorcery_config
|
|
94
92
|
attributes = {config.lock_expires_at_attribute_name => Time.now.in_time_zone + config.login_lock_time_period,
|
|
95
93
|
config.unlock_token_attribute_name => TemporaryToken.generate_random_token}
|
|
96
|
-
|
|
94
|
+
sorcery_adapter.update_attributes(attributes)
|
|
97
95
|
|
|
98
96
|
unless config.unlock_token_mailer_disabled || config.unlock_token_mailer.nil?
|
|
99
97
|
send_unlock_token_email!
|
|
@@ -106,7 +104,9 @@ module Sorcery
|
|
|
106
104
|
end
|
|
107
105
|
|
|
108
106
|
def send_unlock_token_email!
|
|
109
|
-
|
|
107
|
+
return if sorcery_config.unlock_token_email_method_name.nil?
|
|
108
|
+
|
|
109
|
+
generic_send_email(:unlock_token_email_method_name, :unlock_token_mailer)
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
# Prevents a locked user from logging in, and unlocks users that expired their lock time.
|
|
@@ -8,7 +8,7 @@ module Sorcery
|
|
|
8
8
|
# Socery assumes (read: requires) you will create external users in the same table where
|
|
9
9
|
# you keep your regular users,
|
|
10
10
|
# but that you will have a separate table for keeping their external authentication data,
|
|
11
|
-
# and that that separate table has a few rows for each user, facebook and twitter
|
|
11
|
+
# and that that separate table has a few rows for each user, facebook and twitter
|
|
12
12
|
# for example (a one-to-many relationship).
|
|
13
13
|
#
|
|
14
14
|
# External users will have a null crypted_password field, since we do not hold their password.
|
|
@@ -22,7 +22,7 @@ module Sorcery
|
|
|
22
22
|
:provider_uid_attribute_name
|
|
23
23
|
|
|
24
24
|
end
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
base.sorcery_config.instance_eval do
|
|
27
27
|
@defaults.merge!(:@authentications_class => nil,
|
|
28
28
|
:@authentications_user_id_attribute_name => :user_id,
|
|
@@ -31,26 +31,70 @@ module Sorcery
|
|
|
31
31
|
|
|
32
32
|
reset!
|
|
33
33
|
end
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
base.send(:include, InstanceMethods)
|
|
36
36
|
base.extend(ClassMethods)
|
|
37
37
|
|
|
38
38
|
end
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
module ClassMethods
|
|
41
41
|
# takes a provider and uid and finds a user by them.
|
|
42
42
|
def load_from_provider(provider,uid)
|
|
43
43
|
config = sorcery_config
|
|
44
|
-
authentication = config.authentications_class.
|
|
45
|
-
user =
|
|
44
|
+
authentication = config.authentications_class.sorcery_adapter.find_by_oauth_credentials(provider, uid)
|
|
45
|
+
user = sorcery_adapter.find_by_id(authentication.send(config.authentications_user_id_attribute_name)) if authentication
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def create_and_validate_from_provider(provider, uid, attrs)
|
|
49
|
+
user = new(attrs)
|
|
50
|
+
user.send(sorcery_config.authentications_class.to_s.downcase.pluralize).build(
|
|
51
|
+
sorcery_config.provider_uid_attribute_name => uid,
|
|
52
|
+
sorcery_config.provider_attribute_name => provider
|
|
53
|
+
)
|
|
54
|
+
saved = user.sorcery_adapter.save
|
|
55
|
+
[user, saved]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def create_from_provider(provider, uid, attrs)
|
|
59
|
+
user = new
|
|
60
|
+
attrs.each do |k,v|
|
|
61
|
+
user.send(:"#{k}=", v)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
if block_given?
|
|
65
|
+
return false unless yield user
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
sorcery_adapter.transaction do
|
|
69
|
+
user.sorcery_adapter.save(:validate => false)
|
|
70
|
+
sorcery_config.authentications_class.create!(
|
|
71
|
+
sorcery_config.authentications_user_id_attribute_name => user.id,
|
|
72
|
+
sorcery_config.provider_attribute_name => provider,
|
|
73
|
+
sorcery_config.provider_uid_attribute_name => uid
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
user
|
|
46
77
|
end
|
|
47
78
|
end
|
|
48
|
-
|
|
79
|
+
|
|
49
80
|
module InstanceMethods
|
|
81
|
+
def add_provider_to_user(provider, uid)
|
|
82
|
+
authentications = sorcery_config.authentications_class.name.underscore.pluralize
|
|
83
|
+
# first check to see if user has a particular authentication already
|
|
84
|
+
if sorcery_adapter.find_authentication_by_oauth_credentials(authentications, provider, uid).nil?
|
|
85
|
+
user = send(authentications).build(sorcery_config.provider_uid_attribute_name => uid,
|
|
86
|
+
sorcery_config.provider_attribute_name => provider)
|
|
87
|
+
user.sorcery_adapter.save(validate: false)
|
|
88
|
+
else
|
|
89
|
+
user = false
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
user
|
|
93
|
+
end
|
|
50
94
|
|
|
51
95
|
end
|
|
52
|
-
|
|
96
|
+
|
|
53
97
|
end
|
|
54
98
|
end
|
|
55
99
|
end
|
|
56
|
-
end
|
|
100
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Sorcery
|
|
2
2
|
module Model
|
|
3
3
|
module Submodules
|
|
4
|
-
# The Remember Me submodule takes care of setting the user's cookie so that he will
|
|
4
|
+
# The Remember Me submodule takes care of setting the user's cookie so that he will
|
|
5
5
|
# be automatically logged in to the site on every visit,
|
|
6
6
|
# until the cookie expires.
|
|
7
7
|
module RememberMe
|
|
@@ -12,7 +12,7 @@ module Sorcery
|
|
|
12
12
|
:remember_me_for # how long in seconds to remember.
|
|
13
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,
|
|
@@ -20,47 +20,43 @@ module Sorcery
|
|
|
20
20
|
|
|
21
21
|
reset!
|
|
22
22
|
end
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
base.send(:include, InstanceMethods)
|
|
25
|
+
base.sorcery_config.after_config << :define_remember_me_fields
|
|
25
26
|
|
|
26
|
-
base.sorcery_config.after_config << :define_remember_me_mongoid_fields if defined?(Mongoid) and base.ancestors.include?(Mongoid::Document)
|
|
27
|
-
if defined?(MongoMapper) and base.ancestors.include?(MongoMapper::Document)
|
|
28
|
-
base.sorcery_config.after_config << :define_remember_me_mongo_mapper_fields
|
|
29
|
-
end
|
|
30
|
-
|
|
31
27
|
base.extend(ClassMethods)
|
|
32
28
|
end
|
|
33
29
|
|
|
34
30
|
module ClassMethods
|
|
35
31
|
protected
|
|
36
32
|
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
def define_remember_me_fields
|
|
34
|
+
sorcery_adapter.define_field sorcery_config.remember_me_token_attribute_name, String
|
|
35
|
+
sorcery_adapter.define_field sorcery_config.remember_me_token_expires_at_attribute_name, Time
|
|
40
36
|
end
|
|
41
37
|
|
|
42
|
-
def define_remember_me_mongo_mapper_fields
|
|
43
|
-
key sorcery_config.remember_me_token_attribute_name, String
|
|
44
|
-
key sorcery_config.remember_me_token_expires_at_attribute_name, Time
|
|
45
|
-
end
|
|
46
38
|
end
|
|
47
39
|
|
|
48
40
|
module InstanceMethods
|
|
49
41
|
# You shouldn't really use this one yourself - it's called by the controller's 'remember_me!' method.
|
|
50
42
|
def remember_me!
|
|
51
43
|
config = sorcery_config
|
|
52
|
-
self.
|
|
44
|
+
self.sorcery_adapter.update_attributes(config.remember_me_token_attribute_name => TemporaryToken.generate_random_token,
|
|
53
45
|
config.remember_me_token_expires_at_attribute_name => Time.now.in_time_zone + config.remember_me_for)
|
|
54
46
|
end
|
|
55
|
-
|
|
47
|
+
|
|
48
|
+
def has_remember_me_token?
|
|
49
|
+
self.send(sorcery_config.remember_me_token_attribute_name).present?
|
|
50
|
+
end
|
|
51
|
+
|
|
56
52
|
# You shouldn't really use this one yourself - it's called by the controller's 'forget_me!' method.
|
|
57
53
|
def forget_me!
|
|
58
54
|
config = sorcery_config
|
|
59
|
-
self.
|
|
55
|
+
self.sorcery_adapter.update_attributes(config.remember_me_token_attribute_name => nil,
|
|
60
56
|
config.remember_me_token_expires_at_attribute_name => nil)
|
|
61
57
|
end
|
|
62
58
|
end
|
|
63
59
|
end
|
|
64
60
|
end
|
|
65
61
|
end
|
|
66
|
-
end
|
|
62
|
+
end
|
|
@@ -9,14 +9,14 @@ module Sorcery
|
|
|
9
9
|
# he will be able to reset his password via a form.
|
|
10
10
|
#
|
|
11
11
|
# When using this submodule, supplying a mailer is mandatory.
|
|
12
|
-
module ResetPassword
|
|
12
|
+
module ResetPassword
|
|
13
13
|
def self.included(base)
|
|
14
14
|
base.sorcery_config.class_eval do
|
|
15
15
|
attr_accessor :reset_password_token_attribute_name, # reset password code attribute name.
|
|
16
16
|
:reset_password_token_expires_at_attribute_name, # expires at attribute name.
|
|
17
17
|
:reset_password_email_sent_at_attribute_name, # when was email sent, used for hammering
|
|
18
18
|
# protection.
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
:reset_password_mailer, # mailer class. Needed.
|
|
21
21
|
|
|
22
22
|
:reset_password_mailer_disabled, # when true sorcery will not automatically
|
|
@@ -25,15 +25,15 @@ module Sorcery
|
|
|
25
25
|
|
|
26
26
|
:reset_password_email_method_name, # reset password email method on your
|
|
27
27
|
# mailer class.
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
:reset_password_expiration_period, # how many seconds before the reset request
|
|
30
30
|
# expires. nil for never expires.
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
:reset_password_time_between_emails # hammering protection, how long to wait
|
|
33
33
|
# before allowing another email to be sent.
|
|
34
34
|
|
|
35
35
|
end
|
|
36
|
-
|
|
36
|
+
|
|
37
37
|
base.sorcery_config.instance_eval do
|
|
38
38
|
@defaults.merge!(:@reset_password_token_attribute_name => :reset_password_token,
|
|
39
39
|
:@reset_password_token_expires_at_attribute_name => :reset_password_token_expires_at,
|
|
@@ -50,15 +50,12 @@ module Sorcery
|
|
|
50
50
|
base.extend(ClassMethods)
|
|
51
51
|
|
|
52
52
|
base.sorcery_config.after_config << :validate_mailer_defined
|
|
53
|
-
base.sorcery_config.after_config << :
|
|
54
|
-
if defined?(MongoMapper) and base.ancestors.include?(MongoMapper::Document)
|
|
55
|
-
base.sorcery_config.after_config << :define_reset_password_mongo_mapper_fields
|
|
56
|
-
end
|
|
53
|
+
base.sorcery_config.after_config << :define_reset_password_fields
|
|
57
54
|
|
|
58
55
|
base.send(:include, InstanceMethods)
|
|
59
56
|
|
|
60
57
|
end
|
|
61
|
-
|
|
58
|
+
|
|
62
59
|
module ClassMethods
|
|
63
60
|
# Find user by token, also checks for expiration.
|
|
64
61
|
# Returns the user if token found and is valid.
|
|
@@ -67,9 +64,9 @@ module Sorcery
|
|
|
67
64
|
token_expiration_date_attr = @sorcery_config.reset_password_token_expires_at_attribute_name
|
|
68
65
|
load_from_token(token, token_attr_name, token_expiration_date_attr)
|
|
69
66
|
end
|
|
70
|
-
|
|
67
|
+
|
|
71
68
|
protected
|
|
72
|
-
|
|
69
|
+
|
|
73
70
|
# This submodule requires the developer to define his own mailer class to be used by it
|
|
74
71
|
# when reset_password_mailer_disabled is false
|
|
75
72
|
def validate_mailer_defined
|
|
@@ -77,43 +74,45 @@ module Sorcery
|
|
|
77
74
|
raise ArgumentError, msg if @sorcery_config.reset_password_mailer == nil and @sorcery_config.reset_password_mailer_disabled == false
|
|
78
75
|
end
|
|
79
76
|
|
|
80
|
-
def
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def define_reset_password_mongo_mapper_fields
|
|
87
|
-
key sorcery_config.reset_password_token_attribute_name, String
|
|
88
|
-
key sorcery_config.reset_password_token_expires_at_attribute_name, Time
|
|
89
|
-
key sorcery_config.reset_password_email_sent_at_attribute_name, Time
|
|
77
|
+
def define_reset_password_fields
|
|
78
|
+
sorcery_adapter.define_field sorcery_config.reset_password_token_attribute_name, String
|
|
79
|
+
sorcery_adapter.define_field sorcery_config.reset_password_token_expires_at_attribute_name, Time
|
|
80
|
+
sorcery_adapter.define_field sorcery_config.reset_password_email_sent_at_attribute_name, Time
|
|
90
81
|
end
|
|
82
|
+
|
|
91
83
|
end
|
|
92
|
-
|
|
84
|
+
|
|
93
85
|
module InstanceMethods
|
|
94
|
-
# generates a reset code with expiration
|
|
95
|
-
def
|
|
86
|
+
# generates a reset code with expiration
|
|
87
|
+
def generate_reset_password_token!
|
|
96
88
|
config = sorcery_config
|
|
97
|
-
# hammering protection
|
|
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
89
|
attributes = {config.reset_password_token_attribute_name => TemporaryToken.generate_random_token,
|
|
100
90
|
config.reset_password_email_sent_at_attribute_name => Time.now.in_time_zone}
|
|
101
91
|
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
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
92
|
+
|
|
93
|
+
self.sorcery_adapter.update_attributes(attributes)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# generates a reset code with expiration and sends an email to the user.
|
|
97
|
+
def deliver_reset_password_instructions!
|
|
98
|
+
config = sorcery_config
|
|
99
|
+
# hammering protection
|
|
100
|
+
return false if config.reset_password_time_between_emails.present? && 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.seconds.ago.utc
|
|
101
|
+
self.class.sorcery_adapter.transaction do
|
|
102
|
+
generate_reset_password_token!
|
|
103
|
+
send_reset_password_email! unless config.reset_password_mailer_disabled
|
|
105
104
|
end
|
|
106
105
|
end
|
|
107
|
-
|
|
106
|
+
|
|
108
107
|
# Clears token and tries to update the new password for the user.
|
|
109
108
|
def change_password!(new_password)
|
|
110
109
|
clear_reset_password_token
|
|
111
110
|
self.send(:"#{sorcery_config.password_attribute_name}=", new_password)
|
|
112
|
-
save
|
|
111
|
+
sorcery_adapter.save
|
|
113
112
|
end
|
|
114
113
|
|
|
115
114
|
protected
|
|
116
|
-
|
|
115
|
+
|
|
117
116
|
def send_reset_password_email!
|
|
118
117
|
generic_send_email(:reset_password_email_method_name, :reset_password_mailer)
|
|
119
118
|
end
|
|
@@ -125,7 +124,7 @@ module Sorcery
|
|
|
125
124
|
self.send(:"#{config.reset_password_token_expires_at_attribute_name}=", nil) if config.reset_password_expiration_period
|
|
126
125
|
end
|
|
127
126
|
end
|
|
128
|
-
|
|
127
|
+
|
|
129
128
|
end
|
|
130
129
|
end
|
|
131
130
|
end
|