doorkeeper 4.2.6 → 5.5.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1049 -0
- data/README.md +110 -353
- data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
- data/app/controllers/doorkeeper/application_controller.rb +6 -7
- data/app/controllers/doorkeeper/application_metal_controller.rb +7 -11
- data/app/controllers/doorkeeper/applications_controller.rb +65 -16
- data/app/controllers/doorkeeper/authorizations_controller.rb +97 -17
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +22 -3
- data/app/controllers/doorkeeper/token_info_controller.rb +16 -4
- data/app/controllers/doorkeeper/tokens_controller.rb +115 -38
- data/app/helpers/doorkeeper/dashboard_helper.rb +10 -6
- data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
- data/app/views/doorkeeper/applications/_form.html.erb +33 -21
- data/app/views/doorkeeper/applications/edit.html.erb +1 -1
- data/app/views/doorkeeper/applications/index.html.erb +18 -6
- data/app/views/doorkeeper/applications/new.html.erb +1 -1
- data/app/views/doorkeeper/applications/show.html.erb +40 -16
- data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
- data/app/views/doorkeeper/authorizations/new.html.erb +6 -0
- data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +16 -14
- data/config/locales/en.yml +34 -7
- data/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/lib/doorkeeper/config/option.rb +82 -0
- data/lib/doorkeeper/config/validations.rb +53 -0
- data/lib/doorkeeper/config.rb +514 -167
- data/lib/doorkeeper/engine.rb +11 -5
- data/lib/doorkeeper/errors.rb +25 -16
- data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
- data/lib/doorkeeper/grant_flow/flow.rb +44 -0
- data/lib/doorkeeper/grant_flow/registry.rb +50 -0
- data/lib/doorkeeper/grant_flow.rb +45 -0
- data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
- data/lib/doorkeeper/grape/helpers.rb +23 -12
- data/lib/doorkeeper/helpers/controller.rb +51 -14
- data/lib/doorkeeper/models/access_grant_mixin.rb +94 -27
- data/lib/doorkeeper/models/access_token_mixin.rb +284 -96
- data/lib/doorkeeper/models/application_mixin.rb +58 -27
- data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +12 -6
- data/lib/doorkeeper/models/concerns/orderable.rb +15 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +4 -7
- data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +3 -27
- data/lib/doorkeeper/models/concerns/scopes.rb +12 -2
- data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
- data/lib/doorkeeper/oauth/authorization/code.rb +48 -12
- data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +66 -28
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +7 -5
- data/lib/doorkeeper/oauth/authorization_code_request.rb +63 -10
- data/lib/doorkeeper/oauth/base_request.rb +35 -19
- data/lib/doorkeeper/oauth/base_response.rb +2 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +9 -7
- data/lib/doorkeeper/oauth/client.rb +10 -11
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +47 -4
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +16 -9
- data/lib/doorkeeper/oauth/client_credentials/validator.rb +56 -0
- data/lib/doorkeeper/oauth/client_credentials_request.rb +10 -11
- data/lib/doorkeeper/oauth/code_request.rb +8 -12
- data/lib/doorkeeper/oauth/code_response.rb +27 -15
- data/lib/doorkeeper/oauth/error.rb +5 -3
- data/lib/doorkeeper/oauth/error_response.rb +35 -15
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +11 -3
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -18
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +20 -3
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +53 -3
- data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
- data/lib/doorkeeper/oauth/invalid_token_response.rb +29 -5
- data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +44 -10
- data/lib/doorkeeper/oauth/pre_authorization.rb +135 -26
- data/lib/doorkeeper/oauth/refresh_token_request.rb +60 -31
- data/lib/doorkeeper/oauth/scopes.rb +26 -12
- data/lib/doorkeeper/oauth/token.rb +13 -9
- data/lib/doorkeeper/oauth/token_introspection.rb +202 -0
- data/lib/doorkeeper/oauth/token_request.rb +8 -20
- data/lib/doorkeeper/oauth/token_response.rb +14 -10
- data/lib/doorkeeper/oauth.rb +13 -0
- data/lib/doorkeeper/orm/active_record/access_grant.rb +6 -4
- data/lib/doorkeeper/orm/active_record/access_token.rb +5 -42
- data/lib/doorkeeper/orm/active_record/application.rb +6 -20
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +69 -0
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +60 -0
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +199 -0
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +33 -0
- data/lib/doorkeeper/orm/active_record.rb +37 -8
- data/lib/doorkeeper/rails/helpers.rb +14 -13
- data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/lib/doorkeeper/rails/routes/mapper.rb +4 -2
- data/lib/doorkeeper/rails/routes/mapping.rb +9 -7
- data/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/lib/doorkeeper/rails/routes.rb +41 -28
- data/lib/doorkeeper/rake/db.rake +40 -0
- data/lib/doorkeeper/rake/setup.rake +11 -0
- data/lib/doorkeeper/rake.rb +14 -0
- data/lib/doorkeeper/request/authorization_code.rb +6 -4
- data/lib/doorkeeper/request/client_credentials.rb +3 -3
- data/lib/doorkeeper/request/code.rb +1 -1
- data/lib/doorkeeper/request/password.rb +5 -14
- data/lib/doorkeeper/request/refresh_token.rb +6 -5
- data/lib/doorkeeper/request/strategy.rb +4 -2
- data/lib/doorkeeper/request/token.rb +1 -1
- data/lib/doorkeeper/request.rb +62 -29
- data/lib/doorkeeper/secret_storing/base.rb +64 -0
- data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
- data/lib/doorkeeper/secret_storing/plain.rb +33 -0
- data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
- data/lib/doorkeeper/server.rb +9 -11
- data/lib/doorkeeper/stale_records_cleaner.rb +24 -0
- data/lib/doorkeeper/validations.rb +5 -2
- data/lib/doorkeeper/version.rb +12 -1
- data/lib/doorkeeper.rb +111 -62
- data/lib/generators/doorkeeper/application_owner_generator.rb +28 -13
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
- data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/lib/generators/doorkeeper/install_generator.rb +19 -9
- data/lib/generators/doorkeeper/migration_generator.rb +27 -10
- data/lib/generators/doorkeeper/pkce_generator.rb +33 -0
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -19
- data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
- data/{spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb → lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb} +3 -1
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
- data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +412 -33
- data/lib/generators/doorkeeper/templates/migration.rb.erb +88 -0
- data/lib/generators/doorkeeper/views_generator.rb +8 -4
- data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
- metadata +114 -276
- data/.coveralls.yml +0 -1
- data/.gitignore +0 -19
- data/.hound.yml +0 -13
- data/.rspec +0 -1
- data/.travis.yml +0 -26
- data/Appraisals +0 -14
- data/CONTRIBUTING.md +0 -47
- data/Gemfile +0 -10
- data/NEWS.md +0 -606
- data/RELEASING.md +0 -10
- data/Rakefile +0 -20
- data/app/validators/redirect_uri_validator.rb +0 -34
- data/doorkeeper.gemspec +0 -29
- data/gemfiles/rails_4_2.gemfile +0 -11
- data/gemfiles/rails_5_0.gemfile +0 -12
- data/gemfiles/rails_5_1.gemfile +0 -13
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -45
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +0 -7
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb +0 -11
- data/lib/generators/doorkeeper/templates/migration.rb +0 -68
- data/spec/controllers/application_metal_controller.rb +0 -10
- data/spec/controllers/applications_controller_spec.rb +0 -58
- data/spec/controllers/authorizations_controller_spec.rb +0 -218
- data/spec/controllers/protected_resources_controller_spec.rb +0 -300
- data/spec/controllers/token_info_controller_spec.rb +0 -52
- data/spec/controllers/tokens_controller_spec.rb +0 -88
- data/spec/dummy/Rakefile +0 -7
- data/spec/dummy/app/controllers/application_controller.rb +0 -3
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -7
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -12
- data/spec/dummy/app/controllers/home_controller.rb +0 -17
- data/spec/dummy/app/controllers/metal_controller.rb +0 -11
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -11
- data/spec/dummy/app/helpers/application_helper.rb +0 -5
- data/spec/dummy/app/models/user.rb +0 -5
- data/spec/dummy/app/views/home/index.html.erb +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/config/application.rb +0 -23
- data/spec/dummy/config/boot.rb +0 -9
- data/spec/dummy/config/database.yml +0 -15
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -29
- data/spec/dummy/config/environments/production.rb +0 -62
- data/spec/dummy/config/environments/test.rb +0 -44
- data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +0 -6
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/dummy/config/initializers/doorkeeper.rb +0 -96
- data/spec/dummy/config/initializers/secret_token.rb +0 -9
- data/spec/dummy/config/initializers/session_store.rb +0 -8
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -52
- data/spec/dummy/config.ru +0 -4
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -9
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -5
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -60
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -7
- data/spec/dummy/db/schema.rb +0 -67
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -26
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +0 -6
- data/spec/factories.rb +0 -28
- data/spec/generators/application_owner_generator_spec.rb +0 -22
- data/spec/generators/install_generator_spec.rb +0 -31
- data/spec/generators/migration_generator_spec.rb +0 -20
- data/spec/generators/templates/routes.rb +0 -3
- data/spec/generators/views_generator_spec.rb +0 -27
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -24
- data/spec/lib/config_spec.rb +0 -334
- data/spec/lib/doorkeeper_spec.rb +0 -150
- data/spec/lib/models/expirable_spec.rb +0 -50
- data/spec/lib/models/revocable_spec.rb +0 -59
- data/spec/lib/models/scopes_spec.rb +0 -43
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -41
- data/spec/lib/oauth/authorization_code_request_spec.rb +0 -80
- data/spec/lib/oauth/base_request_spec.rb +0 -160
- data/spec/lib/oauth/base_response_spec.rb +0 -45
- data/spec/lib/oauth/client/credentials_spec.rb +0 -88
- data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -44
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -86
- data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -54
- data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -27
- data/spec/lib/oauth/client_credentials_request_spec.rb +0 -104
- data/spec/lib/oauth/client_spec.rb +0 -39
- data/spec/lib/oauth/code_request_spec.rb +0 -45
- data/spec/lib/oauth/code_response_spec.rb +0 -34
- data/spec/lib/oauth/error_response_spec.rb +0 -61
- data/spec/lib/oauth/error_spec.rb +0 -23
- data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -23
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -64
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -20
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -104
- data/spec/lib/oauth/invalid_token_response_spec.rb +0 -56
- data/spec/lib/oauth/password_access_token_request_spec.rb +0 -90
- data/spec/lib/oauth/pre_authorization_spec.rb +0 -155
- data/spec/lib/oauth/refresh_token_request_spec.rb +0 -154
- data/spec/lib/oauth/scopes_spec.rb +0 -122
- data/spec/lib/oauth/token_request_spec.rb +0 -98
- data/spec/lib/oauth/token_response_spec.rb +0 -85
- data/spec/lib/oauth/token_spec.rb +0 -116
- data/spec/lib/request/strategy_spec.rb +0 -53
- data/spec/lib/server_spec.rb +0 -49
- data/spec/models/doorkeeper/access_grant_spec.rb +0 -36
- data/spec/models/doorkeeper/access_token_spec.rb +0 -394
- data/spec/models/doorkeeper/application_spec.rb +0 -179
- data/spec/requests/applications/applications_request_spec.rb +0 -94
- data/spec/requests/applications/authorized_applications_spec.rb +0 -30
- data/spec/requests/endpoints/authorization_spec.rb +0 -71
- data/spec/requests/endpoints/token_spec.rb +0 -64
- data/spec/requests/flows/authorization_code_errors_spec.rb +0 -76
- data/spec/requests/flows/authorization_code_spec.rb +0 -148
- data/spec/requests/flows/client_credentials_spec.rb +0 -58
- data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -32
- data/spec/requests/flows/implicit_grant_spec.rb +0 -61
- data/spec/requests/flows/password_spec.rb +0 -115
- data/spec/requests/flows/refresh_token_spec.rb +0 -174
- data/spec/requests/flows/revoke_token_spec.rb +0 -157
- data/spec/requests/flows/skip_authorization_spec.rb +0 -59
- data/spec/requests/protected_resources/metal_spec.rb +0 -14
- data/spec/requests/protected_resources/private_api_spec.rb +0 -81
- data/spec/routing/custom_controller_routes_spec.rb +0 -71
- data/spec/routing/default_routes_spec.rb +0 -35
- data/spec/routing/scoped_routes_spec.rb +0 -31
- data/spec/spec_helper.rb +0 -4
- data/spec/spec_helper_integration.rb +0 -63
- data/spec/support/dependencies/factory_girl.rb +0 -2
- data/spec/support/helpers/access_token_request_helper.rb +0 -11
- data/spec/support/helpers/authorization_request_helper.rb +0 -41
- data/spec/support/helpers/config_helper.rb +0 -9
- data/spec/support/helpers/model_helper.rb +0 -67
- data/spec/support/helpers/request_spec_helper.rb +0 -84
- data/spec/support/helpers/url_helper.rb +0 -55
- data/spec/support/http_method_shim.rb +0 -38
- data/spec/support/orm/active_record.rb +0 -3
- data/spec/support/shared/controllers_shared_context.rb +0 -69
- data/spec/support/shared/models_shared_examples.rb +0 -52
- data/spec/validators/redirect_uri_validator_spec.rb +0 -78
@@ -1,11 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
module Helpers
|
6
|
+
# Default Doorkeeper token generator. Follows OAuth RFC and
|
7
|
+
# could be customized using `default_generator_method` in
|
8
|
+
# configuration.
|
4
9
|
module UniqueToken
|
5
10
|
def self.generate(options = {})
|
6
|
-
|
7
|
-
|
8
|
-
|
11
|
+
# Access Token value must be 1*VSCHAR or
|
12
|
+
# 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="
|
13
|
+
#
|
14
|
+
# @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.12
|
15
|
+
# @see https://datatracker.ietf.org/doc/html/rfc6750#section-2.1
|
16
|
+
#
|
17
|
+
generator = options.delete(:generator) || SecureRandom.method(default_generator_method)
|
18
|
+
token_size = options.delete(:size) || 32
|
19
|
+
generator.call(token_size)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Generator method for default generator class (SecureRandom)
|
23
|
+
#
|
24
|
+
def self.default_generator_method
|
25
|
+
Doorkeeper.config.default_generator_method
|
9
26
|
end
|
10
27
|
end
|
11
28
|
end
|
@@ -1,10 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ipaddr"
|
4
|
+
|
1
5
|
module Doorkeeper
|
2
6
|
module OAuth
|
3
7
|
module Helpers
|
4
8
|
module URIChecker
|
5
9
|
def self.valid?(url)
|
10
|
+
return true if oob_uri?(url)
|
11
|
+
|
6
12
|
uri = as_uri(url)
|
7
|
-
uri
|
13
|
+
valid_scheme?(uri) && iff_host?(uri) && uri.fragment.nil? && uri.opaque.nil?
|
8
14
|
rescue URI::InvalidURIError
|
9
15
|
false
|
10
16
|
end
|
@@ -12,10 +18,32 @@ module Doorkeeper
|
|
12
18
|
def self.matches?(url, client_url)
|
13
19
|
url = as_uri(url)
|
14
20
|
client_url = as_uri(client_url)
|
21
|
+
|
22
|
+
unless client_url.query.nil?
|
23
|
+
return false unless query_matches?(url.query, client_url.query)
|
24
|
+
|
25
|
+
# Clear out queries so rest of URI can be tested. This allows query
|
26
|
+
# params to be in the request but order not mattering.
|
27
|
+
client_url.query = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# RFC8252, Paragraph 7.3
|
31
|
+
# @see https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
|
32
|
+
if loopback_uri?(url) && loopback_uri?(client_url)
|
33
|
+
url.port = nil
|
34
|
+
client_url.port = nil
|
35
|
+
end
|
36
|
+
|
15
37
|
url.query = nil
|
16
38
|
url == client_url
|
17
39
|
end
|
18
40
|
|
41
|
+
def self.loopback_uri?(uri)
|
42
|
+
IPAddr.new(uri.host).loopback?
|
43
|
+
rescue IPAddr::Error
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
19
47
|
def self.valid_for_authorization?(url, client_url)
|
20
48
|
valid?(url) && client_url.split.any? { |other_url| matches?(url, other_url) }
|
21
49
|
end
|
@@ -24,8 +52,30 @@ module Doorkeeper
|
|
24
52
|
URI.parse(url)
|
25
53
|
end
|
26
54
|
|
27
|
-
def self.
|
28
|
-
|
55
|
+
def self.query_matches?(query, client_query)
|
56
|
+
return true if client_query.blank? && query.blank?
|
57
|
+
return false if client_query.nil? || query.nil?
|
58
|
+
|
59
|
+
# Will return true independent of query order
|
60
|
+
client_query.split("&").sort == query.split("&").sort
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.valid_scheme?(uri)
|
64
|
+
return false if uri.scheme.nil?
|
65
|
+
|
66
|
+
%w[localhost].include?(uri.scheme) == false
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.hypertext_scheme?(uri)
|
70
|
+
%w[http https].include?(uri.scheme)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.iff_host?(uri)
|
74
|
+
!(hypertext_scheme?(uri) && uri.host.nil?)
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.oob_uri?(uri)
|
78
|
+
NonStandard::IETF_WG_OAUTH2_OOB_METHODS.include?(uri)
|
29
79
|
end
|
30
80
|
end
|
31
81
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module OAuth
|
5
|
+
module Hooks
|
6
|
+
class Context
|
7
|
+
attr_reader :auth, :pre_auth
|
8
|
+
|
9
|
+
def initialize(**attributes)
|
10
|
+
attributes.each do |name, value|
|
11
|
+
instance_variable_set(:"@#{name}", value) if respond_to?(name)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def issued_token
|
16
|
+
auth&.issued_token
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module OAuth
|
5
|
+
class InvalidRequestResponse < ErrorResponse
|
6
|
+
attr_reader :reason
|
7
|
+
|
8
|
+
def self.from_request(request, attributes = {})
|
9
|
+
new(
|
10
|
+
attributes.merge(
|
11
|
+
state: request.try(:state),
|
12
|
+
redirect_uri: request.try(:redirect_uri),
|
13
|
+
missing_param: request.try(:missing_param),
|
14
|
+
reason: request.try(:invalid_request_reason),
|
15
|
+
),
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(attributes = {})
|
20
|
+
super(attributes.merge(name: :invalid_request))
|
21
|
+
@missing_param = attributes[:missing_param]
|
22
|
+
@reason = @missing_param.nil? ? attributes[:reason] : :missing_param
|
23
|
+
end
|
24
|
+
|
25
|
+
def status
|
26
|
+
:bad_request
|
27
|
+
end
|
28
|
+
|
29
|
+
def description
|
30
|
+
I18n.translate(
|
31
|
+
reason,
|
32
|
+
scope: %i[doorkeeper errors messages invalid_request],
|
33
|
+
default: :unknown,
|
34
|
+
value: @missing_param,
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def redirectable?
|
39
|
+
super && @missing_param != :client_id
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -1,13 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class InvalidTokenResponse < ErrorResponse
|
4
6
|
attr_reader :reason
|
5
7
|
|
6
8
|
def self.from_access_token(access_token, attributes = {})
|
7
|
-
reason =
|
8
|
-
when access_token.try(:revoked?)
|
9
|
+
reason = if access_token&.revoked?
|
9
10
|
:revoked
|
10
|
-
|
11
|
+
elsif access_token&.expired?
|
11
12
|
:expired
|
12
13
|
else
|
13
14
|
:unknown
|
@@ -21,9 +22,32 @@ module Doorkeeper
|
|
21
22
|
@reason = attributes[:reason] || :unknown
|
22
23
|
end
|
23
24
|
|
25
|
+
def status
|
26
|
+
:unauthorized
|
27
|
+
end
|
28
|
+
|
24
29
|
def description
|
25
|
-
|
26
|
-
|
30
|
+
@description ||=
|
31
|
+
I18n.translate(
|
32
|
+
@reason,
|
33
|
+
scope: %i[doorkeeper errors messages invalid_token],
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def exception_class
|
40
|
+
errors_mapping.fetch(reason)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def errors_mapping
|
46
|
+
{
|
47
|
+
expired: Doorkeeper::Errors::TokenExpired,
|
48
|
+
revoked: Doorkeeper::Errors::TokenRevoked,
|
49
|
+
unknown: Doorkeeper::Errors::TokenUnknown,
|
50
|
+
}
|
27
51
|
end
|
28
52
|
end
|
29
53
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module OAuth
|
5
|
+
class NonStandard
|
6
|
+
# These are not part of the OAuth 2 specification but are still in use by Google
|
7
|
+
# and in some other implementations. Native applications should use one of the
|
8
|
+
# approaches discussed in RFC8252. OOB is 'Out of Band'
|
9
|
+
|
10
|
+
# This value signals to the Google Authorization Server that the authorization
|
11
|
+
# code should be returned in the title bar of the browser, with the page text
|
12
|
+
# prompting the user to copy the code and paste it in the application.
|
13
|
+
# This is useful when the client (such as a Windows application) cannot listen
|
14
|
+
# on an HTTP port without significant client configuration.
|
15
|
+
|
16
|
+
# When you use this value, your application can then detect that the page has loaded, and can
|
17
|
+
# read the title of the HTML page to obtain the authorization code. It is then up to your
|
18
|
+
# application to close the browser window if you want to ensure that the user never sees the
|
19
|
+
# page that contains the authorization code. The mechanism for doing this varies from platform
|
20
|
+
# to platform.
|
21
|
+
#
|
22
|
+
# If your platform doesn't allow you to detect that the page has loaded or read the title of
|
23
|
+
# the page, you can have the user paste the code back to your application, as prompted by the
|
24
|
+
# text in the confirmation page that the OAuth 2.0 server generates.
|
25
|
+
IETF_WG_OAUTH2_OOB = "urn:ietf:wg:oauth:2.0:oob"
|
26
|
+
|
27
|
+
# This is identical to urn:ietf:wg:oauth:2.0:oob, but the text in the confirmation page that
|
28
|
+
# the OAuth 2.0 server generates won't instruct the user to copy the authorization code, but
|
29
|
+
# instead will simply ask the user to close the window.
|
30
|
+
#
|
31
|
+
# This is useful when your application reads the title of the HTML page (by checking window
|
32
|
+
# titles on the desktop, for example) to obtain the authorization code, but can't close the
|
33
|
+
# page on its own.
|
34
|
+
IETF_WG_OAUTH2_OOB_AUTO = "urn:ietf:wg:oauth:2.0:oob:auto"
|
35
|
+
|
36
|
+
IETF_WG_OAUTH2_OOB_METHODS = [IETF_WG_OAUTH2_OOB, IETF_WG_OAUTH2_OOB_AUTO].freeze
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,40 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class PasswordAccessTokenRequest < BaseRequest
|
4
6
|
include OAuth::Helpers
|
5
7
|
|
6
|
-
validate :client,
|
8
|
+
validate :client, error: :invalid_client
|
9
|
+
validate :client_supports_grant_flow, error: :unauthorized_client
|
7
10
|
validate :resource_owner, error: :invalid_grant
|
8
|
-
validate :scopes,
|
11
|
+
validate :scopes, error: :invalid_scope
|
9
12
|
|
10
|
-
|
11
|
-
:access_token
|
13
|
+
attr_reader :client, :credentials, :resource_owner, :parameters, :access_token
|
12
14
|
|
13
|
-
def initialize(server, client, resource_owner, parameters = {})
|
15
|
+
def initialize(server, client, credentials, resource_owner, parameters = {})
|
14
16
|
@server = server
|
15
17
|
@resource_owner = resource_owner
|
16
18
|
@client = client
|
19
|
+
@credentials = credentials
|
17
20
|
@parameters = parameters
|
18
21
|
@original_scopes = parameters[:scope]
|
22
|
+
@grant_type = Doorkeeper::OAuth::PASSWORD
|
19
23
|
end
|
20
24
|
|
21
25
|
private
|
22
26
|
|
23
27
|
def before_successful_response
|
24
|
-
find_or_create_access_token(client, resource_owner
|
28
|
+
find_or_create_access_token(client, resource_owner, scopes, server)
|
29
|
+
super
|
25
30
|
end
|
26
31
|
|
27
32
|
def validate_scopes
|
28
|
-
return true
|
29
|
-
|
33
|
+
return true if scopes.blank?
|
34
|
+
|
35
|
+
ScopeChecker.valid?(
|
36
|
+
scope_str: scopes.to_s,
|
37
|
+
server_scopes: server.scopes,
|
38
|
+
app_scopes: client.try(:scopes),
|
39
|
+
grant_type: grant_type,
|
40
|
+
)
|
30
41
|
end
|
31
42
|
|
32
43
|
def validate_resource_owner
|
33
|
-
|
44
|
+
resource_owner.present?
|
34
45
|
end
|
35
46
|
|
47
|
+
# Section 4.3.2. Access Token Request for Resource Owner Password Credentials Grant:
|
48
|
+
#
|
49
|
+
# If the client type is confidential or the client was issued client credentials (or assigned
|
50
|
+
# other authentication requirements), the client MUST authenticate with the authorization
|
51
|
+
# server as described in Section 3.2.1.
|
52
|
+
#
|
53
|
+
# The authorization server MUST:
|
54
|
+
#
|
55
|
+
# o require client authentication for confidential clients or for any client that was
|
56
|
+
# issued client credentials (or with other authentication requirements)
|
57
|
+
#
|
58
|
+
# o authenticate the client if client authentication is included,
|
59
|
+
#
|
60
|
+
# @see https://datatracker.ietf.org/doc/html/rfc6749#section-4.3
|
61
|
+
#
|
36
62
|
def validate_client
|
37
|
-
|
63
|
+
if Doorkeeper.config.skip_client_authentication_for_password_grant
|
64
|
+
client.present? || (!parameters[:client_id] && credentials.blank?)
|
65
|
+
else
|
66
|
+
client.present?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def validate_client_supports_grant_flow
|
71
|
+
server_config.allow_grant_flow_for_client?(grant_type, client&.application)
|
38
72
|
end
|
39
73
|
end
|
40
74
|
end
|
@@ -1,23 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Doorkeeper
|
2
4
|
module OAuth
|
3
5
|
class PreAuthorization
|
4
6
|
include Validations
|
5
7
|
|
6
|
-
validate :
|
8
|
+
validate :client_id, error: :invalid_request
|
7
9
|
validate :client, error: :invalid_client
|
8
|
-
validate :
|
10
|
+
validate :client_supports_grant_flow, error: :unauthorized_client
|
11
|
+
validate :resource_owner_authorize_for_client, error: :invalid_client
|
9
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
|
17
|
+
validate :code_challenge_method, error: :invalid_code_challenge_method
|
10
18
|
|
11
|
-
|
12
|
-
|
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
|
13
22
|
|
14
|
-
def initialize(server,
|
15
|
-
@server
|
16
|
-
@
|
17
|
-
@response_type
|
18
|
-
@
|
19
|
-
@
|
20
|
-
@
|
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
|
21
34
|
end
|
22
35
|
|
23
36
|
def authorizable?
|
@@ -25,41 +38,137 @@ module Doorkeeper
|
|
25
38
|
end
|
26
39
|
|
27
40
|
def scopes
|
28
|
-
Scopes.from_string
|
41
|
+
Scopes.from_string(scope)
|
29
42
|
end
|
30
43
|
|
31
44
|
def scope
|
32
|
-
@scope.presence || server.default_scopes.
|
45
|
+
@scope.presence || (server.default_scopes.presence && build_scopes)
|
33
46
|
end
|
34
47
|
|
35
48
|
def error_response
|
36
|
-
|
49
|
+
if error == :invalid_request
|
50
|
+
OAuth::InvalidRequestResponse.from_request(
|
51
|
+
self,
|
52
|
+
response_on_fragment: response_on_fragment?,
|
53
|
+
)
|
54
|
+
else
|
55
|
+
OAuth::ErrorResponse.from_request(self, response_on_fragment: response_on_fragment?)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def as_json(_options = nil)
|
60
|
+
pre_auth_hash
|
61
|
+
end
|
62
|
+
|
63
|
+
def form_post_response?
|
64
|
+
response_mode == "form_post"
|
37
65
|
end
|
38
66
|
|
39
67
|
private
|
40
68
|
|
41
|
-
|
42
|
-
|
69
|
+
attr_reader :client_id, :server
|
70
|
+
|
71
|
+
def build_scopes
|
72
|
+
client_scopes = client.scopes
|
73
|
+
if client_scopes.blank?
|
74
|
+
server.default_scopes.to_s
|
75
|
+
else
|
76
|
+
(server.default_scopes & client_scopes).to_s
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def validate_client_id
|
81
|
+
@missing_param = :client_id if client_id.blank?
|
82
|
+
@missing_param.nil?
|
43
83
|
end
|
44
84
|
|
45
85
|
def validate_client
|
46
|
-
client.
|
86
|
+
@client = OAuth::Client.find(client_id)
|
87
|
+
@client.present?
|
88
|
+
end
|
89
|
+
|
90
|
+
def validate_client_supports_grant_flow
|
91
|
+
Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client.application)
|
92
|
+
end
|
93
|
+
|
94
|
+
def validate_resource_owner_authorize_for_client
|
95
|
+
# The `authorize_resource_owner_for_client` config option is used for this validation
|
96
|
+
client.application.authorized_for_resource_owner?(@resource_owner)
|
97
|
+
end
|
98
|
+
|
99
|
+
def validate_redirect_uri
|
100
|
+
return false if redirect_uri.blank?
|
101
|
+
|
102
|
+
Helpers::URIChecker.valid_for_authorization?(
|
103
|
+
redirect_uri,
|
104
|
+
client.redirect_uri,
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
def validate_params
|
109
|
+
@missing_param = if response_type.blank?
|
110
|
+
:response_type
|
111
|
+
elsif @scope.blank? && server.default_scopes.blank?
|
112
|
+
:scope
|
113
|
+
end
|
114
|
+
|
115
|
+
@missing_param.nil?
|
116
|
+
end
|
117
|
+
|
118
|
+
def validate_response_type
|
119
|
+
server.authorization_response_flows.any? do |flow|
|
120
|
+
if flow.matches_response_type?(response_type)
|
121
|
+
@authorization_response_flow = flow
|
122
|
+
true
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def validate_response_mode
|
128
|
+
if response_mode.blank?
|
129
|
+
@response_mode = authorization_response_flow.default_response_mode
|
130
|
+
return true
|
131
|
+
end
|
132
|
+
|
133
|
+
authorization_response_flow.matches_response_mode?(response_mode)
|
47
134
|
end
|
48
135
|
|
49
136
|
def validate_scopes
|
50
|
-
return true unless scope.present?
|
51
137
|
Helpers::ScopeChecker.valid?(
|
52
|
-
scope,
|
53
|
-
server.scopes,
|
54
|
-
client.
|
138
|
+
scope_str: scope,
|
139
|
+
server_scopes: server.scopes,
|
140
|
+
app_scopes: client.scopes,
|
141
|
+
grant_type: grant_type,
|
55
142
|
)
|
56
143
|
end
|
57
144
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
145
|
+
def validate_code_challenge_method
|
146
|
+
return true unless Doorkeeper.config.access_grant_model.pkce_supported?
|
147
|
+
|
148
|
+
code_challenge.blank? ||
|
149
|
+
(code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
|
150
|
+
end
|
151
|
+
|
152
|
+
def response_on_fragment?
|
153
|
+
return response_type == "token" if response_mode.nil?
|
154
|
+
|
155
|
+
response_mode == "fragment"
|
156
|
+
end
|
157
|
+
|
158
|
+
def grant_type
|
159
|
+
response_type == "code" ? AUTHORIZATION_CODE : IMPLICIT
|
160
|
+
end
|
161
|
+
|
162
|
+
def pre_auth_hash
|
163
|
+
{
|
164
|
+
client_id: client.uid,
|
165
|
+
redirect_uri: redirect_uri,
|
166
|
+
state: state,
|
167
|
+
response_type: response_type,
|
168
|
+
scope: scope,
|
169
|
+
client_name: client.name,
|
170
|
+
status: I18n.t("doorkeeper.pre_authorization.status"),
|
171
|
+
}
|
63
172
|
end
|
64
173
|
end
|
65
174
|
end
|