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
@@ -11,9 +11,8 @@ module Doorkeeper
|
|
11
11
|
validate :client_match, error: :invalid_grant
|
12
12
|
validate :scope, error: :invalid_scope
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
attr_reader :missing_param
|
14
|
+
attr_reader :access_token, :client, :credentials, :refresh_token
|
15
|
+
attr_reader :missing_param
|
17
16
|
|
18
17
|
def initialize(server, refresh_token, credentials, parameters = {})
|
19
18
|
@server = server
|
@@ -27,7 +26,7 @@ module Doorkeeper
|
|
27
26
|
private
|
28
27
|
|
29
28
|
def load_client(credentials)
|
30
|
-
|
29
|
+
server_config.application_model.by_uid_and_secret(credentials.uid, credentials.secret)
|
31
30
|
end
|
32
31
|
|
33
32
|
def before_successful_response
|
@@ -42,7 +41,7 @@ module Doorkeeper
|
|
42
41
|
end
|
43
42
|
|
44
43
|
def refresh_token_revoked_on_use?
|
45
|
-
|
44
|
+
server_config.access_token_model.refresh_token_revoked_on_use?
|
46
45
|
end
|
47
46
|
|
48
47
|
def default_scopes
|
@@ -50,30 +49,40 @@ module Doorkeeper
|
|
50
49
|
end
|
51
50
|
|
52
51
|
def create_access_token
|
53
|
-
|
54
|
-
end
|
52
|
+
attributes = {}
|
55
53
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
expires_in: access_token_expires_in,
|
62
|
-
use_refresh_token: true,
|
63
|
-
}.tap do |attributes|
|
64
|
-
if refresh_token_revoked_on_use?
|
65
|
-
attributes[:previous_refresh_token] = refresh_token.refresh_token
|
54
|
+
resource_owner =
|
55
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
56
|
+
refresh_token.resource_owner
|
57
|
+
else
|
58
|
+
refresh_token.resource_owner_id
|
66
59
|
end
|
60
|
+
|
61
|
+
if refresh_token_revoked_on_use?
|
62
|
+
attributes[:previous_refresh_token] = refresh_token.refresh_token
|
67
63
|
end
|
68
|
-
end
|
69
64
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
65
|
+
# RFC6749
|
66
|
+
# 1.5. Refresh Token
|
67
|
+
#
|
68
|
+
# Refresh tokens are issued to the client by the authorization server and are
|
69
|
+
# used to obtain a new access token when the current access token
|
70
|
+
# becomes invalid or expires, or to obtain additional access tokens
|
71
|
+
# with identical or narrower scope (access tokens may have a shorter
|
72
|
+
# lifetime and fewer permissions than authorized by the resource
|
73
|
+
# owner).
|
74
|
+
#
|
75
|
+
# Here we assume that TTL of the token received after refreshing should be
|
76
|
+
# the same as that of the original token.
|
77
|
+
#
|
78
|
+
@access_token = server_config.access_token_model.create_for(
|
79
|
+
application: refresh_token.application,
|
80
|
+
resource_owner: resource_owner,
|
81
|
+
scopes: scopes,
|
82
|
+
expires_in: refresh_token.expires_in,
|
83
|
+
use_refresh_token: true,
|
84
|
+
**attributes,
|
75
85
|
)
|
76
|
-
Authorization::Token.access_token_expires_in(server, context)
|
77
86
|
end
|
78
87
|
|
79
88
|
def validate_token_presence
|
@@ -92,7 +101,7 @@ module Doorkeeper
|
|
92
101
|
client.present?
|
93
102
|
end
|
94
103
|
|
95
|
-
# @see https://
|
104
|
+
# @see https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
|
96
105
|
#
|
97
106
|
def validate_client_match
|
98
107
|
return true if refresh_token.application_id.blank?
|
@@ -104,7 +113,7 @@ module Doorkeeper
|
|
104
113
|
if @original_scopes.present?
|
105
114
|
ScopeChecker.valid?(
|
106
115
|
scope_str: @original_scopes,
|
107
|
-
server_scopes: refresh_token.scopes
|
116
|
+
server_scopes: refresh_token.scopes,
|
108
117
|
)
|
109
118
|
else
|
110
119
|
true
|
@@ -8,15 +8,14 @@ module Doorkeeper
|
|
8
8
|
methods.inject(nil) do |_, method|
|
9
9
|
method = self.method(method) if method.is_a?(Symbol)
|
10
10
|
credentials = method.call(request)
|
11
|
-
break credentials
|
11
|
+
break credentials if credentials.present?
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
def authenticate(request, *methods)
|
16
16
|
if (token = from_request(request, *methods))
|
17
|
-
access_token =
|
18
|
-
|
19
|
-
if access_token.present? && refresh_token_enabled
|
17
|
+
access_token = Doorkeeper.config.access_token_model.by_token(token)
|
18
|
+
if access_token.present? && Doorkeeper.config.refresh_token_enabled?
|
20
19
|
access_token.revoke_previous_refresh_token!
|
21
20
|
end
|
22
21
|
access_token
|
@@ -33,13 +32,13 @@ module Doorkeeper
|
|
33
32
|
|
34
33
|
def from_bearer_authorization(request)
|
35
34
|
pattern = /^Bearer /i
|
36
|
-
header
|
35
|
+
header = request.authorization
|
37
36
|
token_from_header(header, pattern) if match?(header, pattern)
|
38
37
|
end
|
39
38
|
|
40
39
|
def from_basic_authorization(request)
|
41
40
|
pattern = /^Basic /i
|
42
|
-
header
|
41
|
+
header = request.authorization
|
43
42
|
token_from_basic_header(header, pattern) if match?(header, pattern)
|
44
43
|
end
|
45
44
|
|
@@ -55,7 +54,7 @@ module Doorkeeper
|
|
55
54
|
end
|
56
55
|
|
57
56
|
def token_from_header(header, pattern)
|
58
|
-
header.gsub
|
57
|
+
header.gsub(pattern, "")
|
59
58
|
end
|
60
59
|
|
61
60
|
def match?(header, pattern)
|
@@ -4,11 +4,8 @@ module Doorkeeper
|
|
4
4
|
module OAuth
|
5
5
|
# RFC7662 OAuth 2.0 Token Introspection
|
6
6
|
#
|
7
|
-
# @see https://
|
7
|
+
# @see https://datatracker.ietf.org/doc/html/rfc7662
|
8
8
|
class TokenIntrospection
|
9
|
-
attr_reader :server, :token
|
10
|
-
attr_reader :error, :invalid_request_reason
|
11
|
-
|
12
9
|
def initialize(server, token)
|
13
10
|
@server = server
|
14
11
|
@token = token
|
@@ -38,6 +35,9 @@ module Doorkeeper
|
|
38
35
|
|
39
36
|
private
|
40
37
|
|
38
|
+
attr_reader :server, :token
|
39
|
+
attr_reader :error, :invalid_request_reason
|
40
|
+
|
41
41
|
# If the protected resource uses OAuth 2.0 client credentials to
|
42
42
|
# authenticate to the introspection endpoint and its credentials are
|
43
43
|
# invalid, the authorization server responds with an HTTP 401
|
@@ -94,7 +94,7 @@ module Doorkeeper
|
|
94
94
|
client_id: @token.try(:application).try(:uid),
|
95
95
|
token_type: @token.token_type,
|
96
96
|
exp: @token.expires_at.to_i,
|
97
|
-
iat: @token.created_at.to_i
|
97
|
+
iat: @token.created_at.to_i,
|
98
98
|
)
|
99
99
|
end
|
100
100
|
|
@@ -107,7 +107,7 @@ module Doorkeeper
|
|
107
107
|
# authorization server SHOULD NOT include any additional information
|
108
108
|
# about an inactive token, including why the token is inactive.
|
109
109
|
#
|
110
|
-
# @see https://
|
110
|
+
# @see https://datatracker.ietf.org/doc/html/rfc7662 2.2. Introspection Response
|
111
111
|
#
|
112
112
|
def failure_response
|
113
113
|
{
|
@@ -174,28 +174,24 @@ module Doorkeeper
|
|
174
174
|
authorized_token.token == @token&.token
|
175
175
|
end
|
176
176
|
|
177
|
-
#
|
177
|
+
# Config constraints for introspection in Doorkeeper.config.allow_token_introspection
|
178
178
|
def token_introspection_allowed?(auth_client: nil, auth_token: nil)
|
179
|
-
allow_introspection = Doorkeeper.
|
179
|
+
allow_introspection = Doorkeeper.config.allow_token_introspection
|
180
180
|
return allow_introspection unless allow_introspection.respond_to?(:call)
|
181
181
|
|
182
|
-
allow_introspection.call(
|
183
|
-
@token,
|
184
|
-
auth_client,
|
185
|
-
auth_token
|
186
|
-
)
|
182
|
+
allow_introspection.call(@token, auth_client, auth_token)
|
187
183
|
end
|
188
184
|
|
189
185
|
# Allows to customize introspection response.
|
190
186
|
# Provides context (controller) and token for generating developer-specific
|
191
187
|
# response.
|
192
188
|
#
|
193
|
-
# @see https://
|
189
|
+
# @see https://datatracker.ietf.org/doc/html/rfc7662#section-2.2
|
194
190
|
#
|
195
191
|
def customize_response(response)
|
196
|
-
customized_response = Doorkeeper.
|
192
|
+
customized_response = Doorkeeper.config.custom_introspection_response.call(
|
197
193
|
token,
|
198
|
-
server.context
|
194
|
+
server.context,
|
199
195
|
)
|
200
196
|
return response if customized_response.blank?
|
201
197
|
|
@@ -3,16 +3,16 @@
|
|
3
3
|
module Doorkeeper
|
4
4
|
module OAuth
|
5
5
|
class TokenRequest
|
6
|
-
|
6
|
+
attr_reader :pre_auth, :resource_owner
|
7
7
|
|
8
8
|
def initialize(pre_auth, resource_owner)
|
9
|
-
@pre_auth
|
9
|
+
@pre_auth = pre_auth
|
10
10
|
@resource_owner = resource_owner
|
11
11
|
end
|
12
12
|
|
13
13
|
def authorize
|
14
14
|
auth = Authorization::Token.new(pre_auth, resource_owner)
|
15
|
-
auth.issue_token
|
15
|
+
auth.issue_token!
|
16
16
|
CodeResponse.new(pre_auth, auth, response_on_fragment: true)
|
17
17
|
end
|
18
18
|
|
@@ -1,48 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
class AccessGrant < ActiveRecord::Base
|
5
|
-
self.table_name = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}"
|
6
|
-
|
7
|
-
include AccessGrantMixin
|
8
|
-
|
9
|
-
belongs_to :application, class_name: "Doorkeeper::Application",
|
10
|
-
optional: true, inverse_of: :access_grants
|
11
|
-
|
12
|
-
validates :resource_owner_id,
|
13
|
-
:application_id,
|
14
|
-
:token,
|
15
|
-
:expires_in,
|
16
|
-
:redirect_uri,
|
17
|
-
presence: true
|
18
|
-
|
19
|
-
validates :token, uniqueness: { case_sensitive: true }
|
3
|
+
require "doorkeeper/orm/active_record/mixins/access_grant"
|
20
4
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
# The stored refresh_token may be mapped and not available in cleartext.
|
25
|
-
#
|
26
|
-
# Some strategies allow restoring stored secrets (e.g. symmetric encryption)
|
27
|
-
# while hashing strategies do not, so you cannot rely on this value
|
28
|
-
# returning a present value for persisted tokens.
|
29
|
-
def plaintext_token
|
30
|
-
if secret_strategy.allows_restoring_secrets?
|
31
|
-
secret_strategy.restore_secret(self, :token)
|
32
|
-
else
|
33
|
-
@raw_token
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
# Generates token value with UniqueToken class.
|
40
|
-
#
|
41
|
-
# @return [String] token value
|
42
|
-
#
|
43
|
-
def generate_token
|
44
|
-
@raw_token = UniqueToken.generate
|
45
|
-
secret_strategy.store_secret(self, :token, @raw_token)
|
46
|
-
end
|
5
|
+
module Doorkeeper
|
6
|
+
class AccessGrant < ::ActiveRecord::Base
|
7
|
+
include Doorkeeper::Orm::ActiveRecord::Mixins::AccessGrant
|
47
8
|
end
|
48
9
|
end
|
@@ -1,40 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
class AccessToken < ActiveRecord::Base
|
5
|
-
self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}"
|
6
|
-
|
7
|
-
include AccessTokenMixin
|
8
|
-
|
9
|
-
belongs_to :application, class_name: "Doorkeeper::Application",
|
10
|
-
inverse_of: :access_tokens, optional: true
|
11
|
-
|
12
|
-
validates :token, presence: true, uniqueness: { case_sensitive: true }
|
13
|
-
validates :refresh_token, uniqueness: { case_sensitive: true }, if: :use_refresh_token?
|
3
|
+
require "doorkeeper/orm/active_record/mixins/access_token"
|
14
4
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
before_validation :generate_token, on: :create
|
20
|
-
before_validation :generate_refresh_token,
|
21
|
-
on: :create, if: :use_refresh_token?
|
22
|
-
|
23
|
-
# Searches for not revoked Access Tokens associated with the
|
24
|
-
# specific Resource Owner.
|
25
|
-
#
|
26
|
-
# @param resource_owner [ActiveRecord::Base]
|
27
|
-
# Resource Owner model instance
|
28
|
-
#
|
29
|
-
# @return [ActiveRecord::Relation]
|
30
|
-
# active Access Tokens for Resource Owner
|
31
|
-
#
|
32
|
-
def self.active_for(resource_owner)
|
33
|
-
where(resource_owner_id: resource_owner.id, revoked_at: nil)
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.refresh_token_revoked_on_use?
|
37
|
-
column_names.include?("previous_refresh_token")
|
38
|
-
end
|
5
|
+
module Doorkeeper
|
6
|
+
class AccessToken < ::ActiveRecord::Base
|
7
|
+
include Doorkeeper::Orm::ActiveRecord::Mixins::AccessToken
|
39
8
|
end
|
40
9
|
end
|
@@ -1,100 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}"
|
6
|
-
|
7
|
-
include ApplicationMixin
|
8
|
-
|
9
|
-
has_many :access_grants, dependent: :delete_all, class_name: "Doorkeeper::AccessGrant"
|
10
|
-
has_many :access_tokens, dependent: :delete_all, class_name: "Doorkeeper::AccessToken"
|
11
|
-
|
12
|
-
validates :name, :secret, :uid, presence: true
|
13
|
-
validates :uid, uniqueness: { case_sensitive: true }
|
14
|
-
validates :redirect_uri, "doorkeeper/redirect_uri": true
|
15
|
-
validates :confidential, inclusion: { in: [true, false] }
|
16
|
-
|
17
|
-
validate :scopes_match_configured, if: :enforce_scopes?
|
18
|
-
|
19
|
-
before_validation :generate_uid, :generate_secret, on: :create
|
20
|
-
|
21
|
-
has_many :authorized_tokens, -> { where(revoked_at: nil) }, class_name: "AccessToken"
|
22
|
-
has_many :authorized_applications, through: :authorized_tokens, source: :application
|
23
|
-
|
24
|
-
# Returns Applications associated with active (not revoked) Access Tokens
|
25
|
-
# that are owned by the specific Resource Owner.
|
26
|
-
#
|
27
|
-
# @param resource_owner [ActiveRecord::Base]
|
28
|
-
# Resource Owner model instance
|
29
|
-
#
|
30
|
-
# @return [ActiveRecord::Relation]
|
31
|
-
# Applications authorized for the Resource Owner
|
32
|
-
#
|
33
|
-
def self.authorized_for(resource_owner)
|
34
|
-
resource_access_tokens = AccessToken.active_for(resource_owner)
|
35
|
-
where(id: resource_access_tokens.select(:application_id).distinct)
|
36
|
-
end
|
37
|
-
|
38
|
-
# Revokes AccessToken and AccessGrant records that have not been revoked and
|
39
|
-
# associated with the specific Application and Resource Owner.
|
40
|
-
#
|
41
|
-
# @param resource_owner [ActiveRecord::Base]
|
42
|
-
# instance of the Resource Owner model
|
43
|
-
#
|
44
|
-
def self.revoke_tokens_and_grants_for(id, resource_owner)
|
45
|
-
AccessToken.revoke_all_for(id, resource_owner)
|
46
|
-
AccessGrant.revoke_all_for(id, resource_owner)
|
47
|
-
end
|
3
|
+
require "doorkeeper/orm/active_record/redirect_uri_validator"
|
4
|
+
require "doorkeeper/orm/active_record/mixins/application"
|
48
5
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
def renew_secret
|
53
|
-
@raw_secret = UniqueToken.generate
|
54
|
-
secret_strategy.store_secret(self, :secret, @raw_secret)
|
55
|
-
end
|
56
|
-
|
57
|
-
# We keep a volatile copy of the raw secret for initial communication
|
58
|
-
# The stored refresh_token may be mapped and not available in cleartext.
|
59
|
-
#
|
60
|
-
# Some strategies allow restoring stored secrets (e.g. symmetric encryption)
|
61
|
-
# while hashing strategies do not, so you cannot rely on this value
|
62
|
-
# returning a present value for persisted tokens.
|
63
|
-
def plaintext_secret
|
64
|
-
if secret_strategy.allows_restoring_secrets?
|
65
|
-
secret_strategy.restore_secret(self, :secret)
|
66
|
-
else
|
67
|
-
@raw_secret
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def to_json(options = nil)
|
72
|
-
serializable_hash(except: :secret)
|
73
|
-
.merge(secret: plaintext_secret)
|
74
|
-
.to_json(options)
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
def generate_uid
|
80
|
-
self.uid = UniqueToken.generate if uid.blank?
|
81
|
-
end
|
82
|
-
|
83
|
-
def generate_secret
|
84
|
-
return unless secret.blank?
|
85
|
-
renew_secret
|
86
|
-
end
|
87
|
-
|
88
|
-
def scopes_match_configured
|
89
|
-
if scopes.present? &&
|
90
|
-
!ScopeChecker.valid?(scope_str: scopes.to_s,
|
91
|
-
server_scopes: Doorkeeper.configuration.scopes)
|
92
|
-
errors.add(:scopes, :not_match_configured)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def enforce_scopes?
|
97
|
-
Doorkeeper.configuration.enforce_configured_scopes?
|
98
|
-
end
|
6
|
+
module Doorkeeper
|
7
|
+
class Application < ::ActiveRecord::Base
|
8
|
+
include ::Doorkeeper::Orm::ActiveRecord::Mixins::Application
|
99
9
|
end
|
100
10
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper::Orm::ActiveRecord::Mixins
|
4
|
+
module AccessGrant
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
self.table_name = compute_doorkeeper_table_name
|
9
|
+
self.strict_loading_by_default = false if respond_to?(:strict_loading_by_default)
|
10
|
+
|
11
|
+
include ::Doorkeeper::AccessGrantMixin
|
12
|
+
|
13
|
+
belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
|
14
|
+
optional: true,
|
15
|
+
inverse_of: :access_grants
|
16
|
+
|
17
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
18
|
+
belongs_to :resource_owner, polymorphic: true, optional: false
|
19
|
+
else
|
20
|
+
validates :resource_owner_id, presence: true
|
21
|
+
end
|
22
|
+
|
23
|
+
validates :application_id,
|
24
|
+
:token,
|
25
|
+
:expires_in,
|
26
|
+
:redirect_uri,
|
27
|
+
presence: true
|
28
|
+
|
29
|
+
validates :token, uniqueness: { case_sensitive: true }
|
30
|
+
|
31
|
+
before_validation :generate_token, on: :create
|
32
|
+
|
33
|
+
# We keep a volatile copy of the raw token for initial communication
|
34
|
+
# The stored refresh_token may be mapped and not available in cleartext.
|
35
|
+
#
|
36
|
+
# Some strategies allow restoring stored secrets (e.g. symmetric encryption)
|
37
|
+
# while hashing strategies do not, so you cannot rely on this value
|
38
|
+
# returning a present value for persisted tokens.
|
39
|
+
def plaintext_token
|
40
|
+
if secret_strategy.allows_restoring_secrets?
|
41
|
+
secret_strategy.restore_secret(self, :token)
|
42
|
+
else
|
43
|
+
@raw_token
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Generates token value with UniqueToken class.
|
50
|
+
#
|
51
|
+
# @return [String] token value
|
52
|
+
#
|
53
|
+
def generate_token
|
54
|
+
@raw_token = Doorkeeper::OAuth::Helpers::UniqueToken.generate
|
55
|
+
secret_strategy.store_secret(self, :token, @raw_token)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module ClassMethods
|
60
|
+
private
|
61
|
+
|
62
|
+
def compute_doorkeeper_table_name
|
63
|
+
table_name = "oauth_access_grant"
|
64
|
+
table_name = table_name.pluralize if pluralize_table_names
|
65
|
+
"#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper::Orm::ActiveRecord::Mixins
|
4
|
+
module AccessToken
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
self.table_name = compute_doorkeeper_table_name
|
9
|
+
self.strict_loading_by_default = false if respond_to?(:strict_loading_by_default)
|
10
|
+
|
11
|
+
include ::Doorkeeper::AccessTokenMixin
|
12
|
+
|
13
|
+
belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
|
14
|
+
inverse_of: :access_tokens,
|
15
|
+
optional: true
|
16
|
+
|
17
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
18
|
+
belongs_to :resource_owner, polymorphic: true, optional: true
|
19
|
+
end
|
20
|
+
|
21
|
+
validates :token, presence: true, uniqueness: { case_sensitive: true }
|
22
|
+
validates :refresh_token, uniqueness: { case_sensitive: true }, if: :use_refresh_token?
|
23
|
+
|
24
|
+
# @attr_writer [Boolean, nil] use_refresh_token
|
25
|
+
# indicates the possibility of using refresh token
|
26
|
+
attr_writer :use_refresh_token
|
27
|
+
|
28
|
+
before_validation :generate_token, on: :create
|
29
|
+
before_validation :generate_refresh_token,
|
30
|
+
on: :create, if: :use_refresh_token?
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
# Searches for not revoked Access Tokens associated with the
|
35
|
+
# specific Resource Owner.
|
36
|
+
#
|
37
|
+
# @param resource_owner [ActiveRecord::Base]
|
38
|
+
# Resource Owner model instance
|
39
|
+
#
|
40
|
+
# @return [ActiveRecord::Relation]
|
41
|
+
# active Access Tokens for Resource Owner
|
42
|
+
#
|
43
|
+
def active_for(resource_owner)
|
44
|
+
by_resource_owner(resource_owner).where(revoked_at: nil)
|
45
|
+
end
|
46
|
+
|
47
|
+
def refresh_token_revoked_on_use?
|
48
|
+
column_names.include?("previous_refresh_token")
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def compute_doorkeeper_table_name
|
54
|
+
table_name = "oauth_access_token"
|
55
|
+
table_name = table_name.pluralize if pluralize_table_names
|
56
|
+
"#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|