Caused by: com.azure.storage.blob.models.BlobStorageException: Status code 403, "<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:7502f416-401e-0027-5282-XXXXXXXX
Time:2020-01-07T17:47:36.8721923Z</Message><AuthenticationErrorDetail>The MAC signature found in the HTTP request 'XXXXXXX=' is not the same as any computed signature. Server used following string to sign: 'DELETE
x-ms-client-request-id:XXXXX
x-ms-version:2019-02-02
/XXXX.xls'.</AuthenticationErrorDetail></Error>"
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at com.azure.core.http.rest.RestProxy.instantiateUnexpectedException(RestProxy.java:357)
at com.azure.core.http.rest.RestProxy.lambda$ensureExpectedStatus$3(RestProxy.java:400)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:118)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1630)
at reactor.core.publisher.MonoProcessor.onNext(MonoProcessor.java:317)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1630)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:144)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1630)
at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:144)
at reactor.core.publisher.FluxReplay$UnboundedReplayBuffer.replayNormal(FluxReplay.java:551)
at reactor.core.publisher.FluxReplay$UnboundedReplayBuffer.replay(FluxReplay.java:654)
at reactor.core.publisher.FluxReplay.subscribeOrReturn(FluxReplay.java:1096)
at reactor.core.publisher.FluxReplay.subscribe(FluxReplay.java:1064)
at reactor.core.publisher.FluxAutoConnectFuseable.subscribe(FluxAutoConnectFuseable.java:60)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:55)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.Mono.subscribe(Mono.java:4105)
at reactor.core.publisher.MonoProcessor.add(MonoProcessor.java:457)
at reactor.core.publisher.MonoProcessor.subscribe(MonoProcessor.java:370)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:55)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1630)
at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:144)
at reactor.core.publisher.FluxReplay$UnboundedReplayBuffer.replayNormal(FluxReplay.java:551)
at reactor.core.publisher.FluxReplay$UnboundedReplayBuffer.replay(FluxReplay.java:654)
at reactor.core.publisher.FluxReplay$ReplaySubscriber.onComplete(FluxReplay.java:1218)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onComplete(MonoFlatMapMany.java:252)
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136)
at reactor.core.publisher.FluxFilter$FilterSubscriber.onComplete(FluxFilter.java:160)
at reactor.core.publisher.FluxTakeUntil$TakeUntilPredicateSubscriber.onComplete(FluxTakeUntil.java:114)
at reactor.core.publisher.FluxTakeUntil$TakeUntilPredicateSubscriber.onNext(FluxTakeUntil.java:92)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114)
at reactor.core.publisher.FluxRepeatPredicate$RepeatPredicateSubscriber.onNext(FluxRepeatPredicate.java:79)
at reactor.core.publisher.FluxJust$WeakScalarSubscription.request(FluxJust.java:99)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:1994)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:1868)
at reactor.core.publisher.FluxJust.subscribe(FluxJust.java:70)
at reactor.core.publisher.FluxRepeatPredicate$RepeatPredicateSubscriber.resubscribe(FluxRepeatPredicate.java:113)
at reactor.core.publisher.FluxRepeatPredicate.subscribeOrReturn(FluxRepeatPredicate.java:49)
at reactor.core.publisher.Flux.subscribe(Flux.java:8129)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onNext(MonoFlatMapMany.java:188)
at reactor.core.publisher.MonoUsing$MonoUsingSubscriber.onNext(MonoUsing.java:229)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2186)
at reactor.core.publisher.MonoUsing$MonoUsingSubscriber.request(MonoUsing.java:175)
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onSubscribe(MonoFlatMapMany.java:134)
at reactor.core.publisher.MonoUsing$MonoUsingSubscriber.onSubscribe(MonoUsing.java:205)
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54)
at reactor.core.publisher.MonoUsing.subscribe(MonoUsing.java:102)
at reactor.core.publisher.FluxFromMonoOperator.subscribe(FluxFromMonoOperator.java:73)
at reactor.core.publisher.FluxReplay.connect(FluxReplay.java:1057)
at reactor.core.publisher.FluxAutoConnectFuseable.subscribe(FluxAutoConnectFuseable.java:62)
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:55)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1630)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:144)
at reactor.core.publisher.FluxDelaySubscription$DelaySubscriptionMainSubscriber.onNext(FluxDelaySubscription.java:180)
at reactor.core.publisher.SerializedSubscriber.onNext(SerializedSubscriber.java:89)
at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.onNext(FluxTimeout.java:173)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1630)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:144)
at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:156)
at com.azure.core.http.okhttp.OkHttpAsyncHttpClient$OkHttpCallback.onResponse(OkHttpAsyncHttpClient.java:172)
at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:93)
at reactor.core.publisher.Mono.block(Mono.java:1663)
at com.azure.storage.common.implementation.StorageImplUtils.blockWithOptionalTimeout(StorageImplUtils.java:94)
at com.azure.storage.blob.specialized.BlobClientBase.deleteWithResponse(BlobClientBase.java:521)
at com.azure.storage.blob.specialized.BlobClientBase.delete(BlobClientBase.java:495)
To Reproduce
blobContainerClient.getBlobClient(blob).delete();
@Tetradeus thank you for reporting this issue. Can you please clarify a couple points:
Are you specifying ok-http in your issue because it works with the netty client but fails with the ok-http client?
Are you authenticating with a shared key or with a sas token?
To be honest, I have not tested it with the netty client yet. I tried to use this library with netty in an azure function, and because of an older netty lib version in azure function java, it cannot even be used ... So yes, for the moment I had this issue only with okhttp client.
I am authenticating with a shared key. It worked for creation and reading.
@joshfree FYI the dependency issue with azure function. Perhaps we should in some way try to get the two products on the same version so they can be used together?
Thank you for that information. It is quite curious that a shared key would be hitting an auth failure at all, let alone in a specific method like this. Can you please set a break point in the buildStringToSign method in StorageSharedKeyCredential type and capture the string to sign the client is generating. We need to compare that to the value you already shared and see what's going wrong.
Hello @rickle-msft @joshfree,
From my point of view we should be able to use any version of the lib on azure function:
I checked the difference we have between both string used to sign :
DELETE string used to sign:
"DELETE\n\n\n\n\n\nThu, 16 Jan 2020 11:26:18 GMT\n\n\n\n\n\nx-ms-client-request-id:3dbf75d2-14c1-43ce-91ba-10fa5041fdfe\nx-ms-version:2019-02-02\n/secretaccount/etl/tetra%2Fto_process%2FBook1.xls"
Error is
The MAC signature found in the HTTP request 'XXXXX' is not the same as any computed signature. Server used following string to sign: 'DELETE
x-ms-client-request-id:3dbf75d2-14c1-43ce-91ba-10fa5041fdfe
x-ms-version:2019-02-02
/secretaccount/etl/tetra%2Fto_process%2FBook1.xls'.</AuthenticationErrorDetail></Error>"
We could easily see that the header "application/octet-stream" is sent but not included in the string to sign => Please remove that header or add it to the string to sign.
Thanks
@Tetradeus I agree with your thoughts on version compatibility. Josh's team manages the dependencies for the whole repo including storage, though, so he will have to follow up that. It may be worth creating a separate issue to track that specifically.
As for the string to sign error, you are right that the difference is the presence of application/octent-stream. It seems it is not there when we compute the string to sign but is added sometime after the credential policy. @alzimmermsft Is it possible that the okhttp client sets a default value for Content-Type if none is set, so it's being implicitly added after we sign the request?
@Tetradeus My understanding is that the best way around the dependency issue is to use a shaded jar. You can find more information about this in our wiki: https://github.com/Azure/azure-sdk-for-java/wiki/Creating-a-Shaded-Jar
#7229 may also include some useful information for the dependency issue.
As @rickle-msft pointed our OkHttpClient is setting a default Content-Type after the signing operation. We will need to update the OkHttpClient to not to do that. A temporary solution is to remove the application/octet-stream Content-Type header through OkHttp interceptor as shown in the following code. To be safe it removes only for DELETE|GET verbs. Sorry, I know this is not clean solution but a workaround until we fix our OkHttpClient.
Example code to remove Content-Type
option-1 Use OkHttp interceptor
import com.azure.core.http.HttpClient;
import com.azure.core.http.okhttp.OkHttpAsyncHttpClientBuilder;
import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobContainerClient;
import com.azure.storage.blob.BlobServiceClient;
import com.azure.storage.blob.BlobServiceClientBuilder;
import okhttp3.Request;
public class App {
public static void main(String[] args) {
final String connectionString = "<STORAGE_CONNECTION_STRING>";
final String containerName = "<CONTAINER_NAME>";
final String localFilePath = "<PATH_TO_LOCAL_FILE_TO_UPLOAD>";
HttpClient httpClient = new OkHttpAsyncHttpClientBuilder()
.addNetworkInterceptor(chain -> {
if (chain.request().method().equalsIgnoreCase("DELETE")
|| chain.request().method().equalsIgnoreCase("GET")) {
String contentType = chain.request().header("Content-Type");
if (contentType != null
&& contentType.equalsIgnoreCase("application/octet-stream")) {
Request updatedRequest = chain.request().newBuilder()
.removeHeader("Content-Type")
.build();
return chain.proceed(updatedRequest);
return chain.proceed(chain.request());
.build();
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
.httpClient(httpClient)
.connectionString(connectionString)
.buildClient();
BlobContainerClient blobContainerClient = blobServiceClient
.getBlobContainerClient(containerName);
BlobClient blobClient = blobContainerClient
.getBlobClient("myblob");
System.out.println("uploading blob...");
blobClient.uploadFromFile(localFilePath, true);
System.out.println("Blob uploaded...");
System.out.println("Deleting blob...");
blobClient.delete();
System.out.println("Blob deleted...");
option-2 Use Azure SDK Policy
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
.addPolicy((callContext, nextPolicy) -> {
HttpHeaders headers = callContext.getHttpRequest().getHeaders();
String contentType = headers.getValue("Content-Type");
if (contentType == null) {
callContext.getHttpRequest().setHeader("Content-Type", "");
return nextPolicy.process();
.connectionString(connectionString)
.buildClient();
Note: in this case, no need to pass HttpClient .httpClient(httpClient) since we're not configuring anything in OkHttpClient level.
pom.xml
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-core-http-okhttp</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-storage-blob</artifactId>
<version>12.3.0</version>
<exclusions>
<exclusion>
<groupId>com.azure</groupId>
<artifactId>azure-core-http-netty</artifactId>
</exclusion>
</exclusions>
</dependency>
customer-reported
Issues that are reported by GitHub users external to the Azure organization.
Storage
Storage Service (Queues, Blobs, Files)