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.
The newest version!
// 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 X_MS_DATE_HEADER = "x-ms-date";
private static final String X_MS_STRING_TO_SIGN_HEADER = "x-ms-hmac-string-to-sign-base64";
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[]{X_MS_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 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) {
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 {
URL hostnameToSignWith = context.getData("hmacSignatureURL")
.filter(alternativeUrl -> alternativeUrl instanceof URL)
.map(alternativeUrl -> (URL) alternativeUrl)
.orElse(context.getHttpRequest().getUrl());
return appendAuthorizationHeaders(
hostnameToSignWith,
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);
}
}
private Mono
© 2015 - 2025 Weber Informatics LLC | Privacy Policy