doorkeeper 4.2.6 → 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 +5 -5
- data/CHANGELOG.md +1049 -0
- data/README.md +110 -353
- data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
- data/app/controllers/doorkeeper/application_controller.rb +6 -7
- data/app/controllers/doorkeeper/application_metal_controller.rb +7 -11
- data/app/controllers/doorkeeper/applications_controller.rb +65 -16
- 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 +115 -38
- data/app/helpers/doorkeeper/dashboard_helper.rb +10 -6
- data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
- 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 +6 -0
- 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 +34 -7
- 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 +514 -167
- data/lib/doorkeeper/engine.rb +11 -5
- 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 +23 -12
- data/lib/doorkeeper/helpers/controller.rb +51 -14
- data/lib/doorkeeper/models/access_grant_mixin.rb +94 -27
- data/lib/doorkeeper/models/access_token_mixin.rb +284 -96
- data/lib/doorkeeper/models/application_mixin.rb +58 -27
- data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +12 -6
- data/lib/doorkeeper/models/concerns/orderable.rb +15 -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 +66 -28
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +7 -5
- data/lib/doorkeeper/oauth/authorization_code_request.rb +63 -10
- data/lib/doorkeeper/oauth/base_request.rb +35 -19
- data/lib/doorkeeper/oauth/base_response.rb +2 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +9 -7
- 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 +5 -3
- data/lib/doorkeeper/oauth/error_response.rb +35 -15
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +11 -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 +53 -3
- 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 -5
- data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +44 -10
- data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
- data/lib/doorkeeper/oauth/refresh_token_request.rb +60 -31
- data/lib/doorkeeper/oauth/scopes.rb +26 -12
- data/lib/doorkeeper/oauth/token.rb +13 -9
- data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
- 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 +6 -4
- data/lib/doorkeeper/orm/active_record/access_token.rb +5 -42
- 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 +60 -0
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +199 -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 +37 -8
- data/lib/doorkeeper/rails/helpers.rb +14 -13
- 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 +41 -28
- 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 +5 -14
- 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 -11
- 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 +111 -62
- 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 +31 -19
- 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/{spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb → lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
- 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 +412 -33
- 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 +114 -276
- data/.coveralls.yml +0 -1
- data/.gitignore +0 -19
- data/.hound.yml +0 -13
- data/.rspec +0 -1
- data/.travis.yml +0 -26
- data/Appraisals +0 -14
- data/CONTRIBUTING.md +0 -47
- data/Gemfile +0 -10
- data/NEWS.md +0 -606
- data/RELEASING.md +0 -10
- data/Rakefile +0 -20
- data/app/validators/redirect_uri_validator.rb +0 -34
- data/doorkeeper.gemspec +0 -29
- data/gemfiles/rails_4_2.gemfile +0 -11
- data/gemfiles/rails_5_0.gemfile +0 -12
- data/gemfiles/rails_5_1.gemfile +0 -13
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb +0 -11
- data/lib/generators/doorkeeper/templates/migration.rb +0 -68
- data/spec/controllers/application_metal_controller.rb +0 -10
- data/spec/controllers/applications_controller_spec.rb +0 -58
- data/spec/controllers/authorizations_controller_spec.rb +0 -218
- data/spec/controllers/protected_resources_controller_spec.rb +0 -300
- 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 -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/active_record_belongs_to_required_by_default.rb +0 -6
- 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/20151223192035_create_doorkeeper_tables.rb +0 -60
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
- data/spec/dummy/db/schema.rb +0 -67
- 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 -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 -334
- 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 -80
- data/spec/lib/oauth/base_request_spec.rb +0 -160
- data/spec/lib/oauth/base_response_spec.rb +0 -45
- data/spec/lib/oauth/client/credentials_spec.rb +0 -88
- 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/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 -104
- data/spec/lib/oauth/invalid_token_response_spec.rb +0 -56
- 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 -154
- data/spec/lib/oauth/scopes_spec.rb +0 -122
- 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 -116
- data/spec/lib/request/strategy_spec.rb +0 -53
- data/spec/lib/server_spec.rb +0 -49
- data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
- data/spec/models/doorkeeper/access_token_spec.rb +0 -394
- data/spec/models/doorkeeper/application_spec.rb +0 -179
- 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 -64
- data/spec/requests/flows/authorization_code_errors_spec.rb +0 -76
- data/spec/requests/flows/authorization_code_spec.rb +0 -148
- 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 -115
- 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 -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 -4
- data/spec/spec_helper_integration.rb +0 -63
- 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 -67
- data/spec/support/helpers/request_spec_helper.rb +0 -84
- data/spec/support/helpers/url_helper.rb +0 -55
- 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 -69
- data/spec/support/shared/models_shared_examples.rb +0 -52
- data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class RefreshTokenRequest < BaseRequest
|
@@ -9,36 +11,37 @@ 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
|
37
39
|
end
|
40
|
+
super
|
38
41
|
end
|
39
42
|
|
40
43
|
def refresh_token_revoked_on_use?
|
41
|
-
|
44
|
+
server_config.access_token_model.refresh_token_revoked_on_use?
|
42
45
|
end
|
43
46
|
|
44
47
|
def default_scopes
|
@@ -46,29 +49,46 @@ module Doorkeeper
|
|
46
49
|
end
|
47
50
|
|
48
51
|
def create_access_token
|
49
|
-
|
50
|
-
end
|
52
|
+
attributes = {}
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
expires_in: access_token_expires_in,
|
58
|
-
use_refresh_token: true
|
59
|
-
}.tap do |attributes|
|
60
|
-
if refresh_token_revoked_on_use?
|
61
|
-
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
|
62
59
|
end
|
60
|
+
|
61
|
+
if refresh_token_revoked_on_use?
|
62
|
+
attributes[:previous_refresh_token] = refresh_token.refresh_token
|
63
63
|
end
|
64
|
-
end
|
65
64
|
|
66
|
-
|
67
|
-
|
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
|
+
)
|
68
86
|
end
|
69
87
|
|
70
88
|
def validate_token_presence
|
71
|
-
refresh_token.
|
89
|
+
@missing_param = :refresh_token if refresh_token.blank? && @refresh_token_parameter.blank?
|
90
|
+
|
91
|
+
@missing_param.nil?
|
72
92
|
end
|
73
93
|
|
74
94
|
def validate_token
|
@@ -76,16 +96,25 @@ module Doorkeeper
|
|
76
96
|
end
|
77
97
|
|
78
98
|
def validate_client
|
79
|
-
|
99
|
+
return true if credentials.blank?
|
100
|
+
|
101
|
+
client.present?
|
80
102
|
end
|
81
103
|
|
104
|
+
# @see https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
|
105
|
+
#
|
82
106
|
def validate_client_match
|
83
|
-
|
107
|
+
return true if refresh_token.application_id.blank?
|
108
|
+
|
109
|
+
client && refresh_token.application_id == client.id
|
84
110
|
end
|
85
111
|
|
86
112
|
def validate_scope
|
87
113
|
if @original_scopes.present?
|
88
|
-
ScopeChecker.valid?(
|
114
|
+
ScopeChecker.valid?(
|
115
|
+
scope_str: @original_scopes,
|
116
|
+
server_scopes: refresh_token.scopes,
|
117
|
+
)
|
89
118
|
else
|
90
119
|
true
|
91
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,28 +39,40 @@ 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
|
-
|
49
|
-
self.class.from_array(all + other.all)
|
50
|
-
else
|
51
|
-
super(other)
|
52
|
-
end
|
52
|
+
self.class.from_array(all + to_array(other))
|
53
53
|
end
|
54
54
|
|
55
55
|
def <=>(other)
|
56
|
-
|
56
|
+
if other.respond_to?(:map)
|
57
|
+
map(&:to_s).sort <=> other.map(&:to_s).sort
|
58
|
+
else
|
59
|
+
super
|
60
|
+
end
|
57
61
|
end
|
58
62
|
|
59
63
|
def &(other)
|
60
|
-
|
61
|
-
|
64
|
+
self.class.from_array(all & to_array(other))
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def to_array(other)
|
70
|
+
case other
|
71
|
+
when Scopes
|
72
|
+
other.all
|
73
|
+
else
|
74
|
+
other.to_a
|
75
|
+
end
|
62
76
|
end
|
63
77
|
end
|
64
78
|
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
|
-
if token = from_request(request, *methods)
|
15
|
-
access_token =
|
16
|
-
access_token.
|
16
|
+
if (token = from_request(request, *methods))
|
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
|
@@ -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,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
|
@@ -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,46 +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
|
6
|
-
|
7
|
-
# Deletes all the Access Tokens created for the specific
|
8
|
-
# Application and Resource Owner.
|
9
|
-
#
|
10
|
-
# @param application_id [Integer] Application ID
|
11
|
-
# @param resource_owner [ActiveRecord::Base] Resource Owner model instance
|
12
|
-
#
|
13
|
-
def self.delete_all_for(application_id, resource_owner)
|
14
|
-
where(application_id: application_id,
|
15
|
-
resource_owner_id: resource_owner.id).delete_all
|
16
|
-
end
|
17
|
-
private_class_method :delete_all_for
|
1
|
+
# frozen_string_literal: true
|
18
2
|
|
19
|
-
|
20
|
-
# specific Resource Owner.
|
21
|
-
#
|
22
|
-
# @param resource_owner [ActiveRecord::Base]
|
23
|
-
# Resource Owner model instance
|
24
|
-
#
|
25
|
-
# @return [ActiveRecord::Relation]
|
26
|
-
# active Access Tokens for Resource Owner
|
27
|
-
#
|
28
|
-
def self.active_for(resource_owner)
|
29
|
-
where(resource_owner_id: resource_owner.id, revoked_at: nil)
|
30
|
-
end
|
3
|
+
require "doorkeeper/orm/active_record/mixins/access_token"
|
31
4
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.refresh_token_revoked_on_use?
|
38
|
-
column_names.include?('previous_refresh_token')
|
39
|
-
end
|
40
|
-
|
41
|
-
# ORM-specific DESC order for `:created_at` column.
|
42
|
-
def self.created_at_desc
|
43
|
-
'created_at desc'
|
44
|
-
end
|
5
|
+
module Doorkeeper
|
6
|
+
class AccessToken < ::ActiveRecord::Base
|
7
|
+
include Doorkeeper::Orm::ActiveRecord::Mixins::AccessToken
|
45
8
|
end
|
46
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
|
-
|
3
|
+
require "doorkeeper/orm/active_record/redirect_uri_validator"
|
4
|
+
require "doorkeeper/orm/active_record/mixins/application"
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# @param resource_owner [ActiveRecord::Base]
|
14
|
-
# Resource Owner model instance
|
15
|
-
#
|
16
|
-
# @return [ActiveRecord::Relation]
|
17
|
-
# Applications authorized for the Resource Owner
|
18
|
-
#
|
19
|
-
def self.authorized_for(resource_owner)
|
20
|
-
resource_access_tokens = AccessToken.active_for(resource_owner)
|
21
|
-
where(id: resource_access_tokens.select(:application_id).distinct)
|
22
|
-
end
|
6
|
+
module Doorkeeper
|
7
|
+
class Application < ::ActiveRecord::Base
|
8
|
+
include ::Doorkeeper::Orm::ActiveRecord::Mixins::Application
|
23
9
|
end
|
24
10
|
end
|