All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.services.s3.internal.S3V4AuthErrorRetryStrategy Maven / Gradle / Ivy

Go to download

The AWS SDK for Java with support for OSGi. The AWS SDK for Java provides Java APIs for building software on AWS' cost-effective, scalable, and reliable infrastructure products. The AWS Java SDK allows developers to code against APIs for all of Amazon's infrastructure web services (Amazon S3, Amazon EC2, Amazon SQS, Amazon Relational Database Service, Amazon AutoScaling, etc).

There is a newer version: 1.11.60
Show newest version
/*
 * Copyright 2010-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package com.amazonaws.services.s3.internal;

import java.net.URI;
import java.net.URISyntaxException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.annotation.Immutable;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.Request;
import com.amazonaws.http.HttpResponse;
import com.amazonaws.internal.SdkPredicate;
import com.amazonaws.regions.Regions;
import com.amazonaws.retry.internal.AuthErrorRetryStrategy;
import com.amazonaws.retry.internal.AuthRetryParameters;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.Headers;
import com.amazonaws.services.s3.S3ClientOptions;
import com.amazonaws.util.StringUtils;

/**
 * The internal implementation of AuthErrorRetryStrategy which automatically switches to V4 signer
 * when the S3 returns auth error asking for v4 authentication.
 */
@Immutable
public class S3V4AuthErrorRetryStrategy implements AuthErrorRetryStrategy {

    private static Log log = LogFactory.getLog(S3V4AuthErrorRetryStrategy.class);

    private static final String V4_REGION_WARNING = "please use region-specific endpoint to access "
            + "buckets located in regions that require V4 signing.";

    private final S3RequestEndpointResolver endpointResolver;
    private final SdkPredicate sigV4RetryPredicate;

    public S3V4AuthErrorRetryStrategy(S3RequestEndpointResolver endpointResolver) {
        this(endpointResolver, new IsSigV4RetryablePredicate());
    }

    /**
     * Currently only used for testing
     */
    S3V4AuthErrorRetryStrategy(S3RequestEndpointResolver endpointResolver,
            SdkPredicate isSigV4Retryable) {
        this.endpointResolver = endpointResolver;
        this.sigV4RetryPredicate = isSigV4Retryable;
    }

    @Override
    public AuthRetryParameters shouldRetryWithAuthParam(Request request,
                                                        HttpResponse response,
                                                        AmazonServiceException ase) {
        if (!sigV4RetryPredicate.test(ase)) {
            return null;
        }
        if (hasServingRegionHeader(response)) {
            return redirectToRegionInHeader(request, response);
        } else if (canUseVirtualAddressing()) {
            return redirectToS3External();
        } else {
            throw new AmazonClientException(V4_REGION_WARNING, ase);
        }
    }

    private boolean canUseVirtualAddressing() {
        return BucketNameUtils.isDNSBucketName(endpointResolver.getBucketName());
    }

    private AuthRetryParameters redirectToRegionInHeader(Request request, HttpResponse response) {
        final String region = getServingRegionHeader(response);
        AWSS3V4Signer v4Signer = buildSigV4Signer(region);
        endpointResolver.resolveRequestEndpoint(request, region);
        return buildRetryParams(v4Signer, request.getEndpoint());
    }

    /**
     * If the response doesn't have the x-amz-region header we have to resort to sending a request
     * to s3-external-1
     *
     * @return
     */
    private AuthRetryParameters redirectToS3External() {
        AWSS3V4Signer v4Signer = buildSigV4Signer(Regions.US_EAST_1.getName());
        try {
            URI bucketEndpoint = new URI(
                    String.format("https://%s.s3-external-1.amazonaws.com", endpointResolver.getBucketName()));
            return buildRetryParams(v4Signer, bucketEndpoint);
        } catch (URISyntaxException e) {
            throw new AmazonClientException(
                    "Failed to re-send the request to \"s3-external-1.amazonaws.com\". " + V4_REGION_WARNING, e);
        }
    }

    private AWSS3V4Signer buildSigV4Signer(final String region) {
        AWSS3V4Signer v4Signer = new AWSS3V4Signer();
        v4Signer.setRegionName(region);
        v4Signer.setServiceName(AmazonS3Client.S3_SERVICE_NAME);
        return v4Signer;
    }

    private AuthRetryParameters buildRetryParams(AWSS3V4Signer signer, URI endpoint) {
        log.warn("Attempting to re-send the request to " + endpoint.getHost() + " with AWS V4 authentication. "
                + "To avoid this warning in the future, " + V4_REGION_WARNING);
        return new AuthRetryParameters(signer, endpoint);
    }

    private static boolean hasServingRegionHeader(HttpResponse response) {
        return !StringUtils.isNullOrEmpty(getServingRegionHeader(response));
    }

    private static String getServingRegionHeader(HttpResponse response) {
        return response.getHeaders().get(Headers.S3_SERVING_REGION);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy