doorkeeper 5.2.2 → 5.5.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (260) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +198 -3
  3. data/README.md +28 -20
  4. data/app/controllers/doorkeeper/application_controller.rb +3 -2
  5. data/app/controllers/doorkeeper/application_metal_controller.rb +2 -2
  6. data/app/controllers/doorkeeper/applications_controller.rb +7 -8
  7. data/app/controllers/doorkeeper/authorizations_controller.rb +48 -18
  8. data/app/controllers/doorkeeper/authorized_applications_controller.rb +6 -6
  9. data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
  10. data/app/controllers/doorkeeper/tokens_controller.rb +70 -25
  11. data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
  12. data/app/views/doorkeeper/applications/_form.html.erb +1 -1
  13. data/app/views/doorkeeper/applications/show.html.erb +35 -14
  14. data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
  15. data/app/views/doorkeeper/authorizations/new.html.erb +2 -0
  16. data/config/locales/en.yml +9 -2
  17. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  18. data/lib/doorkeeper/config/option.rb +26 -14
  19. data/lib/doorkeeper/config/validations.rb +53 -0
  20. data/lib/doorkeeper/config.rb +214 -122
  21. data/lib/doorkeeper/engine.rb +1 -1
  22. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  23. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  24. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  25. data/lib/doorkeeper/grant_flow.rb +45 -0
  26. data/lib/doorkeeper/grape/helpers.rb +2 -2
  27. data/lib/doorkeeper/helpers/controller.rb +18 -12
  28. data/lib/doorkeeper/models/access_grant_mixin.rb +23 -19
  29. data/lib/doorkeeper/models/access_token_mixin.rb +157 -55
  30. data/lib/doorkeeper/models/application_mixin.rb +8 -7
  31. data/lib/doorkeeper/models/concerns/expirable.rb +1 -1
  32. data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
  33. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  34. data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
  35. data/lib/doorkeeper/models/concerns/revocable.rb +1 -28
  36. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  37. data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
  38. data/lib/doorkeeper/oauth/authorization/code.rb +22 -9
  39. data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
  40. data/lib/doorkeeper/oauth/authorization/token.rb +23 -18
  41. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
  42. data/lib/doorkeeper/oauth/authorization_code_request.rb +30 -20
  43. data/lib/doorkeeper/oauth/base_request.rb +19 -23
  44. data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
  45. data/lib/doorkeeper/oauth/client.rb +8 -9
  46. data/lib/doorkeeper/oauth/client_credentials/creator.rb +38 -12
  47. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +10 -8
  48. data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +7 -5
  49. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
  50. data/lib/doorkeeper/oauth/code_request.rb +4 -4
  51. data/lib/doorkeeper/oauth/code_response.rb +24 -14
  52. data/lib/doorkeeper/oauth/error.rb +1 -1
  53. data/lib/doorkeeper/oauth/error_response.rb +10 -11
  54. data/lib/doorkeeper/oauth/forbidden_token_response.rb +2 -1
  55. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +8 -12
  56. data/lib/doorkeeper/oauth/helpers/unique_token.rb +10 -7
  57. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +1 -19
  58. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  59. data/lib/doorkeeper/oauth/invalid_request_response.rb +3 -3
  60. data/lib/doorkeeper/oauth/invalid_token_response.rb +7 -4
  61. data/lib/doorkeeper/oauth/password_access_token_request.rb +28 -10
  62. data/lib/doorkeeper/oauth/pre_authorization.rb +73 -37
  63. data/lib/doorkeeper/oauth/refresh_token_request.rb +35 -26
  64. data/lib/doorkeeper/oauth/token.rb +6 -7
  65. data/lib/doorkeeper/oauth/token_introspection.rb +12 -16
  66. data/lib/doorkeeper/oauth/token_request.rb +3 -3
  67. data/lib/doorkeeper/oauth/token_response.rb +1 -1
  68. data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
  69. data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
  70. data/lib/doorkeeper/orm/active_record/application.rb +5 -95
  71. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +69 -0
  72. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +60 -0
  73. data/lib/doorkeeper/orm/active_record/mixins/application.rb +199 -0
  74. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +8 -3
  75. data/lib/doorkeeper/orm/active_record.rb +5 -7
  76. data/lib/doorkeeper/rails/helpers.rb +4 -4
  77. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  78. data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
  79. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  80. data/lib/doorkeeper/rails/routes.rb +17 -25
  81. data/lib/doorkeeper/rake/db.rake +6 -6
  82. data/lib/doorkeeper/rake/setup.rake +5 -0
  83. data/lib/doorkeeper/request/authorization_code.rb +3 -3
  84. data/lib/doorkeeper/request/client_credentials.rb +2 -2
  85. data/lib/doorkeeper/request/password.rb +3 -2
  86. data/lib/doorkeeper/request/refresh_token.rb +5 -4
  87. data/lib/doorkeeper/request/strategy.rb +2 -2
  88. data/lib/doorkeeper/request.rb +49 -12
  89. data/lib/doorkeeper/server.rb +5 -5
  90. data/lib/doorkeeper/stale_records_cleaner.rb +4 -4
  91. data/lib/doorkeeper/version.rb +2 -6
  92. data/lib/doorkeeper.rb +112 -81
  93. data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
  94. data/lib/generators/doorkeeper/confidential_applications_generator.rb +2 -2
  95. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  96. data/lib/generators/doorkeeper/migration_generator.rb +1 -1
  97. data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
  98. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +2 -2
  99. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +3 -1
  100. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
  101. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
  102. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  103. data/lib/generators/doorkeeper/templates/initializer.rb +99 -14
  104. data/lib/generators/doorkeeper/templates/migration.rb.erb +14 -5
  105. metadata +37 -306
  106. data/Appraisals +0 -40
  107. data/CODE_OF_CONDUCT.md +0 -46
  108. data/CONTRIBUTING.md +0 -49
  109. data/Dangerfile +0 -67
  110. data/Dockerfile +0 -29
  111. data/Gemfile +0 -25
  112. data/NEWS.md +0 -1
  113. data/RELEASING.md +0 -11
  114. data/Rakefile +0 -28
  115. data/SECURITY.md +0 -15
  116. data/UPGRADE.md +0 -2
  117. data/bin/console +0 -16
  118. data/doorkeeper.gemspec +0 -42
  119. data/gemfiles/rails_5_0.gemfile +0 -18
  120. data/gemfiles/rails_5_1.gemfile +0 -18
  121. data/gemfiles/rails_5_2.gemfile +0 -18
  122. data/gemfiles/rails_6_0.gemfile +0 -18
  123. data/gemfiles/rails_master.gemfile +0 -18
  124. data/spec/controllers/application_metal_controller_spec.rb +0 -64
  125. data/spec/controllers/applications_controller_spec.rb +0 -273
  126. data/spec/controllers/authorizations_controller_spec.rb +0 -608
  127. data/spec/controllers/protected_resources_controller_spec.rb +0 -353
  128. data/spec/controllers/token_info_controller_spec.rb +0 -50
  129. data/spec/controllers/tokens_controller_spec.rb +0 -498
  130. data/spec/dummy/Rakefile +0 -9
  131. data/spec/dummy/app/assets/config/manifest.js +0 -2
  132. data/spec/dummy/app/controllers/application_controller.rb +0 -5
  133. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
  134. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
  135. data/spec/dummy/app/controllers/home_controller.rb +0 -18
  136. data/spec/dummy/app/controllers/metal_controller.rb +0 -13
  137. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
  138. data/spec/dummy/app/helpers/application_helper.rb +0 -7
  139. data/spec/dummy/app/models/user.rb +0 -7
  140. data/spec/dummy/app/views/home/index.html.erb +0 -0
  141. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  142. data/spec/dummy/config/application.rb +0 -49
  143. data/spec/dummy/config/boot.rb +0 -7
  144. data/spec/dummy/config/database.yml +0 -15
  145. data/spec/dummy/config/environment.rb +0 -5
  146. data/spec/dummy/config/environments/development.rb +0 -31
  147. data/spec/dummy/config/environments/production.rb +0 -64
  148. data/spec/dummy/config/environments/test.rb +0 -45
  149. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
  150. data/spec/dummy/config/initializers/doorkeeper.rb +0 -166
  151. data/spec/dummy/config/initializers/secret_token.rb +0 -10
  152. data/spec/dummy/config/initializers/session_store.rb +0 -10
  153. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
  154. data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
  155. data/spec/dummy/config/routes.rb +0 -13
  156. data/spec/dummy/config.ru +0 -6
  157. data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
  158. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
  159. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
  160. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
  161. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
  162. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
  163. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
  164. data/spec/dummy/db/schema.rb +0 -68
  165. data/spec/dummy/public/404.html +0 -26
  166. data/spec/dummy/public/422.html +0 -26
  167. data/spec/dummy/public/500.html +0 -26
  168. data/spec/dummy/public/favicon.ico +0 -0
  169. data/spec/dummy/script/rails +0 -9
  170. data/spec/factories.rb +0 -30
  171. data/spec/generators/application_owner_generator_spec.rb +0 -28
  172. data/spec/generators/confidential_applications_generator_spec.rb +0 -29
  173. data/spec/generators/install_generator_spec.rb +0 -36
  174. data/spec/generators/migration_generator_spec.rb +0 -28
  175. data/spec/generators/pkce_generator_spec.rb +0 -28
  176. data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
  177. data/spec/generators/templates/routes.rb +0 -4
  178. data/spec/generators/views_generator_spec.rb +0 -29
  179. data/spec/grape/grape_integration_spec.rb +0 -137
  180. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
  181. data/spec/lib/config_spec.rb +0 -739
  182. data/spec/lib/doorkeeper_spec.rb +0 -27
  183. data/spec/lib/models/expirable_spec.rb +0 -61
  184. data/spec/lib/models/reusable_spec.rb +0 -40
  185. data/spec/lib/models/revocable_spec.rb +0 -59
  186. data/spec/lib/models/scopes_spec.rb +0 -53
  187. data/spec/lib/models/secret_storable_spec.rb +0 -135
  188. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
  189. data/spec/lib/oauth/authorization_code_request_spec.rb +0 -168
  190. data/spec/lib/oauth/base_request_spec.rb +0 -222
  191. data/spec/lib/oauth/base_response_spec.rb +0 -47
  192. data/spec/lib/oauth/client/credentials_spec.rb +0 -90
  193. data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -97
  194. data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
  195. data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
  196. data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -29
  197. data/spec/lib/oauth/client_credentials_request_spec.rb +0 -109
  198. data/spec/lib/oauth/client_spec.rb +0 -38
  199. data/spec/lib/oauth/code_request_spec.rb +0 -46
  200. data/spec/lib/oauth/code_response_spec.rb +0 -36
  201. data/spec/lib/oauth/error_response_spec.rb +0 -66
  202. data/spec/lib/oauth/error_spec.rb +0 -23
  203. data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -22
  204. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -98
  205. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
  206. data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -262
  207. data/spec/lib/oauth/invalid_request_response_spec.rb +0 -75
  208. data/spec/lib/oauth/invalid_token_response_spec.rb +0 -55
  209. data/spec/lib/oauth/password_access_token_request_spec.rb +0 -192
  210. data/spec/lib/oauth/pre_authorization_spec.rb +0 -225
  211. data/spec/lib/oauth/refresh_token_request_spec.rb +0 -178
  212. data/spec/lib/oauth/scopes_spec.rb +0 -148
  213. data/spec/lib/oauth/token_request_spec.rb +0 -153
  214. data/spec/lib/oauth/token_response_spec.rb +0 -86
  215. data/spec/lib/oauth/token_spec.rb +0 -158
  216. data/spec/lib/request/strategy_spec.rb +0 -54
  217. data/spec/lib/secret_storing/base_spec.rb +0 -60
  218. data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
  219. data/spec/lib/secret_storing/plain_spec.rb +0 -44
  220. data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
  221. data/spec/lib/server_spec.rb +0 -49
  222. data/spec/lib/stale_records_cleaner_spec.rb +0 -89
  223. data/spec/models/doorkeeper/access_grant_spec.rb +0 -163
  224. data/spec/models/doorkeeper/access_token_spec.rb +0 -622
  225. data/spec/models/doorkeeper/application_spec.rb +0 -377
  226. data/spec/requests/applications/applications_request_spec.rb +0 -259
  227. data/spec/requests/applications/authorized_applications_spec.rb +0 -32
  228. data/spec/requests/endpoints/authorization_spec.rb +0 -89
  229. data/spec/requests/endpoints/token_spec.rb +0 -75
  230. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -79
  231. data/spec/requests/flows/authorization_code_spec.rb +0 -513
  232. data/spec/requests/flows/client_credentials_spec.rb +0 -166
  233. data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -46
  234. data/spec/requests/flows/implicit_grant_spec.rb +0 -91
  235. data/spec/requests/flows/password_spec.rb +0 -296
  236. data/spec/requests/flows/refresh_token_spec.rb +0 -233
  237. data/spec/requests/flows/revoke_token_spec.rb +0 -151
  238. data/spec/requests/flows/skip_authorization_spec.rb +0 -66
  239. data/spec/requests/protected_resources/metal_spec.rb +0 -16
  240. data/spec/requests/protected_resources/private_api_spec.rb +0 -83
  241. data/spec/routing/custom_controller_routes_spec.rb +0 -133
  242. data/spec/routing/default_routes_spec.rb +0 -41
  243. data/spec/routing/scoped_routes_spec.rb +0 -47
  244. data/spec/spec_helper.rb +0 -57
  245. data/spec/spec_helper_integration.rb +0 -4
  246. data/spec/support/dependencies/factory_bot.rb +0 -4
  247. data/spec/support/doorkeeper_rspec.rb +0 -22
  248. data/spec/support/helpers/access_token_request_helper.rb +0 -13
  249. data/spec/support/helpers/authorization_request_helper.rb +0 -43
  250. data/spec/support/helpers/config_helper.rb +0 -11
  251. data/spec/support/helpers/model_helper.rb +0 -78
  252. data/spec/support/helpers/request_spec_helper.rb +0 -110
  253. data/spec/support/helpers/url_helper.rb +0 -62
  254. data/spec/support/http_method_shim.rb +0 -29
  255. data/spec/support/orm/active_record.rb +0 -5
  256. data/spec/support/shared/controllers_shared_context.rb +0 -123
  257. data/spec/support/shared/hashing_shared_context.rb +0 -36
  258. data/spec/support/shared/models_shared_examples.rb +0 -54
  259. data/spec/validators/redirect_uri_validator_spec.rb +0 -183
  260. data/spec/version/version_spec.rb +0 -17
@@ -16,18 +16,20 @@ module Doorkeeper
16
16
 
17
17
  # :doc:
18
18
  def current_resource_owner
19
+ return @current_resource_owner if defined?(@current_resource_owner)
20
+
19
21
  @current_resource_owner ||= begin
20
- instance_eval(&Doorkeeper.configuration.authenticate_resource_owner)
22
+ instance_eval(&Doorkeeper.config.authenticate_resource_owner)
21
23
  end
22
24
  end
23
25
 
24
26
  def resource_owner_from_credentials
25
- instance_eval(&Doorkeeper.configuration.resource_owner_from_credentials)
27
+ instance_eval(&Doorkeeper.config.resource_owner_from_credentials)
26
28
  end
27
29
 
28
30
  # :doc:
29
31
  def authenticate_admin!
30
- instance_eval(&Doorkeeper.configuration.authenticate_admin)
32
+ instance_eval(&Doorkeeper.config.authenticate_admin)
31
33
  end
32
34
 
33
35
  def server
@@ -36,36 +38,40 @@ module Doorkeeper
36
38
 
37
39
  # :doc:
38
40
  def doorkeeper_token
39
- @doorkeeper_token ||= OAuth::Token.authenticate request, *config_methods
41
+ return @doorkeeper_token if defined?(@doorkeeper_token)
42
+
43
+ @doorkeeper_token ||= OAuth::Token.authenticate(request, *config_methods)
40
44
  end
41
45
 
42
46
  def config_methods
43
- @config_methods ||= Doorkeeper.configuration.access_token_methods
47
+ @config_methods ||= Doorkeeper.config.access_token_methods
44
48
  end
45
49
 
46
50
  def get_error_response_from_exception(exception)
47
51
  if exception.respond_to?(:response)
48
52
  exception.response
49
53
  elsif exception.type == :invalid_request
50
- OAuth::InvalidRequestResponse.new(name: exception.type,
51
- state: params[:state],
52
- missing_param: exception.missing_param)
54
+ OAuth::InvalidRequestResponse.new(
55
+ name: exception.type,
56
+ state: params[:state],
57
+ missing_param: exception.missing_param,
58
+ )
53
59
  else
54
60
  OAuth::ErrorResponse.new(name: exception.type, state: params[:state])
55
61
  end
56
62
  end
57
63
 
58
64
  def handle_token_exception(exception)
59
- error = get_error_response_from_exception exception
60
- headers.merge! error.headers
65
+ error = get_error_response_from_exception(exception)
66
+ headers.merge!(error.headers)
61
67
  self.response_body = error.body.to_json
62
- self.status = error.status
68
+ self.status = error.status
63
69
  end
64
70
 
65
71
  def skip_authorization?
66
72
  !!instance_exec(
67
73
  [server.current_resource_owner, @pre_auth.client],
68
- &Doorkeeper.configuration.skip_authorization
74
+ &Doorkeeper.config.skip_authorization
69
75
  )
