Skip to content

Commit

Permalink
Add support for AzureDefaultCredential-based auth
Browse files Browse the repository at this point in the history
  • Loading branch information
headcr4sh committed May 17, 2024
1 parent 9bdd9f4 commit d65e7c0
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 64 deletions.
8 changes: 6 additions & 2 deletions azure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@
<artifactId>jgroups</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-storage</artifactId>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-storage-blob</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
Expand Down
90 changes: 49 additions & 41 deletions azure/src/main/java/org/jgroups/protocols/azure/AZURE_PING.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,15 @@

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.time.Duration;
import java.util.List;

import com.microsoft.azure.storage.CloudStorageAccount;
import com.microsoft.azure.storage.StorageCredentials;
import com.microsoft.azure.storage.StorageCredentialsAccountAndKey;
import com.microsoft.azure.storage.blob.CloudBlob;
import com.microsoft.azure.storage.blob.CloudBlobClient;
import com.microsoft.azure.storage.blob.CloudBlobContainer;
import com.microsoft.azure.storage.blob.CloudBlockBlob;
import com.microsoft.azure.storage.blob.ListBlobItem;
import com.azure.identity.DefaultAzureCredentialBuilder;

import com.azure.storage.blob.*;
import com.azure.storage.blob.models.BlobItem;
import com.azure.storage.blob.models.ListBlobsOptions;
import com.azure.storage.common.StorageSharedKeyCredential;
import org.jgroups.Address;
import org.jgroups.annotations.Property;
import org.jgroups.conf.ClassConfigurator;
Expand All @@ -49,7 +48,7 @@ public class AZURE_PING extends FILE_PING {
@Property(description = "The name of the storage account.")
protected String storage_account_name;

@Property(description = "The secret account access key.", exposeAsManagedAttribute = false)
@Property(description = "The secret account access key, can be left blank to try to obtain credentials from the environment.", exposeAsManagedAttribute = false)
protected String storage_access_key;

@Property(description = "Container to store ping information in. Must be valid DNS name.")
Expand All @@ -63,7 +62,9 @@ public class AZURE_PING extends FILE_PING {

public static final int STREAM_BUFFER_SIZE = 4096;

private CloudBlobContainer containerReference;
private BlobContainerClient containerClient;

private static final Duration TIMEOUT = Duration.ofSeconds(1);

static {
ClassConfigurator.addProtocol((short) 530, AZURE_PING.class);
Expand All @@ -77,18 +78,25 @@ public void init() throws Exception {
// Can throw IAEs
this.validateConfiguration();

final BlobServiceClientBuilder blobClientBuilder = new BlobServiceClientBuilder();
if (storage_access_key != null) {
blobClientBuilder.credential(new StorageSharedKeyCredential(storage_account_name, storage_access_key));
} else {
blobClientBuilder.credential(new DefaultAzureCredentialBuilder().build());
}

blobClientBuilder.endpoint(new BlobUrlParts()
.setAccountName(storage_account_name)
.setScheme(use_https ? "https" : "http")
.setHost(endpoint_suffix) // endpoint suffix = host base component
.toUrl().toString());


try {
StorageCredentials credentials = new StorageCredentialsAccountAndKey(storage_account_name, storage_access_key);
CloudStorageAccount storageAccount;
if (endpoint_suffix != null) {
storageAccount = new CloudStorageAccount(credentials, use_https, endpoint_suffix);
} else {
storageAccount = new CloudStorageAccount(credentials, use_https);
}
CloudBlobClient blobClient = storageAccount.createCloudBlobClient();
containerReference = blobClient.getContainerReference(container);
boolean created = containerReference.createIfNotExists();
BlobServiceClient blobClient = blobClientBuilder.buildClient();
containerClient = blobClient.getBlobContainerClient(container);

boolean created = containerClient.createIfNotExists();
if (created) {
log.info("Created container named '%s'.", container);
} else {
Expand All @@ -107,11 +115,11 @@ public void validateConfiguration() throws IllegalArgumentException {
|| container.startsWith("-") || container.length() < 3 || container.length() > 63) {
throw new IllegalArgumentException("Container name must be configured and must meet Azure requirements (must be a valid DNS name).");
}
// Account name and access key must be both configured for write access
if (storage_account_name == null || storage_access_key == null) {
throw new IllegalArgumentException("Account name and key must be configured.");
// Account name and must be configured
if (storage_account_name == null) {
throw new IllegalArgumentException("Account name must be configured.");
}
// Lets inform users here that https would be preferred
// Let's inform users here that https would be preferred
if (!use_https) {
log.info("Configuration is using HTTP, consider switching to HTTPS instead.");
}
Expand All @@ -132,15 +140,14 @@ protected void readAll(final List<Address> members, final String clustername, fi

String prefix = sanitize(clustername);

Iterable<ListBlobItem> listBlobItems = containerReference.listBlobs(prefix);
for (ListBlobItem blobItem : listBlobItems) {
Iterable<BlobItem> blobItems = containerClient.listBlobs(new ListBlobsOptions().setPrefix(prefix), TIMEOUT);
for (BlobItem blobItem : blobItems) {
try {
// If the item is a blob and not a virtual directory.
// n.b. what an ugly API this is
if (blobItem instanceof CloudBlob) {
CloudBlob blob = (CloudBlob) blobItem;
if (!blobItem.isPrefix()) {
BlobClient blobClient = containerClient.getBlobClient(blobItem.getName());
ByteArrayOutputStream os = new ByteArrayOutputStream(STREAM_BUFFER_SIZE);
blob.download(os);
blobClient.downloadStream(os);
byte[] pingBytes = os.toByteArray();
parsePingData(pingBytes, members, responses);
}
Expand Down Expand Up @@ -189,8 +196,8 @@ protected void write(final List<PingData> list, final String clustername) {
byte[] data = out.toByteArray();

// Upload the file
CloudBlockBlob blob = containerReference.getBlockBlobReference(filename);
blob.upload(new ByteArrayInputStream(data), data.length);
BlobClient blobClient = containerClient.getBlobClient(filename);
blobClient.upload(new ByteArrayInputStream(data), data.length);

} catch (Exception ex) {
log.error("Error marshalling and uploading ping data.", ex);
Expand All @@ -207,8 +214,8 @@ protected void remove(final String clustername, final Address addr) {
String filename = addressToFilename(clustername, addr);

try {
CloudBlockBlob blob = containerReference.getBlockBlobReference(filename);
boolean deleted = blob.deleteIfExists();
BlobClient blobClient = containerClient.getBlobClient(filename);
boolean deleted = blobClient.deleteIfExists();

if (deleted) {
log.debug("Tried to delete file '%s' but it was already deleted.", filename);
Expand All @@ -229,17 +236,18 @@ protected void removeAll(String clustername) {

clustername = sanitize(clustername);

Iterable<ListBlobItem> listBlobItems = containerReference.listBlobs(clustername);
for (ListBlobItem blobItem : listBlobItems) {
Iterable<BlobItem> blobItems = containerClient.listBlobs(
new ListBlobsOptions().setPrefix(clustername), TIMEOUT);
for (BlobItem blobItem : blobItems) {
try {
// If the item is a blob and not a virtual directory.
if (blobItem instanceof CloudBlob) {
CloudBlob blob = (CloudBlob) blobItem;
boolean deleted = blob.deleteIfExists();
if (!blobItem.isPrefix()) {
BlobClient blobClient = containerClient.getBlobClient(blobItem.getName());
boolean deleted = blobClient.deleteIfExists();
if (deleted) {
log.trace("Deleted file '%s'.", blob.getName());
log.trace("Deleted file '%s'.", blobItem.getName());
} else {
log.debug("Tried to delete file '%s' but it was already deleted.", blob.getName());
log.debug("Tried to delete file '%s' but it was already deleted.", blobItem.getName());
}
}
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,15 @@ public class AZURE_PINGDiscoveryTest {
public void testProtocolStack() throws Exception {
JChannel channel = new JChannel(STACK_XML_CONFIGURATION);

channel.getProtocolStack().getProtocols().replaceAll(protocol -> {
if (protocol instanceof AZURE_PING) {
return new AZURE_PING();
} else {
return protocol;
}
});

try {
try (channel) {
channel.getProtocolStack().getProtocols().replaceAll(protocol -> {
if (protocol instanceof AZURE_PING) {
return new AZURE_PING();
} else {
return protocol;
}
});
channel.connect(RANDOM_CLUSTER_NAME);
} finally {
channel.close();
}

}
Expand Down
19 changes: 9 additions & 10 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@

<properties>
<version.org.jgroups>5.3.6.Final</version.org.jgroups>
<version.com.microsoft.azure.azure-storage>8.6.6</version.com.microsoft.azure.azure-storage>
<version.com.azure-azure-sdk-bom>1.2.23</version.com.azure-azure-sdk-bom>

<!-- Overridden versions as managed by WildFly -->
<version.com.fasterxml.jackson>2.17.1</version.com.fasterxml.jackson> <!-- azure-storage uses 2.6.0 -->
Expand All @@ -81,18 +81,17 @@
<artifactId>jgroups</artifactId>
<version>${version.org.jgroups}</version>
</dependency>

<!-- Pull in Azure bills of material to ensure that the SDK components fit together -->
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-storage</artifactId>
<version>${version.com.microsoft.azure.azure-storage}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
<groupId>com.azure</groupId>
<artifactId>azure-sdk-bom</artifactId>
<version>${version.com.azure-azure-sdk-bom}</version>
<type>pom</type>
<scope>import</scope>
</dependency>


<!-- Override azure-storage dependencies versions with WildFly-managed ones -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
Expand Down

0 comments on commit d65e7c0

Please sign in to comment.