sorcery 0.9.1 → 0.16.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (199) hide show
  1. checksums.yaml +5 -5
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/ISSUE_TEMPLATE.md +24 -0
  4. data/.github/PULL_REQUEST_TEMPLATE.md +7 -0
  5. data/.github/workflows/ruby.yml +70 -0
  6. data/.gitignore +3 -0
  7. data/.rubocop.yml +55 -0
  8. data/.rubocop_todo.yml +163 -0
  9. data/CHANGELOG.md +132 -34
  10. data/CODE_OF_CONDUCT.md +14 -0
  11. data/Gemfile +3 -17
  12. data/{LICENSE.txt → LICENSE.md} +1 -1
  13. data/MAINTAINING.md +64 -0
  14. data/README.md +146 -269
  15. data/Rakefile +4 -2
  16. data/SECURITY.md +19 -0
  17. data/gemfiles/rails_52.gemfile +7 -0
  18. data/gemfiles/rails_60.gemfile +7 -0
  19. data/gemfiles/rails_61.gemfile +7 -0
  20. data/gemfiles/rails_70.gemfile +7 -0
  21. data/lib/generators/sorcery/USAGE +1 -1
  22. data/lib/generators/sorcery/helpers.rb +8 -4
  23. data/lib/generators/sorcery/install_generator.rb +41 -35
  24. data/lib/generators/sorcery/templates/initializer.rb +216 -112
  25. data/lib/generators/sorcery/templates/migration/activity_logging.rb +7 -7
  26. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +5 -5
  27. data/lib/generators/sorcery/templates/migration/core.rb +5 -7
  28. data/lib/generators/sorcery/templates/migration/external.rb +4 -4
  29. data/lib/generators/sorcery/templates/migration/magic_login.rb +9 -0
  30. data/lib/generators/sorcery/templates/migration/remember_me.rb +5 -5
  31. data/lib/generators/sorcery/templates/migration/reset_password.rb +7 -6
  32. data/lib/generators/sorcery/templates/migration/user_activation.rb +6 -6
  33. data/lib/sorcery/adapters/active_record_adapter.rb +11 -21
  34. data/lib/sorcery/adapters/mongoid_adapter.rb +23 -11
  35. data/lib/sorcery/controller/config.rb +27 -23
  36. data/lib/sorcery/controller/submodules/activity_logging.rb +16 -18
  37. data/lib/sorcery/controller/submodules/brute_force_protection.rb +1 -2
  38. data/lib/sorcery/controller/submodules/external.rb +69 -44
  39. data/lib/sorcery/controller/submodules/http_basic_auth.rb +18 -19
  40. data/lib/sorcery/controller/submodules/remember_me.rb +16 -16
  41. data/lib/sorcery/controller/submodules/session_timeout.rb +33 -11
  42. data/lib/sorcery/controller.rb +50 -35
  43. data/lib/sorcery/crypto_providers/aes256.rb +17 -16
  44. data/lib/sorcery/crypto_providers/bcrypt.rb +26 -22
  45. data/lib/sorcery/crypto_providers/common.rb +1 -1
  46. data/lib/sorcery/crypto_providers/md5.rb +5 -5
  47. data/lib/sorcery/crypto_providers/sha1.rb +5 -5
  48. data/lib/sorcery/crypto_providers/sha256.rb +2 -2
  49. data/lib/sorcery/crypto_providers/sha512.rb +3 -3
  50. data/lib/sorcery/engine.rb +19 -11
  51. data/lib/sorcery/model/config.rb +73 -50
  52. data/lib/sorcery/model/submodules/activity_logging.rb +31 -12
  53. data/lib/sorcery/model/submodules/brute_force_protection.rb +38 -31
  54. data/lib/sorcery/model/submodules/external.rb +22 -10
  55. data/lib/sorcery/model/submodules/magic_login.rb +130 -0
  56. data/lib/sorcery/model/submodules/remember_me.rb +19 -7
  57. data/lib/sorcery/model/submodules/reset_password.rb +64 -42
  58. data/lib/sorcery/model/submodules/user_activation.rb +52 -54
  59. data/lib/sorcery/model/temporary_token.rb +30 -7
  60. data/lib/sorcery/model.rb +65 -40
  61. data/lib/sorcery/protocols/oauth.rb +4 -9
  62. data/lib/sorcery/protocols/oauth2.rb +0 -2
  63. data/lib/sorcery/providers/auth0.rb +46 -0
  64. data/lib/sorcery/providers/base.rb +4 -4
  65. data/lib/sorcery/providers/battlenet.rb +51 -0
  66. data/lib/sorcery/providers/discord.rb +52 -0
  67. data/lib/sorcery/providers/facebook.rb +8 -11
  68. data/lib/sorcery/providers/github.rb +5 -7
  69. data/lib/sorcery/providers/google.rb +3 -5
  70. data/lib/sorcery/providers/heroku.rb +7 -8
  71. data/lib/sorcery/providers/instagram.rb +73 -0
  72. data/lib/sorcery/providers/jira.rb +12 -17
  73. data/lib/sorcery/providers/line.rb +63 -0
  74. data/lib/sorcery/providers/linkedin.rb +44 -35
  75. data/lib/sorcery/providers/liveid.rb +4 -7
  76. data/lib/sorcery/providers/microsoft.rb +59 -0
  77. data/lib/sorcery/providers/paypal.rb +60 -0
  78. data/lib/sorcery/providers/salesforce.rb +3 -5
  79. data/lib/sorcery/providers/slack.rb +45 -0
  80. data/lib/sorcery/providers/twitter.rb +4 -6
  81. data/lib/sorcery/providers/vk.rb +8 -9
  82. data/lib/sorcery/providers/wechat.rb +81 -0
  83. data/lib/sorcery/providers/xing.rb +7 -10
  84. data/lib/sorcery/test_helpers/internal/rails.rb +25 -17
  85. data/lib/sorcery/test_helpers/internal.rb +15 -14
  86. data/lib/sorcery/test_helpers/rails/controller.rb +1 -1
  87. data/lib/sorcery/test_helpers/rails/integration.rb +5 -6
  88. data/lib/sorcery/test_helpers/rails/request.rb +20 -0
  89. data/lib/sorcery/version.rb +1 -1
  90. data/lib/sorcery.rb +4 -17
  91. data/sorcery.gemspec +43 -28
  92. data/spec/active_record/user_activation_spec.rb +4 -5
  93. data/spec/active_record/user_activity_logging_spec.rb +4 -6
  94. data/spec/active_record/user_brute_force_protection_spec.rb +5 -6
  95. data/spec/active_record/user_magic_login_spec.rb +15 -0
  96. data/spec/active_record/user_oauth_spec.rb +5 -6
  97. data/spec/active_record/user_remember_me_spec.rb +5 -6
  98. data/spec/active_record/user_reset_password_spec.rb +4 -5
  99. data/spec/active_record/user_spec.rb +7 -17
  100. data/spec/controllers/controller_activity_logging_spec.rb +13 -24
  101. data/spec/controllers/controller_brute_force_protection_spec.rb +8 -10
  102. data/spec/controllers/controller_http_basic_auth_spec.rb +20 -21
  103. data/spec/controllers/controller_oauth2_spec.rb +297 -158
  104. data/spec/controllers/controller_oauth_spec.rb +97 -71
  105. data/spec/controllers/controller_remember_me_spec.rb +49 -36
  106. data/spec/controllers/controller_session_timeout_spec.rb +106 -20
  107. data/spec/controllers/controller_spec.rb +87 -111
  108. data/spec/orm/active_record.rb +3 -3
  109. data/spec/providers/example_provider_spec.rb +17 -0
  110. data/spec/providers/example_spec.rb +17 -0
  111. data/spec/providers/examples_spec.rb +17 -0
  112. data/spec/providers/vk_spec.rb +42 -0
  113. data/spec/rails_app/app/active_record/authentication.rb +1 -1
  114. data/spec/rails_app/app/active_record/user.rb +2 -2
  115. data/spec/rails_app/app/assets/config/manifest.js +1 -0
  116. data/spec/rails_app/app/controllers/application_controller.rb +2 -0
  117. data/spec/rails_app/app/controllers/sorcery_controller.rb +250 -46
  118. data/spec/rails_app/app/mailers/sorcery_mailer.rb +23 -17
  119. data/spec/rails_app/app/views/sorcery_mailer/magic_login_email.html.erb +13 -0
  120. data/spec/rails_app/app/views/sorcery_mailer/magic_login_email.text.erb +6 -0
  121. data/spec/rails_app/config/application.rb +14 -9
  122. data/spec/rails_app/config/boot.rb +2 -2
  123. data/spec/rails_app/config/environment.rb +1 -1
  124. data/spec/rails_app/config/environments/test.rb +1 -1
  125. data/spec/rails_app/config/initializers/compatible_legacy_migration.rb +11 -0
  126. data/spec/rails_app/config/initializers/session_store.rb +3 -3
  127. data/spec/rails_app/config/routes.rb +31 -1
  128. data/spec/rails_app/config/secrets.yml +4 -0
  129. data/spec/rails_app/config.ru +1 -1
  130. data/spec/rails_app/db/migrate/activation/20101224223622_add_activation_to_users.rb +4 -4
  131. data/spec/rails_app/db/migrate/activity_logging/20101224223624_add_activity_logging_to_users.rb +10 -10
  132. data/spec/rails_app/db/migrate/brute_force_protection/20101224223626_add_brute_force_protection_to_users.rb +5 -5
  133. data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +5 -5
  134. data/spec/rails_app/db/migrate/external/20101224223628_create_authentications_and_user_providers.rb +3 -3
  135. data/spec/rails_app/db/migrate/invalidate_active_sessions/20180221093235_add_invalidate_active_sessions_before_to_users.rb +9 -0
  136. data/spec/rails_app/db/migrate/magic_login/20170924151831_add_magic_login_to_users.rb +17 -0
  137. data/spec/rails_app/db/migrate/remember_me/20101224223623_add_remember_me_token_to_users.rb +6 -6
  138. data/spec/rails_app/db/migrate/reset_password/20101224223622_add_reset_password_to_users.rb +7 -5
  139. data/spec/rails_app/db/schema.rb +7 -9
  140. data/spec/shared_examples/user_activation_shared_examples.rb +177 -58
  141. data/spec/shared_examples/user_activity_logging_shared_examples.rb +47 -41
  142. data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +19 -24
  143. data/spec/shared_examples/user_magic_login_shared_examples.rb +150 -0
  144. data/spec/shared_examples/user_oauth_shared_examples.rb +7 -10
  145. data/spec/shared_examples/user_remember_me_shared_examples.rb +91 -22
  146. data/spec/shared_examples/user_reset_password_shared_examples.rb +153 -58
  147. data/spec/shared_examples/user_shared_examples.rb +328 -145
  148. data/spec/sorcery_crypto_providers_spec.rb +122 -75
  149. data/spec/sorcery_temporary_token_spec.rb +27 -0
  150. data/spec/spec.opts +1 -1
  151. data/spec/spec_helper.rb +19 -14
  152. data/spec/support/migration_helper.rb +29 -0
  153. data/spec/support/providers/example.rb +11 -0
  154. data/spec/support/providers/example_provider.rb +11 -0
  155. data/spec/support/providers/examples.rb +11 -0
  156. metadata +119 -89
  157. data/.travis.yml +0 -132
  158. data/gemfiles/active_record-rails40.gemfile +0 -7
  159. data/gemfiles/active_record-rails41.gemfile +0 -7
  160. data/gemfiles/mongo_mapper-rails40.gemfile +0 -9
  161. data/gemfiles/mongo_mapper-rails41.gemfile +0 -9
  162. data/gemfiles/mongoid-rails40.gemfile +0 -9
  163. data/gemfiles/mongoid-rails41.gemfile +0 -9
  164. data/gemfiles/mongoid3-rails32.gemfile +0 -9
  165. data/lib/sorcery/adapters/data_mapper_adapter.rb +0 -176
  166. data/lib/sorcery/adapters/mongo_mapper_adapter.rb +0 -110
  167. data/lib/sorcery/railties/tasks.rake +0 -6
  168. data/spec/data_mapper/user_activation_spec.rb +0 -10
  169. data/spec/data_mapper/user_activity_logging_spec.rb +0 -14
  170. data/spec/data_mapper/user_brute_force_protection_spec.rb +0 -9
  171. data/spec/data_mapper/user_oauth_spec.rb +0 -9
  172. data/spec/data_mapper/user_remember_me_spec.rb +0 -8
  173. data/spec/data_mapper/user_reset_password_spec.rb +0 -8
  174. data/spec/data_mapper/user_spec.rb +0 -27
  175. data/spec/mongo_mapper/user_activation_spec.rb +0 -9
  176. data/spec/mongo_mapper/user_activity_logging_spec.rb +0 -8
  177. data/spec/mongo_mapper/user_brute_force_protection_spec.rb +0 -8
  178. data/spec/mongo_mapper/user_oauth_spec.rb +0 -8
  179. data/spec/mongo_mapper/user_remember_me_spec.rb +0 -8
  180. data/spec/mongo_mapper/user_reset_password_spec.rb +0 -8
  181. data/spec/mongo_mapper/user_spec.rb +0 -37
  182. data/spec/mongoid/user_activation_spec.rb +0 -9
  183. data/spec/mongoid/user_activity_logging_spec.rb +0 -8
  184. data/spec/mongoid/user_brute_force_protection_spec.rb +0 -8
  185. data/spec/mongoid/user_oauth_spec.rb +0 -8
  186. data/spec/mongoid/user_remember_me_spec.rb +0 -8
  187. data/spec/mongoid/user_reset_password_spec.rb +0 -8
  188. data/spec/mongoid/user_spec.rb +0 -51
  189. data/spec/orm/data_mapper.rb +0 -48
  190. data/spec/orm/mongo_mapper.rb +0 -10
  191. data/spec/orm/mongoid.rb +0 -22
  192. data/spec/rails_app/app/data_mapper/authentication.rb +0 -8
  193. data/spec/rails_app/app/data_mapper/user.rb +0 -7
  194. data/spec/rails_app/app/mongo_mapper/authentication.rb +0 -6
  195. data/spec/rails_app/app/mongo_mapper/user.rb +0 -7
  196. data/spec/rails_app/app/mongoid/authentication.rb +0 -7
  197. data/spec/rails_app/app/mongoid/user.rb +0 -7
  198. data/spec/rails_app/config/initializers/secret_token.rb +0 -7
  199. data/spec/rails_app/log/development.log +0 -1791
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
- self.class_eval do
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,32 +39,34 @@ 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
- self.class_eval do
47
+ class_eval do
49
48
  @sorcery_config.submodules = ::Sorcery::Controller::Config.submodules