70
76
  end
71
77
 
@@ -11,14 +11,11 @@ module Doorkeeper
11
11
  include Models::Orderable
12
12
  include Models::SecretStorable
13
13
  include Models::Scopes
14
+ include Models::ResourceOwnerable
14
15
 
15
- # never uses pkce, if pkce migrations were not generated
16
+ # Never uses PKCE if PKCE migrations were not generated
16
17
  def uses_pkce?
17
- pkce_supported? && code_challenge.present?
18
- end
19
-
20
- def pkce_supported?
21
- respond_to? :code_challenge
18
+ self.class.pkce_supported? && code_challenge.present?
22
19
  end
23
20
 
24
21
  module ClassMethods
@@ -27,8 +24,8 @@ module Doorkeeper
27
24
  #
28
25
  # @param token [#to_s] token value (any object that responds to `#to_s`)
29
26
  #
30
- # @return [Doorkeeper::AccessGrant, nil] AccessGrant object or nil
31
- # if there is no record with such token
27
+ # @return [Doorkeeper::AccessGrant, nil]
28
+ # AccessGrant object or nil if there is no record with such token
32
29
  #
33
30
  def by_token(token)
34
31
  find_by_plaintext_token(:token, token)
@@ -39,18 +36,20 @@ module Doorkeeper
39
36
  #
40
37
  # @param application_id [Integer]
41
38
  # ID of the Application
42
- # @param resource_owner [ActiveRecord::Base]
43
- # instance of the Resource Owner model
39
+ # @param resource_owner [ActiveRecord::Base, Integer]
40
+ # instance of the Resource Owner model or it's ID
44
41
  #
45
42
  def revoke_all_for(application_id, resource_owner, clock = Time)
46
- where(application_id: application_id,
47
- resource_owner_id: resource_owner.id,
48
- revoked_at: nil)
43
+ by_resource_owner(resource_owner)
44
+ .where(
45
+ application_id: application_id,
46
+ revoked_at: nil,
47
+ )
49
48
  .update_all(revoked_at: clock.now.utc)
50
49
  end
51
50
 
52
51
  # Implements PKCE code_challenge encoding without base64 padding as described in the spec.
53
- # https://tools.ietf.org/html/rfc7636#appendix-A
52
+ # https://datatracker.ietf.org/doc/html/rfc7636#appendix-A
54
53
  # Appendix A. Notes on Implementing Base64url Encoding without Padding
55
54
  #
56
55
  # This appendix describes how to implement a base64url-encoding
@@ -90,26 +89,31 @@ module Doorkeeper
90
89
  # suitable for PKCE validation
91
90
  #
92
91
  def generate_code_challenge(code_verifier)
93
- padded_result = Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier))
94
- padded_result.split("=")[0] # Remove any trailing '='
92
+ Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier), padding: false)
95
93
  end
96
94
 
97
95
  def pkce_supported?
98
- new.pkce_supported?
96
+ column_names.include?("code_challenge")
99
97
  end
100
98
 
101
99
  ##
102
100
  # Determines the secret storing transformer
