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
@@ -2,6 +2,10 @@ require 'spec_helper'
2
2
 
3
3
  describe 'Custom controller for routes' do
4
4
  before :all do
5
+ Doorkeeper.configure do
6
+ orm DOORKEEPER_ORM
7
+ end
8
+
5
9
  Rails.application.routes.disable_clear_and_finalize = true
6
10
 
7
11
  Rails.application.routes.draw do
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  shared_context 'with token hashing enabled' do
4
- let(:hashed_or_plain_token_func) { Doorkeeper::AccessToken.method(:hashed_or_plain_token) }
4
+ let(:hashed_or_plain_token_func) do
5
+ Doorkeeper::SecretStoring::Sha256Hash.method(:transform_secret)
6
+ end
7
+
5
8
  before do
6
9
  Doorkeeper.configure do
7
10
  hash_token_secrets
@@ -10,17 +13,21 @@ shared_context 'with token hashing enabled' do
10
13
  end
11
14
 
12
15
  shared_context 'with token hashing and fallback lookup enabled' do
13
- let(:hashed_or_plain_token_func) { Doorkeeper::AccessToken.method(:hashed_or_plain_token) }
16
+ let(:hashed_or_plain_token_func) do
17
+ Doorkeeper::SecretStoring::Sha256Hash.method(:transform_secret)
18
+ end
19
+
14
20
  before do
15
21
  Doorkeeper.configure do
16
- hash_token_secrets
17
- fallback_to_plain_secrets
22
+ hash_token_secrets fallback: :plain
18
23
  end
19
24
  end
20
25
  end
21
26
 
22
27
  shared_context 'with application hashing enabled' do
23
- let(:hashed_or_plain_token_func) { Doorkeeper::Application.method(:hashed_or_plain_token) }
28
+ let(:hashed_or_plain_token_func) do
29
+ Doorkeeper::SecretStoring::Sha256Hash.method(:transform_secret)
30
+ end
24
31
  before do
25
32
  Doorkeeper.configure do
26
33
  hash_application_secrets
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doorkeeper
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0.rc1
4
+ version: 5.1.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felipe Elias Philipp
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2019-01-17 00:00:00.000000000 Z
14
+ date: 2019-03-22 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: railties
@@ -28,21 +28,21 @@ dependencies:
28
28
  - !ruby/object:Gem::Version
29
29
  version: '4.2'
30
30
  - !ruby/object:Gem::Dependency
31
- name: capybara
31
+ name: appraisal
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
- - - "~>"
34
+ - - ">="
35
35
  - !ruby/object:Gem::Version
36
- version: '2.18'
36
+ version: '0'
37
37
  type: :development
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
- - - "~>"
41
+ - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: '2.18'
43
+ version: '0'
44
44
  - !ruby/object:Gem::Dependency
45
- name: coveralls
45
+ name: capybara
46
46
  requirement: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - ">="
@@ -56,33 +56,33 @@ dependencies:
56
56
  - !ruby/object:Gem::Version
57
57
  version: '0'
58
58
  - !ruby/object:Gem::Dependency
59
- name: danger
59
+ name: coveralls
60
60
  requirement: !ruby/object:Gem::Requirement
61
61
  requirements:
62
- - - "~>"
62
+ - - ">="
63
63
  - !ruby/object:Gem::Version
64
- version: '5.0'
64
+ version: '0'
65
65
  type: :development
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
68
68
  requirements:
69
- - - "~>"
69
+ - - ">="
70
70
  - !ruby/object:Gem::Version
71
- version: '5.0'
71
+ version: '0'
72
72
  - !ruby/object:Gem::Dependency
73
- name: grape
73
+ name: danger
74
74
  requirement: !ruby/object:Gem::Requirement
75
75
  requirements:
76
- - - ">="
76
+ - - "~>"
77
77
  - !ruby/object:Gem::Version
78
- version: '0'
78
+ version: '5.0'
79
79
  type: :development
80
80
  prerelease: false
81
81
  version_requirements: !ruby/object:Gem::Requirement
82
82
  requirements:
83
- - - ">="
83
+ - - "~>"
84
84
  - !ruby/object:Gem::Version
85
- version: '0'
85
+ version: '5.0'
86
86
  - !ruby/object:Gem::Dependency
87
87
  name: database_cleaner
88
88
  requirement: !ruby/object:Gem::Requirement
@@ -125,6 +125,20 @@ dependencies:
125
125
  - - "~>"
126
126
  - !ruby/object:Gem::Version
127
127
  version: 0.9.3
128
+ - !ruby/object:Gem::Dependency
129
+ name: grape
130
+ requirement: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ type: :development
136
+ prerelease: false
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
128
142
  - !ruby/object:Gem::Dependency
129
143
  name: rake
130
144
  requirement: !ruby/object:Gem::Requirement
@@ -212,6 +226,7 @@ files:
212
226
  - gemfiles/rails_5_0.gemfile
213
227
  - gemfiles/rails_5_1.gemfile
214
228
  - gemfiles/rails_5_2.gemfile
229
+ - gemfiles/rails_6_0.gemfile
215
230
  - gemfiles/rails_master.gemfile
216
231
  - lib/doorkeeper.rb
217
232
  - lib/doorkeeper/config.rb
@@ -225,11 +240,12 @@ files:
225
240
  - lib/doorkeeper/models/application_mixin.rb
226
241
  - lib/doorkeeper/models/concerns/accessible.rb
227
242
  - lib/doorkeeper/models/concerns/expirable.rb
228
- - lib/doorkeeper/models/concerns/hashable.rb
229
243
  - lib/doorkeeper/models/concerns/orderable.rb
230
244
  - lib/doorkeeper/models/concerns/ownership.rb
245
+ - lib/doorkeeper/models/concerns/reusable.rb
231
246
  - lib/doorkeeper/models/concerns/revocable.rb
232
247
  - lib/doorkeeper/models/concerns/scopes.rb
248
+ - lib/doorkeeper/models/concerns/secret_storable.rb
233
249
  - lib/doorkeeper/oauth.rb
234
250
  - lib/doorkeeper/oauth/authorization/code.rb
235
251
  - lib/doorkeeper/oauth/authorization/context.rb
@@ -281,6 +297,10 @@ files:
281
297
  - lib/doorkeeper/request/refresh_token.rb
282
298
  - lib/doorkeeper/request/strategy.rb
283
299
  - lib/doorkeeper/request/token.rb
300
+ - lib/doorkeeper/secret_storing/base.rb
301
+ - lib/doorkeeper/secret_storing/bcrypt.rb
302
+ - lib/doorkeeper/secret_storing/plain.rb
303
+ - lib/doorkeeper/secret_storing/sha256_hash.rb
284
304
  - lib/doorkeeper/server.rb
285
305
  - lib/doorkeeper/stale_records_cleaner.rb
286
306
  - lib/doorkeeper/validations.rb
@@ -360,9 +380,10 @@ files:
360
380
  - spec/lib/config_spec.rb
361
381
  - spec/lib/doorkeeper_spec.rb
362
382
  - spec/lib/models/expirable_spec.rb
363
- - spec/lib/models/hashable_spec.rb
383
+ - spec/lib/models/reusable_spec.rb
364
384
  - spec/lib/models/revocable_spec.rb
365
385
  - spec/lib/models/scopes_spec.rb
386
+ - spec/lib/models/secret_storable_spec.rb
366
387
  - spec/lib/oauth/authorization/uri_builder_spec.rb
367
388
  - spec/lib/oauth/authorization_code_request_spec.rb
368
389
  - spec/lib/oauth/base_request_spec.rb
@@ -391,6 +412,10 @@ files:
391
412
  - spec/lib/oauth/token_response_spec.rb
392
413
  - spec/lib/oauth/token_spec.rb
393
414
  - spec/lib/request/strategy_spec.rb
415
+ - spec/lib/secret_storing/base_spec.rb
416
+ - spec/lib/secret_storing/bcrypt_spec.rb
417
+ - spec/lib/secret_storing/plain_spec.rb
418
+ - spec/lib/secret_storing/sha256_hash_spec.rb
394
419
  - spec/lib/server_spec.rb
