sorcery 0.15.0 → 0.17.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +10 -0
  3. data/.devcontainer/devcontainer.json +29 -0
  4. data/.devcontainer/postcreate.sh +4 -0
  5. data/.github/FUNDING.yml +1 -0
  6. data/.github/ISSUE_TEMPLATE.md +8 -4
  7. data/.github/PULL_REQUEST_TEMPLATE.md +7 -0
  8. data/.github/workflows/ruby.yml +54 -0
  9. data/.gitignore +2 -1
  10. data/.rubocop_todo.yml +44 -26
  11. data/CHANGELOG.md +48 -0
  12. data/CODE_OF_CONDUCT.md +14 -0
  13. data/Gemfile +2 -2
  14. data/MAINTAINING.md +64 -0
  15. data/README.md +3 -6
  16. data/Rakefile +3 -1
  17. data/SECURITY.md +19 -0
  18. data/gemfiles/rails_61.gemfile +7 -0
  19. data/gemfiles/rails_70.gemfile +7 -0
  20. data/gemfiles/rails_71.gemfile +7 -0
  21. data/lib/generators/sorcery/helpers.rb +4 -0
  22. data/lib/generators/sorcery/install_generator.rb +9 -2
  23. data/lib/generators/sorcery/templates/initializer.rb +23 -1
  24. data/lib/generators/sorcery/templates/migration/activity_logging.rb +5 -5
  25. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +4 -4
  26. data/lib/generators/sorcery/templates/migration/core.rb +2 -4
  27. data/lib/generators/sorcery/templates/migration/external.rb +1 -1
  28. data/lib/generators/sorcery/templates/migration/magic_login.rb +4 -4
  29. data/lib/generators/sorcery/templates/migration/remember_me.rb +3 -3
  30. data/lib/generators/sorcery/templates/migration/reset_password.rb +5 -5
  31. data/lib/generators/sorcery/templates/migration/user_activation.rb +4 -4
  32. data/lib/sorcery/adapters/active_record_adapter.rb +2 -2
  33. data/lib/sorcery/adapters/mongoid_adapter.rb +1 -1
  34. data/lib/sorcery/controller/config.rb +6 -6
  35. data/lib/sorcery/controller/submodules/activity_logging.rb +5 -10
  36. data/lib/sorcery/controller/submodules/brute_force_protection.rb +3 -7
  37. data/lib/sorcery/controller/submodules/external.rb +3 -2
  38. data/lib/sorcery/controller/submodules/http_basic_auth.rb +2 -4
  39. data/lib/sorcery/controller/submodules/remember_me.rb +3 -7
  40. data/lib/sorcery/controller/submodules/session_timeout.rb +4 -7
  41. data/lib/sorcery/controller.rb +1 -1
  42. data/lib/sorcery/model/submodules/reset_password.rb +2 -0
  43. data/lib/sorcery/model.rb +11 -6
  44. data/lib/sorcery/protocols/oauth2.rb +1 -0
  45. data/lib/sorcery/providers/battlenet.rb +51 -0
  46. data/lib/sorcery/providers/line.rb +20 -4
  47. data/lib/sorcery/providers/slack.rb +1 -1
  48. data/lib/sorcery/version.rb +1 -1
  49. data/sorcery.gemspec +4 -5
  50. data/spec/controllers/controller_oauth2_spec.rb +27 -9
  51. data/spec/controllers/controller_oauth_spec.rb +10 -4
  52. data/spec/controllers/controller_session_timeout_spec.rb +3 -1
  53. data/spec/controllers/controller_spec.rb +6 -0
  54. data/spec/providers/examples_spec.rb +17 -0
  55. data/spec/rails_app/app/controllers/application_controller.rb +2 -0
  56. data/spec/rails_app/app/controllers/sorcery_controller.rb +21 -1
  57. data/spec/rails_app/config/routes.rb +3 -0
  58. data/spec/shared_examples/user_reset_password_shared_examples.rb +12 -0
  59. data/spec/shared_examples/user_shared_examples.rb +2 -2
  60. data/spec/support/migration_helper.rb +12 -2
  61. data/spec/support/providers/examples.rb +11 -0
  62. metadata +28 -26
  63. data/.travis.yml +0 -8
