doorkeeper 5.3.3 → 5.6.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (247) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +216 -9
  3. data/README.md +30 -21
  4. data/app/controllers/doorkeeper/application_controller.rb +1 -0
  5. data/app/controllers/doorkeeper/applications_controller.rb +4 -4
  6. data/app/controllers/doorkeeper/authorizations_controller.rb +66 -22
  7. data/app/controllers/doorkeeper/authorized_applications_controller.rb +3 -3
  8. data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
  9. data/app/controllers/doorkeeper/tokens_controller.rb +73 -25
  10. data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
  11. data/app/views/doorkeeper/applications/_form.html.erb +1 -1
  12. data/app/views/doorkeeper/applications/show.html.erb +35 -14
  13. data/app/views/doorkeeper/authorizations/error.html.erb +3 -1
  14. data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  15. data/app/views/doorkeeper/authorizations/new.html.erb +16 -14
  16. data/config/locales/en.yml +9 -2
  17. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  18. data/lib/doorkeeper/config/option.rb +26 -14
  19. data/lib/doorkeeper/config/validations.rb +53 -0
  20. data/lib/doorkeeper/config.rb +182 -134
  21. data/lib/doorkeeper/engine.rb +10 -3
  22. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  23. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  24. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  25. data/lib/doorkeeper/grant_flow.rb +45 -0
  26. data/lib/doorkeeper/grape/helpers.rb +1 -1
  27. data/lib/doorkeeper/helpers/controller.rb +9 -5
  28. data/lib/doorkeeper/models/access_grant_mixin.rb +22 -19
  29. data/lib/doorkeeper/models/access_token_mixin.rb +115 -52
  30. data/lib/doorkeeper/models/application_mixin.rb +5 -4
  31. data/lib/doorkeeper/models/concerns/expirable.rb +1 -1
  32. data/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +88 -0
  33. data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +30 -0
  34. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  35. data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
  36. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  37. data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
  38. data/lib/doorkeeper/oauth/authorization/code.rb +25 -6
  39. data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
  40. data/lib/doorkeeper/oauth/authorization/token.rb +24 -16
  41. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
  42. data/lib/doorkeeper/oauth/authorization_code_request.rb +34 -21
  43. data/lib/doorkeeper/oauth/base_request.rb +19 -26
  44. data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
  45. data/lib/doorkeeper/oauth/client.rb +1 -1
  46. data/lib/doorkeeper/oauth/client_credentials/creator.rb +31 -15
  47. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +4 -2
  48. data/lib/doorkeeper/oauth/client_credentials/validator.rb +5 -4
  49. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
  50. data/lib/doorkeeper/oauth/code_request.rb +4 -4
  51. data/lib/doorkeeper/oauth/code_response.rb +22 -12
  52. data/lib/doorkeeper/oauth/error_response.rb +7 -9
  53. data/lib/doorkeeper/oauth/forbidden_token_response.rb +2 -1
  54. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -8
  55. data/lib/doorkeeper/oauth/helpers/unique_token.rb +2 -2
  56. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +4 -22
  57. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  58. data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -2
  59. data/lib/doorkeeper/oauth/password_access_token_request.rb +26 -8
  60. data/lib/doorkeeper/oauth/pre_authorization.rb +65 -33
  61. data/lib/doorkeeper/oauth/refresh_token_request.rb +42 -25
  62. data/lib/doorkeeper/oauth/token.rb +5 -6
  63. data/lib/doorkeeper/oauth/token_introspection.rb +8 -12
  64. data/lib/doorkeeper/oauth/token_request.rb +3 -3
  65. data/lib/doorkeeper/oauth/token_response.rb +2 -3
  66. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +14 -4
  67. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +34 -4
  68. data/lib/doorkeeper/orm/active_record/mixins/application.rb +28 -5
  69. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +6 -1
  70. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +5 -2
  71. data/lib/doorkeeper/orm/active_record.rb +30 -38
  72. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  73. data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
  74. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  75. data/lib/doorkeeper/rails/routes.rb +25 -22
  76. data/lib/doorkeeper/rake/db.rake +3 -3
  77. data/lib/doorkeeper/request/password.rb +1 -0
  78. data/lib/doorkeeper/request/refresh_token.rb +2 -1
  79. data/lib/doorkeeper/request/strategy.rb +2 -2
  80. data/lib/doorkeeper/request.rb +49 -12
  81. data/lib/doorkeeper/server.rb +4 -4
  82. data/lib/doorkeeper/stale_records_cleaner.rb +4 -4
  83. data/lib/doorkeeper/version.rb +2 -6
  84. data/lib/doorkeeper.rb +181 -81
  85. data/lib/generators/doorkeeper/confidential_applications_generator.rb +1 -1
  86. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  87. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +3 -1
  88. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
  89. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
  90. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  91. data/lib/generators/doorkeeper/templates/initializer.rb +73 -17
  92. data/lib/generators/doorkeeper/templates/migration.rb.erb +28 -9
  93. metadata +48 -316
  94. data/Appraisals +0 -40
  95. data/CODE_OF_CONDUCT.md +0 -46
  96. data/CONTRIBUTING.md +0 -49
  97. data/Dangerfile +0 -67
  98. data/Dockerfile +0 -29
  99. data/Gemfile +0 -25
  100. data/NEWS.md +0 -1
  101. data/RELEASING.md +0 -11
  102. data/Rakefile +0 -28
  103. data/SECURITY.md +0 -15
  104. data/UPGRADE.md +0 -2
  105. data/bin/console +0 -16
  106. data/doorkeeper.gemspec +0 -42
  107. data/gemfiles/rails_5_0.gemfile +0 -18
  108. data/gemfiles/rails_5_1.gemfile +0 -18
  109. data/gemfiles/rails_5_2.gemfile +0 -18
  110. data/gemfiles/rails_6_0.gemfile +0 -18
  111. data/gemfiles/rails_master.gemfile +0 -18
  112. data/spec/controllers/application_metal_controller_spec.rb +0 -64
  113. data/spec/controllers/applications_controller_spec.rb +0 -274
  114. data/spec/controllers/authorizations_controller_spec.rb +0 -608
  115. data/spec/controllers/protected_resources_controller_spec.rb +0 -361
  116. data/spec/controllers/token_info_controller_spec.rb +0 -50
  117. data/spec/controllers/tokens_controller_spec.rb +0 -498
  118. data/spec/dummy/Rakefile +0 -9
  119. data/spec/dummy/app/assets/config/manifest.js +0 -2
  120. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  121. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
  122. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
  123. data/spec/dummy/app/controllers/home_controller.rb +0 -18
  124. data/spec/dummy/app/controllers/metal_controller.rb +0 -13
  125. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
  126. data/spec/dummy/app/helpers/application_helper.rb +0 -7
  127. data/spec/dummy/app/models/user.rb +0 -7
  128. data/spec/dummy/app/views/home/index.html.erb +0 -0
  129. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  130. data/spec/dummy/config/application.rb +0 -49
  131. data/spec/dummy/config/boot.rb +0 -7
  132. data/spec/dummy/config/database.yml +0 -15
  133. data/spec/dummy/config/environment.rb +0 -5
  134. data/spec/dummy/config/environments/development.rb +0 -31
  135. data/spec/dummy/config/environments/production.rb +0 -64
  136. data/spec/dummy/config/environments/test.rb +0 -45
  137. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
  138. data/spec/dummy/config/initializers/doorkeeper.rb +0 -166
  139. data/spec/dummy/config/initializers/secret_token.rb +0 -10
  140. data/spec/dummy/config/initializers/session_store.rb +0 -10
  141. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
  142. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  143. data/spec/dummy/config/routes.rb +0 -13
  144. data/spec/dummy/config.ru +0 -6
  145. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
  146. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
  147. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
  148. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
  149. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
  150. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
  151. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
  152. data/spec/dummy/db/schema.rb +0 -68
  153. data/spec/dummy/public/404.html +0 -26
  154. data/spec/dummy/public/422.html +0 -26
  155. data/spec/dummy/public/500.html +0 -26
  156. data/spec/dummy/public/favicon.ico +0 -0
  157. data/spec/dummy/script/rails +0 -9
  158. data/spec/factories.rb +0 -30
  159. data/spec/generators/application_owner_generator_spec.rb +0 -28
  160. data/spec/generators/confidential_applications_generator_spec.rb +0 -29
  161. data/spec/generators/install_generator_spec.rb +0 -36
  162. data/spec/generators/migration_generator_spec.rb +0 -28
  163. data/spec/generators/pkce_generator_spec.rb +0 -28
  164. data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
  165. data/spec/generators/templates/routes.rb +0 -4
  166. data/spec/generators/views_generator_spec.rb +0 -29
  167. data/spec/grape/grape_integration_spec.rb +0 -137
  168. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
  169. data/spec/lib/config_spec.rb +0 -809
  170. data/spec/lib/doorkeeper_spec.rb +0 -27
  171. data/spec/lib/models/expirable_spec.rb +0 -61
  172. data/spec/lib/models/reusable_spec.rb +0 -40
  173. data/spec/lib/models/revocable_spec.rb +0 -59
  174. data/spec/lib/models/scopes_spec.rb +0 -53
  175. data/spec/lib/models/secret_storable_spec.rb +0 -135
  176. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
  177. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -170
  178. data/spec/lib/oauth/base_request_spec.rb +0 -224
  179. data/spec/lib/oauth/base_response_spec.rb +0 -45
  180. data/spec/lib/oauth/client/credentials_spec.rb +0 -90
  181. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -134
  182. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
  183. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
  184. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
  185. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -107
  186. data/spec/lib/oauth/client_spec.rb +0 -38
  187. data/spec/lib/oauth/code_request_spec.rb +0 -46
  188. data/spec/lib/oauth/code_response_spec.rb +0 -32
  189. data/spec/lib/oauth/error_response_spec.rb +0 -64
  190. data/spec/lib/oauth/error_spec.rb +0 -21
  191. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -20
  192. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -110
  193. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
  194. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -262
  195. data/spec/lib/oauth/invalid_request_response_spec.rb +0 -73
  196. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -53
  197. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -190
  198. data/spec/lib/oauth/pre_authorization_spec.rb +0 -223
  199. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
  200. data/spec/lib/oauth/scopes_spec.rb +0 -146
  201. data/spec/lib/oauth/token_request_spec.rb +0 -157
  202. data/spec/lib/oauth/token_response_spec.rb +0 -84
  203. data/spec/lib/oauth/token_spec.rb +0 -156
  204. data/spec/lib/request/strategy_spec.rb +0 -54
  205. data/spec/lib/secret_storing/base_spec.rb +0 -60
  206. data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
  207. data/spec/lib/secret_storing/plain_spec.rb +0 -44
  208. data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
  209. data/spec/lib/server_spec.rb +0 -49
  210. data/spec/lib/stale_records_cleaner_spec.rb +0 -89
  211. data/spec/models/doorkeeper/access_grant_spec.rb +0 -161
  212. data/spec/models/doorkeeper/access_token_spec.rb +0 -622
  213. data/spec/models/doorkeeper/application_spec.rb +0 -482
  214. data/spec/requests/applications/applications_request_spec.rb +0 -259
  215. data/spec/requests/applications/authorized_applications_spec.rb +0 -32
  216. data/spec/requests/endpoints/authorization_spec.rb +0 -91
  217. data/spec/requests/endpoints/token_spec.rb +0 -75
  218. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -79
  219. data/spec/requests/flows/authorization_code_spec.rb +0 -525
  220. data/spec/requests/flows/client_credentials_spec.rb +0 -166
  221. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -46
  222. data/spec/requests/flows/implicit_grant_spec.rb +0 -91
  223. data/spec/requests/flows/password_spec.rb +0 -316
  224. data/spec/requests/flows/refresh_token_spec.rb +0 -233
  225. data/spec/requests/flows/revoke_token_spec.rb +0 -157
  226. data/spec/requests/flows/skip_authorization_spec.rb +0 -66
  227. data/spec/requests/protected_resources/metal_spec.rb +0 -16
  228. data/spec/requests/protected_resources/private_api_spec.rb +0 -83
  229. data/spec/routing/custom_controller_routes_spec.rb +0 -133
  230. data/spec/routing/default_routes_spec.rb +0 -41
  231. data/spec/routing/scoped_routes_spec.rb +0 -47
  232. data/spec/spec_helper.rb +0 -54
  233. data/spec/spec_helper_integration.rb +0 -4
  234. data/spec/support/dependencies/factory_bot.rb +0 -4
  235. data/spec/support/doorkeeper_rspec.rb +0 -22
  236. data/spec/support/helpers/access_token_request_helper.rb +0 -13
  237. data/spec/support/helpers/authorization_request_helper.rb +0 -43
  238. data/spec/support/helpers/config_helper.rb +0 -11
  239. data/spec/support/helpers/model_helper.rb +0 -78
  240. data/spec/support/helpers/request_spec_helper.rb +0 -110
  241. data/spec/support/helpers/url_helper.rb +0 -62
  242. data/spec/support/orm/active_record.rb +0 -5
  243. data/spec/support/shared/controllers_shared_context.rb +0 -133
  244. data/spec/support/shared/hashing_shared_context.rb +0 -36
  245. data/spec/support/shared/models_shared_examples.rb +0 -54
  246. data/spec/validators/redirect_uri_validator_spec.rb +0 -183
  247. data/spec/version/version_spec.rb +0 -17
