Interface S3Presigner

  • All Superinterfaces:
    AutoCloseable, SdkAutoCloseable, SdkPresigner
    All Known Implementing Classes:
    DefaultS3Presigner

    @Immutable
    @ThreadSafe
    public interface S3Presigner
    extends SdkPresigner
    Enables signing an S3 SdkRequest so that it can be executed without requiring any additional authentication on the part of the caller.

    For example: if Alice has access to an S3 object, and she wants to temporarily share access to that object with Bob, she can generate a pre-signed GetObjectRequest to secure share with Bob so that he can download the object without requiring access to Alice's credentials.

    Signature Duration

    Pre-signed requests are only valid for a finite period of time, referred to as the signature duration. This signature duration is configured when the request is generated, and cannot be longer than 7 days. Attempting to generate a signature longer than 7 days in the future will fail at generation time. Attempting to use a pre-signed request after the signature duration has passed will result in an access denied response from the service.

    Example Usage

     
         // Create an S3Presigner using the default region and credentials.
         // This is usually done at application startup, because creating a presigner can be expensive.
         S3Presigner presigner = S3Presigner.create();
    
         // Create a GetObjectRequest to be pre-signed
         GetObjectRequest getObjectRequest =
                 GetObjectRequest.builder()
                                 .bucket("my-bucket")
                                 .key("my-key")
                                 .build();
    
         // Create a GetObjectPresignRequest to specify the signature duration
         GetObjectPresignRequest getObjectPresignRequest =
             GetObjectPresignRequest.builder()
                                    .signatureDuration(Duration.ofMinutes(10))
                                    .getObjectRequest(getObjectRequest)
                                    .build();
    
         // Generate the presigned request
         PresignedGetObjectRequest presignedGetObjectRequest =
             presigner.presignGetObject(getObjectPresignRequest);
    
         // Log the presigned URL, for example.
         System.out.println("Presigned URL: " + presignedGetObjectRequest.url());
    
         // It is recommended to close the S3Presigner when it is done being used, because some credential
         // providers (e.g. if your AWS profile is configured to assume an STS role) require system resources
         // that need to be freed. If you are using one S3Presigner per application (as recommended), this
         // usually is not needed.
         presigner.close();
     
     

    Browser Compatibility

    Some pre-signed requests can be executed by a web browser. These "browser compatible" pre-signed requests do not require the customer to send anything other than a "host" header when performing an HTTP GET against the pre-signed URL.

    Whether a pre-signed request is "browser compatible" can be determined by checking the PresignedRequest.isBrowserExecutable() flag. It is recommended to always check this flag when the pre-signed request needs to be executed by a browser, because some request fields will result in the pre-signed request not being browser-compatible.

    Configurations that affect browser compatibility

    Enabling Checking Validation

    If checksum validations are enabled, the presigned URL will no longer be browser compatible because it adds a signed header that must be included in the HTTP request. Checksum validation is disabled in the presigner by default, but when using a custom S3Configuration when enabling features like path style access or accelerate mode, it must be explicitly disabled:
             S3Presigner presigner = S3Presigner.builder()
                                                .serviceConfiguration(S3Configuration.builder()
                                                                                     .checksumValidationEnabled(false)
                                                                                     .build())
                                                .build();
     

    Executing a Pre-Signed Request from Java code

    Browser-compatible requests (see above) can be executed using a web browser. All pre-signed requests can be executed from Java code. This documentation describes two methods for executing a pre-signed request: (1) using the JDK's URLConnection class, (2) using an SDK synchronous SdkHttpClient class.

    Using {code URLConnection}:

         // Create a pre-signed request using one of the "presign" methods on S3Presigner
         PresignedRequest presignedRequest = ...;
    
         // Create a JDK HttpURLConnection for communicating with S3
         HttpURLConnection connection = (HttpURLConnection) presignedRequest.url().openConnection();
    
         // Specify any headers that are needed by the service (not needed when isBrowserExecutable is true)
         presignedRequest.httpRequest().headers().forEach((header, values) -> {
             values.forEach(value -> {
                 connection.addRequestProperty(header, value);
             });
         });
    
         // Send any request payload that is needed by the service (not needed when isBrowserExecutable is true)
         if (presignedRequest.signedPayload().isPresent()) {
             connection.setDoOutput(true);
             try (InputStream signedPayload = presignedRequest.signedPayload().get().asInputStream();
                  OutputStream httpOutputStream = connection.getOutputStream()) {
                 IoUtils.copy(signedPayload, httpOutputStream);
             }
         }
    
         // Download the result of executing the request
         try (InputStream content = connection.getInputStream()) {
             System.out.println("Service returned response: ");
             IoUtils.copy(content, System.out);
         }
     

    Using {code SdkHttpClient}:

         // Create a pre-signed request using one of the "presign" methods on S3Presigner
         PresignedRequest presignedRequest = ...;
    
         // Create an SdkHttpClient using one of the implementations provided by the SDK
         SdkHttpClient httpClient = ApacheHttpClient.builder().build(); // or UrlConnectionHttpClient.create()
    
         // Specify any request payload that is needed by the service (not needed when isBrowserExecutable is true)
         ContentStreamProvider requestPayload =
             presignedRequest.signedPayload()
                             .map(SdkBytes::asContentStreamProvider)
                             .orElse(null);
    
         // Create the request for sending to the service
         HttpExecuteRequest request =
             HttpExecuteRequest.builder()
                               .request(presignedRequest.httpRequest())
                               .contentStreamProvider(requestPayload)
                               .build();
    
         // Call the service
         HttpExecuteResponse response = httpClient.prepareRequest(request).call();
    
         // Download the result of executing the request
         if (response.responseBody().isPresent()) {
             try (InputStream responseStream = response.responseBody().get()) {
                 System.out.println("Service returned response: ");
                 IoUtils.copy(content, System.out);
             }
         }