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
@@ -4,10 +4,10 @@ module Doorkeeper
4
4
  module OAuth
5
5
  module Authorization
6
6
  class Token
7
- attr_accessor :pre_auth, :resource_owner, :token
7
+ attr_reader :pre_auth, :resource_owner, :token
8
8
 
9
9
  class << self
10
- def build_context(pre_auth_or_oauth_client, grant_type, scopes)
10
+ def build_context(pre_auth_or_oauth_client, grant_type, scopes, resource_owner)
11
11
  oauth_client = if pre_auth_or_oauth_client.respond_to?(:application)
12
12
  pre_auth_or_oauth_client.application
13
13
  elsif pre_auth_or_oauth_client.respond_to?(:client)
@@ -17,9 +17,10 @@ module Doorkeeper
17
17
  end
18
18
 
19
19
  Doorkeeper::OAuth::Authorization::Context.new(
20
- oauth_client,
21
- grant_type,
22
- scopes
20
+ client: oauth_client,
21
+ grant_type: grant_type,
22
+ scopes: scopes,
23
+ resource_owner: resource_owner,
23
24
  )
24
25
  end
25
26
 
@@ -35,7 +36,7 @@ module Doorkeeper
35
36
  end
36
37
 
37
38
  def refresh_token_enabled?(server, context)
38
- if server.refresh_token_enabled?.respond_to? :call
39
+ if server.refresh_token_enabled?.respond_to?(:call)
39
40
  server.refresh_token_enabled?.call(context)
40
41
  else
41
42
  !!server.refresh_token_enabled?
@@ -48,22 +49,26 @@ module Doorkeeper
48
49
  @resource_owner = resource_owner
49
50
  end
50
51
 
51
- def issue_token
52
+ def issue_token!
53
+ return @token if defined?(@token)
54
+
52
55
  context = self.class.build_context(
53
56
  pre_auth.client,
54
57
  Doorkeeper::OAuth::IMPLICIT,
55
- pre_auth.scopes
56
- )
57
- @token ||= AccessToken.find_or_create_for(
58
- pre_auth.client,
59
- resource_owner.id,
60
58
  pre_auth.scopes,
61
- self.class.access_token_expires_in(configuration, context),
62
- false
59
+ resource_owner,
60
+ )
61
+
62
+ @token = Doorkeeper.config.access_token_model.find_or_create_for(
63
+ application: pre_auth.client,
64
+ resource_owner: resource_owner,
65
+ scopes: pre_auth.scopes,
66
+ expires_in: self.class.access_token_expires_in(Doorkeeper.config, context),
67
+ use_refresh_token: false,
63
68
  )
64
69
  end
65
70
 
66
- def native_redirect
71
+ def oob_redirect
67
72
  {
68
73
  controller: controller,
69
74
  action: :show,
@@ -71,12 +76,12 @@ module Doorkeeper
71
76
  }
72
77
  end
73
78
 
74
- private
75
-
76
- def configuration
77
- Doorkeeper.configuration
79
+ def access_token?
80
+ true
78
81
  end
79
82
 
83
+ private
84
+
80
85
  def controller
81
86
  @controller ||= begin
82
87
  mapping = Doorkeeper::Rails::Routes.mapping[:token_info] || {}
@@ -8,9 +8,9 @@ module Doorkeeper
8
8
  class URIBuilder
9
9
  class << self
10
10
  def uri_with_query(url, parameters = {})
11
- uri = URI.parse(url)
11
+ uri = URI.parse(url)
12
12
  original_query = Rack::Utils.parse_query(uri.query)
13
- uri.query = build_query(original_query.merge(parameters))
13
+ uri.query = build_query(original_query.merge(parameters))
14
14
  uri.to_s
15
15
  end
16
16
 
@@ -23,8 +23,8 @@ module Doorkeeper
23
23
  private
24
24
 
25
25
  def build_query(parameters = {})
26
- parameters = parameters.reject { |_, v| v.blank? }
27
- Rack::Utils.build_query parameters
26
+ parameters.reject! { |_, value| value.blank? }
27
+ Rack::Utils.build_query(parameters)
28
28
  end
29
29
  end
30
30
  end
@@ -3,15 +3,15 @@
3
3
  module Doorkeeper
4
4
  module OAuth
5
5
  class AuthorizationCodeRequest < BaseRequest
6
- validate :attributes, error: :invalid_request
6
+ validate :params, error: :invalid_request
7
7
  validate :client, error: :invalid_client
