atlas_rb 1.3.8 → 1.3.9

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: 7f2a9947778ab6d15d96514cdeb949a82ffce8023f6fe0aeee39bfce1c198ce3
4
- data.tar.gz: 864fd37a55f2275417dc5f45f1c60466b41baefc3351ed6f712c7f7dfdcda28d
3
+ metadata.gz: cf2f8c7f9ef316468a2544efe2f4471c23c547ae36d50b9abfee2efd03db38c8
4
+ data.tar.gz: 9da90557d04f84ddad26c05b6c50eab0d9a7378ccf57fbb37ba6b3e7e4355cd4
5
5
  SHA512:
6
- metadata.gz: afef167fa0ed86fb7ebd4d28fe693fb41fe20f2ade2e9b96ce0f1109aec7340038b4a9c9425cf53d3463bc346aa9cf4fa90fd012cf3ad2636dad42784d040fa2
7
- data.tar.gz: aec3edc7ce6cb88a6d9421b449e3420521073bd20083c86afa451d74c74d903c5dc222a85f0bff2bd2a87c094f06fe3066bae7f4b814fd367a6c0640e5a6800e
6
+ metadata.gz: 640d113ae6693aacb7d7d2a943634561281ebb5324d7db5284429673a48ff1ae9cbedda4d55b058710c497573e4c7c379dee18b08119925c5a0e7e73f7105088
7
+ data.tar.gz: 8e7209552ebc5b7b8db138809bd89ef077ac282342c39d483f1c125f68d757c155ff12865f7a1c24bb65040bf287eb13c7ecd81549117cb0cf01d3a1bf58cc79
data/.version CHANGED
@@ -1 +1 @@
1
- 1.3.8
1
+ 1.3.9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- atlas_rb (1.3.8)
4
+ atlas_rb (1.3.9)
5
5
  faraday (~> 2.7)
6
6
  faraday-follow_redirects (~> 0.3.0)
7
7
  faraday-multipart (~> 1)
data/README.md CHANGED
@@ -130,12 +130,14 @@ signs instead of sending `ATLAS_TOKEN` + `User:`. Otherwise it behaves exactly a
130
130
  before — so signing **coexists with `ATLAS_TOKEN` during cutover** (turn it on by
131
131
  configuring the key; roll back by clearing it).
132
132
 