@@ -1,64 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "doorkeeper/config/abstract_builder"
3
4
  require "doorkeeper/config/option"
5
+ require "doorkeeper/config/validations"
4
6
 
5
7
  module Doorkeeper
6
- class MissingConfiguration < StandardError
7
- # Defines a MissingConfiguration error for a missing Doorkeeper
8
- # configuration
9
- def initialize
10
- super("Configuration for doorkeeper missing. Do you have doorkeeper initializer?")
11
- end
12
- end
13
-
14
- class << self
15
- def configure(&block)
16
- @config = Config::Builder.new(&block).build
17
- setup_orm_adapter
18
- setup_orm_models
19
- setup_application_owner if @config.enable_application_owner?
20
- @config
21
- end
22
-
23
- def configuration
24
- @config || (raise MissingConfiguration)
25
- end
26
-
27
- alias config configuration
28
-
29
- def setup_orm_adapter
30
- @orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
31
- rescue NameError => e
32
- 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
34
- trying to load it.
35
-
36
- You probably need to add the related gem for this adapter to work with
37
- doorkeeper.
38
- ERROR_MSG
39
- end
40
-
41
- def setup_orm_models
42
- @orm_adapter.initialize_models!
43
- end
44
-
45
- def setup_application_owner
46
- @orm_adapter.initialize_application_owner!
47
- end
48
- end
49
-
8
+ # Doorkeeper option DSL could be reused in extensions to build their own
9
+ # configurations. To use the Option DSL gems need to define `builder_class` method
10
+ # that returns configuration Builder class. This exception raises when they don't
11
+ # define it.
12
+ #
50
13
  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
