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
@@ -0,0 +1,73 @@
1
+ module Sorcery
2
+ module Providers
3
+ # This class adds support for OAuth with Instagram.com.
4
+ class Instagram < Base
5
+ include Protocols::Oauth2
6
+
7
+ attr_accessor :access_permissions, :token_url,
8
+ :authorization_path, :user_info_path,
9
+ :scope, :user_info_fields
10
+
11
+ def initialize
12
+ super
13
+
14
+ @site = 'https://api.instagram.com'
15
+ @token_url = '/oauth/access_token'
16
+ @authorization_path = '/oauth/authorize/'
17
+ @user_info_path = '/v1/users/self'
18
+ @scope = 'basic'
19
+ end
20
+
21
+ def self.included(base)
22
+ base.extend Sorcery::Providers
23
+ end
24
+
25
+ # provider implements method to build Oauth client
26
+ def login_url(_params, _session)
27
+ authorize_url(token_url: @token_url)
28
+ end
29
+
30
+ # overrides oauth2#authorize_url to allow customized scope.
31
+ def authorize_url(opts = {})
32
+ @scope = access_permissions.present? ? access_permissions.join(' ') : scope
33
+ super(opts.merge(token_url: @token_url))
34
+ end
35
+
36
+ # pass oauth2 param `code` provided by instgrm server
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
+ )
47
+ end
48
+
49
+ # see `user_info_mapping` in config/initializer,
50
+ # given `user_info_mapping` to specify
51
+ # {:db_attribute_name => 'instagram_attr_name'}
52
+ # so that Sorcery can build AR model from attr names
53
+ #
54
+ # NOTE: instead of just getting the user info
55
+ # from the access_token (which already returns them),
56
+ # testing strategy relies on querying user_info_path
57
+ def get_user_hash(access_token)
58
+ call_api_params = {
59
+ access_token: access_token.token,
60
+ client_id: access_token[:client_id]
61
+ }
62
+ response = access_token.get(
63
+ "#{user_info_path}?#{call_api_params.to_param}"
64
+ )
65
+
66
+ user_attrs = {}
67
+ user_attrs[:user_info] = JSON.parse(response.body)['data']
68
+ user_attrs[:uid] = user_attrs[:user_info]['id']
69
+ user_attrs
70
+ end
71
+ end
72
+ end
73
+ end
@@ -7,31 +7,27 @@ module Sorcery
7
7
  # ...
8
8
  #
9
9
  class Jira < Base
10
-
11
10
  include Protocols::Oauth
12
11
 
13
12
  attr_accessor :access_token_path, :authorize_path, :request_token_path,
14
13
  :user_info_path, :site, :signature_method, :private_key_file, :callback_url
15
14
 
16
-
17
15
  def initialize
18
16
  @configuration = {
19
- authorize_path: '/authorize',
20
- request_token_path: '/request-token',
21
- access_token_path: '/access-token'
17
+ authorize_path: '/authorize',
18
+ request_token_path: '/request-token',
19
+ access_token_path: '/access-token'
22
20
  }
23
21
  @user_info_path = '/users/me'
24
22
  end
25
23
 
26
24
  # Override included get_consumer method to provide authorize_path
27
- #read extra configurations
25
+ # read extra configurations
28
26
  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
- })
27
+ @configuration = @configuration.merge(site: site,
28
+ signature_method: signature_method,
29
+ consumer_key: key,
30
+ private_key_file: private_key_file)
35
31
  ::OAuth::Consumer.new(@key, @secret, @configuration)
36
32
  end
37
33
 
@@ -46,13 +42,13 @@ module Sorcery
46
42
 
47
43
  # calculates and returns the url to which the user should be redirected,
48
44
  # to get authenticated at the external provider's site.
49
- def login_url(params, session)
45
+ def login_url(_params, session)
50
46
  req_token = get_request_token
51
47
  session[:request_token] = req_token.token
52
48
  session[:request_token_secret] = req_token.secret
53
49
 
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
50
+ # it was like that -> redirect_to authorize_url({ request_token: req_token.token, request_token_secret: req_token.secret })
51
+ # for some reason Jira does not need these parameters
56
52
 
57
53
  get_request_token(
58
54
  session[:request_token],
@@ -68,10 +64,9 @@ module Sorcery
68
64
  request_token_secret: session[:request_token_secret]
69
65
  }
