doorkeeper 5.1.0.rc1 → 5.1.0.rc2

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +11 -2
  3. data/Appraisals +29 -3
  4. data/Gemfile +13 -5
  5. data/NEWS.md +52 -15
  6. data/README.md +68 -487
  7. data/app/controllers/doorkeeper/token_info_controller.rb +1 -1
  8. data/app/controllers/doorkeeper/tokens_controller.rb +1 -1
  9. data/doorkeeper.gemspec +3 -2
  10. data/gemfiles/rails_4_2.gemfile +8 -5
  11. data/gemfiles/rails_5_0.gemfile +9 -6
  12. data/gemfiles/rails_5_1.gemfile +9 -6
  13. data/gemfiles/rails_5_2.gemfile +9 -6
  14. data/gemfiles/rails_6_0.gemfile +16 -0
  15. data/gemfiles/rails_master.gemfile +8 -10
  16. data/lib/doorkeeper.rb +7 -1
  17. data/lib/doorkeeper/config.rb +110 -24
  18. data/lib/doorkeeper/models/access_grant_mixin.rb +15 -7
  19. data/lib/doorkeeper/models/access_token_mixin.rb +29 -16
  20. data/lib/doorkeeper/models/application_mixin.rb +18 -28
  21. data/lib/doorkeeper/models/concerns/expirable.rb +3 -2
  22. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  23. data/lib/doorkeeper/models/concerns/scopes.rb +4 -0
  24. data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
  25. data/lib/doorkeeper/oauth/authorization/token.rb +3 -1
  26. data/lib/doorkeeper/oauth/error_response.rb +5 -1
  27. data/lib/doorkeeper/oauth/helpers/unique_token.rb +12 -1
  28. data/lib/doorkeeper/oauth/invalid_token_response.rb +4 -0
  29. data/lib/doorkeeper/oauth/token_introspection.rb +72 -6
  30. data/lib/doorkeeper/orm/active_record/access_grant.rb +9 -8
  31. data/lib/doorkeeper/orm/active_record/application.rb +10 -6
  32. data/lib/doorkeeper/secret_storing/base.rb +63 -0
  33. data/lib/doorkeeper/secret_storing/bcrypt.rb +59 -0
  34. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  35. data/lib/doorkeeper/secret_storing/sha256_hash.rb +25 -0
  36. data/lib/doorkeeper/version.rb +1 -1
  37. data/lib/generators/doorkeeper/templates/initializer.rb +62 -20
  38. data/spec/controllers/authorizations_controller_spec.rb +3 -3
  39. data/spec/controllers/token_info_controller_spec.rb +1 -1
  40. data/spec/controllers/tokens_controller_spec.rb +78 -30
  41. data/spec/dummy/config/application.rb +12 -1
  42. data/spec/lib/config_spec.rb +119 -35
  43. data/spec/lib/models/expirable_spec.rb +12 -0
  44. data/spec/lib/models/reusable_spec.rb +40 -0
  45. data/spec/lib/models/scopes_spec.rb +13 -1
  46. data/spec/lib/models/secret_storable_spec.rb +113 -0
  47. data/spec/lib/oauth/authorization_code_request_spec.rb +18 -1
  48. data/spec/lib/oauth/client_credentials/creator_spec.rb +51 -7
  49. data/spec/lib/oauth/error_response_spec.rb +7 -1
  50. data/spec/lib/oauth/password_access_token_request_spec.rb +11 -1
  51. data/spec/lib/oauth/token_request_spec.rb +16 -1
  52. data/spec/lib/secret_storing/base_spec.rb +60 -0
  53. data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
  54. data/spec/lib/secret_storing/plain_spec.rb +44 -0
  55. data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
  56. data/spec/models/doorkeeper/application_spec.rb +23 -4
  57. data/spec/requests/flows/authorization_code_spec.rb +3 -3
  58. data/spec/requests/flows/client_credentials_spec.rb +2 -2
  59. data/spec/requests/flows/implicit_grant_spec.rb +1 -1
  60. data/spec/requests/flows/password_spec.rb +3 -3
  61. data/spec/routing/custom_controller_routes_spec.rb +4 -0
  62. data/spec/support/shared/hashing_shared_context.rb +12 -5
  63. metadata +51 -21
  64. data/lib/doorkeeper/models/concerns/hashable.rb +0 -137
  65. data/spec/lib/models/hashable_spec.rb +0 -183
@@ -6,7 +6,7 @@ module Doorkeeper
6
6
  if doorkeeper_token && doorkeeper_token.accessible?
