doorkeeper 5.1.0 → 5.5.0

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.

Files changed (265) hide show
  1. checksums.yaml +4 -4
  2. data/{NEWS.md → CHANGELOG.md} +234 -25
  3. data/README.md +21 -11
  4. data/app/controllers/doorkeeper/application_controller.rb +2 -2
  5. data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
  6. data/app/controllers/doorkeeper/applications_controller.rb +8 -7
  7. data/app/controllers/doorkeeper/authorizations_controller.rb +56 -19
  8. data/app/controllers/doorkeeper/authorized_applications_controller.rb +5 -5
  9. data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
  10. data/app/controllers/doorkeeper/tokens_controller.rb +93 -25
  11. data/app/views/doorkeeper/applications/_form.html.erb +1 -7
  12. data/app/views/doorkeeper/applications/show.html.erb +35 -14
  13. data/app/views/doorkeeper/authorizations/form_post.html.erb +11 -0
  14. data/config/locales/en.yml +13 -3
  15. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  16. data/lib/doorkeeper/config/option.rb +20 -2
  17. data/lib/doorkeeper/config/validations.rb +53 -0
  18. data/lib/doorkeeper/config.rb +291 -121
  19. data/lib/doorkeeper/engine.rb +1 -1
  20. data/lib/doorkeeper/errors.rb +13 -18
  21. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  22. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  23. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  24. data/lib/doorkeeper/grant_flow.rb +45 -0
  25. data/lib/doorkeeper/grape/helpers.rb +7 -3
  26. data/lib/doorkeeper/helpers/controller.rb +36 -11
  27. data/lib/doorkeeper/models/access_grant_mixin.rb +22 -18
  28. data/lib/doorkeeper/models/access_token_mixin.rb +194 -51
  29. data/lib/doorkeeper/models/application_mixin.rb +8 -7
  30. data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
  31. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  32. data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
  33. data/lib/doorkeeper/models/concerns/revocable.rb +1 -28
  34. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  35. data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
  36. data/lib/doorkeeper/oauth/authorization/code.rb +25 -14
  37. data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
  38. data/lib/doorkeeper/oauth/authorization/token.rb +24 -19
  39. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
  40. data/lib/doorkeeper/oauth/authorization_code_request.rb +40 -21
  41. data/lib/doorkeeper/oauth/base_request.rb +21 -23
  42. data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
  43. data/lib/doorkeeper/oauth/client.rb +8 -9
  44. data/lib/doorkeeper/oauth/client_credentials/creator.rb +45 -5
  45. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +10 -8
  46. data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +13 -3
  47. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
  48. data/lib/doorkeeper/oauth/code_request.rb +6 -12
  49. data/lib/doorkeeper/oauth/code_response.rb +24 -14
  50. data/lib/doorkeeper/oauth/error.rb +1 -1
  51. data/lib/doorkeeper/oauth/error_response.rb +10 -11
  52. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +8 -12
  53. data/lib/doorkeeper/oauth/helpers/unique_token.rb +8 -5
  54. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +19 -5
  55. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  56. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  57. data/lib/doorkeeper/oauth/invalid_token_response.rb +7 -4
  58. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  59. data/lib/doorkeeper/oauth/password_access_token_request.rb +32 -10
  60. data/lib/doorkeeper/oauth/pre_authorization.rb +111 -42
  61. data/lib/doorkeeper/oauth/refresh_token_request.rb +45 -33
  62. data/lib/doorkeeper/oauth/token.rb +6 -7
  63. data/lib/doorkeeper/oauth/token_introspection.rb +24 -18
  64. data/lib/doorkeeper/oauth/token_request.rb +6 -20
  65. data/lib/doorkeeper/oauth/token_response.rb +1 -1
  66. data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
  67. data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
  68. data/lib/doorkeeper/orm/active_record/application.rb +5 -83
  69. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +68 -0
  70. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +59 -0
  71. data/lib/doorkeeper/orm/active_record/mixins/application.rb +198 -0
  72. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  73. data/lib/doorkeeper/orm/active_record.rb +20 -6
  74. data/lib/doorkeeper/rails/helpers.rb +4 -4
  75. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  76. data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
  77. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  78. data/lib/doorkeeper/rails/routes.rb +17 -25
  79. data/lib/doorkeeper/rake/db.rake +6 -6
  80. data/lib/doorkeeper/rake/setup.rake +5 -0
  81. data/lib/doorkeeper/request/authorization_code.rb +5 -3
  82. data/lib/doorkeeper/request/client_credentials.rb +2 -2
  83. data/lib/doorkeeper/request/password.rb +2 -2
  84. data/lib/doorkeeper/request/refresh_token.rb +5 -4
  85. data/lib/doorkeeper/request/strategy.rb +2 -2
  86. data/lib/doorkeeper/request.rb +49 -17
  87. data/lib/doorkeeper/server.rb +7 -11
  88. data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
  89. data/lib/doorkeeper/version.rb +1 -5
  90. data/lib/doorkeeper.rb +114 -79
  91. data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
  92. data/lib/generators/doorkeeper/confidential_applications_generator.rb +2 -2
  93. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  94. data/lib/generators/doorkeeper/migration_generator.rb +1 -1
  95. data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
  96. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +7 -7
  97. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +3 -1
  98. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
  99. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
  100. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  101. data/lib/generators/doorkeeper/templates/initializer.rb +205 -43
  102. data/lib/generators/doorkeeper/templates/migration.rb.erb +18 -6
  103. metadata +43 -310
  104. data/.coveralls.yml +0 -1
  105. data/.github/ISSUE_TEMPLATE.md +0 -25
  106. data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
  107. data/.gitignore +0 -20
  108. data/.gitlab-ci.yml +0 -16
  109. data/.hound.yml +0 -3
  110. data/.rspec +0 -1
  111. data/.rubocop.yml +0 -50
  112. data/.travis.yml +0 -35
  113. data/Appraisals +0 -40
  114. data/CODE_OF_CONDUCT.md +0 -46
  115. data/CONTRIBUTING.md +0 -47
  116. data/Dangerfile +0 -67
  117. data/Gemfile +0 -24
  118. data/RELEASING.md +0 -10
  119. data/Rakefile +0 -28
  120. data/SECURITY.md +0 -15
  121. data/UPGRADE.md +0 -2
  122. data/app/validators/redirect_uri_validator.rb +0 -50
  123. data/bin/console +0 -16
  124. data/doorkeeper.gemspec +0 -34
  125. data/gemfiles/rails_5_0.gemfile +0 -17
  126. data/gemfiles/rails_5_1.gemfile +0 -17
  127. data/gemfiles/rails_5_2.gemfile +0 -17
  128. data/gemfiles/rails_6_0.gemfile +0 -17
  129. data/gemfiles/rails_master.gemfile +0 -17
  130. data/spec/controllers/application_metal_controller_spec.rb +0 -64
  131. data/spec/controllers/applications_controller_spec.rb +0 -180
  132. data/spec/controllers/authorizations_controller_spec.rb +0 -527
  133. data/spec/controllers/protected_resources_controller_spec.rb +0 -353
  134. data/spec/controllers/token_info_controller_spec.rb +0 -50
  135. data/spec/controllers/tokens_controller_spec.rb +0 -330
  136. data/spec/dummy/Rakefile +0 -9
  137. data/spec/dummy/app/assets/config/manifest.js +0 -2
  138. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  139. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
  140. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
  141. data/spec/dummy/app/controllers/home_controller.rb +0 -18
  142. data/spec/dummy/app/controllers/metal_controller.rb +0 -13
  143. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
  144. data/spec/dummy/app/helpers/application_helper.rb +0 -7
  145. data/spec/dummy/app/models/user.rb +0 -7
  146. data/spec/dummy/app/views/home/index.html.erb +0 -0
  147. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  148. data/spec/dummy/config/application.rb +0 -47
  149. data/spec/dummy/config/boot.rb +0 -7
  150. data/spec/dummy/config/database.yml +0 -15
  151. data/spec/dummy/config/environment.rb +0 -5
  152. data/spec/dummy/config/environments/development.rb +0 -31
  153. data/spec/dummy/config/environments/production.rb +0 -64
  154. data/spec/dummy/config/environments/test.rb +0 -45
  155. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
  156. data/spec/dummy/config/initializers/doorkeeper.rb +0 -121
  157. data/spec/dummy/config/initializers/secret_token.rb +0 -10
  158. data/spec/dummy/config/initializers/session_store.rb +0 -10
  159. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
  160. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  161. data/spec/dummy/config/routes.rb +0 -13
  162. data/spec/dummy/config.ru +0 -6
  163. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
  164. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
  165. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
  166. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
  167. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
  168. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
  169. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
  170. data/spec/dummy/db/schema.rb +0 -68
  171. data/spec/dummy/public/404.html +0 -26
  172. data/spec/dummy/public/422.html +0 -26
  173. data/spec/dummy/public/500.html +0 -26
  174. data/spec/dummy/public/favicon.ico +0 -0
  175. data/spec/dummy/script/rails +0 -9
  176. data/spec/factories.rb +0 -30
  177. data/spec/generators/application_owner_generator_spec.rb +0 -28
  178. data/spec/generators/confidential_applications_generator_spec.rb +0 -29
  179. data/spec/generators/install_generator_spec.rb +0 -36
  180. data/spec/generators/migration_generator_spec.rb +0 -28
  181. data/spec/generators/pkce_generator_spec.rb +0 -28
  182. data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
  183. data/spec/generators/templates/routes.rb +0 -4
  184. data/spec/generators/views_generator_spec.rb +0 -29
  185. data/spec/grape/grape_integration_spec.rb +0 -137
  186. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
  187. data/spec/lib/config_spec.rb +0 -697
  188. data/spec/lib/doorkeeper_spec.rb +0 -27
  189. data/spec/lib/models/expirable_spec.rb +0 -61
  190. data/spec/lib/models/reusable_spec.rb +0 -40
  191. data/spec/lib/models/revocable_spec.rb +0 -59
  192. data/spec/lib/models/scopes_spec.rb +0 -53
  193. data/spec/lib/models/secret_storable_spec.rb +0 -135
  194. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
  195. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -156
  196. data/spec/lib/oauth/base_request_spec.rb +0 -205
  197. data/spec/lib/oauth/base_response_spec.rb +0 -47
  198. data/spec/lib/oauth/client/credentials_spec.rb +0 -90
  199. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -94
  200. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
  201. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
  202. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -29
  203. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -109
  204. data/spec/lib/oauth/client_spec.rb +0 -38
  205. data/spec/lib/oauth/code_request_spec.rb +0 -47
  206. data/spec/lib/oauth/code_response_spec.rb +0 -36
  207. data/spec/lib/oauth/error_response_spec.rb +0 -66
  208. data/spec/lib/oauth/error_spec.rb +0 -23
  209. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -22
  210. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -98
  211. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
  212. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -247
  213. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -55
  214. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -192
  215. data/spec/lib/oauth/pre_authorization_spec.rb +0 -215
  216. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
  217. data/spec/lib/oauth/scopes_spec.rb +0 -148
  218. data/spec/lib/oauth/token_request_spec.rb +0 -150
  219. data/spec/lib/oauth/token_response_spec.rb +0 -86
  220. data/spec/lib/oauth/token_spec.rb +0 -158
  221. data/spec/lib/request/strategy_spec.rb +0 -54
  222. data/spec/lib/secret_storing/base_spec.rb +0 -60
  223. data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
  224. data/spec/lib/secret_storing/plain_spec.rb +0 -44
  225. data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
  226. data/spec/lib/server_spec.rb +0 -61
  227. data/spec/lib/stale_records_cleaner_spec.rb +0 -89
  228. data/spec/models/doorkeeper/access_grant_spec.rb +0 -144
  229. data/spec/models/doorkeeper/access_token_spec.rb +0 -591
  230. data/spec/models/doorkeeper/application_spec.rb +0 -367
  231. data/spec/requests/applications/applications_request_spec.rb +0 -259
  232. data/spec/requests/applications/authorized_applications_spec.rb +0 -32
  233. data/spec/requests/endpoints/authorization_spec.rb +0 -73
  234. data/spec/requests/endpoints/token_spec.rb +0 -75
  235. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -78
  236. data/spec/requests/flows/authorization_code_spec.rb +0 -447
  237. data/spec/requests/flows/client_credentials_spec.rb +0 -128
  238. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -34
  239. data/spec/requests/flows/implicit_grant_spec.rb +0 -90
  240. data/spec/requests/flows/password_spec.rb +0 -259
  241. data/spec/requests/flows/refresh_token_spec.rb +0 -233
  242. data/spec/requests/flows/revoke_token_spec.rb +0 -143
  243. data/spec/requests/flows/skip_authorization_spec.rb +0 -66
  244. data/spec/requests/protected_resources/metal_spec.rb +0 -16
  245. data/spec/requests/protected_resources/private_api_spec.rb +0 -83
  246. data/spec/routing/custom_controller_routes_spec.rb +0 -133
  247. data/spec/routing/default_routes_spec.rb +0 -41
  248. data/spec/routing/scoped_routes_spec.rb +0 -47
  249. data/spec/spec_helper.rb +0 -57
  250. data/spec/spec_helper_integration.rb +0 -4
  251. data/spec/support/dependencies/factory_bot.rb +0 -4
  252. data/spec/support/doorkeeper_rspec.rb +0 -22
  253. data/spec/support/helpers/access_token_request_helper.rb +0 -13
  254. data/spec/support/helpers/authorization_request_helper.rb +0 -43
  255. data/spec/support/helpers/config_helper.rb +0 -11
  256. data/spec/support/helpers/model_helper.rb +0 -78
  257. data/spec/support/helpers/request_spec_helper.rb +0 -98
  258. data/spec/support/helpers/url_helper.rb +0 -62
  259. data/spec/support/http_method_shim.rb +0 -29
  260. data/spec/support/orm/active_record.rb +0 -5
  261. data/spec/support/shared/controllers_shared_context.rb +0 -123
  262. data/spec/support/shared/hashing_shared_context.rb +0 -36
  263. data/spec/support/shared/models_shared_examples.rb +0 -54
  264. data/spec/validators/redirect_uri_validator_spec.rb +0 -158
  265. data/spec/version/version_spec.rb +0 -17