70
66
 
71
- args.merge!({ code: params[:code] }) if params[:code]
67
+ args[:code] = params[:code] if params[:code]
72
68
  get_access_token(args)
73
69
  end
74
-
75
70
  end
76
71
  end
77
72
  end
@@ -0,0 +1,63 @@
1
+ module Sorcery
2
+ module Providers
3
+ # This class adds support for OAuth with line.com.
4
+ #
5
+ # config.line.key = <key>
6
+ # config.line.secret = <secret>
7
+ # ...
8
+ #
9
+ class Line < Base
10
+ include Protocols::Oauth2
11
+
12
+ attr_accessor :token_url, :user_info_path, :auth_path, :scope, :bot_prompt
13
+
14
+ def initialize
15
+ super
16
+
17
+ @site = 'https://access.line.me'
18
+ @user_info_path = 'https://api.line.me/v2/profile'
19
+ @token_url = 'https://api.line.me/oauth2/v2.1/token'
20
+ @auth_path = 'oauth2/v2.1/authorize'
21
+ @scope = 'profile'
22
+ end
23
+
24
+ def get_user_hash(access_token)
25
+ response = access_token.get(user_info_path)
26
+ auth_hash(access_token).tap do |h|
27
+ h[:user_info] = JSON.parse(response.body)
28
+ h[:uid] = h[:user_info]['userId'].to_s
29
+ end
30
+ end
31
+
32
+ # calculates and returns the url to which the user should be redirected,
33
+ # to get authenticated at the external provider's site.
34
+ def login_url(_params, _session)
35
+ @state = SecureRandom.hex(16)
36
+ authorize_url(authorize_url: auth_path)
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
+
48
+ # tries to login the user from access token
49
+ def process_callback(params, _session)
50
+ args = {}.tap do |a|
51
+ a[:code] = params[:code] if params[:code]
52
+ end
53
+
54
+ get_access_token(
55
+ args,
56
+ token_url: token_url,
57
+ token_method: :post,
58
+ grant_type: 'authorization_code'
59
+ )
60
+ end
61
+ end
62
+ end
63
+ end
@@ -1,66 +1,75 @@
1
1
  module Sorcery
2
2
  module Providers
3
- # This class adds support for OAuth with Linkedin.com.
3
+ # This class adds support for OAuth with LinkedIn.
4
4
  #
5
5
  # config.linkedin.key = <key>
6
6
  # config.linkedin.secret = <secret>
7
7
  # ...
8
8
  #
9
9
  class Linkedin < Base
10
+ include Protocols::Oauth2
10
11
 
11
- include Protocols::Oauth
12
-
13
- attr_accessor :authorize_path, :access_permissions, :access_token_path,
14
- :request_token_path, :user_info_fields, :user_info_path
12
+ attr_accessor :auth_url, :scope, :token_url, :user_info_url, :email_info_url
15
13
 
16
14
  def initialize
17
- @configuration = {
18
- site: 'https://api.linkedin.com',
19
- authorize_path: '/uas/oauth/authenticate',
20
- request_token_path: '/uas/oauth/requestToken',
21
- access_token_path: '/uas/oauth/accessToken'
22
- }
23
- @user_info_path = '/v1/people/~'
24
- end
15
+ super
25
16
 
26
- # Override included get_consumer method to provide authorize_path
27
- def get_consumer
28
- # Add access permissions to request token path
29
- @configuration[:request_token_path] += '?scope=' + access_permissions.join('+') unless access_permissions.blank? or @configuration[:request_token_path].include? '?scope='
30
- ::OAuth::Consumer.new(@key, @secret, @configuration)
17
+ @site = 'https://api.linkedin.com'
18
+ @auth_url = '/oauth/v2/authorization'
19
+ @token_url = '/oauth/v2/accessToken'
20
+ @user_info_url = 'https://api.linkedin.com/v2/me'
21
+ @email_info_url = 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))'
22
+ @scope = 'r_liteprofile r_emailaddress'
23
+ @state = SecureRandom.hex(16)
31
24
  end
32
25
 
33
26
  def get_user_hash(access_token)
34
- fields = self.user_info_fields.join(',')
35
- response = access_token.get("#{@user_info_path}:(#{fields})", 'x-li-format' => 'json')
27
+ user_info = get_user_info(access_token)
36
28
 
