doorkeeper 5.3.0 → 5.4.0.rc1
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/Appraisals +0 -14
- data/CHANGELOG.md +44 -1
- data/Dangerfile +7 -7
- data/Dockerfile +2 -2
- data/Gemfile +9 -9
- data/README.md +6 -4
- data/app/controllers/doorkeeper/applications_controller.rb +4 -4
- data/app/controllers/doorkeeper/authorizations_controller.rb +31 -12
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +2 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +57 -20
- data/app/views/doorkeeper/applications/show.html.erb +19 -2
- data/bin/console +14 -0
- data/config/locales/en.yml +3 -1
- data/doorkeeper.gemspec +1 -1
- data/gemfiles/rails_5_0.gemfile +8 -7
- data/gemfiles/rails_5_1.gemfile +8 -7
- data/gemfiles/rails_5_2.gemfile +8 -7
- data/gemfiles/rails_6_0.gemfile +8 -7
- data/gemfiles/rails_master.gemfile +8 -7
- data/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/lib/doorkeeper/config/option.rb +28 -14
- data/lib/doorkeeper/config.rb +41 -17
- data/lib/doorkeeper/grape/helpers.rb +1 -1
- data/lib/doorkeeper/models/access_grant_mixin.rb +9 -11
- data/lib/doorkeeper/models/access_token_mixin.rb +102 -42
- data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
- data/lib/doorkeeper/oauth/authorization/code.rb +14 -5
- data/lib/doorkeeper/oauth/authorization/context.rb +2 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +7 -11
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
- data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -8
- data/lib/doorkeeper/oauth/base_request.rb +11 -19
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +25 -7
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
- data/lib/doorkeeper/oauth/client_credentials/validator.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
- data/lib/doorkeeper/oauth/code_request.rb +1 -1
- data/lib/doorkeeper/oauth/code_response.rb +6 -2
- data/lib/doorkeeper/oauth/error_response.rb +2 -4
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -5
- data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -2
- data/lib/doorkeeper/oauth/password_access_token_request.rb +3 -5
- data/lib/doorkeeper/oauth/pre_authorization.rb +32 -27
- data/lib/doorkeeper/oauth/refresh_token_request.rb +18 -22
- data/lib/doorkeeper/oauth/token.rb +1 -1
- data/lib/doorkeeper/oauth/token_introspection.rb +3 -3
- data/lib/doorkeeper/oauth/token_request.rb +2 -2
- data/lib/doorkeeper/oauth/token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +7 -2
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +6 -2
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +6 -2
- data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
- data/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/lib/doorkeeper/rails/routes.rb +13 -17
- data/lib/doorkeeper/request/strategy.rb +2 -2
- data/lib/doorkeeper/server.rb +3 -3
- data/lib/doorkeeper/version.rb +2 -2
- data/lib/doorkeeper.rb +106 -79
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +1 -1
- data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +47 -3
- data/lib/generators/doorkeeper/templates/migration.rb.erb +2 -0
- data/spec/controllers/applications_controller_spec.rb +2 -2
- data/spec/controllers/authorizations_controller_spec.rb +165 -30
- data/spec/controllers/tokens_controller_spec.rb +6 -5
- data/spec/dummy/app/helpers/application_helper.rb +1 -1
- data/spec/dummy/app/models/user.rb +5 -1
- data/spec/dummy/config/application.rb +6 -4
- data/spec/dummy/config/boot.rb +4 -4
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/routes.rb +4 -4
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +2 -2
- data/spec/dummy/db/schema.rb +3 -1
- data/spec/factories.rb +1 -1
- data/spec/generators/enable_polymorphic_resource_owner_generator_spec.rb +47 -0
- data/spec/lib/config_spec.rb +30 -11
- data/spec/lib/models/revocable_spec.rb +2 -3
- data/spec/lib/models/scopes_spec.rb +8 -0
- data/spec/lib/oauth/authorization_code_request_spec.rb +25 -15
- data/spec/lib/oauth/base_request_spec.rb +6 -20
- data/spec/lib/oauth/client_credentials/creator_spec.rb +90 -89
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +84 -86
- data/spec/lib/oauth/client_credentials/validation_spec.rb +38 -40
- data/spec/lib/oauth/client_credentials_request_spec.rb +5 -4
- data/spec/lib/oauth/code_request_spec.rb +1 -1
- data/spec/lib/oauth/code_response_spec.rb +5 -1
- data/spec/lib/oauth/error_response_spec.rb +1 -1
- data/spec/lib/oauth/password_access_token_request_spec.rb +24 -13
- data/spec/lib/oauth/pre_authorization_spec.rb +13 -18
- data/spec/lib/oauth/refresh_token_request_spec.rb +19 -30
- data/spec/lib/oauth/token_request_spec.rb +14 -7
- data/spec/lib/option_spec.rb +51 -0
- data/spec/lib/stale_records_cleaner_spec.rb +18 -5
- data/spec/models/doorkeeper/access_grant_spec.rb +18 -4
- data/spec/models/doorkeeper/access_token_spec.rb +507 -479
- data/spec/models/doorkeeper/application_spec.rb +338 -300
- data/spec/requests/endpoints/token_spec.rb +5 -1
- data/spec/requests/flows/authorization_code_errors_spec.rb +4 -1
- data/spec/requests/flows/authorization_code_spec.rb +6 -1
- data/spec/requests/flows/client_credentials_spec.rb +41 -0
- data/spec/requests/flows/refresh_token_spec.rb +16 -8
- data/spec/requests/flows/revoke_token_spec.rb +143 -104
- data/spec/support/helpers/access_token_request_helper.rb +1 -0
- data/spec/support/helpers/authorization_request_helper.rb +4 -4
- data/spec/support/helpers/config_helper.rb +1 -1
- data/spec/support/shared/controllers_shared_context.rb +2 -2
- data/spec/support/shared/models_shared_examples.rb +6 -4
- metadata +15 -4
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
5
|
gem "rails", git: "https://github.com/rails/rails"
|
|
6
|
-
gem "rspec-core"
|
|
7
|
-
gem "rspec-expectations"
|
|
8
|
-
gem "rspec-mocks"
|
|
9
|
-
gem "rspec-rails", "4.0
|
|
10
|
-
gem "rspec-support"
|
|
11
|
-
gem "rubocop", "~> 0.
|
|
12
|
-
gem "rubocop-performance"
|
|
6
|
+
gem "rspec-core"
|
|
7
|
+
gem "rspec-expectations"
|
|
8
|
+
gem "rspec-mocks"
|
|
9
|
+
gem "rspec-rails", "~> 4.0"
|
|
10
|
+
gem "rspec-support"
|
|
11
|
+
gem "rubocop", "~> 0.80"
|
|
12
|
+
gem "rubocop-performance", require: false
|
|
13
|
+
gem "rubocop-rails", require: false
|
|
13
14
|
gem "bcrypt", "~> 3.1", require: false
|
|
14
15
|
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
|
|
15
16
|
gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
class Config
|
|
5
|
+
# Abstract base class for Doorkeeper and it's extensions configuration
|
|
6
|
+
# builder. Instantiates and validates gem configuration.
|
|
7
|
+
#
|
|
8
|
+
class AbstractBuilder
|
|
9
|
+
attr_reader :config
|
|
10
|
+
|
|
11
|
+
# @param [Class] config class
|
|
12
|
+
#
|
|
13
|
+
def initialize(config = Config.new, &block)
|
|
14
|
+
@config = config
|
|
15
|
+
instance_eval(&block)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Builds and validates configuration.
|
|
19
|
+
#
|
|
20
|
+
# @return [Doorkeeper::Config] config instance
|
|
21
|
+
#
|
|
22
|
+
def build
|
|
23
|
+
@config.validate if @config.respond_to?(:validate)
|
|
24
|
+
@config
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -36,22 +36,29 @@ module Doorkeeper
|
|
|
36
36
|
attribute = options[:as] || name
|
|
37
37
|
attribute_builder = options[:builder_class]
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
end
|
|
45
|
-
else
|
|
46
|
-
define_method name do |*args, &block|
|
|
47
|
-
value = if attribute_builder
|
|
48
|
-
attribute_builder.new(&block).build
|
|
49
|
-
else
|
|
50
|
-
block || args.first
|
|
51
|
-
end
|
|
39
|
+
builder_class.instance_eval do
|
|
40
|
+
if method_defined?(name)
|
|
41
|
+
Kernel.warn "[DOORKEEPER] Option #{name} already defined and will be overridden"
|
|
42
|
+
remove_method name
|
|
43
|
+
end
|
|
52
44
|
|
|
53
|
-
|
|
45
|
+
define_method name do |*args, &block|
|
|
46
|
+
if (deprecation_opts = options[:deprecated])
|
|
47
|
+
warning = "[DOORKEEPER] #{name} has been deprecated and will soon be removed"
|
|
48
|
+
if deprecation_opts.is_a?(Hash)
|
|
49
|
+
warning = "#{warning}\n#{deprecation_opts.fetch(:message)}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
Kernel.warn(warning)
|
|
54
53
|
end
|
|
54
|
+
|
|
55
|
+
value = if attribute_builder
|
|
56
|
+
attribute_builder.new(&block).build
|
|
57
|
+
else
|
|
58
|
+
block || args.first
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
@config.instance_variable_set(:"@#{attribute}", value)
|
|
55
62
|
end
|
|
56
63
|
end
|
|
57
64
|
|
|
@@ -65,6 +72,13 @@ module Doorkeeper
|
|
|
65
72
|
|
|
66
73
|
public attribute
|
|
67
74
|
end
|
|
75
|
+
|
|
76
|
+
def self.extended(base)
|
|
77
|
+
return if base.respond_to?(:builder_class)
|
|
78
|
+
|
|
79
|
+
raise Doorkeeper::MissingConfigurationBuilderClass, "Define `self.builder_class` method " \
|
|
80
|
+
"for #{base} that returns your custom Builder class to use options DSL!"
|
|
81
|
+
end
|
|
68
82
|
end
|
|
69
83
|
end
|
|
70
84
|
end
|
data/lib/doorkeeper/config.rb
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "doorkeeper/config/option"
|
|
4
|
+
require "doorkeeper/config/abstract_builder"
|
|
4
5
|
|
|
5
6
|
module Doorkeeper
|
|
7
|
+
# Defines a MissingConfiguration error for a missing Doorkeeper configuration
|
|
8
|
+
#
|
|
6
9
|
class MissingConfiguration < StandardError
|
|
7
|
-
# Defines a MissingConfiguration error for a missing Doorkeeper
|
|
8
|
-
# configuration
|
|
9
10
|
def initialize
|
|
10
11
|
super("Configuration for doorkeeper missing. Do you have doorkeeper initializer?")
|
|
11
12
|
end
|
|
12
13
|
end
|
|
13
14
|
|
|
15
|
+
# Doorkeeper option DSL could be reused in extensions to build their own
|
|
16
|
+
# configurations. To use the Option DSL gems need to define `builder_class` method
|
|
17
|
+
# that returns configuration Builder class. This exception raises when they don't
|
|
18
|
+
# define it.
|
|
19
|
+
#
|
|
20
|
+
class MissingConfigurationBuilderClass < StandardError; end
|
|
21
|
+
|
|
14
22
|
class << self
|
|
15
23
|
def configure(&block)
|
|
16
24
|
@config = Config::Builder.new(&block).build
|
|
@@ -30,7 +38,7 @@ module Doorkeeper
|
|
|
30
38
|
@orm_adapter = "doorkeeper/orm/#{configuration.orm}".classify.constantize
|
|
31
39
|
rescue NameError => e
|
|
32
40
|
raise e, "ORM adapter not found (#{configuration.orm})", <<-ERROR_MSG.strip_heredoc
|
|
33
|
-
[
|
|
41
|
+
[DOORKEEPER] ORM adapter not found (#{configuration.orm}), or there was an error
|
|
34
42
|
trying to load it.
|
|
35
43
|
|
|
36
44
|
You probably need to add the related gem for this adapter to work with
|
|
@@ -48,17 +56,8 @@ module Doorkeeper
|
|
|
48
56
|
end
|
|
49
57
|
|
|
50
58
|
class Config
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@config = Config.new
|
|
54
|
-
instance_eval(&block)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def build
|
|
58
|
-
@config.validate
|
|
59
|
-
@config
|
|
60
|
-
end
|
|
61
|
-
|
|
59
|
+
# Default Doorkeeper configuration builder
|
|
60
|
+
class Builder < AbstractBuilder
|
|
62
61
|
# Provide support for an owner to be assigned to each registered
|
|
63
62
|
# application (disabled by default)
|
|
64
63
|
# Optional parameter confirmation: true (default false) if you want
|
|
@@ -158,6 +157,12 @@ module Doorkeeper
|
|
|
158
157
|
@config.instance_variable_set(:@api_only, true)
|
|
159
158
|
end
|
|
160
159
|
|
|
160
|
+
# Enables polymorphic Resource Owner association for Access Grant and
|
|
161
|
+
# Access Token models. Requires additional database columns to be setup.
|
|
162
|
+
def use_polymorphic_resource_owner
|
|
163
|
+
@config.instance_variable_set(:@polymorphic_resource_owner, true)
|
|
164
|
+
end
|
|
165
|
+
|
|
161
166
|
# Forbids creating/updating applications with arbitrary scopes that are
|
|
162
167
|
# not in configuration, i.e. `default_scopes` or `optional_scopes`.
|
|
163
168
|
# (disabled by default)
|
|
@@ -219,6 +224,9 @@ module Doorkeeper
|
|
|
219
224
|
end
|
|
220
225
|
end
|
|
221
226
|
|
|
227
|
+
# Replace with `default: Builder` when we drop support of Rails < 5.2
|
|
228
|
+
mattr_reader(:builder_class) { Builder }
|
|
229
|
+
|
|
222
230
|
extend Option
|
|
223
231
|
|
|
224
232
|
option :resource_owner_authenticator,
|
|
@@ -251,8 +259,8 @@ module Doorkeeper
|
|
|
251
259
|
end)
|
|
252
260
|
|
|
253
261
|
# Hooks for authorization
|
|
254
|
-
option :before_successful_authorization, default: ->(_context) {}
|
|
255
|
-
option :after_successful_authorization, default: ->(_context) {}
|
|
262
|
+
option :before_successful_authorization, default: ->(_controller, _context = nil) {}
|
|
263
|
+
option :after_successful_authorization, default: ->(_controller, _context = nil) {}
|
|
256
264
|
# Hooks for strategies responses
|
|
257
265
|
option :before_successful_strategy_response, default: ->(_request) {}
|
|
258
266
|
option :after_successful_strategy_response, default: ->(_request, _response) {}
|
|
@@ -265,9 +273,17 @@ module Doorkeeper
|
|
|
265
273
|
option :authorization_code_expires_in, default: 600
|
|
266
274
|
option :orm, default: :active_record
|
|
267
275
|
option :native_redirect_uri, default: "urn:ietf:wg:oauth:2.0:oob", deprecated: true
|
|
268
|
-
option :active_record_options, default: {}
|
|
269
276
|
option :grant_flows, default: %w[authorization_code client_credentials]
|
|
270
277
|
option :handle_auth_errors, default: :render
|
|
278
|
+
option :token_lookup_batch_size, default: 10_000
|
|
279
|
+
|
|
280
|
+
option :active_record_options,
|
|
281
|
+
default: {},
|
|
282
|
+
deprecated: { message: "Customize Doorkeeper models instead" }
|
|
283
|
+
|
|
284
|
+
# Hook to allow arbitrary user-client authorization
|
|
285
|
+
option :authorize_resource_owner_for_client,
|
|
286
|
+
default: ->(_client, _resource_owner) { true }
|
|
271
287
|
|
|
272
288
|
# Allows to customize OAuth grant flows that +each+ application support.
|
|
273
289
|
# You can configure a custom block (or use a class respond to `#call`) that must
|
|
@@ -471,6 +487,10 @@ module Doorkeeper
|
|
|
471
487
|
option_set? :enable_application_owner
|
|
472
488
|
end
|
|
473
489
|
|
|
490
|
+
def polymorphic_resource_owner?
|
|
491
|
+
option_set? :polymorphic_resource_owner
|
|
492
|
+
end
|
|
493
|
+
|
|
474
494
|
def confirm_application_owner?
|
|
475
495
|
option_set? :confirm_application_owner
|
|
476
496
|
end
|
|
@@ -479,6 +499,10 @@ module Doorkeeper
|
|
|
479
499
|
handle_auth_errors == :raise
|
|
480
500
|
end
|
|
481
501
|
|
|
502
|
+
def application_secret_hashed?
|
|
503
|
+
instance_variable_defined?(:"@application_secret_strategy")
|
|
504
|
+
end
|
|
505
|
+
|
|
482
506
|
def token_secret_strategy
|
|
483
507
|
@token_secret_strategy ||= ::Doorkeeper::SecretStoring::Plain
|
|
484
508
|
end
|
|
@@ -11,14 +11,11 @@ module Doorkeeper
|
|
|
11
11
|
include Models::Orderable
|
|
12
12
|
include Models::SecretStorable
|
|
13
13
|
include Models::Scopes
|
|
14
|
+
include Models::ResourceOwnerable
|
|
14
15
|
|
|
15
16
|
# never uses pkce, if pkce migrations were not generated
|
|
16
17
|
def uses_pkce?
|
|
17
|
-
pkce_supported? && code_challenge.present?
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def pkce_supported?
|
|
21
|
-
respond_to? :code_challenge
|
|
18
|
+
self.class.pkce_supported? && code_challenge.present?
|
|
22
19
|
end
|
|
23
20
|
|
|
24
21
|
module ClassMethods
|
|
@@ -43,11 +40,12 @@ module Doorkeeper
|
|
|
43
40
|
# instance of the Resource Owner model
|
|
44
41
|
#
|
|
45
42
|
def revoke_all_for(application_id, resource_owner, clock = Time)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
by_resource_owner(resource_owner)
|
|
44
|
+
.where(
|
|
45
|
+
application_id: application_id,
|
|
46
|
+
revoked_at: nil,
|
|
47
|
+
)
|
|
48
|
+
.update_all(revoked_at: clock.now.utc)
|
|
51
49
|
end
|
|
52
50
|
|
|
53
51
|
# Implements PKCE code_challenge encoding without base64 padding as described in the spec.
|
|
@@ -96,7 +94,7 @@ module Doorkeeper
|
|
|
96
94
|
end
|
|
97
95
|
|
|
98
96
|
def pkce_supported?
|
|
99
|
-
|
|
97
|
+
column_names.include?("code_challenge")
|
|
100
98
|
end
|
|
101
99
|
|
|
102
100
|
##
|
|
@@ -12,6 +12,7 @@ module Doorkeeper
|
|
|
12
12
|
include Models::Orderable
|
|
13
13
|
include Models::SecretStorable
|
|
14
14
|
include Models::Scopes
|
|
15
|
+
include Models::ResourceOwnerable
|
|
15
16
|
|
|
16
17
|
module ClassMethods
|
|
17
18
|
# Returns an instance of the Doorkeeper::AccessToken with
|
|
@@ -64,11 +65,12 @@ module Doorkeeper
|
|
|
64
65
|
# instance of the Resource Owner model
|
|
65
66
|
#
|
|
66
67
|
def revoke_all_for(application_id, resource_owner, clock = Time)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
by_resource_owner(resource_owner)
|
|
69
|
+
.where(
|
|
70
|
+
application_id: application_id,
|
|
71
|
+
revoked_at: nil,
|
|
72
|
+
)
|
|
73
|
+
.update_all(revoked_at: clock.now.utc)
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
# Looking for not revoked Access Token with a matching set of scopes
|
|
@@ -76,7 +78,7 @@ module Doorkeeper
|
|
|
76
78
|
#
|
|
77
79
|
# @param application [Doorkeeper::Application]
|
|
78
80
|
# Application instance
|
|
79
|
-
# @param
|
|
81
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
80
82
|
# Resource Owner model instance or it's ID
|
|
81
83
|
# @param scopes [String, Doorkeeper::OAuth::Scopes]
|
|
82
84
|
# set of scopes
|
|
@@ -84,14 +86,8 @@ module Doorkeeper
|
|
|
84
86
|
# @return [Doorkeeper::AccessToken, nil] Access Token instance or
|
|
85
87
|
# nil if matching record was not found
|
|
86
88
|
#
|
|
87
|
-
def matching_token_for(application,
|
|
88
|
-
|
|
89
|
-
resource_owner_or_id.id
|
|
90
|
-
else
|
|
91
|
-
resource_owner_or_id
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
tokens = authorized_tokens_for(application.try(:id), resource_owner_id)
|
|
89
|
+
def matching_token_for(application, resource_owner, scopes)
|
|
90
|
+
tokens = authorized_tokens_for(application&.id, resource_owner)
|
|
95
91
|
find_matching_token(tokens, application, scopes)
|
|
96
92
|
end
|
|
97
93
|
|
|
@@ -126,10 +122,11 @@ module Doorkeeper
|
|
|
126
122
|
return nil unless relation
|
|
127
123
|
|
|
128
124
|
matching_tokens = []
|
|
125
|
+
batch_size = Doorkeeper.configuration.token_lookup_batch_size
|
|
129
126
|
|
|
130
|
-
find_access_token_in_batches(relation) do |batch|
|
|
127
|
+
find_access_token_in_batches(relation, batch_size: batch_size) do |batch|
|
|
131
128
|
tokens = batch.select do |token|
|
|
132
|
-
scopes_match?(token.scopes, scopes, application
|
|
129
|
+
scopes_match?(token.scopes, scopes, application&.scopes)
|
|
133
130
|
end
|
|
134
131
|
|
|
135
132
|
matching_tokens.concat(tokens)
|
|
@@ -169,47 +166,78 @@ module Doorkeeper
|
|
|
169
166
|
#
|
|
170
167
|
# @param application [Doorkeeper::Application]
|
|
171
168
|
# Application instance
|
|
172
|
-
# @param
|
|
169
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
173
170
|
# Resource Owner model instance or it's ID
|
|
174
171
|
# @param scopes [#to_s]
|
|
175
172
|
# set of scopes (any object that responds to `#to_s`)
|
|
176
|
-
# @param
|
|
173
|
+
# @param token_attributes [Hash]
|
|
174
|
+
# Additional attributes to use when creating a token
|
|
175
|
+
# @option token_attributes [Integer] :expires_in
|
|
177
176
|
# token lifetime in seconds
|
|
178
|
-
# @
|
|
177
|
+
# @option token_attributes [Boolean] :use_refresh_token
|
|
179
178
|
# whether to use the refresh token
|
|
180
179
|
#
|
|
181
180
|
# @return [Doorkeeper::AccessToken] existing record or a new one
|
|
182
181
|
#
|
|
183
|
-
def find_or_create_for(application
|
|
182
|
+
def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
|
|
184
183
|
if Doorkeeper.config.reuse_access_token
|
|
185
|
-
access_token = matching_token_for(application,
|
|
184
|
+
access_token = matching_token_for(application, resource_owner, scopes)
|
|
186
185
|
|
|
187
186
|
return access_token if access_token&.reusable?
|
|
188
187
|
end
|
|
189
188
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
scopes: scopes
|
|
194
|
-
|
|
195
|
-
use_refresh_token: use_refresh_token,
|
|
189
|
+
create_for(
|
|
190
|
+
application: application,
|
|
191
|
+
resource_owner: resource_owner,
|
|
192
|
+
scopes: scopes,
|
|
193
|
+
**token_attributes,
|
|
196
194
|
)
|
|
197
195
|
end
|
|
198
196
|
|
|
197
|
+
# Creates a not expired AccessToken record with a matching set of
|
|
198
|
+
# scopes that belongs to specific Application and Resource Owner.
|
|
199
|
+
#
|
|
200
|
+
# @param application [Doorkeeper::Application]
|
|
201
|
+
# Application instance
|
|
202
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
203
|
+
# Resource Owner model instance or it's ID
|
|
204
|
+
# @param scopes [#to_s]
|
|
205
|
+
# set of scopes (any object that responds to `#to_s`)
|
|
206
|
+
# @param token_attributes [Hash]
|
|
207
|
+
# Additional attributes to use when creating a token
|
|
208
|
+
# @option token_attributes [Integer] :expires_in
|
|
209
|
+
# token lifetime in seconds
|
|
210
|
+
# @option token_attributes [Boolean] :use_refresh_token
|
|
211
|
+
# whether to use the refresh token
|
|
212
|
+
#
|
|
213
|
+
# @return [Doorkeeper::AccessToken] new access token
|
|
214
|
+
#
|
|
215
|
+
def create_for(application:, resource_owner:, scopes:, **token_attributes)
|
|
216
|
+
token_attributes[:application_id] = application&.id
|
|
217
|
+
token_attributes[:scopes] = scopes.to_s
|
|
218
|
+
|
|
219
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
|
220
|
+
token_attributes[:resource_owner] = resource_owner
|
|
221
|
+
else
|
|
222
|
+
token_attributes[:resource_owner_id] = resource_owner_id_for(resource_owner)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
create!(token_attributes)
|
|
226
|
+
end
|
|
227
|
+
|
|
199
228
|
# Looking for not revoked Access Token records that belongs to specific
|
|
200
229
|
# Application and Resource Owner.
|
|
201
230
|
#
|
|
202
231
|
# @param application_id [Integer]
|
|
203
232
|
# ID of the Application model instance
|
|
204
|
-
# @param
|
|
233
|
+
# @param resource_owner [Integer]
|
|
205
234
|
# ID of the Resource Owner model instance
|
|
206
235
|
#
|
|
207
236
|
# @return [Doorkeeper::AccessToken] array of matching AccessToken objects
|
|
208
237
|
#
|
|
209
|
-
def authorized_tokens_for(application_id,
|
|
210
|
-
where(
|
|
238
|
+
def authorized_tokens_for(application_id, resource_owner)
|
|
239
|
+
by_resource_owner(resource_owner).where(
|
|
211
240
|
application_id: application_id,
|
|
212
|
-
resource_owner_id: resource_owner_id,
|
|
213
241
|
revoked_at: nil,
|
|
214
242
|
)
|
|
215
243
|
end
|
|
@@ -219,15 +247,16 @@ module Doorkeeper
|
|
|
219
247
|
#
|
|
220
248
|
# @param application_id [Integer]
|
|
221
249
|
# ID of the Application model instance
|
|
222
|
-
# @param
|
|
250
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
223
251
|
# ID of the Resource Owner model instance
|
|
224
252
|
#
|
|
225
253
|
# @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
|
|
226
254
|
# nil if nothing was found
|
|
227
255
|
#
|
|
228
|
-
def last_authorized_token_for(application_id,
|
|
229
|
-
authorized_tokens_for(application_id,
|
|
230
|
-
.ordered_by(:created_at, :desc)
|
|
256
|
+
def last_authorized_token_for(application_id, resource_owner)
|
|
257
|
+
authorized_tokens_for(application_id, resource_owner)
|
|
258
|
+
.ordered_by(:created_at, :desc)
|
|
259
|
+
.first
|
|
231
260
|
end
|
|
232
261
|
|
|
233
262
|
##
|
|
@@ -268,7 +297,11 @@ module Doorkeeper
|
|
|
268
297
|
expires_in: expires_in_seconds,
|
|
269
298
|
application: { uid: application.try(:uid) },
|
|
270
299
|
created_at: created_at.to_i,
|
|
271
|
-
}
|
|
300
|
+
}.tap do |json|
|
|
301
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
|
302
|
+
json[:resource_owner_type] = resource_owner_type
|
|
303
|
+
end
|
|
304
|
+
end
|
|
272
305
|
end
|
|
273
306
|
|
|
274
307
|
# Indicates whether the token instance have the same credential
|
|
@@ -280,7 +313,22 @@ module Doorkeeper
|
|
|
280
313
|
#
|
|
281
314
|
def same_credential?(access_token)
|
|
282
315
|
application_id == access_token.application_id &&
|
|
316
|
+
same_resource_owner?(access_token)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Indicates whether the token instance have the same credential
|
|
320
|
+
# as the other Access Token.
|
|
321
|
+
#
|
|
322
|
+
# @param access_token [Doorkeeper::AccessToken] other token
|
|
323
|
+
#
|
|
324
|
+
# @return [Boolean] true if credentials are same of false in other cases
|
|
325
|
+
#
|
|
326
|
+
def same_resource_owner?(access_token)
|
|
327
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
|
328
|
+
resource_owner == access_token.resource_owner
|
|
329
|
+
else
|
|
283
330
|
resource_owner_id == access_token.resource_owner_id
|
|
331
|
+
end
|
|
284
332
|
end
|
|
285
333
|
|
|
286
334
|
# Indicates if token is acceptable for specific scopes.
|
|
@@ -325,7 +373,7 @@ module Doorkeeper
|
|
|
325
373
|
return unless self.class.refresh_token_revoked_on_use?
|
|
326
374
|
|
|
327
375
|
old_refresh_token&.revoke
|
|
328
|
-
|
|
376
|
+
update_column(:previous_refresh_token, "")
|
|
329
377
|
end
|
|
330
378
|
|
|
331
379
|
private
|
|
@@ -362,16 +410,28 @@ module Doorkeeper
|
|
|
362
410
|
def generate_token
|
|
363
411
|
self.created_at ||= Time.now.utc
|
|
364
412
|
|
|
365
|
-
@raw_token = token_generator.generate(
|
|
413
|
+
@raw_token = token_generator.generate(attributes_for_token_generator)
|
|
414
|
+
secret_strategy.store_secret(self, :token, @raw_token)
|
|
415
|
+
@raw_token
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
# Set of attributes that would be passed to token generator to
|
|
419
|
+
# generate unique token based on them.
|
|
420
|
+
#
|
|
421
|
+
# @return [Hash] set of attributes
|
|
422
|
+
#
|
|
423
|
+
def attributes_for_token_generator
|
|
424
|
+
{
|
|
366
425
|
resource_owner_id: resource_owner_id,
|
|
367
426
|
scopes: scopes,
|
|
368
427
|
application: application,
|
|
369
428
|
expires_in: expires_in,
|
|
370
429
|
created_at: created_at,
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
430
|
+
}.tap do |attributes|
|
|
431
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
|
432
|
+
attributes[:resource_owner] = resource_owner
|
|
433
|
+
end
|
|
434
|
+
end
|
|
375
435
|
end
|
|
376
436
|
|
|
377
437
|
def token_generator
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module Models
|
|
5
|
+
module ResourceOwnerable
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
# Searches for record by Resource Owner considering Doorkeeper
|
|
10
|
+
# configuration for resource owner association.
|
|
11
|
+
#
|
|
12
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
13
|
+
# resource owner
|
|
14
|
+
#
|
|
15
|
+
# @return [Doorkeeper::AccessGrant, Doorkeeper::AccessToken]
|
|
16
|
+
# collection of records
|
|
17
|
+
#
|
|
18
|
+
def by_resource_owner(resource_owner)
|
|
19
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
|
20
|
+
where(resource_owner: resource_owner)
|
|
21
|
+
else
|
|
22
|
+
where(resource_owner_id: resource_owner_id_for(resource_owner))
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
|
|
28
|
+
# Backward compatible way to retrieve resource owner itself (if
|
|
29
|
+
# polymorphic association enabled) or just it's ID.
|
|
30
|
+
#
|
|
31
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
|
32
|
+
# resource owner
|
|
33
|
+
#
|
|
34
|
+
# @return [ActiveRecord::Base, Integer]
|
|
35
|
+
# instance of Resource Owner or it's ID
|
|
36
|
+
#
|
|
37
|
+
def resource_owner_id_for(resource_owner)
|
|
38
|
+
if resource_owner.respond_to?(:to_key)
|
|
39
|
+
resource_owner.id
|
|
40
|
+
else
|
|
41
|
+
resource_owner
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -8,7 +8,11 @@ module Doorkeeper
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def scopes=(value)
|
|
11
|
-
|
|
11
|
+
if value.is_a?(Array)
|
|
12
|
+
super(Doorkeeper::OAuth::Scopes.from_array(value).to_s)
|
|
13
|
+
else
|
|
14
|
+
super(Doorkeeper::OAuth::Scopes.from_string(value.to_s).to_s)
|
|
15
|
+
end
|
|
12
16
|
end
|
|
13
17
|
|
|
14
18
|
def scopes_string
|
|
@@ -25,9 +25,7 @@ module Doorkeeper
|
|
|
25
25
|
# @return [Boolean]
|
|
26
26
|
# Whether input matches secret as per the secret strategy
|
|
27
27
|
#
|
|
28
|
-
|
|
29
|
-
secret_strategy.secret_matches?(input, secret)
|
|
30
|
-
end
|
|
28
|
+
delegate :secret_matches?, to: :secret_strategy
|
|
31
29
|
|
|
32
30
|
# Returns an instance of the Doorkeeper::AccessToken with
|
|
33
31
|
# specific token value.
|
|
@@ -4,7 +4,7 @@ module Doorkeeper
|
|
|
4
4
|
module OAuth
|
|
5
5
|
module Authorization
|
|
6
6
|
class Code
|
|
7
|
-
|
|
7
|
+
attr_reader :pre_auth, :resource_owner, :token
|
|
8
8
|
|
|
9
9
|
def initialize(pre_auth, resource_owner)
|
|
10
10
|
@pre_auth = pre_auth
|
|
@@ -12,7 +12,9 @@ module Doorkeeper
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def issue_token
|
|
15
|
-
@token
|
|
15
|
+
return @token if defined?(@token)
|
|
16
|
+
|
|
17
|
+
@token = Doorkeeper.config.access_grant_model.create!(access_grant_attributes)
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
def oob_redirect
|
|
@@ -26,13 +28,20 @@ module Doorkeeper
|
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
def access_grant_attributes
|
|
29
|
-
|
|
31
|
+
attributes = {
|
|
30
32
|
application_id: pre_auth.client.id,
|
|
31
|
-
resource_owner_id: resource_owner.id,
|
|
32
33
|
expires_in: authorization_code_expires_in,
|
|
33
34
|
redirect_uri: pre_auth.redirect_uri,
|
|
34
35
|
scopes: pre_auth.scopes.to_s,
|
|
35
|
-
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
|
39
|
+
attributes[:resource_owner] = resource_owner
|
|
40
|
+
else
|
|
41
|
+
attributes[:resource_owner_id] = resource_owner.id
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
pkce_attributes.merge(attributes)
|
|
36
45
|
end
|
|
37
46
|
|
|
38
47
|
def pkce_attributes
|