doorkeeper 5.2.2 → 5.5.4
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 +198 -3
- data/README.md +28 -20
- data/app/controllers/doorkeeper/application_controller.rb +3 -2
- data/app/controllers/doorkeeper/application_metal_controller.rb +2 -2
- data/app/controllers/doorkeeper/applications_controller.rb +7 -8
- data/app/controllers/doorkeeper/authorizations_controller.rb +48 -18
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +6 -6
- data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +70 -25
- data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
- 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 +15 -0
- data/app/views/doorkeeper/authorizations/new.html.erb +2 -0
- data/config/locales/en.yml +9 -2
- 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/config.rb +214 -122
- data/lib/doorkeeper/engine.rb +1 -1
- 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/grant_flow.rb +45 -0
- data/lib/doorkeeper/grape/helpers.rb +2 -2
- data/lib/doorkeeper/helpers/controller.rb +18 -12
- data/lib/doorkeeper/models/access_grant_mixin.rb +23 -19
- data/lib/doorkeeper/models/access_token_mixin.rb +157 -55
- data/lib/doorkeeper/models/application_mixin.rb +8 -7
- data/lib/doorkeeper/models/concerns/expirable.rb +1 -1
- data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
- data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
- data/lib/doorkeeper/models/concerns/revocable.rb +1 -28
- 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 +22 -9
- data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
- data/lib/doorkeeper/oauth/authorization/token.rb +23 -18
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
- data/lib/doorkeeper/oauth/authorization_code_request.rb +30 -20
- data/lib/doorkeeper/oauth/base_request.rb +19 -23
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
- data/lib/doorkeeper/oauth/client.rb +8 -9
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +38 -12
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +10 -8
- data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +7 -5
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
- data/lib/doorkeeper/oauth/code_request.rb +4 -4
- data/lib/doorkeeper/oauth/code_response.rb +24 -14
- data/lib/doorkeeper/oauth/error.rb +1 -1
- data/lib/doorkeeper/oauth/error_response.rb +10 -11
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +2 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +8 -12
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +10 -7
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +1 -19
- data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/lib/doorkeeper/oauth/invalid_request_response.rb +3 -3
- data/lib/doorkeeper/oauth/invalid_token_response.rb +7 -4
- data/lib/doorkeeper/oauth/password_access_token_request.rb +28 -10
- data/lib/doorkeeper/oauth/pre_authorization.rb +73 -37
- data/lib/doorkeeper/oauth/refresh_token_request.rb +35 -26
- data/lib/doorkeeper/oauth/token.rb +6 -7
- data/lib/doorkeeper/oauth/token_introspection.rb +12 -16
- data/lib/doorkeeper/oauth/token_request.rb +3 -3
- data/lib/doorkeeper/oauth/token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
- data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
- data/lib/doorkeeper/orm/active_record/application.rb +5 -95
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +69 -0
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +60 -0
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +199 -0
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +8 -3
- data/lib/doorkeeper/orm/active_record.rb +5 -7
- data/lib/doorkeeper/rails/helpers.rb +4 -4
- 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 +17 -25
- data/lib/doorkeeper/rake/db.rake +6 -6
- data/lib/doorkeeper/rake/setup.rake +5 -0
- data/lib/doorkeeper/request/authorization_code.rb +3 -3
- data/lib/doorkeeper/request/client_credentials.rb +2 -2
- data/lib/doorkeeper/request/password.rb +3 -2
- data/lib/doorkeeper/request/refresh_token.rb +5 -4
- data/lib/doorkeeper/request/strategy.rb +2 -2
- data/lib/doorkeeper/request.rb +49 -12
- data/lib/doorkeeper/server.rb +5 -5
- data/lib/doorkeeper/stale_records_cleaner.rb +4 -4
- data/lib/doorkeeper/version.rb +2 -6
- data/lib/doorkeeper.rb +112 -81
- data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +2 -2
- data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/lib/generators/doorkeeper/migration_generator.rb +1 -1
- data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +2 -2
- 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 +99 -14
- data/lib/generators/doorkeeper/templates/migration.rb.erb +14 -5
- metadata +37 -306
- 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 -273
- data/spec/controllers/authorizations_controller_spec.rb +0 -608
- data/spec/controllers/protected_resources_controller_spec.rb +0 -353
- 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/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/config.ru +0 -6
- 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 -739
- 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 -168
- data/spec/lib/oauth/base_request_spec.rb +0 -222
- data/spec/lib/oauth/base_response_spec.rb +0 -47
- data/spec/lib/oauth/client/credentials_spec.rb +0 -90
- data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -97
- 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 -29
- data/spec/lib/oauth/client_credentials_request_spec.rb +0 -109
- 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 -36
- data/spec/lib/oauth/error_response_spec.rb +0 -66
- data/spec/lib/oauth/error_spec.rb +0 -23
- data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -22
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -98
- 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 -75
- data/spec/lib/oauth/invalid_token_response_spec.rb +0 -55
- data/spec/lib/oauth/password_access_token_request_spec.rb +0 -192
- data/spec/lib/oauth/pre_authorization_spec.rb +0 -225
- data/spec/lib/oauth/refresh_token_request_spec.rb +0 -178
- data/spec/lib/oauth/scopes_spec.rb +0 -148
- data/spec/lib/oauth/token_request_spec.rb +0 -153
- data/spec/lib/oauth/token_response_spec.rb +0 -86
- data/spec/lib/oauth/token_spec.rb +0 -158
- 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 -163
- data/spec/models/doorkeeper/access_token_spec.rb +0 -622
- data/spec/models/doorkeeper/application_spec.rb +0 -377
- 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 -89
- 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 -513
- 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 -296
- data/spec/requests/flows/refresh_token_spec.rb +0 -233
- data/spec/requests/flows/revoke_token_spec.rb +0 -151
- 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 -57
- 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/http_method_shim.rb +0 -29
- data/spec/support/orm/active_record.rb +0 -5
- data/spec/support/shared/controllers_shared_context.rb +0 -123
- 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
@@ -16,18 +16,20 @@ 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
|
-
instance_eval(&Doorkeeper.
|
22
|
+
instance_eval(&Doorkeeper.config.authenticate_resource_owner)
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
26
|
def resource_owner_from_credentials
|
25
|
-
instance_eval(&Doorkeeper.
|
27
|
+
instance_eval(&Doorkeeper.config.resource_owner_from_credentials)
|
26
28
|
end
|
27
29
|
|
28
30
|
# :doc:
|
29
31
|
def authenticate_admin!
|
30
|
-
instance_eval(&Doorkeeper.
|
32
|
+
instance_eval(&Doorkeeper.config.authenticate_admin)
|
31
33
|
end
|
32
34
|
|
33
35
|
def server
|
@@ -36,36 +38,40 @@ 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
|
43
|
-
@config_methods ||= Doorkeeper.
|
47
|
+
@config_methods ||= Doorkeeper.config.access_token_methods
|
44
48
|
end
|
45
49
|
|
46
50
|
def get_error_response_from_exception(exception)
|
47
51
|
if exception.respond_to?(:response)
|
48
52
|
exception.response
|
49
53
|
elsif exception.type == :invalid_request
|
50
|
-
OAuth::InvalidRequestResponse.new(
|
51
|
-
|
52
|
-
|
54
|
+
OAuth::InvalidRequestResponse.new(
|
55
|
+
name: exception.type,
|
56
|
+
state: params[:state],
|
57
|
+
missing_param: exception.missing_param,
|
58
|
+
)
|
53
59
|
else
|
54
60
|
OAuth::ErrorResponse.new(name: exception.type, state: params[:state])
|
55
61
|
end
|
56
62
|
end
|
57
63
|
|
58
64
|
def handle_token_exception(exception)
|
59
|
-
error = get_error_response_from_exception
|
60
|
-
headers.merge!
|
65
|
+
error = get_error_response_from_exception(exception)
|
66
|
+
headers.merge!(error.headers)
|
61
67
|
self.response_body = error.body.to_json
|
62
|
-
self.status
|
68
|
+
self.status = error.status
|
63
69
|
end
|
64
70
|
|
65
71
|
def skip_authorization?
|
66
72
|
!!instance_exec(
|
67
73
|
[server.current_resource_owner, @pre_auth.client],
|
68
|
-
&Doorkeeper.
|
74
|
+
&Doorkeeper.config.skip_authorization
|
69
75
|
)
|
70
76
|
end
|
71
77
|
|
@@ -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,18 +36,20 @@ 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
|
-
|
43
|
+
by_resource_owner(resource_owner)
|
44
|
+
.where(
|
45
|
+
application_id: application_id,
|
46
|
+
revoked_at: nil,
|
47
|
+
)
|
49
48
|
.update_all(revoked_at: clock.now.utc)
|
50
49
|
end
|
51
50
|
|
52
51
|
# Implements PKCE code_challenge encoding without base64 padding as described in the spec.
|
53
|
-
# https://
|
52
|
+
# https://datatracker.ietf.org/doc/html/rfc7636#appendix-A
|
54
53
|
# Appendix A. Notes on Implementing Base64url Encoding without Padding
|
55
54
|
#
|
56
55
|
# This appendix describes how to implement a base64url-encoding
|
@@ -90,26 +89,31 @@ module Doorkeeper
|
|
90
89
|
# suitable for PKCE validation
|
91
90
|
#
|
92
91
|
def generate_code_challenge(code_verifier)
|
93
|
-
|
94
|
-
padded_result.split("=")[0] # Remove any trailing '='
|
92
|
+
Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier), padding: false)
|
95
93
|
end
|
96
94
|
|
97
95
|
def pkce_supported?
|
98
|
-
|
96
|
+
column_names.include?("code_challenge")
|
99
97
|
end
|
100
98
|
|
101
99
|
##
|
102
100
|
# Determines the secret storing transformer
|
103
101
|
# Unless configured otherwise, uses the plain secret strategy
|
102
|
+
#
|
103
|
+
# @return [Doorkeeper::SecretStoring::Base]
|
104
|
+
#
|
104
105
|
def secret_strategy
|
105
|
-
::Doorkeeper.
|
106
|
+
::Doorkeeper.config.token_secret_strategy
|
106
107
|
end
|
107
108
|
|
108
109
|
##
|
109
110
|
# Determine the fallback storing strategy
|
110
111
|
# Unless configured, there will be no fallback
|
112
|
+
#
|
113
|
+
# @return [Doorkeeper::SecretStoring::Base]
|
114
|
+
#
|
111
115
|
def fallback_secret_strategy
|
112
|
-
::Doorkeeper.
|
116
|
+
::Doorkeeper.config.token_secret_fallback_strategy
|
113
117
|
end
|
114
118
|
end
|
115
119
|
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
|
@@ -40,18 +41,35 @@ module Doorkeeper
|
|
40
41
|
find_by_plaintext_token(:refresh_token, refresh_token)
|
41
42
|
end
|
42
43
|
|
44
|
+
# Returns an instance of the Doorkeeper::AccessToken
|
45
|
+
# found by previous refresh token. Keep in mind that value
|
46
|
+
# of the previous_refresh_token isn't encrypted using
|
47
|
+
# secrets strategy.
|
48
|
+
#
|
49
|
+
# @param previous_refresh_token [#to_s]
|
50
|
+
# previous refresh token value (any object that responds to `#to_s`)
|
51
|
+
#
|
52
|
+
# @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
|
53
|
+
# if there is no record with such refresh token
|
54
|
+
#
|
55
|
+
def by_previous_refresh_token(previous_refresh_token)
|
56
|
+
find_by(refresh_token: previous_refresh_token)
|
57
|
+
end
|
58
|
+
|
43
59
|
# Revokes AccessToken records that have not been revoked and associated
|
44
60
|
# with the specific Application and Resource Owner.
|
45
61
|
#
|
46
62
|
# @param application_id [Integer]
|
47
63
|
# ID of the Application
|
48
|
-
# @param resource_owner [ActiveRecord::Base]
|
49
|
-
# instance of the Resource Owner model
|
64
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
65
|
+
# instance of the Resource Owner model or it's ID
|
50
66
|
#
|
51
67
|
def revoke_all_for(application_id, resource_owner, clock = Time)
|
52
|
-
|
53
|
-
|
54
|
-
|
68
|
+
by_resource_owner(resource_owner)
|
69
|
+
.where(
|
70
|
+
application_id: application_id,
|
71
|
+
revoked_at: nil,
|
72
|
+
)
|
55
73
|
.update_all(revoked_at: clock.now.utc)
|
56
74
|
end
|
57
75
|
|
@@ -60,7 +78,7 @@ module Doorkeeper
|
|
60
78
|
#
|
61
79
|
# @param application [Doorkeeper::Application]
|
62
80
|
# Application instance
|
63
|
-
# @param
|
81
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
64
82
|
# Resource Owner model instance or it's ID
|
65
83
|
# @param scopes [String, Doorkeeper::OAuth::Scopes]
|
66
84
|
# set of scopes
|
@@ -68,22 +86,16 @@ module Doorkeeper
|
|
68
86
|
# @return [Doorkeeper::AccessToken, nil] Access Token instance or
|
69
87
|
# nil if matching record was not found
|
70
88
|
#
|
71
|
-
def matching_token_for(application,
|
72
|
-
|
73
|
-
resource_owner_or_id.id
|
74
|
-
else
|
75
|
-
resource_owner_or_id
|
76
|
-
end
|
77
|
-
|
78
|
-
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)
|
79
91
|
find_matching_token(tokens, application, scopes)
|
80
92
|
end
|
81
93
|
|
82
94
|
# Interface to enumerate access token records in batches in order not
|
83
95
|
# to bloat the memory. Could be overloaded in any ORM extension.
|
84
96
|
#
|
85
|
-
def find_access_token_in_batches(relation,
|
86
|
-
relation.find_in_batches(
|
97
|
+
def find_access_token_in_batches(relation, **args, &block)
|
98
|
+
relation.find_in_batches(**args, &block)
|
87
99
|
end
|
88
100
|
|
89
101
|
# Enumerates AccessToken records in batches to find a matching token.
|
@@ -110,10 +122,11 @@ module Doorkeeper
|
|
110
122
|
return nil unless relation
|
111
123
|
|
112
124
|
matching_tokens = []
|
125
|
+
batch_size = Doorkeeper.configuration.token_lookup_batch_size
|
113
126
|
|
114
|
-
find_access_token_in_batches(relation) do |batch|
|
127
|
+
find_access_token_in_batches(relation, batch_size: batch_size) do |batch|
|
115
128
|
tokens = batch.select do |token|
|
116
|
-
scopes_match?(token.scopes, scopes, application
|
129
|
+
scopes_match?(token.scopes, scopes, application&.scopes)
|
117
130
|
end
|
118
131
|
|
119
132
|
matching_tokens.concat(tokens)
|
@@ -142,8 +155,8 @@ module Doorkeeper
|
|
142
155
|
(token_scopes.sort == param_scopes.sort) &&
|
143
156
|
Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
|
144
157
|
scope_str: param_scopes.to_s,
|
145
|
-
server_scopes: Doorkeeper.
|
146
|
-
app_scopes: app_scopes
|
158
|
+
server_scopes: Doorkeeper.config.scopes,
|
159
|
+
app_scopes: app_scopes,
|
147
160
|
)
|
148
161
|
end
|
149
162
|
|
@@ -153,48 +166,81 @@ module Doorkeeper
|
|
153
166
|
#
|
154
167
|
# @param application [Doorkeeper::Application]
|
155
168
|
# Application instance
|
156
|
-
# @param
|
169
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
157
170
|
# Resource Owner model instance or it's ID
|
158
171
|
# @param scopes [#to_s]
|
159
172
|
# set of scopes (any object that responds to `#to_s`)
|
160
|
-
# @param
|
173
|
+
# @param token_attributes [Hash]
|
174
|
+
# Additional attributes to use when creating a token
|
175
|
+
# @option token_attributes [Integer] :expires_in
|
161
176
|
# token lifetime in seconds
|
162
|
-
# @
|
177
|
+
# @option token_attributes [Boolean] :use_refresh_token
|
163
178
|
# whether to use the refresh token
|
164
179
|
#
|
165
180
|
# @return [Doorkeeper::AccessToken] existing record or a new one
|
166
181
|
#
|
167
|
-
def find_or_create_for(application
|
168
|
-
if Doorkeeper.
|
169
|
-
access_token = matching_token_for(application,
|
182
|
+
def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
|
183
|
+
if Doorkeeper.config.reuse_access_token
|
184
|
+
access_token = matching_token_for(application, resource_owner, scopes)
|
170
185
|
|
171
186
|
return access_token if access_token&.reusable?
|
172
187
|
end
|
173
188
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
scopes: scopes
|
178
|
-
|
179
|
-
use_refresh_token: use_refresh_token
|
189
|
+
create_for(
|
190
|
+
application: application,
|
191
|
+
resource_owner: resource_owner,
|
192
|
+
scopes: scopes,
|
193
|
+
**token_attributes,
|
180
194
|
)
|
181
195
|
end
|
182
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
|
+
|
183
228
|
# Looking for not revoked Access Token records that belongs to specific
|
184
229
|
# Application and Resource Owner.
|
185
230
|
#
|
186
231
|
# @param application_id [Integer]
|
187
232
|
# ID of the Application model instance
|
188
|
-
# @param
|
189
|
-
#
|
233
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
234
|
+
# Resource Owner model instance or it's ID
|
190
235
|
#
|
191
|
-
# @return [
|
236
|
+
# @return [ActiveRecord::Relation]
|
237
|
+
# collection of matching AccessToken objects
|
192
238
|
#
|
193
|
-
def authorized_tokens_for(application_id,
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
239
|
+
def authorized_tokens_for(application_id, resource_owner)
|
240
|
+
by_resource_owner(resource_owner).where(
|
241
|
+
application_id: application_id,
|
242
|
+
revoked_at: nil,
|
243
|
+
)
|
198
244
|
end
|
199
245
|
|
200
246
|
# Convenience method for backwards-compatibility, return the last
|
@@ -202,33 +248,38 @@ module Doorkeeper
|
|
202
248
|
#
|
203
249
|
# @param application_id [Integer]
|
204
250
|
# ID of the Application model instance
|
205
|
-
# @param
|
251
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
206
252
|
# ID of the Resource Owner model instance
|
207
253
|
#
|
208
254
|
# @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
|
209
255
|
# nil if nothing was found
|
210
256
|
#
|
211
|
-
def last_authorized_token_for(application_id,
|
212
|
-
authorized_tokens_for(application_id,
|
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
|
213
261
|
end
|
214
262
|
|
215
263
|
##
|
216
264
|
# Determines the secret storing transformer
|
217
265
|
# Unless configured otherwise, uses the plain secret strategy
|
266
|
+
#
|
267
|
+
# @return [Doorkeeper::SecretStoring::Base]
|
268
|
+
#
|
218
269
|
def secret_strategy
|
219
|
-
::Doorkeeper.
|
270
|
+
::Doorkeeper.config.token_secret_strategy
|
220
271
|
end
|
221
272
|
|
222
273
|
##
|
223
274
|
# Determine the fallback storing strategy
|
224
275
|
# Unless configured, there will be no fallback
|
225
276
|
def fallback_secret_strategy
|
226
|
-
::Doorkeeper.
|
277
|
+
::Doorkeeper.config.token_secret_fallback_strategy
|
227
278
|
end
|
228
279
|
end
|
229
280
|
|
230
281
|
# Access Token type: Bearer.
|
231
|
-
# @see https://
|
282
|
+
# @see https://datatracker.ietf.org/doc/html/rfc6750
|
232
283
|
# The OAuth 2.0 Authorization Framework: Bearer Token Usage
|
233
284
|
#
|
234
285
|
def token_type
|
@@ -250,7 +301,11 @@ module Doorkeeper
|
|
250
301
|
expires_in: expires_in_seconds,
|
251
302
|
application: { uid: application.try(:uid) },
|
252
303
|
created_at: created_at.to_i,
|
253
|
-
}
|
304
|
+
}.tap do |json|
|
305
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
306
|
+
json[:resource_owner_type] = resource_owner_type
|
307
|
+
end
|
308
|
+
end
|
254
309
|
end
|
255
310
|
|
256
311
|
# Indicates whether the token instance have the same credential
|
@@ -262,7 +317,22 @@ module Doorkeeper
|
|
262
317
|
#
|
263
318
|
def same_credential?(access_token)
|
264
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
|
265
334
|
resource_owner_id == access_token.resource_owner_id
|
335
|
+
end
|
266
336
|
end
|
267
337
|
|
268
338
|
# Indicates if token is acceptable for specific scopes.
|
@@ -300,8 +370,28 @@ module Doorkeeper
|
|
300
370
|
end
|
301
371
|
end
|
302
372
|
|
373
|
+
# Revokes token with `:refresh_token` equal to `:previous_refresh_token`
|
374
|
+
# and clears `:previous_refresh_token` attribute.
|
375
|
+
#
|
376
|
+
def revoke_previous_refresh_token!
|
377
|
+
return if !self.class.refresh_token_revoked_on_use? || previous_refresh_token.blank?
|
378
|
+
|
379
|
+
old_refresh_token&.revoke
|
380
|
+
update_attribute(:previous_refresh_token, "")
|
381
|
+
end
|
382
|
+
|
303
383
|
private
|
304
384
|
|
385
|
+
# Searches for Access Token record with `:refresh_token` equal to
|
386
|
+
# `:previous_refresh_token` value.
|
387
|
+
#
|
388
|
+
# @return [Doorkeeper::AccessToken, nil]
|
389
|
+
# Access Token record or nil if nothing found
|
390
|
+
#
|
391
|
+
def old_refresh_token
|
392
|
+
@old_refresh_token ||= self.class.by_previous_refresh_token(previous_refresh_token)
|
393
|
+
end
|
394
|
+
|
305
395
|
# Generates refresh token with UniqueToken generator.
|
306
396
|
#
|
307
397
|
# @return [String] refresh token value
|
@@ -312,7 +402,7 @@ module Doorkeeper
|
|
312
402
|
end
|
313
403
|
|
314
404
|
# Generates and sets the token value with the
|
315
|
-
# configured Generator class (see Doorkeeper.
|
405
|
+
# configured Generator class (see Doorkeeper.config).
|
316
406
|
#
|
317
407
|
# @return [String] generated token value
|
318
408
|
#
|
@@ -324,20 +414,32 @@ module Doorkeeper
|
|
324
414
|
def generate_token
|
325
415
|
self.created_at ||= Time.now.utc
|
326
416
|
|
327
|
-
@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
|
+
{
|
328
429
|
resource_owner_id: resource_owner_id,
|
329
430
|
scopes: scopes,
|
330
431
|
application: application,
|
331
432
|
expires_in: expires_in,
|
332
|
-
created_at: created_at
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
433
|
+
created_at: created_at,
|
434
|
+
}.tap do |attributes|
|
435
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
436
|
+
attributes[:resource_owner] = resource_owner
|
437
|
+
end
|
438
|
+
end
|
337
439
|
end
|
338
440
|
|
339
441
|
def token_generator
|
340
|
-
generator_name = Doorkeeper.
|
442
|
+
generator_name = Doorkeeper.config.access_token_generator
|
341
443
|
generator = generator_name.constantize
|
342
444
|
|
343
445
|
return generator if generator.respond_to?(:generate)
|
@@ -20,8 +20,8 @@ module Doorkeeper
|
|
20
20
|
# @param uid [#to_s] UID (any object that responds to `#to_s`)
|
21
21
|
# @param secret [#to_s] secret (any object that responds to `#to_s`)
|
22
22
|
#
|
23
|
-
# @return [Doorkeeper::Application, nil]
|
24
|
-
# if there is no record with such credentials
|
23
|
+
# @return [Doorkeeper::Application, nil]
|
24
|
+
# Application instance or nil if there is no record with such credentials
|
25
25
|
#
|
26
26
|
def by_uid_and_secret(uid, secret)
|
27
27
|
app = by_uid(uid)
|
@@ -47,22 +47,23 @@ module Doorkeeper
|
|
47
47
|
# Determines the secret storing transformer
|
48
48
|
# Unless configured otherwise, uses the plain secret strategy
|
49
49
|
def secret_strategy
|
50
|
-
::Doorkeeper.
|
50
|
+
::Doorkeeper.config.application_secret_strategy
|
51
51
|
end
|
52
52
|
|
53
53
|
##
|
54
54
|
# Determine the fallback storing strategy
|
55
55
|
# Unless configured, there will be no fallback
|
56
56
|
def fallback_secret_strategy
|
57
|
-
::Doorkeeper.
|
57
|
+
::Doorkeeper.config.application_secret_fallback_strategy
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
# Set an application's valid redirect URIs.
|
62
62
|
#
|
63
|
-
# @param uris [String, Array] Newline-separated string or array the URI(s)
|
63
|
+
# @param uris [String, Array<String>] Newline-separated string or array the URI(s)
|
64
|
+
#
|
65
|
+
# @return [String] The redirect URI(s) separated by newlines.
|
64
66
|
#
|
65
|
-
# @return [String] The redirect URI(s) seperated by newlines.
|
66
67
|
def redirect_uri=(uris)
|
67
68
|
super(uris.is_a?(Array) ? uris.join("\n") : uris)
|
68
69
|
end
|
@@ -72,7 +73,7 @@ module Doorkeeper
|
|
72
73
|
# @param input [#to_s] Plain secret provided by user
|
73
74
|
# (any object that responds to `#to_s`)
|
74
75
|
#
|
75
|
-
# @return [
|
76
|
+
# @return [Boolean] Whether the given secret matches the stored secret
|
76
77
|
# of this application.
|
77
78
|
#
|
78
79
|
def secret_matches?(input)
|
@@ -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
|
@@ -11,7 +11,7 @@ module Doorkeeper
|
|
11
11
|
return false if expired?
|
12
12
|
return true unless expires_in
|
13
13
|
|
14
|
-
threshold_limit = 100 - Doorkeeper.
|
14
|
+
threshold_limit = 100 - Doorkeeper.config.token_reuse_limit
|
15
15
|
expires_in_seconds >= threshold_limit * expires_in / 100
|
16
16
|
end
|
17
17
|
end
|