50
49
  @sorcery_config.submodules.each do |mod|
50
+ # TODO: Is there a cleaner way to handle missing submodules?
51
+ # rubocop:disable Lint/HandleExceptions
51
52
  begin
52
- include Submodules.const_get(mod.to_s.split('_').map {|p| p.capitalize}.join)
53
+ include Submodules.const_get(mod.to_s.split('_').map(&:capitalize).join)
53
54
  rescue NameError
54
55
  # don't stop on a missing submodule. Needed because some submodules are only defined
55
56
  # in the controller side.
56
57
  end
58
+ # rubocop:enable Lint/HandleExceptions
57
59
  end
58
60
  end
59
61
  end
60
62
 
61
63
  # add virtual password accessor and ORM callbacks.
62
64
  def init_orm_hooks!
63
- sorcery_adapter.define_callback :before, :validation, :encrypt_password, if: Proc.new {|record|
65
+ sorcery_adapter.define_callback :before, :validation, :encrypt_password, if: proc { |record|
64
66
  record.send(sorcery_config.password_attribute_name).present?
65
67
  }
66
68
 
67
- sorcery_adapter.define_callback :after, :save, :clear_virtual_password, if: Proc.new {|record|
69
+ sorcery_adapter.define_callback :after, :save, :clear_virtual_password, if: proc { |record|
68
70
  record.send(sorcery_config.password_attribute_name).present?
69
71
  }
70
72
 
@@ -81,10 +83,12 @@ module Sorcery
81
83
  # Takes a username and password,
82
84
  # Finds the user by the username and compares the user's password to the one supplied to the method.
83
85
  # returns the user if success, nil otherwise.
84
- def authenticate(*credentials)
85
- raise ArgumentError, "at least 2 arguments required" if credentials.size < 2
86
+ def authenticate(*credentials, &block)
87
+ raise ArgumentError, 'at least 2 arguments required' if credentials.size < 2
86
88
 
87
- return false if credentials[0].blank?
89
+ if credentials[0].blank?
90
+ return authentication_response(return_value: false, failure: :invalid_login, &block)
91
+ end
88
92
 
89
93
  if @sorcery_config.downcase_username_before_authenticating
90
94
  credentials[0].downcase!
@@ -92,34 +96,59 @@ module Sorcery
92
96
 
93
97
  user = sorcery_adapter.find_by_credentials(credentials)
94
98
 
95
- if user.respond_to?(:active_for_authentication?)
96
- return nil if !user.active_for_authentication?
99
+ unless user
100
+ return authentication_response(failure: :invalid_login, &block)
97
101
  end
98
102
 
99
103
  set_encryption_attributes
100
104
 
101
- user if user && @sorcery_config.before_authenticate.all? {|c| user.send(c)} && user.valid_password?(credentials[1])
105
+ if user.respond_to?(:active_for_authentication?) && !user.active_for_authentication?
106
+ return authentication_response(user: user, failure: :inactive, &block)
107
+ end
108
+
109
+ @sorcery_config.before_authenticate.each do |callback|
110
+ success, reason = user.send(callback)
111
+
112
+ unless success
113
+ return authentication_response(user: user, failure: reason, &block)
114
+ end
115
+ end
116
+
117
+ unless user.valid_password?(credentials[1])
118
+ return authentication_response(user: user, failure: :invalid_password, &block)
119
+ end
120
+
121
+ authentication_response(user: user, return_value: user, &block)
102
122
  end
103
123
 
104
124
  # encrypt tokens using current encryption_provider.
105
125
  def encrypt(*tokens)
106
126
  return tokens.first if @sorcery_config.encryption_provider.nil?
107
127
 
108
- set_encryption_attributes()
128
+ set_encryption_attributes
109
129
 
110
130
  CryptoProviders::AES256.key = @sorcery_config.encryption_key
111
131
  @sorcery_config.encryption_provider.encrypt(*tokens)
112
132
  end
113
133
 
114
- protected
115
-
116
- def set_encryption_attributes()
134
+ # FIXME: This method of passing config to the hashing provider is
135
+ # questionable, and has been refactored in Sorcery v1.
136
+ def set_encryption_attributes
117
137
  @sorcery_config.encryption_provider.stretches = @sorcery_config.stretches if @sorcery_config.encryption_provider.respond_to?(:stretches) && @sorcery_config.stretches
118
138
  @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
139
+ @sorcery_config.encryption_provider.pepper = @sorcery_config.pepper if @sorcery_config.encryption_provider.respond_to?(:pepper) && @sorcery_config.pepper
119
140
  end
120
-
141
+
142
+ protected
143
+
144
+ def authentication_response(options = {})
145
+ yield(options[:user], options[:failure]) if block_given?
146
+
147
+ options[:return_value]
148
+ end
149
+
121
150
  def add_config_inheritance
122
- self.class_eval do
151
+ class_eval do
123
152
  def self.inherited(subclass)
124
153
  subclass.class_eval do
125
154
  class << self
@@ -131,7 +160,6 @@ module Sorcery
131
160
  end
132
161
  end
133
162
  end
134
-
135
163
  end
136
164
 
137
165
  module InstanceMethods
@@ -148,12 +176,15 @@ module Sorcery
148
176
 
149
177
  # Calls the configured encryption provider to compare the supplied password with the encrypted one.
150
178
  def valid_password?(pass)
151
- _crypted = self.send(sorcery_config.crypted_password_attribute_name)
152
- return _crypted == pass if sorcery_config.encryption_provider.nil?
179
+ crypted = send(sorcery_config.crypted_password_attribute_name)
180
+ return crypted == pass if sorcery_config.encryption_provider.nil?
181
+
182
+ # Ensure encryption provider is using configured values
183
+ self.class.set_encryption_attributes
153
184
 
154
- _salt = self.send(sorcery_config.salt_attribute_name) unless sorcery_config.salt_attribute_name.nil?
185
+ salt = send(sorcery_config.salt_attribute_name) unless sorcery_config.salt_attribute_name.nil?
155
186
 
156
- sorcery_config.encryption_provider.matches?(_crypted, pass, _salt)
187
+ sorcery_config.encryption_provider.matches?(crypted, pass, salt)
157
188
  end
158
189
 
159
190
  protected
@@ -162,34 +193,28 @@ module Sorcery
162
193
  # encrypts password with salt and saves it.
163
194
  def encrypt_password
164
195
  config = sorcery_config
165
- self.send(:"#{config.salt_attribute_name}=", new_salt = TemporaryToken.generate_random_token) if !config.salt_attribute_name.nil?
166
- self.send(:"#{config.crypted_password_attribute_name}=", self.class.encrypt(self.send(config.password_attribute_name),new_salt))
196
+ send(:"#{config.salt_attribute_name}=", new_salt = TemporaryToken.generate_random_token) unless config.salt_attribute_name.nil?
197
+ send(:"#{config.crypted_password_attribute_name}=", self.class.encrypt(send(config.password_attribute_name), new_salt))
167
198
  end
168
199
 
169
200
  def clear_virtual_password
170
201
  config = sorcery_config
171
- self.send(:"#{config.password_attribute_name}=", nil)
202
+ send(:"#{config.password_attribute_name}=", nil)
172
203
 
173
- if respond_to?(:"#{config.password_attribute_name}_confirmation=")
174
- self.send(:"#{config.password_attribute_name}_confirmation=", nil)
175
- end
204
+ return unless respond_to?(:"#{config.password_attribute_name}_confirmation=")
205
+
206
+ send(:"#{config.password_attribute_name}_confirmation=", nil)
176
207
  end
177
208
 
178
209
  # calls the requested email method on the configured mailer
179
210
  # supports both the ActionMailer 3 way of calling, and the plain old Ruby object way.
180
211
  def generic_send_email(method, mailer)
181
212
  config = sorcery_config
182
- mail = config.send(mailer).send(config.send(method),self)
183
- if defined?(ActionMailer) and config.send(mailer).kind_of?(Class) and config.send(mailer) < ActionMailer::Base
184
- # Rails 4.2 deprecates #deliver
185
- if mail.respond_to?(:deliver_now)
186
- mail.deliver_now
187
- else
188
- mail.deliver
189
- end
190
- end
213
+ mail = config.send(mailer).send(config.send(method), self)
214
+ return unless mail.respond_to?(config.email_delivery_method)
215
+
216
+ mail.send(config.email_delivery_method)
191
217
  end
192
218
  end
193
-
194
219
  end
195
220
  end
@@ -3,13 +3,13 @@ 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
12
+
13
13
  get_consumer.get_request_token(oauth_callback: @callback_url)
14
14
  end
15
15
 
@@ -17,18 +17,14 @@ module Sorcery
17
17
  get_request_token(
18
18
  args[:request_token],
19
19
  args[:request_token_secret]
20
- ).authorize_url({
21
- oauth_callback: @callback_url
22
- })
20
+ ).authorize_url(oauth_callback: @callback_url)
23
21
  end
24
22
 
25
23
  def get_access_token(args)
26
24
  get_request_token(
27
25
  args[:request_token],
28
26
  args[:request_token_secret]
29
- ).get_access_token({
30
- oauth_verifier: args[:oauth_verifier]
31
- })
27
+ ).get_access_token(oauth_verifier: args[:oauth_verifier])
32
28
  end
