sorcery 0.9.0 → 0.10.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/.travis.yml +29 -104
- data/CHANGELOG.md +22 -1
- data/Gemfile +2 -16
- data/README.md +124 -271
- 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 +29 -53
- 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 +3 -3
- 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/adapters/active_record_adapter.rb +7 -18
- 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 +23 -15
- 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/controller.rb +19 -21
- 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/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/model.rb +27 -31
- 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 +17 -9
- data/lib/sorcery/providers/github.rb +12 -5
- 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 +8 -11
- data/lib/sorcery/test_helpers/internal/rails.rb +16 -8
- data/lib/sorcery/test_helpers/internal.rb +10 -10
- 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/lib/sorcery.rb +0 -28
- 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 +142 -102
- 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/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/config.ru +1 -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 +226 -116
- data/spec/sorcery_crypto_providers_spec.rb +63 -76
- data/spec/spec_helper.rb +17 -13
- metadata +28 -82
- 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/spec/rails_app/log/development.log +0 -1791
|
@@ -8,33 +8,24 @@ module Sorcery
|
|
|
8
8
|
module UserActivation
|
|
9
9
|
def self.included(base)
|
|
10
10
|
base.sorcery_config.class_eval do
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
:activation_needed_email_method_name, # activation needed email method on your
|
|
31
|
-
# mailer class.
|
|
32
|
-
|
|
33
|
-
:activation_success_email_method_name, # activation success email method on your
|
|
34
|
-
# mailer class.
|
|
35
|
-
|
|
36
|
-
:prevent_non_active_users_to_login # do you want to prevent or allow users that
|
|
37
|
-
# did not activate by email to login?
|
|
11
|
+
# The attribute name to hold activation state (active/pending).
|
|
12
|
+
attr_accessor :activation_state_attribute_name
|
|
13
|
+
# The attribute name to hold activation code (sent by email).
|
|
14
|
+
attr_accessor :activation_token_attribute_name
|
|
15
|
+
# The attribute name to hold activation code expiration date.
|
|
16
|
+
attr_accessor :activation_token_expires_at_attribute_name
|
|
17
|
+
# How many seconds before the activation code expires. nil for never expires.
|
|
18
|
+
attr_accessor :activation_token_expiration_period
|
|
19
|
+
# Your mailer class. Required when activation_mailer_disabled == false.
|
|
20
|
+
attr_accessor :user_activation_mailer
|
|
21
|
+
# When true sorcery will not automatically email activation details and allow you to manually handle how and when email is sent
|
|
22
|
+
attr_accessor :activation_mailer_disabled
|
|
23
|
+
# Activation needed email method on your mailer class.
|
|
24
|
+
attr_accessor :activation_needed_email_method_name
|
|
25
|
+
# Activation success email method on your mailer class.
|
|
26
|
+
attr_accessor :activation_success_email_method_name
|
|
27
|
+
# Do you want to prevent or allow users that did not activate by email to login?
|
|
28
|
+
attr_accessor :prevent_non_active_users_to_login
|
|
38
29
|
end
|
|
39
30
|
|
|
40
31
|
base.sorcery_config.instance_eval do
|
|
@@ -52,9 +43,9 @@ module Sorcery
|
|
|
52
43
|
|
|
53
44
|
base.class_eval do
|
|
54
45
|
# don't setup activation if no password supplied - this user is created automatically
|
|
55
|
-
sorcery_adapter.define_callback :before, :create, :setup_activation, :
|
|
46
|
+
sorcery_adapter.define_callback :before, :create, :setup_activation, if: proc { |user| user.send(sorcery_config.password_attribute_name).present? }
|
|
56
47
|
# don't send activation needed email if no crypted password created - this user is external (OAuth etc.)
|
|
57
|
-
sorcery_adapter.define_callback :after, :create, :send_activation_needed_email!, :
|
|
48
|
+
sorcery_adapter.define_callback :after, :create, :send_activation_needed_email!, if: :send_activation_needed_email?
|
|
58
49
|
end
|
|
59
50
|
|
|
60
51
|
base.sorcery_config.after_config << :validate_mailer_defined
|
|
@@ -63,8 +54,6 @@ module Sorcery
|
|
|
63
54
|
|
|
64
55
|
base.extend(ClassMethods)
|
|
65
56
|
base.send(:include, InstanceMethods)
|
|
66
|
-
|
|
67
|
-
|
|
68
57
|
end
|
|
69
58
|
|
|
70
59
|
module ClassMethods
|
|
@@ -81,12 +70,12 @@ module Sorcery
|
|
|
81
70
|
# This submodule requires the developer to define his own mailer class to be used by it
|
|
82
71
|
# when activation_mailer_disabled is false
|
|
83
72
|
def validate_mailer_defined
|
|
84
|
-
|
|
85
|
-
raise ArgumentError,
|
|
73
|
+
message = 'To use user_activation submodule, you must define a mailer (config.user_activation_mailer = YourMailerClass).'
|
|
74
|
+
raise ArgumentError, message if @sorcery_config.user_activation_mailer.nil? && @sorcery_config.activation_mailer_disabled == false
|
|
86
75
|
end
|
|
87
76
|
|
|
88
77
|
def define_user_activation_fields
|
|
89
|
-
|
|
78
|
+
class_eval do
|
|
90
79
|
sorcery_adapter.define_field sorcery_config.activation_state_attribute_name, String
|
|
91
80
|
sorcery_adapter.define_field sorcery_config.activation_token_attribute_name, String
|
|
92
81
|
sorcery_adapter.define_field sorcery_config.activation_token_expires_at_attribute_name, Time
|
|
@@ -98,20 +87,22 @@ module Sorcery
|
|
|
98
87
|
def setup_activation
|
|
99
88
|
config = sorcery_config
|
|
100
89
|
generated_activation_token = TemporaryToken.generate_random_token
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
90
|
+
send(:"#{config.activation_token_attribute_name}=", generated_activation_token)
|
|
91
|
+
send(:"#{config.activation_state_attribute_name}=", 'pending')
|
|
92
|
+
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
93
|
end
|
|
105
94
|
|
|
106
95
|
# clears activation code, sets the user as 'active' and optionaly sends a success email.
|
|
107
96
|
def activate!
|
|
108
97
|
config = sorcery_config
|
|
109
|
-
|
|
110
|
-
|
|
98
|
+
send(:"#{config.activation_token_attribute_name}=", nil)
|
|
99
|
+
send(:"#{config.activation_state_attribute_name}=", 'active')
|
|
111
100
|
send_activation_success_email! if send_activation_success_email?
|
|
112
|
-
sorcery_adapter.save(:
|
|
101
|
+
sorcery_adapter.save(validate: false, raise_on_failure: true)
|
|
113
102
|
end
|
|
114
103
|
|
|
104
|
+
attr_accessor :skip_activation_needed_email, :skip_activation_success_email
|
|
105
|
+
|
|
115
106
|
protected
|
|
116
107
|
|
|
117
108
|
# called automatically after user initial creation.
|
|
@@ -124,24 +115,21 @@ module Sorcery
|
|
|
124
115
|
end
|
|
125
116
|
|
|
126
117
|
def send_activation_success_email?
|
|
127
|
-
!external? &&
|
|
128
|
-
!(sorcery_config.activation_success_email_method_name.nil? ||
|
|
129
|
-
|
|
130
|
-
)
|
|
118
|
+
!external? &&
|
|
119
|
+
!(sorcery_config.activation_success_email_method_name.nil? || sorcery_config.activation_mailer_disabled == true) &&
|
|
120
|
+
!skip_activation_success_email
|
|
131
121
|
end
|
|
132
122
|
|
|
133
123
|
def send_activation_needed_email?
|
|
134
|
-
!external? &&
|
|
135
|
-
!(sorcery_config.activation_needed_email_method_name.nil? ||
|
|
136
|
-
|
|
137
|
-
)
|
|
124
|
+
!external? &&
|
|
125
|
+
!(sorcery_config.activation_needed_email_method_name.nil? || sorcery_config.activation_mailer_disabled == true) &&
|
|
126
|
+
!skip_activation_needed_email
|
|
138
127
|
end
|
|
139
128
|
|
|
140
129
|
def prevent_non_active_login
|
|
141
130
|
config = sorcery_config
|
|
142
|
-
config.prevent_non_active_users_to_login ?
|
|
131
|
+
config.prevent_non_active_users_to_login ? send(config.activation_state_attribute_name) == 'active' : true
|
|
143
132
|
end
|
|
144
|
-
|
|
145
133
|
end
|
|
146
134
|
end
|
|
147
135
|
end
|
|
@@ -12,13 +12,13 @@ module Sorcery
|
|
|
12
12
|
|
|
13
13
|
# Random code, used for salt and temporary tokens.
|
|
14
14
|
def self.generate_random_token
|
|
15
|
-
SecureRandom.
|
|
15
|
+
SecureRandom.urlsafe_base64(15).tr('lIO0', 'sxyz')
|
|
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 = sorcery_adapter.find_by_token(token_attr_name,token)
|
|
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
|
@@ -17,7 +17,7 @@ module Sorcery
|
|
|
17
17
|
include_required_submodules!
|
|
18
18
|
|
|
19
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}
|
|
20
|
+
::Sorcery::Controller::Config.user_config.tap { |blk| blk.call(@sorcery_config) if blk }
|
|
21
21
|
|
|
22
22
|
define_base_fields
|
|
23
23
|
init_orm_hooks!
|
|
@@ -29,7 +29,7 @@ module Sorcery
|
|
|
29
29
|
private
|
|
30
30
|
|
|
31
31
|
def define_base_fields
|
|
32
|
-
|
|
32
|
+
class_eval do
|
|
33
33
|
sorcery_config.username_attribute_names.each do |username|
|
|
34
34
|
sorcery_adapter.define_field username, String, length: 255
|
|
35
35
|
end
|
|
@@ -39,17 +39,16 @@ module Sorcery
|
|
|
39
39
|
sorcery_adapter.define_field sorcery_config.crypted_password_attribute_name, String, length: 255
|
|
40
40
|
sorcery_adapter.define_field sorcery_config.salt_attribute_name, String, length: 255
|
|
41
41
|
end
|
|
42
|
-
|
|
43
42
|
end
|
|
44
43
|
|
|
45
44
|
# includes required submodules into the model class,
|
|
46
45
|
# which usually is called User.
|
|
47
46
|
def include_required_submodules!
|
|
48
|
-
|
|
47
|
+
class_eval do
|
|
49
48
|
@sorcery_config.submodules = ::Sorcery::Controller::Config.submodules
|
|
50
49
|
@sorcery_config.submodules.each do |mod|
|
|
51
50
|
begin
|
|
52
|
-
include Submodules.const_get(mod.to_s.split('_').map
|
|
51
|
+
include Submodules.const_get(mod.to_s.split('_').map(&:capitalize).join)
|
|
53
52
|
rescue NameError
|
|
54
53
|
# don't stop on a missing submodule. Needed because some submodules are only defined
|
|
55
54
|
# in the controller side.
|
|
@@ -60,11 +59,11 @@ module Sorcery
|
|
|
60
59
|
|
|
61
60
|
# add virtual password accessor and ORM callbacks.
|
|
62
61
|
def init_orm_hooks!
|
|
63
|
-
sorcery_adapter.define_callback :before, :validation, :encrypt_password, if:
|
|
62
|
+
sorcery_adapter.define_callback :before, :validation, :encrypt_password, if: proc { |record|
|
|
64
63
|
record.send(sorcery_config.password_attribute_name).present?
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
sorcery_adapter.define_callback :after, :save, :clear_virtual_password, if:
|
|
66
|
+
sorcery_adapter.define_callback :after, :save, :clear_virtual_password, if: proc { |record|
|
|
68
67
|
record.send(sorcery_config.password_attribute_name).present?
|
|
69
68
|
}
|
|
70
69
|
|
|
@@ -82,7 +81,7 @@ module Sorcery
|
|
|
82
81
|
# Finds the user by the username and compares the user's password to the one supplied to the method.
|
|
83
82
|
# returns the user if success, nil otherwise.
|
|
84
83
|
def authenticate(*credentials)
|
|
85
|
-
raise ArgumentError,
|
|
84
|
+
raise ArgumentError, 'at least 2 arguments required' if credentials.size < 2
|
|
86
85
|
|
|
87
86
|
return false if credentials[0].blank?
|
|
88
87
|
|
|
@@ -92,16 +91,20 @@ module Sorcery
|
|
|
92
91
|
|
|
93
92
|
user = sorcery_adapter.find_by_credentials(credentials)
|
|
94
93
|
|
|
94
|
+
if user.respond_to?(:active_for_authentication?)
|
|
95
|
+
return nil unless user.active_for_authentication?
|
|
96
|
+
end
|
|
97
|
+
|
|
95
98
|
set_encryption_attributes
|
|
96
99
|
|
|
97
|
-
user if user && @sorcery_config.before_authenticate.all? {|c| user.send(c)} && user.valid_password?(credentials[1])
|
|
100
|
+
user if user && @sorcery_config.before_authenticate.all? { |c| user.send(c) } && user.valid_password?(credentials[1])
|
|
98
101
|
end
|
|
99
102
|
|
|
100
103
|
# encrypt tokens using current encryption_provider.
|
|
101
104
|
def encrypt(*tokens)
|
|
102
105
|
return tokens.first if @sorcery_config.encryption_provider.nil?
|
|
103
106
|
|
|
104
|
-
set_encryption_attributes
|
|
107
|
+
set_encryption_attributes
|
|
105
108
|
|
|
106
109
|
CryptoProviders::AES256.key = @sorcery_config.encryption_key
|
|
107
110
|
@sorcery_config.encryption_provider.encrypt(*tokens)
|
|
@@ -109,13 +112,13 @@ module Sorcery
|
|
|
109
112
|
|
|
110
113
|
protected
|
|
111
114
|
|
|
112
|
-
def set_encryption_attributes
|
|
115
|
+
def set_encryption_attributes
|
|
113
116
|
@sorcery_config.encryption_provider.stretches = @sorcery_config.stretches if @sorcery_config.encryption_provider.respond_to?(:stretches) && @sorcery_config.stretches
|
|
114
117
|
@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
|
|
115
118
|
end
|
|
116
|
-
|
|
119
|
+
|
|
117
120
|
def add_config_inheritance
|
|
118
|
-
|
|
121
|
+
class_eval do
|
|
119
122
|
def self.inherited(subclass)
|
|
120
123
|
subclass.class_eval do
|
|
121
124
|
class << self
|
|
@@ -127,7 +130,6 @@ module Sorcery
|
|
|
127
130
|
end
|
|
128
131
|
end
|
|
129
132
|
end
|
|
130
|
-
|
|
131
133
|
end
|
|
132
134
|
|
|
133
135
|
module InstanceMethods
|
|
@@ -144,12 +146,12 @@ module Sorcery
|
|
|
144
146
|
|
|
145
147
|
# Calls the configured encryption provider to compare the supplied password with the encrypted one.
|
|
146
148
|
def valid_password?(pass)
|
|
147
|
-
|
|
148
|
-
return
|
|
149
|
+
crypted = send(sorcery_config.crypted_password_attribute_name)
|
|
150
|
+
return crypted == pass if sorcery_config.encryption_provider.nil?
|
|
149
151
|
|
|
150
|
-
|
|
152
|
+
salt = send(sorcery_config.salt_attribute_name) unless sorcery_config.salt_attribute_name.nil?
|
|
151
153
|
|
|
152
|
-
sorcery_config.encryption_provider.matches?(
|
|
154
|
+
sorcery_config.encryption_provider.matches?(crypted, pass, salt)
|
|
153
155
|
end
|
|
154
156
|
|
|
155
157
|
protected
|
|
@@ -158,16 +160,16 @@ module Sorcery
|
|
|
158
160
|
# encrypts password with salt and saves it.
|
|
159
161
|
def encrypt_password
|
|
160
162
|
config = sorcery_config
|
|
161
|
-
|
|
162
|
-
|
|
163
|
+
send(:"#{config.salt_attribute_name}=", new_salt = TemporaryToken.generate_random_token) unless config.salt_attribute_name.nil?
|
|
164
|
+
send(:"#{config.crypted_password_attribute_name}=", self.class.encrypt(send(config.password_attribute_name), new_salt))
|
|
163
165
|
end
|
|
164
166
|
|
|
165
167
|
def clear_virtual_password
|
|
166
168
|
config = sorcery_config
|
|
167
|
-
|
|
169
|
+
send(:"#{config.password_attribute_name}=", nil)
|
|
168
170
|
|
|
169
171
|
if respond_to?(:"#{config.password_attribute_name}_confirmation=")
|
|
170
|
-
|
|
172
|
+
send(:"#{config.password_attribute_name}_confirmation=", nil)
|
|
171
173
|
end
|
|
172
174
|
end
|
|
173
175
|
|
|
@@ -175,17 +177,11 @@ module Sorcery
|
|
|
175
177
|
# supports both the ActionMailer 3 way of calling, and the plain old Ruby object way.
|
|
176
178
|
def generic_send_email(method, mailer)
|
|
177
179
|
config = sorcery_config
|
|
178
|
-
mail = config.send(mailer).send(config.send(method),self)
|
|
179
|
-
if defined?(ActionMailer)
|
|
180
|
-
|
|
181
|
-
if mail.respond_to?(:deliver_now)
|
|
182
|
-
mail.deliver_now
|
|
183
|
-
else
|
|
184
|
-
mail.deliver
|
|
185
|
-
end
|
|
180
|
+
mail = config.send(mailer).send(config.send(method), self)
|
|
181
|
+
if defined?(ActionMailer) && config.send(mailer).is_a?(Class) && config.send(mailer) < ActionMailer::Base
|
|
182
|
+
mail.send(config.email_delivery_method)
|
|
186
183
|
end
|
|
187
184
|
end
|
|
188
185
|
end
|
|
189
|
-
|
|
190
186
|
end
|
|
191
187
|
end
|
|
@@ -3,12 +3,11 @@ require 'oauth'
|
|
|
3
3
|
module Sorcery
|
|
4
4
|
module Protocols
|
|
5
5
|
module Oauth
|
|
6
|
-
|
|
7
6
|
def oauth_version
|
|
8
7
|
'1.0'
|
|
9
8
|
end
|
|
10
9
|
|
|
11
|
-
def get_request_token(token=nil,secret=nil)
|
|
10
|
+
def get_request_token(token = nil, secret = nil)
|
|
12
11
|
return ::OAuth::RequestToken.new(get_consumer, token, secret) if token && secret
|
|
13
12
|
get_consumer.get_request_token(oauth_callback: @callback_url)
|
|
14
13
|
end
|
|
@@ -17,18 +16,14 @@ module Sorcery
|
|
|
17
16
|
get_request_token(
|
|
18
17
|
args[:request_token],
|
|
19
18
|
args[:request_token_secret]
|
|
20
|
-
).authorize_url(
|
|
21
|
-
oauth_callback: @callback_url
|
|
22
|
-
})
|
|
19
|
+
).authorize_url(oauth_callback: @callback_url)
|
|
23
20
|
end
|
|
24
21
|
|
|
25
22
|
def get_access_token(args)
|
|
26
23
|
get_request_token(
|
|
27
24
|
args[:request_token],
|
|
28
25
|
args[:request_token_secret]
|
|
29
|
-
).get_access_token(
|
|
30
|
-
oauth_verifier: args[:oauth_verifier]
|
|
31
|
-
})
|
|
26
|
+
).get_access_token(oauth_verifier: args[:oauth_verifier])
|
|
32
27
|
end
|
|
33
28
|
|
|
34
29
|
protected
|
|
@@ -36,7 +31,6 @@ module Sorcery
|
|
|
36
31
|
def get_consumer
|
|
37
32
|
::OAuth::Consumer.new(@key, @secret, site: @site)
|
|
38
33
|
end
|
|
39
|
-
|
|
40
34
|
end
|
|
41
35
|
end
|
|
42
36
|
end
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
module Sorcery
|
|
2
2
|
module Providers
|
|
3
3
|
class Base
|
|
4
|
-
|
|
5
4
|
attr_reader :access_token
|
|
6
5
|
|
|
7
6
|
attr_accessor :callback_url, :key, :original_callback_url, :secret,
|
|
8
7
|
:site, :state, :user_info_mapping
|
|
9
8
|
|
|
10
|
-
def has_callback
|
|
9
|
+
def has_callback?
|
|
10
|
+
true
|
|
11
|
+
end
|
|
11
12
|
|
|
12
13
|
def initialize
|
|
13
14
|
@user_info_mapping = {}
|
|
14
15
|
end
|
|
15
16
|
|
|
16
|
-
def auth_hash(access_token, hash={})
|
|
17
|
+
def auth_hash(access_token, hash = {})
|
|
17
18
|
return hash if access_token.nil?
|
|
18
19
|
|
|
19
20
|
token_hash = hash.dup
|
|
@@ -32,7 +33,6 @@ module Sorcery
|
|
|
32
33
|
def self.descendants
|
|
33
34
|
ObjectSpace.each_object(Class).select { |klass| klass < self }
|
|
34
35
|
end
|
|
35
|
-
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
end
|
|
@@ -7,21 +7,22 @@ module Sorcery
|
|
|
7
7
|
# ...
|
|
8
8
|
#
|
|
9
9
|
class Facebook < Base
|
|
10
|
-
|
|
11
10
|
include Protocols::Oauth2
|
|
12
11
|
|
|
13
12
|
attr_reader :mode, :param_name, :parse
|
|
14
13
|
attr_accessor :access_permissions, :display, :scope, :token_url,
|
|
15
|
-
:user_info_path
|
|
14
|
+
:user_info_path, :auth_path, :api_version
|
|
16
15
|
|
|
17
16
|
def initialize
|
|
18
17
|
super
|
|
19
18
|
|
|
20
19
|
@site = 'https://graph.facebook.com'
|
|
21
|
-
@
|
|
22
|
-
@
|
|
20
|
+
@auth_site = 'https://www.facebook.com'
|
|
21
|
+
@user_info_path = 'me'
|
|
22
|
+
@scope = 'email'
|
|
23
23
|
@display = 'page'
|
|
24
24
|
@token_url = 'oauth/access_token'
|
|
25
|
+
@auth_path = 'dialog/oauth'
|
|
25
26
|
@mode = :query
|
|
26
27
|
@parse = :query
|
|
27
28
|
@param_name = 'access_token'
|
|
@@ -38,26 +39,33 @@ module Sorcery
|
|
|
38
39
|
|
|
39
40
|
# calculates and returns the url to which the user should be redirected,
|
|
40
41
|
# to get authenticated at the external provider's site.
|
|
41
|
-
def login_url(
|
|
42
|
+
def login_url(_params, _session)
|
|
42
43
|
authorize_url
|
|
43
44
|
end
|
|
44
45
|
|
|
45
46
|
# overrides oauth2#authorize_url to allow customized scope.
|
|
46
47
|
def authorize_url
|
|
48
|
+
# Fix: replace default oauth2 options, specially to prevent the Faraday gem which
|
|
49
|
+
# concatenates with "/", removing the Facebook api version
|
|
50
|
+
options = {
|
|
51
|
+
site: File.join(@site, api_version.to_s),
|
|
52
|
+
authorize_url: File.join(@auth_site, api_version.to_s, auth_path),
|
|
53
|
+
token_url: token_url
|
|
54
|
+
}
|
|
55
|
+
|
|
47
56
|
@scope = access_permissions.present? ? access_permissions.join(',') : scope
|
|
48
|
-
super
|
|
57
|
+
super(options)
|
|
49
58
|
end
|
|
50
59
|
|
|
51
60
|
# tries to login the user from access token
|
|
52
|
-
def process_callback(params,
|
|
61
|
+
def process_callback(params, _session)
|
|
53
62
|
args = {}.tap do |a|
|
|
54
63
|
a[:code] = params[:code] if params[:code]
|
|
55
64
|
end
|
|
56
65
|
|
|
57
66
|
get_access_token(args, token_url: token_url, mode: mode,
|
|
58
|
-
|
|
67
|
+
param_name: param_name, parse: parse)
|
|
59
68
|
end
|
|
60
|
-
|
|
61
69
|
end
|
|
62
70
|
end
|
|
63
71
|
end
|
|
@@ -7,7 +7,6 @@ module Sorcery
|
|
|
7
7
|
# ...
|
|
8
8
|
#
|
|
9
9
|
class Github < Base
|
|
10
|
-
|
|
11
10
|
include Protocols::Oauth2
|
|
12
11
|
|
|
13
12
|
attr_accessor :auth_path, :scope, :token_url, :user_info_path
|
|
@@ -26,19 +25,21 @@ module Sorcery
|
|
|
26
25
|
response = access_token.get(user_info_path)
|
|
27
26
|
|
|
28
27
|
auth_hash(access_token).tap do |h|
|
|
29
|
-
h[:user_info] = JSON.parse(response.body)
|
|
28
|
+
h[:user_info] = JSON.parse(response.body).tap do |uih|
|
|
29
|
+
uih['email'] = primary_email(access_token) if scope =~ /user/
|
|
30
|
+
end
|
|
30
31
|
h[:uid] = h[:user_info]['id']
|
|
31
32
|
end
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
# calculates and returns the url to which the user should be redirected,
|
|
35
36
|
# to get authenticated at the external provider's site.
|
|
36
|
-
def login_url(
|
|
37
|
-
authorize_url(
|
|
37
|
+
def login_url(_params, _session)
|
|
38
|
+
authorize_url(authorize_url: auth_path)
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
# tries to login the user from access token
|
|
41
|
-
def process_callback(params,
|
|
42
|
+
def process_callback(params, _session)
|
|
42
43
|
args = {}.tap do |a|
|
|
43
44
|
a[:code] = params[:code] if params[:code]
|
|
44
45
|
end
|
|
@@ -46,6 +47,12 @@ module Sorcery
|
|
|
46
47
|
get_access_token(args, token_url: token_url, token_method: :post)
|
|
47
48
|
end
|
|
48
49
|
|
|
50
|
+
def primary_email(access_token)
|
|
51
|
+
response = access_token.get(user_info_path + '/emails')
|
|
52
|
+
emails = JSON.parse(response.body)
|
|
53
|
+
primary = emails.find { |i| i['primary'] }
|
|
54
|
+
primary && primary['email'] || emails.first && emails.first['email']
|
|
55
|
+
end
|
|
49
56
|
end
|
|
50
57
|
end
|
|
51
58
|
end
|
|
@@ -7,7 +7,6 @@ module Sorcery
|
|
|
7
7
|
# ...
|
|
8
8
|
#
|
|
9
9
|
class Google < Base
|
|
10
|
-
|
|
11
10
|
include Protocols::Oauth2
|
|
12
11
|
|
|
13
12
|
attr_accessor :auth_url, :scope, :token_url, :user_info_url
|
|
@@ -33,19 +32,18 @@ module Sorcery
|
|
|
33
32
|
|
|
34
33
|
# calculates and returns the url to which the user should be redirected,
|
|
35
34
|
# to get authenticated at the external provider's site.
|
|
36
|
-
def login_url(
|
|
37
|
-
authorize_url(
|
|
35
|
+
def login_url(_params, _session)
|
|
36
|
+
authorize_url(authorize_url: auth_url)
|
|
38
37
|
end
|
|
39
38
|
|
|
40
39
|
# tries to login the user from access token
|
|
41
|
-
def process_callback(params,
|
|
40
|
+
def process_callback(params, _session)
|
|
42
41
|
args = {}.tap do |a|
|
|
43
42
|
a[:code] = params[:code] if params[:code]
|
|
44
43
|
end
|
|
45
44
|
|
|
46
45
|
get_access_token(args, token_url: token_url, token_method: :post)
|
|
47
46
|
end
|
|
48
|
-
|
|
49
47
|
end
|
|
50
48
|
end
|
|
51
49
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
module Sorcery
|
|
2
2
|
module Providers
|
|
3
|
-
|
|
4
3
|
# This class adds support for OAuth with heroku.com.
|
|
5
4
|
|
|
6
5
|
# config.heroku.key = <key>
|
|
@@ -13,7 +12,6 @@ module Sorcery
|
|
|
13
12
|
# The full path must be set for OAuth Callback URL when configuring the API Client Information on Heroku.
|
|
14
13
|
|
|
15
14
|
class Heroku < Base
|
|
16
|
-
|
|
17
15
|
include Protocols::Oauth2
|
|
18
16
|
|
|
19
17
|
attr_accessor :auth_path, :scope, :token_url, :user_info_path
|
|
@@ -40,18 +38,18 @@ module Sorcery
|
|
|
40
38
|
end
|
|
41
39
|
end
|
|
42
40
|
|
|
43
|
-
def login_url(
|
|
44
|
-
authorize_url(
|
|
41
|
+
def login_url(_params, _session)
|
|
42
|
+
authorize_url(authorize_url: auth_path)
|
|
45
43
|
end
|
|
46
44
|
|
|
47
45
|
# tries to login the user from access token
|
|
48
|
-
def process_callback(params,
|
|
49
|
-
raise
|
|
50
|
-
args = {
|
|
46
|
+
def process_callback(params, _session)
|
|
47
|
+
raise 'Invalid state. Potential Cross Site Forgery' if params[:state] != state
|
|
48
|
+
args = {}.tap do |a|
|
|
51
49
|
a[:code] = params[:code] if params[:code]
|
|
52
50
|
end
|
|
53
51
|
get_access_token(args, token_url: token_url, token_method: :post)
|
|
54
52
|
end
|
|
55
53
|
end
|
|
56
54
|
end
|
|
57
|
-
end
|
|
55
|
+
end
|