@@ -5,13 +5,15 @@ module Doorkeeper
5
5
  class ErrorResponse < BaseResponse
6
6
  include OAuth::Helpers
7
7
 
8
+ NON_REDIRECTABLE_STATES = %i[invalid_redirect_uri invalid_client unauthorized_client].freeze
9
+
8
10
  def self.from_request(request, attributes = {})
9
11
  new(
10
12
  attributes.merge(
11
13
  name: request.error,
12
14
  state: request.try(:state),
13
- redirect_uri: request.try(:redirect_uri)
14
- )
15
+ redirect_uri: request.try(:redirect_uri),
16
+ ),
15
17
  )
16
18
  end
17
19
 
@@ -32,7 +34,7 @@ module Doorkeeper
32
34
  end
33
35
 
34
36
  def status
35
- if name == :invalid_client
37
+ if name == :invalid_client || name == :unauthorized_client
36
38
  :unauthorized
37
39
  else
38
40
  :bad_request
@@ -40,15 +42,14 @@ module Doorkeeper
40
42
  end
41
43
 
42
44
  def redirectable?
43
- name != :invalid_redirect_uri && name != :invalid_client &&
44
- !URIChecker.native_uri?(@redirect_uri)
45
+ !NON_REDIRECTABLE_STATES.include?(name) && !URIChecker.oob_uri?(@redirect_uri)
45
46
  end