7
7
  render json: doorkeeper_token, status: :ok
8
8
  else
9
- error = OAuth::ErrorResponse.new(name: :invalid_request)
9
+ error = OAuth::InvalidTokenResponse.new
10
10
  response.headers.merge!(error.headers)
11
11
  render json: error.body, status: error.status
12
12
  end
@@ -33,7 +33,7 @@ module Doorkeeper
33
33
  if introspection.authorized?
34
34
  render json: introspection.to_json, status: 200
35
35
  else
36
- error = OAuth::ErrorResponse.new(name: introspection.error)
36
+ error = introspection.error_response
37
37
  response.headers.merge!(error.headers)
38
38
  render json: error.body, status: error.status
39
39
  end
@@ -19,13 +19,14 @@ Gem::Specification.new do |gem|
19
19
  gem.add_dependency 'railties', '>= 4.2'
20
20
  gem.required_ruby_version = '>= 2.1'
21
21
 
22
- gem.add_development_dependency 'capybara', '~> 2.18'
22
+ gem.add_development_dependency 'appraisal'
23
+ gem.add_development_dependency 'capybara'
23
24
  gem.add_development_dependency 'coveralls'
24
25
  gem.add_development_dependency 'danger', '~> 5.0'
25
- gem.add_development_dependency 'grape'
26
26
  gem.add_development_dependency 'database_cleaner', '~> 1.6'
27
27
  gem.add_development_dependency 'factory_bot', '~> 4.8'
28
28
  gem.add_development_dependency 'generator_spec', '~> 0.9.3'
29
+ gem.add_development_dependency 'grape'
29
30
  gem.add_development_dependency 'rake', '>= 11.3.0'
30
31
  gem.add_development_dependency 'rspec-rails'
31
32
  end
@@ -3,12 +3,15 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "rails", "~> 4.2.0"
6
- gem "bcrypt", "~> 3.1"
7
- gem "appraisal"
6
+ gem "rspec-core", git: "https://github.com/rspec/rspec-core.git"
7
+ gem "rspec-expectations", git: "https://github.com/rspec/rspec-expectations.git"
8
+ gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
+ gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
+ gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
+ gem "bcrypt", "~> 3.1", require: false
8
12
  gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
9
- gem "sqlite3", platform: [:ruby, :mswin, :mingw, :x64_mingw]
13
+ gem "sqlite3", "~> 1.3", "< 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
10
14
  gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
11
- # Older Grape requires Ruby >= 2.2.2
12
- gem "grape", '~> 0.16', '< 0.19.2'
15
+ gem "grape", "~> 0.16", "< 0.19.2"
13
16
 
14
17
  gemspec path: "../"
@@ -2,12 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 5.0.0"
6
- gem "bcrypt", "~> 3.1"
7
- gem "appraisal"
8
- gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
9
- gem "sqlite3", platforms: [:ruby, :mswin, :mingw, :x64_mingw]
5
+ gem "rails", "~> 5.0.0", ">= 5.0.7.2"
6
+ gem "rspec-core", git: "https://github.com/rspec/rspec-core.git"
7
+ gem "rspec-expectations", git: "https://github.com/rspec/rspec-expectations.git"
8
+ gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
+ gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
+ gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
+ gem "bcrypt", "~> 3.1", require: false
12
+ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
13
+ gem "sqlite3", "~> 1.3", "< 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
10
14
  gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
11
- gem "rspec-rails", "~> 3.5"
12
15
 
13
16
  gemspec path: "../"
@@ -2,12 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 5.1.0"
6
- gem "bcrypt", "~> 3.1"
7
- gem "appraisal"
8
- gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
9
- gem "sqlite3", platforms: [:ruby, :mswin, :mingw, :x64_mingw]
5
+ gem "rails", "~> 5.1.0", ">= 5.1.6.2"
6
+ gem "rspec-core", git: "https://github.com/rspec/rspec-core.git"
7
+ gem "rspec-expectations", git: "https://github.com/rspec/rspec-expectations.git"
8
+ gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
+ gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
+ gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
+ gem "bcrypt", "~> 3.1", require: false
12
+ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
13
+ gem "sqlite3", "~> 1.3", "< 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
10
14
  gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
11
- gem "rspec-rails", "~> 3.7"
12
15
 
13
16
  gemspec path: "../"