@@ -1,13 +1,11 @@
1
1
  class SorceryCore < <%= migration_class_name %>
2
2
  def change
3
- create_table :<%= model_class_name.tableize %> do |t|
4
- t.string :email, null: false
3
+ create_table :<%= tableized_model_class %> do |t|
4
+ t.string :email, null: false, index: { unique: true }
5
5
  t.string :crypted_password
6
6
  t.string :salt
7
7
 
8
8
  t.timestamps null: false
9
9
  end
10
-
11
- add_index :<%= model_class_name.tableize %>, :email, unique: true
12
10
  end
13
11
  end
@@ -1,7 +1,7 @@
1
1
  class SorceryExternal < <%= migration_class_name %>
2
2
  def change
3
3
  create_table :authentications do |t|
4
- t.integer :<%= model_class_name.tableize.singularize %>_id, null: false
4
+ t.integer :<%= tableized_model_class.singularize %>_id, null: false
5
5
  t.string :provider, :uid, null: false
6
6
 
7
7
  t.timestamps null: false
@@ -1,9 +1,9 @@
1
1
  class SorceryMagicLogin < <%= migration_class_name %>
2
2
  def change
3
- add_column :<%= model_class_name.tableize %>, :magic_login_token, :string, default: nil
4
- add_column :<%= model_class_name.tableize %>, :magic_login_token_expires_at, :datetime, default: nil
5
- add_column :<%= model_class_name.tableize %>, :magic_login_email_sent_at, :datetime, default: nil
3
+ add_column :<%= tableized_model_class %>, :magic_login_token, :string, default: nil
4
+ add_column :<%= tableized_model_class %>, :magic_login_token_expires_at, :datetime, default: nil
5
+ add_column :<%= tableized_model_class %>, :magic_login_email_sent_at, :datetime, default: nil
6
6
 
7
- add_index :<%= model_class_name.tableize %>, :magic_login_token
7
+ add_index :<%= tableized_model_class %>, :magic_login_token
8
8
  end
9
9
  end
@@ -1,8 +1,8 @@
1
1
  class SorceryRememberMe < <%= migration_class_name %>
2
2
  def change
3
- add_column :<%= model_class_name.tableize %>, :remember_me_token, :string, default: nil
4
- add_column :<%= model_class_name.tableize %>, :remember_me_token_expires_at, :datetime, default: nil
3
+ add_column :<%= tableized_model_class %>, :remember_me_token, :string, default: nil
4
+ add_column :<%= tableized_model_class %>, :remember_me_token_expires_at, :datetime, default: nil
5
5
 
6
- add_index :<%= model_class_name.tableize %>, :remember_me_token
6
+ add_index :<%= tableized_model_class %>, :remember_me_token
7
7
  end
8
8
  end
@@ -1,10 +1,10 @@
1
1
  class SorceryResetPassword < <%= migration_class_name %>
2
2
  def change
3
- add_column :<%= model_class_name.tableize %>, :reset_password_token, :string, default: nil
4
- add_column :<%= model_class_name.tableize %>, :reset_password_token_expires_at, :datetime, default: nil
5
- add_column :<%= model_class_name.tableize %>, :reset_password_email_sent_at, :datetime, default: nil
6
- add_column :<%= model_class_name.tableize %>, :access_count_to_reset_password_page, :integer, default: 0
3
+ add_column :<%= tableized_model_class %>, :reset_password_token, :string, default: nil
4
+ add_column :<%= tableized_model_class %>, :reset_password_token_expires_at, :datetime, default: nil
5
+ add_column :<%= tableized_model_class %>, :reset_password_email_sent_at, :datetime, default: nil
6
+ add_column :<%= tableized_model_class %>, :access_count_to_reset_password_page, :integer, default: 0
7
7
 
8
- add_index :<%= model_class_name.tableize %>, :reset_password_token
8
+ add_index :<%= tableized_model_class %>, :reset_password_token
9
9
  end
10
10
  end
@@ -1,9 +1,9 @@
1
1
  class SorceryUserActivation < <%= migration_class_name %>
2
2
  def change
3
- add_column :<%= model_class_name.tableize %>, :activation_state, :string, default: nil
4
- add_column :<%= model_class_name.tableize %>, :activation_token, :string, default: nil
5
- add_column :<%= model_class_name.tableize %>, :activation_token_expires_at, :datetime, default: nil
3
+ add_column :<%= tableized_model_class %>, :activation_state, :string, default: nil
4
+ add_column :<%= tableized_model_class %>, :activation_token, :string, default: nil
5
+ add_column :<%= tableized_model_class %>, :activation_token_expires_at, :datetime, default: nil
6
6
 
7
- add_index :<%= model_class_name.tableize %>, :activation_token
7
+ add_index :<%= tableized_model_class %>, :activation_token
8
8
  end
9
9
  end
@@ -12,7 +12,7 @@ module Sorcery
12
12
 
13
13
  def save(options = {})
14
14
  mthd = options.delete(:raise_on_failure) ? :save! : :save
15
- @model.send(mthd, options)
15
+ @model.send(mthd, **options)
16
16
  end
17
17
 
18
18
  def increment(field)
@@ -35,7 +35,7 @@ module Sorcery
35
35
  end
36
36
 
37
37
  def define_callback(time, event, method_name, options = {})
38
- @klass.send "#{time}_#{event}", method_name, options.slice(:if, :on)
38
+ @klass.send "#{time}_#{event}", method_name, **options.slice(:if, :on)
39
39
  end
40
40
 
41
41
  def find_by_oauth_credentials(provider, uid)
@@ -32,7 +32,7 @@ module Sorcery
32
32
  end
33
33
 
34
34
  def define_callback(time, event, method_name, options = {})
35
- @klass.send callback_name(time, event, options), method_name, options.slice(:if)
35
+ @klass.send callback_name(time, event, options), method_name, **options.slice(:if)
36
36
  end
37
37
 
38
38
  def callback_name(time, event, options)
@@ -25,12 +25,12 @@ module Sorcery
25
25
  :@user_class => nil,
26
26
  :@submodules => [],
27
27
  :@not_authenticated_action => :not_authenticated,
28
- :@login_sources => [],
29
- :@after_login => [],
30
- :@after_failed_login => [],
31
- :@before_logout => [],
32
- :@after_logout => [],
33
- :@after_remember_me => [],
28
+ :@login_sources => Set.new,
29
+ :@after_login => Set.new,
30
+ :@after_failed_login => Set.new,
31
+ :@before_logout => Set.new,
32
+ :@after_logout => Set.new,
33
+ :@after_remember_me => Set.new,
34
34
  :@save_return_to_url => true,
35
35
  :@cookie_domain => nil
36
36
  }
@@ -30,16 +30,11 @@ module Sorcery
30
30
  end
31
31
  merge_activity_logging_defaults!
32
32
  end
33
- # FIXME: There is likely a more elegant way to safeguard these callbacks.
34
- unless Config.after_login.include?(:register_login_time_to_db)
35
- Config.after_login << :register_login_time_to_db
36
- end
37
- unless Config.after_login.include?(:register_last_ip_address)
38
- Config.after_login << :register_last_ip_address
39
- end
40
- unless Config.before_logout.include?(:register_logout_time_to_db)
41
- Config.before_logout << :register_logout_time_to_db
42
- end
33
+
34
+ Config.after_login << :register_login_time_to_db
35
+ Config.after_login << :register_last_ip_address
36
+ Config.before_logout << :register_logout_time_to_db
37
+
43
38
  base.after_action :register_last_activity_time_to_db
44
39
  end
45
40
 
@@ -10,13 +10,9 @@ module Sorcery
10
10
  module BruteForceProtection
11
11
  def self.included(base)
12
12
  base.send(:include, InstanceMethods)
13
- # FIXME: There is likely a more elegant way to safeguard these callbacks.
14
- unless Config.after_login.include?(:reset_failed_logins_count!)
15
- Config.after_login << :reset_failed_logins_count!
16
- end
17
- unless Config.after_failed_login.include?(:update_failed_logins_count!)
18
- Config.after_failed_login << :update_failed_logins_count!
19
- end
13
+
14
+ Config.after_login << :reset_failed_logins_count!
15
+ Config.after_failed_login << :update_failed_logins_count!
20
16
  end
21
17
 
22
18
  module InstanceMethods
@@ -27,6 +27,7 @@ module Sorcery
27
27
  require 'sorcery/providers/auth0'
28
28
  require 'sorcery/providers/line'
29
29
  require 'sorcery/providers/discord'
30
+ require 'sorcery/providers/battlenet'
30
31
 
31
32
  Config.module_eval do
32
33
  class << self
@@ -39,7 +40,7 @@ module Sorcery
39
40
  providers.each do |name|
40
41
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
41
42
  def self.#{name}
42
- @#{name} ||= Sorcery::Providers.const_get('#{name}'.to_s.classify).new
43
+ @#{name} ||= Sorcery::Providers.const_get('#{name}'.to_s.camelcase).new
43
44
  end
44
45
  RUBY
45
46
  end
@@ -117,7 +118,7 @@ module Sorcery
117
118
  # sends user to authenticate at the provider's website.
118
119
  # after authentication the user is redirected to the callback defined in the provider config
119
120
  def login_at(provider_name, args = {})
120
- redirect_to sorcery_login_url(provider_name, args)
121
+ redirect_to sorcery_login_url(provider_name, args), allow_other_host: true
121
122
  end
122
123
 
123
124
  # tries to login the user from provider's callback
@@ -19,10 +19,8 @@ module Sorcery
19
19
  end
20
20
  merge_http_basic_auth_defaults!
21
21
  end
22
- # FIXME: There is likely a more elegant way to safeguard these callbacks.
23
- unless Config.login_sources.include?(:login_from_basic_auth)
24
- Config.login_sources << :login_from_basic_auth
25
- end
22
+
23
+ Config.login_sources << :login_from_basic_auth
26
24
  end
27
25
 
28
26
  module InstanceMethods
@@ -17,13 +17,9 @@ module Sorcery
17
17
  end
18
18
  merge_remember_me_defaults!
19
19
  end
20
- # FIXME: There is likely a more elegant way to safeguard these callbacks.
21
- unless Config.login_sources.include?(:login_from_cookie)
22
- Config.login_sources << :login_from_cookie
23
- end
24
- unless Config.before_logout.include?(:forget_me!)
25
- Config.before_logout << :forget_me!
26
- end
20
+
21
+ Config.login_sources << :login_from_cookie
22
+ Config.before_logout << :forget_me!
27
23
  end
28
24
 
29
25
  module InstanceMethods
@@ -23,13 +23,10 @@ module Sorcery
23
23
  end
24
24
  merge_session_timeout_defaults!
25
25
  end
26
- # FIXME: There is likely a more elegant way to safeguard these callbacks.
27
- unless Config.after_login.include?(:register_login_time)
28
- Config.after_login << :register_login_time
29
- end
30
- unless Config.after_remember_me.include?(:register_login_time)
31
- Config.after_remember_me << :register_login_time
32
- end
26
+
27
+ Config.after_login << :register_login_time
28
+ Config.after_remember_me << :register_login_time
29
+
33
30
  base.prepend_before_action :validate_session
34
31
  end
35
32
 
@@ -165,7 +165,7 @@ module Sorcery
165
165
  def user_class
166
166
  @user_class ||= Config.user_class.to_s.constantize
167
167
  rescue NameError
168
- raise ArgumentError, 'You have incorrectly defined user_class or have forgotten to define it in intitializer file (config.user_class = \'User\').'
168
+ raise ArgumentError, 'You have incorrectly defined user_class or have forgotten to define it in the initializer file (config.user_class = \'User\').'
169
169
  end
170
170
  end
171
171
  end
@@ -131,6 +131,8 @@ module Sorcery
131
131
  end
132
132
 
133
133
  def change_password!(new_password)
134
+ raise ArgumentError, 'Blank password passed to change_password!' if new_password.blank?
135
+
134
136
  change_password(new_password, raise_on_failure: true)
135
137
  end
136
138
 
data/lib/sorcery/model.rb CHANGED
@@ -131,6 +131,14 @@ module Sorcery
131
131
  @sorcery_config.encryption_provider.encrypt(*tokens)
132
132
  end
133
133
 
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
137
+ @sorcery_config.encryption_provider.stretches = @sorcery_config.stretches if @sorcery_config.encryption_provider.respond_to?(:stretches) && @sorcery_config.stretches
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
140
+ end
141
+
134
142
  protected
135
143
 
136
144
  def authentication_response(options = {})
@@ -139,12 +147,6 @@ module Sorcery
139
147
  options[:return_value]
140
148
  end
141
149
 
142
- def set_encryption_attributes
143
- @sorcery_config.encryption_provider.stretches = @sorcery_config.stretches if @sorcery_config.encryption_provider.respond_to?(:stretches) && @sorcery_config.stretches
144
- @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
145
- @sorcery_config.encryption_provider.pepper = @sorcery_config.pepper if @sorcery_config.encryption_provider.respond_to?(:pepper) && @sorcery_config.pepper
146
- end
147
-
148
150
  def add_config_inheritance
149
151
  class_eval do
150
152
  def self.inherited(subclass)
@@ -177,6 +179,9 @@ module Sorcery
177
179
  crypted = send(sorcery_config.crypted_password_attribute_name)
178
180
  return crypted == pass if sorcery_config.encryption_provider.nil?
179
181
 
182
+ # Ensure encryption provider is using configured values
183
+ self.class.set_encryption_attributes
184
+
180
185
  salt = send(sorcery_config.salt_attribute_name) unless sorcery_config.salt_attribute_name.nil?
181
186
 
182
187
  sorcery_config.encryption_provider.matches?(crypted, pass, salt)
@@ -32,6 +32,7 @@ module Sorcery
32
32
  def build_client(options = {})
33
33
  defaults = {
34
34
  site: @site,
35
+ auth_scheme: :request_body,
35
36
  ssl: { ca_file: Sorcery::Controller::Config.ca_file }
36
37
  }
37
38
  ::OAuth2::Client.new(
@@ -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
@@ -9,15 +9,16 @@ module Sorcery
9
9
  class Line < Base
10
10
  include Protocols::Oauth2
11
11
 
12
- attr_accessor :token_url, :user_info_path, :auth_path
12
+ attr_accessor :token_url, :user_info_path, :auth_path, :scope, :bot_prompt
13
13
 
14
14
  def initialize
15
15
  super
16
16
 
17
17
  @site = 'https://access.line.me'
18
18
  @user_info_path = 'https://api.line.me/v2/profile'
19
- @token_url = 'https://api.line.me/v2/oauth/accessToken'
20
- @auth_path = 'dialog/oauth/weblogin'
19
+ @token_url = 'https://api.line.me/oauth2/v2.1/token'
20
+ @auth_path = 'oauth2/v2.1/authorize'
21
+ @scope = 'profile'
21
22
  end
22
23
 
23
24
  def get_user_hash(access_token)
@@ -34,13 +35,28 @@ module Sorcery
34
35
  @state = SecureRandom.hex(16)
35
36
  authorize_url(authorize_url: auth_path)
36
37
  end
38
+
39
+ # overrides oauth2#authorize_url to add bot_prompt query.
40
+ def authorize_url(options = {})
41
+ options.merge!({
42
+ connection_opts: { params: { bot_prompt: bot_prompt } }
43
+ }) if bot_prompt.present?
44
+
45
+ super(options)
46
+ end
47
+
37
48
  # tries to login the user from access token
38
49
  def process_callback(params, _session)
39
50
  args = {}.tap do |a|
40
51
  a[:code] = params[:code] if params[:code]
41
52
  end
42
53
 
43
- get_access_token(args, token_url: token_url, token_method: :post)
54
+ get_access_token(
55
+ args,
56
+ token_url: token_url,
57
+ token_method: :post,
58
+ grant_type: 'authorization_code'
59
+ )
44
60
  end
45
61
  end
46
62
  end
@@ -18,7 +18,7 @@ module Sorcery
18
18
  end
19
19
 
20
20
  def get_user_hash(access_token)
21
- response = access_token.get(user_info_path, params: { token: access_token.token })
21
+ response = access_token.get(user_info_path)
22
22
  auth_hash(access_token).tap do |h|
23
23
  h[:user_info] = JSON.parse(response.body)
24
24
  h[:user_info]['email'] = h[:user_info]['user']['email']
@@ -1,3 +1,3 @@
1
1
  module Sorcery
2
- VERSION = '0.15.0'.freeze
2
+ VERSION = '0.17.0'.freeze
3
3
  end
data/sorcery.gemspec CHANGED
@@ -14,8 +14,7 @@ Gem::Specification.new do |s|
14
14
  'Josh Buker'
15
15
  ]
16
16
  s.email = [
17
- 'chase.gilliam@gmail.com',
18
- 'contact@joshbuker.com'
17
+ 'crypto@joshbuker.com'
19
18
  ]
20
19
 
21
20
  # TODO: Cleanup formatting.
@@ -35,11 +34,11 @@ Gem::Specification.new do |s|
35
34
  s.required_ruby_version = '>= 2.4.9'
36
35
 
37
36
  s.add_dependency 'bcrypt', '~> 3.1'
38
- s.add_dependency 'oauth', '~> 0.4', '>= 0.4.4'
39
- s.add_dependency 'oauth2', '~> 1.0', '>= 0.8.0'
37
+ s.add_dependency 'oauth', '>= 0.6'
38
+ s.add_dependency 'oauth2', '~> 2.0'
40
39
 
41
40
  s.add_development_dependency 'byebug', '~> 10.0.0'
42
- s.add_development_dependency 'rspec-rails', '~> 3.7.0'
41
+ s.add_development_dependency 'rspec-rails'
43
42
  s.add_development_dependency 'rubocop'
44
43
  s.add_development_dependency 'simplecov', '>= 0.3.8'
45
44
  s.add_development_dependency 'test-unit', '~> 3.2.0'
@@ -32,14 +32,14 @@ describe SorceryController, active_record: true, type: :controller do
32
32
  sorcery_model_property_set(:authentications_class, Authentication)
33
33
  sorcery_controller_external_property_set(:facebook, :user_info_mapping, username: 'name')
34
34
 
35
- expect(User).to receive(:create_from_provider).with('facebook', '123', username: 'Noam Ben Ari')
35
+ expect(User).to receive(:create_from_provider).with('facebook', '123', { username: 'Noam Ben Ari' })
36
36
  get :test_create_from_provider, params: { provider: 'facebook' }
37
37
  end
38
38
 
39
39
  it 'supports nested attributes' do
40
40
  sorcery_model_property_set(:authentications_class, Authentication)
41
41
  sorcery_controller_external_property_set(:facebook, :user_info_mapping, username: 'hometown/name')
42
- expect(User).to receive(:create_from_provider).with('facebook', '123', username: 'Haifa, Israel')
42
+ expect(User).to receive(:create_from_provider).with('facebook', '123', { username: 'Haifa, Israel' })
43
43
 
44
44
  get :test_create_from_provider, params: { provider: 'facebook' }
45
45
  end
@@ -48,7 +48,7 @@ describe SorceryController, active_record: true, type: :controller do
48
48
  sorcery_model_property_set(:authentications_class, Authentication)
49
49
  sorcery_controller_external_property_set(:facebook, :user_info_mapping, username: 'name', created_at: 'does/not/exist')
50
50
 
