doorkeeper 5.3.0 → 5.4.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 (225) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -1
  3. data/README.md +6 -4
  4. data/app/controllers/doorkeeper/applications_controller.rb +7 -7
  5. data/app/controllers/doorkeeper/authorizations_controller.rb +31 -12
  6. data/app/controllers/doorkeeper/authorized_applications_controller.rb +3 -3
  7. data/app/controllers/doorkeeper/tokens_controller.rb +57 -20
  8. data/app/views/doorkeeper/applications/_form.html.erb +1 -1
  9. data/app/views/doorkeeper/applications/show.html.erb +19 -2
  10. data/config/locales/en.yml +3 -1
  11. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  12. data/lib/doorkeeper/config/option.rb +28 -14
  13. data/lib/doorkeeper/config.rb +65 -35
  14. data/lib/doorkeeper/engine.rb +1 -1
  15. data/lib/doorkeeper/grape/helpers.rb +1 -1
  16. data/lib/doorkeeper/helpers/controller.rb +4 -4
  17. data/lib/doorkeeper/models/access_grant_mixin.rb +20 -16
  18. data/lib/doorkeeper/models/access_token_mixin.rb +110 -46
  19. data/lib/doorkeeper/models/application_mixin.rb +5 -4
  20. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  21. data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
  22. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  23. data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
  24. data/lib/doorkeeper/oauth/authorization/code.rb +15 -6
  25. data/lib/doorkeeper/oauth/authorization/context.rb +2 -2
  26. data/lib/doorkeeper/oauth/authorization/token.rb +8 -12
  27. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
  28. data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -8
  29. data/lib/doorkeeper/oauth/base_request.rb +11 -19
  30. data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
  31. data/lib/doorkeeper/oauth/client.rb +1 -1
  32. data/lib/doorkeeper/oauth/client_credentials/creator.rb +26 -8
  33. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
  34. data/lib/doorkeeper/oauth/client_credentials/validator.rb +4 -2
  35. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
  36. data/lib/doorkeeper/oauth/code_request.rb +3 -3
  37. data/lib/doorkeeper/oauth/code_response.rb +6 -2
  38. data/lib/doorkeeper/oauth/error_response.rb +2 -4
  39. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -5
  40. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  41. data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -2
  42. data/lib/doorkeeper/oauth/password_access_token_request.rb +4 -6
  43. data/lib/doorkeeper/oauth/pre_authorization.rb +36 -30
  44. data/lib/doorkeeper/oauth/refresh_token_request.rb +18 -22
  45. data/lib/doorkeeper/oauth/token.rb +5 -6
  46. data/lib/doorkeeper/oauth/token_introspection.rb +4 -8
  47. data/lib/doorkeeper/oauth/token_request.rb +3 -3
  48. data/lib/doorkeeper/oauth/token_response.rb +1 -1
  49. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +8 -3
  50. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +7 -3
  51. data/lib/doorkeeper/orm/active_record/mixins/application.rb +69 -10
  52. data/lib/doorkeeper/orm/active_record.rb +10 -2
  53. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  54. data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
  55. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  56. data/lib/doorkeeper/rails/routes.rb +13 -17
  57. data/lib/doorkeeper/request/refresh_token.rb +2 -1
  58. data/lib/doorkeeper/request/strategy.rb +2 -2
  59. data/lib/doorkeeper/server.rb +4 -4
  60. data/lib/doorkeeper/stale_records_cleaner.rb +4 -4
  61. data/lib/doorkeeper/version.rb +1 -1
  62. data/lib/doorkeeper.rb +106 -79
  63. data/lib/generators/doorkeeper/confidential_applications_generator.rb +1 -1
  64. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  65. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +2 -0
  66. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
  67. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
  68. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  69. data/lib/generators/doorkeeper/templates/initializer.rb +47 -3
  70. data/lib/generators/doorkeeper/templates/migration.rb.erb +14 -5
  71. metadata +12 -295
  72. data/Appraisals +0 -40
  73. data/CODE_OF_CONDUCT.md +0 -46
  74. data/CONTRIBUTING.md +0 -49
  75. data/Dangerfile +0 -67
  76. data/Dockerfile +0 -29
  77. data/Gemfile +0 -25
  78. data/NEWS.md +0 -1
  79. data/RELEASING.md +0 -11
  80. data/Rakefile +0 -28
  81. data/SECURITY.md +0 -15
  82. data/UPGRADE.md +0 -2
  83. data/bin/console +0 -16
  84. data/doorkeeper.gemspec +0 -42
  85. data/gemfiles/rails_5_0.gemfile +0 -18
  86. data/gemfiles/rails_5_1.gemfile +0 -18
  87. data/gemfiles/rails_5_2.gemfile +0 -18
  88. data/gemfiles/rails_6_0.gemfile +0 -18
  89. data/gemfiles/rails_master.gemfile +0 -18
  90. data/spec/controllers/application_metal_controller_spec.rb +0 -64
  91. data/spec/controllers/applications_controller_spec.rb +0 -274
  92. data/spec/controllers/authorizations_controller_spec.rb +0 -608
  93. data/spec/controllers/protected_resources_controller_spec.rb +0 -361
  94. data/spec/controllers/token_info_controller_spec.rb +0 -50
  95. data/spec/controllers/tokens_controller_spec.rb +0 -498
  96. data/spec/dummy/Rakefile +0 -9
  97. data/spec/dummy/app/assets/config/manifest.js +0 -2
  98. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  99. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
  100. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
  101. data/spec/dummy/app/controllers/home_controller.rb +0 -18
  102. data/spec/dummy/app/controllers/metal_controller.rb +0 -13
  103. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
  104. data/spec/dummy/app/helpers/application_helper.rb +0 -7
  105. data/spec/dummy/app/models/user.rb +0 -7
  106. data/spec/dummy/app/views/home/index.html.erb +0 -0
  107. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  108. data/spec/dummy/config/application.rb +0 -49
  109. data/spec/dummy/config/boot.rb +0 -7
  110. data/spec/dummy/config/database.yml +0 -15
  111. data/spec/dummy/config/environment.rb +0 -5
  112. data/spec/dummy/config/environments/development.rb +0 -31
  113. data/spec/dummy/config/environments/production.rb +0 -64
  114. data/spec/dummy/config/environments/test.rb +0 -45
  115. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
  116. data/spec/dummy/config/initializers/doorkeeper.rb +0 -166
  117. data/spec/dummy/config/initializers/secret_token.rb +0 -10
  118. data/spec/dummy/config/initializers/session_store.rb +0 -10
  119. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
  120. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  121. data/spec/dummy/config/routes.rb +0 -13
  122. data/spec/dummy/config.ru +0 -6
  123. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
  124. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
  125. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
  126. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
  127. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
  128. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
  129. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
  130. data/spec/dummy/db/schema.rb +0 -68
  131. data/spec/dummy/public/404.html +0 -26
  132. data/spec/dummy/public/422.html +0 -26
  133. data/spec/dummy/public/500.html +0 -26
  134. data/spec/dummy/public/favicon.ico +0 -0
  135. data/spec/dummy/script/rails +0 -9
  136. data/spec/factories.rb +0 -30
  137. data/spec/generators/application_owner_generator_spec.rb +0 -28
  138. data/spec/generators/confidential_applications_generator_spec.rb +0 -29
  139. data/spec/generators/install_generator_spec.rb +0 -36
  140. data/spec/generators/migration_generator_spec.rb +0 -28
  141. data/spec/generators/pkce_generator_spec.rb +0 -28
  142. data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
  143. data/spec/generators/templates/routes.rb +0 -4
  144. data/spec/generators/views_generator_spec.rb +0 -29
  145. data/spec/grape/grape_integration_spec.rb +0 -137
  146. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
  147. data/spec/lib/config_spec.rb +0 -794
  148. data/spec/lib/doorkeeper_spec.rb +0 -27
  149. data/spec/lib/models/expirable_spec.rb +0 -61
  150. data/spec/lib/models/reusable_spec.rb +0 -40
  151. data/spec/lib/models/revocable_spec.rb +0 -59
  152. data/spec/lib/models/scopes_spec.rb +0 -53
  153. data/spec/lib/models/secret_storable_spec.rb +0 -135
  154. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
  155. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -170
  156. data/spec/lib/oauth/base_request_spec.rb +0 -224
  157. data/spec/lib/oauth/base_response_spec.rb +0 -45
  158. data/spec/lib/oauth/client/credentials_spec.rb +0 -90
  159. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -134
  160. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
  161. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
  162. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  163. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -107
  164. data/spec/lib/oauth/client_spec.rb +0 -38
  165. data/spec/lib/oauth/code_request_spec.rb +0 -46
  166. data/spec/lib/oauth/code_response_spec.rb +0 -32
  167. data/spec/lib/oauth/error_response_spec.rb +0 -64
  168. data/spec/lib/oauth/error_spec.rb +0 -21
  169. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -20
  170. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -110
  171. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
  172. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -262
  173. data/spec/lib/oauth/invalid_request_response_spec.rb +0 -73
  174. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -53
  175. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -190
  176. data/spec/lib/oauth/pre_authorization_spec.rb +0 -223
  177. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
  178. data/spec/lib/oauth/scopes_spec.rb +0 -146
  179. data/spec/lib/oauth/token_request_spec.rb +0 -157
  180. data/spec/lib/oauth/token_response_spec.rb +0 -84
  181. data/spec/lib/oauth/token_spec.rb +0 -156
  182. data/spec/lib/request/strategy_spec.rb +0 -54
  183. data/spec/lib/secret_storing/base_spec.rb +0 -60
  184. data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
  185. data/spec/lib/secret_storing/plain_spec.rb +0 -44
  186. data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
  187. data/spec/lib/server_spec.rb +0 -49
  188. data/spec/lib/stale_records_cleaner_spec.rb +0 -89
  189. data/spec/models/doorkeeper/access_grant_spec.rb +0 -161
  190. data/spec/models/doorkeeper/access_token_spec.rb +0 -622
  191. data/spec/models/doorkeeper/application_spec.rb +0 -404
  192. data/spec/requests/applications/applications_request_spec.rb +0 -259
  193. data/spec/requests/applications/authorized_applications_spec.rb +0 -32
  194. data/spec/requests/endpoints/authorization_spec.rb +0 -91
  195. data/spec/requests/endpoints/token_spec.rb +0 -75
  196. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -79
  197. data/spec/requests/flows/authorization_code_spec.rb +0 -525
  198. data/spec/requests/flows/client_credentials_spec.rb +0 -166
  199. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -46
  200. data/spec/requests/flows/implicit_grant_spec.rb +0 -91
  201. data/spec/requests/flows/password_spec.rb +0 -316
  202. data/spec/requests/flows/refresh_token_spec.rb +0 -233
  203. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  204. data/spec/requests/flows/skip_authorization_spec.rb +0 -66
  205. data/spec/requests/protected_resources/metal_spec.rb +0 -16
  206. data/spec/requests/protected_resources/private_api_spec.rb +0 -83
  207. data/spec/routing/custom_controller_routes_spec.rb +0 -133
  208. data/spec/routing/default_routes_spec.rb +0 -41
  209. data/spec/routing/scoped_routes_spec.rb +0 -47
  210. data/spec/spec_helper.rb +0 -54
  211. data/spec/spec_helper_integration.rb +0 -4
  212. data/spec/support/dependencies/factory_bot.rb +0 -4
  213. data/spec/support/doorkeeper_rspec.rb +0 -22
  214. data/spec/support/helpers/access_token_request_helper.rb +0 -13
  215. data/spec/support/helpers/authorization_request_helper.rb +0 -43
  216. data/spec/support/helpers/config_helper.rb +0 -11
  217. data/spec/support/helpers/model_helper.rb +0 -78
  218. data/spec/support/helpers/request_spec_helper.rb +0 -110
  219. data/spec/support/helpers/url_helper.rb +0 -62
  220. data/spec/support/orm/active_record.rb +0 -5
  221. data/spec/support/shared/controllers_shared_context.rb +0 -133
  222. data/spec/support/shared/hashing_shared_context.rb +0 -36
  223. data/spec/support/shared/models_shared_examples.rb +0 -54
  224. data/spec/validators/redirect_uri_validator_spec.rb +0 -183
  225. data/spec/version/version_spec.rb +0 -17
