doorkeeper 5.3.3 → 5.5.0.rc2
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 +125 -7
- data/README.md +6 -4
- data/app/controllers/doorkeeper/applications_controller.rb +4 -4
- data/app/controllers/doorkeeper/authorizations_controller.rb +46 -16
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +2 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +67 -22
- data/app/views/doorkeeper/applications/_form.html.erb +1 -1
- data/app/views/doorkeeper/applications/show.html.erb +35 -14
- data/app/views/doorkeeper/authorizations/form_post.html.erb +11 -0
- data/config/locales/en.yml +6 -2
- data/lib/doorkeeper.rb +111 -79
- data/lib/doorkeeper/config.rb +148 -94
- data/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/lib/doorkeeper/config/option.rb +26 -14
- data/lib/doorkeeper/config/validations.rb +53 -0
- data/lib/doorkeeper/engine.rb +1 -1
- data/lib/doorkeeper/grant_flow.rb +45 -0
- data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
- data/lib/doorkeeper/grant_flow/flow.rb +44 -0
- data/lib/doorkeeper/grant_flow/registry.rb +50 -0
- data/lib/doorkeeper/grape/helpers.rb +1 -1
- data/lib/doorkeeper/helpers/controller.rb +8 -4
- data/lib/doorkeeper/models/access_grant_mixin.rb +21 -18
- data/lib/doorkeeper/models/access_token_mixin.rb +110 -47
- data/lib/doorkeeper/models/application_mixin.rb +5 -4
- 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 +19 -6
- data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
- data/lib/doorkeeper/oauth/authorization/token.rb +18 -16
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
- data/lib/doorkeeper/oauth/authorization_code_request.rb +17 -14
- data/lib/doorkeeper/oauth/base_request.rb +12 -20
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +27 -8
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +4 -2
- data/lib/doorkeeper/oauth/client_credentials/validator.rb +4 -2
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
- data/lib/doorkeeper/oauth/code_request.rb +3 -3
- data/lib/doorkeeper/oauth/code_response.rb +22 -12
- data/lib/doorkeeper/oauth/error_response.rb +6 -7
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -8
- 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 +24 -7
- data/lib/doorkeeper/oauth/pre_authorization.rb +63 -32
- data/lib/doorkeeper/oauth/refresh_token_request.rb +31 -22
- data/lib/doorkeeper/oauth/token.rb +5 -6
- data/lib/doorkeeper/oauth/token_introspection.rb +4 -8
- data/lib/doorkeeper/oauth/token_request.rb +3 -3
- data/lib/doorkeeper/oauth/token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record.rb +14 -7
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +8 -3
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +7 -3
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +6 -3
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +5 -0
- data/lib/doorkeeper/rails/routes.rb +14 -20
- 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/request.rb +49 -12
- data/lib/doorkeeper/request/refresh_token.rb +2 -1
- data/lib/doorkeeper/request/strategy.rb +2 -2
- data/lib/doorkeeper/server.rb +4 -4
- data/lib/doorkeeper/stale_records_cleaner.rb +4 -4
- data/lib/doorkeeper/version.rb +3 -7
- 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 +3 -1
- 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 +48 -10
- data/lib/generators/doorkeeper/templates/migration.rb.erb +14 -5
- metadata +30 -300
- data/Appraisals +0 -40
- data/CODE_OF_CONDUCT.md +0 -46
- data/CONTRIBUTING.md +0 -49
- data/Dangerfile +0 -67
- data/Dockerfile +0 -29
- data/Gemfile +0 -25
- data/NEWS.md +0 -1
- data/RELEASING.md +0 -11
- data/Rakefile +0 -28
- data/SECURITY.md +0 -15
- data/UPGRADE.md +0 -2
- data/bin/console +0 -16
- data/doorkeeper.gemspec +0 -42
- data/gemfiles/rails_5_0.gemfile +0 -18
- data/gemfiles/rails_5_1.gemfile +0 -18
- data/gemfiles/rails_5_2.gemfile +0 -18
- data/gemfiles/rails_6_0.gemfile +0 -18
- data/gemfiles/rails_master.gemfile +0 -18
- data/spec/controllers/application_metal_controller_spec.rb +0 -64
- data/spec/controllers/applications_controller_spec.rb +0 -274
- data/spec/controllers/authorizations_controller_spec.rb +0 -608
- data/spec/controllers/protected_resources_controller_spec.rb +0 -361
- data/spec/controllers/token_info_controller_spec.rb +0 -50
- data/spec/controllers/tokens_controller_spec.rb +0 -498
- data/spec/dummy/Rakefile +0 -9
- data/spec/dummy/app/assets/config/manifest.js +0 -2
- data/spec/dummy/app/controllers/application_controller.rb +0 -5
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
- data/spec/dummy/app/controllers/home_controller.rb +0 -18
- data/spec/dummy/app/controllers/metal_controller.rb +0 -13
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
- data/spec/dummy/app/helpers/application_helper.rb +0 -7
- data/spec/dummy/app/models/user.rb +0 -7
- data/spec/dummy/app/views/home/index.html.erb +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/config.ru +0 -6
- data/spec/dummy/config/application.rb +0 -49
- data/spec/dummy/config/boot.rb +0 -7
- data/spec/dummy/config/database.yml +0 -15
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -31
- data/spec/dummy/config/environments/production.rb +0 -64
- data/spec/dummy/config/environments/test.rb +0 -45
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
- data/spec/dummy/config/initializers/doorkeeper.rb +0 -166
- data/spec/dummy/config/initializers/secret_token.rb +0 -10
- data/spec/dummy/config/initializers/session_store.rb +0 -10
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
- data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -13
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
- data/spec/dummy/db/schema.rb +0 -68
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -26
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +0 -9
- data/spec/factories.rb +0 -30
- data/spec/generators/application_owner_generator_spec.rb +0 -28
- data/spec/generators/confidential_applications_generator_spec.rb +0 -29
- data/spec/generators/install_generator_spec.rb +0 -36
- data/spec/generators/migration_generator_spec.rb +0 -28
- data/spec/generators/pkce_generator_spec.rb +0 -28
- data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
- data/spec/generators/templates/routes.rb +0 -4
- data/spec/generators/views_generator_spec.rb +0 -29
- data/spec/grape/grape_integration_spec.rb +0 -137
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
- data/spec/lib/config_spec.rb +0 -809
- data/spec/lib/doorkeeper_spec.rb +0 -27
- data/spec/lib/models/expirable_spec.rb +0 -61
- data/spec/lib/models/reusable_spec.rb +0 -40
- data/spec/lib/models/revocable_spec.rb +0 -59
- data/spec/lib/models/scopes_spec.rb +0 -53
- data/spec/lib/models/secret_storable_spec.rb +0 -135
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
- data/spec/lib/oauth/authorization_code_request_spec.rb +0 -170
- data/spec/lib/oauth/base_request_spec.rb +0 -224
- data/spec/lib/oauth/base_response_spec.rb +0 -45
- data/spec/lib/oauth/client/credentials_spec.rb +0 -90
- data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -134
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
- data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
- data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
- data/spec/lib/oauth/client_credentials_request_spec.rb +0 -107
- data/spec/lib/oauth/client_spec.rb +0 -38
- data/spec/lib/oauth/code_request_spec.rb +0 -46
- data/spec/lib/oauth/code_response_spec.rb +0 -32
- data/spec/lib/oauth/error_response_spec.rb +0 -64
- data/spec/lib/oauth/error_spec.rb +0 -21
- data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -20
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -110
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -262
- data/spec/lib/oauth/invalid_request_response_spec.rb +0 -73
- data/spec/lib/oauth/invalid_token_response_spec.rb +0 -53
- data/spec/lib/oauth/password_access_token_request_spec.rb +0 -190
- data/spec/lib/oauth/pre_authorization_spec.rb +0 -223
- data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
- data/spec/lib/oauth/scopes_spec.rb +0 -146
- data/spec/lib/oauth/token_request_spec.rb +0 -157
- data/spec/lib/oauth/token_response_spec.rb +0 -84
- data/spec/lib/oauth/token_spec.rb +0 -156
- data/spec/lib/request/strategy_spec.rb +0 -54
- data/spec/lib/secret_storing/base_spec.rb +0 -60
- data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
- data/spec/lib/secret_storing/plain_spec.rb +0 -44
- data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
- data/spec/lib/server_spec.rb +0 -49
- data/spec/lib/stale_records_cleaner_spec.rb +0 -89
- data/spec/models/doorkeeper/access_grant_spec.rb +0 -161
- data/spec/models/doorkeeper/access_token_spec.rb +0 -622
- data/spec/models/doorkeeper/application_spec.rb +0 -482
- data/spec/requests/applications/applications_request_spec.rb +0 -259
- data/spec/requests/applications/authorized_applications_spec.rb +0 -32
- data/spec/requests/endpoints/authorization_spec.rb +0 -91
- data/spec/requests/endpoints/token_spec.rb +0 -75
- data/spec/requests/flows/authorization_code_errors_spec.rb +0 -79
- data/spec/requests/flows/authorization_code_spec.rb +0 -525
- data/spec/requests/flows/client_credentials_spec.rb +0 -166
- data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -46
- data/spec/requests/flows/implicit_grant_spec.rb +0 -91
- data/spec/requests/flows/password_spec.rb +0 -316
- data/spec/requests/flows/refresh_token_spec.rb +0 -233
- data/spec/requests/flows/revoke_token_spec.rb +0 -157
- data/spec/requests/flows/skip_authorization_spec.rb +0 -66
- data/spec/requests/protected_resources/metal_spec.rb +0 -16
- data/spec/requests/protected_resources/private_api_spec.rb +0 -83
- data/spec/routing/custom_controller_routes_spec.rb +0 -133
- data/spec/routing/default_routes_spec.rb +0 -41
- data/spec/routing/scoped_routes_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -54
- data/spec/spec_helper_integration.rb +0 -4
- data/spec/support/dependencies/factory_bot.rb +0 -4
- data/spec/support/doorkeeper_rspec.rb +0 -22
- data/spec/support/helpers/access_token_request_helper.rb +0 -13
- data/spec/support/helpers/authorization_request_helper.rb +0 -43
- data/spec/support/helpers/config_helper.rb +0 -11
- data/spec/support/helpers/model_helper.rb +0 -78
- data/spec/support/helpers/request_spec_helper.rb +0 -110
- data/spec/support/helpers/url_helper.rb +0 -62
- data/spec/support/orm/active_record.rb +0 -5
- data/spec/support/shared/controllers_shared_context.rb +0 -133
- data/spec/support/shared/hashing_shared_context.rb +0 -36
- data/spec/support/shared/models_shared_examples.rb +0 -54
- data/spec/validators/redirect_uri_validator_spec.rb +0 -183
- data/spec/version/version_spec.rb +0 -17
@@ -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,27 @@ 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
|
+
warning = "#{warning}\n#{deprecation_opts.fetch(:message)}" if deprecation_opts.is_a?(Hash)
|
49
|
+
|
50
|
+
Kernel.warn(warning)
|
54
51
|
end
|
52
|
+
|
53
|
+
value = if attribute_builder
|
54
|
+
attribute_builder.new(&block).build
|
55
|
+
else
|
56
|
+
block || args.first
|
57
|
+
end
|
58
|
+
|
59
|
+
@config.instance_variable_set(:"@#{attribute}", value)
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
@@ -65,6 +70,13 @@ module Doorkeeper
|
|
65
70
|
|
66
71
|
public attribute
|
67
72
|
end
|
73
|
+
|
74
|
+
def self.extended(base)
|
75
|
+
return if base.respond_to?(:builder_class)
|
76
|
+
|
77
|
+
raise Doorkeeper::MissingConfigurationBuilderClass, "Define `self.builder_class` method " \
|
78
|
+
"for #{base} that returns your custom Builder class to use options DSL!"
|
79
|
+
end
|
68
80
|
end
|
69
81
|
end
|
70
82
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
class Config
|
5
|
+
# Doorkeeper configuration validator.
|
6
|
+
#
|
7
|
+
module Validations
|
8
|
+
# Validates configuration options to be set properly.
|
9
|
+
#
|
10
|
+
def validate!
|
11
|
+
validate_reuse_access_token_value
|
12
|
+
validate_token_reuse_limit
|
13
|
+
validate_secret_strategies
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Determine whether +reuse_access_token+ and a non-restorable
|
19
|
+
# +token_secret_strategy+ have both been activated.
|
20
|
+
#
|
21
|
+
# In that case, disable reuse_access_token value and warn the user.
|
22
|
+
def validate_reuse_access_token_value
|
23
|
+
strategy = token_secret_strategy
|
24
|
+
return if !reuse_access_token || strategy.allows_restoring_secrets?
|
25
|
+
|
26
|
+
::Rails.logger.warn(
|
27
|
+
"You have configured both reuse_access_token " \
|
28
|
+
"AND strategy strategy '#{strategy}' that cannot restore tokens. " \
|
29
|
+
"This combination is unsupported. reuse_access_token will be disabled",
|
30
|
+
)
|
31
|
+
@reuse_access_token = false
|
32
|
+
end
|
33
|
+
|
34
|
+
# Validate that the provided strategies are valid for
|
35
|
+
# tokens and applications
|
36
|
+
def validate_secret_strategies
|
37
|
+
token_secret_strategy.validate_for(:token)
|
38
|
+
application_secret_strategy.validate_for(:application)
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate_token_reuse_limit
|
42
|
+
return if !reuse_access_token ||
|
43
|
+
(token_reuse_limit > 0 && token_reuse_limit <= 100)
|
44
|
+
|
45
|
+
::Rails.logger.warn(
|
46
|
+
"You have configured an invalid value for token_reuse_limit option. " \
|
47
|
+
"It will be set to default 100",
|
48
|
+
)
|
49
|
+
@token_reuse_limit = 100
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/doorkeeper/engine.rb
CHANGED
@@ -4,7 +4,7 @@ module Doorkeeper
|
|
4
4
|
class Engine < Rails::Engine
|
5
5
|
initializer "doorkeeper.params.filter" do |app|
|
6
6
|
parameters = %w[client_secret code authentication_token access_token refresh_token]
|
7
|
-
app.config.filter_parameters << /^(#{Regexp.union
|
7
|
+
app.config.filter_parameters << /^(#{Regexp.union(parameters)})$/
|
8
8
|
end
|
9
9
|
|
10
10
|
initializer "doorkeeper.routes" do
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "doorkeeper/grant_flow/flow"
|
4
|
+
require "doorkeeper/grant_flow/fallback_flow"
|
5
|
+
require "doorkeeper/grant_flow/registry"
|
6
|
+
|
7
|
+
module Doorkeeper
|
8
|
+
module GrantFlow
|
9
|
+
extend Registry
|
10
|
+
|
11
|
+
register(
|
12
|
+
:implicit,
|
13
|
+
response_type_matches: "token",
|
14
|
+
response_mode_matches: %w[fragment form_post],
|
15
|
+
response_type_strategy: Doorkeeper::Request::Token,
|
16
|
+
)
|
17
|
+
|
18
|
+
register(
|
19
|
+
:authorization_code,
|
20
|
+
response_type_matches: "code",
|
21
|
+
response_mode_matches: %w[query fragment form_post],
|
22
|
+
response_type_strategy: Doorkeeper::Request::Code,
|
23
|
+
grant_type_matches: "authorization_code",
|
24
|
+
grant_type_strategy: Doorkeeper::Request::AuthorizationCode,
|
25
|
+
)
|
26
|
+
|
27
|
+
register(
|
28
|
+
:client_credentials,
|
29
|
+
grant_type_matches: "client_credentials",
|
30
|
+
grant_type_strategy: Doorkeeper::Request::ClientCredentials,
|
31
|
+
)
|
32
|
+
|
33
|
+
register(
|
34
|
+
:password,
|
35
|
+
grant_type_matches: "password",
|
36
|
+
grant_type_strategy: Doorkeeper::Request::Password,
|
37
|
+
)
|
38
|
+
|
39
|
+
register(
|
40
|
+
:refresh_token,
|
41
|
+
grant_type_matches: "refresh_token",
|
42
|
+
grant_type_strategy: Doorkeeper::Request::RefreshToken,
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module GrantFlow
|
5
|
+
class Flow
|
6
|
+
attr_reader :name, :grant_type_matches, :grant_type_strategy,
|
7
|
+
:response_type_matches, :response_type_strategy,
|
8
|
+
:response_mode_matches
|
9
|
+
|
10
|
+
def initialize(name, **options)
|
11
|
+
@name = name
|
12
|
+
@grant_type_matches = options[:grant_type_matches]
|
13
|
+
@grant_type_strategy = options[:grant_type_strategy]
|
14
|
+
@response_type_matches = options[:response_type_matches]
|
15
|
+
@response_type_strategy = options[:response_type_strategy]
|
16
|
+
@response_mode_matches = options[:response_mode_matches]
|
17
|
+
end
|
18
|
+
|
19
|
+
def handles_grant_type?
|
20
|
+
grant_type_matches.present?
|
21
|
+
end
|
22
|
+
|
23
|
+
def handles_response_type?
|
24
|
+
response_type_matches.present?
|
25
|
+
end
|
26
|
+
|
27
|
+
def matches_grant_type?(value)
|
28
|
+
grant_type_matches === value
|
29
|
+
end
|
30
|
+
|
31
|
+
def matches_response_type?(value)
|
32
|
+
response_type_matches === value
|
33
|
+
end
|
34
|
+
|
35
|
+
def default_response_mode
|
36
|
+
response_mode_matches[0]
|
37
|
+
end
|
38
|
+
|
39
|
+
def matches_response_mode?(value)
|
40
|
+
response_mode_matches.include?(value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module GrantFlow
|
5
|
+
module Registry
|
6
|
+
mattr_accessor :flows
|
7
|
+
self.flows = {}
|
8
|
+
|
9
|
+
mattr_accessor :aliases
|
10
|
+
self.aliases = {}
|
11
|
+
|
12
|
+
# Allows to register custom OAuth grant flow so that Doorkeeper
|
13
|
+
# could recognize and process it.
|
14
|
+
#
|
15
|
+
def register(name_or_flow, **options)
|
16
|
+
unless name_or_flow.is_a?(Doorkeeper::GrantFlow::Flow)
|
17
|
+
name_or_flow = Flow.new(name_or_flow, **options)
|
18
|
+
end
|
19
|
+
|
20
|
+
flow_key = name_or_flow.name.to_sym
|
21
|
+
|
22
|
+
if flows.key?(flow_key)
|
23
|
+
::Kernel.warn <<~WARNING
|
24
|
+
[DOORKEEPER] '#{flow_key}' grant flow already registered and will be overridden
|
25
|
+
in #{caller(1..1).first}
|
26
|
+
WARNING
|
27
|
+
end
|
28
|
+
|
29
|
+
flows[flow_key] = name_or_flow
|
30
|
+
end
|
31
|
+
|
32
|
+
# Allows to register aliases that could be used in `grant_flows`
|
33
|
+
# configuration option. It is possible to have aliases like 1:1 or
|
34
|
+
# 1:N, i.e. "implicit_oidc" => ['token', 'id_token', 'id_token token'].
|
35
|
+
#
|
36
|
+
def register_alias(alias_name, **options)
|
37
|
+
aliases[alias_name.to_sym] = Array.wrap(options.fetch(:as))
|
38
|
+
end
|
39
|
+
|
40
|
+
def expand_alias(alias_name)
|
41
|
+
aliases.fetch(alias_name.to_sym, [])
|
42
|
+
end
|
43
|
+
|
44
|
+
# [NOTE]: make it to use #fetch after removing fallbacks
|
45
|
+
def get(name)
|
46
|
+
flows[name.to_sym]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -16,6 +16,8 @@ module Doorkeeper
|
|
16
16
|
|
17
17
|
# :doc:
|
18
18
|
def current_resource_owner
|
19
|
+
return @current_resource_owner if defined?(@current_resource_owner)
|
20
|
+
|
19
21
|
@current_resource_owner ||= begin
|
20
22
|
instance_eval(&Doorkeeper.config.authenticate_resource_owner)
|
21
23
|
end
|
@@ -36,7 +38,9 @@ module Doorkeeper
|
|
36
38
|
|
37
39
|
# :doc:
|
38
40
|
def doorkeeper_token
|
39
|
-
@doorkeeper_token
|
41
|
+
return @doorkeeper_token if defined?(@doorkeeper_token)
|
42
|
+
|
43
|
+
@doorkeeper_token ||= OAuth::Token.authenticate(request, *config_methods)
|
40
44
|
end
|
41
45
|
|
42
46
|
def config_methods
|
@@ -58,10 +62,10 @@ module Doorkeeper
|
|
58
62
|
end
|
59
63
|
|
60
64
|
def handle_token_exception(exception)
|
61
|
-
error = get_error_response_from_exception
|
62
|
-
headers.merge!
|
65
|
+
error = get_error_response_from_exception(exception)
|
66
|
+
headers.merge!(error.headers)
|
63
67
|
self.response_body = error.body.to_json
|
64
|
-
self.status
|
68
|
+
self.status = error.status
|
65
69
|
end
|
66
70
|
|
67
71
|
def skip_authorization?
|
@@ -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
|
@@ -27,8 +24,8 @@ module Doorkeeper
|
|
27
24
|
#
|
28
25
|
# @param token [#to_s] token value (any object that responds to `#to_s`)
|
29
26
|
#
|
30
|
-
# @return [Doorkeeper::AccessGrant, nil]
|
31
|
-
# if there is no record with such token
|
27
|
+
# @return [Doorkeeper::AccessGrant, nil]
|
28
|
+
# AccessGrant object or nil if there is no record with such token
|
32
29
|
#
|
33
30
|
def by_token(token)
|
34
31
|
find_by_plaintext_token(:token, token)
|
@@ -39,15 +36,16 @@ module Doorkeeper
|
|
39
36
|
#
|
40
37
|
# @param application_id [Integer]
|
41
38
|
# ID of the Application
|
42
|
-
# @param resource_owner [ActiveRecord::Base]
|
43
|
-
# instance of the Resource Owner model
|
39
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
40
|
+
# instance of the Resource Owner model or it's ID
|
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.
|
@@ -91,17 +89,19 @@ module Doorkeeper
|
|
91
89
|
# suitable for PKCE validation
|
92
90
|
#
|
93
91
|
def generate_code_challenge(code_verifier)
|
94
|
-
|
95
|
-
padded_result.split("=")[0] # Remove any trailing '='
|
92
|
+
Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier), padding: false)
|
96
93
|
end
|
97
94
|
|
98
95
|
def pkce_supported?
|
99
|
-
|
96
|
+
column_names.include?("code_challenge")
|
100
97
|
end
|
101
98
|
|
102
99
|
##
|
103
100
|
# Determines the secret storing transformer
|
104
101
|
# Unless configured otherwise, uses the plain secret strategy
|
102
|
+
#
|
103
|
+
# @return [Doorkeeper::SecretStoring::Base]
|
104
|
+
#
|
105
105
|
def secret_strategy
|
106
106
|
::Doorkeeper.config.token_secret_strategy
|
107
107
|
end
|
@@ -109,6 +109,9 @@ module Doorkeeper
|
|
109
109
|
##
|
110
110
|
# Determine the fallback storing strategy
|
111
111
|
# Unless configured, there will be no fallback
|
112
|
+
#
|
113
|
+
# @return [Doorkeeper::SecretStoring::Base]
|
114
|
+
#
|
112
115
|
def fallback_secret_strategy
|
113
116
|
::Doorkeeper.config.token_secret_fallback_strategy
|
114
117
|
end
|
@@ -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
|
@@ -60,15 +61,16 @@ module Doorkeeper
|
|
60
61
|
#
|
61
62
|
# @param application_id [Integer]
|
62
63
|
# ID of the Application
|
63
|
-
# @param resource_owner [ActiveRecord::Base]
|
64
|
-
# instance of the Resource Owner model
|
64
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
65
|
+
# instance of the Resource Owner model or it's ID
|
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,22 +86,16 @@ 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
|
|
98
94
|
# Interface to enumerate access token records in batches in order not
|
99
95
|
# to bloat the memory. Could be overloaded in any ORM extension.
|
100
96
|
#
|
101
|
-
def find_access_token_in_batches(relation,
|
102
|
-
relation.find_in_batches(
|
97
|
+
def find_access_token_in_batches(relation, **args, &block)
|
98
|
+
relation.find_in_batches(**args, &block)
|
103
99
|
end
|
104
100
|
|
105
101
|
# Enumerates AccessToken records in batches to find a matching token.
|
@@ -130,7 +126,7 @@ module Doorkeeper
|
|
130
126
|
|
131
127
|
find_access_token_in_batches(relation, batch_size: batch_size) do |batch|
|
132
128
|
tokens = batch.select do |token|
|
133
|
-
scopes_match?(token.scopes, scopes, application
|
129
|
+
scopes_match?(token.scopes, scopes, application&.scopes)
|
134
130
|
end
|
135
131
|
|
136
132
|
matching_tokens.concat(tokens)
|
@@ -170,47 +166,79 @@ module Doorkeeper
|
|
170
166
|
#
|
171
167
|
# @param application [Doorkeeper::Application]
|
172
168
|
# Application instance
|
173
|
-
# @param
|
169
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
174
170
|
# Resource Owner model instance or it's ID
|
175
171
|
# @param scopes [#to_s]
|
176
172
|
# set of scopes (any object that responds to `#to_s`)
|
177
|
-
# @param
|
173
|
+
# @param token_attributes [Hash]
|
174
|
+
# Additional attributes to use when creating a token
|
175
|
+
# @option token_attributes [Integer] :expires_in
|
178
176
|
# token lifetime in seconds
|
179
|
-
# @
|
177
|
+
# @option token_attributes [Boolean] :use_refresh_token
|
180
178
|
# whether to use the refresh token
|
181
179
|
#
|
182
180
|
# @return [Doorkeeper::AccessToken] existing record or a new one
|
183
181
|
#
|
184
|
-
def find_or_create_for(application
|
182
|
+
def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
|
185
183
|
if Doorkeeper.config.reuse_access_token
|
186
|
-
access_token = matching_token_for(application,
|
184
|
+
access_token = matching_token_for(application, resource_owner, scopes)
|
187
185
|
|
188
186
|
return access_token if access_token&.reusable?
|
189
187
|
end
|
190
188
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
scopes: scopes
|
195
|
-
|
196
|
-
use_refresh_token: use_refresh_token,
|
189
|
+
create_for(
|
190
|
+
application: application,
|
191
|
+
resource_owner: resource_owner,
|
192
|
+
scopes: scopes,
|
193
|
+
**token_attributes,
|
197
194
|
)
|
198
195
|
end
|
199
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
|
+
|
200
228
|
# Looking for not revoked Access Token records that belongs to specific
|
201
229
|
# Application and Resource Owner.
|
202
230
|
#
|
203
231
|
# @param application_id [Integer]
|
204
232
|
# ID of the Application model instance
|
205
|
-
# @param
|
206
|
-
#
|
233
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
234
|
+
# Resource Owner model instance or it's ID
|
207
235
|
#
|
208
|
-
# @return [
|
236
|
+
# @return [ActiveRecord::Relation]
|
237
|
+
# collection of matching AccessToken objects
|
209
238
|
#
|
210
|
-
def authorized_tokens_for(application_id,
|
211
|
-
where(
|
239
|
+
def authorized_tokens_for(application_id, resource_owner)
|
240
|
+
by_resource_owner(resource_owner).where(
|
212
241
|
application_id: application_id,
|
213
|
-
resource_owner_id: resource_owner_id,
|
214
242
|
revoked_at: nil,
|
215
243
|
)
|
216
244
|
end
|
@@ -220,20 +248,24 @@ module Doorkeeper
|
|
220
248
|
#
|
221
249
|
# @param application_id [Integer]
|
222
250
|
# ID of the Application model instance
|
223
|
-
# @param
|
251
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
224
252
|
# ID of the Resource Owner model instance
|
225
253
|
#
|
226
254
|
# @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
|
227
255
|
# nil if nothing was found
|
228
256
|
#
|
229
|
-
def last_authorized_token_for(application_id,
|
230
|
-
authorized_tokens_for(application_id,
|
231
|
-
.ordered_by(:created_at, :desc)
|
257
|
+
def last_authorized_token_for(application_id, resource_owner)
|
258
|
+
authorized_tokens_for(application_id, resource_owner)
|
259
|
+
.ordered_by(:created_at, :desc)
|
260
|
+
.first
|
232
261
|
end
|
233
262
|
|
234
263
|
##
|
235
264
|
# Determines the secret storing transformer
|
236
265
|
# Unless configured otherwise, uses the plain secret strategy
|
266
|
+
#
|
267
|
+
# @return [Doorkeeper::SecretStoring::Base]
|
268
|
+
#
|
237
269
|
def secret_strategy
|
238
270
|
::Doorkeeper.config.token_secret_strategy
|
239
271
|
end
|
@@ -269,7 +301,11 @@ module Doorkeeper
|
|
269
301
|
expires_in: expires_in_seconds,
|
270
302
|
application: { uid: application.try(:uid) },
|
271
303
|
created_at: created_at.to_i,
|
272
|
-
}
|
304
|
+
}.tap do |json|
|
305
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
306
|
+
json[:resource_owner_type] = resource_owner_type
|
307
|
+
end
|
308
|
+
end
|
273
309
|
end
|
274
310
|
|
275
311
|
# Indicates whether the token instance have the same credential
|
@@ -281,7 +317,22 @@ module Doorkeeper
|
|
281
317
|
#
|
282
318
|
def same_credential?(access_token)
|
283
319
|
application_id == access_token.application_id &&
|
320
|
+
same_resource_owner?(access_token)
|
321
|
+
end
|
322
|
+
|
323
|
+
# Indicates whether the token instance have the same credential
|
324
|
+
# as the other Access Token.
|
325
|
+
#
|
326
|
+
# @param access_token [Doorkeeper::AccessToken] other token
|
327
|
+
#
|
328
|
+
# @return [Boolean] true if credentials are same of false in other cases
|
329
|
+
#
|
330
|
+
def same_resource_owner?(access_token)
|
331
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
332
|
+
resource_owner == access_token.resource_owner
|
333
|
+
else
|
284
334
|
resource_owner_id == access_token.resource_owner_id
|
335
|
+
end
|
285
336
|
end
|
286
337
|
|
287
338
|
# Indicates if token is acceptable for specific scopes.
|
@@ -326,7 +377,7 @@ module Doorkeeper
|
|
326
377
|
return unless self.class.refresh_token_revoked_on_use?
|
327
378
|
|
328
379
|
old_refresh_token&.revoke
|
329
|
-
update_attribute
|
380
|
+
update_attribute(:previous_refresh_token, "") if previous_refresh_token.present?
|
330
381
|
end
|
331
382
|
|
332
383
|
private
|
@@ -363,16 +414,28 @@ module Doorkeeper
|
|
363
414
|
def generate_token
|
364
415
|
self.created_at ||= Time.now.utc
|
365
416
|
|
366
|
-
@raw_token = token_generator.generate(
|
417
|
+
@raw_token = token_generator.generate(attributes_for_token_generator)
|
418
|
+
secret_strategy.store_secret(self, :token, @raw_token)
|
419
|
+
@raw_token
|
420
|
+
end
|
421
|
+
|
422
|
+
# Set of attributes that would be passed to token generator to
|
423
|
+
# generate unique token based on them.
|
424
|
+
#
|
425
|
+
# @return [Hash] set of attributes
|
426
|
+
#
|
427
|
+
def attributes_for_token_generator
|
428
|
+
{
|
367
429
|
resource_owner_id: resource_owner_id,
|
368
430
|
scopes: scopes,
|
369
431
|
application: application,
|
370
432
|
expires_in: expires_in,
|
371
433
|
created_at: created_at,
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
434
|
+
}.tap do |attributes|
|
435
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
436
|
+
attributes[:resource_owner] = resource_owner
|
437
|
+
end
|
438
|
+
end
|
376
439
|
end
|
377
440
|
|
378
441
|
def token_generator
|