46
47
 
47
48
  def redirect_uri
48
49
  if @response_on_fragment
49
- Authorization::URIBuilder.uri_with_fragment @redirect_uri, body
50
+ Authorization::URIBuilder.uri_with_fragment(@redirect_uri, body)
50
51
  else
51
- Authorization::URIBuilder.uri_with_query @redirect_uri, body
52
+ Authorization::URIBuilder.uri_with_query(@redirect_uri, body)
52
53
  end
53
54
  end
54
55
 
@@ -67,10 +68,8 @@ module Doorkeeper
67
68
 
68
69
  protected
69
70
 
70
- delegate :realm, to: :configuration
71
-
72
- def configuration
73
- Doorkeeper.configuration
71
+ def realm
72
+ Doorkeeper.config.realm
74
73
  end
75
74
 
76
75
  def exception_class
@@ -12,9 +12,7 @@ module Doorkeeper
12
12
  @scope_str = scope_str
13
13
  @valid_scopes = valid_scopes(server_scopes, app_scopes)
14
14
 
15
- if grant_type
16
- @scopes_by_grant_type = Doorkeeper.configuration.scopes_by_grant_type[grant_type.to_sym]
17
- end
15
+ @scopes_by_grant_type = Doorkeeper.config.scopes_by_grant_type[grant_type.to_sym] if grant_type
18
16
  end
