super-smart-kit 0.0.1

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.
Files changed (149) hide show
  1. checksums.yaml +7 -0
  2. data/doorkeeper-5.9.3/CHANGELOG.md +1208 -0
  3. data/doorkeeper-5.9.3/MIT-LICENSE +20 -0
  4. data/doorkeeper-5.9.3/README.md +186 -0
  5. data/doorkeeper-5.9.3/app/assets/stylesheets/doorkeeper/admin/application.css +10 -0
  6. data/doorkeeper-5.9.3/app/assets/stylesheets/doorkeeper/application.css +64 -0
  7. data/doorkeeper-5.9.3/app/controllers/doorkeeper/application_controller.rb +14 -0
  8. data/doorkeeper-5.9.3/app/controllers/doorkeeper/application_metal_controller.rb +13 -0
  9. data/doorkeeper-5.9.3/app/controllers/doorkeeper/applications_controller.rb +99 -0
  10. data/doorkeeper-5.9.3/app/controllers/doorkeeper/authorizations_controller.rb +164 -0
  11. data/doorkeeper-5.9.3/app/controllers/doorkeeper/authorized_applications_controller.rb +33 -0
  12. data/doorkeeper-5.9.3/app/controllers/doorkeeper/token_info_controller.rb +25 -0
  13. data/doorkeeper-5.9.3/app/controllers/doorkeeper/tokens_controller.rb +180 -0
  14. data/doorkeeper-5.9.3/app/helpers/doorkeeper/dashboard_helper.rb +21 -0
  15. data/doorkeeper-5.9.3/app/views/doorkeeper/applications/_delete_form.html.erb +6 -0
  16. data/doorkeeper-5.9.3/app/views/doorkeeper/applications/_form.html.erb +59 -0
  17. data/doorkeeper-5.9.3/app/views/doorkeeper/applications/edit.html.erb +5 -0
  18. data/doorkeeper-5.9.3/app/views/doorkeeper/applications/index.html.erb +38 -0
  19. data/doorkeeper-5.9.3/app/views/doorkeeper/applications/new.html.erb +5 -0
  20. data/doorkeeper-5.9.3/app/views/doorkeeper/applications/show.html.erb +63 -0
  21. data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/error.html.erb +9 -0
  22. data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  23. data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/new.html.erb +46 -0
  24. data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/show.html.erb +7 -0
  25. data/doorkeeper-5.9.3/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +4 -0
  26. data/doorkeeper-5.9.3/app/views/doorkeeper/authorized_applications/index.html.erb +24 -0
  27. data/doorkeeper-5.9.3/app/views/layouts/doorkeeper/admin.html.erb +39 -0
  28. data/doorkeeper-5.9.3/app/views/layouts/doorkeeper/application.html.erb +23 -0
  29. data/doorkeeper-5.9.3/config/locales/en.yml +155 -0
  30. data/doorkeeper-5.9.3/lib/doorkeeper/config/abstract_builder.rb +28 -0
  31. data/doorkeeper-5.9.3/lib/doorkeeper/config/option.rb +82 -0
  32. data/doorkeeper-5.9.3/lib/doorkeeper/config/validations.rb +65 -0
  33. data/doorkeeper-5.9.3/lib/doorkeeper/config.rb +721 -0
  34. data/doorkeeper-5.9.3/lib/doorkeeper/engine.rb +38 -0
  35. data/doorkeeper-5.9.3/lib/doorkeeper/errors.rb +85 -0
  36. data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  37. data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow/flow.rb +44 -0
  38. data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow/registry.rb +50 -0
  39. data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow.rb +45 -0
  40. data/doorkeeper-5.9.3/lib/doorkeeper/grape/authorization_decorator.rb +19 -0
  41. data/doorkeeper-5.9.3/lib/doorkeeper/grape/helpers.rb +58 -0
  42. data/doorkeeper-5.9.3/lib/doorkeeper/helpers/controller.rb +91 -0
  43. data/doorkeeper-5.9.3/lib/doorkeeper/models/access_grant_mixin.rb +124 -0
  44. data/doorkeeper-5.9.3/lib/doorkeeper/models/access_token_mixin.rb +526 -0
  45. data/doorkeeper-5.9.3/lib/doorkeeper/models/application_mixin.rb +96 -0
  46. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/accessible.rb +15 -0
  47. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/expirable.rb +36 -0
  48. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +96 -0
  49. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/orderable.rb +15 -0
  50. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/ownership.rb +18 -0
  51. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +29 -0
  52. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  53. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  54. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/revocable.rb +31 -0
  55. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/scopes.rb +27 -0
  56. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  57. data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/write_to_primary.rb +57 -0
  58. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/code.rb +76 -0
  59. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  60. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/token.rb +100 -0
  61. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/uri_builder.rb +33 -0
  62. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization_code_request.rb +125 -0
  63. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/base_request.rb +68 -0
  64. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/base_response.rb +31 -0
  65. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client/credentials.rb +34 -0
  66. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client.rb +28 -0
  67. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials/creator.rb +57 -0
  68. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials/issuer.rb +48 -0
  69. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials/validator.rb +55 -0
  70. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials_request.rb +46 -0
  71. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/code_request.rb +25 -0
  72. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/code_response.rb +51 -0
  73. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/error.rb +16 -0
  74. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/error_response.rb +121 -0
  75. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/forbidden_token_response.rb +31 -0
  76. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/helpers/scope_checker.rb +50 -0
  77. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/helpers/unique_token.rb +30 -0
  78. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/helpers/uri_checker.rb +83 -0
  79. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  80. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/invalid_request_response.rb +47 -0
  81. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/invalid_token_response.rb +54 -0
  82. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  83. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/password_access_token_request.rb +75 -0
  84. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/pre_authorization.rb +187 -0
  85. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/refresh_token_request.rb +144 -0
  86. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/scopes.rb +134 -0
  87. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token.rb +66 -0
  88. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token_introspection.rb +220 -0
  89. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token_request.rb +25 -0
  90. data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token_response.rb +38 -0
  91. data/doorkeeper-5.9.3/lib/doorkeeper/oauth.rb +13 -0
  92. data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/access_grant.rb +9 -0
  93. data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/access_token.rb +9 -0
  94. data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/application.rb +10 -0
  95. data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +64 -0
  96. data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/mixins/access_token.rb +95 -0
  97. data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/mixins/application.rb +223 -0
  98. data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  99. data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +44 -0
  100. data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record.rb +41 -0
  101. data/doorkeeper-5.9.3/lib/doorkeeper/rails/helpers.rb +82 -0
  102. data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  103. data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/mapper.rb +30 -0
  104. data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/mapping.rb +40 -0
  105. data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/registry.rb +45 -0
  106. data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes.rb +110 -0
  107. data/doorkeeper-5.9.3/lib/doorkeeper/rake/db.rake +40 -0
  108. data/doorkeeper-5.9.3/lib/doorkeeper/rake/setup.rake +6 -0
  109. data/doorkeeper-5.9.3/lib/doorkeeper/rake.rb +14 -0
  110. data/doorkeeper-5.9.3/lib/doorkeeper/request/authorization_code.rb +26 -0
  111. data/doorkeeper-5.9.3/lib/doorkeeper/request/client_credentials.rb +17 -0
  112. data/doorkeeper-5.9.3/lib/doorkeeper/request/code.rb +17 -0
  113. data/doorkeeper-5.9.3/lib/doorkeeper/request/password.rb +19 -0
  114. data/doorkeeper-5.9.3/lib/doorkeeper/request/refresh_token.rb +22 -0
  115. data/doorkeeper-5.9.3/lib/doorkeeper/request/strategy.rb +19 -0
  116. data/doorkeeper-5.9.3/lib/doorkeeper/request/token.rb +17 -0
  117. data/doorkeeper-5.9.3/lib/doorkeeper/request.rb +73 -0
  118. data/doorkeeper-5.9.3/lib/doorkeeper/revocable_tokens/revocable_access_token.rb +21 -0
  119. data/doorkeeper-5.9.3/lib/doorkeeper/revocable_tokens/revocable_refresh_token.rb +21 -0
  120. data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/base.rb +64 -0
  121. data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  122. data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/plain.rb +33 -0
  123. data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  124. data/doorkeeper-5.9.3/lib/doorkeeper/server.rb +44 -0
  125. data/doorkeeper-5.9.3/lib/doorkeeper/stale_records_cleaner.rb +24 -0
  126. data/doorkeeper-5.9.3/lib/doorkeeper/validations.rb +33 -0
  127. data/doorkeeper-5.9.3/lib/doorkeeper/version.rb +14 -0
  128. data/doorkeeper-5.9.3/lib/doorkeeper.rb +209 -0
  129. data/doorkeeper-5.9.3/lib/generators/doorkeeper/application_owner_generator.rb +33 -0
  130. data/doorkeeper-5.9.3/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
  131. data/doorkeeper-5.9.3/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  132. data/doorkeeper-5.9.3/lib/generators/doorkeeper/install_generator.rb +22 -0
  133. data/doorkeeper-5.9.3/lib/generators/doorkeeper/migration_generator.rb +32 -0
  134. data/doorkeeper-5.9.3/lib/generators/doorkeeper/pkce_generator.rb +33 -0
  135. data/doorkeeper-5.9.3/lib/generators/doorkeeper/previous_refresh_token_generator.rb +41 -0
  136. data/doorkeeper-5.9.3/lib/generators/doorkeeper/remove_applications_secret_not_null_constraint_generator.rb +33 -0
  137. data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/README +24 -0
  138. data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  139. data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
  140. data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +13 -0
  141. data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
  142. data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  143. data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/initializer.rb +544 -0
  144. data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/migration.rb.erb +99 -0
  145. data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/remove_applications_secret_not_null_constraint.rb.erb +7 -0
  146. data/doorkeeper-5.9.3/lib/generators/doorkeeper/views_generator.rb +18 -0
  147. data/doorkeeper-5.9.3/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +6 -0
  148. data/super-smart-kit.gemspec +12 -0
  149. metadata +188 -0
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ class ErrorResponse < BaseResponse
6
+ include OAuth::Helpers
7
+
8
+ NON_REDIRECTABLE_STATES = %i[invalid_redirect_uri invalid_client unauthorized_client].freeze
9
+
10
+ def self.from_request(request, attributes = {})
11
+ new(
12
+ attributes.merge(
13
+ name: error_name_for(request.error),
14
+ exception_class: exception_class_for(request.error),
15
+ translate_options: request.error.try(:translate_options),
16
+ state: request.try(:state),
17
+ redirect_uri: request.try(:redirect_uri),
18
+ ),
19
+ )
20
+ end
21
+
22
+ def self.error_name_for(error)
23
+ error.respond_to?(:name_for_response) ? error.name_for_response : error
24
+ end
25
+
26
+ def self.exception_class_for(error)
27
+ return error if error.respond_to?(:name_for_response)
28
+
29
+ "Doorkeeper::Errors::#{error.to_s.classify}".safe_constantize
30
+ end
31
+
32
+ private_class_method :error_name_for, :exception_class_for
33
+
34
+ delegate :name, :description, :state, to: :@error
35
+
36
+ def initialize(attributes = {})
37
+ @error = OAuth::Error.new(*attributes.values_at(:name, :state, :translate_options))
38
+ @exception_class = attributes[:exception_class]
39
+ @redirect_uri = attributes[:redirect_uri]
40
+ @response_on_fragment = attributes[:response_on_fragment]
41
+ end
42
+
43
+ def body
44
+ {
45
+ error: name,
46
+ error_description: description,
47
+ state: state,
48
+ }.reject { |_, v| v.blank? }
49
+ end
50
+
51
+ def status
52
+ if name == :invalid_client || name == :unauthorized_client
53
+ :unauthorized
54
+ else
55
+ :bad_request
56
+ end
57
+ end
58
+
59
+ def redirectable?
60
+ !NON_REDIRECTABLE_STATES.include?(name) && !URIChecker.oob_uri?(@redirect_uri)
61
+ end
62
+
63
+ def redirect_uri
64
+ if @response_on_fragment
65
+ Authorization::URIBuilder.uri_with_fragment(@redirect_uri, body)
66
+ else
67
+ Authorization::URIBuilder.uri_with_query(@redirect_uri, body)
68
+ end
69
+ end
70
+
71
+ def headers
72
+ {
73
+ "Cache-Control" => "no-store, no-cache",
74
+ "Content-Type" => "application/json; charset=utf-8",
75
+ "WWW-Authenticate" => authenticate_info,
76
+ }
77
+ end
78
+
79
+ def raise_exception!
80
+ raise exception_class.new(self), description
81
+ end
82
+
83
+ protected
84
+
85
+ def realm
86
+ Doorkeeper.config.realm
87
+ end
88
+
89
+ def exception_class
90
+ return @exception_class if @exception_class
91
+
92
+ raise NotImplementedError, "error response must define #exception_class"
93
+ end
94
+
95
+ private
96
+
97
+ def authenticate_info
98
+ %(Bearer realm="#{realm}", error="#{sanitize_error_values(name)}", error_description="#{sanitize_error_values(description)}")
99
+ end
100
+
101
+ # This method removes any characters that are invalid in error
102
+ # details per RFC6750.
103
+ #
104
+ # > Values for the "error" and "error_description" attributes
105
+ # > (specified in Appendixes A.7 and A.8 of [RFC6749]) MUST NOT
106
+ # > include characters outside the set %x20-21 (" " or "!") / %x23-5B /
107
+ # > %x5D-7E (ascii "#" to "~" without "\").
108
+ def sanitize_error_values(string)
109
+ string.to_s.each_char.map do |char|
110
+ if char.in?("\x20".encode("utf-8").."\x21".encode("utf-8")) ||
111
+ char.in?("\x23".encode("utf-8").."\x5B".encode("utf-8")) ||
112
+ char.in?("\x5D".encode("utf-8").."\x7E".encode("utf-8"))
113
+ char
114
+ else
115
+ "_"
116
+ end
117
+ end.join("")
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ class ForbiddenTokenResponse < ErrorResponse
6
+ def self.from_scopes(scopes, attributes = {})
7
+ new(attributes.merge(scopes: scopes))
8
+ end
9
+
10
+ def initialize(attributes = {})
11
+ super(attributes.merge(name: :insufficient_scope, state: :forbidden))
12
+ @scopes = attributes[:scopes]
13
+ end
14
+
15
+ def status
16
+ :forbidden
17
+ end
18
+
19
+ def description
20
+ @description ||= I18n.t("doorkeeper.errors.messages.forbidden_token.missing_scope",
21
+ oauth_scopes: @scopes.map(&:to_s).join(" "),)
22
+ end
23
+
24
+ protected
25
+
26
+ def exception_class
27
+ Doorkeeper::Errors::TokenForbidden
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ module Helpers
6
+ module ScopeChecker
7
+ class Validator
8
+ attr_reader :parsed_scopes, :scope_str
9
+
10
+ def initialize(scope_str, server_scopes, app_scopes, grant_type)
11
+ @parsed_scopes = OAuth::Scopes.from_string(scope_str)
12
+ @scope_str = scope_str
13
+ @valid_scopes = valid_scopes(server_scopes, app_scopes)
14
+
15
+ @scopes_by_grant_type = Doorkeeper.config.scopes_by_grant_type[grant_type.to_sym] if grant_type
16
+ end
17
+
18
+ def valid?
19
+ scope_str.present? &&
20
+ scope_str !~ /[\n\r\t]/ &&
21
+ @valid_scopes.has_scopes?(parsed_scopes) &&
22
+ permitted_to_grant_type?
23
+ end
24
+
25
+ private
26
+
27
+ def valid_scopes(server_scopes, app_scopes)
28
+ app_scopes.presence || server_scopes
29
+ end
30
+
31
+ def permitted_to_grant_type?
32
+ return true unless @scopes_by_grant_type
33
+
34
+ OAuth::Scopes.from_array(@scopes_by_grant_type)
35
+ .has_scopes?(parsed_scopes)
36
+ end
37
+ end
38
+
39
+ def self.valid?(scope_str:, server_scopes:, app_scopes: nil, grant_type: nil)
40
+ Validator.new(
41
+ scope_str,
42
+ server_scopes,
43
+ app_scopes,
44
+ grant_type,
45
+ ).valid?
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ module Helpers
6
+ # Default Doorkeeper token generator. Follows OAuth RFC and
7
+ # could be customized using `default_generator_method` in
8
+ # configuration.
9
+ module UniqueToken
10
+ def self.generate(options = {})
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
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ipaddr"
4
+
5
+ module Doorkeeper
6
+ module OAuth
7
+ module Helpers
8
+ module URIChecker
9
+ def self.valid?(url)
10
+ return true if oob_uri?(url)
11
+
12
+ uri = as_uri(url)
13
+ valid_scheme?(uri) && iff_host?(uri) && uri.fragment.nil? && uri.opaque.nil?
14
+ rescue URI::InvalidURIError
15
+ false
16
+ end
17
+
18
+ def self.matches?(url, client_url)
19
+ url = as_uri(url)
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
+
37
+ url.query = nil
38
+ url == client_url
39
+ end
40
+
41
+ def self.loopback_uri?(uri)
42
+ IPAddr.new(uri.host).loopback?
43
+ rescue IPAddr::Error, IPAddr::InvalidAddressError
44
+ false
45
+ end
46
+
47
+ def self.valid_for_authorization?(url, client_url)
48
+ valid?(url) && client_url.split.any? { |other_url| matches?(url, other_url) }
49
+ end
50
+
51
+ def self.as_uri(url)
52
+ URI.parse(url)
53
+ end
54
+
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.blank?
65
+
66
+ %w[localhost].exclude?(uri.scheme)
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.blank?)
75
+ end
76
+
77
+ def self.oob_uri?(uri)
78
+ NonStandard::IETF_WG_OAUTH2_OOB_METHODS.include?(uri)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ 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,47 @@
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 exception_class
39
+ Doorkeeper::Errors::InvalidRequest
40
+ end
41
+
42
+ def redirectable?
43
+ super && @missing_param != :client_id
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ class InvalidTokenResponse < ErrorResponse
6
+ attr_reader :reason
7
+
8
+ def self.from_access_token(access_token, attributes = {})
9
+ reason = if access_token&.revoked?
10
+ :revoked
11
+ elsif access_token&.expired?
12
+ :expired
13
+ else
14
+ :unknown
15
+ end
16
+
17
+ new(attributes.merge(reason: reason))
18
+ end
19
+
20
+ def initialize(attributes = {})
21
+ super(attributes.merge(name: :invalid_token, state: :unauthorized))
22
+ @reason = attributes[:reason] || :unknown
23
+ end
24
+
25
+ def status
26
+ :unauthorized
27
+ end
28
+
29
+ def description
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
+ }
51
+ end
52
+ end
53
+ end
54
+ 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
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module OAuth
5
+ class PasswordAccessTokenRequest < BaseRequest
6
+ include OAuth::Helpers
7
+
8
+ validate :client, error: Errors::InvalidClient
9
+ validate :client_supports_grant_flow, error: Errors::UnauthorizedClient
10
+ validate :resource_owner, error: Errors::InvalidGrant
11
+ validate :scopes, error: Errors::InvalidScope
12
+
13
+ attr_reader :client, :credentials, :resource_owner, :parameters, :access_token
14
+
15
+ def initialize(server, client, credentials, resource_owner, parameters = {})
16
+ @server = server
17
+ @resource_owner = resource_owner
18
+ @client = client
19
+ @credentials = credentials
20
+ @parameters = parameters
21
+ @original_scopes = parameters[:scope]
22
+ @grant_type = Doorkeeper::OAuth::PASSWORD
23
+ end
24
+
25
+ private
26
+
27
+ def before_successful_response
28
+ find_or_create_access_token(client, resource_owner, scopes, {}, server)
29
+ super
30
+ end
31
+
32
+ def validate_scopes
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
+ )
41
+ end
42
+
43
+ def validate_resource_owner
44
+ resource_owner.present?
45
+ end
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
+ #
62
+ def validate_client
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
+ Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client&.application)
72
+ end
73
+ end
74
+ end
75
+ end