Azure / azure-storage-java

Microsoft Azure Storage Library for Java
https://docs.microsoft.com/en-us/java/api/overview/azure/storage
MIT License
189 stars 163 forks source link

Not able to generate the right SAS from the library version 8.0.0 #515

Open ramanmishra opened 4 years ago

ramanmishra commented 4 years ago

Which service(blob, file, queue, table) does this issue concern?

It is concerned to a private blob so I can't share the information about it. But I am creating the SAS token for the container and using it for azcopy command it is not able to do the Authorization.

Which version of the SDK was used?

Please note that if your issue is with v11, we are recommending customers either move back to v11 or move to v12 (currently in preview) if at all possible. Hopefully this resolves your issue, but if there is some reason why moving away from v11 is not possible at this time, please do continue to ask your question and we will do our best to support you. The README for this SDK has been updated to point to more information on why we have made this decision.

What problem was encountered?

When I am generating the SAS token and using it in the azcopy command it is giving the following error. Signature did not match. String to sign used was racwdl

403 Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature

Have you found a mitigation/solution?

Not yet SAStoken.txt

rickle-msft commented 4 years ago

Hi, @ramanmishra. Thank you for posting this question. The best way to debug this is to capture the body of the failed response (in a network trace, logs, or a debug session) which contains the string to sign used by the service to generate the signature. We can then compare that to the string to sign used by the sdk to see where things are going wrong. Can you try to capture both of those pieces of information and share them here (redacting any sensitive information such as the blob name).

Alternatively, we have recently encountered some problems where a customer is using the SDK to generate a sas but is trying to use the url with the sas attached to download from a browser or a plain HttpUrlConnection rather than through a CloudBlob object. Is this by chance your scenario?

ramanmishra commented 4 years ago

String to signature racwdl 2019-12-29T07:24:41Z 2020-01-05T07:24:16Z /blob/blobname

https 2018-03-28

rickle-msft commented 4 years ago

@ramanmishra Is this the string to sign from the SDK or the one captured from the error message returned from the service? And which ever one it is, can you please capture and share the other one as well?

ramanmishra commented 4 years ago

@rickle-msft This is from the SDK, In error it's not fiving string to sign it just say 403 unauthorized.

rickle-msft commented 4 years ago

@ramanmishra Are you making a HEAD request (getProperties call)? That's the only api that doesn't return a body in the error. Can you try downloading some range or something so that we can get an error response that has a body? That body should contain the string to sign that the service computed and we can determine the difference between them that will highlight the auth failure.

ramanmishra commented 4 years ago

@rickle-msft I am using Azure storage dependeny in my scala code not the api call to get sas token.

rickle-msft commented 4 years ago

@ramanmishra That's fine. It shouldn't matter how you are getting the sas token. What I'm saying is we have tests that demonstrate sas token authentication succeeds if it's configured correctly. Because you are seeing failures, something is not getting configured correctly. The best way to determine the cause of the auth failure is to compare the string to sign generated by the SDK and the string to sign returned by the service in an auth failure. You have provided the string to sign from the client, which is great. Now we need the string to sign returned by the service. The only cases when the service does not return this in the body of the error response is in a HEAD (getProperties) response. If you can trigger an auth failure with your sas token using any other method (like a download) and either capture the body of the network trace or copy the exception message, then we can compare the two string to sign values and figure out what's going wrong.

rickle-msft commented 4 years ago

Just to clarify, when you say that string to sign came from the sdk, are you saying you set a breakpoint in the sas generation code?

ramanmishra commented 4 years ago

Yes exactly, that's what I did.

rickle-msft commented 4 years ago

Ok. So the other piece of information that we need is the error response from the service. Azcopy should be logging this if it is not possible for you to grab it from a network capture tool like Fiddler. If you can provide the string to sign from the error response provided by the service, that will give us a lot of information about where the problem is originating.

vladonemo commented 3 years ago

We are observing the same issue. It appears to be the bug related to the urlEncoding of the blobName.

If a blobName contains e.g. slash (/), it is encoded to %2F in the URL. But the actual character / is used for the signature string. Hence:

This generated URL is wrong: http://localhost:10001/devstoreaccount1/test/location%2Ffile%2Fpackage.txt?sv=2020-08-04&spr=https%2Chttp&se=2021-08-26T09%3A39%3A54Z&sp=r&sig=9jOJgBZ4IlN9lqqSxbr%2FOokuiecVcNqwXxEB1FR%2BiXU%3D&sr=b

After replacing %2F with the /, the file can be downloaded again: http://localhost:10001/devstoreaccount1/test/location/file/package.txt?sv=2020-08-04&spr=https%2Chttp&se=2021-08-26T09%3A39%3A54Z&sp=r&sig=9jOJgBZ4IlN9lqqSxbr%2FOokuiecVcNqwXxEB1FR%2BiXU%3D&sr=b

(I'm using Azurite for this purpose)

vladonemo commented 3 years ago

ignore my previous comment. According to similar issue for .NET sdk, both / and %2F are treated the same by the Azure Blob Storage.

The issue was on our side in the code that tries to download the file. Be careful if you are using Spring's RestTemplate. By calling the new RestTemplate().getForObject(url, String.class) where url is string, the RestTemplate encodes the URL once more. So it will actually call this URL: http://localhost:10001/devstoreaccount1/test/location%252Ffile%252Fpackage.txt?sv=2020-08-04&spr=https%252Chttp&se=2021-08-26T11%253A21%253A19Z&sp=r&sig=d6TkVL5%252Bxfh%252BCz%252BYINx7lMvROerEN83HvBdQ0lW93Vg%253D&sr=b

One should either provide URI argument type (e.g. new RestTemplate().getForObject(new URI(url), String.class)) should set the URI Template Handler to the one that doesn't encode URI.