Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,43 @@ public static Builder builder() {
return new Builder();
}

/**
* Return a new builder already holding every claim of this payload, so that a copy can be made with
* one or two of them changed.
* <p>
* A payload's claims cannot be reassigned, and the builder this returns is a separate object: setting a
* claim on the builder changes only what {@code build()} will produce, never this payload. Callers can
* therefore hand the same payload to several recipients and adjust it for each.
* <p>
* All eight claims are carried over -- {@code iss}, {@code jti}, {@code iat}, {@code aud}, {@code txn},
* {@code rci}, {@code sub_id} and {@code events}. The {@code events} map is passed by reference rather
* than copied, so this payload and every copy made from it share one map, which {@link #getEvents()}
* hands out as it is rather than as an unmodifiable view. The sharing is intended, since the event content
* is what stays the same between the copies, but it leaves the map the one part of a payload that is not
* fixed once built: a modification through it is seen by the payload it came from and by its siblings, so
* the map must be left alone after the payload is built.
* <p>
* It exists because a Security Event Token describes a transmission rather than an occurrence. The same
* occurrence delivered to two subscribers is two tokens, alike in the claims that describe the event and
* differing in the claims that describe the delivery -- {@code iss} above all, which names the
* organization transmitting it. The publisher uses this to re-stamp those claims per recipient instead of
* rebuilding the event content once per webhook.
*
* @return A new builder holding this payload's claims, ready to be adjusted and built.
*/
public Builder toBuilder() {

return new Builder()
.iss(this.iss)
.jti(this.jti)
.iat(this.iat)
.aud(this.aud)
.txn(this.txn)
.rci(this.rci)
.subId(this.subId)
.events(this.events);
}

/**
* Builder class for Security Event Token Payload.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,61 @@ public void testSecurityEventTokenPayloadWithEmptyEvent() {
Assert.assertTrue(payload.getEvents().isEmpty());
}

@Test
public void testSecurityEventTokenPayloadToBuilderCarriesEveryClaim() {

Map<String, EventPayload> eventMap = new HashMap<>();
eventMap.put("key1", new EventPayload() {
});
Subject subId = SimpleSubject.createOpaqueSubject("subId123");

SecurityEventTokenPayload payload = SecurityEventTokenPayload.builder()
.iss("issuer")
.jti("jti123")
.iat(123456789L)
.aud("audience")
.txn("transaction")
.rci("rci123")
.subId(subId)
.events(eventMap)
.build();

SecurityEventTokenPayload copy = payload.toBuilder()
.iss("another-issuer")
.build();

// The claim set on the copy is the copy's own.
Assert.assertEquals(copy.getIss(), "another-issuer");
// Every other claim is carried over.
Assert.assertEquals(copy.getJti(), "jti123");
Assert.assertEquals(copy.getIat(), 123456789L);
Assert.assertEquals(copy.getAud(), "audience");
Assert.assertEquals(copy.getTxn(), "transaction");
Assert.assertEquals(copy.getRci(), "rci123");
Assert.assertEquals(copy.getSubId(), subId);
// The event map is shared rather than copied, which is what makes the copy cheap.
Assert.assertSame(copy.getEvents(), payload.getEvents());
// The payload the copy was made from is left as it was.
Assert.assertEquals(payload.getIss(), "issuer");
}

@Test
public void testSecurityEventTokenPayloadToBuilderWithoutClaims() {

SecurityEventTokenPayload payload = SecurityEventTokenPayload.builder().build();

SecurityEventTokenPayload copy = payload.toBuilder().build();

Assert.assertNull(copy.getIss());
Assert.assertNull(copy.getJti());
Assert.assertEquals(copy.getIat(), 0L);
Assert.assertNull(copy.getAud());
Assert.assertNull(copy.getTxn());
Assert.assertNull(copy.getRci());
Assert.assertNull(copy.getSubId());
Assert.assertNull(copy.getEvents());
}

@Test
public void testSecurityEventTokenPayloadWithSubId() {

Expand Down
Loading