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
|
@@ -10,16 +10,16 @@ module Sorcery
|
|
|
10
10
|
base.sorcery_config.class_eval do
|
|
11
11
|
attr_accessor :activation_state_attribute_name, # the attribute name to hold activation state
|
|
12
12
|
# (active/pending).
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
:activation_token_attribute_name, # the attribute name to hold activation code
|
|
15
15
|
# (sent by email).
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
:activation_token_expires_at_attribute_name, # the attribute name to hold activation code
|
|
18
|
-
# expiration date.
|
|
19
|
-
|
|
18
|
+
# expiration date.
|
|
19
|
+
|
|
20
20
|
:activation_token_expiration_period, # how many seconds before the activation code
|
|
21
21
|
# expires. nil for never expires.
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
:user_activation_mailer, # your mailer class. Required when
|
|
24
24
|
# activation_mailer_disabled == false.
|
|
25
25
|
|
|
@@ -29,14 +29,14 @@ module Sorcery
|
|
|
29
29
|
|
|
30
30
|
:activation_needed_email_method_name, # activation needed email method on your
|
|
31
31
|
# mailer class.
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
:activation_success_email_method_name, # activation success email method on your
|
|
34
34
|
# mailer class.
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
:prevent_non_active_users_to_login # do you want to prevent or allow users that
|
|
37
37
|
# did not activate by email to login?
|
|
38
38
|
end
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
base.sorcery_config.instance_eval do
|
|
41
41
|
@defaults.merge!(:@activation_state_attribute_name => :activation_state,
|
|
42
42
|
:@activation_token_attribute_name => :activation_token,
|
|
@@ -49,27 +49,24 @@ module Sorcery
|
|
|
49
49
|
:@prevent_non_active_users_to_login => true)
|
|
50
50
|
reset!
|
|
51
51
|
end
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
base.class_eval do
|
|
54
54
|
# don't setup activation if no password supplied - this user is created automatically
|
|
55
|
-
|
|
55
|
+
sorcery_adapter.define_callback :before, :create, :setup_activation, :if => Proc.new { |user| user.send(sorcery_config.password_attribute_name).present? }
|
|
56
56
|
# don't send activation needed email if no crypted password created - this user is external (OAuth etc.)
|
|
57
|
-
|
|
57
|
+
sorcery_adapter.define_callback :after, :create, :send_activation_needed_email!, :if => :send_activation_needed_email?
|
|
58
58
|
end
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
base.sorcery_config.after_config << :validate_mailer_defined
|
|
61
|
-
base.sorcery_config.after_config << :
|
|
62
|
-
if defined?(MongoMapper) and base.ancestors.include?(MongoMapper::Document)
|
|
63
|
-
base.sorcery_config.after_config << :define_user_activation_mongo_mapper_fields
|
|
64
|
-
end
|
|
61
|
+
base.sorcery_config.after_config << :define_user_activation_fields
|
|
65
62
|
base.sorcery_config.before_authenticate << :prevent_non_active_login
|
|
66
|
-
|
|
63
|
+
|
|
67
64
|
base.extend(ClassMethods)
|
|
68
65
|
base.send(:include, InstanceMethods)
|
|
69
66
|
|
|
70
67
|
|
|
71
68
|
end
|
|
72
|
-
|
|
69
|
+
|
|
73
70
|
module ClassMethods
|
|
74
71
|
# Find user by token, also checks for expiration.
|
|
75
72
|
# Returns the user if token found and is valid.
|
|
@@ -78,9 +75,9 @@ module Sorcery
|
|
|
78
75
|
token_expiration_date_attr = @sorcery_config.activation_token_expires_at_attribute_name
|
|
79
76
|
load_from_token(token, token_attr_name, token_expiration_date_attr)
|
|
80
77
|
end
|
|
81
|
-
|
|
78
|
+
|
|
82
79
|
protected
|
|
83
|
-
|
|
80
|
+
|
|
84
81
|
# This submodule requires the developer to define his own mailer class to be used by it
|
|
85
82
|
# when activation_mailer_disabled is false
|
|
86
83
|
def validate_mailer_defined
|
|
@@ -88,42 +85,34 @@ module Sorcery
|
|
|
88
85
|
raise ArgumentError, msg if @sorcery_config.user_activation_mailer == nil and @sorcery_config.activation_mailer_disabled == false
|
|
89
86
|
end
|
|
90
87
|
|
|
91
|
-
def
|
|
92
|
-
self.class_eval do
|
|
93
|
-
field sorcery_config.activation_state_attribute_name, :type => String
|
|
94
|
-
field sorcery_config.activation_token_attribute_name, :type => String
|
|
95
|
-
field sorcery_config.activation_token_expires_at_attribute_name, :type => Time
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def define_user_activation_mongo_mapper_fields
|
|
88
|
+
def define_user_activation_fields
|
|
100
89
|
self.class_eval do
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
90
|
+
sorcery_adapter.define_field sorcery_config.activation_state_attribute_name, String
|
|
91
|
+
sorcery_adapter.define_field sorcery_config.activation_token_attribute_name, String
|
|
92
|
+
sorcery_adapter.define_field sorcery_config.activation_token_expires_at_attribute_name, Time
|
|
104
93
|
end
|
|
105
94
|
end
|
|
106
95
|
end
|
|
107
|
-
|
|
96
|
+
|
|
108
97
|
module InstanceMethods
|
|
98
|
+
def setup_activation
|
|
99
|
+
config = sorcery_config
|
|
100
|
+
generated_activation_token = TemporaryToken.generate_random_token
|
|
101
|
+
self.send(:"#{config.activation_token_attribute_name}=", generated_activation_token)
|
|
102
|
+
self.send(:"#{config.activation_state_attribute_name}=", "pending")
|
|
103
|
+
self.send(:"#{config.activation_token_expires_at_attribute_name}=", Time.now.in_time_zone + config.activation_token_expiration_period) if config.activation_token_expiration_period
|
|
104
|
+
end
|
|
105
|
+
|
|
109
106
|
# clears activation code, sets the user as 'active' and optionaly sends a success email.
|
|
110
107
|
def activate!
|
|
111
108
|
config = sorcery_config
|
|
112
109
|
self.send(:"#{config.activation_token_attribute_name}=", nil)
|
|
113
110
|
self.send(:"#{config.activation_state_attribute_name}=", "active")
|
|
114
111
|
send_activation_success_email! if send_activation_success_email?
|
|
115
|
-
save
|
|
112
|
+
sorcery_adapter.save(:validate => false, :raise_on_failure => true)
|
|
116
113
|
end
|
|
117
|
-
|
|
118
|
-
protected
|
|
119
114
|
|
|
120
|
-
|
|
121
|
-
config = sorcery_config
|
|
122
|
-
generated_activation_token = TemporaryToken.generate_random_token
|
|
123
|
-
self.send(:"#{config.activation_token_attribute_name}=", generated_activation_token)
|
|
124
|
-
self.send(:"#{config.activation_state_attribute_name}=", "pending")
|
|
125
|
-
self.send(:"#{config.activation_token_expires_at_attribute_name}=", Time.now.in_time_zone + config.activation_token_expiration_period) if config.activation_token_expiration_period
|
|
126
|
-
end
|
|
115
|
+
protected
|
|
127
116
|
|
|
128
117
|
# called automatically after user initial creation.
|
|
129
118
|
def send_activation_needed_email!
|
|
@@ -133,21 +122,21 @@ module Sorcery
|
|
|
133
122
|
def send_activation_success_email!
|
|
134
123
|
generic_send_email(:activation_success_email_method_name, :user_activation_mailer)
|
|
135
124
|
end
|
|
136
|
-
|
|
125
|
+
|
|
137
126
|
def send_activation_success_email?
|
|
138
127
|
!external? && (
|
|
139
128
|
!(sorcery_config.activation_success_email_method_name.nil? ||
|
|
140
129
|
sorcery_config.activation_mailer_disabled == true)
|
|
141
130
|
)
|
|
142
131
|
end
|
|
143
|
-
|
|
132
|
+
|
|
144
133
|
def send_activation_needed_email?
|
|
145
134
|
!external? && (
|
|
146
135
|
!(sorcery_config.activation_needed_email_method_name.nil? ||
|
|
147
136
|
sorcery_config.activation_mailer_disabled == true)
|
|
148
137
|
)
|
|
149
138
|
end
|
|
150
|
-
|
|
139
|
+
|
|
151
140
|
def prevent_non_active_login
|
|
152
141
|
config = sorcery_config
|
|
153
142
|
config.prevent_non_active_users_to_login ? self.send(config.activation_state_attribute_name) == "active" : true
|
|
@@ -157,4 +146,4 @@ module Sorcery
|
|
|
157
146
|
end
|
|
158
147
|
end
|
|
159
148
|
end
|
|
160
|
-
end
|
|
149
|
+
end
|
|
@@ -3,22 +3,22 @@ require 'securerandom'
|
|
|
3
3
|
module Sorcery
|
|
4
4
|
module Model
|
|
5
5
|
# This module encapsulates the logic for temporary token.
|
|
6
|
-
# A temporary token is created to identify a user in scenarios
|
|
6
|
+
# A temporary token is created to identify a user in scenarios
|
|
7
7
|
# such as reseting password and activating the user by email.
|
|
8
8
|
module TemporaryToken
|
|
9
9
|
def self.included(base)
|
|
10
10
|
base.extend(ClassMethods)
|
|
11
11
|
end
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
# Random code, used for salt and temporary tokens.
|
|
14
14
|
def self.generate_random_token
|
|
15
15
|
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
|
|
16
16
|
end
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
module ClassMethods
|
|
19
19
|
def load_from_token(token, token_attr_name, token_expiration_date_attr)
|
|
20
20
|
return nil if token.blank?
|
|
21
|
-
user =
|
|
21
|
+
user = sorcery_adapter.find_by_token(token_attr_name,token)
|
|
22
22
|
if !user.blank? && !user.send(token_expiration_date_attr).nil?
|
|
23
23
|
return Time.now.in_time_zone < user.send(token_expiration_date_attr) ? user : nil
|
|
24
24
|
end
|
data/lib/sorcery/model.rb
CHANGED
|
@@ -7,91 +7,70 @@ module Sorcery
|
|
|
7
7
|
# which when called adds the other capabilities to the class.
|
|
8
8
|
# This method is also the place to configure the plugin in the Model layer.
|
|
9
9
|
module Model
|
|
10
|
-
def
|
|
11
|
-
|
|
12
|
-
class << self
|
|
13
|
-
def authenticates_with_sorcery!
|
|
14
|
-
@sorcery_config = Config.new
|
|
15
|
-
self.class_eval do
|
|
16
|
-
extend ClassMethods # included here, before submodules, so they can be overriden by them.
|
|
17
|
-
include InstanceMethods
|
|
18
|
-
include TemporaryToken
|
|
19
|
-
end
|
|
10
|
+
def authenticates_with_sorcery!
|
|
11
|
+
@sorcery_config = Config.new
|
|
20
12
|
|
|
21
|
-
|
|
13
|
+
extend ClassMethods # included here, before submodules, so they can be overriden by them.
|
|
14
|
+
include InstanceMethods
|
|
15
|
+
include TemporaryToken
|
|
22
16
|
|
|
23
|
-
|
|
24
|
-
::Sorcery::Controller::Config.user_config.tap{|blk| blk.call(@sorcery_config) if blk}
|
|
17
|
+
include_required_submodules!
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
# This runs the options block set in the initializer on the model class.
|
|
20
|
+
::Sorcery::Controller::Config.user_config.tap{|blk| blk.call(@sorcery_config) if blk}
|
|
28
21
|
|
|
29
|
-
|
|
22
|
+
define_base_fields
|
|
23
|
+
init_orm_hooks!
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
@sorcery_config.after_config << :add_config_inheritance if @sorcery_config.subclasses_inherit_config
|
|
26
|
+
@sorcery_config.after_config.each { |c| send(c) }
|
|
27
|
+
end
|
|
34
28
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# includes required submodules into the model class,
|
|
38
|
-
# which usually is called User.
|
|
39
|
-
def include_required_submodules!
|
|
40
|
-
self.class_eval do
|
|
41
|
-
@sorcery_config.submodules = ::Sorcery::Controller::Config.submodules
|
|
42
|
-
@sorcery_config.submodules.each do |mod|
|
|
43
|
-
begin
|
|
44
|
-
include Submodules.const_get(mod.to_s.split("_").map {|p| p.capitalize}.join(""))
|
|
45
|
-
rescue NameError
|
|
46
|
-
# don't stop on a missing submodule. Needed because some submodules are only defined
|
|
47
|
-
# in the controller side.
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
29
|
+
private
|
|
52
30
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
end
|
|
31
|
+
def define_base_fields
|
|
32
|
+
self.class_eval do
|
|
33
|
+
sorcery_config.username_attribute_names.each do |username|
|
|
34
|
+
sorcery_adapter.define_field username, String, length: 255
|
|
35
|
+
end
|
|
36
|
+
unless sorcery_config.username_attribute_names.include?(sorcery_config.email_attribute_name)
|
|
37
|
+
sorcery_adapter.define_field sorcery_config.email_attribute_name, String, length: 255
|
|
38
|
+
end
|
|
39
|
+
sorcery_adapter.define_field sorcery_config.crypted_password_attribute_name, String, length: 255
|
|
40
|
+
sorcery_adapter.define_field sorcery_config.salt_attribute_name, String, length: 255
|
|
41
|
+
end
|
|
65
42
|
|
|
66
|
-
|
|
67
|
-
def init_mongo_mapper_support!
|
|
68
|
-
self.class_eval do
|
|
69
|
-
sorcery_config.username_attribute_names.each do |username|
|
|
70
|
-
key username, String
|
|
71
|
-
end
|
|
72
|
-
key sorcery_config.email_attribute_name, String unless sorcery_config.username_attribute_names.include?(sorcery_config.email_attribute_name)
|
|
73
|
-
key sorcery_config.crypted_password_attribute_name, String
|
|
74
|
-
key sorcery_config.salt_attribute_name, String
|
|
75
|
-
end
|
|
76
|
-
end
|
|
43
|
+
end
|
|
77
44
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
end
|
|
45
|
+
# includes required submodules into the model class,
|
|
46
|
+
# which usually is called User.
|
|
47
|
+
def include_required_submodules!
|
|
48
|
+
self.class_eval do
|
|
49
|
+
@sorcery_config.submodules = ::Sorcery::Controller::Config.submodules
|
|
50
|
+
@sorcery_config.submodules.each do |mod|
|
|
51
|
+
begin
|
|
52
|
+
include Submodules.const_get(mod.to_s.split('_').map {|p| p.capitalize}.join)
|
|
53
|
+
rescue NameError
|
|
54
|
+
# don't stop on a missing submodule. Needed because some submodules are only defined
|
|
55
|
+
# in the controller side.
|
|
90
56
|
end
|
|
91
57
|
end
|
|
92
58
|
end
|
|
93
59
|
end
|
|
94
60
|
|
|
61
|
+
# add virtual password accessor and ORM callbacks.
|
|
62
|
+
def init_orm_hooks!
|
|
63
|
+
sorcery_adapter.define_callback :before, :validation, :encrypt_password, if: Proc.new {|record|
|
|
64
|
+
record.send(sorcery_config.password_attribute_name).present?
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
sorcery_adapter.define_callback :after, :save, :clear_virtual_password, if: Proc.new {|record|
|
|
68
|
+
record.send(sorcery_config.password_attribute_name).present?
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
attr_accessor sorcery_config.password_attribute_name
|
|
72
|
+
end
|
|
73
|
+
|
|
95
74
|
module ClassMethods
|
|
96
75
|
# Returns the class instance variable for configuration, when called by the class itself.
|
|
97
76
|
def sorcery_config
|
|
@@ -111,12 +90,11 @@ module Sorcery
|
|
|
111
90
|
credentials[0].downcase!
|
|
112
91
|
end
|
|
113
92
|
|
|
114
|
-
user = find_by_credentials(credentials)
|
|
93
|
+
user = sorcery_adapter.find_by_credentials(credentials)
|
|
115
94
|
|
|
116
95
|
set_encryption_attributes
|
|
117
96
|
|
|
118
|
-
|
|
119
|
-
user if user && @sorcery_config.before_authenticate.all? {|c| user.send(c)} && credentials_match?(user.send(@sorcery_config.crypted_password_attribute_name),credentials[1],_salt)
|
|
97
|
+
user if user && @sorcery_config.before_authenticate.all? {|c| user.send(c)} && user.valid_password?(credentials[1])
|
|
120
98
|
end
|
|
121
99
|
|
|
122
100
|
# encrypt tokens using current encryption_provider.
|
|
@@ -135,13 +113,7 @@ module Sorcery
|
|
|
135
113
|
@sorcery_config.encryption_provider.stretches = @sorcery_config.stretches if @sorcery_config.encryption_provider.respond_to?(:stretches) && @sorcery_config.stretches
|
|
136
114
|
@sorcery_config.encryption_provider.join_token = @sorcery_config.salt_join_token if @sorcery_config.encryption_provider.respond_to?(:join_token) && @sorcery_config.salt_join_token
|
|
137
115
|
end
|
|
138
|
-
|
|
139
|
-
# Calls the configured encryption provider to compare the supplied password with the encrypted one.
|
|
140
|
-
def credentials_match?(crypted, *tokens)
|
|
141
|
-
return crypted == tokens.join if @sorcery_config.encryption_provider.nil?
|
|
142
|
-
@sorcery_config.encryption_provider.matches?(crypted, *tokens)
|
|
143
|
-
end
|
|
144
|
-
|
|
116
|
+
|
|
145
117
|
def add_config_inheritance
|
|
146
118
|
self.class_eval do
|
|
147
119
|
def self.inherited(subclass)
|
|
@@ -170,6 +142,16 @@ module Sorcery
|
|
|
170
142
|
send(sorcery_config.crypted_password_attribute_name).nil?
|
|
171
143
|
end
|
|
172
144
|
|
|
145
|
+
# Calls the configured encryption provider to compare the supplied password with the encrypted one.
|
|
146
|
+
def valid_password?(pass)
|
|
147
|
+
_crypted = self.send(sorcery_config.crypted_password_attribute_name)
|
|
148
|
+
return _crypted == pass if sorcery_config.encryption_provider.nil?
|
|
149
|
+
|
|
150
|
+
_salt = self.send(sorcery_config.salt_attribute_name) unless sorcery_config.salt_attribute_name.nil?
|
|
151
|
+
|
|
152
|
+
sorcery_config.encryption_provider.matches?(_crypted, pass, _salt)
|
|
153
|
+
end
|
|
154
|
+
|
|
173
155
|
protected
|
|
174
156
|
|
|
175
157
|
# creates new salt and saves it.
|
|
@@ -183,6 +165,10 @@ module Sorcery
|
|
|
183
165
|
def clear_virtual_password
|
|
184
166
|
config = sorcery_config
|
|
185
167
|
self.send(:"#{config.password_attribute_name}=", nil)
|
|
168
|
+
|
|
169
|
+
if respond_to?(:"#{config.password_attribute_name}_confirmation=")
|
|
170
|
+
self.send(:"#{config.password_attribute_name}_confirmation=", nil)
|
|
171
|
+
end
|
|
186
172
|
end
|
|
187
173
|
|
|
188
174
|
# calls the requested email method on the configured mailer
|
|
@@ -191,100 +177,14 @@ module Sorcery
|
|
|
191
177
|
config = sorcery_config
|
|
192
178
|
mail = config.send(mailer).send(config.send(method),self)
|
|
193
179
|
if defined?(ActionMailer) and config.send(mailer).kind_of?(Class) and config.send(mailer) < ActionMailer::Base
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
# Every submodule which gets loaded may add accessors to this class so that all
|
|
201
|
-
# options will be configured from a single place.
|
|
202
|
-
class Config
|
|
203
|
-
|
|
204
|
-
attr_accessor :username_attribute_names, # change default username attribute, for example, to use :email
|
|
205
|
-
# as the login.
|
|
206
|
-
|
|
207
|
-
:password_attribute_name, # change *virtual* password attribute, the one which is used
|
|
208
|
-
# until an encrypted one is generated.
|
|
209
|
-
|
|
210
|
-
:email_attribute_name, # change default email attribute.
|
|
211
|
-
|
|
212
|
-
:downcase_username_before_authenticating, # downcase the username before trying to authenticate, default is false
|
|
213
|
-
|
|
214
|
-
:crypted_password_attribute_name, # change default crypted_password attribute.
|
|
215
|
-
:salt_join_token, # what pattern to use to join the password with the salt
|
|
216
|
-
:salt_attribute_name, # change default salt attribute.
|
|
217
|
-
:stretches, # how many times to apply encryption to the password.
|
|
218
|
-
:encryption_key, # encryption key used to encrypt reversible encryptions such as
|
|
219
|
-
# AES256.
|
|
220
|
-
|
|
221
|
-
:subclasses_inherit_config, # make this configuration inheritable for subclasses. Useful for
|
|
222
|
-
# ActiveRecord's STI.
|
|
223
|
-
|
|
224
|
-
:submodules, # configured in config/application.rb
|
|
225
|
-
:before_authenticate, # an array of method names to call before authentication
|
|
226
|
-
# completes. used internally.
|
|
227
|
-
|
|
228
|
-
:after_config # an array of method names to call after configuration by user.
|
|
229
|
-
# used internally.
|
|
230
|
-
|
|
231
|
-
attr_reader :encryption_provider, # change default encryption_provider.
|
|
232
|
-
:custom_encryption_provider, # use an external encryption class.
|
|
233
|
-
:encryption_algorithm # encryption algorithm name. See 'encryption_algorithm=' below
|
|
234
|
-
# for available options.
|
|
235
|
-
|
|
236
|
-
def initialize
|
|
237
|
-
@defaults = {
|
|
238
|
-
:@submodules => [],
|
|
239
|
-
:@username_attribute_names => [:email],
|
|
240
|
-
:@password_attribute_name => :password,
|
|
241
|
-
:@downcase_username_before_authenticating => false,
|
|
242
|
-
:@email_attribute_name => :email,
|
|
243
|
-
:@crypted_password_attribute_name => :crypted_password,
|
|
244
|
-
:@encryption_algorithm => :bcrypt,
|
|
245
|
-
:@encryption_provider => CryptoProviders::BCrypt,
|
|
246
|
-
:@custom_encryption_provider => nil,
|
|
247
|
-
:@encryption_key => nil,
|
|
248
|
-
:@salt_join_token => "",
|
|
249
|
-
:@salt_attribute_name => :salt,
|
|
250
|
-
:@stretches => nil,
|
|
251
|
-
:@subclasses_inherit_config => false,
|
|
252
|
-
:@before_authenticate => [],
|
|
253
|
-
:@after_config => []
|
|
254
|
-
}
|
|
255
|
-
reset!
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
# Resets all configuration options to their default values.
|
|
259
|
-
def reset!
|
|
260
|
-
@defaults.each do |k,v|
|
|
261
|
-
instance_variable_set(k,v)
|
|
262
|
-
end
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
def username_attribute_names=(fields)
|
|
266
|
-
@username_attribute_names = fields.kind_of?(Array) ? fields : [fields]
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
def custom_encryption_provider=(provider)
|
|
270
|
-
@custom_encryption_provider = @encryption_provider = provider
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
def encryption_algorithm=(algo)
|
|
274
|
-
@encryption_algorithm = algo
|
|
275
|
-
@encryption_provider = case @encryption_algorithm.to_sym
|
|
276
|
-
when :none then nil
|
|
277
|
-
when :md5 then CryptoProviders::MD5
|
|
278
|
-
when :sha1 then CryptoProviders::SHA1
|
|
279
|
-
when :sha256 then CryptoProviders::SHA256
|
|
280
|
-
when :sha512 then CryptoProviders::SHA512
|
|
281
|
-
when :aes256 then CryptoProviders::AES256
|
|
282
|
-
when :bcrypt then CryptoProviders::BCrypt
|
|
283
|
-
when :custom then @custom_encryption_provider
|
|
284
|
-
else raise ArgumentError.new("Encryption algorithm supplied, #{algo}, is invalid")
|
|
180
|
+
# Rails 4.2 deprecates #deliver
|
|
181
|
+
if mail.respond_to?(:deliver_now)
|
|
182
|
+
mail.deliver_now
|
|
183
|
+
else
|
|
184
|
+
mail.deliver
|
|
185
|
+
end
|
|
285
186
|
end
|
|
286
187
|
end
|
|
287
|
-
|
|
288
188
|
end
|
|
289
189
|
|
|
290
190
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'oauth'
|
|
2
|
+
|
|
3
|
+
module Sorcery
|
|
4
|
+
module Protocols
|
|
5
|
+
module Oauth
|
|
6
|
+
|
|
7
|
+
def oauth_version
|
|
8
|
+
'1.0'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def get_request_token(token=nil,secret=nil)
|
|
12
|
+
return ::OAuth::RequestToken.new(get_consumer, token, secret) if token && secret
|
|
13
|
+
get_consumer.get_request_token(oauth_callback: @callback_url)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def authorize_url(args)
|
|
17
|
+
get_request_token(
|
|
18
|
+
args[:request_token],
|
|
19
|
+
args[:request_token_secret]
|
|
20
|
+
).authorize_url({
|
|
21
|
+
oauth_callback: @callback_url
|
|
22
|
+
})
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def get_access_token(args)
|
|
26
|
+
get_request_token(
|
|
27
|
+
args[:request_token],
|
|
28
|
+
args[:request_token_secret]
|
|
29
|
+
).get_access_token({
|
|
30
|
+
oauth_verifier: args[:oauth_verifier]
|
|
31
|
+
})
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
def get_consumer
|
|
37
|
+
::OAuth::Consumer.new(@key, @secret, site: @site)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'oauth2'
|
|
2
|
+
|
|
3
|
+
module Sorcery
|
|
4
|
+
module Protocols
|
|
5
|
+
module Oauth2
|
|
6
|
+
|
|
7
|
+
def oauth_version
|
|
8
|
+
'2.0'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def authorize_url(options = {})
|
|
12
|
+
client = build_client(options)
|
|
13
|
+
client.auth_code.authorize_url(
|
|
14
|
+
redirect_uri: @callback_url,
|
|
15
|
+
scope: @scope,
|
|
16
|
+
display: @display,
|
|
17
|
+
state: @state
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def get_access_token(args, options = {})
|
|
22
|
+
client = build_client(options)
|
|
23
|
+
client.auth_code.get_token(
|
|
24
|
+
args[:code],
|
|
25
|
+
{
|
|
26
|
+
redirect_uri: @callback_url,
|
|
27
|
+
parse: options.delete(:parse)
|
|
28
|
+
},
|
|
29
|
+
options
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def build_client(options = {})
|
|
34
|
+
defaults = {
|
|
35
|
+
site: @site,
|
|
36
|
+
ssl: { ca_file: Sorcery::Controller::Config.ca_file }
|
|
37
|
+
}
|
|
38
|
+
::OAuth2::Client.new(
|
|
39
|
+
@key,
|
|
40
|
+
@secret,
|
|
41
|
+
defaults.merge!(options)
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Sorcery
|
|
2
|
+
module Providers
|
|
3
|
+
class Base
|
|
4
|
+
|
|
5
|
+
attr_reader :access_token
|
|
6
|
+
|
|
7
|
+
attr_accessor :callback_url, :key, :original_callback_url, :secret,
|
|
8
|
+
:site, :state, :user_info_mapping
|
|
9
|
+
|
|
10
|
+
def has_callback?; true; end
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@user_info_mapping = {}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def auth_hash(access_token, hash={})
|
|
17
|
+
return hash if access_token.nil?
|
|
18
|
+
|
|
19
|
+
token_hash = hash.dup
|
|
20
|
+
token_hash[:token] = access_token.token if access_token.respond_to?(:token)
|
|
21
|
+
token_hash[:refresh_token] = access_token.refresh_token if access_token.respond_to?(:refresh_token)
|
|
22
|
+
token_hash[:expires_at] = access_token.expires_at if access_token.respond_to?(:expires_at)
|
|
23
|
+
token_hash[:expires_in] = access_token.expires_at if access_token.respond_to?(:expires_in)
|
|
24
|
+
token_hash
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.name
|
|
28
|
+
super.gsub(/Sorcery::Providers::/, '').downcase
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Ensure that all descendant classes are loaded before run this
|
|
32
|
+
def self.descendants
|
|
33
|
+
ObjectSpace.each_object(Class).select { |klass| klass < self }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|