machina-auth 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95a0c331d428907d79a618631f8b39aea1aa20e297090e44229aed0bc93c0324
4
- data.tar.gz: 1489dd29fdf00291cb414b57f198d210bd9e1af818d373b4064b7cda6c0f1b66
3
+ metadata.gz: 60692b69e1db477292fba2a947650c2ac15099a616a05318071860a02a550694
4
+ data.tar.gz: 3625e766f4645037333365f8771e6363be979de0c484ff086b61ced3b335b84b
5
5
  SHA512:
6
- metadata.gz: '08a671be6f57a8ef5098444165e335e33cfb85e371f7d34d7842699854bab66050f1de191dc203839dc7c4b94dc72a556803699bc08333e453a5552fd0b94007'
7
- data.tar.gz: 236485e85bfc0ef18afc0ddde3251b411f8579ff90b1fa870958b403e2175fbfbfce751d9c629d787c9848f709473e7f7f3779843ab6232b100aee27f1acfb83
6
+ metadata.gz: 10cb1b5e52daf7e76f344bfb8445e2ecca186d5cda9b1693dd376cd7ad4e503306229eabe510879ab72cd10c0a275b5c51ba2d84275758539b5fe1d8ca12b482
7
+ data.tar.gz: a168a7dd638f5663394dda922ba91582bfef041922325c635deff9d2ce79b7828916f21553ab5357d12a8b88276e6f8c560584898c212a9daaea0a4b560a7b98
@@ -10,12 +10,14 @@ module Machina
10
10
  :product_slug,
11
11
  :cache_store,
12
12
  :cache_ttl,
13
+ :negative_cache_ttl,
13
14
  :manifest,
14
15
  :skip_paths,
15
16
  :identity_callback_uri
16
17
 
17
18
  def initialize
18
19
  @cache_ttl = 5.minutes
20
+ @negative_cache_ttl = 30.seconds
19
21
  @skip_paths = []
20
22
  end
21
23
  end
@@ -8,7 +8,11 @@ module Machina
8
8
  # resolves them against the identity service, and sets Current.authorized.
9
9
  class Authentication
10
10
  TRANSIENT_FAILURE = :transient_failure
11
- private_constant :TRANSIENT_FAILURE
11
+
12
+ # Negative-cache marker for a rejected token. A Hash, so it round-trips through any cache coder.
13
+ INVALID_SESSION = { '__machina_invalid__' => true }.freeze
14
+
15
+ private_constant :TRANSIENT_FAILURE, :INVALID_SESSION
12
16
 
13
17
  def initialize(app)
14
18
  @app = app
@@ -39,7 +43,7 @@ module Machina
39
43
  if transient_failure?(session_data)
40
44
  @app.call(env)
41
45
  else
42
- handle_expired_token(env, request, token, hints)
46
+ handle_expired_token(env, request, token)
43
47
  end
44
48
  end
45
49
 
@@ -62,10 +66,9 @@ module Machina
62
66
  end
63
67
  end
64
68
 
65
- # Clears the cache and cookie for a token that Console explicitly rejected.
66
- def handle_expired_token(env, request, token, hints)
67
- Machina.cache.delete(cache_key(token, hints))
68
-
69
+ # Clears the cookie for a rejected token. The cache holds the INVALID_SESSION
70
+ # sentinel (written in fetch_from_identity_service) and must not be cleared here.
71
+ def handle_expired_token(env, request, token)
69
72
  status, headers, body = @app.call(env)
70
73
  Rack::Utils.delete_cookie_header!(headers, 'machina_session') if request.cookies['machina_session'] == token
71
74
  [status, headers, body]
@@ -92,6 +95,7 @@ module Machina
92
95
 
93
96
  def resolve_session(token, hints)
94
97
  cached = Machina.cache.read(cache_key(token, hints))
98
+ return nil if cached == INVALID_SESSION
95
99
  return cached if cached.present? && !(cached.is_a?(Hash) && cached['stale'])
96
100
 
97
101
  fetch_from_identity_service(token, hints)
@@ -109,7 +113,7 @@ module Machina
109
113
  response = Machina.identity_client.resolve_session(token, **hints.to_resolve_kwargs)
110
114
 
111
115
  unless response.success?
112
- Machina.cache.delete(cache_key(token, hints))
116
+ Machina.cache.write(cache_key(token, hints), INVALID_SESSION, expires_in: Machina.config.negative_cache_ttl)
113
117
  return nil
114
118
  end
115
119
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Machina
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -154,7 +154,7 @@ RSpec.describe Machina::Middleware::Authentication do
154
154
  expect(JSON.parse(body.first)).to eq('user_id' => nil, 'permissions' => nil)
155
155
  end
156
156
 
157
- it 'evicts cached session and passes through when Console returns non-200 on stale re-fetch' do
157
+ it 'negative-caches the rejection and passes through when Console returns non-200 on stale re-fetch' do
158
158
  token = 'ps_stale_token'
159
159
  cache_key = "machina:session:#{token}"
160
160
  stale_data = MockResponses.session_resolution_minimal['data'].merge('stale' => true)
@@ -169,10 +169,11 @@ RSpec.describe Machina::Middleware::Authentication do
169
169
  status, = middleware.call(env)
170
170
 
171
171
  expect(status).to eq(200)
172
- expect(Machina.cache.read(cache_key)).to be_nil
172
+ # The stale session is replaced by the short-lived negative sentinel, not deleted.
173
+ expect(Machina.cache.read(cache_key)).to eq('__machina_invalid__' => true)
173
174
  end
174
175
 
175
- it 'evicts cached session when Console returns non-200 after cache expires' do
176
+ it 'negative-caches the rejection when Console returns non-200 after cache expires' do
176
177
  token = 'ps_expired_cache'
177
178
  cache_key = "machina:session:#{token}"
178
179
 
@@ -197,7 +198,24 @@ RSpec.describe Machina::Middleware::Authentication do
197
198
  status, = middleware.call(env)
198
199
 
199
200
  expect(status).to eq(200)
200
- expect(Machina.cache.read(cache_key)).to be_nil
201
+ expect(Machina.cache.read(cache_key)).to eq('__machina_invalid__' => true)
202
+ end
203
+
204
+ it 'does not re-hit Console for a rejected token while the negative cache is warm' do
205
+ token = 'ps_dead_token'
206
+
207
+ allow(identity_client).to receive(:resolve_session).with(token).and_return(
208
+ Machina::IdentityClient::Response.new(status: 404, body: '{}'),
209
+ )
210
+
211
+ 3.times do
212
+ env = Rack::MockRequest.env_for('/resource', 'HTTP_AUTHORIZATION' => "Bearer #{token}")
213
+ status, = middleware.call(env)
214
+ expect(status).to eq(200)
215
+ end
216
+
217
+ # Without negative caching this would be 3 calls; the sentinel absorbs the retries.
218
+ expect(identity_client).to have_received(:resolve_session).with(token).once
201
219
  end
202
220
 
203
221
  context 'when a stale cookie coexists with a fresh callback token' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: machina-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ZAR