51
- expect(User).to receive(:create_from_provider).with('facebook', '123', username: 'Noam Ben Ari')
51
+ expect(User).to receive(:create_from_provider).with('facebook', '123', { username: 'Noam Ben Ari' })
52
52
 
53
53
  get :test_create_from_provider, params: { provider: 'facebook' }
54
54
  end
@@ -59,7 +59,7 @@ describe SorceryController, active_record: true, type: :controller do
59
59
  sorcery_controller_external_property_set(:facebook, :user_info_mapping, username: 'name')
60
60
 
61
61
  u = double('user')
62
- expect(User).to receive(:create_from_provider).with('facebook', '123', username: 'Noam Ben Ari').and_return(u).and_yield(u)
62
+ expect(User).to receive(:create_from_provider).with('facebook', '123', { username: 'Noam Ben Ari' }).and_return(u).and_yield(u)
63
63
  # test_create_from_provider_with_block in controller will check for uniqueness of username
64
64
  get :test_create_from_provider_with_block, params: { provider: 'facebook' }
65
65
  end
@@ -116,12 +116,21 @@ describe SorceryController, active_record: true, type: :controller do
116
116
  end
117
117
 
118
118
  context 'when callback_url begin with http://' do
119
+ before do
120
+ sorcery_controller_external_property_set(:facebook, :callback_url, '/oauth/twitter/callback')
121
+ sorcery_controller_external_property_set(:facebook, :api_version, 'v2.2')
122
+ end
123
+
119
124
  it 'login_at redirects correctly' do
120
125
  create_new_user
121
126
  get :login_at_test_facebook
122
127
  expect(response).to be_a_redirect
123
128
  expect(response).to redirect_to("https://www.facebook.com/v2.2/dialog/oauth?client_id=#{::Sorcery::Controller::Config.facebook.key}&display=page&redirect_uri=http%3A%2F%2Ftest.host%2Foauth%2Ftwitter%2Fcallback&response_type=code&scope=email&state")
124
129
  end
130
+
131
+ after do
132
+ sorcery_controller_external_property_set(:facebook, :callback_url, 'http://blabla.com')
133
+ end
125
134
  end
126
135
 
127
136
  it "'login_from' logins if user exists" do
@@ -155,7 +164,7 @@ describe SorceryController, active_record: true, type: :controller do
155
164
  expect(flash[:notice]).to eq 'Success!'
156
165
  end
157
166
 
158
- %i[github google liveid vk salesforce paypal slack wechat microsoft instagram auth0 discord].each do |provider|
167
+ %i[github google liveid vk salesforce paypal slack wechat microsoft instagram auth0 discord battlenet].each do |provider|
159
168
  describe "with #{provider}" do
160
169
  it 'login_at redirects correctly' do
161
170
  get :"login_at_test_#{provider}"
@@ -218,6 +227,7 @@ describe SorceryController, active_record: true, type: :controller do
218
227
  auth0
219
228
  line
220
229
  discord
230
+ battlenet
221
231
  ]
222
232
  )
223
233
 
@@ -265,6 +275,9 @@ describe SorceryController, active_record: true, type: :controller do
265
275
  sorcery_controller_external_property_set(:discord, :key, 'eYVNBjBDi33aa9GkA3w')
266
276
  sorcery_controller_external_property_set(:discord, :secret, 'XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8')
267
277
  sorcery_controller_external_property_set(:discord, :callback_url, 'http://blabla.com')
278
+ sorcery_controller_external_property_set(:battlenet, :key, '4c43d4862c774ca5bbde89873bf0d338')
279
+ sorcery_controller_external_property_set(:battlenet, :secret, 'TxY7IwKOykACd8kUxPyVGTqBs44UBDdX')
280
+ sorcery_controller_external_property_set(:battlenet, :callback_url, 'http://blabla.com')
268
281
  end
269
282
 
270
283
  after(:each) do
@@ -287,7 +300,7 @@ describe SorceryController, active_record: true, type: :controller do
287
300
  expect(ActionMailer::Base.deliveries.size).to eq old_size
