com.azure.communication.common.implementation.HmacAuthenticationPolicy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of azure-communication-common Show documentation
Show all versions of azure-communication-common Show documentation
This package contains data structures commonly used for communicating with Microsoft Azure Communication Services.
For this release, see notes - https://github.com/Azure/azure-sdk-for-java/blob/master/sdk/communication/azure-communication-common/README.md and https://github.com/Azure/azure-sdk-for-java/blob/master/sdk/communication/azure-communication-common/CHANGELOG.md.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.communication.common.implementation;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.http.HttpPipelineCallContext;
import com.azure.core.http.HttpPipelineNextPolicy;
import com.azure.core.http.HttpResponse;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.util.logging.ClientLogger;
import reactor.core.Exceptions;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* HttpPipelinePolicy to append CommunicationClient required headers
*/
public final class HmacAuthenticationPolicy implements HttpPipelinePolicy {
private static final String DATE_HEADER = "date";
private static final String HOST_HEADER = "host";
private static final String CONTENT_HASH_HEADER = "x-ms-content-sha256";
// Order of the headers are important here for generating correct signature
private static final String[] SIGNED_HEADERS = new String[]{DATE_HEADER, HOST_HEADER, CONTENT_HASH_HEADER};
private static final String AUTHORIZATIONHEADERNAME = "Authorization";
private static final String HMACSHA256FORMAT = "HMAC-SHA256 SignedHeaders=%s&Signature=%s";
// Previously DateTimeFormatter.RFC_1123_DATE_TIME was being used. There
// was an issue with the day of month part. RFC_1123_DATE_TIME does not
// append a leading '0' on days that are less than 10. It is important
// that the locale remain US. In other locals the values that are generated
// for the day and month strings may be different. (e.g. Canada day strings
// have a '.' at the end)
static final DateTimeFormatter HMAC_DATETIMEFORMATTER_PATTERN =
DateTimeFormatter.ofPattern("E, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
private final AzureKeyCredential credential;
private Mac sha256HMAC;
private final ClientLogger logger = new ClientLogger(HmacAuthenticationPolicy.class);
/**
* Created with a non-null client credential
* @param clientCredential client credential with valid access key
*/
public HmacAuthenticationPolicy(AzureKeyCredential clientCredential) {
Objects.requireNonNull(clientCredential, "'clientCredential' cannot be a null value.");
credential = clientCredential;
}
@Override
public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
String accessKey = credential.getKey();
byte[] key = Base64.getDecoder().decode(accessKey);
Mac sha256HMAC;
try {
sha256HMAC = Mac.getInstance("HmacSHA256");
sha256HMAC.init(new SecretKeySpec(key, "HmacSHA256"));
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw logger.logExceptionAsError(new RuntimeException(e));
}
this.sha256HMAC = sha256HMAC;
final Flux contents = context.getHttpRequest().getBody() == null
? Flux.just(ByteBuffer.allocate(0))
: context.getHttpRequest().getBody();
if ("http".equals(context.getHttpRequest().getUrl().getProtocol())) {
return Mono.error(
new RuntimeException("AzureKeyCredential requires a URL using the HTTPS protocol scheme"));
}
try {
return appendAuthorizationHeaders(
context.getHttpRequest().getUrl(),
context.getHttpRequest().getHttpMethod().toString(),
contents)
.flatMap(headers -> {
headers.entrySet().forEach(
header -> context.getHttpRequest().setHeader(header.getKey(), header.getValue()));
return next.process();
});
} catch (RuntimeException r) {
return Mono.error(r);
}
}
Mono
© 2015 - 2025 Weber Informatics LLC | Privacy Policy