@@ -1,16 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "doorkeeper/config/option"
4
+ require "doorkeeper/config/abstract_builder"
4
5
 
5
6
  module Doorkeeper
7
+ # Defines a MissingConfiguration error for a missing Doorkeeper configuration
8
+ #
6
9
  class MissingConfiguration < StandardError
7
- # Defines a MissingConfiguration error for a missing Doorkeeper
8
- # configuration
9
10
  def initialize
10
11
  super("Configuration for doorkeeper missing. Do you have doorkeeper initializer?")
11
12
  end
12
13
  end
13
14
 
15
+ # Doorkeeper option DSL could be reused in extensions to build their own
16
+ # configurations. To use the Option DSL gems need to define `builder_class` method
17
+ # that returns configuration Builder class. This exception raises when they don't
18
+ # define it.
19
+ #
20
+ class MissingConfigurationBuilderClass < StandardError; end
21
+
14
22
  class << self
15
23
  def configure(&block)
16
24
  @config = Config::Builder.new(&block).build
@@ -30,7 +38,7 @@ module Doorkeeper
30
38
  @orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
31
39
  rescue NameError => e
32
40
  raise e, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.strip_heredoc
33
- [doorkeeper] ORM adapter not found (#{configuration.orm}), or there was an error
41
+ [DOORKEEPER] ORM adapter not found (#{configuration.orm}), or there was an error
34
42
  trying to load it.
35
43
 
36
44
  You probably need to add the related gem for this adapter to work with
@@ -48,17 +56,8 @@ module Doorkeeper
48
56
  end
49
57
 
50
58
  class Config
51
- class Builder
52
- def initialize(&block)
53
- @config = Config.new
54
- instance_eval(&block)
55
- end
56
-
57
- def build
58
- @config.validate
59
- @config
60
- end
61
-
59
+ # Default Doorkeeper configuration builder
60
+ class Builder < AbstractBuilder
62
61
  # Provide support for an owner to be assigned to each registered
63
62
  # application (disabled by default)
64
63
  # Optional parameter confirmation: true (default false) if you want
@@ -135,15 +134,6 @@ module Doorkeeper
135
134
  @config.instance_variable_set(:@reuse_access_token, true)
136
135
  end
137
136
 
138
- # Sets the token_reuse_limit
139
- # It will be used only when reuse_access_token option in enabled
140
- # By default it will be 100
141
- # It will be used for token reusablity to some threshold percentage
142
- # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1189
143
- def token_reuse_limit(percentage)
144
- @config.instance_variable_set(:@token_reuse_limit, percentage)
145
- end
146
-
147
137
  # TODO: maybe make it more generic for other flows too?
148
138
  # Only allow one valid access token obtained via client credentials
149
139
  # per client. If a new access token is obtained before the old one
@@ -158,6 +148,12 @@ module Doorkeeper
158
148
  @config.instance_variable_set(:@api_only, true)
159
149
  end
160
150
 
151
+ # Enables polymorphic Resource Owner association for Access Grant and
152
+ # Access Token models. Requires additional database columns to be setup.
153
+ def use_polymorphic_resource_owner
154
+ @config.instance_variable_set(:@polymorphic_resource_owner, true)
155
+ end
156
+
161
157
  # Forbids creating/updating applications with arbitrary scopes that are
162
158
  # not in configuration, i.e. `default_scopes` or `optional_scopes`.
163
159
  # (disabled by default)
@@ -219,6 +215,9 @@ module Doorkeeper
219
215
  end
220
216
  end
221
217
 
218
+ # Replace with `default: Builder` when we drop support of Rails < 5.2
219
+ mattr_reader(:builder_class) { Builder }
220
+
222
221
  extend Option
223
222
 
224
223
  option :resource_owner_authenticator,
@@ -251,8 +250,8 @@ module Doorkeeper
251
250
  end)
252
251
 
253
252
  # Hooks for authorization
254
- option :before_successful_authorization, default: ->(_context) {}
255
- option :after_successful_authorization, default: ->(_context) {}
253
+ option :before_successful_authorization, default: ->(_controller, _context = nil) {}
254
+ option :after_successful_authorization, default: ->(_controller, _context = nil) {}
256
255
  # Hooks for strategies responses
257
256
  option :before_successful_strategy_response, default: ->(_request) {}
258
257
  option :after_successful_strategy_response, default: ->(_request, _response) {}
@@ -265,9 +264,24 @@ module Doorkeeper
265
264
  option :authorization_code_expires_in, default: 600
266
265
  option :orm, default: :active_record
267
266
  option :native_redirect_uri, default: "urn:ietf:wg:oauth:2.0:oob", deprecated: true
268
- option :active_record_options, default: {}
269
267
  option :grant_flows, default: %w[authorization_code client_credentials]
270
268
  option :handle_auth_errors, default: :render
269
+ option :token_lookup_batch_size, default: 10_000
270
+
271
+ # Sets the token_reuse_limit
272
+ # It will be used only when reuse_access_token option in enabled
273
+ # By default it will be 100
274
+ # It will be used for token reusablity to some threshold percentage
275
+ # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1189
276
+ option :token_reuse_limit, default: 100
277
+
278
+ option :active_record_options,
279
+ default: {},
280
+ deprecated: { message: "Customize Doorkeeper models instead" }
281
+
282
+ # Hook to allow arbitrary user-client authorization
283
+ option :authorize_resource_owner_for_client,
284
+ default: ->(_client, _resource_owner) { true }
271
285
 
272
286
  # Allows to customize OAuth grant flows that +each+ application support.
273
287
  # You can configure a custom block (or use a class respond to `#call`) that must
@@ -410,20 +424,32 @@ module Doorkeeper
410
424
  :application_secret_fallback_strategy
411
425
 
412
426
  # Return the valid subset of this configuration
413
- def validate
427
+ def validate!
414
428
  validate_reuse_access_token_value
415
429
  validate_token_reuse_limit
416
430
  validate_secret_strategies
417
431
  end
418
432
 
433
+ # Doorkeeper Access Token model class.
434
+ #
435
+ # @return [ActiveRecord::Base, Mongoid::Document, Sequel::Model]
436
+ #
419
437
  def access_token_model
420
438
  @access_token_model ||= access_token_class.constantize
421
439
  end
422
440
 
441
+ # Doorkeeper Access Grant model class.
442
+ #
443
+ # @return [ActiveRecord::Base, Mongoid::Document, Sequel::Model]
444
+ #
423
445
  def access_grant_model
424
446
  @access_grant_model ||= access_grant_class.constantize
425
447
  end
426
448
 
449
+ # Doorkeeper Application model class.
450
+ #
451
+ # @return [ActiveRecord::Base, Mongoid::Document, Sequel::Model]
452
+ #
427
453
  def application_model
428
454
  @application_model ||= application_class.constantize
429
455
  end
@@ -444,14 +470,6 @@ module Doorkeeper
444
470
  end
445
471
  end
446
472
 
447
- def token_reuse_limit
448
- @token_reuse_limit ||= 100
449
- end
450
-
451
- def revoke_previous_client_credentials_token
452
- @revoke_previous_client_credentials_token || false
453
- end
454
-
455
473
  def resolve_controller(name)
456
474
  config_option = public_send(:"#{name}_controller")
457
475
  controller_name = if config_option.respond_to?(:call)
@@ -463,6 +481,10 @@ module Doorkeeper
463
481
  controller_name.constantize
464
482
  end
465
483
 
484
+ def revoke_previous_client_credentials_token?
485
+ option_set? :revoke_previous_client_credentials_token
486
+ end
487
+
466
488
  def enforce_configured_scopes?
467
489
  option_set? :enforce_configured_scopes
468
490
  end
@@ -471,6 +493,10 @@ module Doorkeeper
471
493
  option_set? :enable_application_owner
472
494
  end
473
495
 
496
+ def polymorphic_resource_owner?
497
+ option_set? :polymorphic_resource_owner
498
+ end
499
+
474
500
  def confirm_application_owner?
475
501
  option_set? :confirm_application_owner
476
502
  end
@@ -479,6 +505,10 @@ module Doorkeeper
479
505
  handle_auth_errors == :raise
480
506
  end
481
507
 
508
+ def application_secret_hashed?
509
+ instance_variable_defined?(:"@application_secret_strategy")
510
+ end
511
+
482
512
  def token_secret_strategy
483
513
  @token_secret_strategy ||= ::Doorkeeper::SecretStoring::Plain
484
514
  end
@@ -4,7 +4,7 @@ module Doorkeeper
4
4
  class Engine < Rails::Engine
5
5
  initializer "doorkeeper.params.filter" do |app|
6
6
  parameters = %w[client_secret code authentication_token access_token refresh_token]
7
- app.config.filter_parameters << /^(#{Regexp.union parameters})$/
7
+ app.config.filter_parameters << /^(#{Regexp.union(parameters)})$/
8
8
  end
9
9
 
10
10
  initializer "doorkeeper.routes" do
@@ -18,7 +18,7 @@ module Doorkeeper
18
18
 
19
19
  scopes = if endpoint_scopes
20
20
  Doorkeeper::OAuth::Scopes.from_array(endpoint_scopes)
21
- elsif scopes && !scopes.empty?
21
+ elsif scopes.present?
22
22
  Doorkeeper::OAuth::Scopes.from_array(scopes)
23
23
  end
24
24
 
@@ -36,7 +36,7 @@ module Doorkeeper
36
36
 
37
37
  # :doc:
38
38
  def doorkeeper_token
39
- @doorkeeper_token ||= OAuth::Token.authenticate request, *config_methods
39
+ @doorkeeper_token ||= OAuth::Token.authenticate(request, *config_methods)
40
40
  end
41
41
 
42
42
  def config_methods
@@ -58,10 +58,10 @@ module Doorkeeper
58
58
  end
59
59
 
60
60
  def handle_token_exception(exception)
61
- error = get_error_response_from_exception exception
62
- headers.merge! error.headers
61
+ error = get_error_response_from_exception(exception)
62
+ headers.merge!(error.headers)
63
63
  self.response_body = error.body.to_json
64
- self.status = error.status
64
+ self.status = error.status
65
65
  end
66
66
 
67
67
  def skip_authorization?
@@ -11,14 +11,11 @@ module Doorkeeper
11
11
  include Models::Orderable
12
12
  include Models::SecretStorable
13
13
  include Models::Scopes
14
+ include Models::ResourceOwnerable
14
15
 
15
- # never uses pkce, if pkce migrations were not generated
16
+ # Never uses PKCE if PKCE migrations were not generated
16
17
  def uses_pkce?
17
- pkce_supported? && code_challenge.present?
18
- end
19
-
20
- def pkce_supported?
21
- respond_to? :code_challenge
18
+ self.class.pkce_supported? && code_challenge.present?
22
19
  end
23
20
 
24
21
  module ClassMethods
@@ -27,8 +24,8 @@ module Doorkeeper
27
24
  #
28
25
  # @param token [#to_s] token value (any object that responds to `#to_s`)
29
26
  #
30
- # @return [Doorkeeper::AccessGrant, nil] AccessGrant object or nil
31
- # if there is no record with such token
27
+ # @return [Doorkeeper::AccessGrant, nil]
28
+ # AccessGrant object or nil if there is no record with such token
32
29
  #
33
30
  def by_token(token)
34
31
  find_by_plaintext_token(:token, token)
@@ -39,15 +36,16 @@ module Doorkeeper
39
36
  #
40
37
  # @param application_id [Integer]
41
38
  # ID of the Application
42
- # @param resource_owner [ActiveRecord::Base]
43
- # instance of the Resource Owner model
39
+ # @param resource_owner [ActiveRecord::Base, Integer]
40
+ # instance of the Resource Owner model or it's ID
44
41
  #
45
42
  def revoke_all_for(application_id, resource_owner, clock = Time)
46
- where(
47
- application_id: application_id,
48
- resource_owner_id: resource_owner.id,
49
- revoked_at: nil,
50
- ).update_all(revoked_at: clock.now.utc)
43
+ by_resource_owner(resource_owner)
44
+ .where(
45
+ application_id: application_id,
46
+ revoked_at: nil,
47
+ )
48
+ .update_all(revoked_at: clock.now.utc)
51
49
  end
52
50
 
53
51
  # Implements PKCE code_challenge encoding without base64 padding as described in the spec.
@@ -96,12 +94,15 @@ module Doorkeeper
96
94
  end
97
95
 
98
96
  def pkce_supported?
99
- new.pkce_supported?
97
+ column_names.include?("code_challenge")
100
98
  end
101
99
 
102
100
  ##
103
101
  # Determines the secret storing transformer
104
102
  # Unless configured otherwise, uses the plain secret strategy
103
+ #
104
+ # @return [Doorkeeper::SecretStoring::Base]
105
+ #
105
106
  def secret_strategy
106
107
  ::Doorkeeper.config.token_secret_strategy
107
108
  end
@@ -109,6 +110,9 @@ module Doorkeeper
109
110
  ##
110
111
  # Determine the fallback storing strategy
111
112
  # Unless configured, there will be no fallback
113
+ #
114
+ # @return [Doorkeeper::SecretStoring::Base]
115
+ #
112
116
  def fallback_secret_strategy
113
117
  ::Doorkeeper.config.token_secret_fallback_strategy
114
118
  end
@@ -12,6 +12,7 @@ module Doorkeeper
12
12
  include Models::Orderable
13
13
  include Models::SecretStorable
14
14
  include Models::Scopes
15
+ include Models::ResourceOwnerable
15
16
 
16
17
  module ClassMethods
17
18
  # Returns an instance of the Doorkeeper::AccessToken with
@@ -60,15 +61,16 @@ module Doorkeeper
60
61
  #
61
62
  # @param application_id [Integer]
62
63
  # ID of the Application
63
- # @param resource_owner [ActiveRecord::Base]
64
- # instance of the Resource Owner model
64
+ # @param resource_owner [ActiveRecord::Base, Integer]
65
+ # instance of the Resource Owner model or it's ID
65
66
  #
66
67
  def revoke_all_for(application_id, resource_owner, clock = Time)
67
- where(
68
- application_id: application_id,
69
- resource_owner_id: resource_owner.id,
70
- revoked_at: nil,
71
- ).update_all(revoked_at: clock.now.utc)
68
+ by_resource_owner(resource_owner)
69
+ .where(
70
+ application_id: application_id,
71
+ revoked_at: nil,
72
+ )
73
+ .update_all(revoked_at: clock.now.utc)
72
74
  end
73
75
 
74
76
  # Looking for not revoked Access Token with a matching set of scopes
@@ -76,7 +78,7 @@ module Doorkeeper
76
78
  #
77
79
  # @param application [Doorkeeper::Application]
78
80
  # Application instance
79
- # @param resource_owner_or_id [ActiveRecord::Base, Integer]
81
+ # @param resource_owner [ActiveRecord::Base, Integer]
80
82
  # Resource Owner model instance or it's ID
81
83
  # @param scopes [String, Doorkeeper::OAuth::Scopes]
82
84
  # set of scopes
@@ -84,14 +86,8 @@ module Doorkeeper
84
86
  # @return [Doorkeeper::AccessToken, nil] Access Token instance or
85
87
  # nil if matching record was not found
86
88
  #
87
- def matching_token_for(application, resource_owner_or_id, scopes)
88
- resource_owner_id = if resource_owner_or_id.respond_to?(:to_key)
89
- resource_owner_or_id.id
90
- else
91
- resource_owner_or_id
92
- end
93
-
94
- tokens = authorized_tokens_for(application.try(:id), resource_owner_id)
89
+ def matching_token_for(application, resource_owner, scopes)
90
+ tokens = authorized_tokens_for(application&.id, resource_owner)
95
91
  find_matching_token(tokens, application, scopes)
96
92
  end
97
93
 
@@ -126,10 +122,11 @@ module Doorkeeper
126
122
  return nil unless relation
127
123
 
128
124
  matching_tokens = []
125
+ batch_size = Doorkeeper.configuration.token_lookup_batch_size
129
126
 
130
- find_access_token_in_batches(relation) do |batch|
127
+ find_access_token_in_batches(relation, batch_size: batch_size) do |batch|
131
128
  tokens = batch.select do |token|
132
- scopes_match?(token.scopes, scopes, application.try(:scopes))
129
+ scopes_match?(token.scopes, scopes, application&.scopes)
133
130
  end
134
131
 
135
132
  matching_tokens.concat(tokens)
@@ -169,47 +166,79 @@ module Doorkeeper
169
166
  #
170
167
  # @param application [Doorkeeper::Application]
171
168
  # Application instance
172
- # @param resource_owner_id [ActiveRecord::Base, Integer]
169
+ # @param resource_owner [ActiveRecord::Base, Integer]
173
170
  # Resource Owner model instance or it's ID
174
171
  # @param scopes [#to_s]
175
172
  # set of scopes (any object that responds to `#to_s`)
176
- # @param expires_in [Integer]
173
+ # @param token_attributes [Hash]
174
+ # Additional attributes to use when creating a token
175
+ # @option token_attributes [Integer] :expires_in
177
176
  # token lifetime in seconds
178
- # @param use_refresh_token [Boolean]
177
+ # @option token_attributes [Boolean] :use_refresh_token
179
178
  # whether to use the refresh token
180
179
  #
181
180
  # @return [Doorkeeper::AccessToken] existing record or a new one
182
181
  #
183
- def find_or_create_for(application, resource_owner_id, scopes, expires_in, use_refresh_token)
182
+ def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
184
183
  if Doorkeeper.config.reuse_access_token
185
- access_token = matching_token_for(application, resource_owner_id, scopes)
184
+ access_token = matching_token_for(application, resource_owner, scopes)
186
185
 
187
186
  return access_token if access_token&.reusable?
188
187
  end
189
188
 
190
- create!(
191
- application_id: application.try(:id),
192
- resource_owner_id: resource_owner_id,
193
- scopes: scopes.to_s,
194
- expires_in: expires_in,
195
- use_refresh_token: use_refresh_token,
189
+ create_for(
190
+ application: application,
191
+ resource_owner: resource_owner,
192
+ scopes: scopes,
193
+ **token_attributes,
196
194
  )
197
195
  end
198
196
 
197
+ # Creates a not expired AccessToken record with a matching set of
198
+ # scopes that belongs to specific Application and Resource Owner.
199
+ #
200
+ # @param application [Doorkeeper::Application]
201
+ # Application instance
202
+ # @param resource_owner [ActiveRecord::Base, Integer]
203
+ # Resource Owner model instance or it's ID
204
+ # @param scopes [#to_s]
205
+ # set of scopes (any object that responds to `#to_s`)
206
+ # @param token_attributes [Hash]
207
+ # Additional attributes to use when creating a token
208
+ # @option token_attributes [Integer] :expires_in
209
+ # token lifetime in seconds
210
+ # @option token_attributes [Boolean] :use_refresh_token
211
+ # whether to use the refresh token
212
+ #
213
+ # @return [Doorkeeper::AccessToken] new access token
214
+ #
215
+ def create_for(application:, resource_owner:, scopes:, **token_attributes)
216
+ token_attributes[:application_id] = application&.id
217
+ token_attributes[:scopes] = scopes.to_s
218
+
219
+ if Doorkeeper.config.polymorphic_resource_owner?
220
+ token_attributes[:resource_owner] = resource_owner
221
+ else
222
+ token_attributes[:resource_owner_id] = resource_owner_id_for(resource_owner)
223
+ end
224
+
225
+ create!(token_attributes)
226
+ end
227
+
199
228
  # Looking for not revoked Access Token records that belongs to specific
200
229
  # Application and Resource Owner.
201
230
  #
202
231
  # @param application_id [Integer]
203
232
  # ID of the Application model instance
204
- # @param resource_owner_id [Integer]
205
- # ID of the Resource Owner model instance
233
+ # @param resource_owner [ActiveRecord::Base, Integer]
234
+ # Resource Owner model instance or it's ID
206
235
  #
207
- # @return [Doorkeeper::AccessToken] array of matching AccessToken objects
236
+ # @return [ActiveRecord::Relation]
237
+ # collection of matching AccessToken objects
208
238
  #
209
- def authorized_tokens_for(application_id, resource_owner_id)
210
- where(
239
+ def authorized_tokens_for(application_id, resource_owner)
240
+ by_resource_owner(resource_owner).where(
211
241
  application_id: application_id,
212
- resource_owner_id: resource_owner_id,
213
242
  revoked_at: nil,
214
243
  )
215
244
  end
@@ -219,20 +248,24 @@ module Doorkeeper
219
248
  #
220
249
  # @param application_id [Integer]
221
250
  # ID of the Application model instance
222
- # @param resource_owner_id [Integer]
251
+ # @param resource_owner [ActiveRecord::Base, Integer]
223
252
  # ID of the Resource Owner model instance
224
253
  #
225
254
  # @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
226
255
  # nil if nothing was found
227
256
  #
228
- def last_authorized_token_for(application_id, resource_owner_id)
229
- authorized_tokens_for(application_id, resource_owner_id)
230
- .ordered_by(:created_at, :desc).first
257
+ def last_authorized_token_for(application_id, resource_owner)
258
+ authorized_tokens_for(application_id, resource_owner)
259
+ .ordered_by(:created_at, :desc)
260
+ .first
231
261
  end
232
262
 
233
263
  ##
234
264
  # Determines the secret storing transformer
235
265
  # Unless configured otherwise, uses the plain secret strategy
266
+ #
267
+ # @return [Doorkeeper::SecretStoring::Base]
268
+ #
236
269
  def secret_strategy
237
270
  ::Doorkeeper.config.token_secret_strategy
238
271
  end
@@ -268,7 +301,11 @@ module Doorkeeper
268
301
  expires_in: expires_in_seconds,
269
302
  application: { uid: application.try(:uid) },
270
303
  created_at: created_at.to_i,
271
- }
304
+ }.tap do |json|
305
+ if Doorkeeper.configuration.polymorphic_resource_owner?
306
+ json[:resource_owner_type] = resource_owner_type
307
+ end
308
+ end
272
309
  end
273
310
 
274
311
  # Indicates whether the token instance have the same credential
@@ -280,7 +317,22 @@ module Doorkeeper
280
317
  #
281
318
  def same_credential?(access_token)
282
319
  application_id == access_token.application_id &&
320
+ same_resource_owner?(access_token)
321
+ end
322
+
323
+ # Indicates whether the token instance have the same credential
324
+ # as the other Access Token.
325
+ #
326
+ # @param access_token [Doorkeeper::AccessToken] other token
327
+ #
328
+ # @return [Boolean] true if credentials are same of false in other cases
329
+ #
330
+ def same_resource_owner?(access_token)
331
+ if Doorkeeper.configuration.polymorphic_resource_owner?
332
+ resource_owner == access_token.resource_owner
333
+ else
283
334
  resource_owner_id == access_token.resource_owner_id
335
+ end
284
336
  end
285
337
 
286
338
  # Indicates if token is acceptable for specific scopes.
@@ -325,7 +377,7 @@ module Doorkeeper
325
377
  return unless self.class.refresh_token_revoked_on_use?
326
378
 
327
379
  old_refresh_token&.revoke
328
- update_attribute :previous_refresh_token, ""
380
+ update_column(:previous_refresh_token, "")
329
381
  end
330
382
 
331
383
  private
@@ -362,16 +414,28 @@ module Doorkeeper
362
414
  def generate_token
363
415
  self.created_at ||= Time.now.utc
364
416
 
365
- @raw_token = token_generator.generate(
417
+ @raw_token = token_generator.generate(attributes_for_token_generator)
418
+ secret_strategy.store_secret(self, :token, @raw_token)
419
+ @raw_token
420
+ end
421
+
422
+ # Set of attributes that would be passed to token generator to
423
+ # generate unique token based on them.
424
+ #
425
+ # @return [Hash] set of attributes
426
+ #
427
+ def attributes_for_token_generator
428
+ {
366
429
  resource_owner_id: resource_owner_id,
367
430
  scopes: scopes,
368
431
  application: application,
369
432
  expires_in: expires_in,
370
433
  created_at: created_at,
371
- )
372
-
373
- secret_strategy.store_secret(self, :token, @raw_token)
374
- @raw_token
434
+ }.tap do |attributes|
435
+ if Doorkeeper.config.polymorphic_resource_owner?
436
+ attributes[:resource_owner] = resource_owner
437
+ end
438
+ end
375
439
  end
376
440
 
377
441
  def token_generator
@@ -20,8 +20,8 @@ module Doorkeeper
20
20
  # @param uid [#to_s] UID (any object that responds to `#to_s`)
21
21
  # @param secret [#to_s] secret (any object that responds to `#to_s`)
22
22
  #
23
- # @return [Doorkeeper::Application, nil] Application instance or nil
24
- # if there is no record with such credentials
23
+ # @return [Doorkeeper::Application, nil]
24
+ # Application instance or nil if there is no record with such credentials
25
25
  #
26
26
  def by_uid_and_secret(uid, secret)
27
27
  app = by_uid(uid)
@@ -60,9 +60,10 @@ module Doorkeeper
60
60
 
61
61
  # Set an application's valid redirect URIs.
62
62
  #
63
- # @param uris [String, Array] Newline-separated string or array the URI(s)
63
+ # @param uris [String, Array<String>] Newline-separated string or array the URI(s)
64
+ #
65
+ # @return [String] The redirect URI(s) separated by newlines.
64
66
  #
65
- # @return [String] The redirect URI(s) seperated by newlines.
66
67
  def redirect_uri=(uris)
67
68
  super(uris.is_a?(Array) ? uris.join("\n") : uris)
68
69
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module ResourceOwnerable
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # Searches for record by Resource Owner considering Doorkeeper
10
+ # configuration for resource owner association.
11
+ #
12
+ # @param resource_owner [ActiveRecord::Base, Integer]
13
+ # resource owner
14
+ #
15
+ # @return [Doorkeeper::AccessGrant, Doorkeeper::AccessToken]
16
+ # collection of records
17
+ #
18
+ def by_resource_owner(resource_owner)
19
+ if Doorkeeper.configuration.polymorphic_resource_owner?
20
+ where(resource_owner: resource_owner)
21
+ else
22
+ where(resource_owner_id: resource_owner_id_for(resource_owner))
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ # Backward compatible way to retrieve resource owner itself (if
29
+ # polymorphic association enabled) or just it's ID.
30
+ #
31
+ # @param resource_owner [ActiveRecord::Base, Integer]
32
+ # resource owner
33
+ #
34
+ # @return [ActiveRecord::Base, Integer]
35
+ # instance of Resource Owner or it's ID
36
+ #
37
+ def resource_owner_id_for(resource_owner)
38
+ if resource_owner.respond_to?(:to_key)
39
+ resource_owner.id
40
+ else
41
+ resource_owner
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -9,7 +9,7 @@ module Doorkeeper
9
9
  # @param clock [Time] time object
10
10
  #
11
11
  def revoke(clock = Time)
12
- update_attribute :revoked_at, clock.now.utc
12
+ update_column(:revoked_at, clock.now.utc)
13
13
  end
14
14
 
15
15
  # Indicates whether the object has been revoked.