19
17
 
20
18
  def valid?
@@ -27,11 +25,7 @@ module Doorkeeper
27
25
  private
28
26
 
29
27
  def valid_scopes(server_scopes, app_scopes)
30
- if app_scopes.present?
31
- app_scopes
32
- else
33
- server_scopes
34
- end
28
+ app_scopes.presence || server_scopes
35
29
  end
36
30
 
37
31
  def permitted_to_grant_type?
@@ -43,10 +37,12 @@ module Doorkeeper
43
37
  end
44
38
 
45
39
  def self.valid?(scope_str:, server_scopes:, app_scopes: nil, grant_type: nil)
46
- Validator.new(scope_str,
47
- server_scopes,
48
- app_scopes,
49
- grant_type).valid?
40
+ Validator.new(
41
+ scope_str,
42
+ server_scopes,
43
+ app_scopes,
44
+ grant_type,
45
+ ).valid?
50
46
  end
51
47
  end
52
48
  end
@@ -3,6 +3,9 @@
3
3
  module Doorkeeper
4
4
  module OAuth
5
5
  module Helpers
6
+ # Default Doorkeeper token generator. Follows OAuth RFC and
7
+ # could be customized using `default_generator_method` in
8
+ # configuration.
6
9
  module UniqueToken
7
10
  def self.generate(options = {})
