Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STG94 Bearer Challenge Implementation #39934

Merged
2 changes: 1 addition & 1 deletion sdk/storage/azure-storage-blob/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "java",
"TagPrefix": "java/storage/azure-storage-blob",
"Tag": "java/storage/azure-storage-blob_aacdd6d63e"
"Tag": "java/storage/azure-storage-blob_e9a4d152f3"
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import com.azure.core.http.policy.AddHeadersFromContextPolicy;
import com.azure.core.http.policy.AddHeadersPolicy;
import com.azure.core.http.policy.AzureSasCredentialPolicy;
import com.azure.core.http.policy.BearerTokenAuthenticationPolicy;
import com.azure.core.http.policy.HttpLogOptions;
import com.azure.core.http.policy.HttpLoggingPolicy;
import com.azure.core.http.policy.HttpPipelinePolicy;
Expand All @@ -38,6 +37,7 @@
import com.azure.storage.common.policy.RequestRetryOptions;
import com.azure.storage.common.policy.ResponseValidationPolicyBuilder;
import com.azure.storage.common.policy.ScrubEtagPolicy;
import com.azure.storage.common.policy.StorageBearerTokenChallengeAuthorizationPolicy;
import com.azure.storage.common.policy.StorageSharedKeyCredentialPolicy;

import java.net.MalformedURLException;
Expand Down Expand Up @@ -123,7 +123,7 @@ public static HttpPipeline buildPipeline(
String scope = audience != null
? ((audience.toString().endsWith("/") ? audience + ".default" : audience + "/.default"))
: Constants.STORAGE_SCOPE;
credentialPolicy = new BearerTokenAuthenticationPolicy(tokenCredential, scope);
credentialPolicy = new StorageBearerTokenChallengeAuthorizationPolicy(tokenCredential, scope);
} else if (azureSasCredential != null) {
credentialPolicy = new AzureSasCredentialPolicy(azureSasCredential, false);
} else if (sasToken != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3072,15 +3072,18 @@ public void storageAccountAudience() {
assertTrue(aadBlob.exists());
}

@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2024-08-04")
@LiveOnly
@Test
public void audienceError() {
BlobClient aadBlob = instrument(new BlobClientBuilder().endpoint(bc.getBlobUrl())
.credential(new MockTokenCredential())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience")))
/* This test tests if the bearer challenge is working properly. A bad audience is passed in, the service returns
the default audience, and the request gets retried with this default audience, making the call function as expected.
*/
public void audienceErrorBearerChallengeRetry() {
BlobClient aadBlob = getBlobClientBuilderWithTokenCredential(bc.getBlobUrl())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
ibrandes marked this conversation as resolved.
Show resolved Hide resolved
.buildClient();

BlobStorageException e = assertThrows(BlobStorageException.class, aadBlob::exists);
assertTrue(e.getErrorCode() == BlobErrorCode.INVALID_AUTHENTICATION_INFO);
assertNotNull(aadBlob.getProperties());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2821,18 +2821,20 @@ public void storageAccountAudience() {
.verifyComplete();
}

@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2024-08-04")
@LiveOnly
@Test
public void audienceError() {
BlobAsyncClient aadBlob = instrument(new BlobClientBuilder().endpoint(bc.getBlobUrl())
.credential(new MockTokenCredential())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience")))
/* This test tests if the bearer challenge is working properly. A bad audience is passed in, the service returns
the default audience, and the request gets retried with this default audience, making the call function as expected.
*/
public void audienceErrorBearerChallengeRetry() {
BlobAsyncClient aadBlob = getBlobClientBuilderWithTokenCredential(bc.getBlobUrl())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildAsyncClient();

StepVerifier.create(aadBlob.exists())
.verifyErrorSatisfies(r -> {
BlobStorageException e = assertInstanceOf(BlobStorageException.class, r);
assertTrue(e.getErrorCode() == BlobErrorCode.INVALID_AUTHENTICATION_INFO);
});
StepVerifier.create(aadBlob.getProperties())
.assertNext(r -> assertNotNull(r))
.verifyComplete();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.azure.storage.common.Utility;
import com.azure.storage.common.implementation.Constants;
import com.azure.storage.common.test.shared.TestHttpClientType;
import com.azure.storage.common.test.shared.extensions.LiveOnly;
import com.azure.storage.common.test.shared.extensions.PlaybackOnly;
import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -1978,15 +1979,18 @@ public void storageAccountAudience() {
assertTrue(aadContainer.exists());
}

@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2024-08-04")
@LiveOnly
@Test
public void audienceError() {
BlobContainerClient aadContainer = getContainerClientBuilder(cc.getBlobContainerUrl())
.credential(new MockTokenCredential())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildClient();
/* This test tests if the bearer challenge is working properly. A bad audience is passed in, the service returns
the default audience, and the request gets retried with this default audience, making the call function as expected.
*/
public void audienceErrorBearerChallengeRetry() {
BlobContainerClient aadContainer = getContainerClientBuilderWithTokenCredential(cc.getBlobContainerUrl())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildClient();

BlobStorageException e = assertThrows(BlobStorageException.class, () -> aadContainer.exists());
assertTrue(e.getErrorCode() == BlobErrorCode.INVALID_AUTHENTICATION_INFO);
assertNotNull(aadContainer.getProperties());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.azure.storage.blob.specialized.PageBlobAsyncClient;
import com.azure.storage.common.implementation.Constants;
import com.azure.storage.common.test.shared.TestHttpClientType;
import com.azure.storage.common.test.shared.extensions.LiveOnly;
import com.azure.storage.common.test.shared.extensions.PlaybackOnly;
import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -2101,18 +2102,20 @@ public void storageAccountAudience() {
.expectNext(true);
}

@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2024-08-04")
@LiveOnly
@Test
public void audienceError() {
BlobContainerAsyncClient aadContainer = getContainerClientBuilder(ccAsync.getBlobContainerUrl())
.credential(new MockTokenCredential())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildAsyncClient();
/* This test tests if the bearer challenge is working properly. A bad audience is passed in, the service returns
the default audience, and the request gets retried with this default audience, making the call function as expected.
*/
public void audienceErrorBearerChallengeRetry() {
BlobContainerAsyncClient aadContainer = getContainerClientBuilderWithTokenCredential(ccAsync.getBlobContainerUrl())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildAsyncClient();

StepVerifier.create(aadContainer.exists())
.verifyErrorSatisfies(r -> {
BlobStorageException e = assertInstanceOf(BlobStorageException.class, r);
assertTrue(e.getErrorCode() == BlobErrorCode.INVALID_AUTHENTICATION_INFO);
});
.assertNext(r -> assertNotNull(r))
.verifyComplete();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import com.azure.core.http.rest.PagedIterable;
import com.azure.core.http.rest.PagedResponse;
import com.azure.core.http.rest.Response;
import com.azure.core.test.utils.MockTokenCredential;
import com.azure.core.util.Context;
import com.azure.core.util.paging.ContinuablePage;
import com.azure.identity.DefaultAzureCredentialBuilder;
Expand Down Expand Up @@ -1141,16 +1140,18 @@ public void storageAccountAudience() {
assertNotNull(aadService.getProperties());
}

@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2024-08-04")
@LiveOnly
@Test
public void audienceError() {
BlobServiceClient aadService = instrument(new BlobServiceClientBuilder()
.endpoint(cc.getBlobContainerUrl())
.credential(new MockTokenCredential())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience")))
.buildClient();
/* This test tests if the bearer challenge is working properly. A bad audience is passed in, the service returns
the default audience, and the request gets retried with this default audience, making the call function as expected.
*/
public void audienceErrorBearerChallengeRetry() {
BlobServiceClient aadService = getServiceClientBuilderWithTokenCredential(cc.getBlobContainerUrl())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildClient();

BlobStorageException e = assertThrows(BlobStorageException.class, () -> aadService.getProperties());
assertTrue(e.getErrorCode() == BlobErrorCode.INVALID_AUTHENTICATION_INFO);
assertNotNull(aadService.getProperties());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.azure.core.http.rest.PagedResponse;
import com.azure.core.http.rest.Response;
import com.azure.core.test.TestMode;
import com.azure.core.test.utils.MockTokenCredential;
import com.azure.core.util.Context;
import com.azure.core.util.paging.ContinuablePage;
import com.azure.identity.DefaultAzureCredentialBuilder;
Expand Down Expand Up @@ -1204,19 +1203,20 @@ public void storageAccountAudience() {
.verifyComplete();
}

@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2024-08-04")
@LiveOnly
@Test
public void audienceError() {
BlobServiceAsyncClient aadService = instrument(new BlobServiceClientBuilder()
.endpoint(ccAsync.getBlobContainerUrl())
.credential(new MockTokenCredential())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience")))
.buildAsyncClient();
/* This test tests if the bearer challenge is working properly. A bad audience is passed in, the service returns
the default audience, and the request gets retried with this default audience, making the call function as expected.
*/
public void audienceErrorBearerChallengeRetry() {
BlobServiceAsyncClient aadService = getServiceClientBuilderWithTokenCredential(ccAsync.getBlobContainerUrl())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildAsyncClient();

StepVerifier.create(aadService.getProperties())
.verifyErrorSatisfies(r -> {
BlobStorageException e = assertInstanceOf(BlobStorageException.class, r);
assertTrue(e.getErrorCode() == BlobErrorCode.INVALID_AUTHENTICATION_INFO);
});
.assertNext(r -> assertNotNull(r))
.verifyComplete();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import com.azure.core.exception.UnexpectedLengthException;
import com.azure.core.http.rest.Response;
import com.azure.core.test.utils.MockTokenCredential;
import com.azure.core.test.utils.TestUtils;
import com.azure.core.util.Context;
import com.azure.storage.blob.BlobServiceVersion;
Expand All @@ -25,6 +24,7 @@
import com.azure.storage.blob.sas.BlobContainerSasPermission;
import com.azure.storage.blob.sas.BlobServiceSasSignatureValues;
import com.azure.storage.common.implementation.Constants;
import com.azure.storage.common.test.shared.extensions.LiveOnly;
import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion;
import com.azure.storage.common.test.shared.policy.TransientFailureInjectingHttpPipelinePolicy;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -851,16 +851,18 @@ public void storageAccountAudience() {
assertTrue(aadBlob.exists());
}

@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2024-08-04")
@LiveOnly
@Test
public void audienceError() {
AppendBlobClient aadBlob = instrument(new SpecializedBlobClientBuilder()
.endpoint(bc.getBlobUrl())
.credential(new MockTokenCredential())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience")))
/* This test tests if the bearer challenge is working properly. A bad audience is passed in, the service returns
the default audience, and the request gets retried with this default audience, making the call function as expected.
*/
public void audienceErrorBearerChallengeRetry() {
AppendBlobClient aadBlob = getSpecializedBuilderWithTokenCredential(bc.getBlobUrl())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildAppendBlobClient();

BlobStorageException e = assertThrows(BlobStorageException.class, () -> aadBlob.exists());
assertTrue(e.getErrorCode() == BlobErrorCode.INVALID_AUTHENTICATION_INFO);
assertNotNull(aadBlob.getProperties());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package com.azure.storage.blob.specialized;

import com.azure.core.exception.UnexpectedLengthException;
import com.azure.core.test.utils.MockTokenCredential;
import com.azure.core.test.utils.TestUtils;
import com.azure.core.util.FluxUtil;
import com.azure.storage.blob.BlobServiceVersion;
Expand All @@ -22,6 +21,7 @@
import com.azure.storage.blob.sas.BlobSasPermission;
import com.azure.storage.blob.sas.BlobServiceSasSignatureValues;
import com.azure.storage.common.implementation.Constants;
import com.azure.storage.common.test.shared.extensions.LiveOnly;
import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion;
import com.azure.storage.common.test.shared.policy.TransientFailureInjectingHttpPipelinePolicy;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -904,19 +904,20 @@ public void storageAccountAudience() {
.verifyComplete();
}

@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2024-08-04")
@LiveOnly
@Test
public void audienceError() {
AppendBlobAsyncClient aadBlob = instrument(new SpecializedBlobClientBuilder()
.endpoint(bc.getBlobUrl())
.credential(new MockTokenCredential())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience")))
/* This test tests if the bearer challenge is working properly. A bad audience is passed in, the service returns
the default audience, and the request gets retried with this default audience, making the call function as expected.
*/
public void audienceErrorBearerChallengeRetry() {
AppendBlobAsyncClient aadBlob = getSpecializedBuilderWithTokenCredential(bc.getBlobUrl())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildAppendBlobAsyncClient();

StepVerifier.create(aadBlob.exists())
.verifyErrorSatisfies(r -> {
BlobStorageException e = assertInstanceOf(BlobStorageException.class, r);
assertTrue(e.getErrorCode() == BlobErrorCode.INVALID_AUTHENTICATION_INFO);
});
StepVerifier.create(aadBlob.getProperties())
.assertNext(r -> assertNotNull(r))
.verifyComplete();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.azure.core.http.HttpHeaderName;
import com.azure.core.http.HttpHeaders;
import com.azure.core.http.rest.Response;
import com.azure.core.test.utils.MockTokenCredential;
import com.azure.core.test.utils.TestUtils;
import com.azure.core.util.BinaryData;
import com.azure.core.util.Context;
Expand Down Expand Up @@ -1767,16 +1766,18 @@ public void storageAccountAudience() {
assertTrue(aadBlob.exists());
}

@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2024-08-04")
@LiveOnly
@Test
public void audienceError() {
BlockBlobClient aadBlob = instrument(new SpecializedBlobClientBuilder()
.endpoint(blockBlobClient.getBlobUrl())
.credential(new MockTokenCredential())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience")))
/* This test tests if the bearer challenge is working properly. A bad audience is passed in, the service returns
the default audience, and the request gets retried with this default audience, making the call function as expected.
*/
public void audienceErrorBearerChallengeRetry() {
BlockBlobClient aadBlob = getSpecializedBuilderWithTokenCredential(blockBlobClient.getBlobUrl())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildBlockBlobClient();

BlobStorageException e = assertThrows(BlobStorageException.class, () -> aadBlob.exists());
assertTrue(e.getErrorCode() == BlobErrorCode.INVALID_AUTHENTICATION_INFO);
assertNotNull(aadBlob.getProperties());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.http.rest.Response;
import com.azure.core.test.http.MockHttpResponse;
import com.azure.core.test.utils.MockTokenCredential;
import com.azure.core.test.utils.TestUtils;
import com.azure.core.util.BinaryData;
import com.azure.core.util.FluxUtil;
Expand Down Expand Up @@ -2650,19 +2649,20 @@ public void storageAccountAudience() {
.verifyComplete();
}

@RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2024-08-04")
@LiveOnly
@Test
public void audienceError() {
BlockBlobAsyncClient aadBlob = instrument(new SpecializedBlobClientBuilder()
.endpoint(blockBlobAsyncClient.getBlobUrl())
.credential(new MockTokenCredential())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience")))
/* This test tests if the bearer challenge is working properly. A bad audience is passed in, the service returns
the default audience, and the request gets retried with this default audience, making the call function as expected.
*/
public void audienceErrorBearerChallengeRetry() {
BlockBlobAsyncClient aadBlob = getSpecializedBuilderWithTokenCredential(blockBlobAsyncClient.getBlobUrl())
.audience(BlobAudience.createBlobServiceAccountAudience("badAudience"))
.buildBlockBlobAsyncClient();

StepVerifier.create(aadBlob.exists())
.verifyErrorSatisfies(r -> {
BlobStorageException e = assertInstanceOf(BlobStorageException.class, r);
assertTrue(e.getErrorCode() == BlobErrorCode.INVALID_AUTHENTICATION_INFO);
});
StepVerifier.create(aadBlob.getProperties())
.assertNext(r -> assertNotNull(r))
.verifyComplete();
}

@Test
Expand Down