machina-auth 0.1.6 → 0.1.7

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: 779a01d0ee76aefd789279497b06a5eb82bafc444d783d6f279cf75e31e37b57
4
- data.tar.gz: 3533cf0c697aa3698225c9527df313f7d09643cd04e641af597d0b0d874ab518
3
+ metadata.gz: 376d280c6510f8afa38049e22a0c73df81355c57571b83ef571d547e340ee7c3
4
+ data.tar.gz: 13ce052358975310f67e3b3a65daee423fb48ddc9e2490632b548c66aa0f32d9
5
5
  SHA512:
6
- metadata.gz: 4d896e66034311c92ef6b5b99f1ffd6d0adfa8033f78922305d354c5009500e516ebbd49b766f615758cbaee4003246017a2fed1209cdbbb2539b3e614e78d5f
7
- data.tar.gz: e7276fa8589250b587754784882592380d20bf30e05b0dcf71b352b7d5664375decc54907c18821d8369e4aa83ae5f6c00d208ff0efe8f1ecd0f8e86873a3c00
6
+ metadata.gz: 271245b4d9c4e3a28d4feafe688d9c3e1985d28566f5f86037ab68ef76fa246f266c67b5dad94ad0d23b111844f9c9e9224e656f97bdeaf9ef76efaf4f18311b
7
+ data.tar.gz: f719e7340acaab6a85ea6b96408c639e0608c797dcbd64f57fa9f5fa76921c5a6ccaac3d0c2751932d77de0ca1019fd4f127479f9b461686b6b0b36c99206c95
@@ -23,10 +23,7 @@ module Machina
23
23
  # Token present but invalid/expired: clear the stale cache entry and
24
24
  # fall through with nil authorized. API callers get 401 from the
25
25
  # controller; browser users get redirected to login by authenticate!.
26
- unless session_data
27
- Machina.cache.delete(cache_key(token))
28
- return @app.call(env)
29
- end
26
+ return handle_expired_token(env, request, token) unless session_data
30
27
 
31
28
  Machina::Current.authorized = Machina::Authorized.new(session_data)
32
29
 
@@ -56,11 +53,23 @@ module Machina
56
53
  end
57
54
  end
58
55
 
56
+ # Clears the cache entry for the expired token and, when the token
57
+ # originated from the session cookie, deletes that cookie so the
58
+ # browser stops sending it on subsequent requests. This prevents a
59
+ # redirect loop where an expired cookie shadows fresh callback tokens.
60
+ def handle_expired_token(env, request, token)
61
+ Machina.cache.delete(cache_key(token))
62
+
63
+ status, headers, body = @app.call(env)
64
+ Rack::Utils.delete_cookie_header!(headers, 'machina_session') if request.cookies['machina_session'] == token
65
+ [status, headers, body]
66
+ end
67
+
59
68
  def extract_token(request)
60
- request.cookies['machina_session']
69
+ request.params['token']
70
+ || request.cookies['machina_session']
61
71
  || extract_bearer(request)
62
72
  || request.headers['X-Api-Key']
63
- || request.params['token']
64
73
  end
65
74
 
66
75
  def extract_bearer(request)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Machina
4
- VERSION = '0.1.6'
4
+ VERSION = '0.1.7'
5
5
  end
@@ -100,6 +100,66 @@ RSpec.describe Machina::Middleware::Authentication do
100
100
  expect(Machina.cache.read(cache_key)).to be_nil
101
101
  end
102
102
 
103
+ context 'when a stale cookie coexists with a fresh callback token' do
104
+ let(:stale_token) { 'ps_expired_cookie' }
105
+ let(:fresh_token) { 'ps_fresh_callback' }
106
+
107
+ before do
108
+ allow(identity_client).to receive(:resolve_session).with(stale_token).and_return(
109
+ Machina::IdentityClient::Response.new(status: 404, body: '{}'),
110
+ )
111
+
112
+ allow(identity_client).to receive(:resolve_session).with(fresh_token).and_return(
113
+ Machina::IdentityClient::Response.new(status: 200, body: MockResponses.session_resolution),
114
+ )
115
+ end
116
+
117
+ it 'prefers the query param token over the stale cookie' do
118
+ env = Rack::MockRequest.env_for(
119
+ '/auth/machina/callback?token=ps_fresh_callback',
120
+ 'HTTP_COOKIE' => 'machina_session=ps_expired_cookie',
121
+ )
122
+
123
+ status, _headers, body = middleware.call(env)
124
+
125
+ expect(status).to eq(200)
126
+ parsed = JSON.parse(body.first)
127
+ expect(parsed['user_id']).to eq(MockResponses.session_resolution['data']['user']['id'])
128
+ expect(identity_client).not_to have_received(:resolve_session).with(stale_token)
129
+ end
130
+ end
131
+
132
+ it 'deletes the session cookie when a cookie-sourced token is expired' do
133
+ allow(identity_client).to receive(:resolve_session).with('ps_expired_cookie').and_return(
134
+ Machina::IdentityClient::Response.new(status: 404, body: '{}'),
135
+ )
136
+
137
+ env = Rack::MockRequest.env_for(
138
+ '/resource',
139
+ 'HTTP_COOKIE' => 'machina_session=ps_expired_cookie',
140
+ )
141
+
142
+ _status, headers, _body = middleware.call(env)
143
+
144
+ expect(headers['set-cookie']).to include('machina_session=')
145
+ expect(headers['set-cookie']).to include('max-age=0')
146
+ end
147
+
148
+ it 'does not delete the cookie when a bearer token fails resolution' do
149
+ allow(identity_client).to receive(:resolve_session).with('ps_expired_bearer').and_return(
150
+ Machina::IdentityClient::Response.new(status: 404, body: '{}'),
151
+ )
152
+
153
+ env = Rack::MockRequest.env_for(
154
+ '/resource',
155
+ 'HTTP_AUTHORIZATION' => 'Bearer ps_expired_bearer',
156
+ )
157
+
158
+ _status, headers, _body = middleware.call(env)
159
+
160
+ expect(headers['set-cookie']).to be_nil
161
+ end
162
+
103
163
  it 'uses the cache on subsequent requests' do
104
164
  response = Machina::IdentityClient::Response.new(
105
165
  status: 200,
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.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - ZAR