Skip to content

Commit 4133bd2

Browse files
Stg91/aad audience (Azure#37204)
* adding audiences for each class * adding support for all client builders to have audience as field * everything but datalake file api and filesystem api * fromstring test and bugfixes * bugfix and recordings besides blobs * blob recordings * style * spelling errors apparently * more style and rerecording * removed broken test * queue recordings * fileshare recordings * blob recordings * comment changes --------- Co-authored-by: Rabab Ibrahim <[email protected]>
1 parent cea7a30 commit 4133bd2

File tree

48 files changed

+1553
-39
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1553
-39
lines changed

sdk/storage/azure-storage-blob/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "java",
44
"TagPrefix": "java/storage/azure-storage-blob",
5-
"Tag": "java/storage/azure-storage-blob_043be4a1dc"
5+
"Tag": "java/storage/azure-storage-blob_3ba5b9fd92"
66
}

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobClientBuilder.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.azure.core.util.logging.ClientLogger;
2929
import com.azure.storage.blob.implementation.models.EncryptionScope;
3030
import com.azure.storage.blob.implementation.util.BuilderHelper;
31+
import com.azure.storage.blob.models.BlobAudience;
3132
import com.azure.storage.blob.models.CpkInfo;
3233
import com.azure.storage.blob.models.CustomerProvidedKey;
3334
import com.azure.storage.common.StorageSharedKeyCredential;
@@ -95,6 +96,7 @@ public final class BlobClientBuilder implements
9596
private ClientOptions clientOptions = new ClientOptions();
9697
private Configuration configuration;
9798
private BlobServiceVersion version;
99+
private BlobAudience audience;
98100

99101
/**
100102
* Creates a builder instance that is able to configure and construct {@link BlobClient BlobClients} and {@link
@@ -173,7 +175,7 @@ public BlobAsyncClient buildAsyncClient() {
173175
HttpPipeline pipeline = (httpPipeline != null) ? httpPipeline : BuilderHelper.buildPipeline(
174176
storageSharedKeyCredential, tokenCredential, azureSasCredential, sasToken,
175177
endpoint, retryOptions, coreRetryOptions, logOptions,
176-
clientOptions, httpClient, perCallPolicies, perRetryPolicies, configuration, LOGGER);
178+
clientOptions, httpClient, perCallPolicies, perRetryPolicies, configuration, audience, LOGGER);
177179

178180
return new BlobAsyncClient(pipeline, endpoint, serviceVersion, accountName, blobContainerName, blobName,
179181
snapshot, customerProvidedKey, encryptionScope, versionId);
@@ -614,4 +616,15 @@ public BlobClientBuilder serviceVersion(BlobServiceVersion version) {
614616
this.version = version;
615617
return this;
616618
}
619+
620+
/**
621+
* Sets the Audience to use for authentication with Azure Active Directory (AAD). The audience is not considered
622+
* when using a shared key.
623+
* @param audience {@link BlobAudience} to be used when requesting a token from Azure Active Directory (AAD).
624+
* @return the updated BlobClientBuilder object
625+
*/
626+
public BlobClientBuilder audience(BlobAudience audience) {
627+
this.audience = audience;
628+
return this;
629+
}
617630
}

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobContainerClientBuilder.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.azure.core.util.logging.ClientLogger;
2929
import com.azure.storage.blob.implementation.models.EncryptionScope;
3030
import com.azure.storage.blob.implementation.util.BuilderHelper;
31+
import com.azure.storage.blob.models.BlobAudience;
3132
import com.azure.storage.blob.models.BlobContainerEncryptionScope;
3233
import com.azure.storage.blob.models.CpkInfo;
3334
import com.azure.storage.blob.models.CustomerProvidedKey;
@@ -93,6 +94,7 @@ public final class BlobContainerClientBuilder implements
9394
private ClientOptions clientOptions = new ClientOptions();
9495
private Configuration configuration;
9596
private BlobServiceVersion version;
97+
private BlobAudience audience;
9698

9799
/**
98100
* Creates a builder instance that is able to configure and construct {@link BlobContainerClient ContainerClients}
@@ -161,7 +163,7 @@ public BlobContainerAsyncClient buildAsyncClient() {
161163
HttpPipeline pipeline = (httpPipeline != null) ? httpPipeline : BuilderHelper.buildPipeline(
162164
storageSharedKeyCredential, tokenCredential, azureSasCredential, sasToken,
163165
endpoint, retryOptions, coreRetryOptions, logOptions,
164-
clientOptions, httpClient, perCallPolicies, perRetryPolicies, configuration, LOGGER);
166+
clientOptions, httpClient, perCallPolicies, perRetryPolicies, configuration, audience, LOGGER);
165167

166168
return new BlobContainerAsyncClient(pipeline, endpoint, serviceVersion, accountName, blobContainerName,
167169
customerProvidedKey, encryptionScope, blobContainerEncryptionScope);
@@ -569,4 +571,15 @@ public BlobContainerClientBuilder serviceVersion(BlobServiceVersion version) {
569571
this.version = version;
570572
return this;
571573
}
574+
575+
/**
576+
* Sets the Audience to use for authentication with Azure Active Directory (AAD). The audience is not considered
577+
* when using a shared key.
578+
* @param audience {@link BlobAudience} to be used when requesting a token from Azure Active Directory (AAD).
579+
* @return the updated BlobContainerClientBuilder object
580+
*/
581+
public BlobContainerClientBuilder audience(BlobAudience audience) {
582+
this.audience = audience;
583+
return this;
584+
}
572585
}

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/BlobServiceClientBuilder.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.azure.core.util.logging.ClientLogger;
3131
import com.azure.storage.blob.implementation.models.EncryptionScope;
3232
import com.azure.storage.blob.implementation.util.BuilderHelper;
33+
import com.azure.storage.blob.models.BlobAudience;
3334
import com.azure.storage.blob.models.BlobContainerEncryptionScope;
3435
import com.azure.storage.blob.models.CpkInfo;
3536
import com.azure.storage.blob.models.CustomerProvidedKey;
@@ -94,6 +95,7 @@ public final class BlobServiceClientBuilder implements
9495
private ClientOptions clientOptions = new ClientOptions();
9596
private Configuration configuration;
9697
private BlobServiceVersion version;
98+
private BlobAudience audience;
9799

