Skip to content

Commit bc5ee75

Browse files
authored
Add Utility APIs Requested to azure-core (#33547)
Add Utility APIs Requested to azure-core
1 parent 1f73c46 commit bc5ee75

File tree

5 files changed

+204
-87
lines changed

5 files changed

+204
-87
lines changed

sdk/core/azure-core-test/src/main/java/com/azure/core/test/utils/TestUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public final class TestUtils {
2727
*/
2828
public static void assertArraysEqual(byte[] expected, byte[] actual) {
2929
if (!Arrays.equals(expected, actual)) {
30-
assertArraysEqual(expected, actual);
30+
Assertions.assertArrayEquals(expected, actual);
3131
}
3232
}
3333

@@ -79,7 +79,7 @@ public static void assertByteBuffersEqual(ByteBuffer expected, ByteBuffer actual
7979
byte[] actualArray = new byte[actual.remaining()];
8080
actual.get(actualArray);
8181

82-
assertArraysEqual(expectedArray, actualArray);
82+
Assertions.assertArrayEquals(expectedArray, actualArray);
8383
}
8484
}
8585

sdk/core/azure-core/src/main/java/com/azure/core/http/policy/HttpLoggingPolicy.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ private void log(LogLevel logLevel, ClientLogger logger, HttpRequestLoggingConte
198198
}
199199
}
200200

