doorkeeper 3.1.0 → 5.6.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1079 -0
- data/README.md +114 -326
- data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
- data/app/controllers/doorkeeper/application_controller.rb +7 -6
- data/app/controllers/doorkeeper/application_metal_controller.rb +9 -12
- data/app/controllers/doorkeeper/applications_controller.rb +66 -21
- data/app/controllers/doorkeeper/authorizations_controller.rb +100 -18
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +23 -4
- data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
- data/app/controllers/doorkeeper/tokens_controller.rb +138 -22
- data/app/helpers/doorkeeper/dashboard_helper.rb +15 -9
- data/app/views/doorkeeper/applications/_delete_form.html.erb +4 -3
- data/app/views/doorkeeper/applications/_form.html.erb +33 -21
- data/app/views/doorkeeper/applications/edit.html.erb +1 -1
- data/app/views/doorkeeper/applications/index.html.erb +18 -6
- data/app/views/doorkeeper/applications/new.html.erb +1 -1
- data/app/views/doorkeeper/applications/show.html.erb +40 -16
- data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
- data/app/views/doorkeeper/authorizations/new.html.erb +17 -11
- data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
- data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
- data/config/locales/en.yml +37 -9
- data/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/lib/doorkeeper/config/option.rb +82 -0
- data/lib/doorkeeper/config/validations.rb +53 -0
- data/lib/doorkeeper/config.rb +602 -142
- data/lib/doorkeeper/engine.rb +22 -7
- data/lib/doorkeeper/errors.rb +37 -10
- 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/authorization_decorator.rb +6 -4
- data/lib/doorkeeper/grape/helpers.rb +24 -12
- data/lib/doorkeeper/helpers/controller.rb +49 -27
- data/lib/doorkeeper/models/access_grant_mixin.rb +99 -16
- data/lib/doorkeeper/models/access_token_mixin.rb +386 -77
- data/lib/doorkeeper/models/application_mixin.rb +73 -30
- data/lib/doorkeeper/models/concerns/accessible.rb +6 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +20 -6
- data/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +88 -0
- data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +4 -2
- data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +13 -2
- data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
- data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
- data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
- data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +72 -28
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +22 -18
- data/lib/doorkeeper/oauth/authorization_code_request.rb +64 -14
- data/lib/doorkeeper/oauth/base_request.rb +66 -0
- data/lib/doorkeeper/oauth/base_response.rb +31 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +23 -10
- data/lib/doorkeeper/oauth/client.rb +10 -12
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +48 -4
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +17 -9
- data/lib/doorkeeper/oauth/client_credentials/validator.rb +55 -0
- data/lib/doorkeeper/oauth/client_credentials_request.rb +14 -15
- data/lib/doorkeeper/oauth/code_request.rb +8 -12
- data/lib/doorkeeper/oauth/code_response.rb +31 -19
- data/lib/doorkeeper/oauth/error.rb +5 -3
- data/lib/doorkeeper/oauth/error_response.rb +41 -20
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +11 -3
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +24 -19
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +55 -4
- data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
- data/lib/doorkeeper/oauth/invalid_token_response.rb +31 -5
- data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +46 -18
- data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
- data/lib/doorkeeper/oauth/refresh_token_request.rb +67 -30
- data/lib/doorkeeper/oauth/scopes.rb +26 -12
- data/lib/doorkeeper/oauth/token.rb +28 -25
- data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
- data/lib/doorkeeper/oauth/token_request.rb +8 -21
- data/lib/doorkeeper/oauth/token_response.rb +14 -10
- data/lib/doorkeeper/oauth.rb +13 -0
- data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
- data/lib/doorkeeper/orm/active_record/access_token.rb +5 -17
- data/lib/doorkeeper/orm/active_record/application.rb +6 -20
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +69 -0
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +81 -0
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +214 -0
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
- data/lib/doorkeeper/orm/active_record.rb +36 -26
- data/lib/doorkeeper/rails/helpers.rb +14 -15
- data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/lib/doorkeeper/rails/routes/mapper.rb +4 -2
- data/lib/doorkeeper/rails/routes/mapping.rb +10 -8
- data/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/lib/doorkeeper/rails/routes.rb +45 -28
- data/lib/doorkeeper/rake/db.rake +40 -0
- data/lib/doorkeeper/rake/setup.rake +6 -0
- data/lib/doorkeeper/rake.rb +14 -0
- data/lib/doorkeeper/request/authorization_code.rb +12 -4
- data/lib/doorkeeper/request/client_credentials.rb +3 -3
- data/lib/doorkeeper/request/code.rb +1 -1
- data/lib/doorkeeper/request/password.rb +5 -4
- data/lib/doorkeeper/request/refresh_token.rb +6 -5
- data/lib/doorkeeper/request/strategy.rb +4 -2
- data/lib/doorkeeper/request/token.rb +1 -1
- data/lib/doorkeeper/request.rb +62 -29
- data/lib/doorkeeper/secret_storing/base.rb +64 -0
- data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
- data/lib/doorkeeper/secret_storing/plain.rb +33 -0
- data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
- data/lib/doorkeeper/server.rb +9 -19
- data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
- data/lib/doorkeeper/validations.rb +5 -2
- data/lib/doorkeeper/version.rb +12 -1
- data/lib/doorkeeper.rb +112 -56
- data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
- data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/lib/generators/doorkeeper/install_generator.rb +19 -9
- data/lib/generators/doorkeeper/migration_generator.rb +27 -10
- data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +41 -0
- data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +13 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
- data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +417 -32
- data/lib/generators/doorkeeper/templates/migration.rb.erb +88 -0
- data/lib/generators/doorkeeper/views_generator.rb +8 -4
- data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
- metadata +163 -280
- data/.gitignore +0 -14
- data/.hound.yml +0 -13
- data/.rspec +0 -1
- data/.travis.yml +0 -22
- data/CONTRIBUTING.md +0 -45
- data/Gemfile +0 -10
- data/NEWS.md +0 -525
- data/RELEASING.md +0 -17
- data/Rakefile +0 -20
- data/app/validators/redirect_uri_validator.rb +0 -34
- data/doorkeeper.gemspec +0 -27
- data/lib/doorkeeper/oauth/client/methods.rb +0 -18
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
- data/lib/doorkeeper/oauth/request_concern.rb +0 -48
- data/lib/generators/doorkeeper/application_scopes_generator.rb +0 -34
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
- data/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb +0 -5
- data/lib/generators/doorkeeper/templates/migration.rb +0 -50
- data/spec/controllers/applications_controller_spec.rb +0 -58
- data/spec/controllers/authorizations_controller_spec.rb +0 -203
- data/spec/controllers/protected_resources_controller_spec.rb +0 -271
- data/spec/controllers/token_info_controller_spec.rb +0 -52
- data/spec/controllers/tokens_controller_spec.rb +0 -88
- data/spec/dummy/Rakefile +0 -7
- data/spec/dummy/app/controllers/application_controller.rb +0 -3
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
- data/spec/dummy/app/controllers/home_controller.rb +0 -17
- data/spec/dummy/app/controllers/metal_controller.rb +0 -11
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
- data/spec/dummy/app/helpers/application_helper.rb +0 -5
- data/spec/dummy/app/models/user.rb +0 -9
- 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 -57
- data/spec/dummy/config/boot.rb +0 -9
- data/spec/dummy/config/database.yml +0 -15
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -29
- data/spec/dummy/config/environments/production.rb +0 -62
- data/spec/dummy/config/environments/test.rb +0 -55
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
- data/spec/dummy/config/initializers/secret_token.rb +0 -9
- data/spec/dummy/config/initializers/session_store.rb +0 -8
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -52
- data/spec/dummy/config.ru +0 -4
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
- data/spec/dummy/db/migrate/20130902165751_create_doorkeeper_tables.rb +0 -41
- data/spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb +0 -7
- data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
- data/spec/dummy/db/schema.rb +0 -66
- 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 -6
- data/spec/factories.rb +0 -26
- data/spec/generators/application_owner_generator_spec.rb +0 -22
- data/spec/generators/install_generator_spec.rb +0 -31
- data/spec/generators/migration_generator_spec.rb +0 -20
- data/spec/generators/templates/routes.rb +0 -3
- data/spec/generators/views_generator_spec.rb +0 -27
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
- data/spec/lib/config_spec.rb +0 -317
- data/spec/lib/doorkeeper_spec.rb +0 -28
- data/spec/lib/models/expirable_spec.rb +0 -51
- data/spec/lib/models/revocable_spec.rb +0 -36
- data/spec/lib/models/scopes_spec.rb +0 -43
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -42
- data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
- data/spec/lib/oauth/client/credentials_spec.rb +0 -47
- data/spec/lib/oauth/client/methods_spec.rb +0 -54
- data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
- data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
- data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
- data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
- data/spec/lib/oauth/client_spec.rb +0 -39
- data/spec/lib/oauth/code_request_spec.rb +0 -45
- data/spec/lib/oauth/error_response_spec.rb +0 -61
- data/spec/lib/oauth/error_spec.rb +0 -23
- data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
- data/spec/lib/oauth/invalid_token_response_spec.rb +0 -28
- data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
- data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
- data/spec/lib/oauth/refresh_token_request_spec.rb +0 -123
- data/spec/lib/oauth/scopes_spec.rb +0 -123
- data/spec/lib/oauth/token_request_spec.rb +0 -98
- data/spec/lib/oauth/token_response_spec.rb +0 -85
- data/spec/lib/oauth/token_spec.rb +0 -109
- data/spec/lib/request/strategy_spec.rb +0 -53
- data/spec/lib/server_spec.rb +0 -52
- data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
- data/spec/models/doorkeeper/access_token_spec.rb +0 -350
- data/spec/models/doorkeeper/application_spec.rb +0 -187
- data/spec/requests/applications/applications_request_spec.rb +0 -94
- data/spec/requests/applications/authorized_applications_spec.rb +0 -30
- data/spec/requests/endpoints/authorization_spec.rb +0 -72
- data/spec/requests/endpoints/token_spec.rb +0 -64
- data/spec/requests/flows/authorization_code_errors_spec.rb +0 -66
- data/spec/requests/flows/authorization_code_spec.rb +0 -156
- data/spec/requests/flows/client_credentials_spec.rb +0 -58
- data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
- data/spec/requests/flows/implicit_grant_spec.rb +0 -61
- data/spec/requests/flows/password_spec.rb +0 -94
- data/spec/requests/flows/refresh_token_spec.rb +0 -104
- data/spec/requests/flows/revoke_token_spec.rb +0 -143
- data/spec/requests/flows/skip_authorization_spec.rb +0 -59
- data/spec/requests/protected_resources/metal_spec.rb +0 -14
- data/spec/requests/protected_resources/private_api_spec.rb +0 -81
- data/spec/routing/custom_controller_routes_spec.rb +0 -71
- data/spec/routing/default_routes_spec.rb +0 -35
- data/spec/routing/scoped_routes_spec.rb +0 -31
- data/spec/spec_helper.rb +0 -2
- data/spec/spec_helper_integration.rb +0 -56
- data/spec/support/dependencies/factory_girl.rb +0 -2
- data/spec/support/helpers/access_token_request_helper.rb +0 -11
- data/spec/support/helpers/authorization_request_helper.rb +0 -41
- data/spec/support/helpers/config_helper.rb +0 -9
- data/spec/support/helpers/model_helper.rb +0 -45
- data/spec/support/helpers/request_spec_helper.rb +0 -76
- data/spec/support/helpers/url_helper.rb +0 -55
- data/spec/support/orm/active_record.rb +0 -3
- data/spec/support/shared/controllers_shared_context.rb +0 -60
- data/spec/support/shared/models_shared_examples.rb +0 -52
- data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -0,0 +1,202 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module OAuth
|
5
|
+
# RFC7662 OAuth 2.0 Token Introspection
|
6
|
+
#
|
7
|
+
# @see https://datatracker.ietf.org/doc/html/rfc7662
|
8
|
+
class TokenIntrospection
|
9
|
+
def initialize(server, token)
|
10
|
+
@server = server
|
11
|
+
@token = token
|
12
|
+
|
13
|
+
authorize!
|
14
|
+
end
|
15
|
+
|
16
|
+
def authorized?
|
17
|
+
@error.blank?
|
18
|
+
end
|
19
|
+
|
20
|
+
def error_response
|
21
|
+
return if @error.blank?
|
22
|
+
|
23
|
+
if @error == :invalid_token
|
24
|
+
OAuth::InvalidTokenResponse.from_access_token(authorized_token)
|
25
|
+
elsif @error == :invalid_request
|
26
|
+
OAuth::InvalidRequestResponse.from_request(self)
|
27
|
+
else
|
28
|
+
OAuth::ErrorResponse.new(name: @error)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_json(*)
|
33
|
+
active? ? success_response : failure_response
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_reader :server, :token
|
39
|
+
attr_reader :error, :invalid_request_reason
|
40
|
+
|
41
|
+
# If the protected resource uses OAuth 2.0 client credentials to
|
42
|
+
# authenticate to the introspection endpoint and its credentials are
|
43
|
+
# invalid, the authorization server responds with an HTTP 401
|
44
|
+
# (Unauthorized) as described in Section 5.2 of OAuth 2.0 [RFC6749].
|
45
|
+
#
|
46
|
+
# Endpoint must first validate the authentication.
|
47
|
+
# If the authentication is invalid, the endpoint should respond with
|
48
|
+
# an HTTP 401 status code and an invalid_client response.
|
49
|
+
#
|
50
|
+
# @see https://www.oauth.com/oauth2-servers/token-introspection-endpoint/
|
51
|
+
#
|
52
|
+
# To prevent token scanning attacks, the endpoint MUST also require
|
53
|
+
# some form of authorization to access this endpoint, such as client
|
54
|
+
# authentication as described in OAuth 2.0 [RFC6749] or a separate
|
55
|
+
# OAuth 2.0 access token such as the bearer token described in OAuth
|
56
|
+
# 2.0 Bearer Token Usage [RFC6750].
|
57
|
+
#
|
58
|
+
def authorize!
|
59
|
+
# Requested client authorization
|
60
|
+
if server.credentials
|
61
|
+
@error = :invalid_client unless authorized_client
|
62
|
+
elsif authorized_token
|
63
|
+
# Requested bearer token authorization
|
64
|
+
#
|
65
|
+
# If the protected resource uses an OAuth 2.0 bearer token to authorize
|
66
|
+
# its call to the introspection endpoint and the token used for
|
67
|
+
# authorization does not contain sufficient privileges or is otherwise
|
68
|
+
# invalid for this request, the authorization server responds with an
|
69
|
+
# HTTP 401 code as described in Section 3 of OAuth 2.0 Bearer Token
|
70
|
+
# Usage [RFC6750].
|
71
|
+
#
|
72
|
+
@error = :invalid_token unless valid_authorized_token?
|
73
|
+
else
|
74
|
+
@error = :invalid_request
|
75
|
+
@invalid_request_reason = :request_not_authorized
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Client Authentication
|
80
|
+
def authorized_client
|
81
|
+
@authorized_client ||= server.credentials && server.client
|
82
|
+
end
|
83
|
+
|
84
|
+
# Bearer Token Authentication
|
85
|
+
def authorized_token
|
86
|
+
@authorized_token ||= Doorkeeper.authenticate(server.context.request)
|
87
|
+
end
|
88
|
+
|
89
|
+
# 2.2. Introspection Response
|
90
|
+
def success_response
|
91
|
+
customize_response(
|
92
|
+
active: true,
|
93
|
+
scope: @token.scopes_string,
|
94
|
+
client_id: @token.try(:application).try(:uid),
|
95
|
+
token_type: @token.token_type,
|
96
|
+
exp: @token.expires_at.to_i,
|
97
|
+
iat: @token.created_at.to_i,
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
# If the introspection call is properly authorized but the token is not
|
102
|
+
# active, does not exist on this server, or the protected resource is
|
103
|
+
# not allowed to introspect this particular token, then the
|
104
|
+
# authorization server MUST return an introspection response with the
|
105
|
+
# "active" field set to "false". Note that to avoid disclosing too
|
106
|
+
# much of the authorization server's state to a third party, the
|
107
|
+
# authorization server SHOULD NOT include any additional information
|
108
|
+
# about an inactive token, including why the token is inactive.
|
109
|
+
#
|
110
|
+
# @see https://datatracker.ietf.org/doc/html/rfc7662 2.2. Introspection Response
|
111
|
+
#
|
112
|
+
def failure_response
|
113
|
+
{
|
114
|
+
active: false,
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
# Boolean indicator of whether or not the presented token
|
119
|
+
# is currently active. The specifics of a token's "active" state
|
120
|
+
# will vary depending on the implementation of the authorization
|
121
|
+
# server and the information it keeps about its tokens, but a "true"
|
122
|
+
# value return for the "active" property will generally indicate
|
123
|
+
# that a given token has been issued by this authorization server,
|
124
|
+
# has not been revoked by the resource owner, and is within its
|
125
|
+
# given time window of validity (e.g., after its issuance time and
|
126
|
+
# before its expiration time).
|
127
|
+
#
|
128
|
+
# Any other error is considered an "inactive" token.
|
129
|
+
#
|
130
|
+
# * The token requested does not exist or is invalid
|
131
|
+
# * The token expired
|
132
|
+
# * The token was issued to a different client than is making this request
|
133
|
+
#
|
134
|
+
# Since resource servers using token introspection rely on the
|
135
|
+
# authorization server to determine the state of a token, the
|
136
|
+
# authorization server MUST perform all applicable checks against a
|
137
|
+
# token's state. For instance, these tests include the following:
|
138
|
+
#
|
139
|
+
# o If the token can expire, the authorization server MUST determine
|
140
|
+
# whether or not the token has expired.
|
141
|
+
# o If the token can be issued before it is able to be used, the
|
142
|
+
# authorization server MUST determine whether or not a token's valid
|
143
|
+
# period has started yet.
|
144
|
+
# o If the token can be revoked after it was issued, the authorization
|
145
|
+
# server MUST determine whether or not such a revocation has taken
|
146
|
+
# place.
|
147
|
+
# o If the token has been signed, the authorization server MUST
|
148
|
+
# validate the signature.
|
149
|
+
# o If the token can be used only at certain resource servers, the
|
150
|
+
# authorization server MUST determine whether or not the token can
|
151
|
+
# be used at the resource server making the introspection call.
|
152
|
+
#
|
153
|
+
def active?
|
154
|
+
if authorized_client
|
155
|
+
valid_token? && token_introspection_allowed?(auth_client: authorized_client.application)
|
156
|
+
else
|
157
|
+
valid_token?
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Token can be valid only if it is not expired or revoked.
|
162
|
+
def valid_token?
|
163
|
+
@token&.accessible?
|
164
|
+
end
|
165
|
+
|
166
|
+
def valid_authorized_token?
|
167
|
+
!authorized_token_matches_introspected? &&
|
168
|
+
authorized_token.accessible? &&
|
169
|
+
token_introspection_allowed?(auth_token: authorized_token)
|
170
|
+
end
|
171
|
+
|
172
|
+
# RFC7662 Section 2.1
|
173
|
+
def authorized_token_matches_introspected?
|
174
|
+
authorized_token.token == @token&.token
|
175
|
+
end
|
176
|
+
|
177
|
+
# Config constraints for introspection in Doorkeeper.config.allow_token_introspection
|
178
|
+
def token_introspection_allowed?(auth_client: nil, auth_token: nil)
|
179
|
+
allow_introspection = Doorkeeper.config.allow_token_introspection
|
180
|
+
return allow_introspection unless allow_introspection.respond_to?(:call)
|
181
|
+
|
182
|
+
allow_introspection.call(@token, auth_client, auth_token)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Allows to customize introspection response.
|
186
|
+
# Provides context (controller) and token for generating developer-specific
|
187
|
+
# response.
|
188
|
+
#
|
189
|
+
# @see https://datatracker.ietf.org/doc/html/rfc7662#section-2.2
|
190
|
+
#
|
191
|
+
def customize_response(response)
|
192
|
+
customized_response = Doorkeeper.config.custom_introspection_response.call(
|
193
|
+
token,
|
194
|
+
server.context,
|
195
|
+
)
|
196
|
+
return response if customized_response.blank?
|
197
|
+
|
198
|
+
response.merge(customized_response)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -1,37 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class TokenRequest
|
4
|
-
|
6
|
+
attr_reader :pre_auth, :resource_owner
|
5
7
|
|
6
8
|
def initialize(pre_auth, resource_owner)
|
7
|
-
@pre_auth
|
8
|
-
@client = pre_auth.client
|
9
|
+
@pre_auth = pre_auth
|
9
10
|
@resource_owner = resource_owner
|
10
11
|
end
|
11
12
|
|
12
13
|
def authorize
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@response = CodeResponse.new pre_auth,
|
17
|
-
auth,
|
18
|
-
response_on_fragment: true
|
19
|
-
else
|
20
|
-
@response = error_response
|
21
|
-
end
|
14
|
+
auth = Authorization::Token.new(pre_auth, resource_owner)
|
15
|
+
auth.issue_token!
|
16
|
+
CodeResponse.new(pre_auth, auth, response_on_fragment: true)
|
22
17
|
end
|
23
18
|
|
24
19
|
def deny
|
25
20
|
pre_auth.error = :access_denied
|
26
|
-
error_response
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def error_response
|
32
|
-
ErrorResponse.from_request pre_auth,
|
33
|
-
redirect_uri: pre_auth.redirect_uri,
|
34
|
-
response_on_fragment: true
|
21
|
+
pre_auth.error_response
|
35
22
|
end
|
36
23
|
end
|
37
24
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class TokenResponse
|
4
|
-
|
6
|
+
attr_reader :token
|
5
7
|
|
6
8
|
def initialize(token)
|
7
9
|
@token = token
|
@@ -9,12 +11,12 @@ module Doorkeeper
|
|
9
11
|
|
10
12
|
def body
|
11
13
|
{
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
"access_token" => token.plaintext_token,
|
15
|
+
"token_type" => token.token_type,
|
16
|
+
"expires_in" => token.expires_in_seconds,
|
17
|
+
"refresh_token" => token.plaintext_refresh_token,
|
18
|
+
"scope" => token.scopes_string,
|
19
|
+
"created_at" => token.created_at.to_i,
|
18
20
|
}.reject { |_, value| value.blank? }
|
19
21
|
end
|
20
22
|
|
@@ -23,9 +25,11 @@ module Doorkeeper
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def headers
|
26
|
-
{
|
27
|
-
|
28
|
-
|
28
|
+
{
|
29
|
+
"Cache-Control" => "no-store",
|
30
|
+
"Pragma" => "no-cache",
|
31
|
+
"Content-Type" => "application/json; charset=utf-8",
|
32
|
+
}
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module OAuth
|
5
|
+
GRANT_TYPES = [
|
6
|
+
AUTHORIZATION_CODE = "authorization_code",
|
7
|
+
IMPLICIT = "implicit",
|
8
|
+
PASSWORD = "password",
|
9
|
+
CLIENT_CREDENTIALS = "client_credentials",
|
10
|
+
REFRESH_TOKEN = "refresh_token",
|
11
|
+
].freeze
|
12
|
+
end
|
13
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "doorkeeper/orm/active_record/mixins/access_grant"
|
4
4
|
|
5
|
-
|
5
|
+
module Doorkeeper
|
6
|
+
class AccessGrant < ::ActiveRecord::Base
|
7
|
+
include Doorkeeper::Orm::ActiveRecord::Mixins::AccessGrant
|
6
8
|
end
|
7
9
|
end
|
@@ -1,21 +1,9 @@
|
|
1
|
-
|
2
|
-
class AccessToken < ActiveRecord::Base
|
3
|
-
self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}".to_sym
|
4
|
-
|
5
|
-
include AccessTokenMixin
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
7
|
-
|
8
|
-
where(application_id: application_id,
|
9
|
-
resource_owner_id: resource_owner.id).delete_all
|
10
|
-
end
|
11
|
-
private_class_method :delete_all_for
|
3
|
+
require "doorkeeper/orm/active_record/mixins/access_token"
|
12
4
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
def self.created_at_desc
|
18
|
-
'created_at desc'
|
19
|
-
end
|
5
|
+
module Doorkeeper
|
6
|
+
class AccessToken < ::ActiveRecord::Base
|
7
|
+
include Doorkeeper::Orm::ActiveRecord::Mixins::AccessToken
|
20
8
|
end
|
21
9
|
end
|
@@ -1,24 +1,10 @@
|
|
1
|
-
|
2
|
-
class Application < ActiveRecord::Base
|
3
|
-
self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}".to_sym
|
4
|
-
|
5
|
-
include ApplicationMixin
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
else
|
10
|
-
has_many :authorized_tokens, class_name: 'AccessToken', conditions: { revoked_at: nil }
|
11
|
-
end
|
12
|
-
has_many :authorized_applications, through: :authorized_tokens, source: :application
|
3
|
+
require "doorkeeper/orm/active_record/redirect_uri_validator"
|
4
|
+
require "doorkeeper/orm/active_record/mixins/application"
|
13
5
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def self.authorized_for(resource_owner)
|
19
|
-
joins(:authorized_applications).
|
20
|
-
where(AccessToken.table_name => { resource_owner_id: resource_owner.id, revoked_at: nil }).
|
21
|
-
group(column_names_with_table.join(','))
|
22
|
-
end
|
6
|
+
module Doorkeeper
|
7
|
+
class Application < ::ActiveRecord::Base
|
8
|
+
include ::Doorkeeper::Orm::ActiveRecord::Mixins::Application
|
23
9
|
end
|
24
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,81 @@
|
|
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
|
+
# Returns non-expired and non-revoked access tokens
|
52
|
+
def not_expired
|
53
|
+
relation = where(revoked_at: nil)
|
54
|
+
|
55
|
+
if supports_expiration_time_math?
|
56
|
+
# have not reached the expiration time or it never expires
|
57
|
+
relation.where("#{expiration_time_sql} > ?", Time.now.utc).or(
|
58
|
+
relation.where(expires_in: nil)
|
59
|
+
)
|
60
|
+
else
|
61
|
+
::Kernel.warn <<~WARNING.squish
|
62
|
+
[DOORKEEPER] Doorkeeper doesn't support expiration time math for your database adapter (#{adapter_name}).
|
63
|
+
Please add a class method `custom_expiration_time_sql` for your AccessToken class/mixin to provide a custom
|
64
|
+
SQL expression to calculate access token expiration time. See lib/doorkeeper/orm/active_record/mixins/access_token.rb
|
65
|
+
for more details.
|
66
|
+
WARNING
|
67
|
+
|
68
|
+
relation
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def compute_doorkeeper_table_name
|
75
|
+
table_name = "oauth_access_token"
|
76
|
+
table_name = table_name.pluralize if pluralize_table_names
|
77
|
+
"#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|