doorkeeper 5.1.2 → 5.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/{NEWS.md → CHANGELOG.md} +314 -27
- data/README.md +39 -22
- data/app/controllers/doorkeeper/application_controller.rb +3 -2
- data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
- data/app/controllers/doorkeeper/applications_controller.rb +5 -4
- data/app/controllers/doorkeeper/authorizations_controller.rb +76 -25
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +5 -5
- data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +99 -28
- data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
- data/app/views/doorkeeper/applications/_form.html.erb +1 -7
- data/app/views/doorkeeper/applications/show.html.erb +35 -14
- data/app/views/doorkeeper/authorizations/error.html.erb +3 -1
- data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
- data/app/views/doorkeeper/authorizations/new.html.erb +16 -14
- data/config/locales/en.yml +16 -3
- data/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/lib/doorkeeper/config/option.rb +20 -2
- data/lib/doorkeeper/config/validations.rb +53 -0
- data/lib/doorkeeper/config.rb +300 -136
- data/lib/doorkeeper/engine.rb +10 -3
- data/lib/doorkeeper/errors.rb +13 -18
- data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
- data/lib/doorkeeper/grant_flow/flow.rb +44 -0
- data/lib/doorkeeper/grant_flow/registry.rb +50 -0
- data/lib/doorkeeper/grant_flow.rb +45 -0
- data/lib/doorkeeper/grape/helpers.rb +7 -3
- data/lib/doorkeeper/helpers/controller.rb +36 -11
- data/lib/doorkeeper/models/access_grant_mixin.rb +23 -19
- data/lib/doorkeeper/models/access_token_mixin.rb +195 -52
- data/lib/doorkeeper/models/application_mixin.rb +8 -7
- data/lib/doorkeeper/models/concerns/expirable.rb +1 -1
- data/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +88 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
- data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +30 -0
- data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
- data/lib/doorkeeper/models/concerns/revocable.rb +1 -28
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
- data/lib/doorkeeper/oauth/authorization/code.rb +31 -14
- data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
- data/lib/doorkeeper/oauth/authorization/token.rb +30 -19
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
- data/lib/doorkeeper/oauth/authorization_code_request.rb +51 -22
- data/lib/doorkeeper/oauth/base_request.rb +21 -22
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
- data/lib/doorkeeper/oauth/client.rb +8 -9
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +42 -5
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +10 -8
- data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +14 -5
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
- data/lib/doorkeeper/oauth/code_request.rb +6 -12
- data/lib/doorkeeper/oauth/code_response.rb +24 -14
- data/lib/doorkeeper/oauth/error.rb +1 -1
- data/lib/doorkeeper/oauth/error_response.rb +11 -13
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +2 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +8 -12
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +10 -7
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +19 -23
- 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 +7 -4
- data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +34 -11
- data/lib/doorkeeper/oauth/pre_authorization.rb +114 -44
- data/lib/doorkeeper/oauth/refresh_token_request.rb +54 -34
- data/lib/doorkeeper/oauth/token.rb +6 -7
- data/lib/doorkeeper/oauth/token_introspection.rb +28 -22
- data/lib/doorkeeper/oauth/token_request.rb +6 -20
- data/lib/doorkeeper/oauth/token_response.rb +2 -3
- data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
- data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
- data/lib/doorkeeper/orm/active_record/application.rb +5 -149
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +63 -0
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +77 -0
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +210 -0
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +5 -2
- data/lib/doorkeeper/orm/active_record.rb +29 -22
- data/lib/doorkeeper/rails/helpers.rb +4 -4
- data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
- data/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/lib/doorkeeper/rails/routes.rb +28 -27
- data/lib/doorkeeper/rake/db.rake +6 -6
- data/lib/doorkeeper/request/authorization_code.rb +5 -3
- data/lib/doorkeeper/request/client_credentials.rb +2 -2
- data/lib/doorkeeper/request/password.rb +3 -2
- data/lib/doorkeeper/request/refresh_token.rb +5 -4
- data/lib/doorkeeper/request/strategy.rb +2 -2
- data/lib/doorkeeper/request.rb +49 -17
- data/lib/doorkeeper/server.rb +7 -11
- data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
- data/lib/doorkeeper/version.rb +2 -6
- data/lib/doorkeeper.rb +183 -80
- data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +2 -2
- data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/lib/generators/doorkeeper/migration_generator.rb +1 -1
- data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +7 -7
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +3 -1
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +230 -50
- data/lib/generators/doorkeeper/templates/migration.rb.erb +31 -9
- metadata +61 -327
- data/.coveralls.yml +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -25
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
- data/.gitignore +0 -20
- data/.gitlab-ci.yml +0 -16
- data/.hound.yml +0 -3
- data/.rspec +0 -1
- data/.rubocop.yml +0 -50
- data/.travis.yml +0 -35
- data/Appraisals +0 -40
- data/CODE_OF_CONDUCT.md +0 -46
- data/CONTRIBUTING.md +0 -47
- data/Dangerfile +0 -67
- data/Gemfile +0 -24
- data/RELEASING.md +0 -10
- data/Rakefile +0 -28
- data/SECURITY.md +0 -15
- data/UPGRADE.md +0 -2
- data/app/validators/redirect_uri_validator.rb +0 -50
- data/bin/console +0 -16
- data/doorkeeper.gemspec +0 -34
- data/gemfiles/rails_5_0.gemfile +0 -17
- data/gemfiles/rails_5_1.gemfile +0 -17
- data/gemfiles/rails_5_2.gemfile +0 -17
- data/gemfiles/rails_6_0.gemfile +0 -17
- data/gemfiles/rails_master.gemfile +0 -17
- data/spec/controllers/application_metal_controller_spec.rb +0 -64
- data/spec/controllers/applications_controller_spec.rb +0 -180
- data/spec/controllers/authorizations_controller_spec.rb +0 -527
- data/spec/controllers/protected_resources_controller_spec.rb +0 -353
- data/spec/controllers/token_info_controller_spec.rb +0 -50
- data/spec/controllers/tokens_controller_spec.rb +0 -330
- data/spec/dummy/Rakefile +0 -9
- data/spec/dummy/app/assets/config/manifest.js +0 -2
- data/spec/dummy/app/controllers/application_controller.rb +0 -5
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
- data/spec/dummy/app/controllers/home_controller.rb +0 -18
- data/spec/dummy/app/controllers/metal_controller.rb +0 -13
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
- data/spec/dummy/app/helpers/application_helper.rb +0 -7
- data/spec/dummy/app/models/user.rb +0 -7
- data/spec/dummy/app/views/home/index.html.erb +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/config/application.rb +0 -47
- data/spec/dummy/config/boot.rb +0 -7
- data/spec/dummy/config/database.yml +0 -15
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -31
- data/spec/dummy/config/environments/production.rb +0 -64
- data/spec/dummy/config/environments/test.rb +0 -45
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
- data/spec/dummy/config/initializers/doorkeeper.rb +0 -121
- data/spec/dummy/config/initializers/secret_token.rb +0 -10
- data/spec/dummy/config/initializers/session_store.rb +0 -10
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
- data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -13
- data/spec/dummy/config.ru +0 -6
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
- data/spec/dummy/db/schema.rb +0 -68
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -26
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +0 -9
- data/spec/factories.rb +0 -30
- data/spec/generators/application_owner_generator_spec.rb +0 -28
- data/spec/generators/confidential_applications_generator_spec.rb +0 -29
- data/spec/generators/install_generator_spec.rb +0 -36
- data/spec/generators/migration_generator_spec.rb +0 -28
- data/spec/generators/pkce_generator_spec.rb +0 -28
- data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
- data/spec/generators/templates/routes.rb +0 -4
- data/spec/generators/views_generator_spec.rb +0 -29
- data/spec/grape/grape_integration_spec.rb +0 -137
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
- data/spec/lib/config_spec.rb +0 -697
- data/spec/lib/doorkeeper_spec.rb +0 -27
- data/spec/lib/models/expirable_spec.rb +0 -61
- data/spec/lib/models/reusable_spec.rb +0 -40
- data/spec/lib/models/revocable_spec.rb +0 -59
- data/spec/lib/models/scopes_spec.rb +0 -53
- data/spec/lib/models/secret_storable_spec.rb +0 -135
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
- data/spec/lib/oauth/authorization_code_request_spec.rb +0 -156
- data/spec/lib/oauth/base_request_spec.rb +0 -205
- data/spec/lib/oauth/base_response_spec.rb +0 -47
- data/spec/lib/oauth/client/credentials_spec.rb +0 -90
- data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -94
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
- data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
- data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -29
- data/spec/lib/oauth/client_credentials_request_spec.rb +0 -109
- data/spec/lib/oauth/client_spec.rb +0 -38
- data/spec/lib/oauth/code_request_spec.rb +0 -47
- data/spec/lib/oauth/code_response_spec.rb +0 -36
- data/spec/lib/oauth/error_response_spec.rb +0 -66
- data/spec/lib/oauth/error_spec.rb +0 -23
- data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -22
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -98
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -247
- data/spec/lib/oauth/invalid_token_response_spec.rb +0 -55
- data/spec/lib/oauth/password_access_token_request_spec.rb +0 -192
- data/spec/lib/oauth/pre_authorization_spec.rb +0 -215
- data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
- data/spec/lib/oauth/scopes_spec.rb +0 -148
- data/spec/lib/oauth/token_request_spec.rb +0 -150
- data/spec/lib/oauth/token_response_spec.rb +0 -86
- data/spec/lib/oauth/token_spec.rb +0 -158
- data/spec/lib/request/strategy_spec.rb +0 -54
- data/spec/lib/secret_storing/base_spec.rb +0 -60
- data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
- data/spec/lib/secret_storing/plain_spec.rb +0 -44
- data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
- data/spec/lib/server_spec.rb +0 -61
- data/spec/lib/stale_records_cleaner_spec.rb +0 -89
- data/spec/models/doorkeeper/access_grant_spec.rb +0 -144
- data/spec/models/doorkeeper/access_token_spec.rb +0 -591
- data/spec/models/doorkeeper/application_spec.rb +0 -472
- data/spec/requests/applications/applications_request_spec.rb +0 -259
- data/spec/requests/applications/authorized_applications_spec.rb +0 -32
- data/spec/requests/endpoints/authorization_spec.rb +0 -73
- data/spec/requests/endpoints/token_spec.rb +0 -75
- data/spec/requests/flows/authorization_code_errors_spec.rb +0 -78
- data/spec/requests/flows/authorization_code_spec.rb +0 -447
- data/spec/requests/flows/client_credentials_spec.rb +0 -128
- data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -34
- data/spec/requests/flows/implicit_grant_spec.rb +0 -90
- data/spec/requests/flows/password_spec.rb +0 -259
- data/spec/requests/flows/refresh_token_spec.rb +0 -233
- data/spec/requests/flows/revoke_token_spec.rb +0 -143
- data/spec/requests/flows/skip_authorization_spec.rb +0 -66
- data/spec/requests/protected_resources/metal_spec.rb +0 -16
- data/spec/requests/protected_resources/private_api_spec.rb +0 -83
- data/spec/routing/custom_controller_routes_spec.rb +0 -133
- data/spec/routing/default_routes_spec.rb +0 -41
- data/spec/routing/scoped_routes_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -57
- data/spec/spec_helper_integration.rb +0 -4
- data/spec/support/dependencies/factory_bot.rb +0 -4
- data/spec/support/doorkeeper_rspec.rb +0 -22
- data/spec/support/helpers/access_token_request_helper.rb +0 -13
- data/spec/support/helpers/authorization_request_helper.rb +0 -43
- data/spec/support/helpers/config_helper.rb +0 -11
- data/spec/support/helpers/model_helper.rb +0 -78
- data/spec/support/helpers/request_spec_helper.rb +0 -98
- data/spec/support/helpers/url_helper.rb +0 -62
- data/spec/support/http_method_shim.rb +0 -29
- data/spec/support/orm/active_record.rb +0 -5
- data/spec/support/shared/controllers_shared_context.rb +0 -123
- data/spec/support/shared/hashing_shared_context.rb +0 -36
- data/spec/support/shared/models_shared_examples.rb +0 -54
- data/spec/validators/redirect_uri_validator_spec.rb +0 -158
- data/spec/version/version_spec.rb +0 -17
@@ -5,25 +5,33 @@ module Doorkeeper
|
|
5
5
|
class PreAuthorization
|
6
6
|
include Validations
|
7
7
|
|
8
|
-
validate :
|
8
|
+
validate :client_id, error: :invalid_request
|
9
9
|
validate :client, error: :invalid_client
|
10
|
-
validate :
|
10
|
+
validate :client_supports_grant_flow, error: :unauthorized_client
|
11
|
+
validate :resource_owner_authorize_for_client, error: :invalid_client
|
11
12
|
validate :redirect_uri, error: :invalid_redirect_uri
|
13
|
+
validate :params, error: :invalid_request
|
14
|
+
validate :response_type, error: :unsupported_response_type
|
15
|
+
validate :response_mode, error: :unsupported_response_mode
|
16
|
+
validate :scopes, error: :invalid_scope
|
12
17
|
validate :code_challenge_method, error: :invalid_code_challenge_method
|
13
18
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def initialize(server,
|
19
|
-
@server
|
20
|
-
@
|
21
|
-
@response_type
|
22
|
-
@
|
23
|
-
@
|
24
|
-
@
|
25
|
-
@
|
26
|
-
@
|
19
|
+
attr_reader :client, :code_challenge, :code_challenge_method, :missing_param,
|
20
|
+
:redirect_uri, :resource_owner, :response_type, :state,
|
21
|
+
:authorization_response_flow, :response_mode, :custom_access_token_attributes
|
22
|
+
|
23
|
+
def initialize(server, parameters = {}, resource_owner = nil)
|
24
|
+
@server = server
|
25
|
+
@client_id = parameters[:client_id]
|
26
|
+
@response_type = parameters[:response_type]
|
27
|
+
@response_mode = parameters[:response_mode]
|
28
|
+
@redirect_uri = parameters[:redirect_uri]
|
29
|
+
@scope = parameters[:scope]
|
30
|
+
@state = parameters[:state]
|
31
|
+
@code_challenge = parameters[:code_challenge]
|
32
|
+
@code_challenge_method = parameters[:code_challenge_method]
|
33
|
+
@resource_owner = resource_owner
|
34
|
+
@custom_access_token_attributes = parameters.slice(*Doorkeeper.config.custom_access_token_attributes)
|
27
35
|
end
|
28
36
|
|
29
37
|
def authorizable?
|
@@ -31,33 +39,38 @@ module Doorkeeper
|
|
31
39
|
end
|
32
40
|
|
33
41
|
def scopes
|
34
|
-
Scopes.from_string
|
42
|
+
Scopes.from_string(scope)
|
35
43
|
end
|
36
44
|
|
37
45
|
def scope
|
38
|
-
@scope.presence || build_scopes
|
46
|
+
@scope.presence || (server.default_scopes.presence && build_scopes)
|
39
47
|
end
|
40
48
|
|
41
49
|
def error_response
|
42
|
-
|
50
|
+
if error == :invalid_request
|
51
|
+
OAuth::InvalidRequestResponse.from_request(
|
52
|
+
self,
|
53
|
+
response_on_fragment: response_on_fragment?,
|
54
|
+
)
|
55
|
+
else
|
56
|
+
OAuth::ErrorResponse.from_request(self, response_on_fragment: response_on_fragment?)
|
57
|
+
end
|
43
58
|
end
|
44
59
|
|
45
|
-
def as_json(_options)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
scope: scope,
|
52
|
-
client_name: client.name,
|
53
|
-
status: I18n.t("doorkeeper.pre_authorization.status"),
|
54
|
-
}
|
60
|
+
def as_json(_options = nil)
|
61
|
+
pre_auth_hash
|
62
|
+
end
|
63
|
+
|
64
|
+
def form_post_response?
|
65
|
+
response_mode == "form_post"
|
55
66
|
end
|
56
67
|
|
57
68
|
private
|
58
69
|
|
70
|
+
attr_reader :client_id, :server
|
71
|
+
|
59
72
|
def build_scopes
|
60
|
-
client_scopes = client.
|
73
|
+
client_scopes = client.scopes
|
61
74
|
if client_scopes.blank?
|
62
75
|
server.default_scopes.to_s
|
63
76
|
else
|
@@ -65,27 +78,23 @@ module Doorkeeper
|
|
65
78
|
end
|
66
79
|
end
|
67
80
|
|
68
|
-
def
|
69
|
-
|
81
|
+
def validate_client_id
|
82
|
+
@missing_param = :client_id if client_id.blank?
|
83
|
+
@missing_param.nil?
|
70
84
|
end
|
71
85
|
|
72
86
|
def validate_client
|
73
|
-
client.
|
87
|
+
@client = OAuth::Client.find(client_id)
|
88
|
+
@client.present?
|
74
89
|
end
|
75
90
|
|
76
|
-
def
|
77
|
-
|
78
|
-
|
79
|
-
Helpers::ScopeChecker.valid?(
|
80
|
-
scope_str: scope,
|
81
|
-
server_scopes: server.scopes,
|
82
|
-
app_scopes: client.application.scopes,
|
83
|
-
grant_type: grant_type
|
84
|
-
)
|
91
|
+
def validate_client_supports_grant_flow
|
92
|
+
Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client.application)
|
85
93
|
end
|
86
94
|
|
87
|
-
def
|
88
|
-
|
95
|
+
def validate_resource_owner_authorize_for_client
|
96
|
+
# The `authorize_resource_owner_for_client` config option is used for this validation
|
97
|
+
client.application.authorized_for_resource_owner?(@resource_owner)
|
89
98
|
end
|
90
99
|
|
91
100
|
def validate_redirect_uri
|
@@ -93,14 +102,75 @@ module Doorkeeper
|
|
93
102
|
|
94
103
|
Helpers::URIChecker.valid_for_authorization?(
|
95
104
|
redirect_uri,
|
96
|
-
client.redirect_uri
|
105
|
+
client.redirect_uri,
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
def validate_params
|
110
|
+
@missing_param = if response_type.blank?
|
111
|
+
:response_type
|
112
|
+
elsif @scope.blank? && server.default_scopes.blank?
|
113
|
+
:scope
|
114
|
+
end
|
115
|
+
|
116
|
+
@missing_param.nil?
|
117
|
+
end
|
118
|
+
|
119
|
+
def validate_response_type
|
120
|
+
server.authorization_response_flows.any? do |flow|
|
121
|
+
if flow.matches_response_type?(response_type)
|
122
|
+
@authorization_response_flow = flow
|
123
|
+
true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def validate_response_mode
|
129
|
+
if response_mode.blank?
|
130
|
+
@response_mode = authorization_response_flow.default_response_mode
|
131
|
+
return true
|
132
|
+
end
|
133
|
+
|
134
|
+
authorization_response_flow.matches_response_mode?(response_mode)
|
135
|
+
end
|
136
|
+
|
137
|
+
def validate_scopes
|
138
|
+
Helpers::ScopeChecker.valid?(
|
139
|
+
scope_str: scope,
|
140
|
+
server_scopes: server.scopes,
|
141
|
+
app_scopes: client.scopes,
|
142
|
+
grant_type: grant_type,
|
97
143
|
)
|
98
144
|
end
|
99
145
|
|
100
146
|
def validate_code_challenge_method
|
147
|
+
return true unless Doorkeeper.config.access_grant_model.pkce_supported?
|
148
|
+
|
101
149
|
code_challenge.blank? ||
|
102
150
|
(code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
|
103
151
|
end
|
152
|
+
|
153
|
+
def response_on_fragment?
|
154
|
+
return response_type == "token" if response_mode.nil?
|
155
|
+
|
156
|
+
response_mode == "fragment"
|
157
|
+
end
|
158
|
+
|
159
|
+
def grant_type
|
160
|
+
response_type == "code" ? AUTHORIZATION_CODE : IMPLICIT
|
161
|
+
end
|
162
|
+
|
163
|
+
def pre_auth_hash
|
164
|
+
{
|
165
|
+
client_id: client.uid,
|
166
|
+
redirect_uri: redirect_uri,
|
167
|
+
state: state,
|
168
|
+
response_type: response_type,
|
169
|
+
scope: scope,
|
170
|
+
client_name: client.name,
|
171
|
+
status: I18n.t("doorkeeper.pre_authorization.status"),
|
172
|
+
}
|
173
|
+
end
|
104
174
|
end
|
105
175
|
end
|
106
176
|
end
|
@@ -11,28 +11,28 @@ module Doorkeeper
|
|
11
11
|
validate :client_match, error: :invalid_grant
|
12
12
|
validate :scope, error: :invalid_scope
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
attr_reader :access_token, :client, :credentials, :refresh_token
|
15
|
+
attr_reader :missing_param
|
16
16
|
|
17
17
|
def initialize(server, refresh_token, credentials, parameters = {})
|
18
|
-
@server
|
19
|
-
@refresh_token
|
20
|
-
@credentials
|
18
|
+
@server = server
|
19
|
+
@refresh_token = refresh_token
|
20
|
+
@credentials = credentials
|
21
21
|
@original_scopes = parameters[:scope] || parameters[:scopes]
|
22
22
|
@refresh_token_parameter = parameters[:refresh_token]
|
23
|
-
|
24
|
-
if credentials
|
25
|
-
@client = Application.by_uid_and_secret credentials.uid,
|
26
|
-
credentials.secret
|
27
|
-
end
|
23
|
+
@client = load_client(credentials) if credentials
|
28
24
|
end
|
29
25
|
|
30
26
|
private
|
31
27
|
|
28
|
+
def load_client(credentials)
|
29
|
+
Doorkeeper.config.application_model.by_uid_and_secret(credentials.uid, credentials.secret)
|
30
|
+
end
|
31
|
+
|
32
32
|
def before_successful_response
|
33
33
|
refresh_token.transaction do
|
34
34
|
refresh_token.lock!
|
35
|
-
raise Errors::
|
35
|
+
raise Errors::InvalidGrantReuse if refresh_token.revoked?
|
36
36
|
|
37
37
|
refresh_token.revoke unless refresh_token_revoked_on_use?
|
38
38
|
create_access_token
|
@@ -41,7 +41,7 @@ module Doorkeeper
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def refresh_token_revoked_on_use?
|
44
|
-
Doorkeeper
|
44
|
+
Doorkeeper.config.access_token_model.refresh_token_revoked_on_use?
|
45
45
|
end
|
46
46
|
|
47
47
|
def default_scopes
|
@@ -49,34 +49,46 @@ module Doorkeeper
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def create_access_token
|
52
|
-
|
53
|
-
end
|
52
|
+
attributes = {}.merge(custom_token_attributes_with_data)
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
expires_in: access_token_expires_in,
|
61
|
-
use_refresh_token: true,
|
62
|
-
}.tap do |attributes|
|
63
|
-
if refresh_token_revoked_on_use?
|
64
|
-
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
|
65
59
|
end
|
60
|
+
|
61
|
+
if refresh_token_revoked_on_use?
|
62
|
+
attributes[:previous_refresh_token] = refresh_token.refresh_token
|
66
63
|
end
|
67
|
-
end
|
68
64
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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 = Doorkeeper.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,
|
74
85
|
)
|
75
|
-
Authorization::Token.access_token_expires_in(server, context)
|
76
86
|
end
|
77
87
|
|
78
88
|
def validate_token_presence
|
79
|
-
refresh_token.
|
89
|
+
@missing_param = :refresh_token if refresh_token.blank? && @refresh_token_parameter.blank?
|
90
|
+
|
91
|
+
@missing_param.nil?
|
80
92
|
end
|
81
93
|
|
82
94
|
def validate_token
|
@@ -89,7 +101,7 @@ module Doorkeeper
|
|
89
101
|
client.present?
|
90
102
|
end
|
91
103
|
|
92
|
-
# @see https://
|
104
|
+
# @see https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
|
93
105
|
#
|
94
106
|
def validate_client_match
|
95
107
|
return true if refresh_token.application_id.blank?
|
@@ -101,12 +113,20 @@ module Doorkeeper
|
|
101
113
|
if @original_scopes.present?
|
102
114
|
ScopeChecker.valid?(
|
103
115
|
scope_str: @original_scopes,
|
104
|
-
server_scopes: refresh_token.scopes
|
116
|
+
server_scopes: refresh_token.scopes,
|
105
117
|
)
|
106
118
|
else
|
107
119
|
true
|
108
120
|
end
|
109
121
|
end
|
122
|
+
|
123
|
+
def custom_token_attributes_with_data
|
124
|
+
refresh_token
|
125
|
+
.attributes
|
126
|
+
.with_indifferent_access
|
127
|
+
.slice(*Doorkeeper.config.custom_access_token_attributes)
|
128
|
+
.symbolize_keys
|
129
|
+
end
|
110
130
|
end
|
111
131
|
end
|
112
132
|
end
|
@@ -8,15 +8,14 @@ module Doorkeeper
|
|
8
8
|
methods.inject(nil) do |_, method|
|
9
9
|
method = self.method(method) if method.is_a?(Symbol)
|
10
10
|
credentials = method.call(request)
|
11
|
-
break credentials
|
11
|
+
break credentials if credentials.present?
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
def authenticate(request, *methods)
|
16
16
|
if (token = from_request(request, *methods))
|
17
|
-
access_token =
|
18
|
-
|
19
|
-
if access_token.present? && refresh_token_enabled
|
17
|
+
access_token = Doorkeeper.config.access_token_model.by_token(token)
|
18
|
+
if access_token.present? && Doorkeeper.config.refresh_token_enabled?
|
20
19
|
access_token.revoke_previous_refresh_token!
|
21
20
|
end
|
22
21
|
access_token
|
@@ -33,13 +32,13 @@ module Doorkeeper
|
|
33
32
|
|
34
33
|
def from_bearer_authorization(request)
|
35
34
|
pattern = /^Bearer /i
|
36
|
-
header
|
35
|
+
header = request.authorization
|
37
36
|
token_from_header(header, pattern) if match?(header, pattern)
|
38
37
|
end
|
39
38
|
|
40
39
|
def from_basic_authorization(request)
|
41
40
|
pattern = /^Basic /i
|
42
|
-
header
|
41
|
+
header = request.authorization
|
43
42
|
token_from_basic_header(header, pattern) if match?(header, pattern)
|
44
43
|
end
|
45
44
|
|
@@ -55,7 +54,7 @@ module Doorkeeper
|
|
55
54
|
end
|
56
55
|
|
57
56
|
def token_from_header(header, pattern)
|
58
|
-
header.gsub
|
57
|
+
header.gsub(pattern, "")
|
59
58
|
end
|
60
59
|
|
61
60
|
def match?(header, pattern)
|
@@ -4,11 +4,8 @@ module Doorkeeper
|
|
4
4
|
module OAuth
|
5
5
|
# RFC7662 OAuth 2.0 Token Introspection
|
6
6
|
#
|
7
|
-
# @see https://
|
7
|
+
# @see https://datatracker.ietf.org/doc/html/rfc7662
|
8
8
|
class TokenIntrospection
|
9
|
-
attr_reader :server, :token
|
10
|
-
attr_reader :error
|
11
|
-
|
12
9
|
def initialize(server, token)
|
13
10
|
@server = server
|
14
11
|
@token = token
|
@@ -25,6 +22,8 @@ module Doorkeeper
|
|
25
22
|
|
26
23
|
if @error == :invalid_token
|
27
24
|
OAuth::InvalidTokenResponse.from_access_token(authorized_token)
|
25
|
+
elsif @error == :invalid_request
|
26
|
+
OAuth::InvalidRequestResponse.from_request(self)
|
28
27
|
else
|
29
28
|
OAuth::ErrorResponse.new(name: @error)
|
30
29
|
end
|
@@ -36,6 +35,9 @@ module Doorkeeper
|
|
36
35
|
|
37
36
|
private
|
38
37
|
|
38
|
+
attr_reader :server, :token
|
39
|
+
attr_reader :error, :invalid_request_reason
|
40
|
+
|
39
41
|
# If the protected resource uses OAuth 2.0 client credentials to
|
40
42
|
# authenticate to the introspection endpoint and its credentials are
|
41
43
|
# invalid, the authorization server responds with an HTTP 401
|
@@ -67,9 +69,10 @@ module Doorkeeper
|
|
67
69
|
# HTTP 401 code as described in Section 3 of OAuth 2.0 Bearer Token
|
68
70
|
# Usage [RFC6750].
|
69
71
|
#
|
70
|
-
@error = :invalid_token
|
72
|
+
@error = :invalid_token unless valid_authorized_token?
|
71
73
|
else
|
72
74
|
@error = :invalid_request
|
75
|
+
@invalid_request_reason = :request_not_authorized
|
73
76
|
end
|
74
77
|
end
|
75
78
|
|
@@ -80,8 +83,7 @@ module Doorkeeper
|
|
80
83
|
|
81
84
|
# Bearer Token Authentication
|
82
85
|
def authorized_token
|
83
|
-
@authorized_token ||=
|
84
|
-
OAuth::Token.authenticate(server.context.request, :from_bearer_authorization)
|
86
|
+
@authorized_token ||= Doorkeeper.authenticate(server.context.request)
|
85
87
|
end
|
86
88
|
|
87
89
|
# 2.2. Introspection Response
|
@@ -92,7 +94,7 @@ module Doorkeeper
|
|
92
94
|
client_id: @token.try(:application).try(:uid),
|
93
95
|
token_type: @token.token_type,
|
94
96
|
exp: @token.expires_at.to_i,
|
95
|
-
iat: @token.created_at.to_i
|
97
|
+
iat: @token.created_at.to_i,
|
96
98
|
)
|
97
99
|
end
|
98
100
|
|
@@ -105,7 +107,7 @@ module Doorkeeper
|
|
105
107
|
# authorization server SHOULD NOT include any additional information
|
106
108
|
# about an inactive token, including why the token is inactive.
|
107
109
|
#
|
108
|
-
# @see https://
|
110
|
+
# @see https://datatracker.ietf.org/doc/html/rfc7662 2.2. Introspection Response
|
109
111
|
#
|
110
112
|
def failure_response
|
111
113
|
{
|
@@ -132,7 +134,7 @@ module Doorkeeper
|
|
132
134
|
# Since resource servers using token introspection rely on the
|
133
135
|
# authorization server to determine the state of a token, the
|
134
136
|
# authorization server MUST perform all applicable checks against a
|
135
|
-
# token's state.
|
137
|
+
# token's state. For instance, these tests include the following:
|
136
138
|
#
|
137
139
|
# o If the token can expire, the authorization server MUST determine
|
138
140
|
# whether or not the token has expired.
|
@@ -150,7 +152,7 @@ module Doorkeeper
|
|
150
152
|
#
|
151
153
|
def active?
|
152
154
|
if authorized_client
|
153
|
-
valid_token? &&
|
155
|
+
valid_token? && token_introspection_allowed?(auth_client: authorized_client.application)
|
154
156
|
else
|
155
157
|
valid_token?
|
156
158
|
end
|
@@ -161,31 +163,35 @@ module Doorkeeper
|
|
161
163
|
@token&.accessible?
|
162
164
|
end
|
163
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
|
+
|
164
172
|
# RFC7662 Section 2.1
|
165
173
|
def authorized_token_matches_introspected?
|
166
174
|
authorized_token.token == @token&.token
|
167
175
|
end
|
168
176
|
|
169
|
-
#
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
true
|
176
|
-
end
|
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)
|
177
183
|
end
|
178
184
|
|
179
185
|
# Allows to customize introspection response.
|
180
186
|
# Provides context (controller) and token for generating developer-specific
|
181
187
|
# response.
|
182
188
|
#
|
183
|
-
# @see https://
|
189
|
+
# @see https://datatracker.ietf.org/doc/html/rfc7662#section-2.2
|
184
190
|
#
|
185
191
|
def customize_response(response)
|
186
|
-
customized_response = Doorkeeper.
|
192
|
+
customized_response = Doorkeeper.config.custom_introspection_response.call(
|
187
193
|
token,
|
188
|
-
server.context
|
194
|
+
server.context,
|
189
195
|
)
|
190
196
|
return response if customized_response.blank?
|
191
197
|
|
@@ -3,36 +3,22 @@
|
|
3
3
|
module Doorkeeper
|
4
4
|
module OAuth
|
5
5
|
class TokenRequest
|
6
|
-
|
6
|
+
attr_reader :pre_auth, :resource_owner
|
7
7
|
|
8
8
|
def initialize(pre_auth, resource_owner)
|
9
|
-
@pre_auth
|
9
|
+
@pre_auth = pre_auth
|
10
10
|
@resource_owner = resource_owner
|
11
11
|
end
|
12
12
|
|
13
13
|
def authorize
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@response = CodeResponse.new pre_auth,
|
18
|
-
auth,
|
19
|
-
response_on_fragment: true
|
20
|
-
else
|
21
|
-
@response = error_response
|
22
|
-
end
|
14
|
+
auth = Authorization::Token.new(pre_auth, resource_owner)
|
15
|
+
auth.issue_token!
|
16
|
+
CodeResponse.new(pre_auth, auth, response_on_fragment: true)
|
23
17
|
end
|
24
18
|
|
25
19
|
def deny
|
26
20
|
pre_auth.error = :access_denied
|
27
|
-
error_response
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def error_response
|
33
|
-
ErrorResponse.from_request pre_auth,
|
34
|
-
redirect_uri: pre_auth.redirect_uri,
|
35
|
-
response_on_fragment: true
|
21
|
+
pre_auth.error_response
|
36
22
|
end
|
37
23
|
end
|
38
24
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Doorkeeper
|
4
4
|
module OAuth
|
5
5
|
class TokenResponse
|
6
|
-
|
6
|
+
attr_reader :token
|
7
7
|
|
8
8
|
def initialize(token)
|
9
9
|
@token = token
|
@@ -26,8 +26,7 @@ module Doorkeeper
|
|
26
26
|
|
27
27
|
def headers
|
28
28
|
{
|
29
|
-
"Cache-Control" => "no-store",
|
30
|
-
"Pragma" => "no-cache",
|
29
|
+
"Cache-Control" => "no-store, no-cache",
|
31
30
|
"Content-Type" => "application/json; charset=utf-8",
|
32
31
|
}
|
33
32
|
end
|
@@ -1,48 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
class AccessGrant < ActiveRecord::Base
|
5
|
-
self.table_name = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}"
|
6
|
-
|
7
|
-
include AccessGrantMixin
|
8
|
-
|
9
|
-
belongs_to :application, class_name: "Doorkeeper::Application",
|
10
|
-
optional: true, inverse_of: :access_grants
|
11
|
-
|
12
|
-
validates :resource_owner_id,
|
13
|
-
:application_id,
|
14
|
-
:token,
|
15
|
-
:expires_in,
|
16
|
-
:redirect_uri,
|
17
|
-
presence: true
|
18
|
-
|
19
|
-
validates :token, uniqueness: true
|
3
|
+
require "doorkeeper/orm/active_record/mixins/access_grant"
|
20
4
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
# The stored refresh_token may be mapped and not available in cleartext.
|
25
|
-
#
|
26
|
-
# Some strategies allow restoring stored secrets (e.g. symmetric encryption)
|
27
|
-
# while hashing strategies do not, so you cannot rely on this value
|
28
|
-
# returning a present value for persisted tokens.
|
29
|
-
def plaintext_token
|
30
|
-
if secret_strategy.allows_restoring_secrets?
|
31
|
-
secret_strategy.restore_secret(self, :token)
|
32
|
-
else
|
33
|
-
@raw_token
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
# Generates token value with UniqueToken class.
|
40
|
-
#
|
41
|
-
# @return [String] token value
|
42
|
-
#
|
43
|
-
def generate_token
|
44
|
-
@raw_token = UniqueToken.generate
|
45
|
-
secret_strategy.store_secret(self, :token, @raw_token)
|
46
|
-
end
|
5
|
+
module Doorkeeper
|
6
|
+
class AccessGrant < ::ActiveRecord::Base
|
7
|
+
include Doorkeeper::Orm::ActiveRecord::Mixins::AccessGrant
|
47
8
|
end
|
48
9
|
end
|