doorkeeper 4.4.3 → 5.5.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/{NEWS.md → CHANGELOG.md} +393 -19
- data/README.md +97 -393
- data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
- data/app/controllers/doorkeeper/application_controller.rb +8 -5
- data/app/controllers/doorkeeper/application_metal_controller.rb +7 -11
- data/app/controllers/doorkeeper/applications_controller.rb +62 -27
- data/app/controllers/doorkeeper/authorizations_controller.rb +97 -17
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +22 -3
- data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
- data/app/controllers/doorkeeper/tokens_controller.rb +98 -32
- data/app/helpers/doorkeeper/dashboard_helper.rb +9 -7
- data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
- data/app/views/doorkeeper/applications/_form.html.erb +27 -26
- data/app/views/doorkeeper/applications/edit.html.erb +1 -1
- data/app/views/doorkeeper/applications/index.html.erb +17 -7
- data/app/views/doorkeeper/applications/new.html.erb +1 -1
- data/app/views/doorkeeper/applications/show.html.erb +38 -17
- 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 +6 -0
- data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
- data/config/locales/en.yml +23 -3
- 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 +471 -140
- data/lib/doorkeeper/engine.rb +8 -2
- data/lib/doorkeeper/errors.rb +25 -16
- 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 +13 -7
- data/lib/doorkeeper/helpers/controller.rb +43 -10
- data/lib/doorkeeper/models/access_grant_mixin.rb +97 -3
- data/lib/doorkeeper/models/access_token_mixin.rb +272 -66
- data/lib/doorkeeper/models/application_mixin.rb +50 -5
- data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +7 -3
- data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
- 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 +3 -27
- 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 +58 -24
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +7 -5
- data/lib/doorkeeper/oauth/authorization_code_request.rb +58 -10
- data/lib/doorkeeper/oauth/base_request.rb +35 -24
- data/lib/doorkeeper/oauth/base_response.rb +2 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +5 -5
- data/lib/doorkeeper/oauth/client.rb +10 -11
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +47 -4
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +16 -9
- data/lib/doorkeeper/oauth/client_credentials/validator.rb +56 -0
- data/lib/doorkeeper/oauth/client_credentials_request.rb +10 -11
- data/lib/doorkeeper/oauth/code_request.rb +8 -12
- data/lib/doorkeeper/oauth/code_response.rb +27 -15
- data/lib/doorkeeper/oauth/error.rb +3 -1
- data/lib/doorkeeper/oauth/error_response.rb +35 -14
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +42 -7
- 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 +29 -4
- data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +43 -10
- data/lib/doorkeeper/oauth/pre_authorization.rb +133 -26
- data/lib/doorkeeper/oauth/refresh_token_request.rb +59 -31
- data/lib/doorkeeper/oauth/scopes.rb +8 -4
- data/lib/doorkeeper/oauth/token.rb +12 -8
- data/lib/doorkeeper/oauth/token_introspection.rb +97 -23
- data/lib/doorkeeper/oauth/token_request.rb +8 -20
- 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 +5 -30
- data/lib/doorkeeper/orm/active_record/access_token.rb +5 -43
- data/lib/doorkeeper/orm/active_record/application.rb +6 -57
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +68 -0
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +59 -0
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +198 -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 +27 -9
- data/lib/doorkeeper/rails/helpers.rb +10 -8
- 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 +9 -7
- data/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/lib/doorkeeper/rails/routes.rb +37 -30
- data/lib/doorkeeper/rake/db.rake +40 -0
- data/lib/doorkeeper/rake/setup.rake +11 -0
- data/lib/doorkeeper/rake.rb +14 -0
- data/lib/doorkeeper/request/authorization_code.rb +6 -4
- data/lib/doorkeeper/request/client_credentials.rb +3 -3
- data/lib/doorkeeper/request/code.rb +1 -1
- data/lib/doorkeeper/request/password.rb +4 -3
- 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 +61 -34
- 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 -11
- data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
- data/lib/doorkeeper/validations.rb +2 -0
- data/lib/doorkeeper/version.rb +7 -29
- data/lib/doorkeeper.rb +111 -64
- data/lib/generators/doorkeeper/application_owner_generator.rb +24 -18
- 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 +23 -18
- data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +28 -22
- data/{spec/dummy/db/migrate/20180210183654_add_confidential_to_application.rb → lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb} +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 +8 -0
- data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +382 -30
- data/lib/generators/doorkeeper/templates/migration.rb.erb +35 -16
- data/lib/generators/doorkeeper/views_generator.rb +8 -4
- data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
- metadata +95 -309
- data/.coveralls.yml +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -25
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
- data/.gitignore +0 -19
- data/.hound.yml +0 -2
- data/.rspec +0 -1
- data/.rubocop.yml +0 -17
- data/.travis.yml +0 -38
- data/Appraisals +0 -18
- data/CODE_OF_CONDUCT.md +0 -46
- data/CONTRIBUTING.md +0 -47
- data/Gemfile +0 -10
- data/RELEASING.md +0 -10
- data/Rakefile +0 -20
- data/SECURITY.md +0 -15
- data/app/validators/redirect_uri_validator.rb +0 -44
- data/doorkeeper.gemspec +0 -32
- data/gemfiles/rails_4_2.gemfile +0 -13
- data/gemfiles/rails_5_0.gemfile +0 -12
- data/gemfiles/rails_5_1.gemfile +0 -12
- data/gemfiles/rails_5_2.gemfile +0 -12
- data/gemfiles/rails_master.gemfile +0 -14
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
- data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +0 -31
- data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +0 -11
- data/spec/controllers/application_metal_controller.rb +0 -10
- data/spec/controllers/applications_controller_spec.rb +0 -69
- data/spec/controllers/authorizations_controller_spec.rb +0 -250
- data/spec/controllers/protected_resources_controller_spec.rb +0 -309
- data/spec/controllers/token_info_controller_spec.rb +0 -56
- data/spec/controllers/tokens_controller_spec.rb +0 -274
- 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 -5
- 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 -23
- 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 -44
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/doorkeeper.rb +0 -112
- data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -6
- data/spec/dummy/config/initializers/secret_token.rb +0 -8
- 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 -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 -62
- 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/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 -6
- data/spec/factories.rb +0 -28
- data/spec/generators/application_owner_generator_spec.rb +0 -41
- data/spec/generators/install_generator_spec.rb +0 -31
- data/spec/generators/migration_generator_spec.rb +0 -41
- data/spec/generators/previous_refresh_token_generator_spec.rb +0 -57
- data/spec/generators/templates/routes.rb +0 -3
- data/spec/generators/views_generator_spec.rb +0 -27
- data/spec/grape/grape_integration_spec.rb +0 -135
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
- data/spec/lib/config_spec.rb +0 -462
- data/spec/lib/doorkeeper_spec.rb +0 -150
- data/spec/lib/models/expirable_spec.rb +0 -50
- data/spec/lib/models/revocable_spec.rb +0 -59
- data/spec/lib/models/scopes_spec.rb +0 -43
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -41
- data/spec/lib/oauth/authorization_code_request_spec.rb +0 -123
- data/spec/lib/oauth/base_request_spec.rb +0 -155
- data/spec/lib/oauth/base_response_spec.rb +0 -45
- data/spec/lib/oauth/client/credentials_spec.rb +0 -90
- data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -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 -105
- data/spec/lib/oauth/client_spec.rb +0 -39
- data/spec/lib/oauth/code_request_spec.rb +0 -43
- data/spec/lib/oauth/code_response_spec.rb +0 -34
- 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 -218
- data/spec/lib/oauth/invalid_token_response_spec.rb +0 -56
- data/spec/lib/oauth/password_access_token_request_spec.rb +0 -96
- data/spec/lib/oauth/pre_authorization_spec.rb +0 -160
- data/spec/lib/oauth/refresh_token_request_spec.rb +0 -166
- data/spec/lib/oauth/scopes_spec.rb +0 -149
- data/spec/lib/oauth/token_request_spec.rb +0 -96
- data/spec/lib/oauth/token_response_spec.rb +0 -85
- data/spec/lib/oauth/token_spec.rb +0 -116
- data/spec/lib/request/strategy_spec.rb +0 -53
- data/spec/lib/server_spec.rb +0 -59
- data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
- data/spec/models/doorkeeper/access_token_spec.rb +0 -418
- data/spec/models/doorkeeper/application_spec.rb +0 -303
- 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 -71
- data/spec/requests/endpoints/token_spec.rb +0 -71
- data/spec/requests/flows/authorization_code_errors_spec.rb +0 -76
- data/spec/requests/flows/authorization_code_spec.rb +0 -149
- data/spec/requests/flows/client_credentials_spec.rb +0 -86
- 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 -197
- data/spec/requests/flows/refresh_token_spec.rb +0 -174
- data/spec/requests/flows/revoke_token_spec.rb +0 -157
- 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 -75
- data/spec/routing/default_routes_spec.rb +0 -39
- data/spec/routing/scoped_routes_spec.rb +0 -31
- data/spec/spec_helper.rb +0 -4
- data/spec/spec_helper_integration.rb +0 -74
- 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 -72
- data/spec/support/helpers/request_spec_helper.rb +0 -88
- data/spec/support/helpers/url_helper.rb +0 -56
- data/spec/support/http_method_shim.rb +0 -38
- data/spec/support/orm/active_record.rb +0 -3
- data/spec/support/shared/controllers_shared_context.rb +0 -65
- data/spec/support/shared/models_shared_examples.rb +0 -52
- data/spec/validators/redirect_uri_validator_spec.rb +0 -123
- data/spec/version/version_spec.rb +0 -15
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class RefreshTokenRequest < BaseRequest
|
@@ -9,28 +11,28 @@ module Doorkeeper
|
|
9
11
|
validate :client_match, error: :invalid_grant
|
10
12
|
validate :scope, error: :invalid_scope
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
+
attr_reader :access_token, :client, :credentials, :refresh_token
|
15
|
+
attr_reader :missing_param
|
14
16
|
|
15
17
|
def initialize(server, refresh_token, credentials, parameters = {})
|
16
|
-
@server
|
17
|
-
@refresh_token
|
18
|
-
@credentials
|
18
|
+
@server = server
|
19
|
+
@refresh_token = refresh_token
|
20
|
+
@credentials = credentials
|
19
21
|
@original_scopes = parameters[:scope] || parameters[:scopes]
|
20
22
|
@refresh_token_parameter = parameters[:refresh_token]
|
21
|
-
|
22
|
-
if credentials
|
23
|
-
@client = Application.by_uid_and_secret credentials.uid,
|
24
|
-
credentials.secret
|
25
|
-
end
|
23
|
+
@client = load_client(credentials) if credentials
|
26
24
|
end
|
27
25
|
|
28
26
|
private
|
29
27
|
|
28
|
+
def load_client(credentials)
|
29
|
+
server_config.application_model.by_uid_and_secret(credentials.uid, credentials.secret)
|
30
|
+
end
|
31
|
+
|
30
32
|
def before_successful_response
|
31
33
|
refresh_token.transaction do
|
32
34
|
refresh_token.lock!
|
33
|
-
raise Errors::
|
35
|
+
raise Errors::InvalidGrantReuse if refresh_token.revoked?
|
34
36
|
|
35
37
|
refresh_token.revoke unless refresh_token_revoked_on_use?
|
36
38
|
create_access_token
|
@@ -39,7 +41,7 @@ module Doorkeeper
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def refresh_token_revoked_on_use?
|
42
|
-
|
44
|
+
server_config.access_token_model.refresh_token_revoked_on_use?
|
43
45
|
end
|
44
46
|
|
45
47
|
def default_scopes
|
@@ -47,29 +49,46 @@ module Doorkeeper
|
|
47
49
|
end
|
48
50
|
|
49
51
|
def create_access_token
|
50
|
-
|
51
|
-
end
|
52
|
+
attributes = {}
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
expires_in: access_token_expires_in,
|
59
|
-
use_refresh_token: true
|
60
|
-
}.tap do |attributes|
|
61
|
-
if refresh_token_revoked_on_use?
|
62
|
-
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
|
63
59
|
end
|
60
|
+
|
61
|
+
if refresh_token_revoked_on_use?
|
62
|
+
attributes[:previous_refresh_token] = refresh_token.refresh_token
|
64
63
|
end
|
65
|
-
end
|
66
64
|
|
67
|
-
|
68
|
-
|
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,
|
85
|
+
)
|
69
86
|
end
|
70
87
|
|
71
88
|
def validate_token_presence
|
72
|
-
refresh_token.
|
89
|
+
@missing_param = :refresh_token if refresh_token.blank? && @refresh_token_parameter.blank?
|
90
|
+
|
91
|
+
@missing_param.nil?
|
73
92
|
end
|
74
93
|
|
75
94
|
def validate_token
|
@@ -77,16 +96,25 @@ module Doorkeeper
|
|
77
96
|
end
|
78
97
|
|
79
98
|
def validate_client
|
80
|
-
|
99
|
+
return true if credentials.blank?
|
100
|
+
|
101
|
+
client.present?
|
81
102
|
end
|
82
103
|
|
104
|
+
# @see https://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-1.5
|
105
|
+
#
|
83
106
|
def validate_client_match
|
84
|
-
|
107
|
+
return true if refresh_token.application_id.blank?
|
108
|
+
|
109
|
+
client && refresh_token.application_id == client.id
|
85
110
|
end
|
86
111
|
|
87
112
|
def validate_scope
|
88
113
|
if @original_scopes.present?
|
89
|
-
ScopeChecker.valid?(
|
114
|
+
ScopeChecker.valid?(
|
115
|
+
scope_str: @original_scopes,
|
116
|
+
server_scopes: refresh_token.scopes,
|
117
|
+
)
|
90
118
|
else
|
91
119
|
true
|
92
120
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class Scopes
|
@@ -5,7 +7,7 @@ module Doorkeeper
|
|
5
7
|
include Comparable
|
6
8
|
|
7
9
|
def self.from_string(string)
|
8
|
-
string ||=
|
10
|
+
string ||= ""
|
9
11
|
new.tap do |scope|
|
10
12
|
scope.add(*string.split)
|
11
13
|
end
|
@@ -37,13 +39,15 @@ module Doorkeeper
|
|
37
39
|
end
|
38
40
|
|
39
41
|
def to_s
|
40
|
-
@scopes.join(
|
42
|
+
@scopes.join(" ")
|
41
43
|
end
|
42
44
|
|
43
|
-
def
|
44
|
-
scopes.all? { |
|
45
|
+
def scopes?(scopes)
|
46
|
+
scopes.all? { |scope| exists?(scope) }
|
45
47
|
end
|
46
48
|
|
49
|
+
alias has_scopes? scopes?
|
50
|
+
|
47
51
|
def +(other)
|
48
52
|
self.class.from_array(all + to_array(other))
|
49
53
|
end
|
@@ -1,19 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class Token
|
4
6
|
class << self
|
5
7
|
def from_request(request, *methods)
|
6
|
-
methods.inject(nil) do |
|
8
|
+
methods.inject(nil) do |_, method|
|
7
9
|
method = self.method(method) if method.is_a?(Symbol)
|
8
10
|
credentials = method.call(request)
|
9
|
-
break credentials
|
11
|
+
break credentials if credentials.present?
|
10
12
|
end
|
11
13
|
end
|
12
14
|
|
13
15
|
def authenticate(request, *methods)
|
14
16
|
if (token = from_request(request, *methods))
|
15
|
-
access_token =
|
16
|
-
access_token.
|
17
|
+
access_token = Doorkeeper.config.access_token_model.by_token(token)
|
18
|
+
if access_token.present? && Doorkeeper.config.refresh_token_enabled?
|
19
|
+
access_token.revoke_previous_refresh_token!
|
20
|
+
end
|
17
21
|
access_token
|
18
22
|
end
|
19
23
|
end
|
@@ -28,13 +32,13 @@ module Doorkeeper
|
|
28
32
|
|
29
33
|
def from_bearer_authorization(request)
|
30
34
|
pattern = /^Bearer /i
|
31
|
-
header
|
35
|
+
header = request.authorization
|
32
36
|
token_from_header(header, pattern) if match?(header, pattern)
|
33
37
|
end
|
34
38
|
|
35
39
|
def from_basic_authorization(request)
|
36
40
|
pattern = /^Basic /i
|
37
|
-
header
|
41
|
+
header = request.authorization
|
38
42
|
token_from_basic_header(header, pattern) if match?(header, pattern)
|
39
43
|
end
|
40
44
|
|
@@ -50,11 +54,11 @@ module Doorkeeper
|
|
50
54
|
end
|
51
55
|
|
52
56
|
def token_from_header(header, pattern)
|
53
|
-
header.gsub
|
57
|
+
header.gsub(pattern, "")
|
54
58
|
end
|
55
59
|
|
56
60
|
def match?(header, pattern)
|
57
|
-
header
|
61
|
+
header&.match(pattern)
|
58
62
|
end
|
59
63
|
end
|
60
64
|
end
|
@@ -1,12 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
# RFC7662 OAuth 2.0 Token Introspection
|
4
6
|
#
|
5
7
|
# @see https://tools.ietf.org/html/rfc7662
|
6
8
|
class TokenIntrospection
|
7
|
-
attr_reader :server, :token
|
8
|
-
attr_reader :error
|
9
|
-
|
10
9
|
def initialize(server, token)
|
11
10
|
@server = server
|
12
11
|
@token = token
|
@@ -18,12 +17,27 @@ module Doorkeeper
|
|
18
17
|
@error.blank?
|
19
18
|
end
|
20
19
|
|
21
|
-
def
|
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(*)
|
22
33
|
active? ? success_response : failure_response
|
23
34
|
end
|
24
35
|
|
25
36
|
private
|
26
37
|
|
38
|
+
attr_reader :server, :token
|
39
|
+
attr_reader :error, :invalid_request_reason
|
40
|
+
|
27
41
|
# If the protected resource uses OAuth 2.0 client credentials to
|
28
42
|
# authenticate to the introspection endpoint and its credentials are
|
29
43
|
# invalid, the authorization server responds with an HTTP 401
|
@@ -35,37 +49,53 @@ module Doorkeeper
|
|
35
49
|
#
|
36
50
|
# @see https://www.oauth.com/oauth2-servers/token-introspection-endpoint/
|
37
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
|
+
#
|
38
58
|
def authorize!
|
39
59
|
# Requested client authorization
|
40
60
|
if server.credentials
|
41
61
|
@error = :invalid_client unless authorized_client
|
42
|
-
|
62
|
+
elsif authorized_token
|
43
63
|
# Requested bearer token authorization
|
44
|
-
|
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
|
45
76
|
end
|
46
77
|
end
|
47
78
|
|
48
79
|
# Client Authentication
|
49
80
|
def authorized_client
|
50
|
-
@
|
81
|
+
@authorized_client ||= server.credentials && server.client
|
51
82
|
end
|
52
83
|
|
53
84
|
# Bearer Token Authentication
|
54
85
|
def authorized_token
|
55
|
-
@
|
56
|
-
OAuth::Token.authenticate(server.context.request, :from_bearer_authorization)
|
86
|
+
@authorized_token ||= Doorkeeper.authenticate(server.context.request)
|
57
87
|
end
|
58
88
|
|
59
89
|
# 2.2. Introspection Response
|
60
90
|
def success_response
|
61
|
-
|
91
|
+
customize_response(
|
62
92
|
active: true,
|
63
93
|
scope: @token.scopes_string,
|
64
94
|
client_id: @token.try(:application).try(:uid),
|
65
95
|
token_type: @token.token_type,
|
66
96
|
exp: @token.expires_at.to_i,
|
67
|
-
iat: @token.created_at.to_i
|
68
|
-
|
97
|
+
iat: @token.created_at.to_i,
|
98
|
+
)
|
69
99
|
end
|
70
100
|
|
71
101
|
# If the introspection call is properly authorized but the token is not
|
@@ -81,7 +111,7 @@ module Doorkeeper
|
|
81
111
|
#
|
82
112
|
def failure_response
|
83
113
|
{
|
84
|
-
active: false
|
114
|
+
active: false,
|
85
115
|
}
|
86
116
|
end
|
87
117
|
|
@@ -101,9 +131,28 @@ module Doorkeeper
|
|
101
131
|
# * The token expired
|
102
132
|
# * The token was issued to a different client than is making this request
|
103
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
|
+
#
|
104
153
|
def active?
|
105
154
|
if authorized_client
|
106
|
-
valid_token? &&
|
155
|
+
valid_token? && token_introspection_allowed?(auth_client: authorized_client.application)
|
107
156
|
else
|
108
157
|
valid_token?
|
109
158
|
end
|
@@ -111,17 +160,42 @@ module Doorkeeper
|
|
111
160
|
|
112
161
|
# Token can be valid only if it is not expired or revoked.
|
113
162
|
def valid_token?
|
114
|
-
@token
|
163
|
+
@token&.accessible?
|
115
164
|
end
|
116
165
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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://tools.ietf.org/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)
|
125
199
|
end
|
126
200
|
end
|
127
201
|
end
|
@@ -1,36 +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
|
9
|
+
@pre_auth = pre_auth
|
8
10
|
@resource_owner = resource_owner
|
9
11
|
end
|
10
12
|
|
11
13
|
def authorize
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
@response = CodeResponse.new pre_auth,
|
16
|
-
auth,
|
17
|
-
response_on_fragment: true
|
18
|
-
else
|
19
|
-
@response = error_response
|
20
|
-
end
|
14
|
+
auth = Authorization::Token.new(pre_auth, resource_owner)
|
15
|
+
auth.issue_token!
|
16
|
+
CodeResponse.new(pre_auth, auth, response_on_fragment: true)
|
21
17
|
end
|
22
18
|
|
23
19
|
def deny
|
24
20
|
pre_auth.error = :access_denied
|
25
|
-
error_response
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def error_response
|
31
|
-
ErrorResponse.from_request pre_auth,
|
32
|
-
redirect_uri: pre_auth.redirect_uri,
|
33
|
-
response_on_fragment: true
|
21
|
+
pre_auth.error_response
|
34
22
|
end
|
35
23
|
end
|
36
24
|
end
|