doorkeeper 5.6.2 → 5.6.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -3
  3. data/README.md +1 -1
  4. data/app/controllers/doorkeeper/authorizations_controller.rb +16 -4
  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/validations.rb +15 -0
  8. data/lib/doorkeeper/config.rb +9 -75
  9. data/lib/doorkeeper/engine.rb +7 -5
  10. data/lib/doorkeeper/errors.rb +1 -0
  11. data/lib/doorkeeper/models/access_token_mixin.rb +4 -3
  12. data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +30 -0
  13. data/lib/doorkeeper/oauth/authorization/code.rb +7 -1
  14. data/lib/doorkeeper/oauth/authorization_code_request.rb +16 -6
  15. data/lib/doorkeeper/oauth/base_request.rb +11 -10
  16. data/lib/doorkeeper/oauth/client_credentials/creator.rb +7 -11
  17. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +3 -3
  18. data/lib/doorkeeper/oauth/password_access_token_request.rb +2 -2
  19. data/lib/doorkeeper/oauth/pre_authorization.rb +11 -10
  20. data/lib/doorkeeper/oauth/refresh_token_request.rb +3 -3
  21. data/lib/doorkeeper/oauth/token_introspection.rb +1 -1
  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: 8430b36ebe602cb716e1d404c53e17cbe41a6e122fb3004e77dc5b16ea70a7bd
4
+ data.tar.gz: 7d8033e2051e21776c0d57e3bbe23d6d2cea04e615c48b9d82a7a704373ff7cb
5
5
  SHA512:
6
- metadata.gz: 127dd3e716bfde2c825ba1d6c4fee662a80a809063a8bd0d5480767fc472c41a6208742407f47656dae95cb7d41b1cb30a920b0270fd2c194a3267fc2c843626
7
- data.tar.gz: e17e0349cefce41f7767f944fded43b71221b0df82042a9fb9c0dddb464308f3642fe2af7fc61bc1ec4ebb09cb3d2ea1d7a3040adc41130259e495cf3e129386
6
+ metadata.gz: a89cf897778ebd53736ff57f9e7f5eb587ffa6da110e04a62a99816b3719ab9d109700a6cace1d36208bfb34eeb4fd7153aeaef7792275b57cde34e189904510
7
+ data.tar.gz: bc943f37ca582f1badaa25d98715f1e5ec2a86f8da3f99ef7367cbcc63a99a20a0cc3458d1c2919bb1088e6a09ffd47e33a6634b78b8fcc0e49993681c56a683
data/CHANGELOG.md CHANGED
@@ -9,6 +9,26 @@ User-visible changes worth mentioning.
9
9
 
10
10
  - [#ID] Add your PR description here.
11
11
 
12
+ # 5.6.5
13
+
14
+ - [#1602] Allow custom data to be stored inside access grants/tokens.
15
+ - [#1634] Code refactoring for custom token attributes.
16
+ - [#1639] Add grant type validation to avoid Internal Server Error for DELETE /oauth/authorize endpoint.
17
+
18
+ # 5.6.4
19
+
20
+ - [#1633] Apply ORM configuration in #to_prepare block to avoid autoloading errors.
21
+
22
+ # 5.6.3
23
+
24
+ - [#1622] Drop support for Rubies 2.5 and 2.6
25
+ - [#1605] Fix URI validation for Ruby 3.2+.
26
+ - [#1625] Exclude endless access tokens from `StaleRecordsCleaner`.
27
+ - [#1626] Remove deprecated `active_record_options` config option.
28
+ - [#1631] Fix regression with redirect behavior after token lookup optimizations (redirect to app URI when found).
29
+ - [#1630] Special case unique index creation for refresh_token on SQL Server.
30
+ - [#1627] Lazy evaluate Doorkeeper config when loading files and executing initializers.
31
+
12
32
  ## 5.6.2
13
33
 
14
34
  - [#1604] Fix fetching of the application when custom application_class defined.
@@ -23,7 +43,7 @@ User-visible changes worth mentioning.
23
43
 
24
44
  - [#1581] Consider `token_type_hint` when searching for access token in TokensController to avoid extra database calls.
25
45
 
26
- ## 5.6.0.rc1
46
+ ## 5.6.0.rc2
27
47
 
28
48
  - [#1558] Fixed bug: able to obtain a token with default scopes even if they are not present in the
29
49
  application scopes when using client credentials.
@@ -284,7 +304,7 @@ User-visible changes worth mentioning.
284
304
  - [#1237] Allow to set blank redirect URI if Doorkeeper configured to use redirect URI-less grant flows.
285
305
  - [#1234] Fix `StaleRecordsCleaner` to properly work with big amount of records.
286
306
  - [#1228] Allow to explicitly set non-expiring tokens in `custom_access_token_expires_in` configuration
287
- option using `Float::INIFINITY` return value.
307
+ option using `Float::INFINITY` return value.
288
308
  - [#1224] Do not try to store token if not found by fallback hashing strategy.
289
309
  - [#1223] Update Hound/Rubocop rules, correct Doorkeeper codebase to follow style-guides.
290
310
  - [#1220] Drop Rails 4.2 & Ruby < 2.4 support.
@@ -369,7 +389,7 @@ User-visible changes worth mentioning.
369
389
  - [#1116] `AccessGrant`s will now be revoked along with `AccessToken`s when
370
390
  hitting the `AuthorizedApplicationController#destroy` route.
371
391
  - [#1114] Make token info endpoint's attributes consistent with token creation
372
- - [#1108] Simple formating of callback URLs when listing oauth applications
392
+ - [#1108] Simple formatting of callback URLs when listing oauth applications
373
393
  - [#1106] Restrict access to AdminController with 'Forbidden 403' if admin_authenticator is not
374
394
  configured by developers.
375
395
 
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,11 +13,19 @@ 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
@@ -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.
@@ -11,6 +11,7 @@ module Doorkeeper
11
11
  validate_reuse_access_token_value
12
12
  validate_token_reuse_limit
13
13
  validate_secret_strategies
14
+ validate_custom_access_token_attributes
14
15
  end
15
16
 
16
17
  private
@@ -48,6 +49,20 @@ module Doorkeeper
48
49
  )
49
50
  @token_reuse_limit = 100
50
51
  end
52
+
53
+ # Validate that the access_token and access_grant models
54
+ # both respond to all of the custom attributes
55
+ def validate_custom_access_token_attributes
56
+ return if custom_access_token_attributes.blank?
57
+
58
+ custom_access_token_attributes.each do |attribute_name|
59
+ [access_token_model, access_grant_model].each do |model|
60
+ next if model.has_attribute?(attribute_name)
61
+
62
+ raise Doorkeeper::Errors::ConfigError, "#{model} does not recognize custom attribute: #{attribute_name}."
63
+ end
64
+ end
65
+ end
51
66
  end
52
67
  end
53
68
  end
@@ -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
@@ -44,6 +44,7 @@ module Doorkeeper
44
44
  UnableToGenerateToken = Class.new(DoorkeeperError)
45
45
  TokenGeneratorNotFound = Class.new(DoorkeeperError)
46
46
  NoOrmCleaner = Class.new(DoorkeeperError)
47
+ ConfigError = Class.new(DoorkeeperError)
47
48
 
48
49
  InvalidToken = Class.new(BaseResponseError)
49
50
  TokenExpired = Class.new(InvalidToken)
@@ -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
@@ -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
@@ -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,
@@ -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.
@@ -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 = 5
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.5
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-02-22 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