@@ -2,12 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", "~> 5.2.0"
6
- gem "bcrypt", "~> 3.1"
7
- gem "appraisal"
8
- gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
9
- gem "sqlite3", platforms: [:ruby, :mswin, :mingw, :x64_mingw]
5
+ gem "rails", "~> 5.2.2", ">= 5.2.2.1"
6
+ gem "rspec-core", git: "https://github.com/rspec/rspec-core.git"
7
+ gem "rspec-expectations", git: "https://github.com/rspec/rspec-expectations.git"
8
+ gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
+ gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
+ gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
+ gem "bcrypt", "~> 3.1", require: false
12
+ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
13
+ gem "sqlite3", "~> 1.3", "< 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
10
14
  gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
11
- gem "rspec-rails", "~> 3.7"
12
15
 
13
16
  gemspec path: "../"
@@ -0,0 +1,16 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 6.0.0.beta3"
6
+ gem "rspec-core", git: "https://github.com/rspec/rspec-core.git"
7
+ gem "rspec-expectations", git: "https://github.com/rspec/rspec-expectations.git"
8
+ gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
+ gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
+ gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
+ gem "bcrypt", "~> 3.1", require: false
12
+ gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
13
+ gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
14
+ gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
15
+
16
+ gemspec path: "../"
@@ -2,17 +2,15 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "rails", git: 'https://github.com/rails/rails'
6
- gem "arel", git: 'https://github.com/rails/arel'
7
-
8
- gem "appraisal"
9
- gem "bcrypt", "~> 3.1"
5
+ gem "rails", git: "https://github.com/rails/rails"
6
+ gem "rspec-core", git: "https://github.com/rspec/rspec-core.git"
7
+ gem "rspec-expectations", git: "https://github.com/rspec/rspec-expectations.git"
8
+ gem "rspec-mocks", git: "https://github.com/rspec/rspec-mocks.git"
9
+ gem "rspec-rails", branch: "4-0-dev", git: "https://github.com/rspec/rspec-rails.git"
10
+ gem "rspec-support", git: "https://github.com/rspec/rspec-support.git"
11
+ gem "bcrypt", "~> 3.1", require: false
10
12
  gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
11
- gem "sqlite3", platform: [:ruby, :mswin, :mingw, :x64_mingw]
13
+ gem "sqlite3", "~> 1.4", platform: [:ruby, :mswin, :mingw, :x64_mingw]
12
14
  gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
13
15
 
14
- %w[rspec-core rspec-expectations rspec-mocks rspec-rails rspec-support].each do |lib|
15
- gem lib, git: "https://github.com/rspec/#{lib}.git", branch: 'master'
16
- end
17
-
18
16
  gemspec path: "../"
@@ -51,12 +51,18 @@ require 'doorkeeper/oauth/token_introspection'
51
51
  require 'doorkeeper/oauth/invalid_token_response'
52
52
  require 'doorkeeper/oauth/forbidden_token_response'
53
53
 
54
+ require 'doorkeeper/secret_storing/base'
55
+ require 'doorkeeper/secret_storing/plain'
56
+ require 'doorkeeper/secret_storing/sha256_hash'
57
+ require 'doorkeeper/secret_storing/bcrypt'
58
+
54
59
  require 'doorkeeper/models/concerns/orderable'
55
60
  require 'doorkeeper/models/concerns/scopes'
56
61
  require 'doorkeeper/models/concerns/expirable'
62
+ require 'doorkeeper/models/concerns/reusable'
57
63
  require 'doorkeeper/models/concerns/revocable'
58
64
  require 'doorkeeper/models/concerns/accessible'
59
- require 'doorkeeper/models/concerns/hashable'
65
+ require 'doorkeeper/models/concerns/secret_storable'
60
66
 
61
67
  require 'doorkeeper/models/access_grant_mixin'
62
68
  require 'doorkeeper/models/access_token_mixin'
@@ -126,6 +126,15 @@ module Doorkeeper
126
126
  @config.instance_variable_set(:@reuse_access_token, true)
127
127
  end
128
128
 
129
+ # Sets the token_reuse_limit
130
+ # It will be used only when reuse_access_token option in enabled
131
+ # By default it will be 100
132
+ # It will be used for token reusablity to some threshold percentage
133
+ # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1189
134
+ def token_reuse_limit(percentage)
135
+ @config.instance_variable_set(:@token_reuse_limit, percentage)
136
+ end
137
+
129
138
  # Use an API mode for applications generated with --api argument
130
139
  # It will skip applications controller, disable forgery protection
131
140
  def api_only
@@ -147,20 +156,53 @@ module Doorkeeper
147
156
 
