doorkeeper 5.1.2 → 5.6.6

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 (272) hide show
  1. checksums.yaml +4 -4
  2. data/{NEWS.md → CHANGELOG.md} +314 -27
  3. data/README.md +39 -22
  4. data/app/controllers/doorkeeper/application_controller.rb +3 -2
  5. data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
  6. data/app/controllers/doorkeeper/applications_controller.rb +5 -4
  7. data/app/controllers/doorkeeper/authorizations_controller.rb +76 -25
  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 +99 -28
  11. data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
  12. data/app/views/doorkeeper/applications/_form.html.erb +1 -7
  13. data/app/views/doorkeeper/applications/show.html.erb +35 -14
  14. data/app/views/doorkeeper/authorizations/error.html.erb +3 -1
  15. data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  16. data/app/views/doorkeeper/authorizations/new.html.erb +16 -14
  17. data/config/locales/en.yml +16 -3
  18. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  19. data/lib/doorkeeper/config/option.rb +20 -2
  20. data/lib/doorkeeper/config/validations.rb +53 -0
  21. data/lib/doorkeeper/config.rb +300 -136
  22. data/lib/doorkeeper/engine.rb +10 -3
  23. data/lib/doorkeeper/errors.rb +13 -18
  24. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  25. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  26. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  27. data/lib/doorkeeper/grant_flow.rb +45 -0
  28. data/lib/doorkeeper/grape/helpers.rb +7 -3
  29. data/lib/doorkeeper/helpers/controller.rb +36 -11
  30. data/lib/doorkeeper/models/access_grant_mixin.rb +23 -19
  31. data/lib/doorkeeper/models/access_token_mixin.rb +195 -52
  32. data/lib/doorkeeper/models/application_mixin.rb +8 -7
  33. data/lib/doorkeeper/models/concerns/expirable.rb +1 -1
  34. data/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +88 -0
  35. data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
  36. data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +30 -0
  37. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  38. data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
  39. data/lib/doorkeeper/models/concerns/revocable.rb +1 -28
  40. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  41. data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
  42. data/lib/doorkeeper/oauth/authorization/code.rb +31 -14
  43. data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
  44. data/lib/doorkeeper/oauth/authorization/token.rb +30 -19
  45. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
  46. data/lib/doorkeeper/oauth/authorization_code_request.rb +51 -22
  47. data/lib/doorkeeper/oauth/base_request.rb +21 -22
  48. data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
  49. data/lib/doorkeeper/oauth/client.rb +8 -9
  50. data/lib/doorkeeper/oauth/client_credentials/creator.rb +42 -5
  51. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +10 -8
  52. data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +14 -5
  53. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
  54. data/lib/doorkeeper/oauth/code_request.rb +6 -12
  55. data/lib/doorkeeper/oauth/code_response.rb +24 -14
  56. data/lib/doorkeeper/oauth/error.rb +1 -1
  57. data/lib/doorkeeper/oauth/error_response.rb +11 -13
  58. data/lib/doorkeeper/oauth/forbidden_token_response.rb +2 -1
  59. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +8 -12
  60. data/lib/doorkeeper/oauth/helpers/unique_token.rb +10 -7
  61. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +19 -23
  62. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  63. data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
  64. data/lib/doorkeeper/oauth/invalid_token_response.rb +7 -4
  65. data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
  66. data/lib/doorkeeper/oauth/password_access_token_request.rb +34 -11
  67. data/lib/doorkeeper/oauth/pre_authorization.rb +114 -44
  68. data/lib/doorkeeper/oauth/refresh_token_request.rb +54 -34
  69. data/lib/doorkeeper/oauth/token.rb +6 -7
  70. data/lib/doorkeeper/oauth/token_introspection.rb +28 -22
  71. data/lib/doorkeeper/oauth/token_request.rb +6 -20
  72. data/lib/doorkeeper/oauth/token_response.rb +2 -3
  73. data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
  74. data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
  75. data/lib/doorkeeper/orm/active_record/application.rb +5 -149
  76. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +63 -0
  77. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +77 -0
  78. data/lib/doorkeeper/orm/active_record/mixins/application.rb +210 -0
  79. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
  80. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +5 -2
  81. data/lib/doorkeeper/orm/active_record.rb +29 -22
  82. data/lib/doorkeeper/rails/helpers.rb +4 -4
  83. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  84. data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
  85. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  86. data/lib/doorkeeper/rails/routes.rb +28 -27
  87. data/lib/doorkeeper/rake/db.rake +6 -6
  88. data/lib/doorkeeper/request/authorization_code.rb +5 -3
  89. data/lib/doorkeeper/request/client_credentials.rb +2 -2
  90. data/lib/doorkeeper/request/password.rb +3 -2
  91. data/lib/doorkeeper/request/refresh_token.rb +5 -4
  92. data/lib/doorkeeper/request/strategy.rb +2 -2
  93. data/lib/doorkeeper/request.rb +49 -17
  94. data/lib/doorkeeper/server.rb +7 -11
  95. data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
  96. data/lib/doorkeeper/version.rb +2 -6
  97. data/lib/doorkeeper.rb +183 -80
  98. data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
  99. data/lib/generators/doorkeeper/confidential_applications_generator.rb +2 -2
  100. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  101. data/lib/generators/doorkeeper/migration_generator.rb +1 -1
  102. data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
  103. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +7 -7
  104. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +3 -1
  105. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
  106. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
  107. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  108. data/lib/generators/doorkeeper/templates/initializer.rb +230 -50
  109. data/lib/generators/doorkeeper/templates/migration.rb.erb +31 -9
  110. metadata +61 -327
  111. data/.coveralls.yml +0 -1
  112. data/.github/ISSUE_TEMPLATE.md +0 -25
  113. data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
  114. data/.gitignore +0 -20
  115. data/.gitlab-ci.yml +0 -16
  116. data/.hound.yml +0 -3
  117. data/.rspec +0 -1
  118. data/.rubocop.yml +0 -50
  119. data/.travis.yml +0 -35
  120. data/Appraisals +0 -40
  121. data/CODE_OF_CONDUCT.md +0 -46
  122. data/CONTRIBUTING.md +0 -47
  123. data/Dangerfile +0 -67
  124. data/Gemfile +0 -24
  125. data/RELEASING.md +0 -10
  126. data/Rakefile +0 -28
  127. data/SECURITY.md +0 -15
  128. data/UPGRADE.md +0 -2
  129. data/app/validators/redirect_uri_validator.rb +0 -50
  130. data/bin/console +0 -16
  131. data/doorkeeper.gemspec +0 -34
  132. data/gemfiles/rails_5_0.gemfile +0 -17
  133. data/gemfiles/rails_5_1.gemfile +0 -17
  134. data/gemfiles/rails_5_2.gemfile +0 -17
  135. data/gemfiles/rails_6_0.gemfile +0 -17
  136. data/gemfiles/rails_master.gemfile +0 -17
  137. data/spec/controllers/application_metal_controller_spec.rb +0 -64
  138. data/spec/controllers/applications_controller_spec.rb +0 -180
  139. data/spec/controllers/authorizations_controller_spec.rb +0 -527
  140. data/spec/controllers/protected_resources_controller_spec.rb +0 -353
  141. data/spec/controllers/token_info_controller_spec.rb +0 -50
  142. data/spec/controllers/tokens_controller_spec.rb +0 -330
  143. data/spec/dummy/Rakefile +0 -9
  144. data/spec/dummy/app/assets/config/manifest.js +0 -2
  145. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  146. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
  147. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
  148. data/spec/dummy/app/controllers/home_controller.rb +0 -18
  149. data/spec/dummy/app/controllers/metal_controller.rb +0 -13
  150. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
  151. data/spec/dummy/app/helpers/application_helper.rb +0 -7
  152. data/spec/dummy/app/models/user.rb +0 -7
  153. data/spec/dummy/app/views/home/index.html.erb +0 -0
  154. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  155. data/spec/dummy/config/application.rb +0 -47
  156. data/spec/dummy/config/boot.rb +0 -7
  157. data/spec/dummy/config/database.yml +0 -15
  158. data/spec/dummy/config/environment.rb +0 -5
  159. data/spec/dummy/config/environments/development.rb +0 -31
  160. data/spec/dummy/config/environments/production.rb +0 -64
  161. data/spec/dummy/config/environments/test.rb +0 -45
  162. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
  163. data/spec/dummy/config/initializers/doorkeeper.rb +0 -121
  164. data/spec/dummy/config/initializers/secret_token.rb +0 -10
  165. data/spec/dummy/config/initializers/session_store.rb +0 -10
  166. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
  167. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  168. data/spec/dummy/config/routes.rb +0 -13
  169. data/spec/dummy/config.ru +0 -6
  170. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
  171. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
  172. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
  173. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
  174. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
  175. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
  176. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
  177. data/spec/dummy/db/schema.rb +0 -68
  178. data/spec/dummy/public/404.html +0 -26
  179. data/spec/dummy/public/422.html +0 -26
  180. data/spec/dummy/public/500.html +0 -26
  181. data/spec/dummy/public/favicon.ico +0 -0
  182. data/spec/dummy/script/rails +0 -9
  183. data/spec/factories.rb +0 -30
  184. data/spec/generators/application_owner_generator_spec.rb +0 -28
  185. data/spec/generators/confidential_applications_generator_spec.rb +0 -29
  186. data/spec/generators/install_generator_spec.rb +0 -36
  187. data/spec/generators/migration_generator_spec.rb +0 -28
  188. data/spec/generators/pkce_generator_spec.rb +0 -28
  189. data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
  190. data/spec/generators/templates/routes.rb +0 -4
  191. data/spec/generators/views_generator_spec.rb +0 -29
  192. data/spec/grape/grape_integration_spec.rb +0 -137
  193. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
  194. data/spec/lib/config_spec.rb +0 -697
  195. data/spec/lib/doorkeeper_spec.rb +0 -27
  196. data/spec/lib/models/expirable_spec.rb +0 -61
  197. data/spec/lib/models/reusable_spec.rb +0 -40
  198. data/spec/lib/models/revocable_spec.rb +0 -59
  199. data/spec/lib/models/scopes_spec.rb +0 -53
  200. data/spec/lib/models/secret_storable_spec.rb +0 -135
  201. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
  202. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -156
  203. data/spec/lib/oauth/base_request_spec.rb +0 -205
  204. data/spec/lib/oauth/base_response_spec.rb +0 -47
  205. data/spec/lib/oauth/client/credentials_spec.rb +0 -90
  206. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -94
  207. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
  208. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
  209. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -29
  210. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -109
  211. data/spec/lib/oauth/client_spec.rb +0 -38
  212. data/spec/lib/oauth/code_request_spec.rb +0 -47
  213. data/spec/lib/oauth/code_response_spec.rb +0 -36
  214. data/spec/lib/oauth/error_response_spec.rb +0 -66
  215. data/spec/lib/oauth/error_spec.rb +0 -23
  216. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -22
  217. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -98
  218. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
  219. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -247
  220. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -55
  221. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -192
  222. data/spec/lib/oauth/pre_authorization_spec.rb +0 -215
  223. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
  224. data/spec/lib/oauth/scopes_spec.rb +0 -148
  225. data/spec/lib/oauth/token_request_spec.rb +0 -150
  226. data/spec/lib/oauth/token_response_spec.rb +0 -86
  227. data/spec/lib/oauth/token_spec.rb +0 -158
  228. data/spec/lib/request/strategy_spec.rb +0 -54
  229. data/spec/lib/secret_storing/base_spec.rb +0 -60
  230. data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
  231. data/spec/lib/secret_storing/plain_spec.rb +0 -44
  232. data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
  233. data/spec/lib/server_spec.rb +0 -61
  234. data/spec/lib/stale_records_cleaner_spec.rb +0 -89
  235. data/spec/models/doorkeeper/access_grant_spec.rb +0 -144
  236. data/spec/models/doorkeeper/access_token_spec.rb +0 -591
  237. data/spec/models/doorkeeper/application_spec.rb +0 -472
  238. data/spec/requests/applications/applications_request_spec.rb +0 -259
  239. data/spec/requests/applications/authorized_applications_spec.rb +0 -32
  240. data/spec/requests/endpoints/authorization_spec.rb +0 -73
  241. data/spec/requests/endpoints/token_spec.rb +0 -75
  242. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -78
  243. data/spec/requests/flows/authorization_code_spec.rb +0 -447
  244. data/spec/requests/flows/client_credentials_spec.rb +0 -128
  245. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -34
  246. data/spec/requests/flows/implicit_grant_spec.rb +0 -90
  247. data/spec/requests/flows/password_spec.rb +0 -259
  248. data/spec/requests/flows/refresh_token_spec.rb +0 -233
  249. data/spec/requests/flows/revoke_token_spec.rb +0 -143
  250. data/spec/requests/flows/skip_authorization_spec.rb +0 -66
  251. data/spec/requests/protected_resources/metal_spec.rb +0 -16
  252. data/spec/requests/protected_resources/private_api_spec.rb +0 -83
  253. data/spec/routing/custom_controller_routes_spec.rb +0 -133
  254. data/spec/routing/default_routes_spec.rb +0 -41
  255. data/spec/routing/scoped_routes_spec.rb +0 -47
  256. data/spec/spec_helper.rb +0 -57
  257. data/spec/spec_helper_integration.rb +0 -4
  258. data/spec/support/dependencies/factory_bot.rb +0 -4
  259. data/spec/support/doorkeeper_rspec.rb +0 -22
  260. data/spec/support/helpers/access_token_request_helper.rb +0 -13
  261. data/spec/support/helpers/authorization_request_helper.rb +0 -43
  262. data/spec/support/helpers/config_helper.rb +0 -11
  263. data/spec/support/helpers/model_helper.rb +0 -78
  264. data/spec/support/helpers/request_spec_helper.rb +0 -98
  265. data/spec/support/helpers/url_helper.rb +0 -62
  266. data/spec/support/http_method_shim.rb +0 -29
  267. data/spec/support/orm/active_record.rb +0 -5
  268. data/spec/support/shared/controllers_shared_context.rb +0 -123
  269. data/spec/support/shared/hashing_shared_context.rb +0 -36
  270. data/spec/support/shared/models_shared_examples.rb +0 -54
  271. data/spec/validators/redirect_uri_validator_spec.rb +0 -158
  272. data/spec/version/version_spec.rb +0 -17
@@ -3,18 +3,12 @@
3
3
  module Doorkeeper
4
4
  module OAuth
5
5
  class ClientCredentialsRequest < BaseRequest
6
- attr_accessor :server, :client, :original_scopes
7
- attr_reader :response
8
- attr_writer :issuer
6
+ attr_reader :client, :original_scopes, :response
9
7
 
10
8
  alias error_response response
11
9
 
12
10
  delegate :error, to: :issuer
13
11
 
14
- def issuer
15
- @issuer ||= Issuer.new(server, Validation.new(server, self))
16
- end
17
-
18
12
  def initialize(server, client, parameters = {})
19
13
  @client = client
20
14
  @server = server
@@ -26,6 +20,13 @@ module Doorkeeper
26
20
  issuer.token
27
21
  end
28
22
 
23
+ def issuer
24
+ @issuer ||= ClientCredentials::Issuer.new(
25
+ server,
26
+ ClientCredentials::Validator.new(server, self),
27
+ )
28
+ end
29
+
29
30
  private
30
31
 
31
32
  def valid?
@@ -3,28 +3,22 @@
3
3
  module Doorkeeper
4
4
  module OAuth
5
5
  class CodeRequest
6
- attr_accessor :pre_auth, :resource_owner, :client
6
+ attr_reader :pre_auth, :resource_owner
7
7
 
8
8
  def initialize(pre_auth, resource_owner)
9
- @pre_auth = pre_auth
10
- @client = pre_auth.client
9
+ @pre_auth = pre_auth
11
10
  @resource_owner = resource_owner
12
11
  end
13
12
 
14
13
  def authorize
15
- if pre_auth.authorizable?
16
- auth = Authorization::Code.new(pre_auth, resource_owner)
17
- auth.issue_token
18
- @response = CodeResponse.new pre_auth, auth
19
- else
20
- @response = ErrorResponse.from_request pre_auth
21
- end
14
+ auth = Authorization::Code.new(pre_auth, resource_owner)
15
+ auth.issue_token!
16
+ CodeResponse.new(pre_auth, auth, response_on_fragment: pre_auth.response_mode == "fragment")
22
17
  end
23
18
 
24
19
  def deny
25
20
  pre_auth.error = :access_denied
26
- ErrorResponse.from_request pre_auth,
27
- redirect_uri: pre_auth.redirect_uri
21
+ pre_auth.error_response
28
22
  end
29
23
  end
30
24
  end
@@ -5,7 +5,7 @@ module Doorkeeper
5
5
  class CodeResponse < BaseResponse
6
6
  include OAuth::Helpers
7
7
 
8
- attr_accessor :pre_auth, :auth, :response_on_fragment
8
+ attr_reader :pre_auth, :auth, :response_on_fragment
9
9
 
10
10
  def initialize(pre_auth, auth, options = {})
11
11
  @pre_auth = pre_auth
@@ -17,23 +17,33 @@ module Doorkeeper
17
17
  true
18
18
  end
19
19
 
20
- def redirect_uri
21
- if URIChecker.native_uri? pre_auth.redirect_uri
22
- auth.native_redirect
23
- elsif response_on_fragment
24
- Authorization::URIBuilder.uri_with_fragment(
25
- pre_auth.redirect_uri,
20
+ def issued_token
21
+ auth.token
22
+ end
23
+
24
+ def body
25
+ if auth.try(:access_token?)
26
+ {
26
27
  access_token: auth.token.plaintext_token,
27
28
  token_type: auth.token.token_type,
28
29
  expires_in: auth.token.expires_in_seconds,
29
- state: pre_auth.state
30
- )
31
- else
32
- Authorization::URIBuilder.uri_with_query(
33
- pre_auth.redirect_uri,
30
+ state: pre_auth.state,
31
+ }
32
+ elsif auth.try(:access_grant?)
33
+ {
34
34
  code: auth.token.plaintext_token,
35
- state: pre_auth.state
36
- )
35
+ state: pre_auth.state,
36
+ }
37
+ end
38
+ end
39
+
40
+ def redirect_uri
41
+ if URIChecker.oob_uri?(pre_auth.redirect_uri)
42
+ auth.oob_redirect
43
+ elsif response_on_fragment
44
+ Authorization::URIBuilder.uri_with_fragment(pre_auth.redirect_uri, body)
45
+ else
46
+ Authorization::URIBuilder.uri_with_query(pre_auth.redirect_uri, body)
37
47
  end
