Search code examples
spring-mvcamazon-s3spring-restclient

Bad Request errors when using Spring RestClient to call AWS S3 predesigned link


I'm trying to make a GET call with the (new) Spring RestClient to an AWS S3 predesigned link.

Example of such link from AWS documentation:

enter image description here

https://examplebucket.s3.us-east-1.amazonaws.com/test.txt ?X-Amz-Algorithm=AWS4-HMAC-SHA256 &X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20130524%2Fus-east-1%2Fs3%2Faws4_request &X-Amz-Date=20200524T000000Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host &X-Amz-Security-Token=IQoJb3JpZ2luX2VjEMv%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJGMEQCIBSUbVdj9YGs2g0HkHsOHFdkwOozjARSKHL987NhhOC8AiBPepRU1obMvIbGU0T%2BWphFPgK%2Fqpxaf5Snvm5M57XFkCqlAgjz%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDQ3MjM4NTU0NDY2MCIM83pULBe5%2F%2BNm1GZBKvkBVslSaJVgwSef7SsoZCJlfJ56weYl3QCwEGr2F4BmCZZyFpmWEYzWnhNK1AnHMj5nkfKlKBx30XAT5PZGVrmq4Vkn9ewlXQy1Iu3QJRi9Tdod8Ef9%2FyajTaUGh76%2BF5u5a4O115jwultOQiKomVwO318CO4l8lv%2F3HhMOkpdanMXn%2B4PY8lvM8RgnzSu90jOUpGXEOAo%2F6G8OqlMim3%2BZmaQmasn4VYRvESEd7O72QGZ3%2BvDnDVnss0lSYjlv8PP7IujnvhZRnj0WoeOyMe1lL0wTG%2Fa9usH5hE52w%2FYUJccOn0OaZuyROuVsRV4Q70sbWQhUvYUt%2B0tUMKzm8vsFOp4BaNZFqobbjtb36Y92v%2Bx5kY6i0s8QE886jJtUWMP5ldMziClGx3p0mN5dzsYlM3GyiJ%2FO1mWkPQDwg3mtSpOA9oeeuAMPTA7qMqy9RNuTKBDSx9EW27wvPzBum3SJhEfxv48euadKgrIX3Z79ruQFSQOc9LUrDjR%2B4SoWAJqK%2BGX8Q3vPSjsLxhqhEMWd6U4TXcM7ku3gxMbzqfT8NDg%3D &X-Amz-Signature=<signature-value>

When using the link as-is (i.e. as a string passed to .uri() method called after restClient.get()) I receive:

[400 Bad Request: "<?xml version="1.0" encoding="UTF-8"?><EOL><Error><Code>AuthorizationQueryParametersError</Code><Message>Error parsing the X-Amz-Credential parameter; the Credential is mal-formed; expecting "&lt;YOUR-AKID&gt;/YYYYMMDD/REGION/SERVICE/aws4_request".</Message>

I tried different things and noticed that passing the value of X-Amz-Credential unencoded (so with slashes instead of %2F), using UriComponentsBuilder with .queryParam() or .replaceQueryParam() methods doesn't cause this error.

However then a new error appears, this time related to X-Amz-Security-Token param:

"<?xml version="1.0" encoding="UTF-8"?><EOL><Error><Code>InvalidToken</Code><Message>The provided token is malformed or otherwise invalid.<Token-0>TOKEN VALUE PRINTED HERE</Token-0></Message>

In this case passing an unencoded value of X-Amz-Security-Token in a similar way doesn't help, the same error occurs.

It seems to me that the problem with X-Amz-Security-Token might be also encoding related, as all the other query params doesn't contain characters that would require encoding and AWS API doesn't complain about them.

However it would be strange that sending encoded query params could cause problems as this is obviously the proper approach. And of course I have no issue with these links when sending the calls using curl or Bruno, I always receive a valid response.

Any idea what might help here?


Solution

  • The problem was indeed encoding related. The right approach in this case was to create an URI object based on the unchanged (i.e. already encoded) predesigned link and use this URI in the Rest Client.

    This can be achieved with:

    UriComponentsBuilder.fromUriString(url).build(true).toUri();
    

    i.e. with passing true to the build() method as the documentation states:

    Params: encoded – whether the components in this builder are already encoded