doorkeeper 5.6.2 → 5.6.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +35 -8
  3. data/README.md +1 -1
  4. data/app/controllers/doorkeeper/authorizations_controller.rb +17 -5
  5. data/app/views/doorkeeper/authorizations/error.html.erb +3 -1
  6. data/lib/doorkeeper/config/abstract_builder.rb +1 -1
  7. data/lib/doorkeeper/config.rb +9 -75
  8. data/lib/doorkeeper/engine.rb +7 -5
  9. data/lib/doorkeeper/models/access_token_mixin.rb +4 -3
  10. data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +30 -0
  11. data/lib/doorkeeper/oauth/authorization/code.rb +7 -1
  12. data/lib/doorkeeper/oauth/authorization_code_request.rb +16 -6
  13. data/lib/doorkeeper/oauth/base_request.rb +11 -10
  14. data/lib/doorkeeper/oauth/client_credentials/creator.rb +7 -11
  15. data/lib/doorkeeper/oauth/error_response.rb +1 -2
  16. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +3 -3
  17. data/lib/doorkeeper/oauth/password_access_token_request.rb +2 -2
  18. data/lib/doorkeeper/oauth/pre_authorization.rb +11 -10
  19. data/lib/doorkeeper/oauth/refresh_token_request.rb +12 -4
  20. data/lib/doorkeeper/oauth/token_introspection.rb +1 -1
  21. data/lib/doorkeeper/oauth/token_response.rb +1 -2
  22. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +0 -6
  23. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +0 -4
  24. data/lib/doorkeeper/orm/active_record/mixins/application.rb +0 -4
  25. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +2 -2
  26. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +5 -2
  27. data/lib/doorkeeper/orm/active_record.rb +7 -11
  28. data/lib/doorkeeper/rails/routes.rb +6 -1
  29. data/lib/doorkeeper/version.rb +1 -1
  30. data/lib/doorkeeper.rb +72 -5
  31. data/lib/generators/doorkeeper/templates/initializer.rb +17 -0
  32. data/lib/generators/doorkeeper/templates/migration.rb.erb +14 -4
  33. metadata +5 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c22e5cf14aebfd8b75510d028c123f9a924d13bf08c2717f2d7ce6c8bc202a1
4
- data.tar.gz: 5c625f6be3f5412c546a175c310577c737407690328e6696a773ab74dd1abe13
3
+ metadata.gz: b62a0472a97d06b40362817c9d5c0dd7dd6e0d0e600437a19f5cf2fd18c4be46
4
+ data.tar.gz: 9850cef14c21a1f0df2fb451a485ab5b8066360a3008124f7aed287409364e36
5
5
  SHA512:
6
- metadata.gz: 127dd3e716bfde2c825ba1d6c4fee662a80a809063a8bd0d5480767fc472c41a6208742407f47656dae95cb7d41b1cb30a920b0270fd2c194a3267fc2c843626
7
- data.tar.gz: e17e0349cefce41f7767f944fded43b71221b0df82042a9fb9c0dddb464308f3642fe2af7fc61bc1ec4ebb09cb3d2ea1d7a3040adc41130259e495cf3e129386
6
+ metadata.gz: de0c7021c4735b26249e5b267db11ede06f55b23d8f9bd51641d1cf3eee3812e14a2deec986e8aa6ee81de98097083fdb634a441fd4928cb47286fa977ba5d96
7
+ data.tar.gz: 3865639c837771ceeafceec8a110e506f88fef45c61f7274782c637e794f9185be18ee98270852bac6fecb0fc90e4893dfed08d715c761507e87396e5a559bc2
data/CHANGELOG.md CHANGED
@@ -9,6 +9,33 @@ User-visible changes worth mentioning.
9
9
 