-
14
+ # Default Doorkeeper configuration builder
15
+ class Builder < AbstractBuilder
62
16
  # Provide support for an owner to be assigned to each registered
63
17
  # application (disabled by default)
64
18
  # Optional parameter confirmation: true (default false) if you want
@@ -135,13 +89,13 @@ module Doorkeeper
135
89
  @config.instance_variable_set(:@reuse_access_token, true)
136
90
  end
137
91
 
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)
92
+ # Choose to use the url path for native autorization codes
93
+ # Enabling this flag sets the authorization code response route for
94
+ # native redirect uris to oauth/authorize/<code>. The default is
95
+ # oauth/authorize/native?code=<code>.
96
+ # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1143
97
+ def use_url_path_for_native_authorization
98
+ @config.instance_variable_set(:@use_url_path_for_native_authorization, true)
145
99
  end
146
100
 
147
101
  # TODO: maybe make it more generic for other flows too?
@@ -158,6 +112,12 @@ module Doorkeeper
158
112
  @config.instance_variable_set(:@api_only, true)
159
113
  end
160
114
 
115
+ # Enables polymorphic Resource Owner association for Access Grant and
116
+ # Access Token models. Requires additional database columns to be setup.
117
+ def use_polymorphic_resource_owner
118
+ @config.instance_variable_set(:@polymorphic_resource_owner, true)
119
+ end
120
+
161
121
  # Forbids creating/updating applications with arbitrary scopes that are