201-
if (httpLogDetailLevel.shouldLogHeaders() && logger.canLogAtLevel(LogLevel.VERBOSE)) {
201+
if (httpLogDetailLevel.shouldLogHeaders() && logger.canLogAtLevel(LogLevel.INFORMATIONAL)) {
202202
addHeadersToLogMessage(allowedHeaderNames, request.getHeaders(), logBuilder);
203203
}
204204

@@ -269,7 +269,7 @@ public Mono<HttpResponse> logResponse(ClientLogger logger, HttpResponseLoggingCo
269269
}
270270

271271
private void logHeaders(ClientLogger logger, HttpResponse response, LoggingEventBuilder logBuilder) {
272-
if (httpLogDetailLevel.shouldLogHeaders() && logger.canLogAtLevel(LogLevel.VERBOSE)) {
272+
if (httpLogDetailLevel.shouldLogHeaders() && logger.canLogAtLevel(LogLevel.INFORMATIONAL)) {
273273
addHeadersToLogMessage(allowedHeaderNames, response.getHeaders(), logBuilder);
274274
}
275275
}

sdk/core/azure-core/src/main/java/com/azure/core/util/AuthorizationChallengeHandler.java

Lines changed: 41 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,12 @@
2323
import java.util.stream.Collectors;
2424
import java.util.stream.Stream;
2525

26+
import static com.azure.core.util.CoreUtils.bytesToHexString;
27+
2628
/**
2729
* This class handles Basic and Digest authorization challenges, complying to RFC 2617 and RFC 7616.
2830
*/
2931
public class AuthorizationChallengeHandler {
30-
/*
31-
* RFC 2617 and 7616 specifies these characters to use when creating a hex string.
32-
*/
33-
private static final char[] HEX_CHARACTERS = "0123456789abcdef".toCharArray();
34-
3532
private static final String BASIC = "Basic ";
3633
private static final String DIGEST = "Digest ";
3734

@@ -274,8 +271,8 @@ private String createDigestAuthorizationHeader(String method, String uri, Map<St
274271
}
275272

276273
String ha1 = algorithm.endsWith(SESS)
277-
? calculateHa1Sess(digestFunction, realm, nonce, clientNonce)
278-
: calculateHa1NoSess(digestFunction, realm);
274+
? calculateHa1Sess(digestFunction, username, realm, password, nonce, clientNonce)
275+
: calculateHa1NoSess(digestFunction, username, realm, password);
279276

280277
String ha2 = AUTH_INT.equals(qop)
281278
? calculateHa2AuthIntQop(digestFunction, method, uri, entityBodySupplier.get())
@@ -285,7 +282,7 @@ private String createDigestAuthorizationHeader(String method, String uri, Map<St
285282
? calculateResponseKnownQop(digestFunction, ha1, nonce, nc, clientNonce, qop, ha2)
286283
: calculateResponseUnknownQop(digestFunction, ha1, nonce, ha2);
287284

288-
String headerUsername = (hashUsername) ? calculateUserhash(digestFunction, realm) : username;
285+
String headerUsername = (hashUsername) ? calculateUserhash(digestFunction, username, realm) : username;
289286

290287
return buildAuthorizationHeader(headerUsername, realm, uri, algorithm, nonce, nc, clientNonce, qop, response,
291288
opaque, hashUsername);
@@ -329,9 +326,10 @@ private String getQop(String qopHeader) {
329326
* - Create the digest of (username + ":" + realm + ":" password).
330327
* - Return the resulting bytes as a hex string.
331328
*/
332-
private String calculateHa1NoSess(Function<byte[], byte[]> digestFunction, String realm) {
333-
return hexStringOf(digestFunction.apply(String.format("%s:%s:%s", username, realm, password)
334-
.getBytes(StandardCharsets.UTF_8)));
329+
private static String calculateHa1NoSess(Function<byte[], byte[]> digestFunction, String username, String realm,
330+
String password) {
331+
return bytesToHexString(digestFunction.apply((
332+
username + ":" + realm + ":" + password).getBytes(StandardCharsets.UTF_8)));
335333
}
336334

337335
/*
@@ -343,10 +341,12 @@ private String calculateHa1NoSess(Function<byte[], byte[]> digestFunction, Strin
343341
* - Create the digest of (userPassHex + ":" nonce + ":" + cnonce).
344342
* - Return the resulting bytes as a hex string.
345343
*/
346-
private String calculateHa1Sess(Function<byte[], byte[]> digestFunction, String realm, String nonce,
347-
String cnonce) {
348-
return hexStringOf(digestFunction.apply(String.format("%s:%s:%s", calculateHa1NoSess(digestFunction, realm),
349-
nonce, cnonce).getBytes(StandardCharsets.UTF_8)));
344+
private static String calculateHa1Sess(Function<byte[], byte[]> digestFunction, String username, String realm,
345+
String password, String nonce, String cnonce) {
346+
String ha1NoSess = calculateHa1NoSess(digestFunction, username, realm, password);
347+
348+
return bytesToHexString(digestFunction.apply(
349+
(ha1NoSess + ":" + nonce + ":" + cnonce).getBytes(StandardCharsets.UTF_8)));
350350
}
351351

352352
/*
@@ -356,9 +356,9 @@ private String calculateHa1Sess(Function<byte[], byte[]> digestFunction, String
356356
* - Create the digest of (httpMethod + ":" + uri).
357357
* - Return the resulting bytes as a hex string.
358358
*/
359-
private String calculateHa2AuthQopOrEmpty(Function<byte[], byte[]> digestFunction, String httpMethod, String uri) {
360-
return hexStringOf(digestFunction.apply(String.format("%s:%s", httpMethod, uri)
361-
.getBytes(StandardCharsets.UTF_8)));
359+
private static String calculateHa2AuthQopOrEmpty(Function<byte[], byte[]> digestFunction, String httpMethod,
360+
String uri) {
361+
return bytesToHexString(digestFunction.apply((httpMethod + ":" + uri).getBytes(StandardCharsets.UTF_8)));
362362
}
363363

364364
/*
@@ -375,10 +375,12 @@ private String calculateHa2AuthQopOrEmpty(Function<byte[], byte[]> digestFunctio
375375
* the body being replay-able this runs into risks when the body is very large and potentially consuming large
376376
* amounts of memory.
377377
*/
378-
private String calculateHa2AuthIntQop(Function<byte[], byte[]> digestFunction, String httpMethod, String uri,
378+
private static String calculateHa2AuthIntQop(Function<byte[], byte[]> digestFunction, String httpMethod, String uri,
379379
byte[] requestEntityBody) {
380-
return hexStringOf(digestFunction.apply(String.format("%s:%s:%s", httpMethod, uri,
381-
hexStringOf(digestFunction.apply(requestEntityBody))).getBytes(StandardCharsets.UTF_8)));
380+
String bodyHex = bytesToHexString(digestFunction.apply(requestEntityBody));
381+
382+
return bytesToHexString(digestFunction.apply(
383+
(httpMethod + ":" + uri + ":" + bodyHex).getBytes(StandardCharsets.UTF_8)));
382384
}
383385

384386
/*
@@ -388,10 +390,9 @@ private String calculateHa2AuthIntQop(Function<byte[], byte[]> digestFunction, S
388390
* - Create the digest of (ha1 + ":" + nonce + ":" + ha2).
389391
* - Return the resulting bytes as a hex string.
390392
*/
391-
private String calculateResponseUnknownQop(Function<byte[], byte[]> digestFunction, String ha1, String nonce,
393+
private static String calculateResponseUnknownQop(Function<byte[], byte[]> digestFunction, String ha1, String nonce,
392394
String ha2) {
393-
return hexStringOf(digestFunction.apply(String.format("%s:%s:%s", ha1, nonce, ha2)
394-
.getBytes(StandardCharsets.UTF_8)));
395+
return bytesToHexString(digestFunction.apply((ha1 + ":" + nonce + ":" + ha2).getBytes(StandardCharsets.UTF_8)));
395396
}
396397

397398
/*
@@ -403,18 +404,20 @@ private String calculateResponseUnknownQop(Function<byte[], byte[]> digestFuncti
403404
*
404405
* nc, nonce count, is represented in a hexadecimal format.
405406
*/
406-
private String calculateResponseKnownQop(Function<byte[], byte[]> digestFunction, String ha1, String nonce, int nc,
407-
String cnonce, String qop, String ha2) {
408-
return hexStringOf(digestFunction.apply(String.format("%s:%s:%08X:%s:%s:%s", ha1, nonce, nc, cnonce, qop, ha2)
409-
.getBytes(StandardCharsets.UTF_8)));
407+
private static String calculateResponseKnownQop(Function<byte[], byte[]> digestFunction, String ha1, String nonce,
408+
int nc, String cnonce, String qop, String ha2) {
409+
String zeroPadNc = String.format("%08X", nc);
410+
411+
return bytesToHexString(digestFunction.apply(
412+
(ha1 + ":" + nonce + ":" + zeroPadNc + ":" + cnonce + ":" + qop + ":" + ha2)
413+
.getBytes(StandardCharsets.UTF_8)));
410414
}
411415

412416
/*
413417
* Calculates the hashed username value if the authenticate challenge has 'userhash=true'.
414418
*/
415-
private String calculateUserhash(Function<byte[], byte[]> digestFunction, String realm) {
416-
return hexStringOf(digestFunction.apply(String.format("%s:%s", username, realm)
417-
.getBytes(StandardCharsets.UTF_8)));
419+
private static String calculateUserhash(Function<byte[], byte[]> digestFunction, String username, String realm) {
420+
return bytesToHexString(digestFunction.apply((username + ":" + realm).getBytes(StandardCharsets.UTF_8)));
418421
}
419422

420423
/*
@@ -461,7 +464,7 @@ private static Map<String, List<Map<String, String>>> partitionByChallengeType(
461464
String generateNonce() {
462465
byte[] nonce = new byte[16];
463466
new SecureRandom().nextBytes(nonce);
464-
return hexStringOf(nonce);
467+
return bytesToHexString(nonce);
465468
}
466469

467470
/*
@@ -479,47 +482,26 @@ private static String buildAuthorizationHeader(String username, String realm, St
479482
.append("response=\"").append(response).append("\"");
480483

481484
if (!CoreUtils.isNullOrEmpty(algorithm)) {
482-
authorizationBuilder.append(", ").append("algorithm=").append(algorithm);
485+
authorizationBuilder.append(", algorithm=").append(algorithm);
483486
}
484487

485488
if (!CoreUtils.isNullOrEmpty(cnonce)) {
486-
authorizationBuilder.append(", ").append("cnonce=\"").append(cnonce).append("\"");
489+
authorizationBuilder.append(", cnonce=\"").append(cnonce).append("\"");
487490
}
488491

489492
if (!CoreUtils.isNullOrEmpty(opaque)) {
490-
authorizationBuilder.append(", ").append("opaque=\"").append(opaque).append("\"");
493+
authorizationBuilder.append(", opaque=\"").append(opaque).append("\"");
491494
}
492495

493496
if (!CoreUtils.isNullOrEmpty(qop)) {
494-
authorizationBuilder.append(", ").append("qop=").append(qop);
495-
authorizationBuilder.append(", ").append("nc=").append(String.format("%08X", nc));
497+
authorizationBuilder.append(", qop=").append(qop);
498+
authorizationBuilder.append(", nc=").append(java.lang.String.format("%08X", nc));
496499
}
497500

498501
if (userhash) {
499-
authorizationBuilder.append(", ").append("userhash=").append(true);
502+
authorizationBuilder.append(", userhash=true");
500503
}
501504

502505
return authorizationBuilder.toString();
503506
}
504-
505-
/*
506-
* Converts the passed byte array into a hex string.
507-
*/
508-
private static String hexStringOf(byte[] bytes) {
509-
// Hex uses 4 bits, converting a byte to hex will double its size.
510-
char[] hexCharacters = new char[bytes.length * 2];
511-
512-
for (int i = 0; i < bytes.length; i++) {
513-
// Convert the byte into an integer, masking all but the last 8 bits (the byte).
514-
int b = bytes[i] & 0xFF;
515-
516-
// Shift 4 times to the right to get the leading 4 bits and get the corresponding hex character.
517-
hexCharacters[i * 2] = HEX_CHARACTERS[b >>> 4];
518-
519-
// Mask all but the last 4 bits and get the corresponding hex character.
520-
hexCharacters[i * 2 + 1] = HEX_CHARACTERS[b & 0x0F];
521-
}
522-
523-
return new String(hexCharacters);
524-
}
525507
}

0 commit comments

Comments
 (0)