148
157
  # Allow optional hashing of input tokens before persisting them.
149
158
  # Will be used for hashing of input token and grants.
150
- def hash_token_secrets
151
- @config.instance_variable_set(:@hash_token_secrets, true)
159
+ #
160
+ # @param using
161
+ # Provide a different secret storage implementation class for tokens
162
+ # @param fallback
163
+ # Provide a fallback secret storage implementation class for tokens
164
+ # or use :plain to fallback to plain tokens
165
+ def hash_token_secrets(using: nil, fallback: nil)
166
+ default = '::Doorkeeper::SecretStoring::Sha256Hash'
167
+ configure_secrets_for :token,
168
+ using: using || default,
169
+ fallback: fallback
152
170
  end
153
171
 
154
172
  # Allow optional hashing of application secrets before persisting them.
155
173
  # Will be used for hashing of input token and grants.
156
- def hash_application_secrets
157
- @config.instance_variable_set(:@hash_application_secrets, true)
174
+ #
175
+ # @param using
176
+ # Provide a different secret storage implementation for applications
177
+ # @param fallback
178
+ # Provide a fallback secret storage implementation for applications
179
+ # or use :plain to fallback to plain application secrets
180
+ def hash_application_secrets(using: nil, fallback: nil)
181
+ default = '::Doorkeeper::SecretStoring::Sha256Hash'
182
+ configure_secrets_for :application,
183
+ using: using || default,
184
+ fallback: fallback
158
185
  end
159
186
 
160
- # Allow plain value lookup when using +hash_token_secrets+
161
- # or +hash_application_secrets+ to avoid disrupting application experience
162
- def fallback_to_plain_secrets
163
- @config.instance_variable_set(:@fallback_to_plain_secrets, true)
187
+ private
188
+
189
+ # Configure the secret storing functionality
190
+ def configure_secrets_for(type, using:, fallback:)
191
+ unless %i[application token].include?(type)
192
+ raise ArgumentError, "Invalid type #{type}"
193
+ end
194
+
195
+ @config.instance_variable_set(:"@#{type}_secret_strategy",
196
+ using.constantize)
197
+
198
+ if fallback.nil?
199
+ return
200
+ elsif fallback.to_sym == :plain
201
+ fallback = '::Doorkeeper::SecretStoring::Plain'
202
+ end
203
+
204
+ @config.instance_variable_set(:"@#{type}_secret_fallback_strategy",
205
+ fallback.constantize)
164
206
  end
165
207
  end
166
208
 
@@ -252,11 +294,16 @@ module Doorkeeper
252
294
 
253
295
  nil
254
296
  end)
255
- option :before_successful_authorization, default: ->(_context) {}
256
- option :after_successful_authorization, default: ->(_context) {}
257
- option :before_successful_strategy_response, default: ->(_request) {}
258
- option :after_successful_strategy_response,
259
- default: ->(_request, _response) {}
297
+
298
+ # Hooks for authorization
299
+ option :before_successful_authorization, default: ->(_context) {}
300
+ option :after_successful_authorization, default: ->(_context) {}
301
+ # Hooks for strategies responses
302
+ option :before_successful_strategy_response, default: ->(_request) {}
303
+ option :after_successful_strategy_response, default: ->(_request, _response) {}
304
+ # Allows to customize Token Introspection response
305
+ option :custom_introspection_response, default: ->(_token, _context) { {} }
306
+
260
307
  option :skip_authorization, default: ->(_routes) {}
261
308
  option :access_token_expires_in, default: 7200
262
309
  option :custom_access_token_expires_in, default: ->(_context) { nil }
@@ -304,6 +351,15 @@ module Doorkeeper
304
351
  option :access_token_generator,
305
352
  default: 'Doorkeeper::OAuth::Helpers::UniqueToken'
306
353
 
354
+
355
+ # Default access token generator is a SecureRandom class from Ruby stdlib.
356
+ # This option defines which method will be used to generate a unique token value.
357
+ #
358
+ # @param access_token_generator [String]
359
+ # the name of the access token generator class
360
+ #
361
+ option :default_generator_method, default: :urlsafe_base64
362
+
307
363
  # The controller Doorkeeper::ApplicationController inherits from.
308
364
  # Defaults to ActionController::Base.
309
365
  # https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller
@@ -319,6 +375,8 @@ module Doorkeeper
319
375
  # Return the valid subset of this configuration
320
376
  def validate
321
377
  validate_reuse_access_token_value
