doorkeeper 5.9.0 → 5.9.1
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 +28 -1
- data/README.md +0 -1
- data/app/controllers/doorkeeper/authorizations_controller.rb +5 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +7 -9
- data/app/views/doorkeeper/applications/show.html.erb +5 -5
- data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/show.html.erb +1 -1
- data/config/locales/en.yml +11 -11
- data/lib/doorkeeper/config/validations.rb +2 -2
- data/lib/doorkeeper/config.rb +5 -5
- data/lib/doorkeeper/engine.rb +2 -4
- data/lib/doorkeeper/errors.rb +2 -2
- data/lib/doorkeeper/helpers/controller.rb +5 -3
- data/lib/doorkeeper/models/access_grant_mixin.rb +1 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +4 -2
- data/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +8 -0
- data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +0 -1
- data/lib/doorkeeper/oauth/authorization_code_request.rb +1 -0
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +4 -3
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -0
- data/lib/doorkeeper/oauth/error_response.rb +21 -1
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -7
- data/lib/doorkeeper/oauth/refresh_token_request.rb +7 -4
- data/lib/doorkeeper/oauth/scopes.rb +3 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +7 -3
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +2 -7
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
- data/lib/doorkeeper/orm/active_record.rb +9 -5
- data/lib/doorkeeper/rails/routes.rb +1 -1
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/doorkeeper.rb +10 -0
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dd9d528da47dec74a5bb12a6e9ce672279cebd0a52cc6a714347df6c17828dfd
|
|
4
|
+
data.tar.gz: 61e4dcc2434b3e1c0400e35bf80eef980b3adb81c2a33cbe74e9797fef3963b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8a3e115278bfb5540ccde8b7ecc4084138935a4a7c928011f38684908c4e5cd0dadbfb14a93bcb4ce39da91a8bcaf599970d39de6d7953752e7c77aa6c03c31e
|
|
7
|
+
data.tar.gz: b62a19e584648c28bd9d4a24e21d3501ac35c85c77de950050c8942bb82be4f821d241b41ebc8544b03c354f93f96e4588c051d1b4eafe77ce6b13c06941ab7c
|
data/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,34 @@ User-visible changes worth mentioning.
|
|
|
7
7
|
|
|
8
8
|
## main
|
|
9
9
|
|
|
10
|
-
Add
|
|
10
|
+
- Add here
|
|
11
|
+
|
|
12
|
+
## 5.9.1
|
|
13
|
+
|
|
14
|
+
- [#1781] Honor `handle_auth_errors :raise` in `AuthorizationsController#authorize_response`
|
|
15
|
+
- [#1795] Fix: detailed error 'insufficient_scope' in protected resources 403s
|
|
16
|
+
- [#1797] Fix `doorkeeper:db:cleanup` rake task failure on PostgreSQL
|
|
17
|
+
- [#1800] Set `@grant_type` in `ClientCredentialsRequest` and `RefreshTokenRequest` constructors so `request.grant_type` returns
|
|
18
|
+
the correct value in hooks like `before_successful_strategy_response`.
|
|
19
|
+
- [#1802] Fix `filter_parameters` not applied when `Doorkeeper.configure` is called inside to_prepare.
|
|
20
|
+
- [#1804] Use `ActiveSupport.on_load(:active_record)` in ORM hooks to prevent loading ActiveRecord models too early
|
|
21
|
+
- [#1806] Fix token revocation bypass for public clients (RFC 7009)
|
|
22
|
+
- [#1815] Expose `current_resource_owner` as a view helper in `Doorkeeper::ApplicationController`.
|
|
23
|
+
- [#1818] Fix token introspection returning `exp: 0` for non-expiring tokens.
|
|
24
|
+
- [#1784] Remove hardcoded colons from view templates, move punctuation to i18n translation strings.
|
|
25
|
+
|
|
26
|
+
**[IMPORTANT]**: if you have customized Doorkeeper views (`authorizations/new`, `authorizations/show`,
|
|
27
|
+
`applications/show`) or overridden the default `en.yml` translations, you may need to update them.
|
|
28
|
+
Colons are no longer hardcoded in the views — they are now part of the translation strings.
|
|
29
|
+
Update the [doorkeeper-i18n](https://github.com/doorkeeper-gem/doorkeeper-i18n) gem to get the
|
|
30
|
+
updated translations for all locales.
|
|
31
|
+
- [#1820] Remove dead wildcard presence check in `Scopes#dynamic_scope_match?` (internal cleanup, no behavior change).
|
|
32
|
+
- [#1822] Update Rubocop config, auto-corrections.
|
|
33
|
+
- [#1823] Update Rubocop config, part 2.
|
|
34
|
+
- [#1825] Update Rubocop config, part 3.
|
|
35
|
+
- [#1821] Fix noisy `Could not find command "no_previous_refresh_token_column?"` Thor output during the
|
|
36
|
+
`PreviousRefreshTokenGenerator` spec by stubbing the underlying DB column check instead of the generator's
|
|
37
|
+
private method (test-only change).
|
|
11
38
|
|
|
12
39
|
## 5.9.0
|
|
13
40
|
|
data/README.md
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
[](https://github.com/doorkeeper-gem/doorkeeper/actions/workflows/ci.yml)
|
|
5
5
|
[](https://qlty.sh/gh/doorkeeper-gem/projects/doorkeeper)
|
|
6
6
|
[](https://coveralls.io/github/doorkeeper-gem/doorkeeper?branch=main)
|
|
7
|
-
[](https://houndci.com)
|
|
8
7
|
[](https://dashboard.guardrails.io/gh/doorkeeper-gem/repos/21183)
|
|
9
8
|
[](https://dependabot.com)
|
|
10
9
|
|
|
@@ -131,7 +131,11 @@ module Doorkeeper
|
|
|
131
131
|
|
|
132
132
|
def authorize_response
|
|
133
133
|
@authorize_response ||= begin
|
|
134
|
-
|
|
134
|
+
unless pre_auth.authorizable?
|
|
135
|
+
response = pre_auth.error_response
|
|
136
|
+
response.raise_exception! if Doorkeeper.config.raise_on_errors?
|
|
137
|
+
return response
|
|
138
|
+
end
|
|
135
139
|
|
|
136
140
|
context = build_context(pre_auth: pre_auth)
|
|
137
141
|
before_successful_authorization(context)
|
|
@@ -87,24 +87,22 @@ module Doorkeeper
|
|
|
87
87
|
# credentials, in the case of a confidential client. The token being
|
|
88
88
|
# revoked must also belong to the requesting client.
|
|
89
89
|
#
|
|
90
|
-
# Once a
|
|
90
|
+
# Once a client is authenticated, it must be authorized to
|
|
91
91
|
# revoke the provided access or refresh token. This ensures one client
|
|
92
92
|
# cannot revoke another's tokens.
|
|
93
93
|
#
|
|
94
|
-
# Doorkeeper
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
# types, they set the application_id as null (since the claim cannot be
|
|
98
|
-
# verified).
|
|
94
|
+
# Doorkeeper checks token ownership for any token that has an
|
|
95
|
+
# application_id set. Tokens issued without a client (application_id
|
|
96
|
+
# is null) can be revoked without client authorization.
|
|
99
97
|
#
|
|
100
98
|
# https://datatracker.ietf.org/doc/html/rfc6749#section-2.1
|
|
101
99
|
# https://datatracker.ietf.org/doc/html/rfc7009
|
|
102
100
|
def authorized?
|
|
103
101
|
# Token belongs to specific client, so we need to check if
|
|
104
102
|
# authenticated client could access it.
|
|
105
|
-
if token.application_id?
|
|
106
|
-
# We authorize client by
|
|
107
|
-
server.client && server.client.
|
|
103
|
+
if token.application_id?
|
|
104
|
+
# We authorize client by comparing client and token application IDs
|
|
105
|
+
server.client && server.client.id == token.application_id
|
|
108
106
|
else
|
|
109
107
|
# Token was issued without client, authorization unnecessary
|
|
110
108
|
true
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
<div class="row">
|
|
6
6
|
<div class="col-md-8">
|
|
7
|
-
<h4><%= t('.application_id')
|
|
7
|
+
<h4><%= t('.application_id') %></h4>
|
|
8
8
|
<p><code class="bg-light" id="application_id"><%= @application.uid %></code></p>
|
|
9
9
|
|
|
10
|
-
<h4><%= t('.secret')
|
|
10
|
+
<h4><%= t('.secret') %></h4>
|
|
11
11
|
<p>
|
|
12
12
|
<code class="bg-light" id="secret">
|
|
13
13
|
<% secret = flash[:application_secret].presence || @application.plaintext_secret %>
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
</code>
|
|
20
20
|
</p>
|
|
21
21
|
|
|
22
|
-
<h4><%= t('.scopes')
|
|
22
|
+
<h4><%= t('.scopes') %></h4>
|
|
23
23
|
<p>
|
|
24
24
|
<code class="bg-light" id="scopes">
|
|
25
25
|
<% if @application.scopes.present? %>
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
</code>
|
|
31
31
|
</p>
|
|
32
32
|
|
|
33
|
-
<h4><%= t('.confidential')
|
|
33
|
+
<h4><%= t('.confidential') %></h4>
|
|
34
34
|
<p><code class="bg-light" id="confidential"><%= @application.confidential? %></code></p>
|
|
35
35
|
|
|
36
|
-
<h4><%= t('.callback_urls')
|
|
36
|
+
<h4><%= t('.callback_urls') %></h4>
|
|
37
37
|
|
|
38
38
|
<% if @application.redirect_uri.present? %>
|
|
39
39
|
<table>
|
data/config/locales/en.yml
CHANGED
|
@@ -16,7 +16,7 @@ en:
|
|
|
16
16
|
secured_uri: 'must be an HTTPS/SSL URI.'
|
|
17
17
|
forbidden_uri: 'is forbidden by the server.'
|
|
18
18
|
scopes:
|
|
19
|
-
not_match_configured: "doesn't match configured on the server."
|
|
19
|
+
not_match_configured: "doesn't match those configured on the server."
|
|
20
20
|
|
|
21
21
|
doorkeeper:
|
|
22
22
|
applications:
|
|
@@ -33,7 +33,7 @@ en:
|
|
|
33
33
|
help:
|
|
34
34
|
confidential: 'Application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential.'
|
|
35
35
|
redirect_uri: 'Use one line per URI'
|
|
36
|
-
blank_redirect_uri: "Leave it blank if you configured your provider to use Client Credentials, Resource Owner Password Credentials or any other grant type that doesn't require redirect URI."
|
|
36
|
+
blank_redirect_uri: "Leave it blank if you configured your provider to use Client Credentials, Resource Owner Password Credentials or any other grant type that doesn't require a redirect URI."
|
|
37
37
|
scopes: 'Separate scopes with spaces. Leave blank to use the default scopes.'
|
|
38
38
|
edit:
|
|
39
39
|
title: 'Edit application'
|
|
@@ -51,12 +51,12 @@ en:
|
|
|
51
51
|
title: 'New Application'
|
|
52
52
|
show:
|
|
53
53
|
title: 'Application: %{name}'
|
|
54
|
-
application_id: 'UID'
|
|
55
|
-
secret: 'Secret'
|
|
54
|
+
application_id: 'UID:'
|
|
55
|
+
secret: 'Secret:'
|
|
56
56
|
secret_hashed: 'Secret hashed'
|
|
57
|
-
scopes: 'Scopes'
|
|
58
|
-
confidential: 'Confidential'
|
|
59
|
-
callback_urls: 'Callback
|
|
57
|
+
scopes: 'Scopes:'
|
|
58
|
+
confidential: 'Confidential:'
|
|
59
|
+
callback_urls: 'Callback URLs:'
|
|
60
60
|
actions: 'Actions'
|
|
61
61
|
not_defined: 'Not defined'
|
|
62
62
|
|
|
@@ -69,9 +69,9 @@ en:
|
|
|
69
69
|
new:
|
|
70
70
|
title: 'Authorization required'
|
|
71
71
|
prompt: 'Authorize %{client_name} to use your account?'
|
|
72
|
-
able_to: 'This application will be able to'
|
|
72
|
+
able_to: 'This application will be able to:'
|
|
73
73
|
show:
|
|
74
|
-
title: 'Authorization code'
|
|
74
|
+
title: 'Authorization code:'
|
|
75
75
|
form_post:
|
|
76
76
|
title: 'Submit this form'
|
|
77
77
|
|
|
@@ -95,9 +95,9 @@ en:
|
|
|
95
95
|
invalid_request:
|
|
96
96
|
unknown: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
|
|
97
97
|
missing_param: 'Missing required parameter: %{value}.'
|
|
98
|
-
request_not_authorized: 'Request
|
|
98
|
+
request_not_authorized: 'Request needs to be authorized. Required parameter for authorizing the request is missing or invalid.'
|
|
99
99
|
invalid_code_challenge: 'Code challenge is required.'
|
|
100
|
-
invalid_redirect_uri: "The requested redirect
|
|
100
|
+
invalid_redirect_uri: "The requested redirect URI is malformed or doesn't match the client redirect URI."
|
|
101
101
|
unauthorized_client: 'The client is not authorized to perform this request using this method.'
|
|
102
102
|
access_denied: 'The resource owner or authorization server denied the request.'
|
|
103
103
|
invalid_scope: 'The requested scope is invalid, unknown, or malformed.'
|
|
@@ -51,14 +51,14 @@ module Doorkeeper
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def validate_pkce_code_challenge_methods
|
|
54
|
-
return if pkce_code_challenge_methods.all? {|method| method =~ /^plain$|^S256$/ }
|
|
54
|
+
return if pkce_code_challenge_methods.all? { |method| method =~ /^plain$|^S256$/ }
|
|
55
55
|
|
|
56
56
|
::Rails.logger.warn(
|
|
57
57
|
"[DOORKEEPER] You have configured an invalid value for pkce_code_challenge_methods option. " \
|
|
58
58
|
"It will be set to default ['plain', 'S256']",
|
|
59
59
|
)
|
|
60
60
|
|
|
61
|
-
@pkce_code_challenge_methods = [
|
|
61
|
+
@pkce_code_challenge_methods = ["plain", "S256"]
|
|
62
62
|
end
|
|
63
63
|
end
|
|
64
64
|
end
|
data/lib/doorkeeper/config.rb
CHANGED
|
@@ -38,7 +38,7 @@ module Doorkeeper
|
|
|
38
38
|
# @param opts [Hash] the options to configure dynamic scopes
|
|
39
39
|
def enable_dynamic_scopes(opts = {})
|
|
40
40
|
@config.instance_variable_set(:@enable_dynamic_scopes, true)
|
|
41
|
-
@config.instance_variable_set(:@dynamic_scopes_delimiter, opts[:delimiter] ||
|
|
41
|
+
@config.instance_variable_set(:@dynamic_scopes_delimiter, opts[:delimiter] || ":")
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
# Define default access token scopes for your provider
|
|
@@ -115,7 +115,7 @@ module Doorkeeper
|
|
|
115
115
|
@config.instance_variable_set(:@enable_multiple_database_roles, true)
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
-
# Choose to use the url path for native autorization codes
|
|
118
|
+
# Choose to use the url path for native autorization codes
|
|
119
119
|
# Enabling this flag sets the authorization code response route for
|
|
120
120
|
# native redirect uris to oauth/authorize/<code>. The default is
|
|
121
121
|
# oauth/authorize/native?code=<code>.
|
|
@@ -592,7 +592,7 @@ module Doorkeeper
|
|
|
592
592
|
|
|
593
593
|
def pkce_code_challenge_methods_supported
|
|
594
594
|
return [] unless access_grant_model.pkce_supported?
|
|
595
|
-
|
|
595
|
+
|
|
596
596
|
pkce_code_challenge_methods
|
|
597
597
|
end
|
|
598
598
|
|
|
@@ -633,10 +633,10 @@ module Doorkeeper
|
|
|
633
633
|
def deprecated_token_grant_types_resolver
|
|
634
634
|
@deprecated_token_grant_types ||= calculate_token_grant_types
|
|
635
635
|
end
|
|
636
|
-
|
|
636
|
+
|
|
637
637
|
def native_authorization_code_route
|
|
638
638
|
@use_url_path_for_native_authorization = false unless defined?(@use_url_path_for_native_authorization)
|
|
639
|
-
@use_url_path_for_native_authorization ?
|
|
639
|
+
@use_url_path_for_native_authorization ? "/:code" : "/native"
|
|
640
640
|
end
|
|
641
641
|
|
|
642
642
|
# [NOTE]: deprecated and will be removed soon
|
data/lib/doorkeeper/engine.rb
CHANGED
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
module Doorkeeper
|
|
4
4
|
class Engine < Rails::Engine
|
|
5
5
|
initializer "doorkeeper.params.filter", after: :load_config_initializers do |app|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
parameters << "code" if Doorkeeper.config.grant_flows.include?("authorization_code")
|
|
9
|
-
app.config.filter_parameters << /^(#{Regexp.union(parameters)})$/
|
|
6
|
+
app.config.to_prepare do
|
|
7
|
+
Doorkeeper.setup_filter_parameters
|
|
10
8
|
end
|
|
11
9
|
end
|
|
12
10
|
|
data/lib/doorkeeper/errors.rb
CHANGED
|
@@ -45,7 +45,7 @@ module Doorkeeper
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def self.name_for_response
|
|
48
|
-
|
|
48
|
+
name.demodulize.underscore.to_sym
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
@@ -54,7 +54,7 @@ module Doorkeeper
|
|
|
54
54
|
challenge_methods = Doorkeeper.config.pkce_code_challenge_methods_supported
|
|
55
55
|
{
|
|
56
56
|
challenge_methods: challenge_methods.join(", "),
|
|
57
|
-
count: challenge_methods.length
|
|
57
|
+
count: challenge_methods.length,
|
|
58
58
|
}
|
|
59
59
|
end
|
|
60
60
|
end
|
|
@@ -7,6 +7,10 @@ module Doorkeeper
|
|
|
7
7
|
# Rails controller helpers.
|
|
8
8
|
#
|
|
9
9
|
module Controller
|
|
10
|
+
def self.included(base)
|
|
11
|
+
base.helper_method :current_resource_owner if base.respond_to?(:helper_method)
|
|
12
|
+
end
|
|
13
|
+
|
|
10
14
|
private
|
|
11
15
|
|
|
12
16
|
# :doc:
|
|
@@ -18,9 +22,7 @@ module Doorkeeper
|
|
|
18
22
|
def current_resource_owner
|
|
19
23
|
return @current_resource_owner if defined?(@current_resource_owner)
|
|
20
24
|
|
|
21
|
-
@current_resource_owner ||=
|
|
22
|
-
instance_eval(&Doorkeeper.config.authenticate_resource_owner)
|
|
23
|
-
end
|
|
25
|
+
@current_resource_owner ||= instance_eval(&Doorkeeper.config.authenticate_resource_owner)
|
|
24
26
|
end
|
|
25
27
|
|
|
26
28
|
def resource_owner_from_credentials
|
|
@@ -222,7 +222,8 @@ module Doorkeeper
|
|
|
222
222
|
if Doorkeeper.config.reuse_access_token
|
|
223
223
|
custom_attributes = extract_custom_attributes(token_attributes).presence
|
|
224
224
|
access_token = matching_token_for(
|
|
225
|
-
application, resource_owner, scopes, custom_attributes: custom_attributes, include_expired: false
|
|
225
|
+
application, resource_owner, scopes, custom_attributes: custom_attributes, include_expired: false,
|
|
226
|
+
)
|
|
226
227
|
|
|
227
228
|
return access_token if access_token&.reusable?
|
|
228
229
|
end
|
|
@@ -329,7 +330,8 @@ module Doorkeeper
|
|
|
329
330
|
# A hash containing only the custom access token attributes.
|
|
330
331
|
def extract_custom_attributes(attributes)
|
|
331
332
|
attributes.with_indifferent_access.slice(
|
|
332
|
-
*Doorkeeper.configuration.custom_access_token_attributes
|
|
333
|
+
*Doorkeeper.configuration.custom_access_token_attributes,
|
|
334
|
+
)
|
|
333
335
|
end
|
|
334
336
|
end
|
|
335
337
|
|
|
@@ -5,6 +5,14 @@ module Doorkeeper
|
|
|
5
5
|
module ExpirationTimeSqlMath
|
|
6
6
|
extend ::ActiveSupport::Concern
|
|
7
7
|
|
|
8
|
+
WARNING_MESSAGE = <<~WARNING.squish
|
|
9
|
+
[DOORKEEPER] Doorkeeper doesn't support expiration time math for your database adapter.
|
|
10
|
+
Records with an individual expires_in value longer than the global TTL may be incorrectly processed.
|
|
11
|
+
Please add a class method `custom_expiration_time_sql` to your AccessToken/AccessGrant models/mixins to provide a custom
|
|
12
|
+
SQL expression to calculate access token expiration time. See lib/doorkeeper/orm/active_record/mixins/access_token.rb
|
|
13
|
+
for more details.
|
|
14
|
+
WARNING
|
|
15
|
+
|
|
8
16
|
class ExpirationTimeSqlGenerator
|
|
9
17
|
attr_reader :model
|
|
10
18
|
|
|
@@ -45,10 +45,11 @@ module Doorkeeper
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def find_active_existing_token_for(client, scopes, attributes)
|
|
48
|
-
custom_attributes = Doorkeeper.config.access_token_model
|
|
49
|
-
extract_custom_attributes(attributes).presence
|
|
48
|
+
custom_attributes = Doorkeeper.config.access_token_model
|
|
49
|
+
.extract_custom_attributes(attributes).presence
|
|
50
50
|
Doorkeeper.config.access_token_model.matching_token_for(
|
|
51
|
-
client, nil, scopes, custom_attributes: custom_attributes, include_expired: false
|
|
51
|
+
client, nil, scopes, custom_attributes: custom_attributes, include_expired: false,
|
|
52
|
+
)
|
|
52
53
|
end
|
|
53
54
|
end
|
|
54
55
|
end
|
|
@@ -88,13 +88,33 @@ module Doorkeeper
|
|
|
88
88
|
|
|
89
89
|
def exception_class
|
|
90
90
|
return @exception_class if @exception_class
|
|
91
|
+
|
|
91
92
|
raise NotImplementedError, "error response must define #exception_class"
|
|
92
93
|
end
|
|
93
94
|
|
|
94
95
|
private
|
|
95
96
|
|
|
96
97
|
def authenticate_info
|
|
97
|
-
%(Bearer realm="#{realm}", error="#{name}", error_description="#{description}")
|
|
98
|
+
%(Bearer realm="#{realm}", error="#{sanitize_error_values(name)}", error_description="#{sanitize_error_values(description)}")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# This method removes any characters that are invalid in error
|
|
102
|
+
# details per RFC6750.
|
|
103
|
+
#
|
|
104
|
+
# > Values for the "error" and "error_description" attributes
|
|
105
|
+
# > (specified in Appendixes A.7 and A.8 of [RFC6749]) MUST NOT
|
|
106
|
+
# > include characters outside the set %x20-21 (" " or "!") / %x23-5B /
|
|
107
|
+
# > %x5D-7E (ascii "#" to "~" without "\").
|
|
108
|
+
def sanitize_error_values(string)
|
|
109
|
+
string.to_s.each_char.map do |char|
|
|
110
|
+
if char.in?("\x20".encode("utf-8").."\x21".encode("utf-8")) ||
|
|
111
|
+
char.in?("\x23".encode("utf-8").."\x5B".encode("utf-8")) ||
|
|
112
|
+
char.in?("\x5D".encode("utf-8").."\x7E".encode("utf-8"))
|
|
113
|
+
char
|
|
114
|
+
else
|
|
115
|
+
"_"
|
|
116
|
+
end
|
|
117
|
+
end.join("")
|
|
98
118
|
end
|
|
99
119
|
end
|
|
100
120
|
end
|
|
@@ -8,7 +8,7 @@ module Doorkeeper
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def initialize(attributes = {})
|
|
11
|
-
super(attributes.merge(name: :
|
|
11
|
+
super(attributes.merge(name: :insufficient_scope, state: :forbidden))
|
|
12
12
|
@scopes = attributes[:scopes]
|
|
13
13
|
end
|
|
14
14
|
|
|
@@ -16,12 +16,6 @@ module Doorkeeper
|
|
|
16
16
|
:forbidden
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def headers
|
|
20
|
-
headers = super
|
|
21
|
-
headers.delete "WWW-Authenticate"
|
|
22
|
-
headers
|
|
23
|
-
end
|
|
24
|
-
|
|
25
19
|
def description
|
|
26
20
|
@description ||= I18n.t("doorkeeper.errors.messages.forbidden_token.missing_scope",
|
|
27
21
|
oauth_scopes: @scopes.map(&:to_s).join(" "),)
|
|
@@ -18,6 +18,7 @@ module Doorkeeper
|
|
|
18
18
|
@server = server
|
|
19
19
|
@refresh_token = refresh_token
|
|
20
20
|
@credentials = credentials
|
|
21
|
+
@grant_type = Doorkeeper::OAuth::REFRESH_TOKEN
|
|
21
22
|
@original_scopes = parameters[:scope] || parameters[:scopes]
|
|
22
23
|
@refresh_token_parameter = parameters[:refresh_token]
|
|
23
24
|
@client = load_client(credentials) if credentials
|
|
@@ -36,12 +37,14 @@ module Doorkeeper
|
|
|
36
37
|
# This allows multiple concurrent refresh requests to succeed during the
|
|
37
38
|
# transition period, after which the old refresh token will be revoked.
|
|
38
39
|
raise Errors::InvalidGrantReuse if refresh_token.revoked?
|
|
40
|
+
|
|
39
41
|
create_access_token
|
|
40
42
|
else
|
|
41
43
|
# Use locking when refresh tokens are revoked immediately
|
|
42
44
|
# to prevent race conditions where multiple tokens could be created
|
|
43
45
|
refresh_token.with_lock do
|
|
44
46
|
raise Errors::InvalidGrantReuse if refresh_token.revoked?
|
|
47
|
+
|
|
45
48
|
refresh_token.revoke
|
|
46
49
|
create_access_token
|
|
47
50
|
end
|
|
@@ -131,10 +134,10 @@ module Doorkeeper
|
|
|
131
134
|
|
|
132
135
|
def custom_token_attributes_with_data
|
|
133
136
|
refresh_token
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
.attributes
|
|
138
|
+
.with_indifferent_access
|
|
139
|
+
.slice(*Doorkeeper.config.custom_access_token_attributes)
|
|
140
|
+
.symbolize_keys
|
|
138
141
|
end
|
|
139
142
|
end
|
|
140
143
|
end
|
|
@@ -88,7 +88,7 @@ module Doorkeeper
|
|
|
88
88
|
#
|
|
89
89
|
# @param other The set of scopes to filter
|
|
90
90
|
def allowed(other)
|
|
91
|
-
filtered_scopes = other.select { |scope|
|
|
91
|
+
filtered_scopes = other.select { |scope| exists?(scope) }
|
|
92
92
|
self.class.from_array(filtered_scopes)
|
|
93
93
|
end
|
|
94
94
|
|
|
@@ -115,7 +115,8 @@ module Doorkeeper
|
|
|
115
115
|
return false if allowed_pattern[0] != request_pattern[0]
|
|
116
116
|
return false if allowed_pattern[1].blank?
|
|
117
117
|
return false if request_pattern[1].blank?
|
|
118
|
-
|
|
118
|
+
|
|
119
|
+
return true if allowed_pattern[1] == DYNAMIC_SCOPE_WILDCARD
|
|
119
120
|
|
|
120
121
|
allowed_pattern[1] == request_pattern[1]
|
|
121
122
|
end
|
|
@@ -102,14 +102,18 @@ module Doorkeeper
|
|
|
102
102
|
|
|
103
103
|
# 2.2. Introspection Response
|
|
104
104
|
def success_response
|
|
105
|
-
|
|
105
|
+
response = {
|
|
106
106
|
active: true,
|
|
107
107
|
scope: @token.scopes_string,
|
|
108
108
|
client_id: @token.try(:application).try(:uid),
|
|
109
109
|
token_type: @token.token_type,
|
|
110
|
-
exp: @token.expires_at.to_i,
|
|
111
110
|
iat: @token.created_at.to_i,
|
|
112
|
-
|
|
111
|
+
}
|
|
112
|
+
# `exp` is OPTIONAL per RFC 7662 §2.2; omit it for non-expiring tokens
|
|
113
|
+
# so clients don't interpret `0` as "expired at 1970-01-01".
|
|
114
|
+
response[:exp] = @token.expires_at.to_i if @token.expires_at
|
|
115
|
+
|
|
116
|
+
customize_response(response)
|
|
113
117
|
end
|
|
114
118
|
|
|
115
119
|
# If the introspection call is properly authorized but the token is not
|
|
@@ -73,15 +73,10 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
|
|
|
73
73
|
if supports_expiration_time_math?
|
|
74
74
|
# have not reached the expiration time or it never expires
|
|
75
75
|
relation.where("#{expiration_time_sql} > ?", Time.now.utc).or(
|
|
76
|
-
relation.where(expires_in: nil)
|
|
76
|
+
relation.where(expires_in: nil),
|
|
77
77
|
)
|
|
78
78
|
else
|
|
79
|
-
::Kernel.warn
|
|
80
|
-
[DOORKEEPER] Doorkeeper doesn't support expiration time math for your database adapter (#{adapter_name}).
|
|
81
|
-
Please add a class method `custom_expiration_time_sql` for your AccessToken class/mixin to provide a custom
|
|
82
|
-
SQL expression to calculate access token expiration time. See lib/doorkeeper/orm/active_record/mixins/access_token.rb
|
|
83
|
-
for more details.
|
|
84
|
-
WARNING
|
|
79
|
+
::Kernel.warn(::Doorkeeper::Models::ExpirationTimeSqlMath::WARNING_MESSAGE)
|
|
85
80
|
|
|
86
81
|
relation
|
|
87
82
|
end
|
|
@@ -24,12 +24,19 @@ module Doorkeeper
|
|
|
24
24
|
# Clears expired records
|
|
25
25
|
def clean_expired(ttl)
|
|
26
26
|
table = @base_scope.arel_table
|
|
27
|
+
model_class = @base_scope.is_a?(::ActiveRecord::Relation) ? @base_scope.klass : @base_scope
|
|
27
28
|
|
|
28
|
-
@base_scope
|
|
29
|
+
scope = @base_scope
|
|
29
30
|
.where.not(expires_in: nil)
|
|
30
31
|
.where(table[:created_at].lt(Time.current - ttl))
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
|
|
33
|
+
if model_class.respond_to?(:supports_expiration_time_math?) && model_class.supports_expiration_time_math?
|
|
34
|
+
scope = scope.where("#{model_class.expiration_time_sql} < ?", Time.current)
|
|
35
|
+
else
|
|
36
|
+
::Kernel.warn(::Doorkeeper::Models::ExpirationTimeSqlMath::WARNING_MESSAGE)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
scope.in_batches(&:delete_all)
|
|
33
40
|
end
|
|
34
41
|
end
|
|
35
42
|
end
|
|
@@ -33,12 +33,16 @@ module Doorkeeper
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def self.initialize_configured_associations
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
# NOTE: on_load block is instance_exec'd on ActiveRecord::Base,
|
|
37
|
+
# so use fully qualified references (e.g. Doorkeeper.config).
|
|
38
|
+
ActiveSupport.on_load(:active_record) do
|
|
39
|
+
if Doorkeeper.config.enable_application_owner?
|
|
40
|
+
Doorkeeper.config.application_model.include ::Doorkeeper::Models::Ownership
|
|
41
|
+
end
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
Doorkeeper.config.access_grant_model.include ::Doorkeeper::Models::PolymorphicResourceOwner::ForAccessGrant
|
|
44
|
+
Doorkeeper.config.access_token_model.include ::Doorkeeper::Models::PolymorphicResourceOwner::ForAccessToken
|
|
45
|
+
end
|
|
42
46
|
end
|
|
43
47
|
end
|
|
44
48
|
end
|
data/lib/doorkeeper/version.rb
CHANGED
data/lib/doorkeeper.rb
CHANGED
|
@@ -154,6 +154,16 @@ module Doorkeeper
|
|
|
154
154
|
end
|
|
155
155
|
end
|
|
156
156
|
|
|
157
|
+
def setup_filter_parameters
|
|
158
|
+
return unless defined?(::Rails) && ::Rails.application && configured?
|
|
159
|
+
|
|
160
|
+
parameters = %w[client_secret authentication_token access_token refresh_token]
|
|
161
|
+
parameters << "code" if configuration.grant_flows.include?("authorization_code")
|
|
162
|
+
filter = /^(#{Regexp.union(parameters)})$/
|
|
163
|
+
filter_params = ::Rails.application.config.filter_parameters
|
|
164
|
+
filter_params << filter unless filter_params.include?(filter)
|
|
165
|
+
end
|
|
166
|
+
|
|
157
167
|
def setup_orm_adapter
|
|
158
168
|
@orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
|
|
159
169
|
rescue NameError => e
|
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: 5.9.
|
|
4
|
+
version: 5.9.1
|
|
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
|
|
@@ -330,7 +329,6 @@ metadata:
|
|
|
330
329
|
bug_tracker_uri: https://github.com/doorkeeper-gem/doorkeeper/issues
|
|
331
330
|
documentation_uri: https://doorkeeper.gitbook.io/guides/
|
|
332
331
|
funding_uri: https://opencollective.com/doorkeeper-gem
|
|
333
|
-
post_install_message:
|
|
334
332
|
rdoc_options: []
|
|
335
333
|
require_paths:
|
|
336
334
|
- lib
|
|
@@ -345,8 +343,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
345
343
|
- !ruby/object:Gem::Version
|
|
346
344
|
version: '0'
|
|
347
345
|
requirements: []
|
|
348
|
-
rubygems_version:
|
|
349
|
-
signing_key:
|
|
346
|
+
rubygems_version: 4.0.11
|
|
350
347
|
specification_version: 4
|
|
351
348
|
summary: OAuth 2 provider for Rails and Grape
|
|
352
349
|
test_files: []
|