Karthik Raj
Karthik Raj

Reputation: 261

Generate a Pre-signed URL Using the AWS SDK for Java

I was following the example from https://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURLJavaSDK.html to create pre-signed s3 urls (v4) and I get Access Denied error when I try to access the signed the url

<Error>
   <Code>AccessDenied</Code>
   <Message>Access Denied</Message>
   <RequestId>0FB02ECDDF5EAC7B</RequestId>
   <HostId>vA+mmsv9PCunNe5uPkPrmpqqN3vFctQ13c9dIRlKWTYsT0zNA1V9g+4YS+lCItrBlyQtdHpyspg=</HostId>
</Error>

The following is the code snippet

public class GeneratePresignedURL {

    public static void main(String[] args) throws IOException {
        String clientRegion = "us-east-1";
        String bucketName = "com-example-bucket";
        String objectKey = "path/to/file.img"; // No leading `/`
        // https://com-example-bucket.s3.amazonaws.com/path/to/file.img

        try { 
            AWSCredentialsProvider awsCredentialsProvider = new DefaultAWSCredentialsProviderChain();

            // Assuming that us-east-1 defaults to v4, couldn't find a way to set it explicitly
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .withRegion(clientRegion)
                    .withCredentials(awsCredentialsProvider)
                    .build();

            // Set the presigned URL to expire after 10 minutes.
            java.util.Date expiration = new java.util.Date();
            long expTimeMillis = expiration.getTime();
            expTimeMillis += 1000 * 60 * 10;
            expiration.setTime(expTimeMillis);

            // Generate the presigned URL.
            System.out.println("Generating pre-signed URL.");
            GeneratePresignedUrlRequest generatePresignedUrlRequest = 
                    new GeneratePresignedUrlRequest(bucketName, objectKey)
                    .withMethod(HttpMethod.GET)
                    .withExpiration(expiration);
            URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);

            System.out.println("Pre-Signed URL: " + url.toString());
            /*
                sample signature:
                https://com-example-bucket.s3.amazonaws.com/path/to/file.img?X-Amz-Security-Token=FQoDYXdzEDcaDLjUOdj2hDTZvWUQaiK3AxulqM%2BOPlp%2Bnq71P0LyuI0vj8tT%2F9i24Wd3jY8dUbudWbhUH9IAsPnl7asujO90GlaFP4dXujDDLwIakMjCJSfOFM4IoGJz8XtcjXkqJCNaenbrTA%2F3PfSl%2Fe9wQwJlY8gOu8%2Byioq2ElHULMKv52nEZj8s3v4dD0pGHQTYc4hGV7ty9CYwXNgz6w3TREhxuFdAewNgTRnY1uFNy7on6NDF5IE15vlJ2PxqrX53ZMLKP%2FdU8i5BcpZ3ySVhNpBpU3GJAPMOh%2B2ztCAk1zPjW4G0N5n9BlnjTMGs3vGBb9IW%2F8dzAoxaG9U9%2B%2FCp8euJN562dYYSZ9wmQgsfOVqc5OksdnHVkPJW400ObOcKmc9mqIRyqA%2B3Mv4z0%2Fx6iLYRJ3UaloFSGbmR6VlIxMl%2F67aHrmCnBE23a1%2BNMWgzLx%2FogqZy3CD%2F%2Fs6Jt1qkxUrRwC0RPK93LHD74qm8rjqZcEKFrBOrZsYtcl3zKgRIEHCbatQ7dwT634sdF0MwaD0vwTsbsStZDW903k5C%2FDuz4rEmkPv6c5CmFvxp4xOkUtMbDk4B8Z641CoeAMMOKICH%2FlW7%2F1as3nQo07Ow2QU%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20180621T214222Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3000&X-Amz-Credential=<access_key>%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=<signature>
            */
        }
        catch(AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process 
            // it, so it returned an error response.
            e.printStackTrace();
        }
        catch(SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}

The signature format seems to be correct and I am not sure if I am missing some other s3 client config. Since I don't get a signature mismatch error or invalid url error, I assume that the Access Key used to sign the url is correct.

Upvotes: 2

Views: 26192

Answers (6)

vaquar khan
vaquar khan

Reputation: 11449

          import com.amazonaws.AmazonServiceException;
          import com.amazonaws.HttpMethod;
          import com.amazonaws.SdkClientException;
          import com.amazonaws.auth.AWSStaticCredentialsProvider;
          import com.amazonaws.auth.BasicAWSCredentials;
          import com.amazonaws.regions.Regions;
          import com.amazonaws.services.s3.AmazonS3;
          import com.amazonaws.services.s3.AmazonS3ClientBuilder;
           import com.amazonaws.services.s3.model.CannedAccessControlList;
           import com.amazonaws.services.s3.model.DeleteObjectRequest;
           import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
           import com.amazonaws.services.s3.model.ObjectListing;
           import com.amazonaws.services.s3.model.S3Object;
           import com.amazonaws.services.s3.model.S3ObjectSummary;




