doorkeeper 5.9.9 → 6.0.0.beta1
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 +44 -22
- data/README.md +1 -0
- data/app/controllers/doorkeeper/authorizations_controller.rb +3 -33
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +0 -23
- data/app/controllers/doorkeeper/metadata_controller.rb +20 -0
- data/app/controllers/doorkeeper/tokens_controller.rb +10 -1
- data/app/views/doorkeeper/authorizations/new.html.erb +6 -0
- data/lib/doorkeeper/client_authentication/credentials.rb +11 -0
- data/lib/doorkeeper/client_authentication/fallback_method.rb +19 -0
- data/lib/doorkeeper/client_authentication/legacy_callable.rb +46 -0
- data/lib/doorkeeper/client_authentication/method.rb +23 -0
- data/lib/doorkeeper/client_authentication/registry.rb +47 -0
- data/lib/doorkeeper/client_authentication.rb +93 -0
- data/lib/doorkeeper/config/option.rb +1 -1
- data/lib/doorkeeper/config/validations.rb +162 -1
- data/lib/doorkeeper/config.rb +114 -15
- data/lib/doorkeeper/errors.rb +1 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +40 -5
- data/lib/doorkeeper/models/application_mixin.rb +14 -6
- data/lib/doorkeeper/models/concerns/secret_storable.rb +10 -1
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +11 -0
- data/lib/doorkeeper/oauth/authorization_code_request.rb +4 -1
- data/lib/doorkeeper/oauth/client.rb +18 -0
- data/lib/doorkeeper/oauth/client_authentication/client_secret_basic.rb +53 -0
- data/lib/doorkeeper/oauth/client_authentication/client_secret_post.rb +29 -0
- data/lib/doorkeeper/oauth/client_authentication/none.rb +32 -0
- data/lib/doorkeeper/oauth/code_response.rb +16 -2
- data/lib/doorkeeper/oauth/error_response.rb +11 -2
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +0 -14
- data/lib/doorkeeper/oauth/metadata_response.rb +157 -0
- data/lib/doorkeeper/oauth/pre_authorization.rb +12 -32
- data/lib/doorkeeper/oauth/token.rb +2 -95
- data/lib/doorkeeper/oauth/token_introspection.rb +27 -7
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +2 -2
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +1 -5
- data/lib/doorkeeper/rails/routes/mapping.rb +1 -0
- data/lib/doorkeeper/rails/routes.rb +6 -0
- data/lib/doorkeeper/request.rb +65 -18
- data/lib/doorkeeper/server.rb +5 -2
- data/lib/doorkeeper/version.rb +4 -4
- data/lib/doorkeeper.rb +8 -4
- data/lib/generators/doorkeeper/templates/initializer.rb +67 -18
- metadata +14 -7
- data/lib/doorkeeper/oauth/client/credentials.rb +0 -86
data/lib/doorkeeper/request.rb
CHANGED
|
@@ -3,30 +3,40 @@
|
|
|
3
3
|
module Doorkeeper
|
|
4
4
|
module Request
|
|
5
5
|
class << self
|
|
6
|
-
#
|
|
7
|
-
#
|
|
6
|
+
# Detect the OAuth client authentication method (RFC 6749 §2.3) that the
|
|
7
|
+
# given request uses. Returns the matching method's strategy (not the
|
|
8
|
+
# registry's Method wrapper), or FallbackMethod when none matches
|
|
9
|
+
# (which authenticates to no credentials).
|
|
8
10
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
# Raises Errors::MultipleClientAuthMethods when the request itself
|
|
12
|
+
# uses more than one client authentication method, since RFC 6749 §2.3
|
|
13
|
+
# forbids that (see +validate_client_authentication!+).
|
|
14
|
+
def client_authentication_method(request)
|
|
15
|
+
validate_client_authentication!(request)
|
|
16
|
+
|
|
17
|
+
authentication_method = client_authentication_methods.detect do |method|
|
|
18
|
+
method.matches_request?(request)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
if authentication_method
|
|
22
|
+
authentication_method.strategy
|
|
23
|
+
else
|
|
24
|
+
Doorkeeper::ClientAuthentication::FallbackMethod
|
|
25
|
+
end
|
|
26
|
+
end
|
|
17
27
|
|
|
28
|
+
def authorization_strategy(response_type)
|
|
18
29
|
grant_flow = authorization_flows.detect do |flow|
|
|
19
30
|
flow.matches_response_type?(response_type)
|
|
20
31
|
end
|
|
21
32
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
grant_flow.response_type_strategy || build_fallback_strategy_class(response_type)
|
|
33
|
+
if grant_flow
|
|
34
|
+
grant_flow.response_type_strategy
|
|
35
|
+
else
|
|
36
|
+
# [NOTE]: this will be removed in a newer versions of Doorkeeper.
|
|
37
|
+
# For retro-compatibility only
|
|
38
|
+
build_fallback_strategy_class(response_type)
|
|
39
|
+
end
|
|
30
40
|
end
|
|
31
41
|
|
|
32
42
|
def token_strategy(grant_type)
|
|
@@ -52,6 +62,43 @@ module Doorkeeper
|
|
|
52
62
|
|
|
53
63
|
private
|
|
54
64
|
|
|
65
|
+
# RFC 6749 §2.3 forbids clients to "use more than one authentication
|
|
66
|
+
# method in each request", so the request payload is validated against
|
|
67
|
+
# every *registered* method — regardless of which ones are configured —
|
|
68
|
+
# before any method is selected: a client sending, say, both Basic
|
|
69
|
+
# credentials and body credentials is rejected even when only one of
|
|
70
|
+
# those methods is enabled on the server.
|
|
71
|
+
#
|
|
72
|
+
# Only real authentication mechanisms count towards the limit:
|
|
73
|
+
#
|
|
74
|
+
# * +:none+ is the absence of client authentication (a public client
|
|
75
|
+
# identifying itself with a bare +client_id+), not a mechanism of its
|
|
76
|
+
# own — RFC 7521 §4.2, for example, explicitly allows a +client_id+
|
|
77
|
+
# next to a client assertion.
|
|
78
|
+
# * Deprecated +client_credentials+ callable extractors are
|
|
79
|
+
# configuration adapters rather than registered methods, so they
|
|
80
|
+
# cannot count either; they keep the historical "first extractor that
|
|
81
|
+
# returns a uid wins" selection (see
|
|
82
|
+
# ClientAuthentication::LegacyCallable) for the deprecation window.
|
|
83
|
+
def validate_client_authentication!(request)
|
|
84
|
+
matched = 0
|
|
85
|
+
|
|
86
|
+
Doorkeeper::ClientAuthentication.registered_methods.each_value do |method|
|
|
87
|
+
next if method.name == :none
|
|
88
|
+
next unless method.matches_request?(request)
|
|
89
|
+
|
|
90
|
+
matched += 1
|
|
91
|
+
|
|
92
|
+
# RFC 6749 §2.3 only forbids using more than one method, so bail out
|
|
93
|
+
# on the second match instead of evaluating the remaining methods.
|
|
94
|
+
raise Errors::MultipleClientAuthMethods if matched > 1
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def client_authentication_methods
|
|
99
|
+
Doorkeeper.configuration.client_authentication_methods
|
|
100
|
+
end
|
|
101
|
+
|
|
55
102
|
def authorization_flows
|
|
56
103
|
Doorkeeper.configuration.authorization_response_flows
|
|
57
104
|
end
|
data/lib/doorkeeper/server.rb
CHANGED
|
@@ -8,6 +8,10 @@ module Doorkeeper
|
|
|
8
8
|
@context = context
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
def client_authentication_method_for_request
|
|
12
|
+
Request.client_authentication_method(context.request)
|
|
13
|
+
end
|
|
14
|
+
|
|
11
15
|
def authorization_request(strategy)
|
|
12
16
|
klass = Request.authorization_strategy(strategy)
|
|
13
17
|
klass.new(self)
|
|
@@ -37,8 +41,7 @@ module Doorkeeper
|
|
|
37
41
|
end
|
|
38
42
|
|
|
39
43
|
def credentials
|
|
40
|
-
|
|
41
|
-
@credentials ||= OAuth::Client::Credentials.from_request(context.request, *methods)
|
|
44
|
+
@credentials ||= client_authentication_method_for_request.authenticate(context.request)
|
|
42
45
|
end
|
|
43
46
|
end
|
|
44
47
|
end
|
data/lib/doorkeeper/version.rb
CHANGED
data/lib/doorkeeper.rb
CHANGED
|
@@ -7,6 +7,7 @@ require "doorkeeper/engine"
|
|
|
7
7
|
#
|
|
8
8
|
module Doorkeeper
|
|
9
9
|
autoload :Errors, "doorkeeper/errors"
|
|
10
|
+
autoload :ClientAuthentication, "doorkeeper/client_authentication"
|
|
10
11
|
autoload :GrantFlow, "doorkeeper/grant_flow"
|
|
11
12
|
autoload :OAuth, "doorkeeper/oauth"
|
|
12
13
|
autoload :Rake, "doorkeeper/rake"
|
|
@@ -52,6 +53,7 @@ module Doorkeeper
|
|
|
52
53
|
autoload :InvalidTokenResponse, "doorkeeper/oauth/invalid_token_response"
|
|
53
54
|
autoload :InvalidRequestResponse, "doorkeeper/oauth/invalid_request_response"
|
|
54
55
|
autoload :ForbiddenTokenResponse, "doorkeeper/oauth/forbidden_token_response"
|
|
56
|
+
autoload :MetadataResponse, "doorkeeper/oauth/metadata_response"
|
|
55
57
|
autoload :NonStandard, "doorkeeper/oauth/nonstandard"
|
|
56
58
|
autoload :PasswordAccessTokenRequest, "doorkeeper/oauth/password_access_token_request"
|
|
57
59
|
autoload :PreAuthorization, "doorkeeper/oauth/pre_authorization"
|
|
@@ -62,6 +64,12 @@ module Doorkeeper
|
|
|
62
64
|
autoload :TokenRequest, "doorkeeper/oauth/token_request"
|
|
63
65
|
autoload :TokenResponse, "doorkeeper/oauth/token_response"
|
|
64
66
|
|
|
67
|
+
module ClientAuthentication
|
|
68
|
+
autoload :None, "doorkeeper/oauth/client_authentication/none"
|
|
69
|
+
autoload :ClientSecretBasic, "doorkeeper/oauth/client_authentication/client_secret_basic"
|
|
70
|
+
autoload :ClientSecretPost, "doorkeeper/oauth/client_authentication/client_secret_post"
|
|
71
|
+
end
|
|
72
|
+
|
|
65
73
|
module Authorization
|
|
66
74
|
autoload :Code, "doorkeeper/oauth/authorization/code"
|
|
67
75
|
autoload :Context, "doorkeeper/oauth/authorization/context"
|
|
@@ -69,10 +77,6 @@ module Doorkeeper
|
|
|
69
77
|
autoload :URIBuilder, "doorkeeper/oauth/authorization/uri_builder"
|
|
70
78
|
end
|
|
71
79
|
|
|
72
|
-
class Client
|
|
73
|
-
autoload :Credentials, "doorkeeper/oauth/client/credentials"
|
|
74
|
-
end
|
|
75
|
-
|
|
76
80
|
module ClientCredentials
|
|
77
81
|
autoload :Validator, "doorkeeper/oauth/client_credentials/validator"
|
|
78
82
|
autoload :Creator, "doorkeeper/oauth/client_credentials/creator"
|
|
@@ -150,6 +150,15 @@ Doorkeeper.configure do
|
|
|
150
150
|
# token found for the application, resources owner and/or set of scopes.
|
|
151
151
|
# Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383
|
|
152
152
|
#
|
|
153
|
+
# Matching considers only the application, resource owner, scopes, custom access token
|
|
154
|
+
# attributes (see +custom_access_token_attributes+) and whether a refresh token is
|
|
155
|
+
# expected — not the authorization request that produced the token. Separate authorization
|
|
156
|
+
# grants for the same combination share a single access token, so concurrent sessions of
|
|
157
|
+
# the same client become interdependent (e.g. refreshing the token in one session revokes
|
|
158
|
+
# it for the others). If you need independent tokens per session or device, keep this
|
|
159
|
+
# option disabled or differentiate the sessions with +custom_access_token_attributes+.
|
|
160
|
+
# See https://github.com/doorkeeper-gem/doorkeeper/issues/1693
|
|
161
|
+
#
|
|
153
162
|
# You can not enable this option together with +hash_token_secrets+.
|
|
154
163
|
#
|
|
155
164
|
# reuse_access_token
|
|
@@ -188,8 +197,8 @@ Doorkeeper.configure do
|
|
|
188
197
|
#
|
|
189
198
|
# revoke_previous_authorization_code_token
|
|
190
199
|
|
|
191
|
-
# Require
|
|
192
|
-
# to obtain an access_token (disabled by default)
|
|
200
|
+
# Require all clients (including confidential ones) to use PKCE when using an
|
|
201
|
+
# authorization code to obtain an access_token (disabled by default)
|
|
193
202
|
#
|
|
194
203
|
# force_pkce
|
|
195
204
|
|
|
@@ -277,21 +286,18 @@ Doorkeeper.configure do
|
|
|
277
286
|
#
|
|
278
287
|
# enforce_configured_scopes
|
|
279
288
|
|
|
280
|
-
#
|
|
281
|
-
#
|
|
282
|
-
#
|
|
289
|
+
# Configure the OAuth client authentication methods (RFC 6749 §2.3) Doorkeeper
|
|
290
|
+
# will accept and the order in which they are tried. By default it accepts
|
|
291
|
+
# HTTP Basic auth (`client_secret_basic`), credentials in the request body
|
|
292
|
+
# (`client_secret_post`), and public clients with no secret (`none`).
|
|
283
293
|
# Check out https://github.com/doorkeeper-gem/doorkeeper/wiki/Changing-how-clients-are-authenticated
|
|
284
294
|
# for more information on customization
|
|
285
295
|
#
|
|
286
|
-
#
|
|
287
|
-
# §2.3 checks that reject a request authenticating the client with more than
|
|
288
|
-
# one method, or presenting more than one client identity. A callable may
|
|
289
|
-
# legitimately overlap the built-in extractors, and the extractors after the
|
|
290
|
-
# matching one are never called, so what they would have returned is unknown.
|
|
291
|
-
# Prefer the symbol extractors unless you need something they cannot express;
|
|
292
|
-
# a callable has to reject such a request itself.
|
|
296
|
+
# client_authentication %i[client_secret_basic client_secret_post none]
|
|
293
297
|
#
|
|
294
|
-
# client_credentials
|
|
298
|
+
# The legacy `client_credentials` option is deprecated; `:from_basic` and
|
|
299
|
+
# `:from_params` are automatically mapped to `:client_secret_basic` and
|
|
300
|
+
# `:client_secret_post`.
|
|
295
301
|
|
|
296
302
|
# Change the way access token is authenticated from the request object.
|
|
297
303
|
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
|
|
@@ -316,13 +322,10 @@ Doorkeeper.configure do
|
|
|
316
322
|
# Specify what redirect URI's you want to block during Application creation.
|
|
317
323
|
# Any redirect URI is allowed by default.
|
|
318
324
|
#
|
|
319
|
-
#
|
|
320
|
-
# always rejected, regardless of this option.
|
|
321
|
-
#
|
|
322
|
-
# You can use this option in order to forbid URI's of a particular host
|
|
325
|
+
# You can use this option in order to forbid URI's with 'javascript' scheme
|
|
323
326
|
# for example.
|
|
324
327
|
#
|
|
325
|
-
# forbid_redirect_uri { |uri| uri.
|
|
328
|
+
# forbid_redirect_uri { |uri| uri.scheme.to_s.downcase == 'javascript' }
|
|
326
329
|
|
|
327
330
|
# Allows to set blank redirect URIs for Applications in case Doorkeeper configured
|
|
328
331
|
# to use URI-less OAuth grant flows like Client Credentials or Resource Owner
|
|
@@ -388,6 +391,9 @@ Doorkeeper.configure do
|
|
|
388
391
|
# If not specified, Doorkeeper enables authorization_code and
|
|
389
392
|
# client_credentials.
|
|
390
393
|
#
|
|
394
|
+
# The Refresh Token Grant Flow ("refresh_token") doesn't need to be listed
|
|
395
|
+
# here: it is enabled automatically when +use_refresh_token+ is configured.
|
|
396
|
+
#
|
|
391
397
|
# implicit and password grant flows have risks that you should understand
|
|
392
398
|
# before enabling:
|
|
393
399
|
# https://datatracker.ietf.org/doc/html/rfc6819#section-4.4.2
|
|
@@ -552,4 +558,47 @@ Doorkeeper.configure do
|
|
|
552
558
|
# WWW-Authenticate Realm (default: "Doorkeeper").
|
|
553
559
|
#
|
|
554
560
|
# realm "Doorkeeper"
|
|
561
|
+
|
|
562
|
+
# OAuth 2.0 Authorization Server Metadata (RFC 8414).
|
|
563
|
+
#
|
|
564
|
+
# Doorkeeper exposes an authorization server metadata document at
|
|
565
|
+
# `/.well-known/oauth-authorization-server`, built from the configuration
|
|
566
|
+
# above. The two options below let you customize that document.
|
|
567
|
+
#
|
|
568
|
+
# `issuer` is the authorization server's issuer identifier. When left as nil
|
|
569
|
+
# (the default) the request base URL is used for the metadata `issuer` field
|
|
570
|
+
# only. Note the asymmetry: RFC 9207 below is gated on an explicitly
|
|
571
|
+
# configured issuer, so leaving it nil still advertises a metadata `issuer`
|
|
572
|
+
# (the base URL) while `authorization_response_iss_parameter_supported` stays
|
|
573
|
+
# false and no `iss` parameter is emitted.
|
|
574
|
+
#
|
|
575
|
+
# Configuring an issuer also enables RFC 9207 (Authorization Server Issuer
|
|
576
|
+
# Identification): the `iss` parameter is added to the authorization
|
|
577
|
+
# responses redirected back to the client - both successful responses and
|
|
578
|
+
# error responses such as access_denied - and advertised via the
|
|
579
|
+
# `authorization_response_iss_parameter_supported` metadata field. Clients
|
|
580
|
+
# that parse the authorization redirect will start seeing this parameter.
|
|
581
|
+
# Per RFC 8414 and RFC 9207 the value should be an https URL with no query or
|
|
582
|
+
# fragment; a non-compliant value logs a warning at boot but is still used.
|
|
583
|
+
# Prefer a host-only issuer: Doorkeeper serves its metadata only at the root
|
|
584
|
+
# /.well-known/oauth-authorization-server, so a path-bearing issuer (e.g.
|
|
585
|
+
# https://auth.example.com/tenant) is not discoverable by RFC 8414 clients and
|
|
586
|
+
# also logs a warning.
|
|
587
|
+
#
|
|
588
|
+
# issuer "https://auth.example.com"
|
|
589
|
+
#
|
|
590
|
+
# `custom_metadata` is a Hash that is merged into the metadata response. Use
|
|
591
|
+
# it to advertise additional or non-default metadata fields, for example a
|
|
592
|
+
# `userinfo_endpoint` (which Doorkeeper itself leaves null) when pairing with
|
|
593
|
+
# an OpenID Connect extension.
|
|
594
|
+
#
|
|
595
|
+
# The merge happens last, so it can also override computed fields - including
|
|
596
|
+
# `authorization_response_iss_parameter_supported`, which Doorkeeper derives
|
|
597
|
+
# from whether `issuer` is set. Overriding a computed field is allowed but is
|
|
598
|
+
# your responsibility to keep consistent with the server's actual behaviour
|
|
599
|
+
# (e.g. don't advertise iss support as true if no `issuer` is configured).
|
|
600
|
+
#
|
|
601
|
+
# custom_metadata(
|
|
602
|
+
# userinfo_endpoint: "https://auth.example.com/oauth/userinfo",
|
|
603
|
+
# )
|
|
555
604
|
end
|
metadata
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: doorkeeper
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 6.0.0.beta1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Felipe Elias Philipp
|
|
8
8
|
- Tute Costa
|
|
9
9
|
- Jon Moss
|
|
10
10
|
- Nikita Bulai
|
|
11
|
-
autorequire:
|
|
12
11
|
bindir: bin
|
|
13
12
|
cert_chain: []
|
|
14
|
-
date:
|
|
13
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
15
14
|
dependencies:
|
|
16
15
|
- !ruby/object:Gem::Dependency
|
|
17
16
|
name: railties
|
|
@@ -184,6 +183,7 @@ files:
|
|
|
184
183
|
- app/controllers/doorkeeper/applications_controller.rb
|
|
185
184
|
- app/controllers/doorkeeper/authorizations_controller.rb
|
|
186
185
|
- app/controllers/doorkeeper/authorized_applications_controller.rb
|
|
186
|
+
- app/controllers/doorkeeper/metadata_controller.rb
|
|
187
187
|
- app/controllers/doorkeeper/token_info_controller.rb
|
|
188
188
|
- app/controllers/doorkeeper/tokens_controller.rb
|
|
189
189
|
- app/helpers/doorkeeper/dashboard_helper.rb
|
|
@@ -203,6 +203,12 @@ files:
|
|
|
203
203
|
- app/views/layouts/doorkeeper/application.html.erb
|
|
204
204
|
- config/locales/en.yml
|
|
205
205
|
- lib/doorkeeper.rb
|
|
206
|
+
- lib/doorkeeper/client_authentication.rb
|
|
207
|
+
- lib/doorkeeper/client_authentication/credentials.rb
|
|
208
|
+
- lib/doorkeeper/client_authentication/fallback_method.rb
|
|
209
|
+
- lib/doorkeeper/client_authentication/legacy_callable.rb
|
|
210
|
+
- lib/doorkeeper/client_authentication/method.rb
|
|
211
|
+
- lib/doorkeeper/client_authentication/registry.rb
|
|
206
212
|
- lib/doorkeeper/config.rb
|
|
207
213
|
- lib/doorkeeper/config/abstract_builder.rb
|
|
208
214
|
- lib/doorkeeper/config/option.rb
|
|
@@ -240,7 +246,9 @@ files:
|
|
|
240
246
|
- lib/doorkeeper/oauth/base_request.rb
|
|
241
247
|
- lib/doorkeeper/oauth/base_response.rb
|
|
242
248
|
- lib/doorkeeper/oauth/client.rb
|
|
243
|
-
- lib/doorkeeper/oauth/
|
|
249
|
+
- lib/doorkeeper/oauth/client_authentication/client_secret_basic.rb
|
|
250
|
+
- lib/doorkeeper/oauth/client_authentication/client_secret_post.rb
|
|
251
|
+
- lib/doorkeeper/oauth/client_authentication/none.rb
|
|
244
252
|
- lib/doorkeeper/oauth/client_credentials/creator.rb
|
|
245
253
|
- lib/doorkeeper/oauth/client_credentials/issuer.rb
|
|
246
254
|
- lib/doorkeeper/oauth/client_credentials/validator.rb
|
|
@@ -256,6 +264,7 @@ files:
|
|
|
256
264
|
- lib/doorkeeper/oauth/hooks/context.rb
|
|
257
265
|
- lib/doorkeeper/oauth/invalid_request_response.rb
|
|
258
266
|
- lib/doorkeeper/oauth/invalid_token_response.rb
|
|
267
|
+
- lib/doorkeeper/oauth/metadata_response.rb
|
|
259
268
|
- lib/doorkeeper/oauth/nonstandard.rb
|
|
260
269
|
- lib/doorkeeper/oauth/password_access_token_request.rb
|
|
261
270
|
- lib/doorkeeper/oauth/pre_authorization.rb
|
|
@@ -330,7 +339,6 @@ metadata:
|
|
|
330
339
|
bug_tracker_uri: https://github.com/doorkeeper-gem/doorkeeper/issues
|
|
331
340
|
documentation_uri: https://doorkeeper.gitbook.io/guides/
|
|
332
341
|
funding_uri: https://opencollective.com/doorkeeper-gem
|
|
333
|
-
post_install_message:
|
|
334
342
|
rdoc_options: []
|
|
335
343
|
require_paths:
|
|
336
344
|
- lib
|
|
@@ -345,8 +353,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
345
353
|
- !ruby/object:Gem::Version
|
|
346
354
|
version: '0'
|
|
347
355
|
requirements: []
|
|
348
|
-
rubygems_version:
|
|
349
|
-
signing_key:
|
|
356
|
+
rubygems_version: 4.0.11
|
|
350
357
|
specification_version: 4
|
|
351
358
|
summary: OAuth 2 provider for Rails and Grape
|
|
352
359
|
test_files: []
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Doorkeeper
|
|
4
|
-
module OAuth
|
|
5
|
-
class Client
|
|
6
|
-
Credentials = Struct.new(:uid, :secret) do
|
|
7
|
-
class << self
|
|
8
|
-
# Extracts the client credentials from the request using the
|
|
9
|
-
# configured extraction methods. The first method that yields
|
|
10
|
-
# credentials wins, as it always has.
|
|
11
|
-
#
|
|
12
|
-
# Raises Errors::MultipleClientAuthMethods when the request
|
|
13
|
-
# authenticates the client with more than one method, or presents
|
|
14
|
-
# more than one client identity, which RFC 6749 §2.3 forbids ("The
|
|
15
|
-
# client MUST NOT use more than one authentication method in each
|
|
16
|
-
# request").
|
|
17
|
-
def from_request(request, *credentials_methods)
|
|
18
|
-
# Callable extractors are opaque: they may legitimately overlap the
|
|
19
|
-
# built-in methods they are configured with, and evaluating all of
|
|
20
|
-
# them would also break the existing contract that the extractors
|
|
21
|
-
# after the matching one are not called. Such configurations keep
|
|
22
|
-
# the historical behaviour untouched, including the fact that a
|
|
23
|
-
# request authenticating with more than one method, or presenting
|
|
24
|
-
# more than one client identity, resolves to the first extracted
|
|
25
|
-
# credentials instead of being rejected: the extractor that would
|
|
26
|
-
# have surfaced the second identity is never evaluated. The
|
|
27
|
-
# +client_credentials+ configuration option documents this.
|
|
28
|
-
return first_from_request(request, credentials_methods) unless credentials_methods.all?(Symbol)
|
|
29
|
-
|
|
30
|
-
credentials = credentials_methods.filter_map { |method| extract(request, method) }
|
|
31
|
-
|
|
32
|
-
# Only credentials carrying a secret authenticate the client. A bare
|
|
33
|
-
# uid is a public client identifying itself (RFC 6749 §2.3 "none"),
|
|
34
|
-
# not an authentication method of its own, so it doesn't count
|
|
35
|
-
# towards the single-method rule — RFC 7521 §4.2, for example,
|
|
36
|
-
# explicitly allows a client_id next to another authentication
|
|
37
|
-
# method.
|
|
38
|
-
raise Errors::MultipleClientAuthMethods if credentials.count { |c| c.secret.present? } > 1
|
|
39
|
-
|
|
40
|
-
# §4.2 allows that bare client_id because it identifies the *same*
|
|
41
|
-
# client as the authentication method it accompanies. Credentials
|
|
42
|
-
# naming two different clients are two client identities in one
|
|
43
|
-
# request and authenticate neither: without this check the first
|
|
44
|
-
# extracted uid would win and the other identity would be silently
|
|
45
|
-
# discarded, so the caller could authenticate as one client while
|
|
46
|
-
# the request asks to act as another.
|
|
47
|
-
raise Errors::MultipleClientAuthMethods if credentials.uniq(&:uid).size > 1
|
|
48
|
-
|
|
49
|
-
credentials.first
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def from_params(request)
|
|
53
|
-
request.parameters.values_at(:client_id, :client_secret)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def from_basic(request)
|
|
57
|
-
authorization = request.authorization
|
|
58
|
-
if authorization.present? && authorization =~ /^Basic (.*)/im
|
|
59
|
-
Base64.decode64(Regexp.last_match(1)).split(/:/, 2)
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
def first_from_request(request, credentials_methods)
|
|
66
|
-
credentials_methods.inject(nil) do |_, method|
|
|
67
|
-
credentials = extract(request, method)
|
|
68
|
-
break credentials if credentials
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Returns the credentials the given method extracts from the request,
|
|
73
|
-
# or nil when it extracts none.
|
|
74
|
-
def extract(request, method)
|
|
75
|
-
method = self.method(method) if method.is_a?(Symbol)
|
|
76
|
-
Credentials.new(*method.call(request)).presence
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# Public clients may have their secret blank, but "credentials" are
|
|
81
|
-
# still present
|
|
82
|
-
delegate :blank?, to: :uid
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|