33
29
 
34
30
  protected
@@ -36,7 +32,6 @@ module Sorcery
36
32
  def get_consumer
37
33
  ::OAuth::Consumer.new(@key, @secret, site: @site)
38
34
  end
39
-
40
35
  end
41
36
  end
42
37
  end
@@ -3,7 +3,6 @@ require 'oauth2'
3
3
  module Sorcery
4
4
  module Protocols
5
5
  module Oauth2
6
-
7
6
  def oauth_version
8
7
  '2.0'
9
8
  end
@@ -41,7 +40,6 @@ module Sorcery
41
40
  defaults.merge!(options)
42
41
  )
43
42
  end
44
-
45
43
  end
46
44
  end
47
45
  end
@@ -0,0 +1,46 @@
1
+ module Sorcery
2
+ module Providers
3
+ # This class adds support for OAuth with Auth0.com
4
+ #
5
+ # config.auth0.key = <key>
6
+ # config.auth0.secret = <secret>
7
+ # config.auth0.domain = <domain>
8
+ # ...
9
+ #
10
+ class Auth0 < Base
11
+ include Protocols::Oauth2
12
+
13
+ attr_accessor :auth_path, :token_path, :user_info_path, :scope
14
+
15
+ def initialize
16
+ super
17
+
18
+ @auth_path = '/authorize'
19
+ @token_path = '/oauth/token'
20
+ @user_info_path = '/userinfo'
21
+ @scope = 'openid profile email'
22
+ end
23
+
24
+ def get_user_hash(access_token)
25
+ response = access_token.get(user_info_path)
26
+
27
+ auth_hash(access_token).tap do |h|
28
+ h[:user_info] = JSON.parse(response.body)
29
+ h[:uid] = h[:user_info]['sub']
30
+ end
31
+ end
32
+
33
+ def login_url(_params, _session)
34
+ authorize_url(authorize_url: auth_path)
35
+ end
36
+
37
+ def process_callback(params, _session)
38
+ args = {}.tap do |a|
39
+ a[:code] = params[:code] if params[:code]
40
+ end
41
+
42
+ get_access_token(args, token_url: token_path, token_method: :post)
43
+ end
44
+ end
45
+ end
46
+ 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?; true; end
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
@@ -0,0 +1,51 @@
1
+ module Sorcery
2
+ module Providers
3
+ # This class adds support for OAuth with BattleNet
4
+
5
+ class Battlenet < Base
6
+ include Protocols::Oauth2
7
+
8
+ attr_accessor :auth_path, :scope, :token_url, :user_info_path
9
+
10
+ def initialize
11
+ super
12
+
13
+ @scope = 'openid'
14
+ @site = 'https://eu.battle.net/'
15
+ @auth_path = '/oauth/authorize'
16
+ @token_url = '/oauth/token'
17
+ @user_info_path = '/oauth/userinfo'
18
+ @state = SecureRandom.hex(16)
19
+ end
20
+
21
+ def get_user_hash(access_token)
22
+ response = access_token.get(user_info_path)
23
+ body = JSON.parse(response.body)
24
+ auth_hash(access_token).tap do |h|
25
+ h[:user_info] = body
26
+ h[:battletag] = body['battletag']
27
+ h[:uid] = body['id']
28
+ end
29
+ end
30
+
31
+ # calculates and returns the url to which the user should be redirected,
32
+ # to get authenticated at the external provider's site.
33
+ def login_url(_params, _session)
34
+ authorize_url(authorize_url: auth_path)
35
+ end
36
+
37
+ # tries to login the user from access token
38
+ def process_callback(params, _session)
39
+ args = { code: params[:code] }
40
+ get_access_token(
41
+ args,
42
+ token_url: token_url,
43
+ client_id: @key,
44
+ client_secret: @secret,
45
+ grant_type: 'authorization_code',
46
+ token_method: :post
47
+ )
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,52 @@
1
+ module Sorcery
2
+ module Providers
3
+ # This class adds support for OAuth with discordapp.com
4
+
5
+ class Discord < Base
6
+ include Protocols::Oauth2
7
+
8
+ attr_accessor :auth_path, :scope, :token_url, :user_info_path
9
+
10
+ def initialize
11
+ super
12
+
13
+ @scope = 'identify'
14
+ @site = 'https://discordapp.com/'
15
+ @auth_path = '/api/oauth2/authorize'
16
+ @token_url = '/api/oauth2/token'
17
+ @user_info_path = '/api/users/@me'
18
+ @state = SecureRandom.hex(16)
19
+ end
20
+
21
+ def get_user_hash(access_token)
22
+ response = access_token.get(user_info_path)
23
+ body = JSON.parse(response.body)
24
+ auth_hash(access_token).tap do |h|
25
+ h[:user_info] = body
26
+ h[:uid] = body['id']
27
+ end
28
+ end
29
+
30
+ # calculates and returns the url to which the user should be redirected,
31
+ # to get authenticated at the external provider's site.
32
+ def login_url(_params, _session)
33
+ authorize_url(authorize_url: auth_path)
34
+ end
35
+
36
+ # tries to login the user from access token
37
+ def process_callback(params, _session)
38
+ args = {}.tap do |a|
39
+ a[:code] = params[:code] if params[:code]
40
+ end
41
+ get_access_token(
42
+ args,
43
+ token_url: token_url,
44
+ client_id: @key,
45
+ client_secret: @secret,
46
+ grant_type: 'authorization_code',
47
+ token_method: :post
48
+ )
49
+ end
50
+ end
51
+ end
52
+ end
@@ -7,12 +7,11 @@ module Sorcery
7
7
  # ...