10
10
  - [#ID] Add your PR description here.
11
11
 
12
+ ## 5.6.6
13
+
14
+ - [#1644] Update HTTP headers.
15
+ - [#1646] Block public clients automatic authorization skip.
16
+ - [#1648] Add custom token attributes to Refresh Token Request.
17
+ - [#1649] Fixed custom_access_token_attributes related errors.
18
+
19
+ # 5.6.5
20
+
21
+ - [#1602] Allow custom data to be stored inside access grants/tokens.
22
+ - [#1634] Code refactoring for custom token attributes.
23
+ - [#1639] Add grant type validation to avoid Internal Server Error for DELETE /oauth/authorize endpoint.
24
+
25
+ # 5.6.4
26
+
27
+ - [#1633] Apply ORM configuration in #to_prepare block to avoid autoloading errors.
28
+
29
+ # 5.6.3
30
+
31
+ - [#1622] Drop support for Rubies 2.5 and 2.6
32
+ - [#1605] Fix URI validation for Ruby 3.2+.
33
+ - [#1625] Exclude endless access tokens from `StaleRecordsCleaner`.
34
+ - [#1626] Remove deprecated `active_record_options` config option.
35
+ - [#1631] Fix regression with redirect behavior after token lookup optimizations (redirect to app URI when found).
36
+ - [#1630] Special case unique index creation for refresh_token on SQL Server.
37
+ - [#1627] Lazy evaluate Doorkeeper config when loading files and executing initializers.
38
+
12
39
  ## 5.6.2
13
40
 
14
41
  - [#1604] Fix fetching of the application when custom application_class defined.
@@ -23,9 +50,9 @@ User-visible changes worth mentioning.
23
50
 
24
51
  - [#1581] Consider `token_type_hint` when searching for access token in TokensController to avoid extra database calls.
25
52
 
26
- ## 5.6.0.rc1
53
+ ## 5.6.0.rc2
27
54
 
28
- - [#1558] Fixed bug: able to obtain a token with default scopes even if they are not present in the
55
+ - [#1558] Fixed bug: able to obtain a token with default scopes even if they are not present in the
29
56
  application scopes when using client credentials.
30
57
  - [#1567] Only filter `code` parameter if authorization_code grant flow is enabled.
31
58
 
@@ -60,7 +87,7 @@ User-visible changes worth mentioning.
60
87
  ## 5.5.1
61
88
 
62
89
  - [#1496] Revoke `old_refresh_token` if `previous_refresh_token` is present.
63
- - [#1495] Fix `respond_to` undefined in API-only mode
90
+ - [#1495] Fix `respond_to` undefined in API-only mode
64
91
  - [#1488] Verify client authentication for Resource Owner Password Grant when
65
92
  `config.skip_client_authentication_for_password_grant` is set and the client credentials
66
93
  are sent in a HTTP Basic auth header.
@@ -74,10 +101,10 @@ User-visible changes worth mentioning.
74
101
  ## 5.5.0.rc2
75
102
 
76
103
  - [#1473] Enable `Applications` and `AuthorizedApplications` controllers in API mode.
77
-
78
- **[IMPORTANT]** you can still skip these controllers using `skip_controllers` in
104
+
105
+ **[IMPORTANT]** you can still skip these controllers using `skip_controllers` in
79
106
  `use_doorkeeper` inside `routes.rb`. Please do it in case you don't need them.
80
-
107
+
81
108
  - [#1472] Fix `establish_connection` configuration for custom defined models.
82
109
  - [#1471] Add support for Ruby 3.0.
83
110
  - [#1469] Check if `redirect_uri` exists.
@@ -284,7 +311,7 @@ User-visible changes worth mentioning.
284
311
  - [#1237] Allow to set blank redirect URI if Doorkeeper configured to use redirect URI-less grant flows.
285
312
  - [#1234] Fix `StaleRecordsCleaner` to properly work with big amount of records.
286
313
  - [#1228] Allow to explicitly set non-expiring tokens in `custom_access_token_expires_in` configuration
287
- option using `Float::INIFINITY` return value.
314
+ option using `Float::INFINITY` return value.
288
315
  - [#1224] Do not try to store token if not found by fallback hashing strategy.
289
316
  - [#1223] Update Hound/Rubocop rules, correct Doorkeeper codebase to follow style-guides.
290
317
  - [#1220] Drop Rails 4.2 & Ruby < 2.4 support.
@@ -369,7 +396,7 @@ User-visible changes worth mentioning.
369
396
  - [#1116] `AccessGrant`s will now be revoked along with `AccessToken`s when
370
397
  hitting the `AuthorizedApplicationController#destroy` route.
371
398
  - [#1114] Make token info endpoint's attributes consistent with token creation
372
- - [#1108] Simple formating of callback URLs when listing oauth applications
399
+ - [#1108] Simple formatting of callback URLs when listing oauth applications
373
400
  - [#1106] Restrict access to AdminController with 'Forbidden 403' if admin_authenticator is not
374
401
  configured by developers.
375
402
 
data/README.md CHANGED
@@ -105,7 +105,7 @@ Extensions that are not included by default and can be installed separately.
105
105
  | JWT Token support | [doorkeeper-gem/doorkeeper-jwt](https://github.com/doorkeeper-gem/doorkeeper-jwt) |
106
106
  | Assertion grant extension | [doorkeeper-gem/doorkeeper-grants\_assertion](https://github.com/doorkeeper-gem/doorkeeper-grants_assertion) |
107
107
  | I18n translations | [doorkeeper-gem/doorkeeper-i18n](https://github.com/doorkeeper-gem/doorkeeper-i18n) |
108
- | CIBA - Client Initiated Backchannel Authentication Flow extention | [doorkeeper-ciba](https://github.com/autoseg/doorkeeper-ciba) |
108
+ | CIBA - Client Initiated Backchannel Authentication Flow extension | [doorkeeper-ciba](https://github.com/autoseg/doorkeeper-ciba) |
109
109
  | Device Authorization Grant | [doorkeeper-device_authorization_grant](https://github.com/exop-group/doorkeeper-device_authorization_grant) |
110
110
 
111
111
  ## Example Applications
@@ -13,17 +13,25 @@ module Doorkeeper
13
13
  end
14
14
 
15
15
  def create
16
- redirect_or_render authorize_response
16
+ redirect_or_render(authorize_response)
17
17
  end
18
18
 
19
19
  def destroy
20
- redirect_or_render authorization.deny
20
+ redirect_or_render(authorization.deny)
21
+ rescue Doorkeeper::Errors::InvalidTokenStrategy => e
22
+ error_response = get_error_response_from_exception(e)
23
+
24
+ if Doorkeeper.configuration.api_only
25
+ render json: error_response.body, status: :bad_request
26
+ else
27
+ render :error, locals: { error_response: error_response }
28
+ end
21
29
  end
22
30
 
23
31
  private
24
32
 
25
33
  def render_success
26
- if skip_authorization? || matching_token?
34
+ if skip_authorization? || (matching_token? && pre_auth.client.application.confidential?)
27
35
  redirect_or_render(authorize_response)
28
36
  elsif Doorkeeper.configuration.api_only
29
37
  render json: pre_auth
@@ -37,7 +45,7 @@ module Doorkeeper
37
45
  render json: pre_auth.error_response.body,
38
46
  status: :bad_request
39
47
  else
40
- render :error
48
+ render :error, locals: { error_response: pre_auth.error_response }
41
49
  end
42
50
  end
43
51
 
@@ -88,7 +96,7 @@ module Doorkeeper
88
96
  end
89
97
 
90
98
  def pre_auth_param_fields
91
- %i[
99
+ custom_access_token_attributes + %i[
92
100
  client_id
93
101
  code_challenge
94
102
  code_challenge_method
@@ -100,6 +108,10 @@ module Doorkeeper
100
108
  ]
101
109
  end
102
110
 
111
+ def custom_access_token_attributes
112
+ Doorkeeper.config.custom_access_token_attributes.map(&:to_sym)
113
+ end
114
+
103
115
  def authorization
104
116
  @authorization ||= strategy.request
105
117
  end
@@ -3,5 +3,7 @@
3
3
  </div>
4
4
 
5
5
  <main role="main">
6
- <pre><%= @pre_auth.error_response.body[:error_description] %></pre>
6
+ <pre>
7
+ <%= (respond_to?(:error_response) ? error_response : @pre_auth.error_response).body[:error_description] %>
8
+ </pre>
7
9
  </main>
@@ -12,7 +12,7 @@ module Doorkeeper
12
12
  #
13
13
  def initialize(config = Config.new, &block)
14
14
  @config = config
15
- instance_eval(&block)
15
+ instance_eval(&block) if block_given?
16
16
  end
17
17
 
18
18
  # Builds and validates configuration.
@@ -5,81 +5,11 @@ require "doorkeeper/config/option"
5
5
  require "doorkeeper/config/validations"
6
6
 
7
7
  module Doorkeeper
8
- # Defines a MissingConfiguration error for a missing Doorkeeper configuration
9
- #
10
- class MissingConfiguration < StandardError
11
- def initialize
12
- super("Configuration for doorkeeper missing. Do you have doorkeeper initializer?")
13
- end
14
- end
15
-
16
8
  # Doorkeeper option DSL could be reused in extensions to build their own
17
9
  # configurations. To use the Option DSL gems need to define `builder_class` method
18
10
  # that returns configuration Builder class. This exception raises when they don't
19
11
  # define it.
20
12
  #
21
- class MissingConfigurationBuilderClass < StandardError; end
22
-
23
- class << self
24
- attr_reader :orm_adapter
25
-
26
- def configure(&block)
27
- @config = Config::Builder.new(&block).build
28
- end
29
-
30
- # @return [Doorkeeper::Config] configuration instance
31
- #
32
- def configuration
33
- @config || (raise MissingConfiguration)
34
- end
35
-
36
- alias config configuration
37
-
38
- def setup
39
- setup_orm_adapter
40
- run_orm_hooks
41
- config.clear_cache!
42
-
43
- # Deprecated, will be removed soon
44
- unless configuration.orm == :active_record
45
- setup_orm_models
46
- setup_application_owner
47
- end
48
- end
49
-
50
- def setup_orm_adapter
51
- @orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
52
- rescue NameError => e
53
- raise e, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.strip_heredoc
54
- [DOORKEEPER] ORM adapter not found (#{configuration.orm}), or there was an error
55
- trying to load it.
56
-
57
- You probably need to add the related gem for this adapter to work with
58
- doorkeeper.
59
- ERROR_MSG
60
- end
61
-
62
- def run_orm_hooks
63
- if @orm_adapter.respond_to?(:run_hooks)
64
- @orm_adapter.run_hooks
65
- else
66
- ::Kernel.warn <<~MSG.strip_heredoc
67
- [DOORKEEPER] ORM "#{configuration.orm}" should move all it's setup logic under `#run_hooks` method for
68
- the #{@orm_adapter.name}. Later versions of Doorkeeper will no longer support `setup_orm_models` and
69
- `setup_application_owner` API.
70
- MSG
71
- end
72
- end
73
-
74
- def setup_orm_models
75
- @orm_adapter.initialize_models!
76
- end
77
-
78
- def setup_application_owner
79
- @orm_adapter.initialize_application_owner!
80
- end
81
- end
82
-
83
13
  class Config
84
14
  # Default Doorkeeper configuration builder
85
15
  class Builder < AbstractBuilder
@@ -324,11 +254,6 @@ module Doorkeeper
324
254
  option :skip_client_authentication_for_password_grant,
325
255
  default: false
326
256
 
327
- # TODO: remove the option
328
- option :active_record_options,
329
- default: {},
330
- deprecated: { message: "Customize Doorkeeper models instead" }
331
-
332
257
  # Hook to allow arbitrary user-client authorization
333
258
  option :authorize_resource_owner_for_client,
334
259
  default: ->(_client, _resource_owner) { true }
@@ -396,6 +321,15 @@ module Doorkeeper
396
321
  option :access_token_generator,
397
322
  default: "Doorkeeper::OAuth::Helpers::UniqueToken"
398
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
+
399
333
  # Use a custom class for generating the application secret.
400
334
  # https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-application-secret-generator
401
335
  #
@@ -2,10 +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 authentication_token access_token refresh_token]
7
- parameters << "code" if Doorkeeper.config.grant_flows.include?("authorization_code")
8
- 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
9
11
  end
10
12
 
11
13
  initializer "doorkeeper.routes" do
@@ -19,7 +21,7 @@ module Doorkeeper
19
21
  end
20
22
 
21
23
  config.to_prepare do
22
- Doorkeeper.setup
24
+ Doorkeeper.run_orm_hooks
23
25
  end
24
26
 
25
27
  if defined?(Sprockets) && Sprockets::VERSION.chr.to_i >= 4
@@ -87,8 +87,9 @@ module Doorkeeper
87
87
  # @return [Doorkeeper::AccessToken, nil] Access Token instance or
88
88
  # nil if matching record was not found
89
89
  #
90
- def matching_token_for(application, resource_owner, scopes)
91
- tokens = authorized_tokens_for(application&.id, resource_owner).not_expired
90
+ def matching_token_for(application, resource_owner, scopes, include_expired: true)
91
+ tokens = authorized_tokens_for(application&.id, resource_owner)
92
+ tokens = tokens.not_expired unless include_expired
92
93
  find_matching_token(tokens, application, scopes)
93
94
  end
94
95
 
@@ -180,7 +181,7 @@ module Doorkeeper
180
181
  #
181
182
  def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
182
183
  if Doorkeeper.config.reuse_access_token
183
- access_token = matching_token_for(application, resource_owner, scopes)
184
+ access_token = matching_token_for(application, resource_owner, scopes, include_expired: false)
184
185
 
185
186
  return access_token if access_token&.reusable?
186
187
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module PolymorphicResourceOwner
6
+ module ForAccessGrant
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ if Doorkeeper.config.polymorphic_resource_owner?
11
+ belongs_to :resource_owner, polymorphic: true, optional: false
12
+ else
13
+ validates :resource_owner_id, presence: true
14
+ end
15
+ end
16
+ end
17
+
18
+ module ForAccessToken
19
+ extend ActiveSupport::Concern
20
+
21
+ included do
22
+ if Doorkeeper.config.polymorphic_resource_owner?
23
+ belongs_to :resource_owner, polymorphic: true, optional: true
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -45,7 +45,13 @@ module Doorkeeper
45
45
  attributes[:resource_owner_id] = resource_owner.id
46
46
  end
47
47
 
48
- pkce_attributes.merge(attributes)
48
+ pkce_attributes.merge(attributes).merge(custom_attributes)
49
+ end
50
+
51
+ def custom_attributes
52
+ # Custom access token attributes are saved into the access grant,
53
+ # and then included in subsequently generated access tokens.
54
+ @pre_auth.custom_access_token_attributes.to_h.with_indifferent_access
49
55
  end
50
56
 
51
57
  def pkce_attributes
@@ -35,6 +35,7 @@ module Doorkeeper
35
35
  grant.application,
36
36
  resource_owner,
37
37
  grant.scopes,
38
+ custom_token_attributes_with_data,
38
39
  server,
39
40
  )
40
41
  end
@@ -55,11 +56,12 @@ module Doorkeeper
55
56
  end
56
57
 
57
58
  def validate_params
58
- @missing_param = if grant&.uses_pkce? && code_verifier.blank?
59
- :code_verifier
60
- elsif redirect_uri.blank?
61
- :redirect_uri
62
- end
59
+ @missing_param =
60
+ if grant&.uses_pkce? && code_verifier.blank?
61
+ :code_verifier
62
+ elsif redirect_uri.blank?
63
+ :redirect_uri
64
+ end
63
65
 
64
66
  @missing_param.nil?
65
67
  end
@@ -97,7 +99,15 @@ module Doorkeeper
97
99
  end
98
100
 
99
101
  def generate_code_challenge(code_verifier)
100
- server_config.access_grant_model.generate_code_challenge(code_verifier)
102
+ Doorkeeper.config.access_grant_model.generate_code_challenge(code_verifier)
103
+ end
104
+
105
+ def custom_token_attributes_with_data
106
+ grant
107
+ .attributes
108
+ .with_indifferent_access
109
+ .slice(*Doorkeeper.config.custom_access_token_attributes)
110
+ .symbolize_keys
101
111
  end
102
112
  end
103
113
  end
@@ -26,27 +26,28 @@ module Doorkeeper
26
26
  @scopes ||= build_scopes
27
27
  end
28
28
 
29
- def find_or_create_access_token(client, resource_owner, scopes, server)
29
+ def find_or_create_access_token(client, resource_owner, scopes, custom_attributes, server)
30
30
  context = Authorization::Token.build_context(client, grant_type, scopes, resource_owner)
31
- @access_token = server_config.access_token_model.find_or_create_for(
32
- application: client.is_a?(server_config.application_model) ? client : client&.application,
31
+ application = client.is_a?(Doorkeeper.config.application_model) ? client : client&.application
32
+
33
+ token_attributes = {
34
+ application: application,
33
35
  resource_owner: resource_owner,
34
36
  scopes: scopes,
35
37
  expires_in: Authorization::Token.access_token_expires_in(server, context),
36
38
  use_refresh_token: Authorization::Token.refresh_token_enabled?(server, context),
37
- )
39
+ }
40
+
41
+ @access_token =
42
+ Doorkeeper.config.access_token_model.find_or_create_for(**token_attributes.merge(custom_attributes))
38
43
  end
39
44
 
40
45
  def before_successful_response
41
- server_config.before_successful_strategy_response.call(self)
46
+ Doorkeeper.config.before_successful_strategy_response.call(self)
42
47
  end
43
48
 
44
49
  def after_successful_response
45
- server_config.after_successful_strategy_response.call(self, @response)
46
- end
47
-
48
- def server_config
49
- Doorkeeper.config
50
+ Doorkeeper.config.after_successful_strategy_response.call(self, @response)
50
51
  end
51
52
 
52
53
  private
@@ -9,12 +9,12 @@ module Doorkeeper
9
9
 
10
10
  if lookup_existing_token?
11
11
  existing_token = find_active_existing_token_for(client, scopes)
12
- return existing_token if server_config.reuse_access_token && existing_token&.reusable?
12
+ return existing_token if Doorkeeper.config.reuse_access_token && existing_token&.reusable?
13
13
  end
14
14
 
15
15
  with_revocation(existing_token: existing_token) do
16
- application = client.is_a?(server_config.application_model) ? client : client&.application
17
- server_config.access_token_model.create_for(
16
+ application = client.is_a?(Doorkeeper.config.application_model) ? client : client&.application
17
+ Doorkeeper.config.access_token_model.create_for(
18
18
  application: application,
19
19
  resource_owner: nil,
20
20
  scopes: scopes,
@@ -26,7 +26,7 @@ module Doorkeeper
26
26
  private
27
27
 
28
28
  def with_revocation(existing_token:)
29
- if existing_token && server_config.revoke_previous_client_credentials_token?
29
+ if existing_token && Doorkeeper.config.revoke_previous_client_credentials_token?
30
30
  existing_token.with_lock do
31
31
  raise Errors::DoorkeeperError, :invalid_token_reuse if existing_token.revoked?
32
32
 
@@ -40,16 +40,12 @@ module Doorkeeper
40
40
  end
41
41
 
42
42
  def lookup_existing_token?
43
- server_config.reuse_access_token ||
44
- server_config.revoke_previous_client_credentials_token?
43
+ Doorkeeper.config.reuse_access_token ||
44
+ Doorkeeper.config.revoke_previous_client_credentials_token?
45
45
  end
46
46
 
47
47
  def find_active_existing_token_for(client, scopes)
48
- server_config.access_token_model.matching_token_for(client, nil, scopes)
49
- end
50
-
51
- def server_config
52
- Doorkeeper.config
48
+ Doorkeeper.config.access_token_model.matching_token_for(client, nil, scopes, include_expired: false)
53
49
  end
54
50
  end
55
51
  end
@@ -55,8 +55,7 @@ module Doorkeeper
55
55
 
56
56
  def headers
57
57
  {
58
- "Cache-Control" => "no-store",
59
- "Pragma" => "no-cache",
58
+ "Cache-Control" => "no-store, no-cache",
60
59
  "Content-Type" => "application/json; charset=utf-8",
61
60
  "WWW-Authenticate" => authenticate_info,
62
61
  }
@@ -61,9 +61,9 @@ module Doorkeeper
61
61
  end
62
62
 
63
63
  def self.valid_scheme?(uri)
64
- return false if uri.scheme.nil?
64
+ return false if uri.scheme.blank?
65
65
 
66
- %w[localhost].include?(uri.scheme) == false
66
+ %w[localhost].exclude?(uri.scheme)
67
67
  end
68
68
 
69
69
  def self.hypertext_scheme?(uri)
@@ -71,7 +71,7 @@ module Doorkeeper
71
71
  end
72
72
 
73
73
  def self.iff_host?(uri)
74
- !(hypertext_scheme?(uri) && uri.host.nil?)
74
+ !(hypertext_scheme?(uri) && uri.host.blank?)
75
75
  end
76
76
 
77
77
  def self.oob_uri?(uri)
@@ -25,7 +25,7 @@ module Doorkeeper
25
25
  private
26
26
 
27
27
  def before_successful_response
28
- find_or_create_access_token(client, resource_owner, scopes, server)
28
+ find_or_create_access_token(client, resource_owner, scopes, {}, server)
29
29
  super
30
30
  end
31
31
 
@@ -68,7 +68,7 @@ module Doorkeeper
68
68
  end
69
69
 
70
70
  def validate_client_supports_grant_flow
71
- server_config.allow_grant_flow_for_client?(grant_type, client&.application)
71
+ Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client&.application)
72
72
  end
73
73
  end
74
74
  end
@@ -18,19 +18,20 @@ module Doorkeeper
18
18
 
19
19
  attr_reader :client, :code_challenge, :code_challenge_method, :missing_param,
20
20
  :redirect_uri, :resource_owner, :response_type, :state,
21
- :authorization_response_flow, :response_mode
21
+ :authorization_response_flow, :response_mode, :custom_access_token_attributes
22
22
 
23
23
  def initialize(server, parameters = {}, resource_owner = nil)
24
- @server = server
25
- @client_id = parameters[:client_id]
26
- @response_type = parameters[:response_type]
27
- @response_mode = parameters[:response_mode]
28
- @redirect_uri = parameters[:redirect_uri]
29
- @scope = parameters[:scope]
30
- @state = parameters[:state]
31
- @code_challenge = parameters[:code_challenge]
24
+ @server = server
25
+ @client_id = parameters[:client_id]
26
+ @response_type = parameters[:response_type]
27
+ @response_mode = parameters[:response_mode]
28
+ @redirect_uri = parameters[:redirect_uri]
29
+ @scope = parameters[:scope]
30
+ @state = parameters[:state]
31
+ @code_challenge = parameters[:code_challenge]
32
32
  @code_challenge_method = parameters[:code_challenge_method]
33
- @resource_owner = resource_owner
33
+ @resource_owner = resource_owner
34
+ @custom_access_token_attributes = parameters.slice(*Doorkeeper.config.custom_access_token_attributes)
34
35
  end
35
36
 
36
37
  def authorizable?
@@ -26,7 +26,7 @@ module Doorkeeper
26
26
  private
27
27
 
28
28
  def load_client(credentials)
29
- server_config.application_model.by_uid_and_secret(credentials.uid, credentials.secret)
29
+ Doorkeeper.config.application_model.by_uid_and_secret(credentials.uid, credentials.secret)
30
30
  end
31
31
 
32
32
  def before_successful_response
@@ -41,7 +41,7 @@ module Doorkeeper
41
41
  end
42
42
 
43
43
  def refresh_token_revoked_on_use?
44
- server_config.access_token_model.refresh_token_revoked_on_use?
44
+ Doorkeeper.config.access_token_model.refresh_token_revoked_on_use?
45
45
  end
46
46
 
47
47
  def default_scopes
@@ -49,7 +49,7 @@ module Doorkeeper
49
49
  end
50
50
 
51
51
  def create_access_token
52
- attributes = {}
52
+ attributes = {}.merge(custom_token_attributes_with_data)
53
53
 
54
54
  resource_owner =
55
55
  if Doorkeeper.config.polymorphic_resource_owner?
@@ -75,7 +75,7 @@ module Doorkeeper
75
75
  # Here we assume that TTL of the token received after refreshing should be
76
76
  # the same as that of the original token.
77
77
  #
78
- @access_token = server_config.access_token_model.create_for(
78
+ @access_token = Doorkeeper.config.access_token_model.create_for(
79
79
  application: refresh_token.application,
80
80
  resource_owner: resource_owner,
81
81
  scopes: scopes,
@@ -119,6 +119,14 @@ module Doorkeeper
119
119
  true
120
120
  end
121
121
  end
122
+
123
+ def custom_token_attributes_with_data
124
+ refresh_token
125
+ .attributes
126
+ .with_indifferent_access
127
+ .slice(*Doorkeeper.config.custom_access_token_attributes)
128
+ .symbolize_keys
129
+ end
122
130
  end
123
131
  end
124
132
  end
@@ -134,7 +134,7 @@ module Doorkeeper
134
134
  # Since resource servers using token introspection rely on the
135
135
  # authorization server to determine the state of a token, the
136
136
  # authorization server MUST perform all applicable checks against a
137
- # token's state. For instance, these tests include the following:
137
+ # token's state. For instance, these tests include the following:
138
138
  #
139
139
  # o If the token can expire, the authorization server MUST determine
140
140
  # whether or not the token has expired.
@@ -26,8 +26,7 @@ module Doorkeeper
26
26
 
27
27
  def headers
28
28
  {
29
- "Cache-Control" => "no-store",
30
- "Pragma" => "no-cache",
29
+ "Cache-Control" => "no-store, no-cache",
31
30
  "Content-Type" => "application/json; charset=utf-8",
32
31
  }
33
32
  end
@@ -14,12 +14,6 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
14
14
  optional: true,
15
15
  inverse_of: :access_grants
16
16
 
17
- if Doorkeeper.config.polymorphic_resource_owner?
18
- belongs_to :resource_owner, polymorphic: true, optional: false
19
- else
20
- validates :resource_owner_id, presence: true
21
- end
22
-
23
17
  validates :application_id,
24
18
  :token,
25
19
  :expires_in,
@@ -14,10 +14,6 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
14
14
  inverse_of: :access_tokens,
15
15
  optional: true
16
16
 
17
- if Doorkeeper.config.polymorphic_resource_owner?
18
- belongs_to :resource_owner, polymorphic: true, optional: true
19
- end
20
-
21
17
  validates :token, presence: true, uniqueness: { case_sensitive: true }
22
18
  validates :refresh_token, uniqueness: { case_sensitive: true }, if: :use_refresh_token?
23
19
 
@@ -10,10 +10,6 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
10
10
 
11
11
  include ::Doorkeeper::ApplicationMixin
12
12
 
13
- if Doorkeeper.config.enable_application_owner?
14
- include ::Doorkeeper::Models::Ownership
15
- end
16
-
17
13
  has_many :access_grants,
18
14
  foreign_key: :application_id,
19
15
  dependent: :delete_all,
@@ -45,11 +45,11 @@ module Doorkeeper
45
45
  end
46
46
 
47
47
  def unspecified_host?(uri)
48
- uri.is_a?(URI::HTTP) && uri.host.nil?
48
+ uri.is_a?(URI::HTTP) && uri.host.blank?
49
49
  end
50
50
 
51
51
  def relative_uri?(uri)
52
- uri.scheme.nil? && uri.host.nil?
52
+ uri.scheme.nil? && uri.host.blank?
53
53
  end
54
54
 
55
55
  def invalid_ssl_uri?(uri)
@@ -15,7 +15,8 @@ module Doorkeeper
15
15
  def clean_revoked
16
16
  table = @base_scope.arel_table
17
17
 
18
- @base_scope.where.not(revoked_at: nil)
18
+ @base_scope
19
+ .where.not(revoked_at: nil)
19
20
  .where(table[:revoked_at].lt(Time.current))
20
21
  .in_batches(&:delete_all)
21
22
  end
@@ -24,7 +25,9 @@ module Doorkeeper
24
25
  def clean_expired(ttl)
25
26
  table = @base_scope.arel_table
26
27
 
27
- @base_scope.where(table[:created_at].lt(Time.current - ttl))
28
+ @base_scope
29
+ .where.not(expires_in: nil)
30
+ .where(table[:created_at].lt(Time.current - ttl))
28
31
  .in_batches(&:delete_all)
29
32
  end
30
33
  end
@@ -29,20 +29,16 @@ module Doorkeeper
29
29
  end
30
30
 
31
31
  def self.run_hooks
32
- # Deprecated, will be removed soon
33
- return unless (options = Doorkeeper.config.active_record_options[:establish_connection])
32
+ initialize_configured_associations
33
+ end
34
34
 
35
- Doorkeeper::Orm::ActiveRecord.models.each do |model|
36
- model.establish_connection(options)
35
+ def self.initialize_configured_associations
36
+ if Doorkeeper.config.enable_application_owner?
37
+ Doorkeeper.config.application_model.include ::Doorkeeper::Models::Ownership
37
38
  end
38
- end
39
39
 
40
- def self.models
41
- [
42
- Doorkeeper.config.access_grant_model,
43
- Doorkeeper.config.access_token_model,
44
- Doorkeeper.config.application_model,
45
- ]
40
+ Doorkeeper.config.access_grant_model.include ::Doorkeeper::Models::PolymorphicResourceOwner::ForAccessGrant
41
+ Doorkeeper.config.access_token_model.include ::Doorkeeper::Models::PolymorphicResourceOwner::ForAccessToken
46
42
  end
47
43
  end
48
44
  end
@@ -36,7 +36,7 @@ module Doorkeeper
36
36
  map_route(:authorizations, :authorization_routes)
37
37
  map_route(:tokens, :token_routes)
38
38
  map_route(:tokens, :revoke_routes)
39
- map_route(:tokens, :introspect_routes) unless Doorkeeper.config.allow_token_introspection.is_a?(FalseClass)
39
+ map_route(:tokens, :introspect_routes) if introspection_routes?
40
40
  map_route(:applications, :application_routes)
41
41
  map_route(:authorized_applications, :authorized_applications_routes)
42
42
  map_route(:token_info, :token_info_routes)
@@ -100,6 +100,11 @@ module Doorkeeper
100
100
  def native_authorization_code_route
101
101
  Doorkeeper.configuration.native_authorization_code_route
102
102
  end
103
+
104
+ def introspection_routes?
105
+ Doorkeeper.configured? &&
106
+ !Doorkeeper.config.allow_token_introspection.is_a?(FalseClass)
107
+ end
103
108
  end
104
109
  end
105
110
  end
@@ -5,7 +5,7 @@ module Doorkeeper
5
5
  # Semantic versioning
6
6
  MAJOR = 5
7
7
  MINOR = 6
8
- TINY = 2
8
+ TINY = 6
9
9
  PRE = nil
10
10
 
11
11
  # Full version number
data/lib/doorkeeper.rb CHANGED
@@ -90,6 +90,7 @@ module Doorkeeper
90
90
  autoload :Expirable, "doorkeeper/models/concerns/expirable"
91
91
  autoload :ExpirationTimeSqlMath, "doorkeeper/models/concerns/expiration_time_sql_math"
92
92
  autoload :Orderable, "doorkeeper/models/concerns/orderable"
93
+ autoload :PolymorphicResourceOwner, "doorkeeper/models/concerns/polymorphic_resource_owner"
93
94
  autoload :Scopes, "doorkeeper/models/concerns/scopes"
94
95
  autoload :Reusable, "doorkeeper/models/concerns/reusable"
95
96
  autoload :ResourceOwnerable, "doorkeeper/models/concerns/resource_ownerable"
@@ -113,11 +114,77 @@ module Doorkeeper
113
114
  autoload :BCrypt, "doorkeeper/secret_storing/bcrypt"
114
115
  end
115
116
 
116
- def self.authenticate(request, methods = Doorkeeper.config.access_token_methods)
117
- OAuth::Token.authenticate(request, *methods)
118
- end
117
+ class << self
118
+ attr_reader :orm_adapter
119
+
120
+ def configure(&block)
121
+ @config = Config::Builder.new(&block).build
122
+ setup
123
+ @config
124
+ end
125
+
126
+ # @return [Doorkeeper::Config] configuration instance
127
+ #
128
+ def configuration
129
+ @config || configure
130
+ end
131
+
132
+ def configured?
133
+ !@config.nil?
134
+ end
135
+
136
+ alias config configuration
137
+
138
+ def setup
139
+ setup_orm_adapter
140
+
141
+ # Deprecated, will be removed soon
142
+ unless configuration.orm == :active_record
143
+ setup_orm_models
144
+ setup_application_owner
145
+ end
146
+ end
147
+
148
+ def setup_orm_adapter
149
+ @orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
150
+ rescue NameError => e
151
+ raise e, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.strip_heredoc
152
+ [DOORKEEPER] ORM adapter not found (#{configuration.orm}), or there was an error
153
+ trying to load it.
119
154
 
120
- def self.gem_version
121
- ::Gem::Version.new(::Doorkeeper::VERSION::STRING)
155
+ You probably need to add the related gem for this adapter to work with
156
+ doorkeeper.
157
+ ERROR_MSG
158
+ end
159
+
160
+ def run_orm_hooks
161
+ config.clear_cache!
162
+
163
+ if @orm_adapter.respond_to?(:run_hooks)
164
+ @orm_adapter.run_hooks
165
+ else
166
+ ::Kernel.warn <<~MSG.strip_heredoc
167
+ [DOORKEEPER] ORM "#{configuration.orm}" should move all it's setup logic under `#run_hooks` method for
168
+ the #{@orm_adapter.name}. Later versions of Doorkeeper will no longer support `setup_orm_models` and
169
+ `setup_application_owner` API.
170
+ MSG
171
+ end
172
+ end
173
+
174
+ def setup_orm_models
175
+ @orm_adapter.initialize_models!
176
+ end
177
+
178
+ def setup_application_owner
179
+ @orm_adapter.initialize_application_owner!
180
+ end
181
+
182
+ def authenticate(request, methods = Doorkeeper.config.access_token_methods)
183
+ OAuth::Token.authenticate(request, *methods)
184
+ end
185
+
186
+ def gem_version
187
+ ::Gem::Version.new(::Doorkeeper::VERSION::STRING)
188
+ end
122
189
  end
123
190
  end
@@ -391,6 +391,23 @@ Doorkeeper.configure do
391
391
  # resource_owner.admin? || client.owners_allowlist.include?(resource_owner)
392
392
  # end
393
393
 
394
+ # Allows additional data fields to be sent while granting access to an application,
395
+ # and for this additional data to be included in subsequently generated access tokens.
396
+ # The 'authorizations/new' page will need to be overridden to include this additional data
397
+ # in the request params when granting access. The access grant and access token models
398
+ # will both need to respond to these additional data fields, and have a database column
399
+ # to store them in.
400
+ #
401
+ # Example:
402
+ # You have a multi-tenanted platform and want to be able to grant access to a specific
403
+ # tenant, rather than all the tenants a user has access to. You can use this config
404
+ # option to specify that a ':tenant_id' will be passed when authorizing. This tenant_id
405
+ # will be included in the access tokens. When a request is made with one of these access
406
+ # tokens, you can check that the requested data belongs to the specified tenant.
407
+ #
408
+ # Default value is an empty Array: []
409
+ # custom_access_token_attributes [:tenant_id]
410
+
394
411
  # Hook into the strategies' request & response life-cycle in case your
395
412
  # application needs advanced customization or logging:
396
413
  #
@@ -24,9 +24,9 @@ class CreateDoorkeeperTables < ActiveRecord::Migration<%= migration_version %>
24
24
  t.string :token, null: false
25
25
  t.integer :expires_in, null: false
26
26
  t.text :redirect_uri, null: false
27
+ t.string :scopes, null: false, default: ''
27
28
  t.datetime :created_at, null: false
28
29
  t.datetime :revoked_at
29
- t.string :scopes, null: false, default: ''
30
30
  end
31
31
 
32
32
  add_index :oauth_access_grants, :token, unique: true
@@ -53,9 +53,9 @@ class CreateDoorkeeperTables < ActiveRecord::Migration<%= migration_version %>
53
53
 
54
54
  t.string :refresh_token
55
55
  t.integer :expires_in
56
- t.datetime :revoked_at
57
- t.datetime :created_at, null: false
58
56
  t.string :scopes
57
+ t.datetime :created_at, null: false
58
+ t.datetime :revoked_at
59
59
 
60
60
  # The authorization server MAY issue a new refresh token, in which case
61
61
  # *the client MUST discard the old refresh token* and replace it with the
@@ -74,7 +74,17 @@ class CreateDoorkeeperTables < ActiveRecord::Migration<%= migration_version %>
74
74
  end
75
75
 
76
76
  add_index :oauth_access_tokens, :token, unique: true
77
- add_index :oauth_access_tokens, :refresh_token, unique: true
77
+
78
+ # See https://github.com/doorkeeper-gem/doorkeeper/issues/1592
79
+ if ActiveRecord::Base.connection.adapter_name == "SQLServer"
80
+ execute <<~SQL.squish
81
+ CREATE UNIQUE NONCLUSTERED INDEX index_oauth_access_tokens_on_refresh_token ON oauth_access_tokens(refresh_token)
82
+ WHERE refresh_token IS NOT NULL
83
+ SQL
84
+ else
85
+ add_index :oauth_access_tokens, :refresh_token, unique: true
86
+ end
87
+
78
88
  add_foreign_key(
79
89
  :oauth_access_tokens,
80
90
  :oauth_applications,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doorkeeper
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.6.2
4
+ version: 5.6.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felipe Elias Philipp
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2022-11-29 00:00:00.000000000 Z
14
+ date: 2023-03-29 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: railties
@@ -69,20 +69,6 @@ dependencies:
69
69
  - - ">="
70
70
  - !ruby/object:Gem::Version
71
71
  version: '0'
72
- - !ruby/object:Gem::Dependency
73
- name: danger
74
- requirement: !ruby/object:Gem::Requirement
75
- requirements:
76
- - - "~>"
77
- - !ruby/object:Gem::Version
78
- version: '8.0'
79
- type: :development
80
- prerelease: false
81
- version_requirements: !ruby/object:Gem::Requirement
82
- requirements:
83
- - - "~>"
84
- - !ruby/object:Gem::Version
85
- version: '8.0'
86
72
  - !ruby/object:Gem::Dependency
87
73
  name: database_cleaner
88
74
  requirement: !ruby/object:Gem::Requirement
@@ -238,6 +224,7 @@ files:
238
224
  - lib/doorkeeper/models/concerns/expiration_time_sql_math.rb
239
225
  - lib/doorkeeper/models/concerns/orderable.rb
240
226
  - lib/doorkeeper/models/concerns/ownership.rb
227
+ - lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb
241
228
  - lib/doorkeeper/models/concerns/resource_ownerable.rb
242
229
  - lib/doorkeeper/models/concerns/reusable.rb
243
230
  - lib/doorkeeper/models/concerns/revocable.rb
@@ -352,14 +339,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
352
339
  requirements:
353
340
  - - ">="
354
341
  - !ruby/object:Gem::Version
355
- version: '2.5'
342
+ version: '2.7'
356
343
  required_rubygems_version: !ruby/object:Gem::Requirement
357
344
  requirements:
358
345
  - - ">="
359
346
  - !ruby/object:Gem::Version
360
347
  version: '0'
361
348
  requirements: []
362
- rubygems_version: 3.1.4
349
+ rubygems_version: 3.1.6
363
350
  signing_key:
364
351
  specification_version: 4
365
352
  summary: OAuth 2 provider for Rails and Grape