378
+ validate_token_reuse_limit
379
+ validate_secret_strategies
322
380
  end
323
381
 
324
382
  def api_only
@@ -337,6 +395,10 @@ module Doorkeeper
337
395
  end
338
396
  end
339
397
 
398
+ def token_reuse_limit
399
+ @token_reuse_limit ||= 100
400
+ end
401
+
340
402
  def enforce_configured_scopes?
341
403
  option_set? :enforce_configured_scopes
342
404
  end
@@ -353,16 +415,20 @@ module Doorkeeper
353
415
  handle_auth_errors == :raise
354
416
  end
355
417
 
356
- def hash_token_secrets?
357
- option_set? :hash_token_secrets
418
+ def token_secret_strategy
419
+ @token_secret_strategy ||= ::Doorkeeper::SecretStoring::Plain
420
+ end
421
+
422
+ def token_secret_fallback_strategy
423
+ @token_secret_fallback_strategy
358
424
  end
359
425
 
360
- def hash_application_secrets?
361
- option_set? :hash_application_secrets
426
+ def application_secret_strategy
427
+ @application_secret_strategy ||= ::Doorkeeper::SecretStoring::Plain
362
428
  end
363
429
 
364
- def fallback_to_plain_secrets?
365
- option_set? :fallback_to_plain_secrets
430
+ def application_secret_fallback_strategy
431
+ @application_secret_fallback_strategy
366
432
  end
367
433
 
368
434
  def default_scopes
@@ -424,18 +490,38 @@ module Doorkeeper
424
490
  types
425
491
  end
426
492
 
427
- # Determine whether +reuse_access_token+ and +hash_token_secrets+
428
- # have both been activated.
493
+ # Determine whether +reuse_access_token+ and a non-restorable
494
+ # +token_secret_strategy+ have both been activated.
429
495
  #
430
496
  # In that case, disable reuse_access_token value and warn the user.
431
497
  def validate_reuse_access_token_value
432
- return unless hash_token_secrets? && reuse_access_token
498
+ strategy = token_secret_strategy
499
+ return if !reuse_access_token || strategy.allows_restoring_secrets?
433
500
 
434
501
  ::Rails.logger.warn(
435
- 'You are configured both reuse_access_token AND hash_token_secrets. ' \
436
- 'This combination is unsupported. reuse_access_token will be disabled'
502
+ "You have configured both reuse_access_token " \
503
+ "AND strategy strategy '#{strategy}' that cannot restore tokens. " \
504
+ "This combination is unsupported. reuse_access_token will be disabled"
437
505
  )
438
506
  @reuse_access_token = false
439
507
  end
508
+
509
+ # Validate that the provided strategies are valid for
510
+ # tokens and applications
511
+ def validate_secret_strategies
512
+ token_secret_strategy.validate_for :token
513
+ application_secret_strategy.validate_for :application
514
+ end
515
+
516
+ def validate_token_reuse_limit
517
+ return if !reuse_access_token ||
518
+ (token_reuse_limit > 0 && token_reuse_limit <= 100)
519
+
520
+ ::Rails.logger.warn(
521
+ 'You have configured an invalid value for token_reuse_limit option. ' \
522
+ 'It will be set to default 100'
523
+ )
524
+ @token_reuse_limit = 100
525
+ end
440
526
  end
441
527
  end
@@ -9,7 +9,7 @@ module Doorkeeper
9
9
  include Models::Revocable
10
10
  include Models::Accessible
11
11
  include Models::Orderable
12
- include Models::Hashable
12
+ include Models::SecretStorable
13
13
  include Models::Scopes
14
14
 
15
15
  # never uses pkce, if pkce migrations were not generated
@@ -34,12 +34,6 @@ module Doorkeeper
34
34
  find_by_plaintext_token(:token, token)
35
35
  end
36
36
 
37
- # We want to perform secret hashing whenever the user
38
- # enables the configuration option +hash_token_secrets+
39
- def perform_secret_hashing?
40
- Doorkeeper.configuration.hash_token_secrets?
41
- end
42
-
43
37
  # Revokes AccessGrant records that have not been revoked and associated
44
38
  # with the specific Application and Resource Owner.
45
39
  #
@@ -101,6 +95,20 @@ module Doorkeeper
101
95
  def pkce_supported?
102
96
  new.pkce_supported?
103
97
  end