8
11
  # Access Token value must be 1*VSCHAR or
@@ -11,15 +14,15 @@ module Doorkeeper
11
14
  # @see https://tools.ietf.org/html/rfc6749#appendix-A.12
12
15
  # @see https://tools.ietf.org/html/rfc6750#section-2.1
13
16
  #
14
- generator_method = options.delete(:generator) || SecureRandom.method(self.generator_method)
15
- token_size = options.delete(:size) || 32
16
- generator_method.call(token_size)
17
+ generator = options.delete(:generator) || SecureRandom.method(default_generator_method)
18
+ token_size = options.delete(:size) || 32
19
+ generator.call(token_size)
17
20
  end
18
21
 
19
22
  # Generator method for default generator class (SecureRandom)
20
23
  #
21
- def self.generator_method
22
- Doorkeeper.configuration.default_generator_method
24
+ def self.default_generator_method
25
+ Doorkeeper.config.default_generator_method
23
26
  end
24
27
  end
25
28
  end
@@ -18,17 +18,17 @@ module Doorkeeper
18
18
 
19
19
  # For backward compatibility with old rubies
20
20
  if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.5.0")
21
- IPAddr.send(:include, Doorkeeper::IPAddrLoopback)
21
+ IPAddr.include Doorkeeper::IPAddrLoopback
22
22
  end
23
23
 
24
24
  module OAuth
25
25
  module Helpers
26
26
  module URIChecker
27
27
  def self.valid?(url)
28
- return true if native_uri?(url)
28
+ return true if oob_uri?(url)
29
29
 
30
30
  uri = as_uri(url)
31
- uri.fragment.nil? && !uri.host.nil? && !uri.scheme.nil?
31
+ valid_scheme?(uri) && iff_host?(uri) && uri.fragment.nil? && uri.opaque.nil?
32
32
  rescue URI::InvalidURIError
33
33
  false
34
34
  end
@@ -78,8 +78,22 @@ module Doorkeeper
78
78
  client_query.split("&").sort == query.split("&").sort
79
79
  end
80
80
 
81
- def self.native_uri?(url)
82
- url == Doorkeeper.configuration.native_redirect_uri
81
+ def self.valid_scheme?(uri)
82
+ return false if uri.scheme.nil?
83
+
84
+ %w[localhost].include?(uri.scheme) == false
85
+ end
86
+
87
+ def self.hypertext_scheme?(uri)
88
+ %w[http https].include?(uri.scheme)
89
+ end
90
+
91
+ def self.iff_host?(uri)
92
+ !(hypertext_scheme?(uri) && uri.host.nil?)
93
+ end
94
+
95
+ def self.oob_uri?(uri)
96
+ NonStandard::IETF_WG_OAUTH2_OOB_METHODS.include?(uri)
83
97
  end
84
98
  end
85
99
  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
@@ -6,9 +6,9 @@ module Doorkeeper
6
6
  attr_reader :reason
