doorkeeper 4.3.2 → 5.0.0
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/.gitignore +1 -0
- data/.gitlab-ci.yml +16 -0
- data/.rubocop.yml +4 -0
- data/.travis.yml +2 -0
- data/Appraisals +2 -2
- data/Gemfile +1 -1
- data/NEWS.md +70 -0
- data/README.md +92 -9
- 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 +4 -3
- data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
- data/app/controllers/doorkeeper/applications_controller.rb +43 -22
- data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +19 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +11 -16
- data/app/helpers/doorkeeper/dashboard_helper.rb +7 -7
- data/app/validators/redirect_uri_validator.rb +3 -2
- data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
- data/app/views/doorkeeper/applications/_form.html.erb +31 -19
- 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 +8 -5
- 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 +16 -1
- data/doorkeeper.gemspec +18 -18
- data/gemfiles/rails_5_2.gemfile +1 -1
- data/gemfiles/rails_master.gemfile +4 -1
- data/lib/doorkeeper/config.rb +77 -27
- data/lib/doorkeeper/engine.rb +4 -0
- data/lib/doorkeeper/errors.rb +2 -5
- data/lib/doorkeeper/grape/helpers.rb +1 -1
- data/lib/doorkeeper/helpers/controller.rb +7 -2
- data/lib/doorkeeper/models/access_grant_mixin.rb +71 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +40 -23
- data/lib/doorkeeper/models/application_mixin.rb +8 -1
- data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
- data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
- data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +36 -14
- data/lib/doorkeeper/oauth/authorization_code_request.rb +27 -2
- data/lib/doorkeeper/oauth/base_request.rb +20 -9
- data/lib/doorkeeper/oauth/client/credentials.rb +4 -2
- data/lib/doorkeeper/oauth/client.rb +0 -2
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -1
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -3
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -6
- data/lib/doorkeeper/oauth/client_credentials_request.rb +0 -4
- data/lib/doorkeeper/oauth/error_response.rb +11 -3
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +1 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -4
- data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
- data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -1
- data/lib/doorkeeper/oauth/scopes.rb +1 -1
- data/lib/doorkeeper/oauth/token.rb +5 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +2 -2
- data/lib/doorkeeper/oauth/token_response.rb +4 -2
- data/lib/doorkeeper/oauth.rb +13 -0
- data/lib/doorkeeper/orm/active_record/application.rb +25 -0
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
- data/lib/doorkeeper/orm/active_record.rb +2 -0
- data/lib/doorkeeper/rails/helpers.rb +2 -4
- data/lib/doorkeeper/rails/routes.rb +13 -1
- 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 +0 -2
- data/lib/doorkeeper/request/client_credentials.rb +0 -2
- data/lib/doorkeeper/request/code.rb +0 -2
- data/lib/doorkeeper/request/password.rb +1 -13
- data/lib/doorkeeper/request/refresh_token.rb +0 -2
- data/lib/doorkeeper/request/token.rb +0 -2
- data/lib/doorkeeper/request.rb +28 -35
- data/lib/doorkeeper/version.rb +5 -4
- data/lib/doorkeeper.rb +19 -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 +76 -11
- data/lib/generators/doorkeeper/templates/migration.rb.erb +1 -0
- 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 +126 -13
- data/spec/controllers/authorizations_controller_spec.rb +279 -17
- data/spec/controllers/protected_resources_controller_spec.rb +16 -16
- data/spec/controllers/token_info_controller_spec.rb +4 -12
- data/spec/controllers/tokens_controller_spec.rb +72 -22
- data/spec/dummy/app/assets/config/manifest.js +2 -0
- data/spec/dummy/config/environments/test.rb +4 -5
- data/spec/dummy/config/initializers/doorkeeper.rb +11 -1
- data/spec/dummy/config/initializers/new_framework_defaults.rb +4 -0
- data/spec/dummy/config/routes.rb +3 -42
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
- data/spec/dummy/db/schema.rb +38 -37
- 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 +1 -1
- 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/views_generator_spec.rb +1 -1
- data/spec/grape/grape_integration_spec.rb +1 -1
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
- data/spec/lib/config_spec.rb +88 -14
- data/spec/lib/doorkeeper_spec.rb +1 -126
- 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 +24 -2
- data/spec/lib/oauth/base_request_spec.rb +40 -2
- data/spec/lib/oauth/base_response_spec.rb +1 -1
- data/spec/lib/oauth/client/credentials_spec.rb +5 -5
- data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
- data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
- data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
- 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 +4 -2
- 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 +0 -3
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -2
- data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
- data/spec/lib/oauth/password_access_token_request_spec.rb +37 -2
- data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
- data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
- data/spec/lib/oauth/scopes_spec.rb +0 -3
- data/spec/lib/oauth/token_request_spec.rb +4 -5
- data/spec/lib/oauth/token_response_spec.rb +0 -1
- data/spec/lib/oauth/token_spec.rb +37 -14
- data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
- data/spec/lib/request/strategy_spec.rb +0 -1
- data/spec/lib/server_spec.rb +1 -1
- data/spec/models/doorkeeper/access_grant_spec.rb +44 -1
- data/spec/models/doorkeeper/access_token_spec.rb +66 -22
- data/spec/models/doorkeeper/application_spec.rb +64 -6
- 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 +1 -1
- data/spec/requests/endpoints/token_spec.rb +7 -5
- data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
- data/spec/requests/flows/authorization_code_spec.rb +198 -2
- data/spec/requests/flows/client_credentials_spec.rb +46 -6
- data/spec/requests/flows/implicit_grant_errors_spec.rb +1 -1
- data/spec/requests/flows/implicit_grant_spec.rb +38 -11
- data/spec/requests/flows/password_spec.rb +120 -23
- data/spec/requests/flows/refresh_token_spec.rb +2 -2
- data/spec/requests/flows/revoke_token_spec.rb +11 -11
- 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 +1 -1
- 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/doorkeeper_rspec.rb +19 -0
- data/spec/support/helpers/authorization_request_helper.rb +4 -4
- data/spec/support/helpers/request_spec_helper.rb +10 -2
- data/spec/support/helpers/url_helper.rb +7 -3
- data/spec/support/http_method_shim.rb +12 -16
- data/spec/validators/redirect_uri_validator_spec.rb +7 -1
- data/spec/version/version_spec.rb +3 -3
- data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
- metadata +36 -10
- data/spec/controllers/application_metal_controller.rb +0 -10
- /data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
|
@@ -6,18 +6,26 @@ module Doorkeeper
|
|
|
6
6
|
validate :grant, error: :invalid_grant
|
|
7
7
|
# @see https://tools.ietf.org/html/rfc6749#section-5.2
|
|
8
8
|
validate :redirect_uri, error: :invalid_grant
|
|
9
|
+
validate :code_verifier, error: :invalid_grant
|
|
9
10
|
|
|
10
|
-
attr_accessor :server, :grant, :client, :redirect_uri, :access_token
|
|
11
|
+
attr_accessor :server, :grant, :client, :redirect_uri, :access_token,
|
|
12
|
+
:code_verifier
|
|
11
13
|
|
|
12
14
|
def initialize(server, grant, client, parameters = {})
|
|
13
15
|
@server = server
|
|
14
16
|
@client = client
|
|
15
17
|
@grant = grant
|
|
18
|
+
@grant_type = Doorkeeper::OAuth::AUTHORIZATION_CODE
|
|
16
19
|
@redirect_uri = parameters[:redirect_uri]
|
|
20
|
+
@code_verifier = parameters[:code_verifier]
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
private
|
|
20
24
|
|
|
25
|
+
def client_by_uid(parameters)
|
|
26
|
+
Doorkeeper::Application.by_uid(parameters[:client_id])
|
|
27
|
+
end
|
|
28
|
+
|
|
21
29
|
def before_successful_response
|
|
22
30
|
grant.transaction do
|
|
23
31
|
grant.lock!
|
|
@@ -33,11 +41,13 @@ module Doorkeeper
|
|
|
33
41
|
end
|
|
34
42
|
|
|
35
43
|
def validate_attributes
|
|
44
|
+
return false if grant && grant.uses_pkce? && code_verifier.blank?
|
|
45
|
+
return false if grant && !grant.pkce_supported? && !code_verifier.blank?
|
|
36
46
|
redirect_uri.present?
|
|
37
47
|
end
|
|
38
48
|
|
|
39
49
|
def validate_client
|
|
40
|
-
|
|
50
|
+
!client.nil?
|
|
41
51
|
end
|
|
42
52
|
|
|
43
53
|
def validate_grant
|
|
@@ -51,6 +61,21 @@ module Doorkeeper
|
|
|
51
61
|
grant.redirect_uri
|
|
52
62
|
)
|
|
53
63
|
end
|
|
64
|
+
|
|
65
|
+
# if either side (server or client) request pkce, check the verifier
|
|
66
|
+
# against the DB - if pkce is supported
|
|
67
|
+
def validate_code_verifier
|
|
68
|
+
return true unless grant.uses_pkce? || code_verifier
|
|
69
|
+
return false unless grant.pkce_supported?
|
|
70
|
+
|
|
71
|
+
if grant.code_challenge_method == 'S256'
|
|
72
|
+
grant.code_challenge == AccessGrant.generate_code_challenge(code_verifier)
|
|
73
|
+
elsif grant.code_challenge_method == 'plain'
|
|
74
|
+
grant.code_challenge == code_verifier
|
|
75
|
+
else
|
|
76
|
+
false
|
|
77
|
+
end
|
|
78
|
+
end
|
|
54
79
|
end
|
|
55
80
|
end
|
|
56
81
|
end
|
|
@@ -3,6 +3,8 @@ module Doorkeeper
|
|
|
3
3
|
class BaseRequest
|
|
4
4
|
include Validations
|
|
5
5
|
|
|
6
|
+
attr_reader :grant_type
|
|
7
|
+
|
|
6
8
|
def authorize
|
|
7
9
|
validate
|
|
8
10
|
|
|
@@ -17,11 +19,7 @@ module Doorkeeper
|
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def scopes
|
|
20
|
-
@scopes ||=
|
|
21
|
-
OAuth::Scopes.from_string(@original_scopes)
|
|
22
|
-
else
|
|
23
|
-
default_scopes
|
|
24
|
-
end
|
|
22
|
+
@scopes ||= build_scopes
|
|
25
23
|
end
|
|
26
24
|
|
|
27
25
|
def default_scopes
|
|
@@ -33,12 +31,13 @@ module Doorkeeper
|
|
|
33
31
|
end
|
|
34
32
|
|
|
35
33
|
def find_or_create_access_token(client, resource_owner_id, scopes, server)
|
|
34
|
+
context = Authorization::Token.build_context(client, grant_type, scopes)
|
|
36
35
|
@access_token = AccessToken.find_or_create_for(
|
|
37
36
|
client,
|
|
38
37
|
resource_owner_id,
|
|
39
38
|
scopes,
|
|
40
|
-
Authorization::Token.access_token_expires_in(server,
|
|
41
|
-
|
|
39
|
+
Authorization::Token.access_token_expires_in(server, context),
|
|
40
|
+
Authorization::Token.refresh_token_enabled?(server, context)
|
|
42
41
|
)
|
|
43
42
|
end
|
|
44
43
|
|
|
@@ -47,8 +46,20 @@ module Doorkeeper
|
|
|
47
46
|
end
|
|
48
47
|
|
|
49
48
|
def after_successful_response
|
|
50
|
-
Doorkeeper.configuration.after_successful_strategy_response.
|
|
51
|
-
|
|
49
|
+
Doorkeeper.configuration.after_successful_strategy_response.call(self, @response)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def build_scopes
|
|
55
|
+
if @original_scopes.present?
|
|
56
|
+
OAuth::Scopes.from_string(@original_scopes)
|
|
57
|
+
else
|
|
58
|
+
client_scopes = @client.try(:scopes)
|
|
59
|
+
return default_scopes if client_scopes.blank?
|
|
60
|
+
|
|
61
|
+
default_scopes & @client.scopes
|
|
62
|
+
end
|
|
52
63
|
end
|
|
53
64
|
end
|
|
54
65
|
end
|
|
@@ -4,7 +4,7 @@ module Doorkeeper
|
|
|
4
4
|
Credentials = Struct.new(:uid, :secret) do
|
|
5
5
|
class << self
|
|
6
6
|
def from_request(request, *credentials_methods)
|
|
7
|
-
credentials_methods.inject(nil) do |
|
|
7
|
+
credentials_methods.inject(nil) do |_, method|
|
|
8
8
|
method = self.method(method) if method.is_a?(Symbol)
|
|
9
9
|
credentials = Credentials.new(*method.call(request))
|
|
10
10
|
break credentials unless credentials.blank?
|
|
@@ -23,8 +23,10 @@ module Doorkeeper
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
# Public clients may have their secret blank, but "credentials" are
|
|
27
|
+
# still present
|
|
26
28
|
def blank?
|
|
27
|
-
uid.blank?
|
|
29
|
+
uid.blank?
|
|
28
30
|
end
|
|
29
31
|
end
|
|
30
32
|
end
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'doorkeeper/oauth/client_credentials/validation'
|
|
2
|
-
|
|
3
1
|
module Doorkeeper
|
|
4
2
|
module OAuth
|
|
5
3
|
class ClientCredentialsRequest < BaseRequest
|
|
@@ -25,7 +23,12 @@ module Doorkeeper
|
|
|
25
23
|
private
|
|
26
24
|
|
|
27
25
|
def create_token(client, scopes, creator)
|
|
28
|
-
|
|
26
|
+
context = Authorization::Token.build_context(
|
|
27
|
+
client,
|
|
28
|
+
Doorkeeper::OAuth::CLIENT_CREDENTIALS,
|
|
29
|
+
scopes
|
|
30
|
+
)
|
|
31
|
+
ttl = Authorization::Token.access_token_expires_in(@server, context)
|
|
29
32
|
|
|
30
33
|
creator.call(
|
|
31
34
|
client,
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
require 'doorkeeper/validations'
|
|
2
|
-
require 'doorkeeper/oauth/scopes'
|
|
3
|
-
require 'doorkeeper/oauth/helpers/scope_checker'
|
|
4
|
-
|
|
5
1
|
module Doorkeeper
|
|
6
2
|
module OAuth
|
|
7
3
|
class ClientCredentialsRequest < BaseRequest
|
|
@@ -13,7 +9,9 @@ module Doorkeeper
|
|
|
13
9
|
validate :scopes, error: :invalid_scope
|
|
14
10
|
|
|
15
11
|
def initialize(server, request)
|
|
16
|
-
@server
|
|
12
|
+
@server = server
|
|
13
|
+
@request = request
|
|
14
|
+
@client = request.client
|
|
17
15
|
|
|
18
16
|
validate
|
|
19
17
|
end
|
|
@@ -25,7 +23,7 @@ module Doorkeeper
|
|
|
25
23
|
end
|
|
26
24
|
|
|
27
25
|
def validate_scopes
|
|
28
|
-
return true
|
|
26
|
+
return true if @request.scopes.blank?
|
|
29
27
|
|
|
30
28
|
application_scopes = if @client.present?
|
|
31
29
|
@client.application.scopes
|
|
@@ -4,7 +4,13 @@ module Doorkeeper
|
|
|
4
4
|
include OAuth::Helpers
|
|
5
5
|
|
|
6
6
|
def self.from_request(request, attributes = {})
|
|
7
|
-
new(
|
|
7
|
+
new(
|
|
8
|
+
attributes.merge(
|
|
9
|
+
name: request.error,
|
|
10
|
+
state: request.try(:state),
|
|
11
|
+
redirect_uri: request.try(:redirect_uri)
|
|
12
|
+
)
|
|
13
|
+
)
|
|
8
14
|
end
|
|
9
15
|
|
|
10
16
|
delegate :name, :description, :state, to: :@error
|
|
@@ -41,10 +47,12 @@ module Doorkeeper
|
|
|
41
47
|
end
|
|
42
48
|
|
|
43
49
|
def headers
|
|
44
|
-
{
|
|
50
|
+
{
|
|
51
|
+
'Cache-Control' => 'no-store',
|
|
45
52
|
'Pragma' => 'no-cache',
|
|
46
53
|
'Content-Type' => 'application/json; charset=utf-8',
|
|
47
|
-
'WWW-Authenticate' => authenticate_info
|
|
54
|
+
'WWW-Authenticate' => authenticate_info
|
|
55
|
+
}
|
|
48
56
|
end
|
|
49
57
|
|
|
50
58
|
protected
|
|
@@ -17,10 +17,6 @@ module Doorkeeper
|
|
|
17
17
|
@valid_scopes.has_scopes?(parsed_scopes)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
def match?
|
|
21
|
-
valid? && parsed_scopes.has_scopes?(@valid_scopes)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
20
|
private
|
|
25
21
|
|
|
26
22
|
def valid_scopes(server_scopes, application_scopes)
|
|
@@ -35,10 +31,6 @@ module Doorkeeper
|
|
|
35
31
|
def self.valid?(scope_str, server_scopes, application_scopes = nil)
|
|
36
32
|
Validator.new(scope_str, server_scopes, application_scopes).valid?
|
|
37
33
|
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
34
|
end
|
|
43
35
|
end
|
|
44
36
|
end
|
|
@@ -16,6 +16,7 @@ module Doorkeeper
|
|
|
16
16
|
@client = client
|
|
17
17
|
@parameters = parameters
|
|
18
18
|
@original_scopes = parameters[:scope]
|
|
19
|
+
@grant_type = Doorkeeper::OAuth::PASSWORD
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
private
|
|
@@ -26,16 +27,18 @@ module Doorkeeper
|
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
def validate_scopes
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
client_scopes = client.try(:scopes)
|
|
31
|
+
return true if scopes.blank?
|
|
32
|
+
|
|
33
|
+
ScopeChecker.valid?(scopes.to_s, server.scopes, client_scopes)
|
|
31
34
|
end
|
|
32
35
|
|
|
33
36
|
def validate_resource_owner
|
|
34
|
-
|
|
37
|
+
!resource_owner.nil?
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
def validate_client
|
|
38
|
-
!parameters[:client_id] ||
|
|
41
|
+
!parameters[:client_id] || !client.nil?
|
|
39
42
|
end
|
|
40
43
|
end
|
|
41
44
|
end
|
|
@@ -7,17 +7,21 @@ module Doorkeeper
|
|
|
7
7
|
validate :client, error: :invalid_client
|
|
8
8
|
validate :scopes, error: :invalid_scope
|
|
9
9
|
validate :redirect_uri, error: :invalid_redirect_uri
|
|
10
|
+
validate :code_challenge_method, error: :invalid_code_challenge_method
|
|
10
11
|
|
|
11
|
-
attr_accessor :server, :client, :response_type, :redirect_uri, :state
|
|
12
|
+
attr_accessor :server, :client, :response_type, :redirect_uri, :state,
|
|
13
|
+
:code_challenge, :code_challenge_method
|
|
12
14
|
attr_writer :scope
|
|
13
15
|
|
|
14
16
|
def initialize(server, client, attrs = {})
|
|
15
|
-
@server
|
|
16
|
-
@client
|
|
17
|
-
@response_type
|
|
18
|
-
@redirect_uri
|
|
19
|
-
@scope
|
|
20
|
-
@state
|
|
17
|
+
@server = server
|
|
18
|
+
@client = client
|
|
19
|
+
@response_type = attrs[:response_type]
|
|
20
|
+
@redirect_uri = attrs[:redirect_uri]
|
|
21
|
+
@scope = attrs[:scope]
|
|
22
|
+
@state = attrs[:state]
|
|
23
|
+
@code_challenge = attrs[:code_challenge]
|
|
24
|
+
@code_challenge_method = attrs[:code_challenge_method]
|
|
21
25
|
end
|
|
22
26
|
|
|
23
27
|
def authorizable?
|
|
@@ -29,15 +33,36 @@ module Doorkeeper
|
|
|
29
33
|
end
|
|
30
34
|
|
|
31
35
|
def scope
|
|
32
|
-
@scope.presence ||
|
|
36
|
+
@scope.presence || build_scopes
|
|
33
37
|
end
|
|
34
38
|
|
|
35
39
|
def error_response
|
|
36
40
|
OAuth::ErrorResponse.from_request(self)
|
|
37
41
|
end
|
|
38
42
|
|
|
43
|
+
def as_json(_options)
|
|
44
|
+
{
|
|
45
|
+
client_id: client.uid,
|
|
46
|
+
redirect_uri: redirect_uri,
|
|
47
|
+
state: state,
|
|
48
|
+
response_type: response_type,
|
|
49
|
+
scope: scope,
|
|
50
|
+
client_name: client.name,
|
|
51
|
+
status: I18n.t('doorkeeper.pre_authorization.status')
|
|
52
|
+
}
|
|
53
|
+
end
|
|
54
|
+
|
|
39
55
|
private
|
|
40
56
|
|
|
57
|
+
def build_scopes
|
|
58
|
+
client_scopes = client.application.scopes
|
|
59
|
+
if client_scopes.blank?
|
|
60
|
+
server.default_scopes.to_s
|
|
61
|
+
else
|
|
62
|
+
(server.default_scopes & client_scopes).to_s
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
41
66
|
def validate_response_type
|
|
42
67
|
server.authorization_response_types.include? response_type
|
|
43
68
|
end
|
|
@@ -47,7 +72,8 @@ module Doorkeeper
|
|
|
47
72
|
end
|
|
48
73
|
|
|
49
74
|
def validate_scopes
|
|
50
|
-
return true
|
|
75
|
+
return true if scope.blank?
|
|
76
|
+
|
|
51
77
|
Helpers::ScopeChecker.valid?(
|
|
52
78
|
scope,
|
|
53
79
|
server.scopes,
|
|
@@ -55,11 +81,17 @@ module Doorkeeper
|
|
|
55
81
|
)
|
|
56
82
|
end
|
|
57
83
|
|
|
58
|
-
# TODO: test uri should be matched against the client's one
|
|
59
84
|
def validate_redirect_uri
|
|
60
|
-
return false
|
|
61
|
-
|
|
62
|
-
|
|
85
|
+
return false if redirect_uri.blank?
|
|
86
|
+
|
|
87
|
+
Helpers::URIChecker.valid_for_authorization?(
|
|
88
|
+
redirect_uri,
|
|
89
|
+
client.redirect_uri
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def validate_code_challenge_method
|
|
94
|
+
!code_challenge.present? || (code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
|
|
63
95
|
end
|
|
64
96
|
end
|
|
65
97
|
end
|
|
@@ -65,7 +65,12 @@ module Doorkeeper
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def access_token_expires_in
|
|
68
|
-
Authorization::Token.
|
|
68
|
+
context = Authorization::Token.build_context(
|
|
69
|
+
client,
|
|
70
|
+
Doorkeeper::OAuth::REFRESH_TOKEN,
|
|
71
|
+
scopes
|
|
72
|
+
)
|
|
73
|
+
Authorization::Token.access_token_expires_in(server, context)
|
|
69
74
|
end
|
|
70
75
|
|
|
71
76
|
def validate_token_presence
|
|
@@ -3,7 +3,7 @@ module Doorkeeper
|
|
|
3
3
|
class Token
|
|
4
4
|
class << self
|
|
5
5
|
def from_request(request, *methods)
|
|
6
|
-
methods.inject(nil) do |
|
|
6
|
+
methods.inject(nil) do |_, method|
|
|
7
7
|
method = self.method(method) if method.is_a?(Symbol)
|
|
8
8
|
credentials = method.call(request)
|
|
9
9
|
break credentials unless credentials.blank?
|
|
@@ -13,7 +13,10 @@ module Doorkeeper
|
|
|
13
13
|
def authenticate(request, *methods)
|
|
14
14
|
if (token = from_request(request, *methods))
|
|
15
15
|
access_token = AccessToken.by_token(token)
|
|
16
|
-
|
|
16
|
+
refresh_token_enabled = Doorkeeper.configuration.refresh_token_enabled?
|
|
17
|
+
if access_token.present? && refresh_token_enabled
|
|
18
|
+
access_token.revoke_previous_refresh_token!
|
|
19
|
+
end
|
|
17
20
|
access_token
|
|
18
21
|
end
|
|
19
22
|
end
|
|
@@ -47,12 +47,12 @@ module Doorkeeper
|
|
|
47
47
|
|
|
48
48
|
# Client Authentication
|
|
49
49
|
def authorized_client
|
|
50
|
-
@
|
|
50
|
+
@authorized_client ||= server.credentials && server.client
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
# Bearer Token Authentication
|
|
54
54
|
def authorized_token
|
|
55
|
-
@
|
|
55
|
+
@authorized_token ||=
|
|
56
56
|
OAuth::Token.authenticate(server.context.request, :from_bearer_authorization)
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -23,9 +23,11 @@ module Doorkeeper
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def headers
|
|
26
|
-
{
|
|
26
|
+
{
|
|
27
|
+
'Cache-Control' => 'no-store',
|
|
27
28
|
'Pragma' => 'no-cache',
|
|
28
|
-
'Content-Type' => 'application/json; charset=utf-8'
|
|
29
|
+
'Content-Type' => 'application/json; charset=utf-8'
|
|
30
|
+
}
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
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'.freeze,
|
|
7
|
+
IMPLICIT = 'implicit'.freeze,
|
|
8
|
+
PASSWORD = 'password'.freeze,
|
|
9
|
+
CLIENT_CREDENTIALS = 'client_credentials'.freeze,
|
|
10
|
+
REFRESH_TOKEN = 'refresh_token'.freeze
|
|
11
|
+
].freeze
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -11,6 +11,9 @@ module Doorkeeper
|
|
|
11
11
|
validates :name, :secret, :uid, presence: true
|
|
12
12
|
validates :uid, uniqueness: true
|
|
13
13
|
validates :redirect_uri, redirect_uri: true
|
|
14
|
+
validates :confidential, inclusion: { in: [true, false] }
|
|
15
|
+
|
|
16
|
+
validate :scopes_match_configured, if: :enforce_scopes?
|
|
14
17
|
|
|
15
18
|
before_validation :generate_uid, :generate_secret, on: :create
|
|
16
19
|
|
|
@@ -31,6 +34,17 @@ module Doorkeeper
|
|
|
31
34
|
where(id: resource_access_tokens.select(:application_id).distinct)
|
|
32
35
|
end
|
|
33
36
|
|
|
37
|
+
# Revokes AccessToken and AccessGrant records that have not been revoked and
|
|
38
|
+
# associated with the specific Application and Resource Owner.
|
|
39
|
+
#
|
|
40
|
+
# @param resource_owner [ActiveRecord::Base]
|
|
41
|
+
# instance of the Resource Owner model
|
|
42
|
+
#
|
|
43
|
+
def self.revoke_tokens_and_grants_for(id, resource_owner)
|
|
44
|
+
AccessToken.revoke_all_for(id, resource_owner)
|
|
45
|
+
AccessGrant.revoke_all_for(id, resource_owner)
|
|
46
|
+
end
|
|
47
|
+
|
|
34
48
|
private
|
|
35
49
|
|
|
36
50
|
def generate_uid
|
|
@@ -40,5 +54,16 @@ module Doorkeeper
|
|
|
40
54
|
def generate_secret
|
|
41
55
|
self.secret = UniqueToken.generate if secret.blank?
|
|
42
56
|
end
|
|
57
|
+
|
|
58
|
+
def scopes_match_configured
|
|
59
|
+
if scopes.present? &&
|
|
60
|
+
!ScopeChecker.valid?(scopes.to_s, Doorkeeper.configuration.scopes)
|
|
61
|
+
errors.add(:scopes, :not_match_configured)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def enforce_scopes?
|
|
66
|
+
Doorkeeper.configuration.enforce_configured_scopes?
|
|
67
|
+
end
|
|
43
68
|
end
|
|
44
69
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module Orm
|
|
5
|
+
module ActiveRecord
|
|
6
|
+
class StaleRecordsCleaner
|
|
7
|
+
def initialize(base_scope)
|
|
8
|
+
@base_scope = base_scope
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def clean_revoked
|
|
12
|
+
table = @base_scope.arel_table
|
|
13
|
+
@base_scope.where.not(revoked_at: nil)
|
|
14
|
+
.where(table[:revoked_at].lt(Time.current))
|
|
15
|
+
.delete_all
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def clean_expired(ttl)
|
|
19
|
+
table = @base_scope.arel_table
|
|
20
|
+
@base_scope.where(table[:created_at].lt(Time.current - ttl))
|
|
21
|
+
.delete_all
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -4,9 +4,7 @@ module Doorkeeper
|
|
|
4
4
|
def doorkeeper_authorize!(*scopes)
|
|
5
5
|
@_doorkeeper_scopes = scopes.presence || Doorkeeper.configuration.default_scopes
|
|
6
6
|
|
|
7
|
-
unless valid_doorkeeper_token?
|
|
8
|
-
doorkeeper_render_error
|
|
9
|
-
end
|
|
7
|
+
doorkeeper_render_error unless valid_doorkeeper_token?
|
|
10
8
|
end
|
|
11
9
|
|
|
12
10
|
def doorkeeper_unauthorized_render_options(**); end
|
|
@@ -68,7 +66,7 @@ module Doorkeeper
|
|
|
68
66
|
end
|
|
69
67
|
|
|
70
68
|
def doorkeeper_token
|
|
71
|
-
@
|
|
69
|
+
@doorkeeper_token ||= OAuth::Token.authenticate(
|
|
72
70
|
request,
|
|
73
71
|
*Doorkeeper.configuration.access_token_methods
|
|
74
72
|
)
|
|
@@ -4,6 +4,10 @@ require 'doorkeeper/rails/routes/mapper'
|
|
|
4
4
|
module Doorkeeper
|
|
5
5
|
module Rails
|
|
6
6
|
class Routes # :nodoc:
|
|
7
|
+
mattr_reader :mapping do
|
|
8
|
+
{}
|
|
9
|
+
end
|
|
10
|
+
|
|
7
11
|
module Helper
|
|
8
12
|
def use_doorkeeper(options = {}, &block)
|
|
9
13
|
Doorkeeper::Rails::Routes.new(self, &block).generate_routes!(options)
|
|
@@ -19,6 +23,10 @@ module Doorkeeper
|
|
|
19
23
|
def initialize(routes, &block)
|
|
20
24
|
@routes = routes
|
|
21
25
|
@mapping = Mapper.new.map(&block)
|
|
26
|
+
|
|
27
|
+
if Doorkeeper.configuration.api_only
|
|
28
|
+
@mapping.skips.push(:applications, :authorized_applications)
|
|
29
|
+
end
|
|
22
30
|
end
|
|
23
31
|
|
|
24
32
|
def generate_routes!(options)
|
|
@@ -36,7 +44,11 @@ module Doorkeeper
|
|
|
36
44
|
private
|
|
37
45
|
|
|
38
46
|
def map_route(name, method)
|
|
39
|
-
|
|
47
|
+
return if @mapping.skipped?(name)
|
|
48
|
+
|
|
49
|
+
send(method, @mapping[name])
|
|
50
|
+
|
|
51
|
+
mapping[name] = @mapping[name]
|
|
40
52
|
end
|
|
41
53
|
|
|
42
54
|
def authorization_routes(mapping)
|