288
301
  end
289
302
 
290
- %i[github google liveid vk salesforce paypal wechat microsoft instagram auth0 discord].each do |provider|
303
+ %i[github google liveid vk salesforce paypal wechat microsoft instagram auth0 discord battlenet].each do |provider|
291
304
  it "does not send activation email to external users (#{provider})" do
292
305
  old_size = ActionMailer::Base.deliveries.size
293
306
  create_new_external_user provider
@@ -311,7 +324,7 @@ describe SorceryController, active_record: true, type: :controller do
311
324
  sorcery_reload!(%i[activity_logging external])
312
325
  end
313
326
 
314
- %w[facebook github google liveid vk salesforce slack discord].each do |provider|
327
+ %w[facebook github google liveid vk salesforce slack discord battlenet].each do |provider|
315
328
  context "when #{provider}" do
316
329
  before(:each) do
317
330
  sorcery_controller_property_set(:register_login_time, true)
@@ -350,7 +363,7 @@ describe SorceryController, active_record: true, type: :controller do
350
363
 
351
364
  let(:user) { double('user', id: 42) }
352
365
 
353
- %w[facebook github google liveid vk salesforce slack discord].each do |provider|
366
+ %w[facebook github google liveid vk salesforce slack discord battlenet].each do |provider|
354
367
  context "when #{provider}" do
355
368
  before(:each) do
356
369
  sorcery_model_property_set(:authentications_class, Authentication)
@@ -484,6 +497,7 @@ describe SorceryController, active_record: true, type: :controller do
484
497
  auth0
485
498
  line
486
499
  discord
500
+ battlenet
487
501
  ]
488
502
  )
489
503
  sorcery_controller_external_property_set(:facebook, :key, 'eYVNBjBDi33aa9GkA3w')
@@ -529,6 +543,9 @@ describe SorceryController, active_record: true, type: :controller do
529
543
  sorcery_controller_external_property_set(:discord, :key, 'eYVNBjBDi33aa9GkA3w')
530
544
  sorcery_controller_external_property_set(:discord, :secret, 'XpbeSdCoaKSmQGSeokz5qcUATClRW5u08QWNfv71N8')
531
545
  sorcery_controller_external_property_set(:discord, :callback_url, 'http://blabla.com')
546
+ sorcery_controller_external_property_set(:battlenet, :key, '4c43d4862c774ca5bbde89873bf0d338')
547
+ sorcery_controller_external_property_set(:battlenet, :secret, 'TxY7IwKOykACd8kUxPyVGTqBs44UBDdX')
548
+ sorcery_controller_external_property_set(:battlenet, :callback_url, 'http://blabla.com')
532
549
  end
533
550
 
534
551
  def provider_url(provider)
@@ -544,7 +561,8 @@ describe SorceryController, active_record: true, type: :controller do
544
561
  microsoft: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=#{::Sorcery::Controller::Config.microsoft.key}&display&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=openid+email+https%3A%2F%2Fgraph.microsoft.com%2FUser.Read&state",
545
562
  instagram: "https://api.instagram.com/oauth/authorize?client_id=#{::Sorcery::Controller::Config.instagram.key}&display&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=#{::Sorcery::Controller::Config.instagram.scope}&state",
546
563
  auth0: "https://sorcery-test.auth0.com/authorize?client_id=#{::Sorcery::Controller::Config.auth0.key}&display&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=openid+profile+email&state",
547
- discord: "https://discordapp.com/api/oauth2/authorize?client_id=#{::Sorcery::Controller::Config.discord.key}&display&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=identify&state"
564
+ discord: "https://discordapp.com/api/oauth2/authorize?client_id=#{::Sorcery::Controller::Config.discord.key}&display&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=identify&state",
565
+ battlenet: "https://eu.battle.net/oauth/authorize?client_id=#{::Sorcery::Controller::Config.battlenet.key}&display&redirect_uri=http%3A%2F%2Fblabla.com&response_type=code&scope=openid&state"
548
566
  }[provider]
549
567
  end
550
568
  end