38
48
  end
39
49
  end
@@ -7,7 +7,7 @@ module Doorkeeper
7
7
  I18n.translate(
8
8
  name,
9
9
  scope: %i[doorkeeper errors messages],
10
- default: :server_error
10
+ default: :server_error,
11
11
  )
12
12
  end
13
13
  end
@@ -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,22 +42,20 @@ 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
 
55
56
  def headers
56
57
  {
57
- "Cache-Control" => "no-store",
58
- "Pragma" => "no-cache",
58
+ "Cache-Control" => "no-store, no-cache",
59
59
  "Content-Type" => "application/json; charset=utf-8",
60
60
  "WWW-Authenticate" => authenticate_info,
61
61
  }
@@ -67,10 +67,8 @@ module Doorkeeper
67
67
 
68
68
  protected
69
69
 
70
- delegate :realm, to: :configuration
71
-
72
- def configuration
73
- Doorkeeper.configuration
70
+ def realm
71
+ Doorkeeper.config.realm
74
72
  end
75
73
 
76
74
  def exception_class
@@ -23,7 +23,8 @@ module Doorkeeper
23
23
  end
24
24
 
25
25
  def description
26
- @description ||= @scopes.map { |s| I18n.t(s, scope: %i[doorkeeper scopes]) }.join("\n")
26
+ @description ||= I18n.t("doorkeeper.errors.messages.forbidden_token.missing_scope",
27
+ oauth_scopes: @scopes.map(&:to_s).join(" "),)
27
28
  end