98100
/**
99101
* Creates a builder instance that is able to configure and construct {@link BlobServiceClient BlobServiceClients}
@@ -135,7 +137,7 @@ public BlobServiceAsyncClient buildAsyncClient() {
135137
HttpPipeline pipeline = (httpPipeline != null) ? httpPipeline : BuilderHelper.buildPipeline(
136138
storageSharedKeyCredential, tokenCredential, azureSasCredential, sasToken,
137139
endpoint, retryOptions, coreRetryOptions, logOptions,
138-
clientOptions, httpClient, perCallPolicies, perRetryPolicies, configuration, LOGGER);
140+
clientOptions, httpClient, perCallPolicies, perRetryPolicies, configuration, audience, LOGGER);
139141

140142
boolean foundCredential = false;
141143
for (int i = 0; i < pipeline.getPolicyCount(); i++) {
@@ -531,4 +533,15 @@ public BlobServiceClientBuilder serviceVersion(BlobServiceVersion version) {
531533
this.version = version;
532534
return this;
533535
}
536+
537+
/**
538+
* Sets the Audience to use for authentication with Azure Active Directory (AAD). The audience is not considered
539+
* when using a shared key.
540+
* @param audience {@link BlobAudience} to be used when requesting a token from Azure Active Directory (AAD).
541+
* @return the updated BlobServiceClientBuilder object
542+
*/
543+
public BlobServiceClientBuilder audience(BlobAudience audience) {
544+
this.audience = audience;
545+
return this;
546+
}
534547
}

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BuilderHelper.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.azure.core.util.tracing.Tracer;
2929
import com.azure.core.util.tracing.TracerProvider;
3030
import com.azure.storage.blob.BlobUrlParts;
31+
import com.azure.storage.blob.models.BlobAudience;
3132
import com.azure.storage.common.StorageSharedKeyCredential;
3233
import com.azure.storage.common.implementation.BuilderUtils;
3334
import com.azure.storage.common.implementation.Constants;
@@ -77,6 +78,7 @@ public final class BuilderHelper {
7778
* @param perRetryPolicies Additional {@link HttpPipelinePolicy policies} to set in the pipeline per retry.
7879
* @param configuration Configuration store contain environment settings.
7980
* @param logger {@link ClientLogger} used to log any exception.
81+
* @param audience {@link BlobAudience} used to determine the audience of the blob.
8082
* @return A new {@link HttpPipeline} from the passed values.
8183
*/
8284
public static HttpPipeline buildPipeline(
@@ -85,7 +87,7 @@ public static HttpPipeline buildPipeline(
8587
RequestRetryOptions retryOptions, RetryOptions coreRetryOptions,
8688
HttpLogOptions logOptions, ClientOptions clientOptions, HttpClient httpClient,
8789
List<HttpPipelinePolicy> perCallPolicies, List<HttpPipelinePolicy> perRetryPolicies,
88-
Configuration configuration, ClientLogger logger) {
90+
Configuration configuration, BlobAudience audience, ClientLogger logger) {
8991

9092
CredentialValidator.validateSingleCredentialIsPresent(
9193
storageSharedKeyCredential, tokenCredential, azureSasCredential, sasToken, logger);
@@ -115,7 +117,10 @@ public static HttpPipeline buildPipeline(
115117
credentialPolicy = new StorageSharedKeyCredentialPolicy(storageSharedKeyCredential);
116118
} else if (tokenCredential != null) {
117119
httpsValidation(tokenCredential, "bearer token", endpoint, logger);
118-
credentialPolicy = new BearerTokenAuthenticationPolicy(tokenCredential, Constants.STORAGE_SCOPE);
120+
String scope = audience != null
121+
? ((audience.toString().endsWith("/") ? audience + ".default" : audience + "/.default"))
122+
: Constants.STORAGE_SCOPE;
123+
credentialPolicy = new BearerTokenAuthenticationPolicy(tokenCredential, scope);
119124
} else if (azureSasCredential != null) {
120125
credentialPolicy = new AzureSasCredentialPolicy(azureSasCredential, false);
121126
} else if (sasToken != null) {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.storage.blob.models;
5+
6+
import com.azure.core.util.ExpandableStringEnum;
7+
8+
import java.util.Collection;
9+
10+
/**
11+
* The audience to be used when requesting a token from Azure Active Directory (AAD).
12+
* Note: This audience only has an effect when authenticating a TokenCredential.
13+
*/
14+
public class BlobAudience extends ExpandableStringEnum<BlobAudience> {
15+
16+
/**
17+
* Gets default Audience used to acquire a token for authorizing requests to any Azure Storage account.
18+
* If no audience is specified, this resource ID is the default value: "https://storage.azure.com/".
19+
*/
20+
public static final BlobAudience AZURE_PUBLIC_CLOUD = fromString("https://storage.azure.com/");
21+
22+
/**
23+
* Creates a new instance of {@link BlobAudience} without a {@link #toString()} value.
24+
* This constructor shouldn't be called as it will produce a {@link BlobAudience} which doesn't have a String enum
25+
* value.
26+
*
27+
* @deprecated Use one of the constants or the {@link #fromString(String)} factory method.
28+
*/
29+
@Deprecated
30+
public BlobAudience() {
31+
}
32+
33+
/**
34+
* The service endpoint for a given storage account. Use this method to acquire a token for authorizing requests to
35+
* that specific Azure Storage account and service only.
36+
*
37+
* @param storageAccountName The storage account name used to populate the service endpoint.
38+
* @return the audience with the blob service endpoint.
39+
*/
40+
public static BlobAudience createBlobServiceAccountAudience(String storageAccountName) {
41+
return fromString(String.format("https://%s.blob.core.windows.net/", storageAccountName));
42+
}
43+
44+
/**
45+
* The Azure Active Directory audience to use when forming authorization scopes.
46+
* For the Language service, this value corresponds to a URL that identifies the Azure cloud where the resource is
47+
* located.
48+
* For more information see
49+
* <a href="https://learn.microsoft.com/en-us/azure/storage/blobs/authorize-access-azure-active-directory">
50+
* Authorize access to Azure blobs using Azure Active Directory</a>.
51+
*
52+
* @param audience The Azure Active Directory audience to use when forming authorization scopes.
53+
* @return the corresponding BlobAudience.
54+
*/
55+
public static BlobAudience fromString(String audience) {
56+
return fromString(audience, BlobAudience.class);
57+
}
58+
59+
/**
60+
* @return known BlobAudience values.
61+
*/
62+
public static Collection<BlobAudience> values() {
63+
return values(BlobAudience.class);
64+
}
65+
}
66+

sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/specialized/SpecializedBlobClientBuilder.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.azure.storage.blob.BlobUrlParts;
3333
import com.azure.storage.blob.implementation.models.EncryptionScope;
3434
import com.azure.storage.blob.implementation.util.BuilderHelper;
35+
import com.azure.storage.blob.models.BlobAudience;
3536
import com.azure.storage.blob.models.CpkInfo;
3637
import com.azure.storage.blob.models.CustomerProvidedKey;
3738
import com.azure.storage.blob.models.PageRange;
@@ -103,6 +104,7 @@ public final class SpecializedBlobClientBuilder implements
103104
private ClientOptions clientOptions = new ClientOptions();
104105
private Configuration configuration;
105106
private BlobServiceVersion version;
107+
private BlobAudience audience;
106108

107109
/**
108110
* Creates a {@link AppendBlobClient} based on options set in the Builder. AppendBlobClients are used to perform
@@ -235,7 +237,7 @@ private HttpPipeline getHttpPipeline() {
235237
return (httpPipeline != null) ? httpPipeline : BuilderHelper.buildPipeline(
236238
storageSharedKeyCredential, tokenCredential, azureSasCredential, sasToken,
237239
endpoint, retryOptions, coreRetryOptions, logOptions,
238-
clientOptions, httpClient, perCallPolicies, perRetryPolicies, configuration, LOGGER);
240+
clientOptions, httpClient, perCallPolicies, perRetryPolicies, configuration, audience, LOGGER);
239241
}
240242

241243
private BlobServiceVersion getServiceVersion() {
@@ -759,4 +761,15 @@ public SpecializedBlobClientBuilder serviceVersion(BlobServiceVersion version) {
759761
this.version = version;
760762
return this;
761763
}
764+
765+
/**
766+
* Sets the Audience to use for authentication with Azure Active Directory (AAD). The audience is not considered
767+
* when using a shared key.
768+
* @param audience {@link BlobAudience} to be used when requesting a token from Azure Active Directory (AAD).
769+
* @return the updated SpecializedBlobClientBuilder object
770+
*/
771+
public SpecializedBlobClientBuilder audience(BlobAudience audience) {
772+
this.audience = audience;
773+
return this;
774+
}
762775
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.azure.storage.blob;
2+
3+
import com.azure.core.credential.TokenCredential;
4+
import com.azure.identity.DefaultAzureCredentialBuilder;
5+
import com.azure.storage.blob.models.BlobAudience;
6+
7+
import java.util.Locale;
8+
9+
/**
10+
* This example shows how to use audience-based authentication with Azure Storage fpr blobs. Audience-based
11+
* authentication requires AAD authentication. The audience is to be used when requesting a token from
12+
* Azure Active Directory (AAD). Note: This audience only has an effect when authenticating a TokenCredential.
13+
*/
14+
public class BlobAudienceExample {
15+
16+
public static void main(String[] args) {
17+
/*
18+
* From the Azure portal, get your Storage account's name.
19+
*/
20+
String accountName = SampleHelper.getAccountName();
21+
22+
/*
23+
* audience will look like: "https://<your storage account>.blob.core.windows.net"
24+
*/
25+
BlobAudience audience = BlobAudience.createBlobServiceAccountAudience(accountName);
26+
27+
/* The credential used is DefaultAzureCredential because it combines commonly used credentials
28+
* in deployment and development and chooses the credential to used based on its running environment.
29+
* More information can be found at: https://learn.microsoft.com/java/api/overview/azure/identity-readme
30+
* AAD authentication is required for audience-based authentication.
31+
*/
32+
TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build();
33+
34+
/*
35+
* From the Azure portal, get your Storage account blob service URL endpoint.
36+
* The URL typically looks like this:
37+
*/
38+
String endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName);
39+
40+
/*
41+
* Create a BlobServiceClient object that wraps the service endpoint, credential and a request pipeline.
42+
*/
43+
BlobServiceClient serviceClient = new BlobServiceClientBuilder()
44+
.endpoint(endpoint)
45+
.credential(tokenCredential)
46+
.audience(null) // The default audience is "https://storage.azure.com"
47+
.buildClient();
48+
49+
// This call will succeed because the default audience is "https://storage.azure.com"
50+
serviceClient.getProperties();
51+
52+
53+
/*
54+
Now create a BlobContainerClient that takes a specific audience.
55+
*/
56+
BlobContainerClient containerClient = new BlobContainerClientBuilder()
57+
.endpoint(endpoint)
58+
.credential(tokenCredential)
59+
.audience(audience)
60+
.containerName("myContainer")
61+
.buildClient();
62+
63+
/*
64+
Any calls to the service should successfully work with the specified audience.
65+
*/
66+
containerClient.create();
67+
containerClient.getBlobClient("myBlob").uploadFromFile("path/to/file");
68+
69+
/*
70+
The storage account name must be a valid name. If an incorrect storage account name is specified, authentication
71+
will fail.
72+
*/
73+
BlobAudience badAudience = BlobAudience.createBlobServiceAccountAudience("invalidAccount");
74+
BlobContainerClient badContainerClient = new BlobContainerClientBuilder()
75+
.endpoint(endpoint)
76+
.credential(tokenCredential)
77+
.audience(badAudience) // audience will look like: "https://invalidaccount.blob.core.windows.net"
78+
.containerName("myBadContainer")
79+
.buildClient();
80+
81+
try {
82+
badContainerClient.create();
83+
} catch (Exception e) {
84+
System.out.println("Authentication failed with invalid storage account name.");
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)