sorcery 0.8.6 → 0.9.1
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 +2 -1
- data/.travis.yml +75 -14
- data/CHANGELOG.md +32 -1
- data/Gemfile +1 -0
- data/README.md +138 -86
- data/gemfiles/active_record-rails40.gemfile +7 -0
- data/gemfiles/active_record-rails41.gemfile +3 -2
- data/gemfiles/mongo_mapper-rails40.gemfile +9 -0
- data/gemfiles/mongo_mapper-rails41.gemfile +2 -1
- data/gemfiles/mongoid-rails40.gemfile +9 -0
- data/gemfiles/mongoid-rails41.gemfile +3 -5
- 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 +36 -10
- 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 +9 -29
- 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 +5 -64
- data/lib/sorcery/model/config.rb +96 -0
- data/lib/sorcery/model/submodules/activity_logging.rb +29 -36
- data/lib/sorcery/model/submodules/brute_force_protection.rb +21 -37
- data/lib/sorcery/model/submodules/external.rb +53 -9
- data/lib/sorcery/model/submodules/remember_me.rb +12 -31
- data/lib/sorcery/model/submodules/reset_password.rb +21 -39
- data/lib/sorcery/model/submodules/user_activation.rb +21 -63
- data/lib/sorcery/model/temporary_token.rb +4 -4
- data/lib/sorcery/model.rb +47 -175
- data/lib/sorcery/providers/base.rb +11 -0
- data/lib/sorcery/providers/facebook.rb +16 -5
- data/lib/sorcery/providers/github.rb +11 -2
- data/lib/sorcery/providers/google.rb +1 -1
- data/lib/sorcery/providers/heroku.rb +57 -0
- data/lib/sorcery/providers/jira.rb +77 -0
- data/lib/sorcery/providers/linkedin.rb +1 -1
- data/lib/sorcery/providers/liveid.rb +1 -1
- data/lib/sorcery/providers/salesforce.rb +50 -0
- data/lib/sorcery/providers/twitter.rb +1 -1
- data/lib/sorcery/providers/vk.rb +6 -4
- data/lib/sorcery/providers/xing.rb +2 -2
- data/lib/sorcery/test_helpers/internal.rb +7 -3
- data/lib/sorcery/test_helpers/rails/controller.rb +5 -1
- data/lib/sorcery/version.rb +3 -0
- data/lib/sorcery.rb +75 -43
- data/sorcery.gemspec +6 -2
- data/spec/active_record/user_activity_logging_spec.rb +9 -0
- data/spec/controllers/controller_activity_logging_spec.rb +124 -0
- data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
- data/spec/{active_record → controllers}/controller_http_basic_auth_spec.rb +14 -11
- data/spec/{active_record → controllers}/controller_oauth2_spec.rb +151 -64
- data/spec/{active_record → controllers}/controller_oauth_spec.rb +94 -70
- data/spec/{active_record → controllers}/controller_remember_me_spec.rb +32 -12
- data/spec/{active_record → controllers}/controller_session_timeout_spec.rb +15 -5
- data/spec/{shared_examples/controller_shared_examples.rb → controllers/controller_spec.rb} +34 -19
- data/spec/{datamapper → data_mapper}/user_activation_spec.rb +1 -1
- data/spec/data_mapper/user_activity_logging_spec.rb +14 -0
- data/spec/{datamapper → data_mapper}/user_brute_force_protection_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_oauth_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_remember_me_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_reset_password_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_spec.rb +1 -1
- data/spec/mongoid/user_spec.rb +13 -0
- data/spec/orm/active_record.rb +12 -0
- data/spec/orm/{datamapper.rb → data_mapper.rb} +16 -2
- data/spec/orm/mongo_mapper.rb +0 -1
- data/spec/orm/mongoid.rb +4 -0
- data/spec/rails_app/app/controllers/sorcery_controller.rb +62 -1
- data/spec/rails_app/app/mongo_mapper/user.rb +2 -0
- data/spec/rails_app/config/routes.rb +9 -0
- data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +2 -2
- data/spec/shared_examples/user_activation_shared_examples.rb +7 -7
- data/spec/shared_examples/user_activity_logging_shared_examples.rb +73 -5
- data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +127 -9
- data/spec/shared_examples/user_oauth_shared_examples.rb +3 -6
- data/spec/shared_examples/user_remember_me_shared_examples.rb +6 -3
- data/spec/shared_examples/user_reset_password_shared_examples.rb +10 -10
- data/spec/shared_examples/user_shared_examples.rb +146 -46
- data/spec/spec_helper.rb +7 -22
- metadata +36 -57
- data/Gemfile.rails4 +0 -22
- data/VERSION +0 -1
- data/lib/sorcery/model/adapters/active_record.rb +0 -54
- data/lib/sorcery/model/adapters/datamapper.rb +0 -123
- data/lib/sorcery/model/adapters/mongo_mapper.rb +0 -60
- data/lib/sorcery/model/adapters/mongoid.rb +0 -88
- data/lib/sorcery/test_helpers/rails.rb +0 -7
- data/spec/active_record/controller_activity_logging_spec.rb +0 -29
- data/spec/active_record/controller_brute_force_protection_spec.rb +0 -158
- data/spec/active_record/controller_spec.rb +0 -8
- data/spec/active_record/integration_spec.rb +0 -23
- data/spec/datamapper/controller_activity_logging_spec.rb +0 -17
- data/spec/datamapper/controller_spec.rb +0 -8
- data/spec/datamapper/user_activity_logging_spec.rb +0 -9
- data/spec/mongo_mapper/controller_spec.rb +0 -8
- data/spec/mongoid/controller_activity_logging_spec.rb +0 -16
- data/spec/mongoid/controller_spec.rb +0 -8
- 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_activity_logging_shared_examples.rb +0 -125
- data/spec/shared_examples/controller_oauth2_shared_examples.rb +0 -52
- data/spec/shared_examples/controller_oauth_shared_examples.rb +0 -62
- /data/spec/rails_app/app/{datamapper → data_mapper}/authentication.rb +0 -0
- /data/spec/rails_app/app/{datamapper → data_mapper}/user.rb +0 -0
data/lib/sorcery/model.rb
CHANGED
|
@@ -19,17 +19,28 @@ module Sorcery
|
|
|
19
19
|
# This runs the options block set in the initializer on the model class.
|
|
20
20
|
::Sorcery::Controller::Config.user_config.tap{|blk| blk.call(@sorcery_config) if blk}
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
init_mongo_mapper_support! if defined?(MongoMapper) and self.ancestors.include?(MongoMapper::Document)
|
|
24
|
-
init_datamapper_support! if defined?(DataMapper) and self.ancestors.include?(DataMapper::Resource)
|
|
25
|
-
|
|
22
|
+
define_base_fields
|
|
26
23
|
init_orm_hooks!
|
|
27
24
|
|
|
28
25
|
@sorcery_config.after_config << :add_config_inheritance if @sorcery_config.subclasses_inherit_config
|
|
29
26
|
@sorcery_config.after_config.each { |c| send(c) }
|
|
30
27
|
end
|
|
31
28
|
|
|
32
|
-
|
|
29
|
+
private
|
|
30
|
+
|
|
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
|
|
42
|
+
|
|
43
|
+
end
|
|
33
44
|
|
|
34
45
|
# includes required submodules into the model class,
|
|
35
46
|
# which usually is called User.
|
|
@@ -47,77 +58,17 @@ module Sorcery
|
|
|
47
58
|
end
|
|
48
59
|
end
|
|
49
60
|
|
|
50
|
-
# defines mongoid fields on the model class,
|
|
51
|
-
# using 1.8.x hash syntax to perserve compatibility.
|
|
52
|
-
def init_mongoid_support!
|
|
53
|
-
self.class_eval do
|
|
54
|
-
sorcery_config.username_attribute_names.each do |username|
|
|
55
|
-
field username, :type => String
|
|
56
|
-
end
|
|
57
|
-
field sorcery_config.email_attribute_name, :type => String unless sorcery_config.username_attribute_names.include?(sorcery_config.email_attribute_name)
|
|
58
|
-
field sorcery_config.crypted_password_attribute_name, :type => String
|
|
59
|
-
field sorcery_config.salt_attribute_name, :type => String
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# defines mongo_mapper fields on the model class,
|
|
64
|
-
def init_mongo_mapper_support!
|
|
65
|
-
self.class_eval do
|
|
66
|
-
sorcery_config.username_attribute_names.each do |username|
|
|
67
|
-
key username, String
|
|
68
|
-
end
|
|
69
|
-
key sorcery_config.email_attribute_name, String unless sorcery_config.username_attribute_names.include?(sorcery_config.email_attribute_name)
|
|
70
|
-
key sorcery_config.crypted_password_attribute_name, String
|
|
71
|
-
key sorcery_config.salt_attribute_name, String
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# defines datamapper fields on the model class
|
|
76
|
-
def init_datamapper_support!
|
|
77
|
-
self.class_eval do
|
|
78
|
-
sorcery_config.username_attribute_names.each do |username|
|
|
79
|
-
property username, String, :length => 255
|
|
80
|
-
end
|
|
81
|
-
unless sorcery_config.username_attribute_names.include?(sorcery_config.email_attribute_name)
|
|
82
|
-
property sorcery_config.email_attribute_name, String, :length => 255
|
|
83
|
-
end
|
|
84
|
-
property sorcery_config.crypted_password_attribute_name, String, :length => 255
|
|
85
|
-
property sorcery_config.salt_attribute_name, String, :length => 255
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
61
|
# add virtual password accessor and ORM callbacks.
|
|
90
62
|
def init_orm_hooks!
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
end
|
|
95
|
-
self.class_eval do
|
|
96
|
-
attr_accessor @sorcery_config.password_attribute_name
|
|
97
|
-
#attr_protected @sorcery_config.crypted_password_attribute_name, @sorcery_config.salt_attribute_name
|
|
98
|
-
before_save :encrypt_password, :if => Proc.new { |record|
|
|
99
|
-
record.send(sorcery_config.password_attribute_name).present?
|
|
100
|
-
}
|
|
101
|
-
after_save :clear_virtual_password, :if => Proc.new { |record|
|
|
102
|
-
record.send(sorcery_config.password_attribute_name).present?
|
|
103
|
-
}
|
|
104
|
-
end
|
|
105
|
-
end
|
|
63
|
+
sorcery_adapter.define_callback :before, :validation, :encrypt_password, if: Proc.new {|record|
|
|
64
|
+
record.send(sorcery_config.password_attribute_name).present?
|
|
65
|
+
}
|
|
106
66
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
encrypt_password
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
after :save do
|
|
116
|
-
if self.send(sorcery_config.password_attribute_name).present?
|
|
117
|
-
clear_virtual_password
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|
|
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
|
|
121
72
|
end
|
|
122
73
|
|
|
123
74
|
module ClassMethods
|
|
@@ -139,12 +90,15 @@ module Sorcery
|
|
|
139
90
|
credentials[0].downcase!
|
|
140
91
|
end
|
|
141
92
|
|
|
142
|
-
user = find_by_credentials(credentials)
|
|
93
|
+
user = sorcery_adapter.find_by_credentials(credentials)
|
|
94
|
+
|
|
95
|
+
if user.respond_to?(:active_for_authentication?)
|
|
96
|
+
return nil if !user.active_for_authentication?
|
|
97
|
+
end
|
|
143
98
|
|
|
144
99
|
set_encryption_attributes
|
|
145
100
|
|
|
146
|
-
|
|
147
|
-
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)
|
|
101
|
+
user if user && @sorcery_config.before_authenticate.all? {|c| user.send(c)} && user.valid_password?(credentials[1])
|
|
148
102
|
end
|
|
149
103
|
|
|
150
104
|
# encrypt tokens using current encryption_provider.
|
|
@@ -163,13 +117,7 @@ module Sorcery
|
|
|
163
117
|
@sorcery_config.encryption_provider.stretches = @sorcery_config.stretches if @sorcery_config.encryption_provider.respond_to?(:stretches) && @sorcery_config.stretches
|
|
164
118
|
@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
|
|
165
119
|
end
|
|
166
|
-
|
|
167
|
-
# Calls the configured encryption provider to compare the supplied password with the encrypted one.
|
|
168
|
-
def credentials_match?(crypted, *tokens)
|
|
169
|
-
return crypted == tokens.join if @sorcery_config.encryption_provider.nil?
|
|
170
|
-
@sorcery_config.encryption_provider.matches?(crypted, *tokens)
|
|
171
|
-
end
|
|
172
|
-
|
|
120
|
+
|
|
173
121
|
def add_config_inheritance
|
|
174
122
|
self.class_eval do
|
|
175
123
|
def self.inherited(subclass)
|
|
@@ -198,6 +146,16 @@ module Sorcery
|
|
|
198
146
|
send(sorcery_config.crypted_password_attribute_name).nil?
|
|
199
147
|
end
|
|
200
148
|
|
|
149
|
+
# Calls the configured encryption provider to compare the supplied password with the encrypted one.
|
|
150
|
+
def valid_password?(pass)
|
|
151
|
+
_crypted = self.send(sorcery_config.crypted_password_attribute_name)
|
|
152
|
+
return _crypted == pass if sorcery_config.encryption_provider.nil?
|
|
153
|
+
|
|
154
|
+
_salt = self.send(sorcery_config.salt_attribute_name) unless sorcery_config.salt_attribute_name.nil?
|
|
155
|
+
|
|
156
|
+
sorcery_config.encryption_provider.matches?(_crypted, pass, _salt)
|
|
157
|
+
end
|
|
158
|
+
|
|
201
159
|
protected
|
|
202
160
|
|
|
203
161
|
# creates new salt and saves it.
|
|
@@ -223,100 +181,14 @@ module Sorcery
|
|
|
223
181
|
config = sorcery_config
|
|
224
182
|
mail = config.send(mailer).send(config.send(method),self)
|
|
225
183
|
if defined?(ActionMailer) and config.send(mailer).kind_of?(Class) and config.send(mailer) < ActionMailer::Base
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
# Every submodule which gets loaded may add accessors to this class so that all
|
|
233
|
-
# options will be configured from a single place.
|
|
234
|
-
class Config
|
|
235
|
-
|
|
236
|
-
attr_accessor :username_attribute_names, # change default username attribute, for example, to use :email
|
|
237
|
-
# as the login.
|
|
238
|
-
|
|
239
|
-
:password_attribute_name, # change *virtual* password attribute, the one which is used
|
|
240
|
-
# until an encrypted one is generated.
|
|
241
|
-
|
|
242
|
-
:email_attribute_name, # change default email attribute.
|
|
243
|
-
|
|
244
|
-
:downcase_username_before_authenticating, # downcase the username before trying to authenticate, default is false
|
|
245
|
-
|
|
246
|
-
:crypted_password_attribute_name, # change default crypted_password attribute.
|
|
247
|
-
:salt_join_token, # what pattern to use to join the password with the salt
|
|
248
|
-
:salt_attribute_name, # change default salt attribute.
|
|
249
|
-
:stretches, # how many times to apply encryption to the password.
|
|
250
|
-
:encryption_key, # encryption key used to encrypt reversible encryptions such as
|
|
251
|
-
# AES256.
|
|
252
|
-
|
|
253
|
-
:subclasses_inherit_config, # make this configuration inheritable for subclasses. Useful for
|
|
254
|
-
# ActiveRecord's STI.
|
|
255
|
-
|
|
256
|
-
:submodules, # configured in config/application.rb
|
|
257
|
-
:before_authenticate, # an array of method names to call before authentication
|
|
258
|
-
# completes. used internally.
|
|
259
|
-
|
|
260
|
-
:after_config # an array of method names to call after configuration by user.
|
|
261
|
-
# used internally.
|
|
262
|
-
|
|
263
|
-
attr_reader :encryption_provider, # change default encryption_provider.
|
|
264
|
-
:custom_encryption_provider, # use an external encryption class.
|
|
265
|
-
:encryption_algorithm # encryption algorithm name. See 'encryption_algorithm=' below
|
|
266
|
-
# for available options.
|
|
267
|
-
|
|
268
|
-
def initialize
|
|
269
|
-
@defaults = {
|
|
270
|
-
:@submodules => [],
|
|
271
|
-
:@username_attribute_names => [:email],
|
|
272
|
-
:@password_attribute_name => :password,
|
|
273
|
-
:@downcase_username_before_authenticating => false,
|
|
274
|
-
:@email_attribute_name => :email,
|
|
275
|
-
:@crypted_password_attribute_name => :crypted_password,
|
|
276
|
-
:@encryption_algorithm => :bcrypt,
|
|
277
|
-
:@encryption_provider => CryptoProviders::BCrypt,
|
|
278
|
-
:@custom_encryption_provider => nil,
|
|
279
|
-
:@encryption_key => nil,
|
|
280
|
-
:@salt_join_token => "",
|
|
281
|
-
:@salt_attribute_name => :salt,
|
|
282
|
-
:@stretches => nil,
|
|
283
|
-
:@subclasses_inherit_config => false,
|
|
284
|
-
:@before_authenticate => [],
|
|
285
|
-
:@after_config => []
|
|
286
|
-
}
|
|
287
|
-
reset!
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
# Resets all configuration options to their default values.
|
|
291
|
-
def reset!
|
|
292
|
-
@defaults.each do |k,v|
|
|
293
|
-
instance_variable_set(k,v)
|
|
294
|
-
end
|
|
295
|
-
end
|
|
296
|
-
|
|
297
|
-
def username_attribute_names=(fields)
|
|
298
|
-
@username_attribute_names = fields.kind_of?(Array) ? fields : [fields]
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
def custom_encryption_provider=(provider)
|
|
302
|
-
@custom_encryption_provider = @encryption_provider = provider
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
def encryption_algorithm=(algo)
|
|
306
|
-
@encryption_algorithm = algo
|
|
307
|
-
@encryption_provider = case @encryption_algorithm.to_sym
|
|
308
|
-
when :none then nil
|
|
309
|
-
when :md5 then CryptoProviders::MD5
|
|
310
|
-
when :sha1 then CryptoProviders::SHA1
|
|
311
|
-
when :sha256 then CryptoProviders::SHA256
|
|
312
|
-
when :sha512 then CryptoProviders::SHA512
|
|
313
|
-
when :aes256 then CryptoProviders::AES256
|
|
314
|
-
when :bcrypt then CryptoProviders::BCrypt
|
|
315
|
-
when :custom then @custom_encryption_provider
|
|
316
|
-
else raise ArgumentError.new("Encryption algorithm supplied, #{algo}, is invalid")
|
|
184
|
+
# Rails 4.2 deprecates #deliver
|
|
185
|
+
if mail.respond_to?(:deliver_now)
|
|
186
|
+
mail.deliver_now
|
|
187
|
+
else
|
|
188
|
+
mail.deliver
|
|
189
|
+
end
|
|
317
190
|
end
|
|
318
191
|
end
|
|
319
|
-
|
|
320
192
|
end
|
|
321
193
|
|
|
322
194
|
end
|
|
@@ -13,6 +13,17 @@ module Sorcery
|
|
|
13
13
|
@user_info_mapping = {}
|
|
14
14
|
end
|
|
15
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
|
+
|
|
16
27
|
def self.name
|
|
17
28
|
super.gsub(/Sorcery::Providers::/, '').downcase
|
|
18
29
|
end
|
|
@@ -12,16 +12,18 @@ module Sorcery
|
|
|
12
12
|
|
|
13
13
|
attr_reader :mode, :param_name, :parse
|
|
14
14
|
attr_accessor :access_permissions, :display, :scope, :token_url,
|
|
15
|
-
:user_info_path
|
|
15
|
+
:user_info_path, :auth_path, :api_version
|
|
16
16
|
|
|
17
17
|
def initialize
|
|
18
18
|
super
|
|
19
19
|
|
|
20
20
|
@site = 'https://graph.facebook.com'
|
|
21
|
-
@
|
|
22
|
-
@
|
|
21
|
+
@auth_site = 'https://www.facebook.com'
|
|
22
|
+
@user_info_path = 'me'
|
|
23
|
+
@scope = 'email'
|
|
23
24
|
@display = 'page'
|
|
24
25
|
@token_url = 'oauth/access_token'
|
|
26
|
+
@auth_path = 'dialog/oauth'
|
|
25
27
|
@mode = :query
|
|
26
28
|
@parse = :query
|
|
27
29
|
@param_name = 'access_token'
|
|
@@ -30,7 +32,7 @@ module Sorcery
|
|
|
30
32
|
def get_user_hash(access_token)
|
|
31
33
|
response = access_token.get(user_info_path)
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
auth_hash(access_token).tap do |h|
|
|
34
36
|
h[:user_info] = JSON.parse(response.body)
|
|
35
37
|
h[:uid] = h[:user_info]['id']
|
|
36
38
|
end
|
|
@@ -44,8 +46,17 @@ module Sorcery
|
|
|
44
46
|
|
|
45
47
|
# overrides oauth2#authorize_url to allow customized scope.
|
|
46
48
|
def authorize_url
|
|
49
|
+
|
|
50
|
+
# Fix: replace default oauth2 options, specially to prevent the Faraday gem which
|
|
51
|
+
# concatenates with "/", removing the Facebook api version
|
|
52
|
+
options = {
|
|
53
|
+
site: File::join(@site, api_version.to_s),
|
|
54
|
+
authorize_url: File::join(@auth_site, api_version.to_s, auth_path),
|
|
55
|
+
token_url: token_url
|
|
56
|
+
}
|
|
57
|
+
|
|
47
58
|
@scope = access_permissions.present? ? access_permissions.join(',') : scope
|
|
48
|
-
super
|
|
59
|
+
super(options)
|
|
49
60
|
end
|
|
50
61
|
|
|
51
62
|
# tries to login the user from access token
|
|
@@ -25,8 +25,10 @@ module Sorcery
|
|
|
25
25
|
def get_user_hash(access_token)
|
|
26
26
|
response = access_token.get(user_info_path)
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
h[:user_info] = JSON.parse(response.body)
|
|
28
|
+
auth_hash(access_token).tap do |h|
|
|
29
|
+
h[:user_info] = JSON.parse(response.body).tap do |uih|
|
|
30
|
+
uih['email'] = primary_email(access_token) if scope =~ /user/
|
|
31
|
+
end
|
|
30
32
|
h[:uid] = h[:user_info]['id']
|
|
31
33
|
end
|
|
32
34
|
end
|
|
@@ -46,6 +48,13 @@ module Sorcery
|
|
|
46
48
|
get_access_token(args, token_url: token_url, token_method: :post)
|
|
47
49
|
end
|
|
48
50
|
|
|
51
|
+
def primary_email(access_token)
|
|
52
|
+
response = access_token.get(user_info_path + "/emails")
|
|
53
|
+
emails = JSON.parse(response.body)
|
|
54
|
+
primary = emails.find{|i| i['primary'] }
|
|
55
|
+
primary && primary['email'] || emails.first && emails.first['email']
|
|
56
|
+
end
|
|
57
|
+
|
|
49
58
|
end
|
|
50
59
|
end
|
|
51
60
|
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Sorcery
|
|
2
|
+
module Providers
|
|
3
|
+
|
|
4
|
+
# This class adds support for OAuth with heroku.com.
|
|
5
|
+
|
|
6
|
+
# config.heroku.key = <key>
|
|
7
|
+
# config.heroku.secret = <secret>
|
|
8
|
+
# config.heroku.callback_url = "<host>/oauth/callback?provider=heroku"
|
|
9
|
+
# config.heroku.scope = "read"
|
|
10
|
+
# config.heroku.user_info_mapping = {:email => "email", :name => "email" }
|
|
11
|
+
|
|
12
|
+
# NOTE:
|
|
13
|
+
# The full path must be set for OAuth Callback URL when configuring the API Client Information on Heroku.
|
|
14
|
+
|
|
15
|
+
class Heroku < Base
|
|
16
|
+
|
|
17
|
+
include Protocols::Oauth2
|
|
18
|
+
|
|
19
|
+
attr_accessor :auth_path, :scope, :token_url, :user_info_path
|
|
20
|
+
|
|
21
|
+
def initialize
|
|
22
|
+
super
|
|
23
|
+
|
|
24
|
+
@scope = nil
|
|
25
|
+
@site = 'https://id.heroku.com'
|
|
26
|
+
@user_info_path = 'https://api.heroku.com/account'
|
|
27
|
+
@auth_path = '/oauth/authorize'
|
|
28
|
+
@token_url = '/oauth/token'
|
|
29
|
+
@user_info_path = '/account'
|
|
30
|
+
@state = SecureRandom.hex(16)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def get_user_hash(access_token)
|
|
34
|
+
response = access_token.get(user_info_path)
|
|
35
|
+
body = JSON.parse(response.body)
|
|
36
|
+
auth_hash(access_token).tap do |h|
|
|
37
|
+
h[:user_info] = body
|
|
38
|
+
h[:uid] = body['id'].to_s
|
|
39
|
+
h[:email] = body['email'].to_s
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def login_url(params, session)
|
|
44
|
+
authorize_url({ authorize_url: auth_path })
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# tries to login the user from access token
|
|
48
|
+
def process_callback(params, session)
|
|
49
|
+
raise "Invalid state. Potential Cross Site Forgery" if params[:state] != state
|
|
50
|
+
args = { }.tap do |a|
|
|
51
|
+
a[:code] = params[:code] if params[:code]
|
|
52
|
+
end
|
|
53
|
+
get_access_token(args, token_url: token_url, token_method: :post)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module Sorcery
|
|
2
|
+
module Providers
|
|
3
|
+
# This class adds support for OAuth with Jira
|
|
4
|
+
#
|
|
5
|
+
# config.jira.key = <key>
|
|
6
|
+
# config.jira.secret = <secret>
|
|
7
|
+
# ...
|
|
8
|
+
#
|
|
9
|
+
class Jira < Base
|
|
10
|
+
|
|
11
|
+
include Protocols::Oauth
|
|
12
|
+
|
|
13
|
+
attr_accessor :access_token_path, :authorize_path, :request_token_path,
|
|
14
|
+
:user_info_path, :site, :signature_method, :private_key_file, :callback_url
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def initialize
|
|
18
|
+
@configuration = {
|
|
19
|
+
authorize_path: '/authorize',
|
|
20
|
+
request_token_path: '/request-token',
|
|
21
|
+
access_token_path: '/access-token'
|
|
22
|
+
}
|
|
23
|
+
@user_info_path = '/users/me'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Override included get_consumer method to provide authorize_path
|
|
27
|
+
#read extra configurations
|
|
28
|
+
def get_consumer
|
|
29
|
+
@configuration = @configuration.merge({
|
|
30
|
+
site: site,
|
|
31
|
+
signature_method: signature_method,
|
|
32
|
+
consumer_key: key,
|
|
33
|
+
private_key_file: private_key_file
|
|
34
|
+
})
|
|
35
|
+
::OAuth::Consumer.new(@key, @secret, @configuration)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def get_user_hash(access_token)
|
|
39
|
+
response = access_token.get(user_info_path)
|
|
40
|
+
|
|
41
|
+
auth_hash(access_token).tap do |h|
|
|
42
|
+
h[:user_info] = JSON.parse(response.body)['users'].first
|
|
43
|
+
h[:uid] = user_hash[:user_info]['id'].to_s
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# calculates and returns the url to which the user should be redirected,
|
|
48
|
+
# to get authenticated at the external provider's site.
|
|
49
|
+
def login_url(params, session)
|
|
50
|
+
req_token = get_request_token
|
|
51
|
+
session[:request_token] = req_token.token
|
|
52
|
+
session[:request_token_secret] = req_token.secret
|
|
53
|
+
|
|
54
|
+
#it was like that -> redirect_to authorize_url({ request_token: req_token.token, request_token_secret: req_token.secret })
|
|
55
|
+
#for some reason Jira does not need these parameters
|
|
56
|
+
|
|
57
|
+
get_request_token(
|
|
58
|
+
session[:request_token],
|
|
59
|
+
session[:request_token_secret]
|
|
60
|
+
).authorize_url
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# tries to login the user from access token
|
|
64
|
+
def process_callback(params, session)
|
|
65
|
+
args = {
|
|
66
|
+
oauth_verifier: params[:oauth_verifier],
|
|
67
|
+
request_token: session[:request_token],
|
|
68
|
+
request_token_secret: session[:request_token_secret]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
args.merge!({ code: params[:code] }) if params[:code]
|
|
72
|
+
get_access_token(args)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -34,7 +34,7 @@ module Sorcery
|
|
|
34
34
|
fields = self.user_info_fields.join(',')
|
|
35
35
|
response = access_token.get("#{@user_info_path}:(#{fields})", 'x-li-format' => 'json')
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
auth_hash(access_token).tap do |h|
|
|
38
38
|
h[:user_info] = JSON.parse(response.body)
|
|
39
39
|
h[:uid] = h[:user_info]['id'].to_s
|
|
40
40
|
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Sorcery
|
|
2
|
+
module Providers
|
|
3
|
+
# This class adds support for OAuth with salesforce.com.
|
|
4
|
+
#
|
|
5
|
+
# config.salesforce.key = <key>
|
|
6
|
+
# config.salesforce.secret = <secret>
|
|
7
|
+
# ...
|
|
8
|
+
#
|
|
9
|
+
class Salesforce < Base
|
|
10
|
+
|
|
11
|
+
include Protocols::Oauth2
|
|
12
|
+
|
|
13
|
+
attr_accessor :auth_url, :token_url, :scope
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
super
|
|
17
|
+
|
|
18
|
+
@site = 'https://login.salesforce.com'
|
|
19
|
+
@auth_url = '/services/oauth2/authorize'
|
|
20
|
+
@token_url = '/services/oauth2/token'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def get_user_hash(access_token)
|
|
24
|
+
user_info_url = access_token.params['id']
|
|
25
|
+
response = access_token.get(user_info_url)
|
|
26
|
+
|
|
27
|
+
auth_hash(access_token).tap do |h|
|
|
28
|
+
h[:user_info] = JSON.parse(response.body)
|
|
29
|
+
h[:uid] = h[:user_info]['user_id']
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# calculates and returns the url to which the user should be redirected,
|
|
34
|
+
# to get authenticated at the external provider's site.
|
|
35
|
+
def login_url(params, session)
|
|
36
|
+
authorize_url({ authorize_url: auth_url })
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# tries to login the user from access token
|
|
40
|
+
def process_callback(params, session)
|
|
41
|
+
args = {}.tap do |a|
|
|
42
|
+
a[:code] = params[:code] if params[:code]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
get_access_token(args, token_url: token_url, token_method: :post)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
data/lib/sorcery/providers/vk.rb
CHANGED
|
@@ -19,24 +19,26 @@ module Sorcery
|
|
|
19
19
|
@user_info_url = 'https://api.vk.com/method/getProfiles'
|
|
20
20
|
@auth_path = '/authorize'
|
|
21
21
|
@token_path = '/access_token'
|
|
22
|
-
@scope = ''
|
|
22
|
+
@scope = 'email'
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def get_user_hash(access_token)
|
|
26
|
-
user_hash =
|
|
26
|
+
user_hash = auth_hash(access_token)
|
|
27
27
|
|
|
28
28
|
params = {
|
|
29
29
|
access_token: access_token.token,
|
|
30
30
|
uids: access_token.params['user_id'],
|
|
31
31
|
fields: user_info_mapping.values.join(','),
|
|
32
|
-
scope: scope
|
|
32
|
+
scope: scope
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
response = access_token.get(user_info_url, params: params)
|
|
36
36
|
if user_hash[:user_info] = JSON.parse(response.body)
|
|
37
37
|
user_hash[:user_info] = user_hash[:user_info]['response'][0]
|
|
38
|
-
user_hash[:user_info]['full_name'] = [user_hash[:user_info]['first_name'], user_hash[:user_info]['last_name']].join
|
|
38
|
+
user_hash[:user_info]['full_name'] = [user_hash[:user_info]['first_name'], user_hash[:user_info]['last_name']].join(' ')
|
|
39
|
+
|
|
39
40
|
user_hash[:uid] = user_hash[:user_info]['uid']
|
|
41
|
+
user_hash[:user_info]['email'] = access_token.params['email']
|
|
40
42
|
end
|
|
41
43
|
user_hash
|
|
42
44
|
end
|
|
@@ -32,9 +32,9 @@ module Sorcery
|
|
|
32
32
|
def get_user_hash(access_token)
|
|
33
33
|
response = access_token.get(user_info_path)
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
auth_hash(access_token).tap do |h|
|
|
36
36
|
h[:user_info] = JSON.parse(response.body)['users'].first
|
|
37
|
-
h[:uid] =
|
|
37
|
+
h[:uid] = h[:user_info]['id'].to_s
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
@@ -30,14 +30,14 @@ module Sorcery
|
|
|
30
30
|
|
|
31
31
|
def create_new_user(attributes_hash = nil)
|
|
32
32
|
@user = build_new_user(attributes_hash)
|
|
33
|
-
@user.
|
|
33
|
+
@user.sorcery_adapter.save(:raise_on_failure => true)
|
|
34
34
|
@user
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def create_new_external_user(provider, attributes_hash = nil)
|
|
38
38
|
user_attributes_hash = attributes_hash || {:username => 'gizmo'}
|
|
39
39
|
@user = User.new(user_attributes_hash)
|
|
40
|
-
@user.
|
|
40
|
+
@user.sorcery_adapter.save(:raise_on_failure => true)
|
|
41
41
|
@user.authentications.create!({:provider => provider, :uid => 123})
|
|
42
42
|
@user
|
|
43
43
|
end
|
|
@@ -47,7 +47,7 @@ module Sorcery
|
|
|
47
47
|
|
|
48
48
|
user_attributes_hash = attributes_hash || {:username => 'gizmo'}
|
|
49
49
|
@user = User.new(user_attributes_hash)
|
|
50
|
-
@user.
|
|
50
|
+
@user.sorcery_adapter.save(:raise_on_failure => true)
|
|
51
51
|
@user.send(authentication_association).create!({:provider => provider, :uid => 123})
|
|
52
52
|
@user
|
|
53
53
|
end
|
|
@@ -58,6 +58,10 @@ module Sorcery
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
def update_model(&block)
|
|
62
|
+
User.class_exec(&block)
|
|
63
|
+
end
|
|
64
|
+
|
|
61
65
|
private
|
|
62
66
|
|
|
63
67
|
# reload user class between specs
|