8
8
  #
9
9
  class Facebook < Base
10
-
11
10
  include Protocols::Oauth2
12
11
 
13
- attr_reader :mode, :param_name, :parse
12
+ attr_reader :mode, :param_name
14
13
  attr_accessor :access_permissions, :display, :scope, :token_url,
15
- :user_info_path, :auth_path, :api_version
14
+ :user_info_path, :auth_path, :api_version, :parse
16
15
 
17
16
  def initialize
18
17
  super
@@ -25,7 +24,7 @@ module Sorcery
25
24
  @token_url = 'oauth/access_token'
26
25
  @auth_path = 'dialog/oauth'
27
26
  @mode = :query
28
- @parse = :query
27
+ @parse = :json
29
28
  @param_name = 'access_token'
30
29
  end
31
30
 
@@ -40,18 +39,17 @@ module Sorcery
40
39
 
41
40
  # calculates and returns the url to which the user should be redirected,
42
41
  # to get authenticated at the external provider's site.
43
- def login_url(params, session)
42
+ def login_url(_params, _session)
44
43
  authorize_url
45
44
  end
46
45
 
47
46
  # overrides oauth2#authorize_url to allow customized scope.
48
47
  def authorize_url
49
-
50
48
  # Fix: replace default oauth2 options, specially to prevent the Faraday gem which