          <dependency>
                <groupId>com.amazonaws</groupId>
                <artifactId>aws-java-sdk</artifactId>
                 <version>1.11.163</version>
         </dependency>


                  String GeneratePresignedUrlAndUploadObject() {

                    String accesskey = "XXXXXXXXXXXXXXXXXXXXXX";
                    String secretkey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
                    String bucketName = "your-bucket-Name";
                    Regions regions = Regions.US_EAST_1;
                    String objecKey = "your-file-name-you-need-url";

                    BasicAWSCredentials awsCreds = new BasicAWSCredentials(accesskey, secretkey);
                    //
                    final AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                            .withCredentials(new AWSStaticCredentialsProvider(awsCreds)).withRegion(regions).build();

                    // Set the expiry time
                    java.util.Date expiration = new java.util.Date();
                    long expTimeMillis = expiration.getTime();
                    expTimeMillis += 1000 * 60 * 60;
                    expiration.setTime(expTimeMillis);

                    GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objecKey)
                            .withMethod(HttpMethod.GET).withExpiration(expiration);
                    //
                    URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
                    System.out.println("Pre-Signed URL: " + url.toString());

                    return url.toString();
                }

Upvotes: 0

anandchaugule
anandchaugule

Reputation: 1127

Here are steps to generate aws-s3 pre-signed url to access the content stored in s3 through java can create with simple step

  1. First add maven dependency in your pom
<dependency>
  <groupId>com.amazonaws</groupId>
  <artifactId>aws-java-sdk-s3</artifactId>
  <version>1.11.870</version>
</dependency>
  1. Get S3 credential accessKey, secretKey, region of s3 storage it must needed
  2. Write java class
  3. First get s3Client connection using below code snippet providing your own credential
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
final AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(new 
AWSStaticCredentialsProvider(awsCreds)).withRegion(region).build();
  1. You must have your bucketName if you don't have create bucket and store your content
  2. Use below code snippet to generate pre-signed url
// Set the expiry time
java.util.Date expiration = new java.util.Date();
long expTimeMillis = expiration.getTime();
expTimeMillis += 1000 * 60 * 60;
expiration.setTime(expTimeMillis);
  1. Pass your objectKey is noting but your existed s3 base filename
GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest(bucketName, objecKey)
.withMethod(HttpMethod.GET)
.withExpiration(expiration);
URL url = s3client.generatePresignedUrl(generatePresignedUrlRequest);
System.out.println("Pre-Signed URL: " + url.toString());

Upvotes: 9

harishanth raveendren
harishanth raveendren

Reputation: 604

Be mindful of assigning the cognito auth-role with access to S3 else the permission will be denied in case you are using the cognito-credentials user pool session to provide the required access to s3client. This was an issue which i was facing as well.

Upvotes: 0

Ramesh
Ramesh

Reputation: 210

Try to add .withPathStyleAccessEnabled(true) as mentioned in below snap.

// Assuming that us-east-1 defaults to v4, couldn't find a way to set it explicitly
       AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                        .withRegion(clientRegion)
                        .withPathStyleAccessEnabled(true)
                        .withCredentials(awsCredentialsProvider)
                        .build();

Change/check this change CROS properties of AWS S3 bucket.

<CORSConfiguration>
 <CORSRule>
   <AllowedOrigin>*</AllowedOrigin>

   <AllowedMethod>PUT</AllowedMethod>
   <AllowedMethod>POST</AllowedMethod>
   <AllowedMethod>DELETE</AllowedMethod>

   <AllowedHeader>*</AllowedHeader>
 </CORSRule>
 <CORSRule>
   <AllowedOrigin>*</AllowedOrigin>
   <AllowedMethod>GET</AllowedMethod>
 </CORSRule>
</CORSConfiguration>

Upvotes: 0

Karthik Raj
Karthik Raj

Reputation: 261

The issue seems to be that the role didn't have permissions to access the s3 bucket path/to/file

Upvotes: 0

Mausam Sharma
Mausam Sharma

Reputation: 892

It is due to the region mismatch. You have set clientRegion to be us-east-1 but if you are accessing it from any other region it will give access denied error. You can only access the object from us-east-1 region or just change it to your region. It's ap-south-1 for Indian clients.

Upvotes: 0

Related Questions