98
+
99
+ ##
100
+ # Determines the secret storing transformer
101
+ # Unless configured otherwise, uses the plain secret strategy
102
+ def secret_strategy
103
+ ::Doorkeeper.configuration.token_secret_strategy
104
+ end
105
+
106
+ ##
107
+ # Determine the fallback storing strategy
108
+ # Unless configured, there will be no fallback
109
+ def fallback_secret_strategy
110
+ ::Doorkeeper.configuration.token_secret_fallback_strategy
111
+ end
104
112
  end
105
113
  end
106
114
  end
@@ -6,10 +6,11 @@ module Doorkeeper
6
6
 
7
7
  include OAuth::Helpers
8
8
  include Models::Expirable
9
+ include Models::Reusable
9
10
  include Models::Revocable
10
11
  include Models::Accessible
11
12
  include Models::Orderable
12
- include Models::Hashable
13
+ include Models::SecretStorable
13
14
  include Models::Scopes
14
15
 
15
16
  module ClassMethods
@@ -39,12 +40,6 @@ module Doorkeeper
39
40
  find_by_plaintext_token(:refresh_token, refresh_token)
40
41
  end
41
42
 
42
- # We want to perform secret hashing whenever the user
43
- # enables the configuration option +hash_token_secrets+
44
- def perform_secret_hashing?
45
- Doorkeeper.configuration.hash_token_secrets?
46
- end
47
-
48
43
  # Revokes AccessToken records that have not been revoked and associated
49
44
  # with the specific Application and Resource Owner.
50
45
  #
@@ -132,7 +127,7 @@ module Doorkeeper
132
127
  if Doorkeeper.configuration.reuse_access_token
133
128
  access_token = matching_token_for(application, resource_owner_id, scopes)
134
129
 
135
- return access_token if access_token && !access_token.expired?
130
+ return access_token if access_token && access_token.reusable?
136
131
  end
137
132
 
138
133
  create!(
@@ -175,6 +170,20 @@ module Doorkeeper
175
170
  def last_authorized_token_for(application_id, resource_owner_id)
176
171
  authorized_tokens_for(application_id, resource_owner_id).first
177
172
  end
173
+
174
+ ##
175
+ # Determines the secret storing transformer
176
+ # Unless configured otherwise, uses the plain secret strategy
177
+ def secret_strategy
178
+ ::Doorkeeper.configuration.token_secret_strategy
179
+ end
180
+
181
+ ##
182
+ # Determine the fallback storing strategy
183
+ # Unless configured, there will be no fallback
184
+ def fallback_secret_strategy
185
+ ::Doorkeeper.configuration.token_secret_fallback_strategy
186
+ end
178
187
  end
179
188
 
180
189
  # Access Token type: Bearer.
@@ -229,20 +238,24 @@ module Doorkeeper
229
238
  # We keep a volatile copy of the raw refresh token for initial communication
230
239
  # The stored refresh_token may be mapped and not available in cleartext.
231
240
  def plaintext_refresh_token
232
- if perform_secret_hashing?
233
- @raw_refresh_token
241
+ if secret_strategy.allows_restoring_secrets?
242
+ secret_strategy.restore_secret(self, :refresh_token)
234
243
  else
235
- refresh_token
244
+ @raw_refresh_token
236
245
  end
237
246
  end
238
247
 
239
248
  # We keep a volatile copy of the raw token for initial communication
240
249
  # The stored refresh_token may be mapped and not available in cleartext.
250
+ #
251
+ # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
252
+ # while hashing strategies do not, so you cannot rely on this value
253
+ # returning a present value for persisted tokens.
241
254
  def plaintext_token
242
- if perform_secret_hashing?
243
- @raw_token
255
+ if secret_strategy.allows_restoring_secrets?
256
+ secret_strategy.restore_secret(self, :token)
244
257
  else
245
- token
258
+ @raw_token
246
259
  end
247
260
  end
248
261
 
@@ -254,7 +267,7 @@ module Doorkeeper
254
267
  #
255
268
  def generate_refresh_token
256
269
  @raw_refresh_token = UniqueToken.generate
257
- self.refresh_token = hashed_or_plain_token(@raw_refresh_token)
270
+ secret_strategy.store_secret(self, :refresh_token, @raw_refresh_token)
258
271
  end
259
272
 
260
273
  # Generates and sets the token value with the
@@ -278,7 +291,7 @@ module Doorkeeper
278
291
  created_at: created_at
279
292
  )
280
293
 
281
- self.token = hashed_or_plain_token(@raw_token)
294
+ secret_strategy.store_secret(self, :token, @raw_token)
282
295
  @raw_token
283
296
  end
284
297