doorkeeper 4.4.3 → 5.0.3
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/.gitignore +1 -0
- data/.gitlab-ci.yml +16 -0
- data/.travis.yml +7 -0
- data/Appraisals +2 -2
- data/Dangerfile +64 -0
- data/Gemfile +1 -1
- data/NEWS.md +98 -8
- data/README.md +110 -12
- data/Rakefile +6 -0
- data/UPGRADE.md +2 -0
- data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
- data/app/controllers/doorkeeper/application_controller.rb +6 -3
- data/app/controllers/doorkeeper/application_metal_controller.rb +6 -0
- data/app/controllers/doorkeeper/applications_controller.rb +46 -24
- data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +21 -2
- data/app/controllers/doorkeeper/token_info_controller.rb +2 -0
- data/app/controllers/doorkeeper/tokens_controller.rb +4 -6
- data/app/helpers/doorkeeper/dashboard_helper.rb +9 -7
- data/app/validators/redirect_uri_validator.rb +5 -2
- data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
- data/app/views/doorkeeper/applications/_form.html.erb +25 -24
- 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 +6 -6
- data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
- data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
- data/config/locales/en.yml +10 -1
- data/doorkeeper.gemspec +25 -26
- data/gemfiles/rails_5_2.gemfile +1 -1
- data/gemfiles/rails_master.gemfile +4 -1
- data/lib/doorkeeper/config.rb +81 -40
- data/lib/doorkeeper/engine.rb +6 -0
- data/lib/doorkeeper/errors.rb +17 -3
- data/lib/doorkeeper/grape/authorization_decorator.rb +2 -0
- data/lib/doorkeeper/grape/helpers.rb +3 -1
- data/lib/doorkeeper/helpers/controller.rb +9 -2
- data/lib/doorkeeper/models/access_grant_mixin.rb +73 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +44 -25
- data/lib/doorkeeper/models/application_mixin.rb +2 -0
- data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +2 -0
- data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +2 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +2 -0
- data/lib/doorkeeper/models/concerns/scopes.rb +3 -1
- data/lib/doorkeeper/oauth/authorization/code.rb +33 -8
- data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +38 -14
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +2 -0
- data/lib/doorkeeper/oauth/authorization_code_request.rb +29 -2
- data/lib/doorkeeper/oauth/base_request.rb +22 -9
- data/lib/doorkeeper/oauth/base_response.rb +2 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +3 -1
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +4 -1
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +7 -2
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +5 -5
- data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -3
- data/lib/doorkeeper/oauth/code_request.rb +2 -0
- data/lib/doorkeeper/oauth/code_response.rb +2 -0
- data/lib/doorkeeper/oauth/error.rb +2 -0
- data/lib/doorkeeper/oauth/error_response.rb +21 -3
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +9 -2
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -8
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +2 -0
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +5 -2
- data/lib/doorkeeper/oauth/invalid_token_response.rb +18 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +9 -4
- data/lib/doorkeeper/oauth/pre_authorization.rb +43 -11
- data/lib/doorkeeper/oauth/refresh_token_request.rb +16 -3
- data/lib/doorkeeper/oauth/scopes.rb +3 -1
- data/lib/doorkeeper/oauth/token.rb +7 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +4 -2
- data/lib/doorkeeper/oauth/token_request.rb +2 -0
- data/lib/doorkeeper/oauth/token_response.rb +6 -2
- data/lib/doorkeeper/oauth.rb +13 -0
- data/lib/doorkeeper/orm/active_record/application.rb +75 -12
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
- data/lib/doorkeeper/orm/active_record.rb +4 -0
- data/lib/doorkeeper/rails/helpers.rb +6 -4
- data/lib/doorkeeper/rails/routes/mapper.rb +2 -0
- data/lib/doorkeeper/rails/routes/mapping.rb +2 -0
- data/lib/doorkeeper/rails/routes.rb +23 -8
- data/lib/doorkeeper/rake/db.rake +40 -0
- data/lib/doorkeeper/rake/setup.rake +6 -0
- data/lib/doorkeeper/rake.rb +14 -0
- data/lib/doorkeeper/request/authorization_code.rb +1 -1
- data/lib/doorkeeper/request/client_credentials.rb +1 -1
- data/lib/doorkeeper/request/code.rb +1 -1
- data/lib/doorkeeper/request/password.rb +1 -1
- data/lib/doorkeeper/request/refresh_token.rb +1 -1
- data/lib/doorkeeper/request/strategy.rb +2 -0
- data/lib/doorkeeper/request/token.rb +1 -1
- data/lib/doorkeeper/request.rb +29 -34
- data/lib/doorkeeper/server.rb +2 -0
- data/lib/doorkeeper/stale_records_cleaner.rb +20 -0
- data/lib/doorkeeper/validations.rb +2 -0
- data/lib/doorkeeper/version.rb +6 -24
- data/lib/doorkeeper.rb +20 -17
- data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
- data/lib/generators/doorkeeper/install_generator.rb +17 -9
- data/lib/generators/doorkeeper/migration_generator.rb +23 -18
- data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
- data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +96 -13
- data/lib/generators/doorkeeper/templates/migration.rb.erb +2 -3
- data/lib/generators/doorkeeper/views_generator.rb +3 -1
- data/spec/controllers/application_metal_controller_spec.rb +50 -0
- data/spec/controllers/applications_controller_spec.rb +123 -14
- data/spec/controllers/authorizations_controller_spec.rb +334 -51
- data/spec/controllers/protected_resources_controller_spec.rb +60 -18
- data/spec/controllers/token_info_controller_spec.rb +4 -12
- data/spec/controllers/tokens_controller_spec.rb +17 -20
- data/spec/dummy/Rakefile +1 -1
- data/spec/dummy/app/assets/config/manifest.js +2 -0
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +1 -1
- data/spec/dummy/app/controllers/home_controller.rb +1 -2
- data/spec/dummy/config/application.rb +1 -1
- data/spec/dummy/config/boot.rb +2 -4
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/test.rb +5 -6
- data/spec/dummy/config/initializers/doorkeeper.rb +12 -6
- data/spec/dummy/config/initializers/new_framework_defaults.rb +2 -0
- data/spec/dummy/config/initializers/secret_token.rb +1 -1
- data/spec/dummy/config/routes.rb +3 -42
- data/spec/dummy/config.ru +1 -1
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +4 -4
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +1 -1
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
- data/spec/dummy/db/migrate/{20180210183654_add_confidential_to_application.rb → 20180210183654_add_confidential_to_applications.rb} +1 -1
- data/spec/dummy/db/schema.rb +36 -36
- data/spec/dummy/script/rails +4 -3
- data/spec/factories.rb +6 -6
- data/spec/generators/application_owner_generator_spec.rb +1 -1
- data/spec/generators/confidential_applications_generator_spec.rb +45 -0
- data/spec/generators/install_generator_spec.rb +5 -2
- data/spec/generators/migration_generator_spec.rb +1 -1
- data/spec/generators/pkce_generator_spec.rb +43 -0
- data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
- data/spec/generators/templates/routes.rb +0 -1
- data/spec/generators/views_generator_spec.rb +2 -2
- data/spec/grape/grape_integration_spec.rb +2 -2
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
- data/spec/lib/config_spec.rb +105 -39
- data/spec/lib/doorkeeper_spec.rb +6 -131
- data/spec/lib/models/expirable_spec.rb +0 -3
- data/spec/lib/models/revocable_spec.rb +0 -2
- data/spec/lib/models/scopes_spec.rb +0 -4
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
- data/spec/lib/oauth/authorization_code_request_spec.rb +17 -7
- data/spec/lib/oauth/base_request_spec.rb +49 -11
- data/spec/lib/oauth/base_response_spec.rb +1 -1
- data/spec/lib/oauth/client/credentials_spec.rb +2 -4
- data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +24 -7
- data/spec/lib/oauth/client_credentials/validation_spec.rb +4 -4
- data/spec/lib/oauth/client_credentials_integration_spec.rb +2 -2
- data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
- data/spec/lib/oauth/client_spec.rb +0 -3
- data/spec/lib/oauth/code_request_spec.rb +5 -3
- data/spec/lib/oauth/code_response_spec.rb +1 -1
- data/spec/lib/oauth/error_response_spec.rb +0 -3
- data/spec/lib/oauth/error_spec.rb +0 -2
- data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +8 -11
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +22 -13
- data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
- data/spec/lib/oauth/password_access_token_request_spec.rb +53 -6
- data/spec/lib/oauth/pre_authorization_spec.rb +33 -4
- data/spec/lib/oauth/refresh_token_request_spec.rb +22 -14
- data/spec/lib/oauth/scopes_spec.rb +0 -3
- data/spec/lib/oauth/token_request_spec.rb +8 -9
- data/spec/lib/oauth/token_response_spec.rb +0 -1
- data/spec/lib/oauth/token_spec.rb +40 -14
- data/spec/lib/request/strategy_spec.rb +0 -1
- data/spec/lib/server_spec.rb +7 -7
- data/spec/lib/stale_records_cleaner_spec.rb +89 -0
- data/spec/models/doorkeeper/access_grant_spec.rb +44 -1
- data/spec/models/doorkeeper/access_token_spec.rb +80 -32
- data/spec/models/doorkeeper/application_spec.rb +293 -221
- data/spec/requests/applications/applications_request_spec.rb +134 -1
- data/spec/requests/applications/authorized_applications_spec.rb +1 -1
- data/spec/requests/endpoints/authorization_spec.rb +3 -3
- data/spec/requests/endpoints/token_spec.rb +7 -5
- data/spec/requests/flows/authorization_code_errors_spec.rb +2 -2
- data/spec/requests/flows/authorization_code_spec.rb +258 -2
- data/spec/requests/flows/client_credentials_spec.rb +46 -6
- data/spec/requests/flows/implicit_grant_errors_spec.rb +3 -3
- data/spec/requests/flows/implicit_grant_spec.rb +38 -11
- data/spec/requests/flows/password_spec.rb +61 -3
- data/spec/requests/flows/refresh_token_spec.rb +59 -2
- data/spec/requests/flows/revoke_token_spec.rb +20 -20
- data/spec/requests/flows/skip_authorization_spec.rb +16 -11
- data/spec/requests/protected_resources/metal_spec.rb +1 -1
- data/spec/requests/protected_resources/private_api_spec.rb +3 -3
- data/spec/routing/custom_controller_routes_spec.rb +59 -7
- data/spec/routing/default_routes_spec.rb +2 -2
- data/spec/routing/scoped_routes_spec.rb +16 -2
- data/spec/spec_helper.rb +54 -3
- data/spec/spec_helper_integration.rb +2 -74
- data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
- data/spec/support/doorkeeper_rspec.rb +20 -0
- data/spec/support/helpers/authorization_request_helper.rb +4 -4
- data/spec/support/helpers/model_helper.rb +8 -4
- data/spec/support/helpers/request_spec_helper.rb +10 -2
- data/spec/support/helpers/url_helper.rb +18 -14
- data/spec/support/http_method_shim.rb +12 -16
- data/spec/support/shared/controllers_shared_context.rb +56 -0
- data/spec/validators/redirect_uri_validator_spec.rb +9 -3
- data/spec/version/version_spec.rb +3 -3
- data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
- metadata +54 -35
- 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
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module Models
|
3
5
|
module Scopes
|
@@ -10,7 +12,7 @@ module Doorkeeper
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def includes_scope?(*required_scopes)
|
13
|
-
required_scopes.blank? || required_scopes.any? { |
|
15
|
+
required_scopes.blank? || required_scopes.any? { |scope| scopes.exists?(scope.to_s) }
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
module Authorization
|
@@ -5,18 +7,12 @@ module Doorkeeper
|
|
5
7
|
attr_accessor :pre_auth, :resource_owner, :token
|
6
8
|
|
7
9
|
def initialize(pre_auth, resource_owner)
|
8
|
-
@pre_auth
|
10
|
+
@pre_auth = pre_auth
|
9
11
|
@resource_owner = resource_owner
|
10
12
|
end
|
11
13
|
|
12
14
|
def issue_token
|
13
|
-
@token ||= AccessGrant.create!
|
14
|
-
application_id: pre_auth.client.id,
|
15
|
-
resource_owner_id: resource_owner.id,
|
16
|
-
expires_in: configuration.authorization_code_expires_in,
|
17
|
-
redirect_uri: pre_auth.redirect_uri,
|
18
|
-
scopes: pre_auth.scopes.to_s
|
19
|
-
)
|
15
|
+
@token ||= AccessGrant.create! access_grant_attributes
|
20
16
|
end
|
21
17
|
|
22
18
|
def native_redirect
|
@@ -26,6 +22,35 @@ module Doorkeeper
|
|
26
22
|
def configuration
|
27
23
|
Doorkeeper.configuration
|
28
24
|
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def authorization_code_expires_in
|
29
|
+
configuration.authorization_code_expires_in
|
30
|
+
end
|
31
|
+
|
32
|
+
def access_grant_attributes
|
33
|
+
pkce_attributes.merge application_id: pre_auth.client.id,
|
34
|
+
resource_owner_id: resource_owner.id,
|
35
|
+
expires_in: authorization_code_expires_in,
|
36
|
+
redirect_uri: pre_auth.redirect_uri,
|
37
|
+
scopes: pre_auth.scopes.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
def pkce_attributes
|
41
|
+
return {} unless pkce_supported?
|
42
|
+
|
43
|
+
{
|
44
|
+
code_challenge: pre_auth.code_challenge,
|
45
|
+
code_challenge_method: pre_auth.code_challenge_method
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
# ensures firstly, if migration with additional pcke columns was
|
50
|
+
# generated and migrated
|
51
|
+
def pkce_supported?
|
52
|
+
Doorkeeper::AccessGrant.pkce_supported?
|
53
|
+
end
|
29
54
|
end
|
30
55
|
end
|
31
56
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module OAuth
|
5
|
+
module Authorization
|
6
|
+
class Context
|
7
|
+
attr_reader :client, :grant_type, :scopes
|
8
|
+
|
9
|
+
def initialize(client, grant_type, scopes)
|
10
|
+
@client = client
|
11
|
+
@grant_type = grant_type
|
12
|
+
@scopes = scopes
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
module Authorization
|
@@ -5,24 +7,34 @@ module Doorkeeper
|
|
5
7
|
attr_accessor :pre_auth, :resource_owner, :token
|
6
8
|
|
7
9
|
class << self
|
8
|
-
def
|
9
|
-
if (expiration = custom_expiration(server, pre_auth_or_oauth_client))
|
10
|
-
expiration
|
11
|
-
else
|
12
|
-
server.access_token_expires_in
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def custom_expiration(server, pre_auth_or_oauth_client)
|
10
|
+
def build_context(pre_auth_or_oauth_client, grant_type, scopes)
|
19
11
|
oauth_client = if pre_auth_or_oauth_client.respond_to?(:client)
|
20
12
|
pre_auth_or_oauth_client.client
|
21
13
|
else
|
22
14
|
pre_auth_or_oauth_client
|
23
15
|
end
|
24
16
|
|
25
|
-
|
17
|
+
Doorkeeper::OAuth::Authorization::Context.new(
|
18
|
+
oauth_client,
|
19
|
+
grant_type,
|
20
|
+
scopes
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def access_token_expires_in(server, context)
|
25
|
+
if (expiration = server.custom_access_token_expires_in.call(context))
|
26
|
+
expiration
|
27
|
+
else
|
28
|
+
server.access_token_expires_in
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def refresh_token_enabled?(server, context)
|
33
|
+
if server.refresh_token_enabled?.respond_to? :call
|
34
|
+
server.refresh_token_enabled?.call(context)
|
35
|
+
else
|
36
|
+
!!server.refresh_token_enabled?
|
37
|
+
end
|
26
38
|
end
|
27
39
|
end
|
28
40
|
|
@@ -32,18 +44,23 @@ module Doorkeeper
|
|
32
44
|
end
|
33
45
|
|
34
46
|
def issue_token
|
47
|
+
context = self.class.build_context(
|
48
|
+
pre_auth.client,
|
49
|
+
Doorkeeper::OAuth::IMPLICIT,
|
50
|
+
pre_auth.scopes
|
51
|
+
)
|
35
52
|
@token ||= AccessToken.find_or_create_for(
|
36
53
|
pre_auth.client,
|
37
54
|
resource_owner.id,
|
38
55
|
pre_auth.scopes,
|
39
|
-
self.class.access_token_expires_in(configuration,
|
56
|
+
self.class.access_token_expires_in(configuration, context),
|
40
57
|
false
|
41
58
|
)
|
42
59
|
end
|
43
60
|
|
44
61
|
def native_redirect
|
45
62
|
{
|
46
|
-
controller:
|
63
|
+
controller: controller,
|
47
64
|
action: :show,
|
48
65
|
access_token: token.token
|
49
66
|
}
|
@@ -54,6 +71,13 @@ module Doorkeeper
|
|
54
71
|
def configuration
|
55
72
|
Doorkeeper.configuration
|
56
73
|
end
|
74
|
+
|
75
|
+
def controller
|
76
|
+
@controller ||= begin
|
77
|
+
mapping = Doorkeeper::Rails::Routes.mapping[:token_info] || {}
|
78
|
+
mapping[:controllers] || 'doorkeeper/token_info'
|
79
|
+
end
|
80
|
+
end
|
57
81
|
end
|
58
82
|
end
|
59
83
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class AuthorizationCodeRequest < BaseRequest
|
@@ -6,18 +8,26 @@ module Doorkeeper
|
|
6
8
|
validate :grant, error: :invalid_grant
|
7
9
|
# @see https://tools.ietf.org/html/rfc6749#section-5.2
|
8
10
|
validate :redirect_uri, error: :invalid_grant
|
11
|
+
validate :code_verifier, error: :invalid_grant
|
9
12
|
|
10
|
-
attr_accessor :server, :grant, :client, :redirect_uri, :access_token
|
13
|
+
attr_accessor :server, :grant, :client, :redirect_uri, :access_token,
|
14
|
+
:code_verifier
|
11
15
|
|
12
16
|
def initialize(server, grant, client, parameters = {})
|
13
17
|
@server = server
|
14
18
|
@client = client
|
15
19
|
@grant = grant
|
20
|
+
@grant_type = Doorkeeper::OAuth::AUTHORIZATION_CODE
|
16
21
|
@redirect_uri = parameters[:redirect_uri]
|
22
|
+
@code_verifier = parameters[:code_verifier]
|
17
23
|
end
|
18
24
|
|
19
25
|
private
|
20
26
|
|
27
|
+
def client_by_uid(parameters)
|
28
|
+
Doorkeeper::Application.by_uid(parameters[:client_id])
|
29
|
+
end
|
30
|
+
|
21
31
|
def before_successful_response
|
22
32
|
grant.transaction do
|
23
33
|
grant.lock!
|
@@ -33,11 +43,13 @@ module Doorkeeper
|
|
33
43
|
end
|
34
44
|
|
35
45
|
def validate_attributes
|
46
|
+
return false if grant && grant.uses_pkce? && code_verifier.blank?
|
47
|
+
return false if grant && !grant.pkce_supported? && !code_verifier.blank?
|
36
48
|
redirect_uri.present?
|
37
49
|
end
|
38
50
|
|
39
51
|
def validate_client
|
40
|
-
|
52
|
+
!client.nil?
|
41
53
|
end
|
42
54
|
|
43
55
|
def validate_grant
|
@@ -51,6 +63,21 @@ module Doorkeeper
|
|
51
63
|
grant.redirect_uri
|
52
64
|
)
|
53
65
|
end
|
66
|
+
|
67
|
+
# if either side (server or client) request pkce, check the verifier
|
68
|
+
# against the DB - if pkce is supported
|
69
|
+
def validate_code_verifier
|
70
|
+
return true unless grant.uses_pkce? || code_verifier
|
71
|
+
return false unless grant.pkce_supported?
|
72
|
+
|
73
|
+
if grant.code_challenge_method == 'S256'
|
74
|
+
grant.code_challenge == AccessGrant.generate_code_challenge(code_verifier)
|
75
|
+
elsif grant.code_challenge_method == 'plain'
|
76
|
+
grant.code_challenge == code_verifier
|
77
|
+
else
|
78
|
+
false
|
79
|
+
end
|
80
|
+
end
|
54
81
|
end
|
55
82
|
end
|
56
83
|
end
|
@@ -1,8 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class BaseRequest
|
4
6
|
include Validations
|
5
7
|
|
8
|
+
attr_reader :grant_type
|
9
|
+
|
6
10
|
def authorize
|
7
11
|
validate
|
8
12
|
|
@@ -17,11 +21,7 @@ module Doorkeeper
|
|
17
21
|
end
|
18
22
|
|
19
23
|
def scopes
|
20
|
-
@scopes ||=
|
21
|
-
OAuth::Scopes.from_string(@original_scopes)
|
22
|
-
else
|
23
|
-
default_scopes
|
24
|
-
end
|
24
|
+
@scopes ||= build_scopes
|
25
25
|
end
|
26
26
|
|
27
27
|
def default_scopes
|
@@ -33,12 +33,13 @@ module Doorkeeper
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def find_or_create_access_token(client, resource_owner_id, scopes, server)
|
36
|
+
context = Authorization::Token.build_context(client, grant_type, scopes)
|
36
37
|
@access_token = AccessToken.find_or_create_for(
|
37
38
|
client,
|
38
39
|
resource_owner_id,
|
39
40
|
scopes,
|
40
|
-
Authorization::Token.access_token_expires_in(server,
|
41
|
-
|
41
|
+
Authorization::Token.access_token_expires_in(server, context),
|
42
|
+
Authorization::Token.refresh_token_enabled?(server, context)
|
42
43
|
)
|
43
44
|
end
|
44
45
|
|
@@ -47,8 +48,20 @@ module Doorkeeper
|
|
47
48
|
end
|
48
49
|
|
49
50
|
def after_successful_response
|
50
|
-
Doorkeeper.configuration.after_successful_strategy_response.
|
51
|
-
|
51
|
+
Doorkeeper.configuration.after_successful_strategy_response.call(self, @response)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def build_scopes
|
57
|
+
if @original_scopes.present?
|
58
|
+
OAuth::Scopes.from_string(@original_scopes)
|
59
|
+
else
|
60
|
+
client_scopes = @client.try(:scopes)
|
61
|
+
return default_scopes if client_scopes.blank?
|
62
|
+
|
63
|
+
default_scopes & @client.scopes
|
64
|
+
end
|
52
65
|
end
|
53
66
|
end
|
54
67
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class Client
|
4
6
|
Credentials = Struct.new(:uid, :secret) do
|
5
7
|
class << self
|
6
8
|
def from_request(request, *credentials_methods)
|
7
|
-
credentials_methods.inject(nil) do |
|
9
|
+
credentials_methods.inject(nil) do |_, method|
|
8
10
|
method = self.method(method) if method.is_a?(Symbol)
|
9
11
|
credentials = Credentials.new(*method.call(request))
|
10
12
|
break credentials unless credentials.blank?
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class ClientCredentialsRequest < BaseRequest
|
@@ -5,7 +7,8 @@ module Doorkeeper
|
|
5
7
|
def call(client, scopes, attributes = {})
|
6
8
|
AccessToken.find_or_create_for(
|
7
9
|
client, nil, scopes, attributes[:expires_in],
|
8
|
-
attributes[:use_refresh_token]
|
10
|
+
attributes[:use_refresh_token]
|
11
|
+
)
|
9
12
|
end
|
10
13
|
end
|
11
14
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Doorkeeper
|
4
4
|
module OAuth
|
@@ -25,7 +25,12 @@ module Doorkeeper
|
|
25
25
|
private
|
26
26
|
|
27
27
|
def create_token(client, scopes, creator)
|
28
|
-
|
28
|
+
context = Authorization::Token.build_context(
|
29
|
+
client,
|
30
|
+
Doorkeeper::OAuth::CLIENT_CREDENTIALS,
|
31
|
+
scopes
|
32
|
+
)
|
33
|
+
ttl = Authorization::Token.access_token_expires_in(@server, context)
|
29
34
|
|
30
35
|
creator.call(
|
31
36
|
client,
|
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'doorkeeper/oauth/scopes'
|
3
|
-
require 'doorkeeper/oauth/helpers/scope_checker'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
3
|
module Doorkeeper
|
6
4
|
module OAuth
|
@@ -13,7 +11,9 @@ module Doorkeeper
|
|
13
11
|
validate :scopes, error: :invalid_scope
|
14
12
|
|
15
13
|
def initialize(server, request)
|
16
|
-
@server
|
14
|
+
@server = server
|
15
|
+
@request = request
|
16
|
+
@client = request.client
|
17
17
|
|
18
18
|
validate
|
19
19
|
end
|
@@ -25,7 +25,7 @@ module Doorkeeper
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def validate_scopes
|
28
|
-
return true
|
28
|
+
return true if @request.scopes.blank?
|
29
29
|
|
30
30
|
application_scopes = if @client.present?
|
31
31
|
@client.application.scopes
|
@@ -1,10 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class ErrorResponse < BaseResponse
|
4
6
|
include OAuth::Helpers
|
5
7
|
|
6
8
|
def self.from_request(request, attributes = {})
|
7
|
-
new(
|
9
|
+
new(
|
10
|
+
attributes.merge(
|
11
|
+
name: request.error,
|
12
|
+
state: request.try(:state),
|
13
|
+
redirect_uri: request.try(:redirect_uri)
|
14
|
+
)
|
15
|
+
)
|
8
16
|
end
|
9
17
|
|
10
18
|
delegate :name, :description, :state, to: :@error
|
@@ -41,10 +49,16 @@ module Doorkeeper
|
|
41
49
|
end
|
42
50
|
|
43
51
|
def headers
|
44
|
-
{
|
52
|
+
{
|
53
|
+
'Cache-Control' => 'no-store',
|
45
54
|
'Pragma' => 'no-cache',
|
46
55
|
'Content-Type' => 'application/json; charset=utf-8',
|
47
|
-
'WWW-Authenticate' => authenticate_info
|
56
|
+
'WWW-Authenticate' => authenticate_info
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
def raise_exception!
|
61
|
+
raise exception_class.new(self), description
|
48
62
|
end
|
49
63
|
|
50
64
|
protected
|
@@ -55,6 +69,10 @@ module Doorkeeper
|
|
55
69
|
Doorkeeper.configuration
|
56
70
|
end
|
57
71
|
|
72
|
+
def exception_class
|
73
|
+
raise NotImplementedError, "error response must define #exception_class"
|
74
|
+
end
|
75
|
+
|
58
76
|
private
|
59
77
|
|
60
78
|
def authenticate_info
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class ForbiddenTokenResponse < ErrorResponse
|
@@ -21,8 +23,13 @@ module Doorkeeper
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def description
|
24
|
-
|
25
|
-
|
26
|
+
@description ||= @scopes.map { |s| I18n.t(s, scope: %i[doorkeeper scopes]) }.join("\n")
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def exception_class
|
32
|
+
Doorkeeper::Errors::TokenForbidden
|
26
33
|
end
|
27
34
|
end
|
28
35
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
module Helpers
|
@@ -17,10 +19,6 @@ module Doorkeeper
|
|
17
19
|
@valid_scopes.has_scopes?(parsed_scopes)
|
18
20
|
end
|
19
21
|
|
20
|
-
def match?
|
21
|
-
valid? && parsed_scopes.has_scopes?(@valid_scopes)
|
22
|
-
end
|
23
|
-
|
24
22
|
private
|
25
23
|
|
26
24
|
def valid_scopes(server_scopes, application_scopes)
|
@@ -35,10 +33,6 @@ module Doorkeeper
|
|
35
33
|
def self.valid?(scope_str, server_scopes, application_scopes = nil)
|
36
34
|
Validator.new(scope_str, server_scopes, application_scopes).valid?
|
37
35
|
end
|
38
|
-
|
39
|
-
def self.match?(scope_str, server_scopes, application_scopes = nil)
|
40
|
-
Validator.new(scope_str, server_scopes, application_scopes).match?
|
41
|
-
end
|
42
36
|
end
|
43
37
|
end
|
44
38
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
module Helpers
|
@@ -14,12 +16,13 @@ module Doorkeeper
|
|
14
16
|
url = as_uri(url)
|
15
17
|
client_url = as_uri(client_url)
|
16
18
|
|
17
|
-
|
19
|
+
unless client_url.query.nil?
|
18
20
|
return false unless query_matches?(url.query, client_url.query)
|
19
21
|
# Clear out queries so rest of URI can be tested. This allows query
|
20
22
|
# params to be in the request but order not mattering.
|
21
23
|
client_url.query = nil
|
22
24
|
end
|
25
|
+
|
23
26
|
url.query = nil
|
24
27
|
url == client_url
|
25
28
|
end
|
@@ -33,7 +36,7 @@ module Doorkeeper
|
|
33
36
|
end
|
34
37
|
|
35
38
|
def self.query_matches?(query, client_query)
|
36
|
-
return true if client_query.
|
39
|
+
return true if client_query.blank? && query.blank?
|
37
40
|
return false if client_query.nil? || query.nil?
|
38
41
|
# Will return true independent of query order
|
39
42
|
client_query.split('&').sort == query.split('&').sort
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class InvalidTokenResponse < ErrorResponse
|
@@ -24,6 +26,22 @@ module Doorkeeper
|
|
24
26
|
scope = { scope: %i[doorkeeper errors messages invalid_token] }
|
25
27
|
@description ||= I18n.translate @reason, scope
|
26
28
|
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def exception_class
|
33
|
+
errors_mapping.fetch(reason)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def errors_mapping
|
39
|
+
{
|
40
|
+
expired: Doorkeeper::Errors::TokenExpired,
|
41
|
+
revoked: Doorkeeper::Errors::TokenRevoked,
|
42
|
+
unknown: Doorkeeper::Errors::TokenUnknown
|
43
|
+
}
|
44
|
+
end
|
27
45
|
end
|
28
46
|
end
|
29
47
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class PasswordAccessTokenRequest < BaseRequest
|
@@ -16,6 +18,7 @@ module Doorkeeper
|
|
16
18
|
@client = client
|
17
19
|
@parameters = parameters
|
18
20
|
@original_scopes = parameters[:scope]
|
21
|
+
@grant_type = Doorkeeper::OAuth::PASSWORD
|
19
22
|
end
|
20
23
|
|
21
24
|
private
|
@@ -26,16 +29,18 @@ module Doorkeeper
|
|
26
29
|
end
|
27
30
|
|
28
31
|
def validate_scopes
|
29
|
-
|
30
|
-
|
32
|
+
client_scopes = client.try(:scopes)
|
33
|
+
return true if scopes.blank?
|
34
|
+
|
35
|
+
ScopeChecker.valid?(scopes.to_s, server.scopes, client_scopes)
|
31
36
|
end
|
32
37
|
|
33
38
|
def validate_resource_owner
|
34
|
-
|
39
|
+
!resource_owner.nil?
|
35
40
|
end
|
36
41
|
|
37
42
|
def validate_client
|
38
|
-
!parameters[:client_id] ||
|
43
|
+
!parameters[:client_id] || !client.nil?
|
39
44
|
end
|
40
45
|
end
|
41
46
|
end
|