51
49
  # concatenates with "/", removing the Facebook api version
52
50
  options = {
53
- site: File::join(@site, api_version.to_s),
54
- authorize_url: File::join(@auth_site, api_version.to_s, auth_path),
51
+ site: File.join(@site, api_version.to_s),
52
+ authorize_url: File.join(@auth_site, api_version.to_s, auth_path),
55
53
  token_url: token_url
56
54
  }
57
55
 
@@ -60,15 +58,14 @@ module Sorcery
60
58
  end
61
59
 
62
60
  # tries to login the user from access token
63
- def process_callback(params, session)
61
+ def process_callback(params, _session)
64
62
  args = {}.tap do |a|
65
63
  a[:code] = params[:code] if params[:code]
66
64
  end
67
65
 
68
66
  get_access_token(args, token_url: token_url, mode: mode,
69
- param_name: param_name, parse: parse)
67
+ param_name: param_name, parse: parse)
70
68
  end
71
-
72
69
  end
73
70
  end
74
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
@@ -35,12 +34,12 @@ module Sorcery
35
34
 
36
35
  # calculates and returns the url to which the user should be redirected,
37
36
  # to get authenticated at the external provider's site.
38
- def login_url(params, session)
39
- authorize_url({ authorize_url: auth_path })
37
+ def login_url(_params, _session)
38
+ authorize_url(authorize_url: auth_path)
40
39
  end