37
29
  auth_hash(access_token).tap do |h|
38
- h[:user_info] = JSON.parse(response.body)
39
- h[:uid] = h[:user_info]['id'].to_s
30
+ h[:user_info] = user_info
31
+ h[:uid] = h[:user_info]['id']
40
32
  end
41
33
  end
42
34
 
43
35
  # calculates and returns the url to which the user should be redirected,
44
36
  # to get authenticated at the external provider's site.
45
- def login_url(params, session)
46
- req_token = get_request_token
47
- session[:request_token] = req_token.token
48
- session[:request_token_secret] = req_token.secret
49
- authorize_url({ request_token: req_token.token, request_token_secret: req_token.secret })
37
+ def login_url(_params, _session)
38
+ authorize_url(authorize_url: auth_url)
50
39
  end
51
40
 
52
41
  # tries to login the user from access token
53
- def process_callback(params, session)
54
- args = {
55
- oauth_verifier: params[:oauth_verifier],
56
- request_token: session[:request_token],
57
- request_token_secret: session[:request_token_secret]
58
- }
42
+ def process_callback(params, _session)
43
+ args = {}.tap do |a|
44
+ a[:code] = params[:code] if params[:code]
45
+ end
59
46
 
60
- args.merge!({ code: params[:code] }) if params[:code]
61
- get_access_token(args)
47
+ get_access_token(args, token_url: token_url, token_method: :post)
62
48
  end
63
49
 
50
+ def get_user_info(access_token)
51
+ response = access_token.get(user_info_url)
52
+ user_info = JSON.parse(response.body)
53
+
54
+ if email_in_scope?
55
+ email = fetch_email(access_token)
56
+
57
+ return user_info.merge(email)
58
+ end
59
+
60
+ user_info
61
+ end
62
+
63
+ def email_in_scope?
64
+ scope.include?('r_emailaddress')
65
+ end
66
+
67
+ def fetch_email(access_token)
68
+ email_response = access_token.get(email_info_url)
69
+ email_info = JSON.parse(email_response.body)['elements'].first
70
+
71
+ email_info['handle~']
72
+ end
64
73
  end
65
74
  end
66
75
  end
@@ -7,7 +7,6 @@ module Sorcery
7
7
  # ...
8
8
  #
9
9
  class Liveid < Base
10
-
11
10
  include Protocols::Oauth2
12
11
 
13
12
  attr_accessor :auth_url, :token_path, :user_info_url, :scope
@@ -34,20 +33,18 @@ module Sorcery
34
33
 
35
34
  # calculates and returns the url to which the user should be redirected,
36
35
  # to get authenticated at the external provider's site.
37
- def login_url(params, session)
38
- self.authorize_url({ authorize_url: auth_url })
36
+ def login_url(_params, _session)
37
+ authorize_url(authorize_url: auth_url)
39
38
  end
40
39
 
41
40
  # tries to login the user from access token
42
- def process_callback(params, session)
41
+ def process_callback(params, _session)
43
42
  args = {}.tap do |a|
44
43
  a[:code] = params[:code] if params[:code]
45
44
  end
46
45
 
47
- get_access_token(args, access_token_path: token_path,
48
- access_token_method: :post)
46
+ get_access_token(args, access_token_path: token_path, access_token_method: :post)
49
47
  end
50
-
51
48
  end
52
49
  end
53
50
  end