162
122
  # not in configuration, i.e. `default_scopes` or `optional_scopes`.
163
123
  # (disabled by default)
@@ -219,7 +179,11 @@ module Doorkeeper
219
179
  end
220
180
  end
221
181
 
182
+ # Replace with `default: Builder` when we drop support of Rails < 5.2
183
+ mattr_reader(:builder_class) { Builder }
184
+
222
185
  extend Option
186
+ include Validations
223
187
 
224
188
  option :resource_owner_authenticator,
225
189
  as: :authenticate_resource_owner,
@@ -251,8 +215,8 @@ module Doorkeeper
251
215
  end)
252
216
 
253
217
  # Hooks for authorization
254
- option :before_successful_authorization, default: ->(_context) {}
255
- option :after_successful_authorization, default: ->(_context) {}
218
+ option :before_successful_authorization, default: ->(_controller, _context = nil) {}
219
+ option :after_successful_authorization, default: ->(_controller, _context = nil) {}
256
220
  # Hooks for strategies responses
257
221
  option :before_successful_strategy_response, default: ->(_request) {}
258
222
  option :after_successful_strategy_response, default: ->(_request, _response) {}
@@ -265,10 +229,34 @@ module Doorkeeper
265
229
  option :authorization_code_expires_in, default: 600
266
230
  option :orm, default: :active_record
267
231
  option :native_redirect_uri, default: "urn:ietf:wg:oauth:2.0:oob", deprecated: true
268
- option :active_record_options, default: {}
269
232
  option :grant_flows, default: %w[authorization_code client_credentials]
270
233
  option :handle_auth_errors, default: :render
271
234
  option :token_lookup_batch_size, default: 10_000