41
40
 
42
41
  # tries to login the user from access token
43
- def process_callback(params, session)
42
+ def process_callback(params, _session)
44
43
  args = {}.tap do |a|
45
44
  a[:code] = params[:code] if params[:code]
46
45
  end
@@ -49,12 +48,11 @@ module Sorcery
49
48
  end
50
49
 
51
50
  def primary_email(access_token)
52
- response = access_token.get(user_info_path + "/emails")
51
+ response = access_token.get(user_info_path + '/emails')
53
52
  emails = JSON.parse(response.body)
54
- primary = emails.find{|i| i['primary'] }
53
+ primary = emails.find { |i| i['primary'] }
55
54
  primary && primary['email'] || emails.first && emails.first['email']
56
55
  end
57
-
58
56
  end
59
57
  end
60
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(params, session)
37
- authorize_url({ authorize_url: auth_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, session)
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,19 @@ module Sorcery
40
38
  end
41
39
  end
42
40
 
43
- def login_url(params, session)
44
- authorize_url({ authorize_url: auth_path })
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, session)
49
- raise "Invalid state. Potential Cross Site Forgery" if params[:state] != state
50
- args = { }.tap do |a|
46
+ def process_callback(params, _session)
47
+ raise 'Invalid state. Potential Cross Site Forgery' if params[:state] != state
48
+
49
+ args = {}.tap do |a|
51
50
  a[:code] = params[:code] if params[:code]
52
51
  end
53
52
  get_access_token(args, token_url: token_url, token_method: :post)
54
53
  end
55
54
  end
56
55
  end
57
- end
56
+ end