8
8
  validate :grant, error: :invalid_grant
9
9
  # @see https://tools.ietf.org/html/rfc6749#section-5.2
10
10
  validate :redirect_uri, error: :invalid_grant
11
11
  validate :code_verifier, error: :invalid_grant
12
12
 
13
- attr_accessor :server, :grant, :client, :redirect_uri, :access_token,
14
- :code_verifier
13
+ attr_reader :grant, :client, :redirect_uri, :access_token, :code_verifier,
14
+ :invalid_request_reason, :missing_param
15
15
 
16
16
  def initialize(server, grant, client, parameters = {})
17
17
  @server = server
@@ -24,29 +24,44 @@ module Doorkeeper
24
24
 
25
25
  private
26
26
 
27
- def client_by_uid(parameters)
28
- Doorkeeper::Application.by_uid(parameters[:client_id])
29
- end
30
-
31
27
  def before_successful_response
32
28
  grant.transaction do
33
29
  grant.lock!
34
30
  raise Errors::InvalidGrantReuse if grant.revoked?
35
31
 
36
32
  grant.revoke
37
- find_or_create_access_token(grant.application,
38
- grant.resource_owner_id,
39
- grant.scopes,
40
- server)
33
+
34
+ find_or_create_access_token(
35
+ grant.application,
36
+ resource_owner,
37
+ grant.scopes,
38
+ server,
39
+ )
41
40
  end
41
+
42
42
  super
43
43
  end
44
44
 
45
- def validate_attributes
46
- return false if grant&.uses_pkce? && code_verifier.blank?
47
- return false if grant && !grant.pkce_supported? && !code_verifier.blank?
45
+ def resource_owner
46
+ if Doorkeeper.config.polymorphic_resource_owner?
47
+ grant.resource_owner
48
+ else
49
+ grant.resource_owner_id
50
+ end
51
+ end
52
+
53
+ def pkce_supported?
54
+ Doorkeeper.config.access_grant_model.pkce_supported?
55
+ end
56
+
57
+ def validate_params
58
+ @missing_param = if grant&.uses_pkce? && code_verifier.blank?
59
+ :code_verifier
60
+ elsif redirect_uri.blank?
61
+ :redirect_uri
62
+ end
48
63
 
49
- redirect_uri.present?
64
+ @missing_param.nil?
50
65
  end
51
66
 
52
67
  def validate_client
@@ -62,24 +77,28 @@ module Doorkeeper
62
77
  def validate_redirect_uri
63
78
  Helpers::URIChecker.valid_for_authorization?(
64
79
  redirect_uri,
65
- grant.redirect_uri
80
+ grant.redirect_uri,
66
81
  )
67
82
  end
68
83
 
69
- # if either side (server or client) request pkce, check the verifier
70
- # against the DB - if pkce is supported
84
+ # if either side (server or client) request PKCE, check the verifier
85
+ # against the DB - if PKCE is supported
71
86
  def validate_code_verifier
72
- return true unless grant.uses_pkce? || code_verifier
73
- return false unless grant.pkce_supported?
87
+ return true unless pkce_supported?
88
+ return grant.code_challenge.blank? if code_verifier.blank?
74
89
 
75
90
  if grant.code_challenge_method == "S256"
76
- grant.code_challenge == AccessGrant.generate_code_challenge(code_verifier)
91
+ grant.code_challenge == generate_code_challenge(code_verifier)
77
92
  elsif grant.code_challenge_method == "plain"
78
93
  grant.code_challenge == code_verifier
79
94
  else
80
95
  false
81
96
  end
82
97
  end
98
+
99
+ def generate_code_challenge(code_verifier)
100
+ server_config.access_grant_model.generate_code_challenge(code_verifier)
101
+ end
83
102
  end
84
103
  end
85
104
  end
@@ -5,16 +5,18 @@ module Doorkeeper
5
5
  class BaseRequest
6
6
  include Validations
7
7
 
8
- attr_reader :grant_type
8
+ attr_reader :grant_type, :server
9
9
 
10
- def authorize
11
- validate
10
+ delegate :default_scopes, to: :server
12
11
 
12
+ def authorize
13
13
  if valid?
14
14
  before_successful_response
15
15
  @response = TokenResponse.new(access_token)
16
16
  after_successful_response
17
17
  @response
18
+ elsif error == :invalid_request
19
+ @response = InvalidRequestResponse.from_request(self)
18
20
  else
19
21
  @response = ErrorResponse.from_request(self)
20
22
  end
@@ -24,31 +26,27 @@ module Doorkeeper
24
26
  @scopes ||= build_scopes
25
27
  end
26
28
 
27
- def default_scopes
28
- server.default_scopes
29
- end
30
-
31
- def valid?
32
- error.nil?
33
- end
34
-
35
- def find_or_create_access_token(client, resource_owner_id, scopes, server)
36
- context = Authorization::Token.build_context(client, grant_type, scopes)
37
- @access_token = AccessToken.find_or_create_for(
38
- client,
39
- resource_owner_id,
40
- scopes,
41
- Authorization::Token.access_token_expires_in(server, context),
42
- Authorization::Token.refresh_token_enabled?(server, context)
29
+ def find_or_create_access_token(client, resource_owner, scopes, server)
30
+ context = Authorization::Token.build_context(client, grant_type, scopes, resource_owner)
31
+ @access_token = server_config.access_token_model.find_or_create_for(
32
+ application: client,
33
+ resource_owner: resource_owner,
34
+ scopes: scopes,
35
+ expires_in: Authorization::Token.access_token_expires_in(server, context),
36
+ use_refresh_token: Authorization::Token.refresh_token_enabled?(server, context),
43
37
  )
44
38
  end
45
39
 
46
40
  def before_successful_response
47
- Doorkeeper.configuration.before_successful_strategy_response.call(self)
41
+ server_config.before_successful_strategy_response.call(self)
48
42
  end
49
43
 
50
44
  def after_successful_response
51
- Doorkeeper.configuration.after_successful_strategy_response.call(self, @response)
45
+ server_config.after_successful_strategy_response.call(self, @response)
46
+ end
47
+
48
+ def server_config
49
+ Doorkeeper.config
52
50
  end
53
51
 
54
52
  private
@@ -57,10 +55,10 @@ module Doorkeeper
57
55
  if @original_scopes.present?
58
56
  OAuth::Scopes.from_string(@original_scopes)
59
57
  else
60
- client_scopes = @client.try(:scopes)
58
+ client_scopes = @client&.scopes
61
59
  return default_scopes if client_scopes.blank?
62
60
 
63
- default_scopes & @client.scopes
61
+ default_scopes & client_scopes
64
62
  end
65
63
  end
66
64
  end
@@ -9,7 +9,7 @@ module Doorkeeper
9
9
  credentials_methods.inject(nil) do |_, method|
10
10
  method = self.method(method) if method.is_a?(Symbol)
11
11
  credentials = Credentials.new(*method.call(request))
12
- break credentials unless credentials.blank?
12
+ break credentials if credentials.present?
13
13
  end
14
14
  end
15
15
 
@@ -27,9 +27,7 @@ module Doorkeeper
27
27
 
28
28
  # Public clients may have their secret blank, but "credentials" are
29
29
  # still present
30
- def blank?
31
- uid.blank?
32
- end
30
+ delegate :blank?, to: :uid
33
31
  end
34
32
  end
35
33
  end
@@ -3,7 +3,7 @@
3
3
  module Doorkeeper
4
4
  module OAuth
5
5
  class Client
6
- attr_accessor :application
6
+ attr_reader :application
7
7
 
8
8
  delegate :id, :name, :uid, :redirect_uri, :scopes, to: :@application
9
9
 
@@ -11,18 +11,17 @@ module Doorkeeper
11
11
  @application = application
12
12
  end
13
13
 
14
- def self.find(uid, method = Application.method(:by_uid))
15
- if (application = method.call(uid))
16
- new(application)
17
- end
14
+ def self.find(uid, method = Doorkeeper.config.application_model.method(:by_uid))
15
+ return unless (application = method.call(uid))
16
+
17
+ new(application)
18
18
  end
19
19
 
20
- def self.authenticate(credentials, method = Application.method(:by_uid_and_secret))
20
+ def self.authenticate(credentials, method = Doorkeeper.config.application_model.method(:by_uid_and_secret))
21
21
  return if credentials.blank?
22
+ return unless (application = method.call(credentials.uid, credentials.secret))
22
23
 
23
- if (application = method.call(credentials.uid, credentials.secret))
24
- new(application)
25
- end
24
+ new(application)
26
25
  end
27
26
  end
28
27
  end
@@ -2,13 +2,53 @@
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
5
- class ClientCredentialsRequest < BaseRequest
5
+ module ClientCredentials
6
6
  class Creator
7
7
  def call(client, scopes, attributes = {})
8
- AccessToken.find_or_create_for(
9
- client, nil, scopes, attributes[:expires_in],
10
- attributes[:use_refresh_token]
11
- )
8
+ existing_token = nil
9
+
10
+ if lookup_existing_token?
11
+ existing_token = find_existing_token_for(client, scopes)
12
+ return existing_token if server_config.reuse_access_token && existing_token&.reusable?
13
+ end
14
+
15
+ with_revocation(existing_token: existing_token) do
16
+ server_config.access_token_model.find_or_create_for(
17
+ application: client,
18
+ resource_owner: nil,
19
+ scopes: scopes,
20
+ **attributes,
21
+ )
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def with_revocation(existing_token:)
28
+ if existing_token && server_config.revoke_previous_client_credentials_token?
29
+ existing_token.with_lock do
30
+ raise Errors::DoorkeeperError, :invalid_token_reuse if existing_token.revoked?
31
+
32
+ existing_token.revoke
33
+
34
+ yield
35
+ end
36
+ else
37
+ yield
38
+ end
39
+ end
40
+
41
+ def lookup_existing_token?
42
+ server_config.reuse_access_token ||
43
+ server_config.revoke_previous_client_credentials_token?
44
+ end
45
+
46
+ def find_existing_token_for(client, scopes)
47
+ server_config.access_token_model.matching_token_for(client, nil, scopes)
48
+ end
49
+
50
+ def server_config
51
+ Doorkeeper.config
12
52
  end
13
53
  end
14
54
  end
@@ -2,23 +2,24 @@
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
5
- class ClientCredentialsRequest < BaseRequest
5
+ module ClientCredentials
6
6
  class Issuer
7
- attr_accessor :token, :validation, :error
7
+ attr_reader :token, :validator, :error
8
8
 
9
- def initialize(server, validation)
9
+ def initialize(server, validator)
10
10
  @server = server
11
- @validation = validation
11
+ @validator = validator
12
12
  end
13
13
 
14
14
  def create(client, scopes, creator = Creator.new)
15
- if validation.valid?
15
+ if validator.valid?
16
16
  @token = create_token(client, scopes, creator)
17
17
  @error = :server_error unless @token
18
18
  else
19
19
  @token = false
20
- @error = validation.error
20
+ @error = validator.error
21
21
  end
22
+
22
23
  @token
23
24
  end
24
25
 
@@ -28,7 +29,8 @@ module Doorkeeper
28
29
  context = Authorization::Token.build_context(
29
30
  client,
30
31
  Doorkeeper::OAuth::CLIENT_CREDENTIALS,
31
- scopes
32
+ scopes,
33
+ nil,
32
34
  )
33
35
  ttl = Authorization::Token.access_token_expires_in(@server, context)
34
36
 
@@ -36,7 +38,7 @@ module Doorkeeper
36
38
  client,
37
39
  scopes,
38
40
  use_refresh_token: false,
39
- expires_in: ttl
41
+ expires_in: ttl,
40
42
  )
41
43
  end
42
44
  end
@@ -2,12 +2,13 @@
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
5
- class ClientCredentialsRequest < BaseRequest
6
- class Validation
5
+ module ClientCredentials
6
+ class Validator
7
7
  include Validations
8
8
  include OAuth::Helpers
9
9
 
10
10
  validate :client, error: :invalid_client
11
+ validate :client_supports_grant_flow, error: :unauthorized_client
11
12
  validate :scopes, error: :invalid_scope
12
13
 
13
14
  def initialize(server, request)
@@ -24,6 +25,15 @@ module Doorkeeper
24
25
  @client.present?
25
26
  end
26
27
 
28
+ def validate_client_supports_grant_flow
29
+ return if @client.blank?
30
+
31
+ Doorkeeper.config.allow_grant_flow_for_client?(
32
+ Doorkeeper::OAuth::CLIENT_CREDENTIALS,
33
+ @client.application,
34
+ )
35
+ end
36
+
27
37
  def validate_scopes
28
38
  return true if @request.scopes.blank?
29
39
 
@@ -37,7 +47,7 @@ module Doorkeeper
37
47
  scope_str: @request.scopes.to_s,
38
48
  server_scopes: @server.scopes,
39
49
  app_scopes: application_scopes,
40
- grant_type: Doorkeeper::OAuth::CLIENT_CREDENTIALS
50
+ grant_type: Doorkeeper::OAuth::CLIENT_CREDENTIALS,
41
51
  )
42
52
  end
43
53
  end
@@ -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)
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