235
+ # Sets the token_reuse_limit
236
+ # It will be used only when reuse_access_token option in enabled
237
+ # By default it will be 100
238
+ # It will be used for token reusablity to some threshold percentage
239
+ # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1189
240
+ option :token_reuse_limit, default: 100
241
+
242
+ # Don't require client authentication for password grants. If client credentials
243
+ # are present they will still be validated, and the grant rejected if the credentials
244
+ # are invalid.
245
+ #
246
+ # This is discouraged. Spec says that password grants always require a client.
247
+ #
248
+ # See https://github.com/doorkeeper-gem/doorkeeper/issues/1412#issuecomment-632750422
249
+ # and https://github.com/doorkeeper-gem/doorkeeper/pull/1420
250
+ #
251
+ # Since many applications use this unsafe behavior in the wild, this is kept as a
252
+ # not-recommended option. You should be aware that you are not following the OAuth
253
+ # spec, and understand the security implications of doing so.
254
+ option :skip_client_authentication_for_password_grant,
255
+ default: false
256
+
257
+ # Hook to allow arbitrary user-client authorization
258
+ option :authorize_resource_owner_for_client,
259
+ default: ->(_client, _resource_owner) { true }
272
260
 
273
261
  # Allows to customize OAuth grant flows that +each+ application support.
274
262
  # You can configure a custom block (or use a class respond to `#call`) that must
@@ -333,17 +321,35 @@ module Doorkeeper
333
321
  option :access_token_generator,
334
322
  default: "Doorkeeper::OAuth::Helpers::UniqueToken"
335
323
 
324
+ # Allows additional data to be received when granting access to an Application, and for this
325
+ # additional data to be sent with subsequently generated access tokens. The access grant and
326
+ # access token models will both need to respond to the specified attribute names.
327
+ #
328
+ # @param attributes [Array] The array of custom attribute names to be saved
329
+ #
330
+ option :custom_access_token_attributes,
331
+ default: []
332
+
333
+ # Use a custom class for generating the application secret.
334
+ # https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-application-secret-generator
335
+ #
336
+ # @param application_secret_generator [String]
337
+ # the name of the application secret generator class
338
+ #
339
+ option :application_secret_generator,
340
+ default: "Doorkeeper::OAuth::Helpers::UniqueToken"
341
+
336
342
  # Default access token generator is a SecureRandom class from Ruby stdlib.
337
343
  # This option defines which method will be used to generate a unique token value.
338
344
  #
339
- # @param access_token_generator [String]
340
- # the name of the access token generator class
345
+ # @param default_generator_method [Symbol]
346
+ # the method name of the default access token generator
341
347
  #
342
348
  option :default_generator_method, default: :urlsafe_base64
343
349
 
344
350
  # The controller Doorkeeper::ApplicationController inherits from.
345
351
  # Defaults to ActionController::Base.
346
- # https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-base-controller
352
+ # https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-controllers
347
353
  #
348
354
  # @param base_controller [String] the name of the base controller
349
355
  option :base_controller,
@@ -410,21 +416,36 @@ module Doorkeeper
410
416
  :token_secret_fallback_strategy,
411
417
  :application_secret_fallback_strategy
412
418
 
413
- # Return the valid subset of this configuration
414
- def validate
415
- validate_reuse_access_token_value
416
- validate_token_reuse_limit
417
- validate_secret_strategies
419
+ def clear_cache!
420
+ %i[
421
+ application_model
422
+ access_token_model
423
+ access_grant_model
424
+ ].each do |var|
425
+ remove_instance_variable("@#{var}") if instance_variable_defined?("@#{var}")
426
+ end
418
427
  end
419
428
 
429
+ # Doorkeeper Access Token model class.
430
+ #
431
+ # @return [ActiveRecord::Base, Mongoid::Document, Sequel::Model]
432
+ #
420
433
  def access_token_model
421
434
  @access_token_model ||= access_token_class.constantize
422
435
  end
423
436
 
437
+ # Doorkeeper Access Grant model class.
438
+ #
439
+ # @return [ActiveRecord::Base, Mongoid::Document, Sequel::Model]
440
+ #
424
441
  def access_grant_model
425
442
  @access_grant_model ||= access_grant_class.constantize
426
443
  end
427
444
 
445
+ # Doorkeeper Application model class.
446
+ #
447
+ # @return [ActiveRecord::Base, Mongoid::Document, Sequel::Model]
448
+ #
428
449
  def application_model
429
450
  @application_model ||= application_class.constantize
430
451
  end
@@ -445,14 +466,6 @@ module Doorkeeper
445
466
  end
446
467
  end
447
468
 
448
- def token_reuse_limit
449
- @token_reuse_limit ||= 100
450
- end
451
-
452
- def revoke_previous_client_credentials_token
453
- @revoke_previous_client_credentials_token || false
454
- end
455
-
456
469
  def resolve_controller(name)
457
470
  config_option = public_send(:"#{name}_controller")
458
471
  controller_name = if config_option.respond_to?(:call)
@@ -464,6 +477,10 @@ module Doorkeeper
464
477
  controller_name.constantize
465
478
  end
466
479
 
480
+ def revoke_previous_client_credentials_token?
481
+ option_set? :revoke_previous_client_credentials_token
482
+ end
483
+
467
484
  def enforce_configured_scopes?