7
7
 
8
8
  def self.from_access_token(access_token, attributes = {})
9
- reason = if access_token.try(:revoked?)
9
+ reason = if access_token&.revoked?
10
10
  :revoked
11
- elsif access_token.try(:expired?)
11
+ elsif access_token&.expired?
12
12
  :expired
13
13
  else
14
14
  :unknown
@@ -27,8 +27,11 @@ module Doorkeeper
27
27
  end
28
28
 
29
29
  def description
30
- scope = { scope: %i[doorkeeper errors messages invalid_token] }
31
- @description ||= I18n.translate @reason, scope
30
+ @description ||=
31
+ I18n.translate(
32
+ @reason,
33
+ scope: %i[doorkeeper errors messages invalid_token],
34
+ )
32
35
  end
33
36
 
34
37
  protected
@@ -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
@@ -5,12 +5,12 @@ module Doorkeeper
5
5
  class PasswordAccessTokenRequest < BaseRequest
6
6
  include OAuth::Helpers
7
7
 
8
- validate :client, error: :invalid_client
8
+ validate :client, error: :invalid_client
9
+ validate :client_supports_grant_flow, error: :unauthorized_client
9
10
  validate :resource_owner, error: :invalid_grant
10
- validate :scopes, error: :invalid_scope
11
+ validate :scopes, error: :invalid_scope
11
12
 
12
- attr_accessor :server, :client, :resource_owner, :parameters,
13
- :access_token
13
+ attr_reader :client, :resource_owner, :parameters, :access_token
14
14
 
15
15
  def initialize(server, client, resource_owner, parameters = {})
16
16
  @server = server
@@ -24,28 +24,50 @@ module Doorkeeper
24
24
  private
25
25
 
26
26
  def before_successful_response
27
- find_or_create_access_token(client, resource_owner.id, scopes, server)
27
+ find_or_create_access_token(client, resource_owner, scopes, server)
28
28
  super
29
29
  end
30
30
 
31
31
  def validate_scopes
32
- client_scopes = client.try(:scopes)
33
32
  return true if scopes.blank?
34
33
 
35
34
  ScopeChecker.valid?(
36
35
  scope_str: scopes.to_s,
37
36
  server_scopes: server.scopes,
38
- app_scopes: client_scopes,
39
- grant_type: grant_type
37
+ app_scopes: client.try(:scopes),
38
+ grant_type: grant_type,
40
39
  )
41
40
  end
42
41
 
43
42
  def validate_resource_owner
44
- !resource_owner.nil?
43
+ resource_owner.present?
45
44
  end
46
45
 
46
+ # Section 4.3.2. Access Token Request for Resource Owner Password Credentials Grant:
47
+ #
48
+ # If the client type is confidential or the client was issued client credentials (or assigned
49
+ # other authentication requirements), the client MUST authenticate with the authorization
50
+ # server as described in Section 3.2.1.
51
+ #
52
+ # The authorization server MUST:
53
+ #
54
+ # o require client authentication for confidential clients or for any client that was
55
+ # issued client credentials (or with other authentication requirements)
56
+ #
57
+ # o authenticate the client if client authentication is included,
58
+ #
59
+ # @see https://tools.ietf.org/html/rfc6749#section-4.3
60
+ #
47
61
  def validate_client
48
- !parameters[:client_id] || client.present?
62
+ if Doorkeeper.config.skip_client_authentication_for_password_grant
63
+ !parameters[:client_id] || client.present?
64
+ else
65
+ client.present?
66
+ end
67
+ end
68
+
69
+ def validate_client_supports_grant_flow
70
+ server_config.allow_grant_flow_for_client?(grant_type, client&.application)
49
71
  end
50
72
  end
51
73
  end
@@ -5,25 +5,32 @@ module Doorkeeper
5
5
  class PreAuthorization
6
6
  include Validations
7
7
 
8
- validate :response_type, error: :unsupported_response_type
8
+ validate :client_id, error: :invalid_request
9
9
  validate :client, error: :invalid_client
10
- validate :scopes, error: :invalid_scope
10
+ validate :client_supports_grant_flow, error: :unauthorized_client
11
+ validate :resource_owner_authorize_for_client, error: :invalid_client
11
12
  validate :redirect_uri, error: :invalid_redirect_uri
