doorkeeper 5.6.9 → 5.7.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 +12 -4
- data/app/controllers/doorkeeper/authorizations_controller.rb +9 -3
- data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/form_post.html.erb +1 -1
- data/lib/doorkeeper/config.rb +11 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +61 -5
- data/lib/doorkeeper/oauth/authorization_code_request.rb +8 -0
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +6 -3
- data/lib/doorkeeper/oauth/pre_authorization.rb +1 -1
- data/lib/doorkeeper/oauth/token_response.rb +3 -1
- data/lib/doorkeeper/version.rb +2 -2
- data/lib/generators/doorkeeper/templates/initializer.rb +11 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aeb5db3b840c0c214129e69fb029c1daf95974b033856ab550e9abd3b529b0c1
|
4
|
+
data.tar.gz: 6f948a7fa2b8a2796c56e94a762b1e256228c13f972bbd056d1b4e246bea5001
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2da3aca020ed25ba334d5dfbcbffd1c46818eaa79bbc67e38bcf01dada8105c6683bfb5552dae1cdce34a68e5baafa0c9a9b49b5c980f78464925f2f7576b873
|
7
|
+
data.tar.gz: 865a9c03a28b309624e8058a251c92d002199f9072015efafafb622fad5878274042bee32aba169a0395fc1ba0558ca86c1bd7b32b9dc288c5136b69c6a68e69
|
data/CHANGELOG.md
CHANGED
@@ -7,7 +7,15 @@ User-visible changes worth mentioning.
|
|
7
7
|
|
8
8
|
## main
|
9
9
|
|
10
|
-
|
10
|
+
Add your entry here.
|
11
|
+
|
12
|
+
## 5.7.0
|
13
|
+
|
14
|
+
- [#1696] Add missing `#issued_token` method to `OAuth::TokenResponse`
|
15
|
+
- [#1697] Allow a TokenResponse body to be customized (memoize response body).
|
16
|
+
- [#1702] Fix bugs for error response in the form_post and error view
|
17
|
+
- [#1660] Custom access token attributes are now considered when finding matching tokens (fixes #1665).
|
18
|
+
Introduce `revoke_previous_client_credentials_token` configuration option.
|
11
19
|
|
12
20
|
## 5.6.9
|
13
21
|
|
@@ -33,17 +41,17 @@ User-visible changes worth mentioning.
|
|
33
41
|
- [#1648] Add custom token attributes to Refresh Token Request.
|
34
42
|
- [#1649] Fixed custom_access_token_attributes related errors.
|
35
43
|
|
36
|
-
|
44
|
+
## 5.6.5
|
37
45
|
|
38
46
|
- [#1602] Allow custom data to be stored inside access grants/tokens.
|
39
47
|
- [#1634] Code refactoring for custom token attributes.
|
40
48
|
- [#1639] Add grant type validation to avoid Internal Server Error for DELETE /oauth/authorize endpoint.
|
41
49
|
|
42
|
-
|
50
|
+
## 5.6.4
|
43
51
|
|
44
52
|
- [#1633] Apply ORM configuration in #to_prepare block to avoid autoloading errors.
|
45
53
|
|
46
|
-
|
54
|
+
## 5.6.3
|
47
55
|
|
48
56
|
- [#1622] Drop support for Rubies 2.5 and 2.6
|
49
57
|
- [#1605] Fix URI validation for Ruby 3.2+.
|
@@ -31,7 +31,7 @@ module Doorkeeper
|
|
31
31
|
private
|
32
32
|
|
33
33
|
def render_success
|
34
|
-
if skip_authorization? ||
|
34
|
+
if skip_authorization? || can_authorize_response?
|
35
35
|
redirect_or_render(authorize_response)
|
36
36
|
elsif Doorkeeper.configuration.api_only
|
37
37
|
render json: pre_auth
|
@@ -52,10 +52,16 @@ module Doorkeeper
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
+
def can_authorize_response?
|
56
|
+
Doorkeeper.config.custom_access_token_attributes.empty? && pre_auth.client.application.confidential? && matching_token?
|
57
|
+
end
|
58
|
+
|
55
59
|
# Active access token issued for the same client and resource owner with
|
56
60
|
# the same set of the scopes exists?
|
57
61
|
def matching_token?
|
58
|
-
|
62
|
+
# We don't match tokens on the custom attributes here - we're in the pre-auth here,
|
63
|
+
# so they haven't been supplied yet (there are no custom attributes to match on yet)
|
64
|
+
@matching_token ||= Doorkeeper.config.access_token_model.matching_token_for(
|
59
65
|
pre_auth.client,
|
60
66
|
current_resource_owner,
|
61
67
|
pre_auth.scopes,
|
@@ -77,7 +83,7 @@ module Doorkeeper
|
|
77
83
|
)
|
78
84
|
end
|
79
85
|
elsif pre_auth.form_post_response?
|
80
|
-
render :form_post
|
86
|
+
render :form_post, locals: { auth: auth }
|
81
87
|
else
|
82
88
|
redirect_to auth.redirect_uri, allow_other_host: true
|
83
89
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
</header>
|
4
4
|
|
5
5
|
<%= form_tag @pre_auth.redirect_uri, method: :post, name: :redirect_form, authenticity_token: false do %>
|
6
|
-
<%
|
6
|
+
<% auth.body.compact.each do |key, value| %>
|
7
7
|
<%= hidden_field_tag key, value %>
|
8
8
|
<% end %>
|
9
9
|
<% end %>
|
data/lib/doorkeeper/config.rb
CHANGED
@@ -106,6 +106,13 @@ module Doorkeeper
|
|
106
106
|
@config.instance_variable_set(:@revoke_previous_client_credentials_token, true)
|
107
107
|
end
|
108
108
|
|
109
|
+
# Only allow one valid access token obtained via authorization code
|
110
|
+
# per client. If a new access token is obtained before the old one
|
111
|
+
# expired, the old one gets revoked (disabled by default)
|
112
|
+
def revoke_previous_authorization_code_token
|
113
|
+
@config.instance_variable_set(:@revoke_previous_authorization_code_token, true)
|
114
|
+
end
|
115
|
+
|
109
116
|
# Use an API mode for applications generated with --api argument
|
110
117
|
# It will skip applications controller, disable forgery protection
|
111
118
|
def api_only
|
@@ -481,6 +488,10 @@ module Doorkeeper
|
|
481
488
|
option_set? :revoke_previous_client_credentials_token
|
482
489
|
end
|
483
490
|
|
491
|
+
def revoke_previous_authorization_code_token?
|
492
|
+
option_set? :revoke_previous_authorization_code_token
|
493
|
+
end
|
494
|
+
|
484
495
|
def enforce_configured_scopes?
|
485
496
|
option_set? :enforce_configured_scopes
|
486
497
|
end
|
@@ -83,14 +83,18 @@ module Doorkeeper
|
|
83
83
|
# Resource Owner model instance or it's ID
|
84
84
|
# @param scopes [String, Doorkeeper::OAuth::Scopes]
|
85
85
|
# set of scopes
|
86
|
+
# @param custom_attributes [Nilable Hash]
|
87
|
+
# A nil value, or hash with keys corresponding to the custom attributes
|
88
|
+
# configured with the `custom_access_token_attributes` config option.
|
89
|
+
# A nil value will ignore custom attributes.
|
86
90
|
#
|
87
91
|
# @return [Doorkeeper::AccessToken, nil] Access Token instance or
|
88
92
|
# nil if matching record was not found
|
89
93
|
#
|
90
|
-
def matching_token_for(application, resource_owner, scopes, include_expired: true)
|
94
|
+
def matching_token_for(application, resource_owner, scopes, custom_attributes: nil, include_expired: true)
|
91
95
|
tokens = authorized_tokens_for(application&.id, resource_owner)
|
92
96
|
tokens = tokens.not_expired unless include_expired
|
93
|
-
find_matching_token(tokens, application, scopes)
|
97
|
+
find_matching_token(tokens, application, custom_attributes, scopes)
|
94
98
|
end
|
95
99
|
|
96
100
|
# Interface to enumerate access token records in batches in order not
|
@@ -114,11 +118,15 @@ module Doorkeeper
|
|
114
118
|
# Application instance
|
115
119
|
# @param scopes [String, Doorkeeper::OAuth::Scopes]
|
116
120
|
# set of scopes
|
121
|
+
# @param custom_attributes [Nilable Hash]
|
122
|
+
# A nil value, or hash with keys corresponding to the custom attributes
|
123
|
+
# configured with the `custom_access_token_attributes` config option.
|
124
|
+
# A nil value will ignore custom attributes.
|
117
125
|
#
|
118
126
|
# @return [Doorkeeper::AccessToken, nil] Access Token instance or
|
119
127
|
# nil if matching record was not found
|
120
128
|
#
|
121
|
-
def find_matching_token(relation, application, scopes)
|
129
|
+
def find_matching_token(relation, application, custom_attributes, scopes)
|
122
130
|
return nil unless relation
|
123
131
|
|
124
132
|
matching_tokens = []
|
@@ -126,7 +134,8 @@ module Doorkeeper
|
|
126
134
|
|
127
135
|
find_access_token_in_batches(relation, batch_size: batch_size) do |batch|
|
128
136
|
tokens = batch.select do |token|
|
129
|
-
scopes_match?(token.scopes, scopes, application&.scopes)
|
137
|
+
scopes_match?(token.scopes, scopes, application&.scopes) &&
|
138
|
+
custom_attributes_match?(token, custom_attributes)
|
130
139
|
end
|
131
140
|
|
132
141
|
matching_tokens.concat(tokens)
|
@@ -160,6 +169,31 @@ module Doorkeeper
|
|
160
169
|
)
|
161
170
|
end
|
162
171
|
|
172
|
+
# Checks whether the token custom attribute values match the custom
|
173
|
+
# attributes from the parameters.
|
174
|
+
#
|
175
|
+
# @param token [Doorkeeper::AccessToken]
|
176
|
+
# The access token whose custom attributes are being compared
|
177
|
+
# to the custom_attributes.
|
178
|
+
#
|
179
|
+
# @param custom_attributes [Hash]
|
180
|
+
# A hash of the attributes for which we want to determine whether
|
181
|
+
# the token's custom attributes match.
|
182
|
+
#
|
183
|
+
# @return [Boolean] true if the token's custom attribute values
|
184
|
+
# match those in the custom_attributes, or if both are empty/blank.
|
185
|
+
# False otherwise.
|
186
|
+
def custom_attributes_match?(token, custom_attributes)
|
187
|
+
return true if custom_attributes.nil?
|
188
|
+
|
189
|
+
token_attribs = token.custom_attributes
|
190
|
+
return true if token_attribs.blank? && custom_attributes.blank?
|
191
|
+
|
192
|
+
Doorkeeper.config.custom_access_token_attributes.all? do |attribute|
|
193
|
+
token_attribs[attribute] == custom_attributes[attribute]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
163
197
|
# Looking for not expired AccessToken record with a matching set of
|
164
198
|
# scopes that belongs to specific Application and Resource Owner.
|
165
199
|
# If it doesn't exists - then creates it.
|
@@ -181,7 +215,9 @@ module Doorkeeper
|
|
181
215
|
#
|
182
216
|
def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
|
183
217
|
if Doorkeeper.config.reuse_access_token
|
184
|
-
|
218
|
+
custom_attributes = extract_custom_attributes(token_attributes).presence
|
219
|
+
access_token = matching_token_for(
|
220
|
+
application, resource_owner, scopes, custom_attributes: custom_attributes, include_expired: false)
|
185
221
|
|
186
222
|
return access_token if access_token&.reusable?
|
187
223
|
end
|
@@ -276,6 +312,18 @@ module Doorkeeper
|
|
276
312
|
def fallback_secret_strategy
|
277
313
|
::Doorkeeper.config.token_secret_fallback_strategy
|
278
314
|
end
|
315
|
+
|
316
|
+
# Extracts the token's custom attributes (defined by the
|
317
|
+
# custom_access_token_attributes config option) from the token's attributes.
|
318
|
+
#
|
319
|
+
# @param attributes [Hash]
|
320
|
+
# A hash of the access token's attributes.
|
321
|
+
# @return [Hash]
|
322
|
+
# A hash containing only the custom access token attributes.
|
323
|
+
def extract_custom_attributes(attributes)
|
324
|
+
attributes.with_indifferent_access.slice(
|
325
|
+
*Doorkeeper.configuration.custom_access_token_attributes)
|
326
|
+
end
|
279
327
|
end
|
280
328
|
|
281
329
|
# Access Token type: Bearer.
|
@@ -308,6 +356,14 @@ module Doorkeeper
|
|
308
356
|
end
|
309
357
|
end
|
310
358
|
|
359
|
+
# The token's custom attributes, as defined by
|
360
|
+
# the custom_access_token_attributes config option.
|
361
|
+
#
|
362
|
+
# @return [Hash] hash of custom access token attributes.
|
363
|
+
def custom_attributes
|
364
|
+
self.class.extract_custom_attributes(attributes)
|
365
|
+
end
|
366
|
+
|
311
367
|
# Indicates whether the token instance have the same credential
|
312
368
|
# as the other Access Token.
|
313
369
|
#
|
@@ -29,6 +29,10 @@ module Doorkeeper
|
|
29
29
|
grant.lock!
|
30
30
|
raise Errors::InvalidGrantReuse if grant.revoked?
|
31
31
|
|
32
|
+
if Doorkeeper.config.revoke_previous_authorization_code_token?
|
33
|
+
revoke_previous_tokens(grant.application, resource_owner)
|
34
|
+
end
|
35
|
+
|
32
36
|
grant.revoke
|
33
37
|
|
34
38
|
find_or_create_access_token(
|
@@ -109,6 +113,10 @@ module Doorkeeper
|
|
109
113
|
.slice(*Doorkeeper.config.custom_access_token_attributes)
|
110
114
|
.symbolize_keys
|
111
115
|
end
|
116
|
+
|
117
|
+
def revoke_previous_tokens(application, resource_owner)
|
118
|
+
Doorkeeper.config.access_token_model.revoke_all_for(application.id, resource_owner)
|
119
|
+
end
|
112
120
|
end
|
113
121
|
end
|
114
122
|
end
|
@@ -8,7 +8,7 @@ module Doorkeeper
|
|
8
8
|
existing_token = nil
|
9
9
|
|
10
10
|
if lookup_existing_token?
|
11
|
-
existing_token = find_active_existing_token_for(client, scopes)
|
11
|
+
existing_token = find_active_existing_token_for(client, scopes, attributes)
|
12
12
|
return existing_token if Doorkeeper.config.reuse_access_token && existing_token&.reusable?
|
13
13
|
end
|
14
14
|
|
@@ -44,8 +44,11 @@ module Doorkeeper
|
|
44
44
|
Doorkeeper.config.revoke_previous_client_credentials_token?
|
45
45
|
end
|
46
46
|
|
47
|
-
def find_active_existing_token_for(client, scopes)
|
48
|
-
Doorkeeper.config.access_token_model.
|
47
|
+
def find_active_existing_token_for(client, scopes, attributes)
|
48
|
+
custom_attributes = Doorkeeper.config.access_token_model.
|
49
|
+
extract_custom_attributes(attributes).presence
|
50
|
+
Doorkeeper.config.access_token_model.matching_token_for(
|
51
|
+
client, nil, scopes, custom_attributes: custom_attributes, include_expired: false)
|
49
52
|
end
|
50
53
|
end
|
51
54
|
end
|
@@ -31,7 +31,7 @@ module Doorkeeper
|
|
31
31
|
@code_challenge = parameters[:code_challenge]
|
32
32
|
@code_challenge_method = parameters[:code_challenge_method]
|
33
33
|
@resource_owner = resource_owner
|
34
|
-
@custom_access_token_attributes = parameters.slice(*Doorkeeper.config.custom_access_token_attributes)
|
34
|
+
@custom_access_token_attributes = parameters.slice(*Doorkeeper.config.custom_access_token_attributes).to_h
|
35
35
|
end
|
36
36
|
|
37
37
|
def authorizable?
|
@@ -5,12 +5,14 @@ module Doorkeeper
|
|
5
5
|
class TokenResponse
|
6
6
|
attr_reader :token
|
7
7
|
|
8
|
+
alias issued_token token
|
9
|
+
|
8
10
|
def initialize(token)
|
9
11
|
@token = token
|
10
12
|
end
|
11
13
|
|
12
14
|
def body
|
13
|
-
{
|
15
|
+
@body ||= {
|
14
16
|
"access_token" => token.plaintext_token,
|
15
17
|
"token_type" => token.token_type,
|
16
18
|
"expires_in" => token.expires_in_seconds,
|
data/lib/doorkeeper/version.rb
CHANGED
@@ -32,7 +32,7 @@ Doorkeeper.configure do
|
|
32
32
|
# You can use your own model classes if you need to extend (or even override) default
|
33
33
|
# Doorkeeper models such as `Application`, `AccessToken` and `AccessGrant.
|
34
34
|
#
|
35
|
-
#
|
35
|
+
# By default Doorkeeper ActiveRecord ORM uses its own classes:
|
36
36
|
#
|
37
37
|
# access_token_class "Doorkeeper::AccessToken"
|
38
38
|
# access_grant_class "Doorkeeper::AccessGrant"
|
@@ -91,7 +91,10 @@ Doorkeeper.configure do
|
|
91
91
|
# authorization_code_expires_in 10.minutes
|
92
92
|
|
93
93
|
# Access token expiration time (default: 2 hours).
|
94
|
-
# If you
|
94
|
+
# If you set this to `nil` Doorkeeper will not expire the token and omit expires_in in response.
|
95
|
+
# It is RECOMMENDED to set expiration time explicitly.
|
96
|
+
# Prefer access_token_expires_in 100.years or similar,
|
97
|
+
# which would be functionally equivalent and avoid the risk of unexpected behavior by callers.
|
95
98
|
#
|
96
99
|
# access_token_expires_in 2.hours
|
97
100
|
|
@@ -164,6 +167,12 @@ Doorkeeper.configure do
|
|
164
167
|
#
|
165
168
|
# revoke_previous_client_credentials_token
|
166
169
|
|
170
|
+
# Only allow one valid access token obtained via authorization code
|
171
|
+
# per client. If a new access token is obtained before the old one
|
172
|
+
# expired, the old one gets revoked (disabled by default)
|
173
|
+
#
|
174
|
+
# revoke_previous_authorization_code_token
|
175
|
+
|
167
176
|
# Hash access and refresh tokens before persisting them.
|
168
177
|
# This will disable the possibility to use +reuse_access_token+
|
169
178
|
# since plain values can no longer be retrieved.
|
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.7.0
|
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: 2024-
|
14
|
+
date: 2024-04-24 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: railties
|
@@ -346,7 +346,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
346
346
|
- !ruby/object:Gem::Version
|
347
347
|
version: '0'
|
348
348
|
requirements: []
|
349
|
-
rubygems_version: 3.
|
349
|
+
rubygems_version: 3.2.3
|
350
350
|
signing_key:
|
351
351
|
specification_version: 4
|
352
352
|
summary: OAuth 2 provider for Rails and Grape
|