@@ -0,0 +1,59 @@
1
+ module Sorcery
2
+ module Providers
3
+ # This class adds support for OAuth with Microsoft Graph.
4
+ #
5
+ # config.microsoft.key = <key>
6
+ # config.microsoft.secret = <secret>
7
+ # ...
8
+ #
9
+ class Microsoft < Base
10
+ include Protocols::Oauth2
11
+
12
+ attr_accessor :auth_url, :scope, :token_url, :user_info_url
13
+
14
+ def initialize
15
+ super
16
+
17
+ @site = 'https://login.microsoftonline.com'
18
+ @auth_url = '/common/oauth2/v2.0/authorize'
19
+ @token_url = '/common/oauth2/v2.0/token'
20
+ @user_info_url = 'https://graph.microsoft.com/v1.0/me'
21
+ @scope = 'openid email https://graph.microsoft.com/User.Read'
22
+ @state = SecureRandom.hex(16)
23
+ end
24
+
25
+ def authorize_url(options = {})
26
+ oauth_params = {
27
+ client_id: @key,
28
+ response_type: 'code'
29
+ }
30
+ options.merge!(oauth_params)
31
+ super(options)
32
+ end
33
+
34
+ def get_user_hash(access_token)
35
+ response = access_token.get(user_info_url)
36
+
37
+ auth_hash(access_token).tap do |h|
38
+ h[:user_info] = JSON.parse(response.body)
39
+ h[:uid] = h[:user_info]['id']
40
+ end
41
+ end
42
+
43
+ # calculates and returns the url to which the user should be redirected,
44
+ # to get authenticated at the external provider's site.
45
+ def login_url(_params, _session)
46
+ authorize_url(authorize_url: auth_url)
47
+ end
48
+
49
+ # tries to login the user from access token
50
+ def process_callback(params, _session)
51
+ args = {}.tap do |a|
52
+ a[:code] = params[:code] if params[:code]
53
+ end
54
+
55
+ get_access_token(args, token_url: token_url, token_method: :post)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,60 @@
1
+ module Sorcery
2
+ module Providers
3
+ # This class adds support for OAuth with paypal.com.
4
+ #
5
+ # config.paypal.key = <key>
6
+ # config.paypal.secret = <secret>
7
+ # ...
8
+ #
9
+ class Paypal < Base
10
+ include Protocols::Oauth2
11
+
12
+ attr_accessor :auth_url, :scope, :token_url, :user_info_url
13
+
14
+ def initialize
15
+ super
16
+
17
+ @scope = 'openid email'
18
+ @site = 'https://api.paypal.com'
19
+ @auth_url = 'https://www.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize'
20
+ @user_info_url = 'https://api.paypal.com/v1/identity/openidconnect/userinfo?schema=openid'
21
+ @token_url = 'https://api.paypal.com/v1/identity/openidconnect/tokenservice'
22
+ @state = SecureRandom.hex(16)
23
+ end
24
+
25
+ def get_user_hash(access_token)
26
+ response = access_token.get(user_info_url)
27
+ body = JSON.parse(response.body)
28
+ auth_hash(access_token).tap do |h|
29
+ h[:user_info] = body
30
+ h[:uid] = body['user_id']
31
+ h[:email] = body['email']
32
+ end
33
+ end
34
+
35
+ def get_access_token(args, options = {})
36
+ client = build_client(options)
37
+ client.auth_code.get_token(
38
+ args[:code],
39
+ {
40
+ redirect_uri: @callback_url,
41
+ parse: options.delete(:parse)
42
+ },
43
+ options
44
+ )
45
+ end
46
+
47
+ def login_url(_params, _session)
48
+ authorize_url(authorize_url: auth_url)
49
+ end
50
+
51
+ def process_callback(params, _session)
52
+ args = {}.tap do |a|
53
+ a[:code] = params[:code] if params[:code]
54
+ end
55
+
56
+ get_access_token(args, token_url: token_url, token_method: :post)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -7,7 +7,6 @@ module Sorcery
7
7
  # ...
8
8
  #
9
9
  class Salesforce < Base
10
-
11
10
  include Protocols::Oauth2
12
11
 
13
12
  attr_accessor :auth_url, :token_url, :scope
@@ -32,19 +31,18 @@ module Sorcery
32
31
 
33
32
  # calculates and returns the url to which the user should be redirected,
34
33
  # to get authenticated at the external provider's site.
35
- def login_url(params, session)
36
- authorize_url({ authorize_url: auth_url })
34
+ def login_url(_params, _session)
35
+ authorize_url(authorize_url: auth_url)
37
36
  end
38
37
 
39
38
  # tries to login the user from access token
40
- def process_callback(params, session)
39
+ def process_callback(params, _session)
41
40
  args = {}.tap do |a|
42
41
  a[:code] = params[:code] if params[:code]
43
42
  end
44
43
 
45
44
  get_access_token(args, token_url: token_url, token_method: :post)
46
45
  end
47
-
48
46
  end
49
47
  end
50
48
  end
