doorkeeper 5.5.4 → 5.6.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -1
- data/README.md +4 -3
- data/app/controllers/doorkeeper/authorizations_controller.rb +3 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +8 -5
- data/app/views/doorkeeper/authorizations/new.html.erb +16 -16
- data/lib/doorkeeper/config/validations.rb +3 -3
- data/lib/doorkeeper/config.rb +62 -6
- data/lib/doorkeeper/engine.rb +6 -1
- data/lib/doorkeeper/helpers/controller.rb +1 -1
- data/lib/doorkeeper/models/access_token_mixin.rb +4 -5
- data/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +88 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +7 -1
- data/lib/doorkeeper/oauth/base_request.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +5 -4
- data/lib/doorkeeper/oauth/client_credentials/validator.rb +1 -2
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +21 -0
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +16 -1
- data/lib/doorkeeper/orm/active_record.rb +27 -30
- data/lib/doorkeeper/rails/routes.rb +6 -2
- data/lib/doorkeeper/rake/setup.rake +0 -5
- data/lib/doorkeeper/version.rb +2 -2
- data/lib/doorkeeper.rb +1 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +4 -3
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c22e5cf14aebfd8b75510d028c123f9a924d13bf08c2717f2d7ce6c8bc202a1
|
4
|
+
data.tar.gz: 5c625f6be3f5412c546a175c310577c737407690328e6696a773ab74dd1abe13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 127dd3e716bfde2c825ba1d6c4fee662a80a809063a8bd0d5480767fc472c41a6208742407f47656dae95cb7d41b1cb30a920b0270fd2c194a3267fc2c843626
|
7
|
+
data.tar.gz: e17e0349cefce41f7767f944fded43b71221b0df82042a9fb9c0dddb464308f3642fe2af7fc61bc1ec4ebb09cb3d2ea1d7a3040adc41130259e495cf3e129386
|
data/CHANGELOG.md
CHANGED
@@ -9,6 +9,36 @@ User-visible changes worth mentioning.
|
|
9
9
|
|
10
10
|
- [#ID] Add your PR description here.
|
11
11
|
|
12
|
+
## 5.6.2
|
13
|
+
|
14
|
+
- [#1604] Fix fetching of the application when custom application_class defined.
|
15
|
+
|
16
|
+
## 5.6.1
|
17
|
+
|
18
|
+
- [#1593] Add support for Trilogy ActiveRecord adapter.
|
19
|
+
- [#1597] Add optional support to use the url path for the native authorization code flow. Ports forward [#1143] from 4.4.3
|
20
|
+
- [#1599] Remove unnecessarily re-fetch of application object when creating an access token.
|
21
|
+
|
22
|
+
## 5.6.0
|
23
|
+
|
24
|
+
- [#1581] Consider `token_type_hint` when searching for access token in TokensController to avoid extra database calls.
|
25
|
+
|
26
|
+
## 5.6.0.rc1
|
27
|
+
|
28
|
+
- [#1558] Fixed bug: able to obtain a token with default scopes even if they are not present in the
|
29
|
+
application scopes when using client credentials.
|
30
|
+
- [#1567] Only filter `code` parameter if authorization_code grant flow is enabled.
|
31
|
+
|
32
|
+
## 5.6.0.rc1
|
33
|
+
|
34
|
+
- [#1551] Change lazy loading for ORM to be Ruby standard autoload.
|
35
|
+
- [#1552] Remove duplicate IDs on Auth form to improve accessibility.
|
36
|
+
- [#1542] Improve performance of `Doorkeeper::AccessToken#matching_token_for` using database specific SQL time math.
|
37
|
+
|
38
|
+
**[IMPORTANT]**: API of the `Doorkeeper::AccessToken#matching_token_for` method has changed and now it returns
|
39
|
+
only **active** access tokens (previously they were just not revoked). Please remember that the idea of the
|
40
|
+
`reuse_access_token` option is to check for existing _active_ token (see configuration option description).
|
41
|
+
|
12
42
|
## 5.5.4
|
13
43
|
|
14
44
|
- [#1535] Revert changes introduced in #1528 to allow query params in `redirect_uri` as per the spec.
|
@@ -25,7 +55,7 @@ User-visible changes worth mentioning.
|
|
25
55
|
- [#1502] Drop support for Ruby 2.4 because of EOL.
|
26
56
|
- [#1504] Updated the url fragment in the comment for code documentation.
|
27
57
|
- [#1512] Fix form behavior when response mode is form_post.
|
28
|
-
- [#1511] Fix that authorization code is returned by fragment if response_mode is
|
58
|
+
- [#1511] Fix that authorization code is returned by fragment if response_mode is fragment.
|
29
59
|
|
30
60
|
## 5.5.1
|
31
61
|
|
data/README.md
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
# Doorkeeper — awesome OAuth 2 provider for your Rails / Grape app.
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/doorkeeper.svg)](https://rubygems.org/gems/doorkeeper)
|
4
|
-
[![
|
4
|
+
[![CI](https://github.com/doorkeeper-gem/doorkeeper/actions/workflows/ci.yml/badge.svg)](https://github.com/doorkeeper-gem/doorkeeper/actions/workflows/ci.yml)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/doorkeeper-gem/doorkeeper.svg)](https://codeclimate.com/github/doorkeeper-gem/doorkeeper)
|
6
6
|
[![Coverage Status](https://coveralls.io/repos/github/doorkeeper-gem/doorkeeper/badge.svg?branch=main)](https://coveralls.io/github/doorkeeper-gem/doorkeeper?branch=main)
|
7
|
-
[![Security](https://hakiri.io/github/doorkeeper-gem/doorkeeper/main.svg)](https://hakiri.io/github/doorkeeper-gem/doorkeeper/main)
|
8
7
|
[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)
|
9
8
|
[![GuardRails badge](https://badges.guardrails.io/doorkeeper-gem/doorkeeper.svg?token=66768ce8f6995814df81f65a2cff40f739f688492704f973e62809e15599bb62)](https://dashboard.guardrails.io/default/gh/doorkeeper-gem/doorkeeper)
|
10
9
|
[![Dependabot](https://img.shields.io/badge/dependabot-enabled-success.svg)](https://dependabot.com)
|
@@ -106,6 +105,8 @@ Extensions that are not included by default and can be installed separately.
|
|
106
105
|
| JWT Token support | [doorkeeper-gem/doorkeeper-jwt](https://github.com/doorkeeper-gem/doorkeeper-jwt) |
|
107
106
|
| Assertion grant extension | [doorkeeper-gem/doorkeeper-grants\_assertion](https://github.com/doorkeeper-gem/doorkeeper-grants_assertion) |
|
108
107
|
| I18n translations | [doorkeeper-gem/doorkeeper-i18n](https://github.com/doorkeeper-gem/doorkeeper-i18n) |
|
108
|
+
| CIBA - Client Initiated Backchannel Authentication Flow extention | [doorkeeper-ciba](https://github.com/autoseg/doorkeeper-ciba) |
|
109
|
+
| Device Authorization Grant | [doorkeeper-device_authorization_grant](https://github.com/exop-group/doorkeeper-device_authorization_grant) |
|
109
110
|
|
110
111
|
## Example Applications
|
111
112
|
|
@@ -188,4 +189,4 @@ contributors](https://github.com/doorkeeper-gem/doorkeeper/graphs/contributors)!
|
|
188
189
|
|
189
190
|
## License
|
190
191
|
|
191
|
-
MIT License.
|
192
|
+
MIT License. Created in Applicake. Maintained by the community.
|
@@ -24,7 +24,7 @@ module Doorkeeper
|
|
24
24
|
|
25
25
|
def render_success
|
26
26
|
if skip_authorization? || matching_token?
|
27
|
-
redirect_or_render
|
27
|
+
redirect_or_render(authorize_response)
|
28
28
|
elsif Doorkeeper.configuration.api_only
|
29
29
|
render json: pre_auth
|
30
30
|
else
|
@@ -41,6 +41,8 @@ module Doorkeeper
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
# Active access token issued for the same client and resource owner with
|
45
|
+
# the same set of the scopes exists?
|
44
46
|
def matching_token?
|
45
47
|
Doorkeeper.config.access_token_model.matching_token_for(
|
46
48
|
pre_auth.client,
|
@@ -30,6 +30,7 @@ module Doorkeeper
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
# OAuth 2.0 Token Introspection - https://datatracker.ietf.org/doc/html/rfc7662
|
33
34
|
def introspect
|
34
35
|
introspection = OAuth::TokenIntrospection.new(server, token)
|
35
36
|
|
@@ -115,12 +116,14 @@ module Doorkeeper
|
|
115
116
|
token.revoke if token&.accessible?
|
116
117
|
end
|
117
118
|
|
118
|
-
# Doorkeeper does not use the token_type_hint logic described in the
|
119
|
-
# RFC 7009 due to the refresh token implementation that is a field in
|
120
|
-
# the access token model.
|
121
119
|
def token
|
122
|
-
@token ||=
|
123
|
-
|
120
|
+
@token ||=
|
121
|
+
if params[:token_type_hint] == "refresh_token"
|
122
|
+
Doorkeeper.config.access_token_model.by_refresh_token(params["token"])
|
123
|
+
else
|
124
|
+
Doorkeeper.config.access_token_model.by_token(params["token"]) ||
|
125
|
+
Doorkeeper.config.access_token_model.by_refresh_token(params["token"])
|
126
|
+
end
|
124
127
|
end
|
125
128
|
|
126
129
|
def strategy
|
@@ -21,25 +21,25 @@
|
|
21
21
|
|
22
22
|
<div class="actions">
|
23
23
|
<%= form_tag oauth_authorization_path, method: :post do %>
|
24
|
-
<%= hidden_field_tag :client_id, @pre_auth.client.uid %>
|
25
|
-
<%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri %>
|
26
|
-
<%= hidden_field_tag :state, @pre_auth.state %>
|
27
|
-
<%= hidden_field_tag :response_type, @pre_auth.response_type %>
|
28
|
-
<%= hidden_field_tag :response_mode, @pre_auth.response_mode %>
|
29
|
-
<%= hidden_field_tag :scope, @pre_auth.scope %>
|
30
|
-
<%= hidden_field_tag :code_challenge, @pre_auth.code_challenge %>
|
31
|
-
<%= hidden_field_tag :code_challenge_method, @pre_auth.code_challenge_method %>
|
24
|
+
<%= hidden_field_tag :client_id, @pre_auth.client.uid, id: nil %>
|
25
|
+
<%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri, id: nil %>
|
26
|
+
<%= hidden_field_tag :state, @pre_auth.state, id: nil %>
|
27
|
+
<%= hidden_field_tag :response_type, @pre_auth.response_type, id: nil %>
|
28
|
+
<%= hidden_field_tag :response_mode, @pre_auth.response_mode, id: nil %>
|
29
|
+
<%= hidden_field_tag :scope, @pre_auth.scope, id: nil %>
|
30
|
+
<%= hidden_field_tag :code_challenge, @pre_auth.code_challenge, id: nil %>
|
31
|
+
<%= hidden_field_tag :code_challenge_method, @pre_auth.code_challenge_method, id: nil %>
|
32
32
|
<%= submit_tag t('doorkeeper.authorizations.buttons.authorize'), class: "btn btn-success btn-lg btn-block" %>
|
33
33
|
<% end %>
|
34
34
|
<%= form_tag oauth_authorization_path, method: :delete do %>
|
35
|
-
<%= hidden_field_tag :client_id, @pre_auth.client.uid %>
|
36
|
-
<%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri %>
|
37
|
-
<%= hidden_field_tag :state, @pre_auth.state %>
|
38
|
-
<%= hidden_field_tag :response_type, @pre_auth.response_type %>
|
39
|
-
<%= hidden_field_tag :response_mode, @pre_auth.response_mode %>
|
40
|
-
<%= hidden_field_tag :scope, @pre_auth.scope %>
|
41
|
-
<%= hidden_field_tag :code_challenge, @pre_auth.code_challenge %>
|
42
|
-
<%= hidden_field_tag :code_challenge_method, @pre_auth.code_challenge_method %>
|
35
|
+
<%= hidden_field_tag :client_id, @pre_auth.client.uid, id: nil %>
|
36
|
+
<%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri, id: nil %>
|
37
|
+
<%= hidden_field_tag :state, @pre_auth.state, id: nil %>
|
38
|
+
<%= hidden_field_tag :response_type, @pre_auth.response_type, id: nil %>
|
39
|
+
<%= hidden_field_tag :response_mode, @pre_auth.response_mode, id: nil %>
|
40
|
+
<%= hidden_field_tag :scope, @pre_auth.scope, id: nil %>
|
41
|
+
<%= hidden_field_tag :code_challenge, @pre_auth.code_challenge, id: nil %>
|
42
|
+
<%= hidden_field_tag :code_challenge_method, @pre_auth.code_challenge_method, id: nil %>
|
43
43
|
<%= submit_tag t('doorkeeper.authorizations.buttons.deny'), class: "btn btn-danger btn-lg btn-block" %>
|
44
44
|
<% end %>
|
45
45
|
</div>
|
@@ -24,8 +24,8 @@ module Doorkeeper
|
|
24
24
|
return if !reuse_access_token || strategy.allows_restoring_secrets?
|
25
25
|
|
26
26
|
::Rails.logger.warn(
|
27
|
-
"You have configured both reuse_access_token " \
|
28
|
-
"AND
|
27
|
+
"[DOORKEEPER] You have configured both reuse_access_token " \
|
28
|
+
"AND '#{strategy}' strategy which cannot restore tokens. " \
|
29
29
|
"This combination is unsupported. reuse_access_token will be disabled",
|
30
30
|
)
|
31
31
|
@reuse_access_token = false
|
@@ -43,7 +43,7 @@ module Doorkeeper
|
|
43
43
|
(token_reuse_limit > 0 && token_reuse_limit <= 100)
|
44
44
|
|
45
45
|
::Rails.logger.warn(
|
46
|
-
"You have configured an invalid value for token_reuse_limit option. " \
|
46
|
+
"[DOORKEEPER] You have configured an invalid value for token_reuse_limit option. " \
|
47
47
|
"It will be set to default 100",
|
48
48
|
)
|
49
49
|
@token_reuse_limit = 100
|
data/lib/doorkeeper/config.rb
CHANGED
@@ -21,12 +21,10 @@ module Doorkeeper
|
|
21
21
|
class MissingConfigurationBuilderClass < StandardError; end
|
22
22
|
|
23
23
|
class << self
|
24
|
+
attr_reader :orm_adapter
|
25
|
+
|
24
26
|
def configure(&block)
|
25
27
|
@config = Config::Builder.new(&block).build
|
26
|
-
setup_orm_adapter
|
27
|
-
setup_orm_models
|
28
|
-
setup_application_owner if @config.enable_application_owner?
|
29
|
-
@config
|
30
28
|
end
|
31
29
|
|
32
30
|
# @return [Doorkeeper::Config] configuration instance
|
@@ -37,6 +35,18 @@ module Doorkeeper
|
|
37
35
|
|
38
36
|
alias config configuration
|
39
37
|
|
38
|
+
def setup
|
39
|
+
setup_orm_adapter
|
40
|
+
run_orm_hooks
|
41
|
+
config.clear_cache!
|
42
|
+
|
43
|
+
# Deprecated, will be removed soon
|
44
|
+
unless configuration.orm == :active_record
|
45
|
+
setup_orm_models
|
46
|
+
setup_application_owner
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
40
50
|
def setup_orm_adapter
|
41
51
|
@orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
|
42
52
|
rescue NameError => e
|
@@ -49,6 +59,18 @@ module Doorkeeper
|
|
49
59
|
ERROR_MSG
|
50
60
|
end
|
51
61
|
|
62
|
+
def run_orm_hooks
|
63
|
+
if @orm_adapter.respond_to?(:run_hooks)
|
64
|
+
@orm_adapter.run_hooks
|
65
|
+
else
|
66
|
+
::Kernel.warn <<~MSG.strip_heredoc
|
67
|
+
[DOORKEEPER] ORM "#{configuration.orm}" should move all it's setup logic under `#run_hooks` method for
|
68
|
+
the #{@orm_adapter.name}. Later versions of Doorkeeper will no longer support `setup_orm_models` and
|
69
|
+
`setup_application_owner` API.
|
70
|
+
MSG
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
52
74
|
def setup_orm_models
|
53
75
|
@orm_adapter.initialize_models!
|
54
76
|
end
|
@@ -137,6 +159,15 @@ module Doorkeeper
|
|
137
159
|
@config.instance_variable_set(:@reuse_access_token, true)
|
138
160
|
end
|
139
161
|
|
162
|
+
# Choose to use the url path for native autorization codes
|
163
|
+
# Enabling this flag sets the authorization code response route for
|
164
|
+
# native redirect uris to oauth/authorize/<code>. The default is
|
165
|
+
# oauth/authorize/native?code=<code>.
|
166
|
+
# Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1143
|
167
|
+
def use_url_path_for_native_authorization
|
168
|
+
@config.instance_variable_set(:@use_url_path_for_native_authorization, true)
|
169
|
+
end
|
170
|
+
|
140
171
|
# TODO: maybe make it more generic for other flows too?
|
141
172
|
# Only allow one valid access token obtained via client credentials
|
142
173
|
# per client. If a new access token is obtained before the old one
|
@@ -293,6 +324,7 @@ module Doorkeeper
|
|
293
324
|
option :skip_client_authentication_for_password_grant,
|
294
325
|
default: false
|
295
326
|
|
327
|
+
# TODO: remove the option
|
296
328
|
option :active_record_options,
|
297
329
|
default: {},
|
298
330
|
deprecated: { message: "Customize Doorkeeper models instead" }
|
@@ -364,11 +396,20 @@ module Doorkeeper
|
|
364
396
|
option :access_token_generator,
|
365
397
|
default: "Doorkeeper::OAuth::Helpers::UniqueToken"
|
366
398
|
|
399
|
+
# Use a custom class for generating the application secret.
|
400
|
+
# https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-application-secret-generator
|
401
|
+
#
|
402
|
+
# @param application_secret_generator [String]
|
403
|
+
# the name of the application secret generator class
|
404
|
+
#
|
405
|
+
option :application_secret_generator,
|
406
|
+
default: "Doorkeeper::OAuth::Helpers::UniqueToken"
|
407
|
+
|
367
408
|
# Default access token generator is a SecureRandom class from Ruby stdlib.
|
368
409
|
# This option defines which method will be used to generate a unique token value.
|
369
410
|
#
|
370
|
-
# @param
|
371
|
-
# the name of the access token generator
|
411
|
+
# @param default_generator_method [Symbol]
|
412
|
+
# the method name of the default access token generator
|
372
413
|
#
|
373
414
|
option :default_generator_method, default: :urlsafe_base64
|
374
415
|
|
@@ -441,6 +482,16 @@ module Doorkeeper
|
|
441
482
|
:token_secret_fallback_strategy,
|
442
483
|
:application_secret_fallback_strategy
|
443
484
|
|
485
|
+
def clear_cache!
|
486
|
+
%i[
|
487
|
+
application_model
|
488
|
+
access_token_model
|
489
|
+
access_grant_model
|
490
|
+
].each do |var|
|
491
|
+
remove_instance_variable("@#{var}") if instance_variable_defined?("@#{var}")
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
444
495
|
# Doorkeeper Access Token model class.
|
445
496
|
#
|
446
497
|
# @return [ActiveRecord::Base, Mongoid::Document, Sequel::Model]
|
@@ -581,6 +632,11 @@ module Doorkeeper
|
|
581
632
|
def deprecated_token_grant_types_resolver
|
582
633
|
@deprecated_token_grant_types ||= calculate_token_grant_types
|
583
634
|
end
|
635
|
+
|
636
|
+
def native_authorization_code_route
|
637
|
+
@use_url_path_for_native_authorization = false unless defined?(@use_url_path_for_native_authorization)
|
638
|
+
@use_url_path_for_native_authorization ? '/:code' : '/native'
|
639
|
+
end
|
584
640
|
|
585
641
|
# [NOTE]: deprecated and will be removed soon
|
586
642
|
def deprecated_authorization_flows
|
data/lib/doorkeeper/engine.rb
CHANGED
@@ -3,7 +3,8 @@
|
|
3
3
|
module Doorkeeper
|
4
4
|
class Engine < Rails::Engine
|
5
5
|
initializer "doorkeeper.params.filter" do |app|
|
6
|
-
parameters = %w[client_secret
|
6
|
+
parameters = %w[client_secret authentication_token access_token refresh_token]
|
7
|
+
parameters << "code" if Doorkeeper.config.grant_flows.include?("authorization_code")
|
7
8
|
app.config.filter_parameters << /^(#{Regexp.union(parameters)})$/
|
8
9
|
end
|
9
10
|
|
@@ -17,6 +18,10 @@ module Doorkeeper
|
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
21
|
+
config.to_prepare do
|
22
|
+
Doorkeeper.setup
|
23
|
+
end
|
24
|
+
|
20
25
|
if defined?(Sprockets) && Sprockets::VERSION.chr.to_i >= 4
|
21
26
|
initializer "doorkeeper.assets.precompile" do |app|
|
22
27
|
# Force users to use:
|
@@ -13,6 +13,7 @@ module Doorkeeper
|
|
13
13
|
include Models::SecretStorable
|
14
14
|
include Models::Scopes
|
15
15
|
include Models::ResourceOwnerable
|
16
|
+
include Models::ExpirationTimeSqlMath
|
16
17
|
|
17
18
|
module ClassMethods
|
18
19
|
# Returns an instance of the Doorkeeper::AccessToken with
|
@@ -87,7 +88,7 @@ module Doorkeeper
|
|
87
88
|
# nil if matching record was not found
|
88
89
|
#
|
89
90
|
def matching_token_for(application, resource_owner, scopes)
|
90
|
-
tokens = authorized_tokens_for(application&.id, resource_owner)
|
91
|
+
tokens = authorized_tokens_for(application&.id, resource_owner).not_expired
|
91
92
|
find_matching_token(tokens, application, scopes)
|
92
93
|
end
|
93
94
|
|
@@ -104,9 +105,7 @@ module Doorkeeper
|
|
104
105
|
#
|
105
106
|
# ActiveRecord 5.x - 6.x ignores custom ordering so we can't perform a
|
106
107
|
# database sort by created_at, so we need to load all the matching records,
|
107
|
-
# sort them and find latest one.
|
108
|
-
# query using Time math if possible, but we n eed to consider ORM and
|
109
|
-
# different databases support.
|
108
|
+
# sort them and find latest one.
|
110
109
|
#
|
111
110
|
# @param relation [ActiveRecord::Relation]
|
112
111
|
# Access tokens relation
|
@@ -213,7 +212,7 @@ module Doorkeeper
|
|
213
212
|
# @return [Doorkeeper::AccessToken] new access token
|
214
213
|
#
|
215
214
|
def create_for(application:, resource_owner:, scopes:, **token_attributes)
|
216
|
-
token_attributes[:
|
215
|
+
token_attributes[:application] = application
|
217
216
|
token_attributes[:scopes] = scopes.to_s
|
218
217
|
|
219
218
|
if Doorkeeper.config.polymorphic_resource_owner?
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module Models
|
5
|
+
module ExpirationTimeSqlMath
|
6
|
+
extend ::ActiveSupport::Concern
|
7
|
+
|
8
|
+
class ExpirationTimeSqlGenerator
|
9
|
+
attr_reader :model
|
10
|
+
|
11
|
+
delegate :table_name, to: :@model
|
12
|
+
|
13
|
+
def initialize(model)
|
14
|
+
@model = model
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate_sql
|
18
|
+
raise "`generate_sql` should be overridden for a #{self.class.name}!"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class MySqlExpirationTimeSqlGenerator < ExpirationTimeSqlGenerator
|
23
|
+
def generate_sql
|
24
|
+
Arel.sql("DATE_ADD(#{table_name}.created_at, INTERVAL #{table_name}.expires_in SECOND)")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class SqlLiteExpirationTimeSqlGenerator < ExpirationTimeSqlGenerator
|
29
|
+
def generate_sql
|
30
|
+
Arel.sql("DATETIME(#{table_name}.created_at, '+' || #{table_name}.expires_in || ' SECONDS')")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class SqlServerExpirationTimeSqlGenerator < ExpirationTimeSqlGenerator
|
35
|
+
def generate_sql
|
36
|
+
Arel.sql("DATEADD(second, #{table_name}.expires_in, #{table_name}.created_at) AT TIME ZONE 'UTC'")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class OracleExpirationTimeSqlGenerator < ExpirationTimeSqlGenerator
|
41
|
+
def generate_sql
|
42
|
+
Arel.sql("#{table_name}.created_at + INTERVAL to_char(#{table_name}.expires_in) second")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class PostgresExpirationTimeSqlGenerator < ExpirationTimeSqlGenerator
|
47
|
+
def generate_sql
|
48
|
+
Arel.sql("#{table_name}.created_at + #{table_name}.expires_in * INTERVAL '1 SECOND'")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
ADAPTERS_MAPPING = {
|
53
|
+
"sqlite" => SqlLiteExpirationTimeSqlGenerator,
|
54
|
+
"sqlite3" => SqlLiteExpirationTimeSqlGenerator,
|
55
|
+
"postgis" => PostgresExpirationTimeSqlGenerator,
|
56
|
+
"postgresql" => PostgresExpirationTimeSqlGenerator,
|
57
|
+
"mysql" => MySqlExpirationTimeSqlGenerator,
|
58
|
+
"mysql2" => MySqlExpirationTimeSqlGenerator,
|
59
|
+
"trilogy" => MySqlExpirationTimeSqlGenerator,
|
60
|
+
"sqlserver" => SqlServerExpirationTimeSqlGenerator,
|
61
|
+
"oracleenhanced" => OracleExpirationTimeSqlGenerator,
|
62
|
+
}.freeze
|
63
|
+
|
64
|
+
module ClassMethods
|
65
|
+
def supports_expiration_time_math?
|
66
|
+
ADAPTERS_MAPPING.key?(adapter_name.downcase) ||
|
67
|
+
respond_to?(:custom_expiration_time_sql)
|
68
|
+
end
|
69
|
+
|
70
|
+
def expiration_time_sql
|
71
|
+
if respond_to?(:custom_expiration_time_sql)
|
72
|
+
custom_expiration_time_sql
|
73
|
+
else
|
74
|
+
expiration_time_sql_expression
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def expiration_time_sql_expression
|
79
|
+
ADAPTERS_MAPPING.fetch(adapter_name.downcase).new(self).generate_sql
|
80
|
+
end
|
81
|
+
|
82
|
+
def adapter_name
|
83
|
+
ActiveRecord::Base.connection.adapter_name
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -60,7 +60,7 @@ module Doorkeeper
|
|
60
60
|
)
|
61
61
|
|
62
62
|
@token = Doorkeeper.config.access_token_model.find_or_create_for(
|
63
|
-
application:
|
63
|
+
application: application,
|
64
64
|
resource_owner: resource_owner,
|
65
65
|
scopes: pre_auth.scopes,
|
66
66
|
expires_in: self.class.access_token_expires_in(Doorkeeper.config, context),
|
@@ -68,6 +68,12 @@ module Doorkeeper
|
|
68
68
|
)
|
69
69
|
end
|
70
70
|
|
71
|
+
def application
|
72
|
+
return unless pre_auth.client
|
73
|
+
|
74
|
+
pre_auth.client.is_a?(Doorkeeper.config.application_model) ? pre_auth.client : pre_auth.client.application
|
75
|
+
end
|
76
|
+
|
71
77
|
def oob_redirect
|
72
78
|
{
|
73
79
|
controller: controller,
|
@@ -29,7 +29,7 @@ module Doorkeeper
|
|
29
29
|
def find_or_create_access_token(client, resource_owner, scopes, server)
|
30
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
|
-
application: client,
|
32
|
+
application: client.is_a?(server_config.application_model) ? client : client&.application,
|
33
33
|
resource_owner: resource_owner,
|
34
34
|
scopes: scopes,
|
35
35
|
expires_in: Authorization::Token.access_token_expires_in(server, context),
|
@@ -8,13 +8,14 @@ module Doorkeeper
|
|
8
8
|
existing_token = nil
|
9
9
|
|
10
10
|
if lookup_existing_token?
|
11
|
-
existing_token =
|
11
|
+
existing_token = find_active_existing_token_for(client, scopes)
|
12
12
|
return existing_token if server_config.reuse_access_token && existing_token&.reusable?
|
13
13
|
end
|
14
14
|
|
15
15
|
with_revocation(existing_token: existing_token) do
|
16
|
-
server_config.
|
17
|
-
|
16
|
+
application = client.is_a?(server_config.application_model) ? client : client&.application
|
17
|
+
server_config.access_token_model.create_for(
|
18
|
+
application: application,
|
18
19
|
resource_owner: nil,
|
19
20
|
scopes: scopes,
|
20
21
|
**attributes,
|
@@ -43,7 +44,7 @@ module Doorkeeper
|
|
43
44
|
server_config.revoke_previous_client_credentials_token?
|
44
45
|
end
|
45
46
|
|
46
|
-
def
|
47
|
+
def find_active_existing_token_for(client, scopes)
|
47
48
|
server_config.access_token_model.matching_token_for(client, nil, scopes)
|
48
49
|
end
|
49
50
|
|
@@ -35,13 +35,12 @@ module Doorkeeper
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def validate_scopes
|
38
|
-
return true if @request.scopes.blank?
|
39
|
-
|
40
38
|
application_scopes = if @client.present?
|
41
39
|
@client.application.scopes
|
42
40
|
else
|
43
41
|
""
|
44
42
|
end
|
43
|
+
return true if @request.scopes.blank? && application_scopes.blank?
|
45
44
|
|
46
45
|
ScopeChecker.valid?(
|
47
46
|
scope_str: @request.scopes.to_s,
|
@@ -48,6 +48,27 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
|
|
48
48
|
column_names.include?("previous_refresh_token")
|
49
49
|
end
|
50
50
|
|
51
|
+
# Returns non-expired and non-revoked access tokens
|
52
|
+
def not_expired
|
53
|
+
relation = where(revoked_at: nil)
|
54
|
+
|
55
|
+
if supports_expiration_time_math?
|
56
|
+
# have not reached the expiration time or it never expires
|
57
|
+
relation.where("#{expiration_time_sql} > ?", Time.now.utc).or(
|
58
|
+
relation.where(expires_in: nil)
|
59
|
+
)
|
60
|
+
else
|
61
|
+
::Kernel.warn <<~WARNING.squish
|
62
|
+
[DOORKEEPER] Doorkeeper doesn't support expiration time math for your database adapter (#{adapter_name}).
|
63
|
+
Please add a class method `custom_expiration_time_sql` for your AccessToken class/mixin to provide a custom
|
64
|
+
SQL expression to calculate access token expiration time. See lib/doorkeeper/orm/active_record/mixins/access_token.rb
|
65
|
+
for more details.
|
66
|
+
WARNING
|
67
|
+
|
68
|
+
relation
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
51
72
|
private
|
52
73
|
|
53
74
|
def compute_doorkeeper_table_name
|
@@ -10,6 +10,10 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
|
|
10
10
|
|
11
11
|
include ::Doorkeeper::ApplicationMixin
|
12
12
|
|
13
|
+
if Doorkeeper.config.enable_application_owner?
|
14
|
+
include ::Doorkeeper::Models::Ownership
|
15
|
+
end
|
16
|
+
|
13
17
|
has_many :access_grants,
|
14
18
|
foreign_key: :application_id,
|
15
19
|
dependent: :delete_all,
|
@@ -44,7 +48,7 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
|
|
44
48
|
# @return [String] new transformed secret value
|
45
49
|
#
|
46
50
|
def renew_secret
|
47
|
-
@raw_secret =
|
51
|
+
@raw_secret = secret_generator.generate
|
48
52
|
secret_strategy.store_secret(self, :secret, @raw_secret)
|
49
53
|
end
|
50
54
|
|
@@ -102,6 +106,17 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
|
|
102
106
|
|
103
107
|
private
|
104
108
|
|
109
|
+
def secret_generator
|
110
|
+
generator_name = Doorkeeper.config.application_secret_generator
|
111
|
+
generator = generator_name.constantize
|
112
|
+
|
113
|
+
return generator if generator.respond_to?(:generate)
|
114
|
+
|
115
|
+
raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
|
116
|
+
rescue NameError
|
117
|
+
raise Errors::TokenGeneratorNotFound, "#{generator_name} not found"
|
118
|
+
end
|
119
|
+
|
105
120
|
def generate_uid
|
106
121
|
self.uid = Doorkeeper::OAuth::Helpers::UniqueToken.generate if uid.blank?
|
107
122
|
end
|
@@ -1,45 +1,42 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/lazy_load_hooks"
|
4
|
-
|
5
3
|
module Doorkeeper
|
4
|
+
autoload :AccessGrant, "doorkeeper/orm/active_record/access_grant"
|
5
|
+
autoload :AccessToken, "doorkeeper/orm/active_record/access_token"
|
6
|
+
autoload :Application, "doorkeeper/orm/active_record/application"
|
7
|
+
autoload :RedirectUriValidator, "doorkeeper/orm/active_record/redirect_uri_validator"
|
8
|
+
|
9
|
+
module Models
|
10
|
+
autoload :Ownership, "doorkeeper/models/concerns/ownership"
|
11
|
+
end
|
12
|
+
|
13
|
+
# ActiveRecord ORM for Doorkeeper entity models.
|
14
|
+
# Consists of three main OAuth entities:
|
15
|
+
# * Access Token
|
16
|
+
# * Access Grant
|
17
|
+
# * Application (client)
|
18
|
+
#
|
19
|
+
# Do a lazy loading of all the required and configured stuff.
|
20
|
+
#
|
6
21
|
module Orm
|
7
|
-
# ActiveRecord ORM for Doorkeeper entity models.
|
8
|
-
# Consists of three main OAuth entities:
|
9
|
-
# * Access Token
|
10
|
-
# * Access Grant
|
11
|
-
# * Application (client)
|
12
|
-
#
|
13
|
-
# Do a lazy loading of all the required and configured stuff.
|
14
|
-
#
|
15
22
|
module ActiveRecord
|
16
|
-
|
17
|
-
lazy_load do
|
18
|
-
require "doorkeeper/orm/active_record/stale_records_cleaner"
|
19
|
-
require "doorkeeper/orm/active_record/access_grant"
|
20
|
-
require "doorkeeper/orm/active_record/access_token"
|
21
|
-
require "doorkeeper/orm/active_record/application"
|
23
|
+
autoload :StaleRecordsCleaner, "doorkeeper/orm/active_record/stale_records_cleaner"
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
end
|
25
|
+
module Mixins
|
26
|
+
autoload :AccessGrant, "doorkeeper/orm/active_record/mixins/access_grant"
|
27
|
+
autoload :AccessToken, "doorkeeper/orm/active_record/mixins/access_token"
|
28
|
+
autoload :Application, "doorkeeper/orm/active_record/mixins/application"
|
29
29
|
end
|
30
30
|
|
31
|
-
def self.
|
32
|
-
|
33
|
-
|
31
|
+
def self.run_hooks
|
32
|
+
# Deprecated, will be removed soon
|
33
|
+
return unless (options = Doorkeeper.config.active_record_options[:establish_connection])
|
34
34
|
|
35
|
-
|
35
|
+
Doorkeeper::Orm::ActiveRecord.models.each do |model|
|
36
|
+
model.establish_connection(options)
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
39
|
-
def self.lazy_load(&block)
|
40
|
-
ActiveSupport.on_load(:active_record, {}, &block)
|
41
|
-
end
|
42
|
-
|
43
40
|
def self.models
|
44
41
|
[
|
45
42
|
Doorkeeper.config.access_grant_model,
|
@@ -53,8 +53,8 @@ module Doorkeeper
|
|
53
53
|
as: mapping[:as],
|
54
54
|
controller: mapping[:controllers],
|
55
55
|
) do
|
56
|
-
routes.get
|
57
|
-
routes.get
|
56
|
+
routes.get native_authorization_code_route, action: :show, on: :member
|
57
|
+
routes.get '/', action: :new, on: :member
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
@@ -96,6 +96,10 @@ module Doorkeeper
|
|
96
96
|
only: %i[index destroy],
|
97
97
|
controller: mapping[:controllers]
|
98
98
|
end
|
99
|
+
|
100
|
+
def native_authorization_code_route
|
101
|
+
Doorkeeper.configuration.native_authorization_code_route
|
102
|
+
end
|
99
103
|
end
|
100
104
|
end
|
101
105
|
end
|
@@ -2,10 +2,5 @@
|
|
2
2
|
|
3
3
|
namespace :doorkeeper do
|
4
4
|
task setup: :environment do
|
5
|
-
# Dirty hack to manually initialize AR because of lazy auto-loading,
|
6
|
-
# in other case we'll see NameError: uninitialized constant Doorkeeper::AccessToken
|
7
|
-
if Doorkeeper.config.orm == :active_record && defined?(::ActiveRecord::Base)
|
8
|
-
Object.const_get("::ActiveRecord::Base")
|
9
|
-
end
|
10
5
|
end
|
11
6
|
end
|
data/lib/doorkeeper/version.rb
CHANGED
data/lib/doorkeeper.rb
CHANGED
@@ -88,6 +88,7 @@ module Doorkeeper
|
|
88
88
|
module Models
|
89
89
|
autoload :Accessible, "doorkeeper/models/concerns/accessible"
|
90
90
|
autoload :Expirable, "doorkeeper/models/concerns/expirable"
|
91
|
+
autoload :ExpirationTimeSqlMath, "doorkeeper/models/concerns/expiration_time_sql_math"
|
91
92
|
autoload :Orderable, "doorkeeper/models/concerns/orderable"
|
92
93
|
autoload :Scopes, "doorkeeper/models/concerns/scopes"
|
93
94
|
autoload :Reusable, "doorkeeper/models/concerns/reusable"
|
@@ -126,9 +126,10 @@ Doorkeeper.configure do
|
|
126
126
|
|
127
127
|
# Reuse access token for the same resource owner within an application (disabled by default).
|
128
128
|
#
|
129
|
-
# This option protects your application from creating new tokens before old valid one becomes
|
130
|
-
# expired so your database doesn't bloat. Keep in mind that when this option is
|
131
|
-
# doesn't
|
129
|
+
# This option protects your application from creating new tokens before old **valid** one becomes
|
130
|
+
# expired so your database doesn't bloat. Keep in mind that when this option is enabled Doorkeeper
|
131
|
+
# doesn't update existing token expiration time, it will create a new token instead if no active matching
|
132
|
+
# token found for the application, resources owner and/or set of scopes.
|
132
133
|
# Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383
|
133
134
|
#
|
134
135
|
# You can not enable this option together with +hash_token_secrets+.
|
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.6.2
|
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:
|
14
|
+
date: 2022-11-29 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: railties
|
@@ -56,7 +56,7 @@ dependencies:
|
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: '0'
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
|
-
name:
|
59
|
+
name: coveralls_reborn
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
61
61
|
requirements:
|
62
62
|
- - ">="
|
@@ -167,6 +167,20 @@ dependencies:
|
|
167
167
|
- - ">="
|
168
168
|
- !ruby/object:Gem::Version
|
169
169
|
version: '0'
|
170
|
+
- !ruby/object:Gem::Dependency
|
171
|
+
name: timecop
|
172
|
+
requirement: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
type: :development
|
178
|
+
prerelease: false
|
179
|
+
version_requirements: !ruby/object:Gem::Requirement
|
180
|
+
requirements:
|
181
|
+
- - ">="
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
version: '0'
|
170
184
|
description: Doorkeeper is an OAuth 2 provider for Rails and Grape.
|
171
185
|
email:
|
172
186
|
- bulaj.nikita@gmail.com
|
@@ -221,6 +235,7 @@ files:
|
|
221
235
|
- lib/doorkeeper/models/application_mixin.rb
|
222
236
|
- lib/doorkeeper/models/concerns/accessible.rb
|
223
237
|
- lib/doorkeeper/models/concerns/expirable.rb
|
238
|
+
- lib/doorkeeper/models/concerns/expiration_time_sql_math.rb
|
224
239
|
- lib/doorkeeper/models/concerns/orderable.rb
|
225
240
|
- lib/doorkeeper/models/concerns/ownership.rb
|
226
241
|
- lib/doorkeeper/models/concerns/resource_ownerable.rb
|
@@ -344,7 +359,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
344
359
|
- !ruby/object:Gem::Version
|
345
360
|
version: '0'
|
346
361
|
requirements: []
|
347
|
-
rubygems_version: 3.1.
|
362
|
+
rubygems_version: 3.1.4
|
348
363
|
signing_key:
|
349
364
|
specification_version: 4
|
350
365
|
summary: OAuth 2 provider for Rails and Grape
|