103
101
  # Unless configured otherwise, uses the plain secret strategy
102
+ #
103
+ # @return [Doorkeeper::SecretStoring::Base]
104
+ #
104
105
  def secret_strategy
105
- ::Doorkeeper.configuration.token_secret_strategy
106
+ ::Doorkeeper.config.token_secret_strategy
106
107
  end
107
108
 
108
109
  ##
109
110
  # Determine the fallback storing strategy
110
111
  # Unless configured, there will be no fallback
112
+ #
113
+ # @return [Doorkeeper::SecretStoring::Base]
114
+ #
111
115
  def fallback_secret_strategy
112
- ::Doorkeeper.configuration.token_secret_fallback_strategy
116
+ ::Doorkeeper.config.token_secret_fallback_strategy
113
117
  end
114
118
  end
115
119
  end
@@ -12,6 +12,7 @@ module Doorkeeper
12
12
  include Models::Orderable
13
13
  include Models::SecretStorable
14
14
  include Models::Scopes
15
+ include Models::ResourceOwnerable
15
16
 
16
17
  module ClassMethods
17
18
  # Returns an instance of the Doorkeeper::AccessToken with
@@ -40,18 +41,35 @@ module Doorkeeper
40
41
  find_by_plaintext_token(:refresh_token, refresh_token)
41
42
  end
42
43
 
44
+ # Returns an instance of the Doorkeeper::AccessToken
45
+ # found by previous refresh token. Keep in mind that value
46
+ # of the previous_refresh_token isn't encrypted using
47
+ # secrets strategy.
48
+ #
49
+ # @param previous_refresh_token [#to_s]
50
+ # previous refresh token value (any object that responds to `#to_s`)
51
+ #
52
+ # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
53
+ # if there is no record with such refresh token
54
+ #
55
+ def by_previous_refresh_token(previous_refresh_token)
56
+ find_by(refresh_token: previous_refresh_token)
57
+ end
58
+
43
59
  # Revokes AccessToken records that have not been revoked and associated
44
60
  # with the specific Application and Resource Owner.
45
61
  #
46
62
  # @param application_id [Integer]
47
63
  # ID of the Application
48
- # @param resource_owner [ActiveRecord::Base]
49
- # instance of the Resource Owner model
64
+ # @param resource_owner [ActiveRecord::Base, Integer]
65
+ # instance of the Resource Owner model or it's ID
50
66
  #
51
67
  def revoke_all_for(application_id, resource_owner, clock = Time)
52
- where(application_id: application_id,
53
- resource_owner_id: resource_owner.id,
54
- revoked_at: nil)
68
+ by_resource_owner(resource_owner)
69
+ .where(
70
+ application_id: application_id,
71
+ revoked_at: nil,
72
+ )
55
73
  .update_all(revoked_at: clock.now.utc)
56
74
  end
57
75
 
@@ -60,7 +78,7 @@ module Doorkeeper
60
78
  #
61
79
  # @param application [Doorkeeper::Application]
62
80
  # Application instance
63
- # @param resource_owner_or_id [ActiveRecord::Base, Integer]
81
+ # @param resource_owner [ActiveRecord::Base, Integer]
64
82
  # Resource Owner model instance or it's ID
65
83
  # @param scopes [String, Doorkeeper::OAuth::Scopes]
66
84
  # set of scopes
@@ -68,22 +86,16 @@ module Doorkeeper
68
86
  # @return [Doorkeeper::AccessToken, nil] Access Token instance or
69
87
  # nil if matching record was not found
70
88
  #
71
- def matching_token_for(application, resource_owner_or_id, scopes)
72
- resource_owner_id = if resource_owner_or_id.respond_to?(:to_key)
73
- resource_owner_or_id.id
74
- else
75
- resource_owner_or_id
76
- end
77
-
78
- tokens = authorized_tokens_for(application.try(:id), resource_owner_id)
89
+ def matching_token_for(application, resource_owner, scopes)
90
+ tokens = authorized_tokens_for(application&.id, resource_owner)
79
91
  find_matching_token(tokens, application, scopes)
80
92
  end
81
93
 
82
94
  # Interface to enumerate access token records in batches in order not
83
95
  # to bloat the memory. Could be overloaded in any ORM extension.
84
96
  #
85
- def find_access_token_in_batches(relation, *args, &block)
86
- relation.find_in_batches(*args, &block)
97
+ def find_access_token_in_batches(relation, **args, &block)
98
+ relation.find_in_batches(**args, &block)
87
99
  end
88
100
 
89
101
  # Enumerates AccessToken records in batches to find a matching token.
@@ -110,10 +122,11 @@ module Doorkeeper
110
122
  return nil unless relation
111
123
 
112
124
  matching_tokens = []
125
+ batch_size = Doorkeeper.configuration.token_lookup_batch_size
113
126
 
114
- find_access_token_in_batches(relation) do |batch|
127
+ find_access_token_in_batches(relation, batch_size: batch_size) do |batch|
115
128
  tokens = batch.select do |token|
116
- scopes_match?(token.scopes, scopes, application.try(:scopes))
129
+ scopes_match?(token.scopes, scopes, application&.scopes)
117
130
  end
118
131
 
119
132
  matching_tokens.concat(tokens)
