Skip to content

Commit e12b302

Browse files
committed
Add httpMethod parameter to DpopHeader generation
1 parent 520bda7 commit e12b302

File tree

2 files changed

+26
-17
lines changed

2 files changed

+26
-17
lines changed

services/signin/src/main/java/software/amazon/awssdk/services/signin/internal/DpopHeaderGenerator.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
package software.amazon.awssdk.services.signin.internal;
1717

18-
import java.io.IOException;
1918
import java.nio.charset.StandardCharsets;
2019
import java.security.InvalidKeyException;
2120
import java.security.NoSuchAlgorithmException;
@@ -61,14 +60,17 @@ private DpopHeaderGenerator() {
6160
* @param pemContent - EC1 / RFC 5915 ASN.1 formated PEM contents
6261
* @param endpoint - The HTTP target URI (Section 7.1 of [RFC9110]) of the request to which the JWT is attached,
6362
* without query and fragment parts
63+
* @param httpMethod - the HTTP method of the request (eg: POST).
6464
* @param epochSeconds - creation time of the JWT in epoch seconds.
6565
* @param uuid - Unique identifier for the DPoP proof JWT - should be a UUID4 string.
6666
* @return DPoP header value
6767
*/
68-
public static String generateDPoPProofHeader(String pemContent, String endpoint, long epochSeconds, String uuid) {
69-
Validate.notBlank(pemContent, "pemContent must be set.");
70-
Validate.notBlank(endpoint, "endpoint must be set.");
71-
Validate.notBlank(uuid, "uuid must be set.");
68+
public static String generateDPoPProofHeader(String pemContent, String endpoint, String httpMethod,
69+
long epochSeconds, String uuid) {
70+
Validate.paramNotBlank(pemContent, "pemContent");
71+
Validate.paramNotBlank(endpoint, "endpoint");
72+
Validate.paramNotBlank(httpMethod, "httpMethod");
73+
Validate.paramNotBlank(uuid, "uuid");
7274

7375
try {
7476
// Load EC public and private key from PEM
@@ -78,7 +80,7 @@ public static String generateDPoPProofHeader(String pemContent, String endpoint,
7880

7981
// Build JSON strings (header, payload) with JsonGenerator
8082
byte[] headerJson = buildHeaderJson(publicKey);
81-
byte[] payloadJson = buildPayloadJson(uuid, endpoint, epochSeconds);
83+
byte[] payloadJson = buildPayloadJson(uuid, endpoint, httpMethod, epochSeconds);
8284

8385
// Base64URL encode header + payload
8486
String encodedHeader = base64UrlEncode(headerJson);
@@ -94,14 +96,14 @@ public static String generateDPoPProofHeader(String pemContent, String endpoint,
9496
// Combine into JWT
9597
String encodedSignature = base64UrlEncode(signatureBytes);
9698
return message + "." + encodedSignature;
97-
} catch (IOException | NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
99+
} catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
98100
throw new RuntimeException(e);
99101
}
100102
}
101103

102104
// build the JWT header which includes the public key
103105
// see: https://datatracker.ietf.org/doc/html/rfc9449#name-dpop-proof-jwt-syntax
104-
private static byte[] buildHeaderJson(ECPublicKey publicKey) throws IOException {
106+
private static byte[] buildHeaderJson(ECPublicKey publicKey) {
105107
ECPoint pubPoint = publicKey.getW();
106108
String x = base64UrlEncode(stripLeadingZero(pubPoint.getAffineX().toByteArray()));
107109
String y = base64UrlEncode(stripLeadingZero(pubPoint.getAffineY().toByteArray()));
@@ -142,7 +144,7 @@ private static byte[] buildHeaderJson(ECPublicKey publicKey) throws IOException
142144

143145
// build claims payload
144146
// see: https://datatracker.ietf.org/doc/html/rfc9449#name-dpop-proof-jwt-syntax
145-
private static byte[] buildPayloadJson(String uuid, String endpoint, long epochSeconds) throws IOException {
147+
private static byte[] buildPayloadJson(String uuid, String endpoint, String httpMethod, long epochSeconds) {
146148
JsonWriter jsonWriter = null;
147149
try {
148150
jsonWriter = JsonWriter.create();
@@ -152,7 +154,7 @@ private static byte[] buildPayloadJson(String uuid, String endpoint, long epochS
152154
jsonWriter.writeValue(uuid);
153155

154156
jsonWriter.writeFieldName("htm");
155-
jsonWriter.writeValue("POST");
157+
jsonWriter.writeValue(httpMethod);
156158

157159
jsonWriter.writeFieldName("htu");
158160
jsonWriter.writeValue(endpoint);

services/signin/src/test/java/software/amazon/awssdk/services/signin/auth/internal/DpopHeaderGeneratorTest.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,13 @@ public class DpopHeaderGeneratorTest {
4848

4949
@Test
5050
public void testGenerateAndVerifyDPoPHeader() throws Exception {
51-
String endpoint = "https://ap-northeast-1.aws-signin-testing.amazon.com/v1/token";
51+
String endpoint = "https://testing.amazon.com/v1/token";
52+
String httpMethod = "POST";
5253
long epochSeconds = Instant.now().getEpochSecond();
5354
String uuid = UUID.randomUUID().toString();
5455

5556
// Generate the DPoP proof JWT
56-
String dpop = DpopHeaderGenerator.generateDPoPProofHeader(VALID_TEST_PEM, endpoint, epochSeconds, uuid);
57+
String dpop = DpopHeaderGenerator.generateDPoPProofHeader(VALID_TEST_PEM, endpoint, httpMethod, epochSeconds, uuid);
5758
assertNotNull(dpop, "DPoP header should not be null");
5859

5960
// JWT should be in form header.payload.signature
@@ -77,7 +78,7 @@ public void testGenerateAndVerifyDPoPHeader() throws Exception {
7778
String payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8);
7879
Map<String, Object> payload = MAPPER.readValue(payloadJson, Map.class);
7980
assertEquals(uuid, payload.get("jti"));
80-
assertEquals("POST", payload.get("htm"));
81+
assertEquals(httpMethod, payload.get("htm"));
8182
assertEquals(endpoint, payload.get("htu"));
8283
assertEquals(((Number) payload.get("iat")).longValue(), epochSeconds);
8384

@@ -90,19 +91,25 @@ public void testGenerateAndVerifyDPoPHeader() throws Exception {
9091
public void missingArguments_raisesException() {
9192
assertThrows(IllegalArgumentException.class, () -> {
9293
DpopHeaderGenerator.generateDPoPProofHeader(
93-
"", "https://example.com",
94+
"", "https://example.com", "POST",
9495
Instant.now().getEpochSecond(), UUID.randomUUID().toString());
9596
});
9697

9798
assertThrows(IllegalArgumentException.class, () -> {
9899
DpopHeaderGenerator.generateDPoPProofHeader(
99-
VALID_TEST_PEM, "",
100+
VALID_TEST_PEM, "", "POST",
100101
Instant.now().getEpochSecond(), UUID.randomUUID().toString());
101102
});
102103

103104
assertThrows(IllegalArgumentException.class, () -> {
104105
DpopHeaderGenerator.generateDPoPProofHeader(
105-
VALID_TEST_PEM, "https://example.com",
106+
VALID_TEST_PEM, "https://example.com", "",
107+
Instant.now().getEpochSecond(), UUID.randomUUID().toString());
108+
});
109+
110+
assertThrows(IllegalArgumentException.class, () -> {
111+
DpopHeaderGenerator.generateDPoPProofHeader(
112+
VALID_TEST_PEM, "https://example.com", "POST",
106113
Instant.now().getEpochSecond(), "");
107114
});
108115
}
@@ -111,7 +118,7 @@ public void missingArguments_raisesException() {
111118
public void invalidKey_raisesException() {
112119
assertThrows(IllegalArgumentException.class, () -> {
113120
DpopHeaderGenerator.generateDPoPProofHeader(
114-
"INVALID-KEY", "https://example.com",
121+
"INVALID-KEY", "https://example.com", "POST",
115122
Instant.now().getEpochSecond(), UUID.randomUUID().toString());
116123
});
117124
}

0 commit comments

Comments
 (0)