395
420
  - spec/lib/stale_records_cleaner_spec.rb
396
421
  - spec/models/doorkeeper/access_grant_spec.rb
@@ -518,9 +543,10 @@ test_files:
518
543
  - spec/lib/config_spec.rb
519
544
  - spec/lib/doorkeeper_spec.rb
520
545
  - spec/lib/models/expirable_spec.rb
521
- - spec/lib/models/hashable_spec.rb
546
+ - spec/lib/models/reusable_spec.rb
522
547
  - spec/lib/models/revocable_spec.rb
523
548
  - spec/lib/models/scopes_spec.rb
549
+ - spec/lib/models/secret_storable_spec.rb
524
550
  - spec/lib/oauth/authorization/uri_builder_spec.rb
525
551
  - spec/lib/oauth/authorization_code_request_spec.rb
526
552
  - spec/lib/oauth/base_request_spec.rb
@@ -549,6 +575,10 @@ test_files:
549
575
  - spec/lib/oauth/token_response_spec.rb
550
576
  - spec/lib/oauth/token_spec.rb
551
577
  - spec/lib/request/strategy_spec.rb
578
+ - spec/lib/secret_storing/base_spec.rb
579
+ - spec/lib/secret_storing/bcrypt_spec.rb
580
+ - spec/lib/secret_storing/plain_spec.rb
581
+ - spec/lib/secret_storing/sha256_hash_spec.rb
552
582
  - spec/lib/server_spec.rb
553
583
  - spec/lib/stale_records_cleaner_spec.rb
554
584
  - spec/models/doorkeeper/access_grant_spec.rb
@@ -1,137 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Doorkeeper
4
- module Models
5
- ##
6
- # Hashable finder to provide lookups for input plaintext values which are
7
- # mapped to their hashes before lookup.
8
- module Hashable
9
- extend ActiveSupport::Concern
10
-
11
- delegate :perform_secret_hashing?,
12
- :hashed_or_plain_token,
13
- to: :class
14
-
15
- # :nodoc
16
- module ClassMethods
17
- # Allow to override the hashing method by the including module
18
- attr_accessor :secret_hash_function, :secret_comparer
19
-
20
- # Compare the given plaintext with the secret
21
- #
22
- # @param input [String]
23
- # The plain input to compare.
24
- #
25
- # @param secret [String]
26
- # The secret value to compare with.
27
- #
28
- # @return [Boolean]
29
- # If hashing is enabled: Whether the secret equals hashed input
30
- # If hashing is disabled: Whether input matches secret
31
- #
32
- def secret_matches?(input, secret)
33
- unless perform_secret_hashing?
34
- return ActiveSupport::SecurityUtils.secure_compare input, secret
35
- end
36
-
37
- (secret_comparer || method(:default_comparer))
38
- .call(input, secret)
39
- end
40
-
41
- # Returns an instance of the Doorkeeper::AccessToken with
42
- # specific token value.
43
- #
44
- # @param attr [Symbol]
45
- # The token attribute we're looking with.
46
- #
47
- # @param token [#to_s]
48
- # token value (any object that responds to `#to_s`)
49
- #
50
- # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
51
- # if there is no record with such token
52
- #
53
- def find_by_plaintext_token(attr, token)
54
- token = token.to_s
55
-
56
- find_by(attr => hashed_or_plain_token(token)) ||
57
- find_by_fallback_token(attr, token)
58
- end
59
-
60
- # Allow looking up previously plain tokens as a fallback
61
- # IFF respective options are enabled
62
- #
63
- # @param attr [Symbol]
64
- # The token attribute we're looking with.
65
- #
66
- # @param token [#to_s]
67
- # token value (any object that responds to `#to_s`)
68
- #
69
- # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
70
- # if there is no record with such token
71
- #
72
- def find_by_fallback_token(attr, token)
73
- return nil unless perform_secret_hashing?
74
- return nil unless Doorkeeper.configuration.fallback_to_plain_secrets?
75
-
76
- find_by(attr => token).tap do |fallback|
77
- upgrade_fallback_value fallback, attr
78
- end
79
- end
80
-
81
- # Hash the given input token
82
- #
83
- # @param plain_token [String]
84
- # The plain text token to hash.
85
- #
86
- # @return [String]
87
- # IFF secret hashing enabled, the hashed token,
88
- # otherwise returns the plain token.
89
- def hashed_or_plain_token(plain_token)
90
- if perform_secret_hashing?
91
- (secret_hash_function || method(:default_hash_function))
92
- .call plain_token
93
- else
94
- plain_token
95
- end
96
- end
97
-
98
- # Allow implementations in ORMs to replace a plain
99
- # value falling back to to avoid it remaining as plain text.
100
- #
101
- # @param instance
102
- # An instance of this model with a plain value token.
103
- #
104
- # @param attr
105
- # The token attribute to upgrade
106
- #
107
- def upgrade_fallback_value(instance, attr)
108
- plain_token = instance.public_send attr
109
- instance.update_column(attr, hashed_or_plain_token(plain_token))
110
- end
111
-
112
- # Including classes can override this function to
113
- # disable or enable secret hashing dynamically
114
- def perform_secret_hashing?
115
- true
116
- end
117
-
118
- # Return a default hashing function to be used when including
119
- # module or user does not specify what to use
120
- # @param plain_token [String]
121
- # The plain text token to hash.
122
- #
123
- # @return [String] Hashed plain text token
124
- #
125
- def default_hash_function(plain_token)
126
- ::Digest::SHA256.hexdigest plain_token
127
- end
128
-
129
- # Return a default comparer for the given hash function
130
- def default_comparer(plain, secret)
131
- hashed = hashed_or_plain_token(plain)
132
- ActiveSupport::SecurityUtils.secure_compare hashed, secret
133
- end
134
- end
135
- end
136
- end
137
- end
@@ -1,183 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe 'Hashable' do
6
- let(:clazz) do
7
- Class.new do
8
- include Doorkeeper::Models::Hashable
9
-
10
- def self.find_by(*)
11
- raise 'stub this'
12
- end
13
-
14
- def update_column(*)
15
- raise 'stub this'
16
- end
17
-
18
- def token
19
- raise 'stub this'
20
- end
21
- end
22
- end
23
-
24
- describe :hashed_or_plain_token do
25
- let(:enabled_hashing?) { false }
26
- subject { clazz.send(:hashed_or_plain_token, 'input') }
27
-
28
- before do
29
- allow(clazz).to receive(:perform_secret_hashing?)
30
- .and_return enabled_hashing?
31
- end
32
-
33
- context 'when no hash function set' do
34
- it 'returns the plain input' do
35
- expect(subject).to eq 'input'
36
- end
37
-
38
- context 'when hashing enabled' do
39
- let(:enabled_hashing?) { true }
40
-
41
- it 'uses the default function' do
42
- expect(clazz)
43
- .to receive(:default_hash_function)
44
- .with('input')
45
- .and_call_original
46
-
47
- expect(subject).not_to eq 'input'
48
- end
49
- end
50
- end
51
-
52
- context 'when hash_function defined' do
53
- let(:hash_function) { ->(input) { input + '-hashed' } }
54
-
55
- before do
56
- clazz.secret_hash_function = hash_function
57
- end
58
-
59
- it 'returns the plain input' do
60
- expect(clazz).not_to receive(:default_hash_function)
61
- expect(subject).to eq 'input'
62
- end
63
-
64
- context 'when hashing enabled' do
65
- let(:enabled_hashing?) { true }
66
-
67
- it 'uses that function' do
68
- expect(hash_function)
69
- .to receive(:call)
70
- .with('input')
71
- .and_call_original
72
-
73
- expect(subject).to eq 'input-hashed'
74
- end
75
- end
76
- end
77
- end
78
-
79
- describe :secret_matches? do
80
- context 'when comparer undefined' do
81
- it 'uses a default compare' do
82
- expect(clazz).to receive(:default_comparer).with('a', 'a').and_return true
83
- expect(clazz.secret_matches?('a', 'a')).to be_truthy
84
- end
85
- end
86
-
87
- context 'when comparer defined' do
88
- let(:comparer) do
89
- ->(*) { false }
90
- end
91
-
92
- before do
93
- clazz.secret_comparer = comparer
94
- end
95
-
96
- it 'uses that comparer' do
97
- expect(comparer).to receive(:call).with('a', 'a').and_call_original
98
- expect(clazz.secret_matches?('a', 'a')).to be_falsey
99
- end
100
- end
101
- end
102
-
103
- describe :find_by_fallback_token do
104
- let(:old_token) { instance_double(clazz, token: 'input') }
105
- subject { clazz.send(:find_by_fallback_token, :token, 'input') }
106
-
107
- it 'does not call find_by when not configured' do
108
- expect(clazz).not_to receive(:find_by)
109
- expect(subject).to eq(nil)
110
- end
111
-
112
- context 'when fallback configured' do
113
- include_context 'with token hashing and fallback lookup enabled'
114
- let(:hashed_token) { hashed_or_plain_token_func.call('input') }
115
-
116
- it 'upgrades the plain token if no hashed exists' do
117
- expect(clazz).to receive(:find_by).with(token: 'input').and_return(old_token)
118
- expect(old_token).to receive(:update_column).with(:token, hashed_token)
119
-
120
- expect(subject).to eq(old_token)
121
- end
122
- end
123
- end
124
-
125
- describe :find_by_plaintext_token do
126
- let(:plain_token) { 'asdf' }
127
- let(:subject) { clazz.send(:find_by_plaintext_token, :token, plain_token) }
128
- let(:hashing_enabled?) { false }
129
-
130
- before do
131
- allow(clazz).to receive(:perform_secret_hashing?).and_return(hashing_enabled?)
132
- end
133
-
134
- context 'when not configured' do
135
- it 'always finds with the plain value even when nil' do
136
- expect(clazz).to receive(:find_by).with(token: plain_token).once.and_return(nil)
137
- expect(subject).to eq(nil)
138
- end
139
- end
140
-
141
- context 'when hashing configured' do
142
- let(:hashing_enabled?) { true }
143
- let(:hashed_token) { clazz.send(:default_hash_function, plain_token) }
144
-
145
- it 'calls find_by only on the hashed value if it returns' do
146
- expect(clazz).not_to receive(:find_by).with(token: plain_token)
147
- expect(clazz).to receive(:find_by).with(token: hashed_token).and_return(:result)
148
-
149
- expect(subject).to eq(:result)
150
- end
151
-
152
- it 'does not fall back to plain token' do
153
- expect(clazz).not_to receive(:find_by).with(token: plain_token)
154
- expect(clazz).to receive(:find_by).with(token: hashed_token).and_return(nil)
155
-
156
- expect(subject).to eq(nil)
157
- end
158
-
159
- context 'when fallback configured' do
160
- let(:old_token) { instance_double(clazz, token: plain_token) }
161
- let(:hashed_token) { hashed_or_plain_token_func.call(plain_token) }
162
-
163
- include_context 'with token hashing and fallback lookup enabled'
164
-
165
- it 'does not fallback if found by hashed token' do
166
- expect(clazz).to receive(:find_by).with(token: hashed_token).and_return old_token
167
- expect(clazz).not_to receive(:find_by).with(token: plain_token)
168
- expect(clazz).not_to receive(:upgrade_fallback_value)
169
-
170
- expect(subject).to eq(old_token)
171
- end
172
-
173
- it 'also searches for the plain token if no hashed exists' do
174
- expect(clazz).to receive(:find_by).with(token: hashed_token).and_return nil
175
- expect(clazz).to receive(:find_by).with(token: plain_token).and_return(old_token)
176
- expect(old_token).to receive(:update_column).with(:token, hashed_token)
177
-
178
- expect(subject).to eq(old_token)
179
- end
180
- end
181
- end
182
- end
183
- end