/* * Copyright 2010-2015 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. * You may obtain a copy of the License at: * * http://aws.amazon.com/apache2.0 * * 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; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import com.amazonaws.AmazonClientException; import com.amazonaws.AmazonWebServiceRequest; import com.amazonaws.Request; import com.amazonaws.auth.AWS4Signer; import com.amazonaws.auth.AnonymousAWSCredentials; import com.amazonaws.auth.Signer; import com.amazonaws.http.HttpMethodName; import com.amazonaws.services.s3.internal.AWSS3V4Signer; import com.amazonaws.services.s3.model.GetObjectRequest; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.lang.reflect.Method; import java.net.URI; /** * A unit test for default singing methods in different regions. */ public class DefaultSigningMethodTest { private static Method CREATE_REQUEST; private static Method EXTRACT_REGION_NAME; private static final String FAKE_BUCKET = "fake-bucket"; private static final String FAKE_KEY = "fake-key"; static { setUpInternalMethods(); } private static void setUpInternalMethods() { try { CREATE_REQUEST = AmazonS3Client.class .getDeclaredMethod("createRequest", String.class, String.class, AmazonWebServiceRequest.class, HttpMethodName.class); CREATE_REQUEST.setAccessible(true); EXTRACT_REGION_NAME = AWS4Signer.class .getDeclaredMethod("extractRegionName", URI.class); EXTRACT_REGION_NAME.setAccessible(true); } catch (Exception e) { fail("Failed to set up the internal methods of AmazonS3Clinet" + e.getMessage()); } } /** Clear system properties */ @Before @After public void clearFlags() { System.clearProperty("com.amazonaws.services.s3.enforceV4"); System.clearProperty("com.amazonaws.services.s3.enableV4"); } /** * Tests that BJS endpoint always defaults to SigV4. */ @Test public void testBJSDefaultSigning() { AmazonS3Client s3 = new AmazonS3Client(); s3.setEndpoint("s3.cn-north-1.amazonaws.com.cn"); assertSigV4WithRegion(s3, "cn-north-1"); // Using any of the system props should not affect the default System.setProperty("com.amazonaws.services.s3.enforceV4", "true"); assertSigV4WithRegion(s3, "cn-north-1"); System.setProperty("com.amazonaws.services.s3.enableV4", "true"); assertSigV4WithRegion(s3, "cn-north-1"); } /** * Tests the behavior when using S3 standard endpoint without providing * region override. */ @Test public void testStandardEndpointWithoutRegionOverride() { AmazonS3Client s3 = new AmazonS3Client(); s3.setEndpoint("s3.amazonaws.com"); // SigV2 by default assertSigV2(s3); // EnforeceV4 is not allowed since no region is specified System.setProperty("com.amazonaws.services.s3.enforceV4", "true"); try { invokeCreateSigner(s3); fail("AmazonClientException is expected since the region is not specified for the request to 's3.amazonaws.com'"); } catch (AmazonClientException expected) { } // EnableV4 should fall back to v2 signing clearFlags(); System.setProperty("com.amazonaws.services.s3.enableV4", "true"); assertSigV2(s3); } /** * Tests the behavior when using S3 standard endpoint with explicit region. */ @Test public void testStandardEndpointWithRegionOverride() { AmazonS3Client s3 = new AmazonS3Client(); // Explicitly setting a regionName, now it defaults to sigv2, but sigv4 // is allowed to be turned on by enforceV4. s3.setEndpoint("s3.amazonaws.com", "s3", "us-west-1"); // Default to SigV2 assertSigV2(s3); // "Enforce" v4 signing should work. System.setProperty("com.amazonaws.services.s3.enforceV4", "true"); assertSigV4WithRegion(s3, "us-west-1"); s3.setEndpoint("s3.amazonaws.com", "s3", "eu-west-1"); assertSigV4WithRegion(s3, "eu-west-1"); // "enableV4" should fall back to SigV2. clearFlags(); System.setProperty("com.amazonaws.services.s3.enableV4", "true"); assertSigV2(s3); } /** * Tests that other endpoints always defaults to SigV2, and can be changed * by system property. */ @Test public void testOtherRegionDefaultSigning() { testSigV4WithRegionDefaultSigning("s3-external-1.amazonaws.com", "us-east-1"); testSigV4WithRegionDefaultSigning("s3-us-west-2.amazonaws.com", "us-west-2"); testSigV4WithRegionDefaultSigning("s3-us-west-1.amazonaws.com", "us-west-1"); testSigV4WithRegionDefaultSigning("s3-eu-west-1.amazonaws.com", "eu-west-1"); testSigV4WithRegionDefaultSigning("s3-ap-southeast-1.amazonaws.com", "ap-southeast-1"); testSigV4WithRegionDefaultSigning("s3-ap-southeast-2.amazonaws.com", "ap-southeast-2"); testSigV4WithRegionDefaultSigning("s3-ap-northeast-1.amazonaws.com", "ap-northeast-1"); testSigV4WithRegionDefaultSigning("s3-sa-east-1.amazonaws.com", "sa-east-1"); } private void testSigV4WithRegionDefaultSigning(String endpoint, String expectedRegionName) { clearFlags(); AmazonS3Client s3 = new AmazonS3Client(); s3.setEndpoint(endpoint); assertSigV4WithRegion(s3, expectedRegionName); // Enforce SigV4 should change the default System.setProperty("com.amazonaws.services.s3.enforceV4", "true"); assertSigV4WithRegion(s3, expectedRegionName); clearFlags(); // Enable SigV4 should also work System.setProperty("com.amazonaws.services.s3.enableV4", "true"); assertSigV4WithRegion(s3, expectedRegionName); } /* * Test utility functions */ /** * Use reflection to call the private method "createSigner" of * AmazonS3Client to create the default signer based on a fake request. * Returns whether the created signer is in SigV4. */ private static void assertSigV4WithRegion(AmazonS3Client s3, String expectedRegion) { Signer signer = invokeCreateSigner(s3); assertTrue(signer instanceof AWSS3V4Signer); assertEquals(expectedRegion, invokeExtractRegionName(s3, (AWSS3V4Signer) signer)); testSignAnonymously(s3); } private static void assertSigV2(AmazonS3Client s3) { Signer signer = invokeCreateSigner(s3); assertFalse(signer instanceof AWSS3V4Signer); } private static Request<?> createFakeGetObjectRequest(AmazonS3Client s3) { try { GetObjectRequest fakeRequest = new GetObjectRequest(FAKE_BUCKET, FAKE_KEY); Request<?> fakeGetObjectRequest = (Request<?>) CREATE_REQUEST.invoke(s3, FAKE_BUCKET, FAKE_KEY, fakeRequest, HttpMethodName.GET); return fakeGetObjectRequest; } catch (Exception e) { fail("Exception when calling the private \"createRequest\" method. " + e.getMessage()); return null; } } private static Signer invokeCreateSigner(AmazonS3Client s3) { Request<?> fakeGetObjectRequest = createFakeGetObjectRequest(s3); return s3.createSigner(fakeGetObjectRequest, FAKE_BUCKET, FAKE_KEY); } private static String invokeExtractRegionName(AmazonS3Client s3, AWSS3V4Signer signer) { try { return (String) EXTRACT_REGION_NAME.invoke(signer, createFakeGetObjectRequest(s3) .getEndpoint()); } catch (Exception e) { fail("Exception when calling the private \"extractRegionName\" method on AWS4Signer. " + e.getMessage()); return null; } } private static void testSignAnonymously(AmazonS3Client s3) { Request<?> fakeGetObjectRequest = createFakeGetObjectRequest(s3); Signer signer = s3.createSigner(fakeGetObjectRequest, FAKE_BUCKET, FAKE_KEY); signer.sign(fakeGetObjectRequest, new AnonymousAWSCredentials()); } }