@@ -0,0 +1,45 @@
1
+ module Sorcery
2
+ module Providers
3
+ # This class adds support for OAuth with slack.com.
4
+
5
+ class Slack < 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 = 'identity.basic, identity.email'
14
+ @site = 'https://slack.com/'
15
+ @user_info_path = 'https://slack.com/api/users.identity'
16
+ @auth_path = '/oauth/authorize'
17
+ @token_url = '/api/oauth.access'
18
+ end
19
+
20
+ def get_user_hash(access_token)
21
+ response = access_token.get(user_info_path)
22
+ auth_hash(access_token).tap do |h|
23
+ h[:user_info] = JSON.parse(response.body)
24
+ h[:user_info]['email'] = h[:user_info]['user']['email']
25
+ h[:uid] = h[:user_info]['user']['id']
26
+ end
27
+ end
28
+
29
+ # calculates and returns the url to which the user should be redirected,
30
+ # to get authenticated at the external provider's site.
31
+ def login_url(_params, _session)
32
+ authorize_url(authorize_url: auth_path)
33
+ end
34
+
35
+ # tries to login the user from access token
36
+ def process_callback(params, _session)
37
+ args = {}.tap do |a|
38
+ a[:code] = params[:code] if params[:code]
39
+ end
40
+
41
+ get_access_token(args, token_url: token_url, token_method: :post)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -7,7 +7,6 @@ module Sorcery
7
7
  # ...
8
8
  #
9
9
  class Twitter < Base
10
-
11
10
  include Protocols::Oauth
12
11
 
13
12
  attr_accessor :state, :user_info_path
@@ -35,11 +34,11 @@ 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
- req_token = self.get_request_token
37
+ def login_url(_params, session)
38
+ req_token = get_request_token
40
39
  session[:request_token] = req_token.token
41
40
  session[:request_token_secret] = req_token.secret
42
- self.authorize_url({ request_token: req_token.token, request_token_secret: req_token.secret })
41
+ authorize_url(request_token: req_token.token, request_token_secret: req_token.secret)
43
42
  end
44
43
 
45
44
  # tries to login the user from access token
@@ -50,10 +49,9 @@ module Sorcery
50
49
  request_token_secret: session[:request_token_secret]
51
50
  }
52
51
 
53
- args.merge!({ code: params[:code] }) if params[:code]
52
+ args[:code] = params[:code] if params[:code]
54
53
  get_access_token(args)
55
54
  end
56
-
57
55
  end
58
56
  end
59
57
  end
@@ -7,10 +7,9 @@ module Sorcery
7
7
  # ...
8
8
  #
9
9
  class Vk < Base
10
-
11
10
  include Protocols::Oauth2
12
11
 
13
- attr_accessor :auth_path, :token_path, :user_info_url, :scope
12
+ attr_accessor :auth_path, :token_path, :user_info_url, :scope, :api_version
14
13
 
15
14
  def initialize
16
15
  super
@@ -29,15 +28,16 @@ module Sorcery
29
28
  access_token: access_token.token,
30
29
  uids: access_token.params['user_id'],
31
30
  fields: user_info_mapping.values.join(','),
32
- scope: scope
31
+ scope: scope,
32
+ v: api_version.to_s
33
33
  }
34
34
 
35
35
  response = access_token.get(user_info_url, params: params)
36
- if user_hash[:user_info] = JSON.parse(response.body)
36
+ if (user_hash[:user_info] = JSON.parse(response.body))
37
37
  user_hash[:user_info] = user_hash[:user_info]['response'][0]
38
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']
40
+ user_hash[:uid] = user_hash[:user_info]['id']
41
41
  user_hash[:user_info]['email'] = access_token.params['email']
42
42
  end
43
43
  user_hash
@@ -45,19 +45,18 @@ module Sorcery
45
45
 
46
46
  # calculates and returns the url to which the user should be redirected,
47
47
  # to get authenticated at the external provider's site.
48
- def login_url(params, session)
49
- self.authorize_url({ authorize_url: auth_path })
48
+ def login_url(_params, _session)
49
+ authorize_url(authorize_url: auth_path)
50
50
  end
51
51
 
52
52
  # tries to login the user from access token
53
- def process_callback(params, session)
53
+ def process_callback(params, _session)
54
54
  args = {}.tap do |a|
55
55
  a[:code] = params[:code] if params[:code]
56
56
  end
57
57
 
58
58
  get_access_token(args, token_url: token_path, token_method: :post)
59
59
  end
60
-
61
60
  end
62
61
  end
63
62
  end