28
29
 
29
30
  protected
@@ -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,23 +3,26 @@
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
9
12
  # 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="
10
13
  #
11
- # @see https://tools.ietf.org/html/rfc6749#appendix-A.12
12
- # @see https://tools.ietf.org/html/rfc6750#section-2.1
14
+ # @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.12
15
+ # @see https://datatracker.ietf.org/doc/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
@@ -3,32 +3,14 @@
3
3
  require "ipaddr"
4
4
 
5
5
  module Doorkeeper
6
- module IPAddrLoopback
7
- def loopback?
8
- case @family
9
- when Socket::AF_INET
10
- @addr & 0xff000000 == 0x7f000000
11
- when Socket::AF_INET6
12
- @addr == 1
13
- else
14
- raise AddressFamilyError, "unsupported address family"
15
- end
16
- end
17
- end
18
-
19
- # For backward compatibility with old rubies
20
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("2.5.0")
21
- IPAddr.send(:include, Doorkeeper::IPAddrLoopback)
22
- end
23
-
24
6
  module OAuth
25
7
  module Helpers
26
8
  module URIChecker
27
9
  def self.valid?(url)
28
- return true if native_uri?(url)
10
+ return true if oob_uri?(url)
29
11
 
30
12
  uri = as_uri(url)
31
- uri.fragment.nil? && !uri.host.nil? && !uri.scheme.nil?
13
+ valid_scheme?(uri) && iff_host?(uri) && uri.fragment.nil? && uri.opaque.nil?
32
14
  rescue URI::InvalidURIError
33
15
  false
34
16
  end
@@ -46,7 +28,7 @@ module Doorkeeper
46
28
  end
47
29
 
48
30
  # RFC8252, Paragraph 7.3
49
- # @see https://tools.ietf.org/html/rfc8252#section-7.3
31
+ # @see https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
50
32
  if loopback_uri?(url) && loopback_uri?(client_url)
51
33
  url.port = nil
52
34
  client_url.port = nil
@@ -78,8 +60,22 @@ module Doorkeeper
78
60
  client_query.split("&").sort == query.split("&").sort
79
61
  end
80
62
 
81
- def self.native_uri?(url)
82
- url == Doorkeeper.configuration.native_redirect_uri
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)
83
79
  end
84
80
  end
85
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
@@ -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,17 +5,18 @@ 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, :credentials, :resource_owner, :parameters, :access_token
14
14
 
15
- def initialize(server, client, resource_owner, parameters = {})
15
+ def initialize(server, client, credentials, resource_owner, parameters = {})
16
16
  @server = server
17
17
  @resource_owner = resource_owner
18
18
  @client = client
19
+ @credentials = credentials
19
20
  @parameters = parameters
20
21
  @original_scopes = parameters[:scope]
21
22
  @grant_type = Doorkeeper::OAuth::PASSWORD
@@ -24,28 +25,50 @@ module Doorkeeper
24
25
  private
25
26
 
26
27
  def before_successful_response
27
- find_or_create_access_token(client, resource_owner.id, scopes, server)
28
+ find_or_create_access_token(client, resource_owner, scopes, {}, server)
28
29
  super
29
30
  end
30
31
 
31
32
  def validate_scopes
32
- client_scopes = client.try(:scopes)
33
33
  return true if scopes.blank?
34
34
 
35
35
  ScopeChecker.valid?(
36
36
  scope_str: scopes.to_s,
37
37
  server_scopes: server.scopes,
38
- app_scopes: client_scopes,
39
- grant_type: grant_type
38
+ app_scopes: client.try(:scopes),
39
+ grant_type: grant_type,
40
40
  )
41
41
  end
42
42
 
43
43
  def validate_resource_owner
44
- !resource_owner.nil?
44
+ resource_owner.present?
45
45
  end
46
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
+ #
47
62
  def validate_client
48
- !parameters[:client_id] || client.present?
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)
49
72
  end
50
73
  end
51
74
  end