doorkeeper 5.4.0 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +56 -10
- data/README.md +4 -4
- data/app/controllers/doorkeeper/authorizations_controller.rb +16 -5
- data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +34 -26
- data/app/views/doorkeeper/applications/show.html.erb +16 -12
- data/app/views/doorkeeper/authorizations/form_post.html.erb +11 -0
- data/config/locales/en.yml +3 -1
- data/lib/doorkeeper/config/option.rb +1 -3
- data/lib/doorkeeper/config/validations.rb +53 -0
- data/lib/doorkeeper/config.rb +87 -62
- data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
- data/lib/doorkeeper/grant_flow/flow.rb +44 -0
- data/lib/doorkeeper/grant_flow/registry.rb +50 -0
- data/lib/doorkeeper/grant_flow.rb +45 -0
- data/lib/doorkeeper/helpers/controller.rb +4 -0
- data/lib/doorkeeper/models/access_grant_mixin.rb +1 -2
- data/lib/doorkeeper/models/access_token_mixin.rb +3 -3
- data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
- data/lib/doorkeeper/oauth/authorization/code.rb +4 -0
- data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
- data/lib/doorkeeper/oauth/authorization/token.rb +10 -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 +17 -11
- 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 +33 -8
- data/lib/doorkeeper/oauth/refresh_token_request.rb +13 -0
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +11 -1
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +9 -1
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +15 -4
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +5 -0
- data/lib/doorkeeper/orm/active_record.rb +5 -14
- data/lib/doorkeeper/rails/routes.rb +1 -3
- data/lib/doorkeeper/rake/db.rake +3 -3
- data/lib/doorkeeper/rake/setup.rake +5 -0
- data/lib/doorkeeper/request.rb +49 -12
- data/lib/doorkeeper/version.rb +1 -5
- data/lib/doorkeeper.rb +5 -0
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +1 -1
- data/lib/generators/doorkeeper/templates/initializer.rb +9 -7
- metadata +20 -7
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module GrantFlow
|
|
5
|
+
class Flow
|
|
6
|
+
attr_reader :name, :grant_type_matches, :grant_type_strategy,
|
|
7
|
+
:response_type_matches, :response_type_strategy,
|
|
8
|
+
:response_mode_matches
|
|
9
|
+
|
|
10
|
+
def initialize(name, **options)
|
|
11
|
+
@name = name
|
|
12
|
+
@grant_type_matches = options[:grant_type_matches]
|
|
13
|
+
@grant_type_strategy = options[:grant_type_strategy]
|
|
14
|
+
@response_type_matches = options[:response_type_matches]
|
|
15
|
+
@response_type_strategy = options[:response_type_strategy]
|
|
16
|
+
@response_mode_matches = options[:response_mode_matches]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def handles_grant_type?
|
|
20
|
+
grant_type_matches.present?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def handles_response_type?
|
|
24
|
+
response_type_matches.present?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def matches_grant_type?(value)
|
|
28
|
+
grant_type_matches === value
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def matches_response_type?(value)
|
|
32
|
+
response_type_matches === value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def default_response_mode
|
|
36
|
+
response_mode_matches[0]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def matches_response_mode?(value)
|
|
40
|
+
response_mode_matches.include?(value)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module GrantFlow
|
|
5
|
+
module Registry
|
|
6
|
+
mattr_accessor :flows
|
|
7
|
+
self.flows = {}
|
|
8
|
+
|
|
9
|
+
mattr_accessor :aliases
|
|
10
|
+
self.aliases = {}
|
|
11
|
+
|
|
12
|
+
# Allows to register custom OAuth grant flow so that Doorkeeper
|
|
13
|
+
# could recognize and process it.
|
|
14
|
+
#
|
|
15
|
+
def register(name_or_flow, **options)
|
|
16
|
+
unless name_or_flow.is_a?(Doorkeeper::GrantFlow::Flow)
|
|
17
|
+
name_or_flow = Flow.new(name_or_flow, **options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
flow_key = name_or_flow.name.to_sym
|
|
21
|
+
|
|
22
|
+
if flows.key?(flow_key)
|
|
23
|
+
::Kernel.warn <<~WARNING
|
|
24
|
+
[DOORKEEPER] '#{flow_key}' grant flow already registered and will be overridden
|
|
25
|
+
in #{caller(1..1).first}
|
|
26
|
+
WARNING
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
flows[flow_key] = name_or_flow
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Allows to register aliases that could be used in `grant_flows`
|
|
33
|
+
# configuration option. It is possible to have aliases like 1:1 or
|
|
34
|
+
# 1:N, i.e. "implicit_oidc" => ['token', 'id_token', 'id_token token'].
|
|
35
|
+
#
|
|
36
|
+
def register_alias(alias_name, **options)
|
|
37
|
+
aliases[alias_name.to_sym] = Array.wrap(options.fetch(:as))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def expand_alias(alias_name)
|
|
41
|
+
aliases.fetch(alias_name.to_sym, [])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# [NOTE]: make it to use #fetch after removing fallbacks
|
|
45
|
+
def get(name)
|
|
46
|
+
flows[name.to_sym]
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "doorkeeper/grant_flow/flow"
|
|
4
|
+
require "doorkeeper/grant_flow/fallback_flow"
|
|
5
|
+
require "doorkeeper/grant_flow/registry"
|
|
6
|
+
|
|
7
|
+
module Doorkeeper
|
|
8
|
+
module GrantFlow
|
|
9
|
+
extend Registry
|
|
10
|
+
|
|
11
|
+
register(
|
|
12
|
+
:implicit,
|
|
13
|
+
response_type_matches: "token",
|
|
14
|
+
response_mode_matches: %w[fragment form_post],
|
|
15
|
+
response_type_strategy: Doorkeeper::Request::Token,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
register(
|
|
19
|
+
:authorization_code,
|
|
20
|
+
response_type_matches: "code",
|
|
21
|
+
response_mode_matches: %w[query fragment form_post],
|
|
22
|
+
response_type_strategy: Doorkeeper::Request::Code,
|
|
23
|
+
grant_type_matches: "authorization_code",
|
|
24
|
+
grant_type_strategy: Doorkeeper::Request::AuthorizationCode,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
register(
|
|
28
|
+
:client_credentials,
|
|
29
|
+
grant_type_matches: "client_credentials",
|
|
30
|
+
grant_type_strategy: Doorkeeper::Request::ClientCredentials,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
register(
|
|
34
|
+
:password,
|
|
35
|
+
grant_type_matches: "password",
|
|
36
|
+
grant_type_strategy: Doorkeeper::Request::Password,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
register(
|
|
40
|
+
:refresh_token,
|
|
41
|
+
grant_type_matches: "refresh_token",
|
|
42
|
+
grant_type_strategy: Doorkeeper::Request::RefreshToken,
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -16,6 +16,8 @@ module Doorkeeper
|
|
|
16
16
|
|
|
17
17
|
# :doc:
|
|
18
18
|
def current_resource_owner
|
|
19
|
+
return @current_resource_owner if defined?(@current_resource_owner)
|
|
20
|
+
|
|
19
21
|
@current_resource_owner ||= begin
|
|
20
22
|
instance_eval(&Doorkeeper.config.authenticate_resource_owner)
|
|
21
23
|
end
|
|
@@ -36,6 +38,8 @@ module Doorkeeper
|
|
|
36
38
|
|
|
37
39
|
# :doc:
|
|
38
40
|
def doorkeeper_token
|
|
41
|
+
return @doorkeeper_token if defined?(@doorkeeper_token)
|
|
42
|
+
|
|
39
43
|
@doorkeeper_token ||= OAuth::Token.authenticate(request, *config_methods)
|
|
40
44
|
end
|
|
41
45
|
|
|
@@ -89,8 +89,7 @@ module Doorkeeper
|
|
|
89
89
|
# suitable for PKCE validation
|
|
90
90
|
#
|
|
91
91
|
def generate_code_challenge(code_verifier)
|
|
92
|
-
|
|
93
|
-
padded_result.split("=")[0] # Remove any trailing '='
|
|
92
|
+
Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier), padding: false)
|
|
94
93
|
end
|
|
95
94
|
|
|
96
95
|
def pkce_supported?
|
|
@@ -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, "") if previous_refresh_token.present?
|
|
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(
|
|
@@ -74,6 +76,10 @@ module Doorkeeper
|
|
|
74
76
|
}
|
|
75
77
|
end
|
|
76
78
|
|
|
79
|
+
def access_token?
|
|
80
|
+
true
|
|
81
|
+
end
|
|
82
|
+
|
|
77
83
|
private
|
|
78
84
|
|
|
79
85
|
def controller
|
|
@@ -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)
|
|
@@ -21,23 +21,29 @@ module Doorkeeper
|
|
|
21
21
|
auth.token
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
def
|
|
25
|
-
if
|
|
26
|
-
|
|
27
|
-
elsif response_on_fragment
|
|
28
|
-
Authorization::URIBuilder.uri_with_fragment(
|
|
29
|
-
pre_auth.redirect_uri,
|
|
24
|
+
def body
|
|
25
|
+
if auth.try(:access_token?)
|
|
26
|
+
{
|
|
30
27
|
access_token: auth.token.plaintext_token,
|
|
31
28
|
token_type: auth.token.token_type,
|
|
32
29
|
expires_in: auth.token.expires_in_seconds,
|
|
33
30
|
state: pre_auth.state,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
pre_auth.redirect_uri,
|
|
31
|
+
}
|
|
32
|
+
elsif auth.try(:access_grant?)
|
|
33
|
+
{
|
|
38
34
|
code: auth.token.plaintext_token,
|
|
39
35
|
state: pre_auth.state,
|
|
40
|
-
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def redirect_uri
|
|
41
|
+
if URIChecker.oob_uri?(pre_auth.redirect_uri)
|
|
42
|
+
auth.oob_redirect
|
|
43
|
+
elsif response_on_fragment
|
|
44
|
+
Authorization::URIBuilder.uri_with_fragment(pre_auth.redirect_uri, body)
|
|
45
|
+
else
|
|
46
|
+
Authorization::URIBuilder.uri_with_query(pre_auth.redirect_uri, body)
|
|
41
47
|
end
|
|
42
48
|
end
|
|
43
49
|
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
|
|
@@ -12,16 +12,19 @@ module Doorkeeper
|
|
|
12
12
|
validate :redirect_uri, error: :invalid_redirect_uri
|
|
13
13
|
validate :params, error: :invalid_request
|
|
14
14
|
validate :response_type, error: :unsupported_response_type
|
|
15
|
+
validate :response_mode, error: :unsupported_response_mode
|
|
15
16
|
validate :scopes, error: :invalid_scope
|
|
16
17
|
validate :code_challenge_method, error: :invalid_code_challenge_method
|
|
17
18
|
|
|
18
19
|
attr_reader :client, :code_challenge, :code_challenge_method, :missing_param,
|
|
19
|
-
:redirect_uri, :resource_owner, :response_type, :state
|
|
20
|
+
:redirect_uri, :resource_owner, :response_type, :state,
|
|
21
|
+
:authorization_response_flow, :response_mode
|
|
20
22
|
|
|
21
23
|
def initialize(server, parameters = {}, resource_owner = nil)
|
|
22
24
|
@server = server
|
|
23
25
|
@client_id = parameters[:client_id]
|
|
24
26
|
@response_type = parameters[:response_type]
|
|
27
|
+
@response_mode = parameters[:response_mode]
|
|
25
28
|
@redirect_uri = parameters[:redirect_uri]
|
|
26
29
|
@scope = parameters[:scope]
|
|
27
30
|
@state = parameters[:state]
|
|
@@ -57,6 +60,10 @@ module Doorkeeper
|
|
|
57
60
|
pre_auth_hash
|
|
58
61
|
end
|
|
59
62
|
|
|
63
|
+
def form_post_response?
|
|
64
|
+
response_mode == "form_post"
|
|
65
|
+
end
|
|
66
|
+
|
|
60
67
|
private
|
|
61
68
|
|
|
62
69
|
attr_reader :client_id, :server
|
|
@@ -84,6 +91,11 @@ module Doorkeeper
|
|
|
84
91
|
Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client.application)
|
|
85
92
|
end
|
|
86
93
|
|
|
94
|
+
def validate_resource_owner_authorize_for_client
|
|
95
|
+
# The `authorize_resource_owner_for_client` config option is used for this validation
|
|
96
|
+
client.application.authorized_for_resource_owner?(@resource_owner)
|
|
97
|
+
end
|
|
98
|
+
|
|
87
99
|
def validate_redirect_uri
|
|
88
100
|
return false if redirect_uri.blank?
|
|
89
101
|
|
|
@@ -104,7 +116,21 @@ module Doorkeeper
|
|
|
104
116
|
end
|
|
105
117
|
|
|
106
118
|
def validate_response_type
|
|
107
|
-
server.
|
|
119
|
+
server.authorization_response_flows.any? do |flow|
|
|
120
|
+
if flow.matches_response_type?(response_type)
|
|
121
|
+
@authorization_response_flow = flow
|
|
122
|
+
true
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def validate_response_mode
|
|
128
|
+
if response_mode.blank?
|
|
129
|
+
@response_mode = authorization_response_flow.default_response_mode
|
|
130
|
+
return true
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
authorization_response_flow.matches_response_mode?(response_mode)
|
|
108
134
|
end
|
|
109
135
|
|
|
110
136
|
def validate_scopes
|
|
@@ -117,17 +143,16 @@ module Doorkeeper
|
|
|
117
143
|
end
|
|
118
144
|
|
|
119
145
|
def validate_code_challenge_method
|
|
146
|
+
return true unless Doorkeeper.config.access_grant_model.pkce_supported?
|
|
147
|
+
|
|
120
148
|
code_challenge.blank? ||
|
|
121
149
|
(code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
|
|
122
150
|
end
|
|
123
151
|
|
|
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
152
|
def response_on_fragment?
|
|
130
|
-
response_type == "token"
|
|
153
|
+
return response_type == "token" if response_mode.nil?
|
|
154
|
+
|
|
155
|
+
response_mode == "fragment"
|
|
131
156
|
end
|
|
132
157
|
|
|
133
158
|
def grant_type
|
|
@@ -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,
|
|
@@ -5,7 +5,7 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
|
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
6
|
|
|
7
7
|
included do
|
|
8
|
-
self.table_name =
|
|
8
|
+
self.table_name = compute_doorkeeper_table_name
|
|
9
9
|
|
|
10
10
|
include ::Doorkeeper::AccessGrantMixin
|
|
11
11
|
|
|
@@ -54,5 +54,15 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
|
|
|
54
54
|
secret_strategy.store_secret(self, :token, @raw_token)
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
|
+
|
|
58
|
+
module ClassMethods
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def compute_doorkeeper_table_name
|
|
62
|
+
table_name = "oauth_access_grant"
|
|
63
|
+
table_name = table_name.pluralize if pluralize_table_names
|
|
64
|
+
"#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
57
67
|
end
|
|
58
68
|
end
|
|
@@ -5,7 +5,7 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
|
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
6
|
|
|
7
7
|
included do
|
|
8
|
-
self.table_name =
|
|
8
|
+
self.table_name = compute_doorkeeper_table_name
|
|
9
9
|
|
|
10
10
|
include ::Doorkeeper::AccessTokenMixin
|
|
11
11
|
|
|
@@ -46,6 +46,14 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
|
|
|
46
46
|
def refresh_token_revoked_on_use?
|
|
47
47
|
column_names.include?("previous_refresh_token")
|
|
48
48
|
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def compute_doorkeeper_table_name
|
|
53
|
+
table_name = "oauth_access_token"
|
|
54
|
+
table_name = table_name.pluralize if pluralize_table_names
|
|
55
|
+
"#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
|
56
|
+
end
|
|
49
57
|
end
|
|
50
58
|
end
|
|
51
59
|
end
|