@@ -142,8 +155,8 @@ module Doorkeeper
142
155
  (token_scopes.sort == param_scopes.sort) &&
143
156
  Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
144
157
  scope_str: param_scopes.to_s,
145
- server_scopes: Doorkeeper.configuration.scopes,
146
- app_scopes: app_scopes
158
+ server_scopes: Doorkeeper.config.scopes,
159
+ app_scopes: app_scopes,
147
160
  )
148
161
  end
149
162
 
@@ -153,48 +166,81 @@ module Doorkeeper
153
166
  #
154
167
  # @param application [Doorkeeper::Application]
155
168
  # Application instance
156
- # @param resource_owner_id [ActiveRecord::Base, Integer]
169
+ # @param resource_owner [ActiveRecord::Base, Integer]
157
170
  # Resource Owner model instance or it's ID
158
171
  # @param scopes [#to_s]
159
172
  # set of scopes (any object that responds to `#to_s`)
160
- # @param expires_in [Integer]
173
+ # @param token_attributes [Hash]
174
+ # Additional attributes to use when creating a token
175
+ # @option token_attributes [Integer] :expires_in
161
176
  # token lifetime in seconds
162
- # @param use_refresh_token [Boolean]
177
+ # @option token_attributes [Boolean] :use_refresh_token
163
178
  # whether to use the refresh token
164
179
  #
165
180
  # @return [Doorkeeper::AccessToken] existing record or a new one
166
181
  #
167
- def find_or_create_for(application, resource_owner_id, scopes, expires_in, use_refresh_token)
168
- if Doorkeeper.configuration.reuse_access_token
169
- access_token = matching_token_for(application, resource_owner_id, scopes)
182
+ def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
183
+ if Doorkeeper.config.reuse_access_token
184
+ access_token = matching_token_for(application, resource_owner, scopes)
170
185
 
171
186
  return access_token if access_token&.reusable?
172
187
  end
173
188
 
174
- create!(
175
- application_id: application.try(:id),
176
- resource_owner_id: resource_owner_id,
177
- scopes: scopes.to_s,
178
- expires_in: expires_in,
179
- use_refresh_token: use_refresh_token
189
+ create_for(
190
+ application: application,
191
+ resource_owner: resource_owner,
192
+ scopes: scopes,
193
+ **token_attributes,
180
194
  )
181
195
  end
182
196
 
197
+ # Creates a not expired AccessToken record with a matching set of
198
+ # scopes that belongs to specific Application and Resource Owner.
199
+ #
200
+ # @param application [Doorkeeper::Application]
201
+ # Application instance
202
+ # @param resource_owner [ActiveRecord::Base, Integer]
203
+ # Resource Owner model instance or it's ID
204
+ # @param scopes [#to_s]
205
+ # set of scopes (any object that responds to `#to_s`)
206
+ # @param token_attributes [Hash]
207
+ # Additional attributes to use when creating a token
208
+ # @option token_attributes [Integer] :expires_in
209
+ # token lifetime in seconds
210
+ # @option token_attributes [Boolean] :use_refresh_token
211
+ # whether to use the refresh token
212
+ #
213
+ # @return [Doorkeeper::AccessToken] new access token
214
+ #
215
+ def create_for(application:, resource_owner:, scopes:, **token_attributes)
216
+ token_attributes[:application_id] = application&.id
217
+ token_attributes[:scopes] = scopes.to_s
218
+
219
+ if Doorkeeper.config.polymorphic_resource_owner?
220
+ token_attributes[:resource_owner] = resource_owner
221
+ else
222
+ token_attributes[:resource_owner_id] = resource_owner_id_for(resource_owner)
223
+ end
224
+
225
+ create!(token_attributes)
226
+ end
227
+
183
228
  # Looking for not revoked Access Token records that belongs to specific
184
229
  # Application and Resource Owner.
185
230
  #
186
231
  # @param application_id [Integer]
187
232
  # ID of the Application model instance
188
- # @param resource_owner_id [Integer]
189
- # ID of the Resource Owner model instance
233
+ # @param resource_owner [ActiveRecord::Base, Integer]
234
+ # Resource Owner model instance or it's ID
190
235
  #
191
- # @return [Doorkeeper::AccessToken] array of matching AccessToken objects
236
+ # @return [ActiveRecord::Relation]
237
+ # collection of matching AccessToken objects
192
238
  #
193
- def authorized_tokens_for(application_id, resource_owner_id)
194
- ordered_by(:created_at, :desc)
195
- .where(application_id: application_id,
196
- resource_owner_id: resource_owner_id,
197
- revoked_at: nil)
239
+ def authorized_tokens_for(application_id, resource_owner)
240
+ by_resource_owner(resource_owner).where(
241
+ application_id: application_id,
242
+ revoked_at: nil,
243
+ )
198
244
  end
199
245
 
200
246
  # Convenience method for backwards-compatibility, return the last
@@ -202,33 +248,38 @@ module Doorkeeper
202
248
  #
203
249
  # @param application_id [Integer]
204
250
  # ID of the Application model instance
205
- # @param resource_owner_id [Integer]
251
+ # @param resource_owner [ActiveRecord::Base, Integer]
206
252
  # ID of the Resource Owner model instance
207
253
  #
208
254
  # @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
209
255
  # nil if nothing was found
210
256
  #
211
- def last_authorized_token_for(application_id, resource_owner_id)
212
- authorized_tokens_for(application_id, resource_owner_id).first
257
+ def last_authorized_token_for(application_id, resource_owner)
258
+ authorized_tokens_for(application_id, resource_owner)
259
+ .ordered_by(:created_at, :desc)
260
+ .first
213
261
  end
214
262
 
215
263
  ##
216
264
  # Determines the secret storing transformer
217
265
  # Unless configured otherwise, uses the plain secret strategy
266
+ #
267
+ # @return [Doorkeeper::SecretStoring::Base]
268
+ #
218
269
  def secret_strategy
219
- ::Doorkeeper.configuration.token_secret_strategy
270
+ ::Doorkeeper.config.token_secret_strategy
220
271
  end
221
272
 
222
273
  ##
223
274
  # Determine the fallback storing strategy
224
275
  # Unless configured, there will be no fallback
225
276
  def fallback_secret_strategy
226
- ::Doorkeeper.configuration.token_secret_fallback_strategy
277
+ ::Doorkeeper.config.token_secret_fallback_strategy
227
278
  end
228
279
  end
229
280
 
230
281
  # Access Token type: Bearer.
231
- # @see https://tools.ietf.org/html/rfc6750
282
+ # @see https://datatracker.ietf.org/doc/html/rfc6750
232
283
  # The OAuth 2.0 Authorization Framework: Bearer Token Usage
233
284
  #
234
285
  def token_type
@@ -250,7 +301,11 @@ module Doorkeeper
250
301
  expires_in: expires_in_seconds,
251
302
  application: { uid: application.try(:uid) },
252
303
  created_at: created_at.to_i,
253
- }
304
+ }.tap do |json|
305
+ if Doorkeeper.configuration.polymorphic_resource_owner?
306
+ json[:resource_owner_type] = resource_owner_type
307
+ end
308
+ end
254
309
  end
255
310
 
256
311
  # Indicates whether the token instance have the same credential
@@ -262,7 +317,22 @@ module Doorkeeper
262
317
  #
263
318
  def same_credential?(access_token)
264
319
  application_id == access_token.application_id &&
320
+ same_resource_owner?(access_token)
321
+ end
322
+
323
+ # Indicates whether the token instance have the same credential
324
+ # as the other Access Token.
325
+ #
326
+ # @param access_token [Doorkeeper::AccessToken] other token
327
+ #
328
+ # @return [Boolean] true if credentials are same of false in other cases
329
+ #
330
+ def same_resource_owner?(access_token)
331
+ if Doorkeeper.configuration.polymorphic_resource_owner?
332
+ resource_owner == access_token.resource_owner
333
+ else
265
334
  resource_owner_id == access_token.resource_owner_id
335
+ end
266
336
  end
267
337
 
268
338
  # Indicates if token is acceptable for specific scopes.
@@ -300,8 +370,28 @@ module Doorkeeper
300
370
  end
301
371
  end
302
372
 
373
+ # Revokes token with `:refresh_token` equal to `:previous_refresh_token`
374
+ # and clears `:previous_refresh_token` attribute.
375
+ #
376
+ def revoke_previous_refresh_token!
377
+ return if !self.class.refresh_token_revoked_on_use? || previous_refresh_token.blank?
378
+
379
+ old_refresh_token&.revoke
380
+ update_attribute(:previous_refresh_token, "")
381
+ end
382
+
303
383
  private
304
384
 
385
+ # Searches for Access Token record with `:refresh_token` equal to
386
+ # `:previous_refresh_token` value.
387
+ #
388
+ # @return [Doorkeeper::AccessToken, nil]
389
+ # Access Token record or nil if nothing found
390
+ #
391
+ def old_refresh_token
392
+ @old_refresh_token ||= self.class.by_previous_refresh_token(previous_refresh_token)
393
+ end
394
+
305
395
  # Generates refresh token with UniqueToken generator.
306
396
  #
307
397
  # @return [String] refresh token value
@@ -312,7 +402,7 @@ module Doorkeeper
312
402
  end
313
403
 
314
404
  # Generates and sets the token value with the
315
- # configured Generator class (see Doorkeeper.configuration).
405
+ # configured Generator class (see Doorkeeper.config).
316
406
  #
317
407
  # @return [String] generated token value
318
408
  #
@@ -324,20 +414,32 @@ module Doorkeeper
324
414
  def generate_token
325
415
  self.created_at ||= Time.now.utc
326
416
 
327
- @raw_token = token_generator.generate(
417
+ @raw_token = token_generator.generate(attributes_for_token_generator)
418
+ secret_strategy.store_secret(self, :token, @raw_token)
419
+ @raw_token
420
+ end
421
+
422
+ # Set of attributes that would be passed to token generator to
423
+ # generate unique token based on them.
424
+ #
425
+ # @return [Hash] set of attributes
426
+ #
427
+ def attributes_for_token_generator
428
+ {
328
429
  resource_owner_id: resource_owner_id,
329
430
  scopes: scopes,
330
431
  application: application,
331
432
  expires_in: expires_in,
332
- created_at: created_at
333
- )
334
-
335
- secret_strategy.store_secret(self, :token, @raw_token)
336
- @raw_token
433
+ created_at: created_at,
434
+ }.tap do |attributes|
435
+ if Doorkeeper.config.polymorphic_resource_owner?
436
+ attributes[:resource_owner] = resource_owner
437
+ end
438
+ end
337
439
  end
338
440
 
339
441
  def token_generator
340
- generator_name = Doorkeeper.configuration.access_token_generator
442
+ generator_name = Doorkeeper.config.access_token_generator
341
443
  generator = generator_name.constantize
342
444
 
343
445
  return generator if generator.respond_to?(:generate)
@@ -20,8 +20,8 @@ module Doorkeeper
20
20
  # @param uid [#to_s] UID (any object that responds to `#to_s`)
21
21
  # @param secret [#to_s] secret (any object that responds to `#to_s`)
22
22
  #
23
- # @return [Doorkeeper::Application, nil] Application instance or nil
24
- # if there is no record with such credentials
23
+ # @return [Doorkeeper::Application, nil]
24
+ # Application instance or nil if there is no record with such credentials
25
25
  #
26
26
  def by_uid_and_secret(uid, secret)
27
27
  app = by_uid(uid)
@@ -47,22 +47,23 @@ module Doorkeeper
47
47
  # Determines the secret storing transformer
48
48
  # Unless configured otherwise, uses the plain secret strategy
49
49
  def secret_strategy
50
- ::Doorkeeper.configuration.application_secret_strategy
50
+ ::Doorkeeper.config.application_secret_strategy
51
51
  end
52
52
 
53
53
  ##
54
54
  # Determine the fallback storing strategy
55
55
  # Unless configured, there will be no fallback
56
56
  def fallback_secret_strategy
57
- ::Doorkeeper.configuration.application_secret_fallback_strategy
57
+ ::Doorkeeper.config.application_secret_fallback_strategy
58
58
  end
59
59
  end
60
60
 
61
61
  # Set an application's valid redirect URIs.
62
62
  #
63
- # @param uris [String, Array] Newline-separated string or array the URI(s)
63
+ # @param uris [String, Array<String>] Newline-separated string or array the URI(s)
64
+ #
65
+ # @return [String] The redirect URI(s) separated by newlines.
64
66
  #
65
- # @return [String] The redirect URI(s) seperated by newlines.
66
67
  def redirect_uri=(uris)
67
68
  super(uris.is_a?(Array) ? uris.join("\n") : uris)
68
69
  end
@@ -72,7 +73,7 @@ module Doorkeeper
72
73
  # @param input [#to_s] Plain secret provided by user
73
74
  # (any object that responds to `#to_s`)
74
75
  #
75
- # @return [true] Whether the given secret matches the stored secret
76
+ # @return [Boolean] Whether the given secret matches the stored secret
76
77
  # of this application.
77
78
  #
78
79
  def secret_matches?(input)
@@ -8,7 +8,7 @@ module Doorkeeper
8
8
  #
9
9
  # @return [Boolean] true if object expired and false in other case
10
10
  def expired?
11
- expires_in && Time.now.utc > expires_at
11
+ !!(expires_in && Time.now.utc > expires_at)
12
12
  end
13
13
 
14
14
  # Calculates expiration time in seconds.
@@ -11,7 +11,7 @@ module Doorkeeper
11
11
  end
12
12
 
13
13
  def validate_owner?
14
- Doorkeeper.configuration.confirm_application_owner?
14
+ Doorkeeper.config.confirm_application_owner?
15
15
  end
16
16
  end
17
17
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doorkeeper
4
+ module Models
5
+ module ResourceOwnerable
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # Searches for record by Resource Owner considering Doorkeeper
10
+ # configuration for resource owner association.
11
+ #
12
+ # @param resource_owner [ActiveRecord::Base, Integer]
13
+ # resource owner
14
+ #
15
+ # @return [Doorkeeper::AccessGrant, Doorkeeper::AccessToken]
16
+ # collection of records
17
+ #
18
+ def by_resource_owner(resource_owner)
19
+ if Doorkeeper.configuration.polymorphic_resource_owner?
20
+ where(resource_owner: resource_owner)
21
+ else
22
+ where(resource_owner_id: resource_owner_id_for(resource_owner))
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ # Backward compatible way to retrieve resource owner itself (if
29
+ # polymorphic association enabled) or just it's ID.
30
+ #
31
+ # @param resource_owner [ActiveRecord::Base, Integer]
32
+ # resource owner
33
+ #
34
+ # @return [ActiveRecord::Base, Integer]
35
+ # instance of Resource Owner or it's ID
36
+ #
37
+ def resource_owner_id_for(resource_owner)
38
+ if resource_owner.respond_to?(:to_key)
39
+ resource_owner.id
40
+ else
41
+ resource_owner
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -11,7 +11,7 @@ module Doorkeeper
11
11
  return false if expired?
12
12
  return true unless expires_in
13
13
 
14
- threshold_limit = 100 - Doorkeeper.configuration.token_reuse_limit
14
+ threshold_limit = 100 - Doorkeeper.config.token_reuse_limit
15
15
  expires_in_seconds >= threshold_limit * expires_in / 100
16
16
  end
17
17
  end