13
+ validate :params, error: :invalid_request
14
+ validate :response_type, error: :unsupported_response_type
15
+ validate :response_mode, error: :unsupported_response_mode
16
+ validate :scopes, error: :invalid_scope
12
17
  validate :code_challenge_method, error: :invalid_code_challenge_method
13
18
 
14
- attr_accessor :server, :client, :response_type, :redirect_uri, :state,
15
- :code_challenge, :code_challenge_method
16
- attr_writer :scope
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
17
22
 
18
- def initialize(server, client, attrs = {})
23
+ def initialize(server, parameters = {}, resource_owner = nil)
19
24
  @server = server
20
- @client = client
21
- @response_type = attrs[:response_type]
22
- @redirect_uri = attrs[:redirect_uri]
23
- @scope = attrs[:scope]
24
- @state = attrs[:state]
25
- @code_challenge = attrs[:code_challenge]
26
- @code_challenge_method = attrs[:code_challenge_method]
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
27
34
  end
28
35
 
29
36
  def authorizable?
@@ -31,33 +38,38 @@ module Doorkeeper
31
38
  end
32
39
 
33
40
  def scopes
34
- Scopes.from_string scope
41
+ Scopes.from_string(scope)
35
42
  end
36
43
 
37
44
  def scope
38
- @scope.presence || build_scopes
45
+ @scope.presence || (server.default_scopes.presence && build_scopes)
39
46
  end
40
47
 
41
48
  def error_response
42
- OAuth::ErrorResponse.from_request(self)
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
43
57
  end
44
58
 
45
- def as_json(_options)
46
- {
47
- client_id: client.uid,
48
- redirect_uri: redirect_uri,
49
- state: state,
50
- response_type: response_type,
51
- scope: scope,
52
- client_name: client.name,
53
- status: I18n.t("doorkeeper.pre_authorization.status"),
54
- }
59
+ def as_json(_options = nil)
60
+ pre_auth_hash
61
+ end
62
+
63
+ def form_post_response?
64
+ response_mode == "form_post"
55
65
  end
56
66
 
57
67
  private
58
68
 
69
+ attr_reader :client_id, :server
70
+
59
71
  def build_scopes
60
- client_scopes = client.application.scopes
72
+ client_scopes = client.scopes
61
73
  if client_scopes.blank?
62
74
  server.default_scopes.to_s
63
75
  else
@@ -65,27 +77,23 @@ module Doorkeeper
65
77
  end
66
78
  end
67
79
 
68
- def validate_response_type
69
- server.authorization_response_types.include? response_type
80
+ def validate_client_id
81
+ @missing_param = :client_id if client_id.blank?
82
+ @missing_param.nil?
70
83
  end
71
84
 
72
85
  def validate_client
73
- client.present?
86
+ @client = OAuth::Client.find(client_id)
87
+ @client.present?
74
88
  end
75
89
 
76
- def validate_scopes
77
- return true if scope.blank?
78
-
79
- Helpers::ScopeChecker.valid?(
80
- scope_str: scope,
81
- server_scopes: server.scopes,
82
- app_scopes: client.application.scopes,
83
- grant_type: grant_type
84
- )
90
+ def validate_client_supports_grant_flow
91
+ Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client.application)
85
92
  end
86
93
 
87
- def grant_type
88
- response_type == "code" ? AUTHORIZATION_CODE : IMPLICIT
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)
89
97
  end
90
98
 
91
99
  def validate_redirect_uri
@@ -93,14 +101,75 @@ module Doorkeeper
93
101
 
94
102
  Helpers::URIChecker.valid_for_authorization?(
95
103
  redirect_uri,
96
- client.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)
134
+ end
135
+
136
+ def validate_scopes
137
+ Helpers::ScopeChecker.valid?(
138
+ scope_str: scope,
139
+ server_scopes: server.scopes,
140
+ app_scopes: client.scopes,
141
+ grant_type: grant_type,
97
142
  )
98
143
  end
99
144
 
100
145
  def validate_code_challenge_method
146
+ return true unless Doorkeeper.config.access_grant_model.pkce_supported?
147
+
101
148
  code_challenge.blank? ||
102
149
  (code_challenge_method.present? && code_challenge_method =~ /^plain$|^S256$/)
103
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
+ }
172
+ end
104
173
  end
105
174
  end
106
175
  end