doorkeeper 5.4.0 → 5.5.0.rc1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -1
- data/app/controllers/doorkeeper/authorizations_controller.rb +2 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +3 -0
- data/config/locales/en.yml +0 -1
- data/lib/doorkeeper.rb +1 -0
- data/lib/doorkeeper/config.rb +79 -62
- data/lib/doorkeeper/config/option.rb +1 -3
- data/lib/doorkeeper/config/validations.rb +53 -0
- data/lib/doorkeeper/grant_flow.rb +43 -0
- data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
- data/lib/doorkeeper/grant_flow/flow.rb +34 -0
- data/lib/doorkeeper/grant_flow/registry.rb +50 -0
- data/lib/doorkeeper/helpers/controller.rb +2 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +3 -3
- data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
- data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
- data/lib/doorkeeper/oauth/authorization/token.rb +6 -4
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +1 -1
- data/lib/doorkeeper/oauth/authorization_code_request.rb +10 -17
- data/lib/doorkeeper/oauth/base_request.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -1
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +1 -0
- data/lib/doorkeeper/oauth/code_response.rb +22 -12
- data/lib/doorkeeper/oauth/error_response.rb +4 -3
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -3
- data/lib/doorkeeper/oauth/password_access_token_request.rb +20 -1
- data/lib/doorkeeper/oauth/pre_authorization.rb +10 -6
- data/lib/doorkeeper/oauth/refresh_token_request.rb +13 -0
- data/lib/doorkeeper/rails/routes.rb +1 -1
- data/lib/doorkeeper/request.rb +49 -12
- data/lib/doorkeeper/version.rb +2 -2
- data/lib/generators/doorkeeper/templates/initializer.rb +9 -7
- metadata +11 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1099136de2b2fe0f0443f88bdbe2260ebed52efb2aab31d1d35bb7aa9f801acd
|
4
|
+
data.tar.gz: '09837820494b55d6bd26e2d997c203b221bc7951e74a6d1e2197122a86f0f1b2'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9197207fe8db140d8658aa12cd7422bfd84a001227a9f0841ebf5d92da4be531cfd7dea26aad584fff3573bc066b8fadc4e9d4e70bcc6dd5978253d94a9d66a4
|
7
|
+
data.tar.gz: 3b37c794027fcdbec12ef314bd6a927e111c2aed2044f3ead9f05893400e7221bf9adf98203efe7a225b395d5644326b943c144c13fb0caeccff5dff20a56ca5
|
data/CHANGELOG.md
CHANGED
@@ -7,7 +7,29 @@ User-visible changes worth mentioning.
|
|
7
7
|
|
8
8
|
## master
|
9
9
|
|
10
|
-
- [#PR ID]
|
10
|
+
- [#PR ID] Add your PR description here.
|
11
|
+
|
12
|
+
## 5.5.0.rc1
|
13
|
+
|
14
|
+
- [#1435] Make error response not redirectable when client is unauthorized
|
15
|
+
- [#1426] Ensure ActiveRecord callbacks are executed on token revocation.
|
16
|
+
- [#1407] Remove redundant and complex to support helpers froms tests (`should_have_json`, etc).
|
17
|
+
- [#1416] Don't add introspection route if token introspection completely disabled.
|
18
|
+
- [#1410] Properly memoize `current_resource_owner` value (consider `nil` and `false` values).
|
19
|
+
- [#1415] Ignore PKCE params for non-PKCE grants.
|
20
|
+
- [#1418] Add ability to register custom OAuth Grant Flows.
|
21
|
+
- [#1420] Require client authentication for Resource Owner Password Grant as stated in OAuth RFC.
|
22
|
+
|
23
|
+
**[IMPORTANT]** you need to create a new OAuth client (`Doorkeeper::Application`) if yoo didn't
|
24
|
+
have it before and use client credentials in HTTP Basic auth if you previously used this grant
|
25
|
+
flow without client authentication. For migration purposes you could enable
|
26
|
+
`skip_client_authentication_for_password_grant` configuration option to `true`, but such behavior
|
27
|
+
(as well as configuration option) would be completely removed in a future version of Doorkeeper.
|
28
|
+
All the users of your provider application now need to include client credentials when they use
|
29
|
+
this grant flow.
|
30
|
+
|
31
|
+
- [#1421] Add Resource Owner instance to authorization hook context for `custom_access_token_expires_in`
|
32
|
+
configuration option to allow resource owner based Access Tokens TTL.
|
11
33
|
|
12
34
|
## 5.4.0
|
13
35
|
|
@@ -69,6 +69,9 @@ module Doorkeeper
|
|
69
69
|
private
|
70
70
|
|
71
71
|
# OAuth 2.0 Section 2.1 defines two client types, "public" & "confidential".
|
72
|
+
#
|
73
|
+
# RFC7009
|
74
|
+
# Section 5. Security Considerations
|
72
75
|
# A malicious client may attempt to guess valid tokens on this endpoint
|
73
76
|
# by making revocation requests against potential token strings.
|
74
77
|
# According to this specification, a client's request must contain a
|
data/config/locales/en.yml
CHANGED
@@ -93,7 +93,6 @@ en:
|
|
93
93
|
invalid_request:
|
94
94
|
unknown: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
|
95
95
|
missing_param: 'Missing required parameter: %{value}.'
|
96
|
-
not_support_pkce: 'Invalid code_verifier parameter. Server does not support pkce.'
|
97
96
|
request_not_authorized: 'Request need to be authorized. Required parameter for authorizing request is missing or invalid.'
|
98
97
|
invalid_redirect_uri: "The requested redirect uri is malformed or doesn't match client redirect URI."
|
99
98
|
unauthorized_client: 'The client is not authorized to perform this request using this method.'
|
data/lib/doorkeeper.rb
CHANGED
data/lib/doorkeeper/config.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "doorkeeper/config/option"
|
4
3
|
require "doorkeeper/config/abstract_builder"
|
4
|
+
require "doorkeeper/config/option"
|
5
|
+
require "doorkeeper/config/validations"
|
5
6
|
|
6
7
|
module Doorkeeper
|
7
8
|
# Defines a MissingConfiguration error for a missing Doorkeeper configuration
|
@@ -219,6 +220,7 @@ module Doorkeeper
|
|
219
220
|
mattr_reader(:builder_class) { Builder }
|
220
221
|
|
221
222
|
extend Option
|
223
|
+
include Validations
|
222
224
|
|
223
225
|
option :resource_owner_authenticator,
|
224
226
|
as: :authenticate_resource_owner,
|
@@ -267,7 +269,6 @@ module Doorkeeper
|
|
267
269
|
option :grant_flows, default: %w[authorization_code client_credentials]
|
268
270
|
option :handle_auth_errors, default: :render
|
269
271
|
option :token_lookup_batch_size, default: 10_000
|
270
|
-
|
271
272
|
# Sets the token_reuse_limit
|
272
273
|
# It will be used only when reuse_access_token option in enabled
|
273
274
|
# By default it will be 100
|
@@ -275,6 +276,11 @@ module Doorkeeper
|
|
275
276
|
# Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1189
|
276
277
|
option :token_reuse_limit, default: 100
|
277
278
|
|
279
|
+
# [NOTE]: will be removed in a future version of Doorkeeper
|
280
|
+
option :skip_client_authentication_for_password_grant,
|
281
|
+
default: false,
|
282
|
+
deprecated: { message: "OAuth RFC requires client authentication so you need at least to create one" }
|
283
|
+
|
278
284
|
option :active_record_options,
|
279
285
|
default: {},
|
280
286
|
deprecated: { message: "Customize Doorkeeper models instead" }
|
@@ -423,13 +429,6 @@ module Doorkeeper
|
|
423
429
|
:token_secret_fallback_strategy,
|
424
430
|
:application_secret_fallback_strategy
|
425
431
|
|
426
|
-
# Return the valid subset of this configuration
|
427
|
-
def validate!
|
428
|
-
validate_reuse_access_token_value
|
429
|
-
validate_token_reuse_limit
|
430
|
-
validate_secret_strategies
|
431
|
-
end
|
432
|
-
|
433
432
|
# Doorkeeper Access Token model class.
|
434
433
|
#
|
435
434
|
# @return [ActiveRecord::Base, Mongoid::Document, Sequel::Model]
|
@@ -545,12 +544,77 @@ module Doorkeeper
|
|
545
544
|
]
|
546
545
|
end
|
547
546
|
|
547
|
+
def enabled_grant_flows
|
548
|
+
@enabled_grant_flows ||= calculate_grant_flows.map { |name| Doorkeeper::GrantFlow.get(name) }.compact
|
549
|
+
end
|
550
|
+
|
551
|
+
def authorization_response_flows
|
552
|
+
@authorization_response_flows ||= enabled_grant_flows.select(&:handles_response_type?) +
|
553
|
+
deprecated_authorization_flows
|
554
|
+
end
|
555
|
+
|
556
|
+
def token_grant_flows
|
557
|
+
@token_grant_flows ||= calculate_token_grant_flows
|
558
|
+
end
|
559
|
+
|
548
560
|
def authorization_response_types
|
549
|
-
|
561
|
+
authorization_response_flows.map(&:response_type_matches)
|
550
562
|
end
|
551
563
|
|
552
564
|
def token_grant_types
|
553
|
-
|
565
|
+
token_grant_flows.map(&:grant_type_matches)
|
566
|
+
end
|
567
|
+
|
568
|
+
# [NOTE]: deprecated and will be removed soon
|
569
|
+
def deprecated_token_grant_types_resolver
|
570
|
+
@deprecated_token_grant_types ||= calculate_token_grant_types
|
571
|
+
end
|
572
|
+
|
573
|
+
# [NOTE]: deprecated and will be removed soon
|
574
|
+
def deprecated_authorization_flows
|
575
|
+
response_types = calculate_authorization_response_types
|
576
|
+
|
577
|
+
if response_types.any?
|
578
|
+
::Kernel.warn <<~WARNING
|
579
|
+
Please, don't patch Doorkeeper::Config#calculate_authorization_response_types method.
|
580
|
+
Register your custom grant flows using the public API:
|
581
|
+
`Doorkeeper::GrantFlow.register(grant_flow_name, **options)`.
|
582
|
+
WARNING
|
583
|
+
end
|
584
|
+
|
585
|
+
response_types.map do |response_type|
|
586
|
+
Doorkeeper::GrantFlow::FallbackFlow.new(response_type, response_type_matches: response_type)
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
# [NOTE]: deprecated and will be removed soon
|
591
|
+
def calculate_authorization_response_types
|
592
|
+
[]
|
593
|
+
end
|
594
|
+
|
595
|
+
# [NOTE]: deprecated and will be removed soon
|
596
|
+
def calculate_token_grant_types
|
597
|
+
types = grant_flows - ["implicit"]
|
598
|
+
types << "refresh_token" if refresh_token_enabled?
|
599
|
+
types
|
600
|
+
end
|
601
|
+
|
602
|
+
# Calculates grant flows configured by the user in Doorkeeper
|
603
|
+
# configuration considering registered aliases that is exposed
|
604
|
+
# to single or multiple other flows.
|
605
|
+
#
|
606
|
+
def calculate_grant_flows
|
607
|
+
configured_flows = grant_flows.map(&:to_s)
|
608
|
+
aliases = Doorkeeper::GrantFlow.aliases.keys.map(&:to_s)
|
609
|
+
|
610
|
+
flows = configured_flows - aliases
|
611
|
+
aliases.each do |flow_alias|
|
612
|
+
next unless configured_flows.include?(flow_alias)
|
613
|
+
|
614
|
+
flows.concat(Doorkeeper::GrantFlow.expand_alias(flow_alias))
|
615
|
+
end
|
616
|
+
|
617
|
+
flows.flatten.uniq
|
554
618
|
end
|
555
619
|
|
556
620
|
def allow_blank_redirect_uri?(application = nil)
|
@@ -579,57 +643,10 @@ module Doorkeeper
|
|
579
643
|
!!(defined?(var) && var)
|
580
644
|
end
|
581
645
|
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
types = []
|
587
|
-
types << "code" if grant_flows.include? "authorization_code"
|
588
|
-
types << "token" if grant_flows.include? "implicit"
|
589
|
-
types
|
590
|
-
end
|
591
|
-
|
592
|
-
# Determines what values are acceptable for 'grant_type' param token
|
593
|
-
# request endpoint, and return them in array.
|
594
|
-
#
|
595
|
-
def calculate_token_grant_types
|
596
|
-
types = grant_flows - ["implicit"]
|
597
|
-
types << "refresh_token" if refresh_token_enabled?
|
598
|
-
types
|
599
|
-
end
|
600
|
-
|
601
|
-
# Determine whether +reuse_access_token+ and a non-restorable
|
602
|
-
# +token_secret_strategy+ have both been activated.
|
603
|
-
#
|
604
|
-
# In that case, disable reuse_access_token value and warn the user.
|
605
|
-
def validate_reuse_access_token_value
|
606
|
-
strategy = token_secret_strategy
|
607
|
-
return if !reuse_access_token || strategy.allows_restoring_secrets?
|
608
|
-
|
609
|
-
::Rails.logger.warn(
|
610
|
-
"You have configured both reuse_access_token " \
|
611
|
-
"AND strategy strategy '#{strategy}' that cannot restore tokens. " \
|
612
|
-
"This combination is unsupported. reuse_access_token will be disabled",
|
613
|
-
)
|
614
|
-
@reuse_access_token = false
|
615
|
-
end
|
616
|
-
|
617
|
-
# Validate that the provided strategies are valid for
|
618
|
-
# tokens and applications
|
619
|
-
def validate_secret_strategies
|
620
|
-
token_secret_strategy.validate_for :token
|
621
|
-
application_secret_strategy.validate_for :application
|
622
|
-
end
|
623
|
-
|
624
|
-
def validate_token_reuse_limit
|
625
|
-
return if !reuse_access_token ||
|
626
|
-
(token_reuse_limit > 0 && token_reuse_limit <= 100)
|
627
|
-
|
628
|
-
::Rails.logger.warn(
|
629
|
-
"You have configured an invalid value for token_reuse_limit option. " \
|
630
|
-
"It will be set to default 100",
|
631
|
-
)
|
632
|
-
@token_reuse_limit = 100
|
646
|
+
def calculate_token_grant_flows
|
647
|
+
flows = enabled_grant_flows.select(&:handles_grant_type?)
|
648
|
+
flows << Doorkeeper::GrantFlow.get("refresh_token") if refresh_token_enabled?
|
649
|
+
flows
|
633
650
|
end
|
634
651
|
end
|
635
652
|
end
|
@@ -45,9 +45,7 @@ module Doorkeeper
|
|
45
45
|
define_method name do |*args, &block|
|
46
46
|
if (deprecation_opts = options[:deprecated])
|
47
47
|
warning = "[DOORKEEPER] #{name} has been deprecated and will soon be removed"
|
48
|
-
if deprecation_opts.is_a?(Hash)
|
49
|
-
warning = "#{warning}\n#{deprecation_opts.fetch(:message)}"
|
50
|
-
end
|
48
|
+
warning = "#{warning}\n#{deprecation_opts.fetch(:message)}" if deprecation_opts.is_a?(Hash)
|
51
49
|
|
52
50
|
Kernel.warn(warning)
|
53
51
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
class Config
|
5
|
+
# Doorkeeper configuration validator.
|
6
|
+
#
|
7
|
+
module Validations
|
8
|
+
# Validates configuration options to be set properly.
|
9
|
+
#
|
10
|
+
def validate!
|
11
|
+
validate_reuse_access_token_value
|
12
|
+
validate_token_reuse_limit
|
13
|
+
validate_secret_strategies
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Determine whether +reuse_access_token+ and a non-restorable
|
19
|
+
# +token_secret_strategy+ have both been activated.
|
20
|
+
#
|
21
|
+
# In that case, disable reuse_access_token value and warn the user.
|
22
|
+
def validate_reuse_access_token_value
|
23
|
+
strategy = token_secret_strategy
|
24
|
+
return if !reuse_access_token || strategy.allows_restoring_secrets?
|
25
|
+
|
26
|
+
::Rails.logger.warn(
|
27
|
+
"You have configured both reuse_access_token " \
|
28
|
+
"AND strategy strategy '#{strategy}' that cannot restore tokens. " \
|
29
|
+
"This combination is unsupported. reuse_access_token will be disabled",
|
30
|
+
)
|
31
|
+
@reuse_access_token = false
|
32
|
+
end
|
33
|
+
|
34
|
+
# Validate that the provided strategies are valid for
|
35
|
+
# tokens and applications
|
36
|
+
def validate_secret_strategies
|
37
|
+
token_secret_strategy.validate_for(:token)
|
38
|
+
application_secret_strategy.validate_for(:application)
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate_token_reuse_limit
|
42
|
+
return if !reuse_access_token ||
|
43
|
+
(token_reuse_limit > 0 && token_reuse_limit <= 100)
|
44
|
+
|
45
|
+
::Rails.logger.warn(
|
46
|
+
"You have configured an invalid value for token_reuse_limit option. " \
|
47
|
+
"It will be set to default 100",
|
48
|
+
)
|
49
|
+
@token_reuse_limit = 100
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,43 @@
|
|
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_type_strategy: Doorkeeper::Request::Token,
|
15
|
+
)
|
16
|
+
|
17
|
+
register(
|
18
|
+
:authorization_code,
|
19
|
+
response_type_matches: "code",
|
20
|
+
response_type_strategy: Doorkeeper::Request::Code,
|
21
|
+
grant_type_matches: "authorization_code",
|
22
|
+
grant_type_strategy: Doorkeeper::Request::AuthorizationCode,
|
23
|
+
)
|
24
|
+
|
25
|
+
register(
|
26
|
+
:client_credentials,
|
27
|
+
grant_type_matches: "client_credentials",
|
28
|
+
grant_type_strategy: Doorkeeper::Request::ClientCredentials,
|
29
|
+
)
|
30
|
+
|
31
|
+
register(
|
32
|
+
:password,
|
33
|
+
grant_type_matches: "password",
|
34
|
+
grant_type_strategy: Doorkeeper::Request::Password,
|
35
|
+
)
|
36
|
+
|
37
|
+
register(
|
38
|
+
:refresh_token,
|
39
|
+
grant_type_matches: "refresh_token",
|
40
|
+
grant_type_strategy: Doorkeeper::Request::RefreshToken,
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,34 @@
|
|
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
|
+
|
9
|
+
def initialize(name, **options)
|
10
|
+
@name = name
|
11
|
+
@grant_type_matches = options[:grant_type_matches]
|
12
|
+
@grant_type_strategy = options[:grant_type_strategy]
|
13
|
+
@response_type_matches = options[:response_type_matches]
|
14
|
+
@response_type_strategy = options[:response_type_strategy]
|
15
|
+
end
|
16
|
+
|
17
|
+
def handles_grant_type?
|
18
|
+
grant_type_matches.present?
|
19
|
+
end
|
20
|
+
|
21
|
+
def handles_response_type?
|
22
|
+
response_type_matches.present?
|
23
|
+
end
|
24
|
+
|
25
|
+
def matches_grant_type?(value)
|
26
|
+
grant_type_matches === value
|
27
|
+
end
|
28
|
+
|
29
|
+
def matches_response_type?(value)
|
30
|
+
response_type_matches === value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
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
|
@@ -94,8 +94,8 @@ module Doorkeeper
|
|
94
94
|
# Interface to enumerate access token records in batches in order not
|
95
95
|
# to bloat the memory. Could be overloaded in any ORM extension.
|
96
96
|
#
|
97
|
-
def find_access_token_in_batches(relation,
|
98
|
-
relation.find_in_batches(
|
97
|
+
def find_access_token_in_batches(relation, **args, &block)
|
98
|
+
relation.find_in_batches(**args, &block)
|
99
99
|
end
|
100
100
|
|
101
101
|
# Enumerates AccessToken records in batches to find a matching token.
|
@@ -377,7 +377,7 @@ module Doorkeeper
|
|
377
377
|
return unless self.class.refresh_token_revoked_on_use?
|
378
378
|
|
379
379
|
old_refresh_token&.revoke
|
380
|
-
|
380
|
+
update_attribute(:previous_refresh_token, "")
|
381
381
|
end
|
382
382
|
|
383
383
|
private
|
@@ -4,12 +4,12 @@ module Doorkeeper
|
|
4
4
|
module OAuth
|
5
5
|
module Authorization
|
6
6
|
class Context
|
7
|
-
attr_reader :client, :grant_type, :scopes
|
7
|
+
attr_reader :client, :grant_type, :resource_owner, :scopes
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
def initialize(**attributes)
|
10
|
+
attributes.each do |name, value|
|
11
|
+
instance_variable_set(:"@#{name}", value) if respond_to?(name)
|
12
|
+
end
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -7,7 +7,7 @@ module Doorkeeper
|
|
7
7
|
attr_reader :pre_auth, :resource_owner, :token
|
8
8
|
|
9
9
|
class << self
|
10
|
-
def build_context(pre_auth_or_oauth_client, grant_type, scopes)
|
10
|
+
def build_context(pre_auth_or_oauth_client, grant_type, scopes, resource_owner)
|
11
11
|
oauth_client = if pre_auth_or_oauth_client.respond_to?(:application)
|
12
12
|
pre_auth_or_oauth_client.application
|
13
13
|
elsif pre_auth_or_oauth_client.respond_to?(:client)
|
@@ -17,9 +17,10 @@ module Doorkeeper
|
|
17
17
|
end
|
18
18
|
|
19
19
|
Doorkeeper::OAuth::Authorization::Context.new(
|
20
|
-
oauth_client,
|
21
|
-
grant_type,
|
22
|
-
scopes,
|
20
|
+
client: oauth_client,
|
21
|
+
grant_type: grant_type,
|
22
|
+
scopes: scopes,
|
23
|
+
resource_owner: resource_owner,
|
23
24
|
)
|
24
25
|
end
|
25
26
|
|
@@ -55,6 +56,7 @@ module Doorkeeper
|
|
55
56
|
pre_auth.client,
|
56
57
|
Doorkeeper::OAuth::IMPLICIT,
|
57
58
|
pre_auth.scopes,
|
59
|
+
resource_owner,
|
58
60
|
)
|
59
61
|
|
60
62
|
@token = Doorkeeper.config.access_token_model.find_or_create_for(
|
@@ -3,7 +3,6 @@
|
|
3
3
|
module Doorkeeper
|
4
4
|
module OAuth
|
5
5
|
class AuthorizationCodeRequest < BaseRequest
|
6
|
-
validate :pkce_support, error: :invalid_request
|
7
6
|
validate :params, error: :invalid_request
|
8
7
|
validate :client, error: :invalid_client
|
9
8
|
validate :grant, error: :invalid_grant
|
@@ -32,12 +31,6 @@ module Doorkeeper
|
|
32
31
|
|
33
32
|
grant.revoke
|
34
33
|
|
35
|
-
resource_owner = if Doorkeeper.config.polymorphic_resource_owner?
|
36
|
-
grant.resource_owner
|
37
|
-
else
|
38
|
-
grant.resource_owner_id
|
39
|
-
end
|
40
|
-
|
41
34
|
find_or_create_access_token(
|
42
35
|
grant.application,
|
43
36
|
resource_owner,
|
@@ -49,16 +42,16 @@ module Doorkeeper
|
|
49
42
|
super
|
50
43
|
end
|
51
44
|
|
52
|
-
def
|
53
|
-
Doorkeeper.config.
|
45
|
+
def resource_owner
|
46
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
47
|
+
grant.resource_owner
|
48
|
+
else
|
49
|
+
grant.resource_owner_id
|
50
|
+
end
|
54
51
|
end
|
55
52
|
|
56
|
-
def
|
57
|
-
|
58
|
-
!pkce_supported? &&
|
59
|
-
code_verifier.present?
|
60
|
-
|
61
|
-
@invalid_request_reason.nil?
|
53
|
+
def pkce_supported?
|
54
|
+
Doorkeeper.config.access_grant_model.pkce_supported?
|
62
55
|
end
|
63
56
|
|
64
57
|
def validate_params
|
@@ -91,8 +84,8 @@ module Doorkeeper
|
|
91
84
|
# if either side (server or client) request PKCE, check the verifier
|
92
85
|
# against the DB - if PKCE is supported
|
93
86
|
def validate_code_verifier
|
94
|
-
return true unless
|
95
|
-
return
|
87
|
+
return true unless pkce_supported?
|
88
|
+
return grant.code_challenge.blank? if code_verifier.blank?
|
96
89
|
|
97
90
|
if grant.code_challenge_method == "S256"
|
98
91
|
grant.code_challenge == generate_code_challenge(code_verifier)
|
@@ -27,7 +27,7 @@ module Doorkeeper
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def find_or_create_access_token(client, resource_owner, scopes, server)
|
30
|
-
context = Authorization::Token.build_context(client, grant_type, scopes)
|
30
|
+
context = Authorization::Token.build_context(client, grant_type, scopes, resource_owner)
|
31
31
|
@access_token = server_config.access_token_model.find_or_create_for(
|
32
32
|
application: client,
|
33
33
|
resource_owner: resource_owner,
|
@@ -39,7 +39,8 @@ module Doorkeeper
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def lookup_existing_token?
|
42
|
-
server_config.reuse_access_token ||
|
42
|
+
server_config.reuse_access_token ||
|
43
|
+
server_config.revoke_previous_client_credentials_token?
|
43
44
|
end
|
44
45
|
|
45
46
|
def find_existing_token_for(client, scopes)
|
@@ -25,21 +25,31 @@ module Doorkeeper
|
|
25
25
|
if URIChecker.oob_uri?(pre_auth.redirect_uri)
|
26
26
|
auth.oob_redirect
|
27
27
|
elsif response_on_fragment
|
28
|
-
|
29
|
-
pre_auth.redirect_uri,
|
30
|
-
access_token: auth.token.plaintext_token,
|
31
|
-
token_type: auth.token.token_type,
|
32
|
-
expires_in: auth.token.expires_in_seconds,
|
33
|
-
state: pre_auth.state,
|
34
|
-
)
|
28
|
+
uri_with_fragment
|
35
29
|
else
|
36
|
-
|
37
|
-
pre_auth.redirect_uri,
|
38
|
-
code: auth.token.plaintext_token,
|
39
|
-
state: pre_auth.state,
|
40
|
-
)
|
30
|
+
uri_with_query
|
41
31
|
end
|
42
32
|
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def uri_with_fragment
|
37
|
+
Authorization::URIBuilder.uri_with_fragment(
|
38
|
+
pre_auth.redirect_uri,
|
39
|
+
access_token: auth.token.plaintext_token,
|
40
|
+
token_type: auth.token.token_type,
|
41
|
+
expires_in: auth.token.expires_in_seconds,
|
42
|
+
state: pre_auth.state,
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def uri_with_query
|
47
|
+
Authorization::URIBuilder.uri_with_query(
|
48
|
+
pre_auth.redirect_uri,
|
49
|
+
code: auth.token.plaintext_token,
|
50
|
+
state: pre_auth.state,
|
51
|
+
)
|
52
|
+
end
|
43
53
|
end
|
44
54
|
end
|
45
55
|
end
|
@@ -5,6 +5,8 @@ module Doorkeeper
|
|
5
5
|
class ErrorResponse < BaseResponse
|
6
6
|
include OAuth::Helpers
|
7
7
|
|
8
|
+
NON_REDIRECTABLE_STATES = %i[invalid_redirect_uri invalid_client unauthorized_client].freeze
|
9
|
+
|
8
10
|
def self.from_request(request, attributes = {})
|
9
11
|
new(
|
10
12
|
attributes.merge(
|
@@ -32,7 +34,7 @@ module Doorkeeper
|
|
32
34
|
end
|
33
35
|
|
34
36
|
def status
|
35
|
-
if name == :invalid_client
|
37
|
+
if name == :invalid_client || name == :unauthorized_client
|
36
38
|
:unauthorized
|
37
39
|
else
|
38
40
|
:bad_request
|
@@ -40,8 +42,7 @@ module Doorkeeper
|
|
40
42
|
end
|
41
43
|
|
42
44
|
def redirectable?
|
43
|
-
name
|
44
|
-
!URIChecker.oob_uri?(@redirect_uri)
|
45
|
+
!NON_REDIRECTABLE_STATES.include?(name) && !URIChecker.oob_uri?(@redirect_uri)
|
45
46
|
end
|
46
47
|
|
47
48
|
def redirect_uri
|
@@ -12,9 +12,7 @@ module Doorkeeper
|
|
12
12
|
@scope_str = scope_str
|
13
13
|
@valid_scopes = valid_scopes(server_scopes, app_scopes)
|
14
14
|
|
15
|
-
if grant_type
|
16
|
-
@scopes_by_grant_type = Doorkeeper.config.scopes_by_grant_type[grant_type.to_sym]
|
17
|
-
end
|
15
|
+
@scopes_by_grant_type = Doorkeeper.config.scopes_by_grant_type[grant_type.to_sym] if grant_type
|
18
16
|
end
|
19
17
|
|
20
18
|
def valid?
|
@@ -43,8 +43,27 @@ module Doorkeeper
|
|
43
43
|
resource_owner.present?
|
44
44
|
end
|
45
45
|
|
46
|
+
# Section 4.3.2. Access Token Request for Resource Owner Password Credentials Grant:
|
47
|
+
#
|
48
|
+
# If the client type is confidential or the client was issued client credentials (or assigned
|
49
|
+
# other authentication requirements), the client MUST authenticate with the authorization
|
50
|
+
# server as described in Section 3.2.1.
|
51
|
+
#
|
52
|
+
# The authorization server MUST:
|
53
|
+
#
|
54
|
+
# o require client authentication for confidential clients or for any client that was
|
55
|
+
# issued client credentials (or with other authentication requirements)
|
56
|
+
#
|
57
|
+
# o authenticate the client if client authentication is included,
|
58
|
+
#
|
59
|
+
# @see https://tools.ietf.org/html/rfc6749#section-4.3
|
60
|
+
#
|
46
61
|
def validate_client
|
47
|
-
|
62
|
+
if Doorkeeper.config.skip_client_authentication_for_password_grant
|
63
|
+
!parameters[:client_id] || client.present?
|
64
|
+
else
|
65
|
+
client.present?
|
66
|
+
end
|
48
67
|
end
|
49
68
|
|
50
69
|
def validate_client_supports_grant_flow
|
@@ -84,6 +84,11 @@ module Doorkeeper
|
|
84
84
|
Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client.application)
|
85
85
|
end
|
86
86
|
|
87
|
+
def validate_resource_owner_authorize_for_client
|
88
|
+
# The `authorize_resource_owner_for_client` config option is used for this validation
|
89
|
+
client.application.authorized_for_resource_owner?(@resource_owner)
|
90
|
+
end
|
91
|
+
|
87
92
|
def validate_redirect_uri
|
88
93
|
return false if redirect_uri.blank?
|
89
94
|
|
@@ -104,7 +109,9 @@ module Doorkeeper
|
|
104
109
|
end
|
105
110
|
|
106
111
|
def validate_response_type
|
107
|
-
server.
|
112
|
+
server.authorization_response_flows.any? do |flow|
|
113
|
+
flow.matches_response_type?(response_type)
|
114
|
+
end
|
108
115
|
end
|
109
116
|
|
110
117
|
def validate_scopes
|
@@ -117,15 +124,12 @@ module Doorkeeper
|
|
117
124
|
end
|
118
125
|
|
119
126
|
def validate_code_challenge_method
|
127
|
+
return true unless Doorkeeper.config.access_grant_model.pkce_supported?
|
128
|
+
|
120
129
|
code_challenge.blank? ||
|
121
130
|
(code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
|
122
131
|
end
|
123
132
|
|
124
|
-
def validate_resource_owner_authorize_for_client
|
125
|
-
# The `authorize_resource_owner_for_client` config option is used for this validation
|
126
|
-
client.application.authorized_for_resource_owner?(@resource_owner)
|
127
|
-
end
|
128
|
-
|
129
133
|
def response_on_fragment?
|
130
134
|
response_type == "token"
|
131
135
|
end
|
@@ -62,6 +62,19 @@ module Doorkeeper
|
|
62
62
|
attributes[:previous_refresh_token] = refresh_token.refresh_token
|
63
63
|
end
|
64
64
|
|
65
|
+
# RFC6749
|
66
|
+
# 1.5. Refresh Token
|
67
|
+
#
|
68
|
+
# Refresh tokens are issued to the client by the authorization server and are
|
69
|
+
# used to obtain a new access token when the current access token
|
70
|
+
# becomes invalid or expires, or to obtain additional access tokens
|
71
|
+
# with identical or narrower scope (access tokens may have a shorter
|
72
|
+
# lifetime and fewer permissions than authorized by the resource
|
73
|
+
# owner).
|
74
|
+
#
|
75
|
+
# Here we assume that TTL of the token received after refreshing should be
|
76
|
+
# the same as that of the original token.
|
77
|
+
#
|
65
78
|
@access_token = server_config.access_token_model.create_for(
|
66
79
|
application: refresh_token.application,
|
67
80
|
resource_owner: resource_owner,
|
@@ -38,7 +38,7 @@ module Doorkeeper
|
|
38
38
|
map_route(:authorizations, :authorization_routes)
|
39
39
|
map_route(:tokens, :token_routes)
|
40
40
|
map_route(:tokens, :revoke_routes)
|
41
|
-
map_route(:tokens, :introspect_routes)
|
41
|
+
map_route(:tokens, :introspect_routes) unless Doorkeeper.config.allow_token_introspection.is_a?(FalseClass)
|
42
42
|
map_route(:applications, :application_routes)
|
43
43
|
map_route(:authorized_applications, :authorized_applications_routes)
|
44
44
|
map_route(:token_info, :token_info_routes)
|
data/lib/doorkeeper/request.rb
CHANGED
@@ -4,32 +4,69 @@ module Doorkeeper
|
|
4
4
|
module Request
|
5
5
|
class << self
|
6
6
|
def authorization_strategy(response_type)
|
7
|
-
|
7
|
+
grant_flow = authorization_flows.detect do |flow|
|
8
|
+
flow.matches_response_type?(response_type)
|
9
|
+
end
|
10
|
+
|
11
|
+
if grant_flow
|
12
|
+
grant_flow.response_type_strategy
|
13
|
+
else
|
14
|
+
# [NOTE]: this will be removed in a newer versions of Doorkeeper.
|
15
|
+
# For retro-compatibility only
|
16
|
+
build_fallback_strategy_class(response_type)
|
17
|
+
end
|
8
18
|
end
|
9
19
|
|
10
20
|
def token_strategy(grant_type)
|
11
21
|
raise Errors::MissingRequiredParameter, :grant_type if grant_type.blank?
|
12
22
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
23
|
+
grant_flow = token_flows.detect do |flow|
|
24
|
+
flow.matches_grant_type?(grant_type)
|
25
|
+
end
|
17
26
|
|
18
|
-
|
19
|
-
|
27
|
+
if grant_flow
|
28
|
+
grant_flow.grant_type_strategy
|
29
|
+
else
|
30
|
+
# [NOTE]: this will be removed in a newer versions of Doorkeeper.
|
31
|
+
# For retro-compatibility only
|
32
|
+
raise Errors::InvalidTokenStrategy unless available.include?(grant_type.to_s)
|
20
33
|
|
21
|
-
|
34
|
+
strategy_class = build_fallback_strategy_class(grant_type)
|
35
|
+
raise Errors::InvalidTokenStrategy unless strategy_class
|
36
|
+
|
37
|
+
strategy_class
|
38
|
+
end
|
22
39
|
end
|
23
40
|
|
24
41
|
private
|
25
42
|
|
26
|
-
def
|
27
|
-
Doorkeeper.
|
43
|
+
def authorization_flows
|
44
|
+
Doorkeeper.configuration.authorization_response_flows
|
45
|
+
end
|
46
|
+
|
47
|
+
def token_flows
|
48
|
+
Doorkeeper.configuration.token_grant_flows
|
28
49
|
end
|
29
50
|
|
30
|
-
|
51
|
+
# [NOTE]: this will be removed in a newer versions of Doorkeeper.
|
52
|
+
# For retro-compatibility only
|
53
|
+
def available
|
54
|
+
Doorkeeper.config.deprecated_token_grant_types_resolver
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_fallback_strategy_class(grant_or_request_type)
|
31
58
|
strategy_class_name = grant_or_request_type.to_s.tr(" ", "_").camelize
|
32
|
-
"Doorkeeper::Request::#{strategy_class_name}".constantize
|
59
|
+
fallback_strategy = "Doorkeeper::Request::#{strategy_class_name}".constantize
|
60
|
+
|
61
|
+
::Kernel.warn <<~WARNING
|
62
|
+
[DOORKEEPER] #{fallback_strategy} found using fallback, it must be
|
63
|
+
registered using `Doorkeeper::GrantFlow.register(grant_flow_name, **options)`.
|
64
|
+
This functionality will be removed in a newer versions of Doorkeeper.
|
65
|
+
WARNING
|
66
|
+
|
67
|
+
fallback_strategy
|
68
|
+
rescue NameError
|
69
|
+
raise Errors::InvalidTokenStrategy
|
33
70
|
end
|
34
71
|
end
|
35
72
|
end
|
data/lib/doorkeeper/version.rb
CHANGED
@@ -103,12 +103,13 @@ Doorkeeper.configure do
|
|
103
103
|
#
|
104
104
|
# `context` has the following properties available:
|
105
105
|
#
|
106
|
-
# `client` - the OAuth client application (see Doorkeeper::OAuth::Client)
|
107
|
-
# `grant_type` - the grant type of the request (see Doorkeeper::OAuth)
|
108
|
-
# `scopes` - the requested scopes (see Doorkeeper::OAuth::Scopes)
|
106
|
+
# * `client` - the OAuth client application (see Doorkeeper::OAuth::Client)
|
107
|
+
# * `grant_type` - the grant type of the request (see Doorkeeper::OAuth)
|
108
|
+
# * `scopes` - the requested scopes (see Doorkeeper::OAuth::Scopes)
|
109
|
+
# * `resource_owner` - authorized resource owner instance (if present)
|
109
110
|
#
|
110
111
|
# custom_access_token_expires_in do |context|
|
111
|
-
# context.client.
|
112
|
+
# context.client.additional_settings.implicit_oauth_expiration
|
112
113
|
# end
|
113
114
|
|
114
115
|
# Use a custom class for generating the access token.
|
@@ -167,8 +168,7 @@ Doorkeeper.configure do
|
|
167
168
|
# since plain values can no longer be retrieved.
|
168
169
|
#
|
169
170
|
# Note: If you are already a user of doorkeeper and have existing tokens
|
170
|
-
# in your installation, they will be invalid without
|
171
|
-
# setting `fallback_to_plain_secrets` below.
|
171
|
+
# in your installation, they will be invalid without adding 'fallback: :plain'.
|
172
172
|
#
|
173
173
|
# hash_token_secrets
|
174
174
|
# By default, token secrets will be hashed using the
|
@@ -202,7 +202,9 @@ Doorkeeper.configure do
|
|
202
202
|
# This will ensure that old access tokens and secrets
|
203
203
|
# will remain valid even if the hashing above is enabled.
|
204
204
|
#
|
205
|
-
#
|
205
|
+
# This can be done by adding 'fallback: plain', e.g. :
|
206
|
+
#
|
207
|
+
# hash_application_secrets using: '::Doorkeeper::SecretStoring::BCrypt', fallback: :plain
|
206
208
|
|
207
209
|
# Issue access tokens with refresh token (disabled by default), you may also
|
208
210
|
# pass a block which accepts `context` to customize when to give a refresh
|
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.
|
4
|
+
version: 5.5.0.rc1
|
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: 2020-
|
14
|
+
date: 2020-08-04 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: railties
|
@@ -103,14 +103,14 @@ dependencies:
|
|
103
103
|
requirements:
|
104
104
|
- - "~>"
|
105
105
|
- !ruby/object:Gem::Version
|
106
|
-
version: '
|
106
|
+
version: '6.0'
|
107
107
|
type: :development
|
108
108
|
prerelease: false
|
109
109
|
version_requirements: !ruby/object:Gem::Requirement
|
110
110
|
requirements:
|
111
111
|
- - "~>"
|
112
112
|
- !ruby/object:Gem::Version
|
113
|
-
version: '
|
113
|
+
version: '6.0'
|
114
114
|
- !ruby/object:Gem::Dependency
|
115
115
|
name: generator_spec
|
116
116
|
requirement: !ruby/object:Gem::Requirement
|
@@ -205,8 +205,13 @@ files:
|
|
205
205
|
- lib/doorkeeper/config.rb
|
206
206
|
- lib/doorkeeper/config/abstract_builder.rb
|
207
207
|
- lib/doorkeeper/config/option.rb
|
208
|
+
- lib/doorkeeper/config/validations.rb
|
208
209
|
- lib/doorkeeper/engine.rb
|
209
210
|
- lib/doorkeeper/errors.rb
|
211
|
+
- lib/doorkeeper/grant_flow.rb
|
212
|
+
- lib/doorkeeper/grant_flow/fallback_flow.rb
|
213
|
+
- lib/doorkeeper/grant_flow/flow.rb
|
214
|
+
- lib/doorkeeper/grant_flow/registry.rb
|
210
215
|
- lib/doorkeeper/grape/authorization_decorator.rb
|
211
216
|
- lib/doorkeeper/grape/helpers.rb
|
212
217
|
- lib/doorkeeper/helpers/controller.rb
|
@@ -327,9 +332,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
327
332
|
version: '2.4'
|
328
333
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
329
334
|
requirements:
|
330
|
-
- - "
|
335
|
+
- - ">"
|
331
336
|
- !ruby/object:Gem::Version
|
332
|
-
version:
|
337
|
+
version: 1.3.1
|
333
338
|
requirements: []
|
334
339
|
rubygems_version: 3.0.2
|
335
340
|
signing_key:
|