133
- Two carve-outs keep the boundaries safe:
134
-
135
- - **Acting-as auto-falls-back to the `ATLAS_TOKEN` relay.** An `on_behalf_of`
136
- request is *not* signed Atlas rejects `On-Behalf-Of` on the assertion path
137
- (403) until a signed `obo` claim ships, so the gem keeps acting-as on the
138
- legacy relay rather than letting it 403.
133
+ Two things to know:
134
+
135
+ - **Acting-as rides a signed `obo` claim.** An `on_behalf_of` request is signed
136
+ with `sub` = the operator and `obo` = the target, inside the signature — so the
137
+ target can't be forged onto a stolen assertion, and no `On-Behalf-Of` header is
138
+ sent. Atlas admin-gates the operator and ignores any header obo on this path.
139
+ (Requires an Atlas on the signed-obo release; older Atlas would silently ignore
140
+ the claim — don't enable signing for acting-as traffic until Atlas is current.)
139
141
  - **`ATLAS_JWT` still wins.** A personal token (BYO-JWT) takes precedence over
140
142
  relay-signing.
141
143
 
@@ -36,12 +36,16 @@ module AtlasRb
36
36
  # short-lived assertion (ES256, `iss=cerberus`, `aud=atlas`, `sub` = the
37
37
  # acting nuid) with Cerberus's private key — Atlas verifies it with the
38
38
  # public key. No `User:` header; identity is the proven `sub`. **Acting-as
39
- # auto-falls-back to the legacy relay**: an `on_behalf_of` request is NOT
40
- # signed (Atlas 403s `On-Behalf-Of` on the assertion path until a signed
41
- # `obo` claim ships), so the boundary cannot be violated by a caller. Off
39
+ # rides a signed `obo` claim** inside the assertion (the target can't be forged
40
+ # onto a stolen assertion; Atlas admin-gates the operator and ignores any
41
+ # header obo on this path) it is no longer punted to the legacy relay. Off
42
42
  # unless a signing key is configured (so it coexists with `ATLAS_TOKEN`
43
43
  # during cutover). `ATLAS_JWT`, if set, still wins over signing.
44
44
  #
45
+ # Requires an Atlas that verifies the signed `obo` claim (the signed-obo
46
+ # release); against an older Atlas an `obo` would be silently ignored, so
47
+ # don't enable signing for acting-as traffic until Atlas is on that version.
48
+ #
45
49
  # The module is mixed in via `extend`, so its methods become class methods on
46
50
  # the host (e.g. `AtlasRb::Work.connection({})`).
47
51
  module FaradayHelper
@@ -184,17 +188,17 @@ module AtlasRb
184
188
  end
185
189
 
186
190
  # A signed-assertion Authorization header (sub = acting nuid), or nil to
187
- # defer to the legacy relay. nil when signing isn't configured, there is no
188
- # acting nuid to put in `sub`, or this is an acting-as request On-Behalf-Of
189
- # stays on the cerberus_token relay (Atlas 403s it on the assertion path),
190
- # so the boundary can't be violated by a caller.
191
+ # defer to the legacy relay. nil when signing isn't configured or there is no
192
+ # acting nuid to put in `sub`. Acting-as is carried IN the assertion as a
193
+ # signed `obo` claim (Atlas honours it on the assertion path as of the
194
+ # signed-obo release), so it is no longer punted to the cerberus_token relay.
191
195
  def signed_relay_headers(nuid, on_behalf_of)
192
- return nil unless nuid && on_behalf_of.nil?
196
+ return nil unless nuid
193
197
 
194
198
  key = assertion_signing_key
195
199
  return nil unless key
196
200
 
197
- { "Authorization" => "Bearer #{signed_assertion(nuid.to_s, key)}" }
201
+ { "Authorization" => "Bearer #{signed_assertion(nuid.to_s, key, on_behalf_of)}" }
198
202
  end
199
203
 
200
204
  # Legacy relay headers: ATLAS_TOKEN bearer + acting-user identity headers.
@@ -209,17 +213,14 @@ module AtlasRb
209
213
  # Mint a Cerberus relay assertion for `nuid`, signed ES256 with `key`. The
210
214
  # `kid` header tells Atlas which public key to verify against; iss/aud are
211
215
  # the fixed contract; the short TTL bounds replay; `jti` is forward-compat
212
- # for an Atlas-side one-time cache.
213
- def signed_assertion(nuid, key)
216
+ # for an Atlas-side one-time cache. When `on_behalf_of` is given, it rides as
217
+ # a SIGNED `obo` claim — acting-as that can't be forged onto a stolen
218
+ # assertion (Atlas admin-gates the operator and ignores any header obo here).
219
+ def signed_assertion(nuid, key, on_behalf_of = nil)
214
220
  now = Time.now.to_i
215
- payload = {
216
- "iss" => ASSERTION_ISSUER,
217
- "aud" => ASSERTION_AUDIENCE,
218
- "sub" => nuid,
219
- "iat" => now,
220
- "exp" => now + ASSERTION_TTL,
221
- "jti" => SecureRandom.uuid
222
- }
221
+ payload = { "iss" => ASSERTION_ISSUER, "aud" => ASSERTION_AUDIENCE, "sub" => nuid,
222
+ "iat" => now, "exp" => now + ASSERTION_TTL, "jti" => SecureRandom.uuid,
223
+ "obo" => on_behalf_of&.to_s }.compact # obo only when acting-as
223
224
  JWT.encode(payload, key, "ES256", { kid: assertion_signing_kid })
224
225
  end
225
226
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atlas_rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.8
4
+ version: 1.3.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cliff
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-06-14 00:00:00.000000000 Z
11
+ date: 2026-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday