EventGridSasCredential.java
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.messaging.eventgrid;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.util.logging.ClientLogger;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
/**
* A way to use a generated shared access signature as a credential to publish events to a topic through a client.
*/
public final class EventGridSasCredential {
private String sas;
private static final ClientLogger logger = new ClientLogger(EventGridSasCredential.class);
/**
* Generate a shared access signature to provide time-limited authentication for requests to the Event Grid
* service.
* @param endpoint the endpoint of the Event Grid topic or domain.
* @param expirationTime the time in which the signature should expire, no longer providing authentication.
* @param keyCredential the access key obtained from the Event Grid topic or domain.
*
* @return the shared access signature string which can be used to construct an instance of
* {@link EventGridSasCredential}.
*/
public static String createSas(String endpoint, OffsetDateTime expirationTime,
AzureKeyCredential keyCredential) {
try {
String resKey = "r";
String expKey = "e";
String signKey = "s";
Charset charset = StandardCharsets.UTF_8;
String encodedResource = URLEncoder.encode(endpoint, charset.name());
String encodedExpiration = URLEncoder.encode(expirationTime.atZoneSameInstant(ZoneOffset.UTC).format(
DateTimeFormatter.ofPattern("M/d/yyyy h:m:s a")),
charset.name());
String unsignedSas = String.format("%s=%s&%s=%s", resKey, encodedResource, expKey, encodedExpiration);
Mac hmac = Mac.getInstance("hmacSHA256");
hmac.init(new SecretKeySpec(Base64.getDecoder().decode(keyCredential.getKey()), "hmacSHA256"));
String signature = new String(Base64.getEncoder().encode(
hmac.doFinal(unsignedSas.getBytes(charset))),
charset);
String encodedSignature = URLEncoder.encode(signature, charset.name());
return String.format("%s&%s=%s", unsignedSas, signKey, encodedSignature);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException | InvalidKeyException e) {
throw logger.logExceptionAsError(new RuntimeException(e));
}
}
/**
* Create an instance of this object to authenticate calls to the EventGrid service.
* @param sas the shared access signature to use.
*/
public EventGridSasCredential(String sas) {
if (sas == null) {
throw logger.logExceptionAsError(new IllegalArgumentException("the access signature cannot be null"));
}
if (sas.isEmpty()) {
throw logger.logExceptionAsError(new IllegalArgumentException("the access signature cannot be empty"));
}
this.sas = sas;
}
/**
* Get the token string to authenticate service calls
* @return the Shared Access Signature as a string
*/
public String getSas() {
return sas;
}
/**
* Change the shared access signature token to a new one.
* @param sas the shared access signature token to use.
*/
public void update(String sas) {
this.sas = sas;
}
}