468
485
  option_set? :enforce_configured_scopes
469
486
  end
@@ -472,6 +489,10 @@ module Doorkeeper
472
489
  option_set? :enable_application_owner
473
490
  end
474
491
 
492
+ def polymorphic_resource_owner?
493
+ option_set? :polymorphic_resource_owner
494
+ end
495
+
475
496
  def confirm_application_owner?
476
497
  option_set? :confirm_application_owner
477
498
  end
@@ -480,6 +501,10 @@ module Doorkeeper
480
501
  handle_auth_errors == :raise
481
502
  end
482
503
 
504
+ def application_secret_hashed?
505
+ instance_variable_defined?(:"@application_secret_strategy")
506
+ end
507
+
483
508
  def token_secret_strategy
484
509
  @token_secret_strategy ||= ::Doorkeeper::SecretStoring::Plain
485
510
  end
@@ -516,12 +541,82 @@ module Doorkeeper
516
541
  ]
517
542
  end
518
543
 
544
+ def enabled_grant_flows
545
+ @enabled_grant_flows ||= calculate_grant_flows.map { |name| Doorkeeper::GrantFlow.get(name) }.compact
546
+ end
547
+
548
+ def authorization_response_flows
549
+ @authorization_response_flows ||= enabled_grant_flows.select(&:handles_response_type?) +
550
+ deprecated_authorization_flows
551
+ end
552
+
553
+ def token_grant_flows
554
+ @token_grant_flows ||= calculate_token_grant_flows
555
+ end
556
+
519
557
  def authorization_response_types
520
- @authorization_response_types ||= calculate_authorization_response_types.freeze
558
+ authorization_response_flows.map(&:response_type_matches)
521
559
  end
522
560
 
523
561
  def token_grant_types
524
- @token_grant_types ||= calculate_token_grant_types.freeze
562
+ token_grant_flows.map(&:grant_type_matches)
563
+ end
564
+
565
+ # [NOTE]: deprecated and will be removed soon
566
+ def deprecated_token_grant_types_resolver
567
+ @deprecated_token_grant_types ||= calculate_token_grant_types
568
+ end
569
+
570
+ def native_authorization_code_route
571
+ @use_url_path_for_native_authorization = false unless defined?(@use_url_path_for_native_authorization)
572
+ @use_url_path_for_native_authorization ? '/:code' : '/native'
573
+ end
574
+
575
+ # [NOTE]: deprecated and will be removed soon
576
+ def deprecated_authorization_flows
577
+ response_types = calculate_authorization_response_types
578
+
579
+ if response_types.any?
580
+ ::Kernel.warn <<~WARNING
581
+ Please, don't patch Doorkeeper::Config#calculate_authorization_response_types method.
582
+ Register your custom grant flows using the public API:
583
+ `Doorkeeper::GrantFlow.register(grant_flow_name, **options)`.
584
+ WARNING
585
+ end
586
+
587
+ response_types.map do |response_type|
588
+ Doorkeeper::GrantFlow::FallbackFlow.new(response_type, response_type_matches: response_type)
589
+ end
590
+ end
591
+
592
+ # [NOTE]: deprecated and will be removed soon
593
+ def calculate_authorization_response_types
594
+ []
595
+ end
596
+
597
+ # [NOTE]: deprecated and will be removed soon
598
+ def calculate_token_grant_types
599
+ types = grant_flows - ["implicit"]
600
+ types << "refresh_token" if refresh_token_enabled?
601
+ types
602
+ end
603
+
604
+ # Calculates grant flows configured by the user in Doorkeeper
605
+ # configuration considering registered aliases that is exposed
606
+ # to single or multiple other flows.
607
+ #
608
+ def calculate_grant_flows
609
+ configured_flows = grant_flows.map(&:to_s)
610
+ aliases = Doorkeeper::GrantFlow.aliases.keys.map(&:to_s)
611
+
612
+ flows = configured_flows - aliases
613
+ aliases.each do |flow_alias|
614
+ next unless configured_flows.include?(flow_alias)
615
+
616
+ flows.concat(Doorkeeper::GrantFlow.expand_alias(flow_alias))
617
+ end
618
+
619
+ flows.flatten.uniq
525
620
  end
526
621
 
527
622
  def allow_blank_redirect_uri?(application = nil)
@@ -550,57 +645,10 @@ module Doorkeeper
550
645
  !!(defined?(var) && var)
551
646
  end
552
647
 
553
- # Determines what values are acceptable for 'response_type' param in
554
- # authorization request endpoint, and return them as an array of strings.
555
- #
556
- def calculate_authorization_response_types
557
- types = []
558
- types << "code" if grant_flows.include? "authorization_code"
559
- types << "token" if grant_flows.include? "implicit"
560
- types
561
- end
562
-
563
- # Determines what values are acceptable for 'grant_type' param token
564
- # request endpoint, and return them in array.
565
- #
566
- def calculate_token_grant_types
567
- types = grant_flows - ["implicit"]
568
- types << "refresh_token" if refresh_token_enabled?
569
- types
570
- end
571
-
572
- # Determine whether +reuse_access_token+ and a non-restorable
573
- # +token_secret_strategy+ have both been activated.
574
- #
575
- # In that case, disable reuse_access_token value and warn the user.
576
- def validate_reuse_access_token_value
577
- strategy = token_secret_strategy
578
- return if !reuse_access_token || strategy.allows_restoring_secrets?
579
-
580
- ::Rails.logger.warn(
581
- "You have configured both reuse_access_token " \
582
- "AND strategy strategy '#{strategy}' that cannot restore tokens. " \
583
- "This combination is unsupported. reuse_access_token will be disabled",
584
- )
585
- @reuse_access_token = false
586
- end
587
-
588
- # Validate that the provided strategies are valid for
589
- # tokens and applications
590
- def validate_secret_strategies
591
- token_secret_strategy.validate_for :token
592
- application_secret_strategy.validate_for :application
593
- end
594
-
595
- def validate_token_reuse_limit
596
- return if !reuse_access_token ||
597
- (token_reuse_limit > 0 && token_reuse_limit <= 100)
598
-
599
- ::Rails.logger.warn(
600
- "You have configured an invalid value for token_reuse_limit option. " \
601
- "It will be set to default 100",
602
- )
603
- @token_reuse_limit = 100
648
+ def calculate_token_grant_flows
649
+ flows = enabled_grant_flows.select(&:handles_grant_type?)
650
+ flows << Doorkeeper::GrantFlow.get("refresh_token") if refresh_token_enabled?
651
+ flows
604
652
  end
605
653
  end
606
654
  end
@@ -2,9 +2,12 @@
2
2
 
3
3
  module Doorkeeper
4
4
  class Engine < Rails::Engine
5
- initializer "doorkeeper.params.filter" do |app|
6
- parameters = %w[client_secret code authentication_token access_token refresh_token]
7
- app.config.filter_parameters << /^(#{Regexp.union parameters})$/
5
+ initializer "doorkeeper.params.filter", after: :load_config_initializers do |app|
6
+ if Doorkeeper.configured?
7
+ parameters = %w[client_secret authentication_token access_token refresh_token]
8
+ parameters << "code" if Doorkeeper.config.grant_flows.include?("authorization_code")
9
+ app.config.filter_parameters << /^(#{Regexp.union(parameters)})$/
10
+ end
8
11
  end
9
12
 
10
13
  initializer "doorkeeper.routes" do
@@ -17,6 +20,10 @@ module Doorkeeper
17
20
  end
18
21
  end
19
22
 
23
+ config.to_prepare do
24
+ Doorkeeper.run_orm_hooks
25
+ end
26
+
20
27
  if defined?(Sprockets) && Sprockets::VERSION.chr.to_i >= 4
21
28
  initializer "doorkeeper.assets.precompile" do |app|
22
29
  # Force users to use:
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module GrantFlow
5
+ class FallbackFlow < Flow
6
+ def handles_grant_type?
7
+ false
8
+ end
9
+
10
+ def handles_response_type?
11
+ false
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module GrantFlow
5
+ class Flow
6
+ attr_reader :name, :grant_type_matches, :grant_type_strategy,
7
+ :response_type_matches, :response_type_strategy,
8
+ :response_mode_matches
9
+
10
+ def initialize(name, **options)
11
+ @name = name
12
+ @grant_type_matches = options[:grant_type_matches]
13
+ @grant_type_strategy = options[:grant_type_strategy]
14
+ @response_type_matches = options[:response_type_matches]
15
+ @response_type_strategy = options[:response_type_strategy]
16
+ @response_mode_matches = options[:response_mode_matches]
17
+ end
18
+
19
+ def handles_grant_type?
20
+ grant_type_matches.present?
21
+ end
22
+
23
+ def handles_response_type?
24
+ response_type_matches.present?
25
+ end
26
+
27
+ def matches_grant_type?(value)
28
+ grant_type_matches === value
29
+ end
30
+
31
+ def matches_response_type?(value)
32
+ response_type_matches === value
33
+ end
34
+
35
+ def default_response_mode
36
+ response_mode_matches[0]
37
+ end
38
+
39
+ def matches_response_mode?(value)
40
+ response_mode_matches.include?(value)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module GrantFlow
5
+ module Registry
6
+ mattr_accessor :flows
7
+ self.flows = {}
8
+
9
+ mattr_accessor :aliases
10
+ self.aliases = {}
11
+
12
+ # Allows to register custom OAuth grant flow so that Doorkeeper
13
+ # could recognize and process it.
14
+ #
15
+ def register(name_or_flow, **options)
16
+ unless name_or_flow.is_a?(Doorkeeper::GrantFlow::Flow)
17
+ name_or_flow = Flow.new(name_or_flow, **options)
18
+ end
19
+
20
+ flow_key = name_or_flow.name.to_sym
21
+
22
+ if flows.key?(flow_key)
23
+ ::Kernel.warn <<~WARNING
24
+ [DOORKEEPER] '#{flow_key}' grant flow already registered and will be overridden
25
+ in #{caller(1..1).first}
26
+ WARNING
27
+ end
28
+
29
+ flows[flow_key] = name_or_flow
30
+ end
31
+
32
+ # Allows to register aliases that could be used in `grant_flows`
33
+ # configuration option. It is possible to have aliases like 1:1 or
34
+ # 1:N, i.e. "implicit_oidc" => ['token', 'id_token', 'id_token token'].
35
+ #
36
+ def register_alias(alias_name, **options)
37
+ aliases[alias_name.to_sym] = Array.wrap(options.fetch(:as))
38
+ end
39
+
40
+ def expand_alias(alias_name)
41
+ aliases.fetch(alias_name.to_sym, [])
42
+ end
43
+
44
+ # [NOTE]: make it to use #fetch after removing fallbacks
45
+ def get(name)
46
+ flows[name.to_sym]
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "doorkeeper/grant_flow/flow"
4
+ require "doorkeeper/grant_flow/fallback_flow"
5
+ require "doorkeeper/grant_flow/registry"
6
+
7
+ module Doorkeeper
8
+ module GrantFlow
9
+ extend Registry
10
+
11
+ register(
12
+ :implicit,
13
+ response_type_matches: "token",
14
+ response_mode_matches: %w[fragment form_post],
15
+ response_type_strategy: Doorkeeper::Request::Token,
16
+ )
17
+
18
+ register(
19
+ :authorization_code,
20
+ response_type_matches: "code",
21
+ response_mode_matches: %w[query fragment form_post],
22
+ response_type_strategy: Doorkeeper::Request::Code,
23
+ grant_type_matches: "authorization_code",
24
+ grant_type_strategy: Doorkeeper::Request::AuthorizationCode,
25
+ )
26
+
27
+ register(
28
+ :client_credentials,
29
+ grant_type_matches: "client_credentials",
30
+ grant_type_strategy: Doorkeeper::Request::ClientCredentials,
31
+ )
32
+
33
+ register(
34
+ :password,
35
+ grant_type_matches: "password",
36
+ grant_type_strategy: Doorkeeper::Request::Password,
37
+ )
38
+
39
+ register(
40
+ :refresh_token,
41
+ grant_type_matches: "refresh_token",
42
+ grant_type_strategy: Doorkeeper::Request::RefreshToken,
43
+ )
44
+ end
45
+ end
@@ -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
 
@@ -16,6 +16,8 @@ module Doorkeeper
16
16
 
17
17
  # :doc:
18
18
  def current_resource_owner
19
+ return @current_resource_owner if defined?(@current_resource_owner)
20
+
19
21
  @current_resource_owner ||= begin
20
22
  instance_eval(&Doorkeeper.config.authenticate_resource_owner)
21
23
  end
@@ -36,7 +38,9 @@ module Doorkeeper
36
38
 
37
39
  # :doc:
38
40
  def doorkeeper_token
39
- @doorkeeper_token ||= OAuth::Token.authenticate request, *config_methods
41
+ return @doorkeeper_token if defined?(@doorkeeper_token)
42
+
43
+ @doorkeeper_token ||= OAuth::Token.authenticate(request, *config_methods)
40
44
  end
41
45
 
42
46
  def config_methods
@@ -58,10 +62,10 @@ module Doorkeeper
58
62
  end
59
63
 
60
64
  def handle_token_exception(exception)
61
- error = get_error_response_from_exception exception
62
- headers.merge! error.headers
65
+ error = get_error_response_from_exception(exception)
66
+ headers.merge!(error.headers)
63
67
  self.response_body = error.body.to_json
64
- self.status = error.status
68
+ self.status = error.status
65
69
  end
66
70
 
67
71
  def skip_authorization?
@@ -78,7 +82,7 @@ module Doorkeeper
78
82
  end
79
83
 
80
84
  def x_www_form_urlencoded?
81
- request.content_type == "application/x-www-form-urlencoded"
85
+ request.media_type == "application/x-www-form-urlencoded"
82
86
  end
83
87
  end
84
88
  end