Skip to content

Commit 35a7a14

Browse files
ginoaugustinejoshunter
authored andcommitted
add support for xdate header in signature
Signed-off-by: Gino Augustine <[email protected]>
1 parent 31ad3b6 commit 35a7a14

File tree

3 files changed

+87
-29
lines changed

3 files changed

+87
-29
lines changed

bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/Constants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public class Constants {
7575
public static final List<String> OPTIONAL_HEADERS_NAMES =
7676
Collections.unmodifiableList(
7777
Arrays.asList(
78-
OPC_OBO_TOKEN, CROSS_TENANCY_REQUEST_HEADER_NAME, X_SUBSCRIPTION));
78+
OPC_OBO_TOKEN, CROSS_TENANCY_REQUEST_HEADER_NAME, X_SUBSCRIPTION, X_DATE));
7979

8080
public static final Map<String, List<String>> OPTIONAL_SIGNING_HEADERS_MAP =
8181
createHeadersToSignForVerbMap(

bmc-common/src/main/java/com/oracle/bmc/http/signing/internal/RequestSignerImpl.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ public static Map<String, String> signRequest(
163163
for (String optionalHeaderName : optionalHeaders) {
164164
if (headers.get(optionalHeaderName) != null) {
165165
requiredHeaders.add(optionalHeaderName);
166+
//If X-Date is present Date header is skipped
167+
if (Constants.X_DATE.equals(optionalHeaderName)) {
168+
requiredHeaders.remove(Constants.DATE);
169+
}
170+
166171
}
167172
}
168173

@@ -317,8 +322,7 @@ static Map<String, String> calculateMissingHeaders(
317322
// all of the required headers that are currently missing
318323
Map<String, String> missingHeaders = new HashMap<>();
319324

320-
if (isRequiredHeaderMissing(Constants.DATE, requiredHeaders, existingHeaders) &&
321-
!existingHeaders.containsKey(Constants.X_DATE)) {
325+
if (isRequiredHeaderMissing(Constants.DATE, requiredHeaders, existingHeaders)) {
322326
missingHeaders.put(Constants.DATE, createFormatter().format(new Date()));
323327
}
324328

bmc-common/src/test/java/com/oracle/bmc/http/signing/internal/RequestSignerImplTest.java

Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,86 @@ public void signRequest_withOptionallySignedHeader()
244244
}
245245
}
246246

247+
// Reload the classes so PowerMockito can inject the static mocks.
248+
@PrepareForTest({LoggerFactory.class, Serializer.class, RequestSignerImpl.class})
249+
@Test
250+
public void signRequest_WhenXDateHeaderSkipDateHeaderFromSignature()
251+
throws IllegalAccessException, NoSuchFieldException {
252+
final Map<String, List<String>> headers = new HashMap<>();
253+
headers.put(Constants.X_DATE,Collections.singletonList("Wed, 11 Oct 2023 12:23:17 GMT"));
254+
headers.put(Constants.DATE,Collections.singletonList("Wed, 11 Oct 2023 12:23:17 GMT"));
255+
256+
URI uri = URI.create("https://test.us-phoenix-1.oraclecloud.com/20181016/paths");
257+
String keyId = "keyId";
258+
259+
KeySupplier<RSAPrivateKey> keySupplier =
260+
(KeySupplier<RSAPrivateKey>) mock(KeySupplier.class);
261+
262+
RSAPrivateKey privateKey = mock(RSAPrivateKey.class);
263+
when(keySupplier.supplyKey(keyId)).thenReturn(Optional.of(privateKey));
264+
265+
SignatureSigner signer = mock(SignatureSigner.class);
266+
267+
Field signerField = RequestSignerImpl.class.getDeclaredField("SIGNER");
268+
boolean wasAccessible = signerField.isAccessible();
269+
signerField.setAccessible(true);
270+
signerField.set(null, signer);
271+
if (!wasAccessible) {
272+
signerField.setAccessible(false);
273+
}
274+
275+
byte[] signature = new byte[] {1, 2, 3, 4, 5};
276+
when(signer.sign(any(RSAPrivateKey.class), any(byte[].class), any(String.class)))
277+
.thenReturn(signature);
278+
279+
RequestSignerImpl.SigningConfiguration signingConfiguration =
280+
new RequestSignerImpl.SigningConfiguration(
281+
SigningStrategy.STANDARD.getHeadersToSign(),
282+
SigningStrategy.STANDARD.getOptionalHeadersToSign(),
283+
SigningStrategy.STANDARD.isSkipContentHeadersForStreamingPutRequests());
284+
String verb = "get";
285+
Map<String, String> authHeaders =
286+
RequestSignerImpl.signRequest(
287+
Algorithm.RSAPSS256,
288+
uri,
289+
verb,
290+
headers,
291+
null,
292+
SignedRequestVersion.getLatestVersion().getVersionName(),
293+
keyId,
294+
keySupplier,
295+
signingConfiguration);
296+
297+
String authorization = authHeaders.get(Constants.AUTHORIZATION_HEADER);
298+
299+
Pattern headersPattern = Pattern.compile("headers=\"([^\"]*)\"");
300+
Matcher matcher = headersPattern.matcher(authorization);
301+
assertTrue(matcher.find());
302+
Set<String> authorizationHeaders =
303+
Collections.unmodifiableSet(
304+
new HashSet<>(Arrays.asList(matcher.group(1).split(" "))));
305+
SigningStrategy.STANDARD.getHeadersToSign().get(verb)
306+
.stream()
307+
.filter(requiredHeader -> !Constants.DATE.equals(requiredHeader))
308+
.forEach(requiredHeader -> {
309+
assertTrue(authorizationHeaders.contains(requiredHeader));
310+
if (requiredHeader.equals(Constants.REQUEST_TARGET)) {
311+
// this is only signed, not passed as header
312+
assertFalse(authHeaders.containsKey(requiredHeader));
313+
} else {
314+
assertTrue(authHeaders.containsKey(requiredHeader));
315+
if (headers.containsKey(requiredHeader)) {
316+
// if it exists, it should have the same value
317+
assertEquals(
318+
headers.get(requiredHeader).get(0), authHeaders.get(requiredHeader));
319+
}
320+
}
321+
});
322+
assertTrue(authorizationHeaders.contains(Constants.X_DATE));
323+
assertFalse(authorizationHeaders.contains(Constants.DATE));
324+
325+
}
326+
247327
@Test
248328
public void calculateMissingHeaders_postStringContentAsJson() throws IOException {
249329
calculateAndVerifyMissingHeaders(
@@ -415,32 +495,6 @@ public void calculateMissingHeaders_headInputStreamBodyWithExcludeBodySigningStr
415495
SigningStrategy.EXCLUDE_BODY);
416496
}
417497

418-
@Test
419-
public void calculateMissingHeaders_whenGetRequestWithXDateHeader()
420-
throws IOException {
421-
final URI uri = URI.create("https://identity.us-phoenix-1.oraclecloud.com/20160918/users");
422-
final Map<String, List<String>> temp = new HashMap<>();
423-
temp.put("x-date",Collections.singletonList("Wed, 11 Oct 2023 12:23:17 GMT"));
424-
final Map<String, List<String>> existingHeaders = Collections.unmodifiableMap(temp);
425-
SigningStrategy signingStrategy = SigningStrategy.STANDARD;
426-
final RequestSignerImpl.SigningConfiguration signingConfiguration =
427-
new RequestSignerImpl.SigningConfiguration(
428-
signingStrategy.getHeadersToSign(),
429-
signingStrategy.getOptionalHeadersToSign(),
430-
signingStrategy.isSkipContentHeadersForStreamingPutRequests());
431-
final Map<String, String> missingHeaders =
432-
RequestSignerImpl.calculateMissingHeaders(
433-
"get",
434-
uri,
435-
existingHeaders,
436-
null,
437-
Constants.ALL_HEADERS_LIST,
438-
signingConfiguration);
439-
assertNotNull(missingHeaders);
440-
assertEquals(1, missingHeaders.size());
441-
assertFalse(missingHeaders.containsKey("date"));
442-
}
443-
444498
private void calculateAndVerifyMissingHeaders(
445499
final String httpMethod,
446500
final String contentType,

0 commit comments

Comments
 (0)