|
46 | 46 | import org.elasticsearch.snapshots.SnapshotId; |
47 | 47 | import org.elasticsearch.snapshots.SnapshotsService; |
48 | 48 | import org.elasticsearch.snapshots.mockstore.BlobStoreWrapper; |
| 49 | +import org.elasticsearch.test.ESIntegTestCase; |
49 | 50 | import org.elasticsearch.threadpool.ThreadPool; |
50 | 51 |
|
51 | 52 | import java.io.IOException; |
|
56 | 57 | import java.util.List; |
57 | 58 | import java.util.Map; |
58 | 59 |
|
| 60 | +import static org.hamcrest.Matchers.containsString; |
59 | 61 | import static org.hamcrest.Matchers.greaterThan; |
60 | 62 | import static org.hamcrest.Matchers.lessThan; |
| 63 | +import static org.hamcrest.Matchers.startsWith; |
61 | 64 |
|
62 | 65 | @SuppressForbidden(reason = "this test uses a HttpServer to emulate an S3 endpoint") |
| 66 | +// Need to set up a new cluster for each test because cluster settings use randomized authentication settings |
| 67 | +@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST) |
63 | 68 | public class S3BlobStoreRepositoryTests extends ESMockAPIBasedRepositoryIntegTestCase { |
64 | 69 |
|
65 | 70 | private static final TimeValue TEST_COOLDOWN_PERIOD = TimeValue.timeValueSeconds(5L); |
66 | 71 |
|
| 72 | + private String region; |
| 73 | + private String signerOverride; |
| 74 | + |
| 75 | + @Override |
| 76 | + public void setUp() throws Exception { |
| 77 | + if (randomBoolean()) { |
| 78 | + region = "test-region"; |
| 79 | + } |
| 80 | + if (region != null && randomBoolean()) { |
| 81 | + signerOverride = randomFrom("AWS3SignerType", "AWS4SignerType"); |
| 82 | + } else if (randomBoolean()) { |
| 83 | + signerOverride = "AWS3SignerType"; |
| 84 | + } |
| 85 | + super.setUp(); |
| 86 | + } |
| 87 | + |
67 | 88 | @Override |
68 | 89 | protected String repositoryType() { |
69 | 90 | return S3Repository.TYPE; |
@@ -99,16 +120,23 @@ protected Settings nodeSettings(int nodeOrdinal) { |
99 | 120 | secureSettings.setString(S3ClientSettings.ACCESS_KEY_SETTING.getConcreteSettingForNamespace("test").getKey(), "access"); |
100 | 121 | secureSettings.setString(S3ClientSettings.SECRET_KEY_SETTING.getConcreteSettingForNamespace("test").getKey(), "secret"); |
101 | 122 |
|
102 | | - return Settings.builder() |
| 123 | + final Settings.Builder builder = Settings.builder() |
103 | 124 | .put(ThreadPool.ESTIMATED_TIME_INTERVAL_SETTING.getKey(), 0) // We have tests that verify an exact wait time |
104 | 125 | .put(S3ClientSettings.ENDPOINT_SETTING.getConcreteSettingForNamespace("test").getKey(), httpServerUrl()) |
105 | 126 | // Disable chunked encoding as it simplifies a lot the request parsing on the httpServer side |
106 | 127 | .put(S3ClientSettings.DISABLE_CHUNKED_ENCODING.getConcreteSettingForNamespace("test").getKey(), true) |
107 | 128 | // Disable request throttling because some random values in tests might generate too many failures for the S3 client |
108 | 129 | .put(S3ClientSettings.USE_THROTTLE_RETRIES_SETTING.getConcreteSettingForNamespace("test").getKey(), false) |
109 | 130 | .put(super.nodeSettings(nodeOrdinal)) |
110 | | - .setSecureSettings(secureSettings) |
111 | | - .build(); |
| 131 | + .setSecureSettings(secureSettings); |
| 132 | + |
| 133 | + if (signerOverride != null) { |
| 134 | + builder.put(S3ClientSettings.SIGNER_OVERRIDE.getConcreteSettingForNamespace("test").getKey(), signerOverride); |
| 135 | + } |
| 136 | + if (region != null) { |
| 137 | + builder.put(S3ClientSettings.REGION.getConcreteSettingForNamespace("test").getKey(), region); |
| 138 | + } |
| 139 | + return builder.build(); |
112 | 140 | } |
113 | 141 |
|
114 | 142 | public void testEnforcedCooldownPeriod() throws IOException { |
@@ -190,11 +218,31 @@ void ensureMultiPartUploadSize(long blobSize) { |
190 | 218 | } |
191 | 219 |
|
192 | 220 | @SuppressForbidden(reason = "this test uses a HttpHandler to emulate an S3 endpoint") |
193 | | - private static class S3BlobStoreHttpHandler extends S3HttpHandler implements BlobStoreHttpHandler { |
| 221 | + private class S3BlobStoreHttpHandler extends S3HttpHandler implements BlobStoreHttpHandler { |
194 | 222 |
|
195 | 223 | S3BlobStoreHttpHandler(final String bucket) { |
196 | 224 | super(bucket); |
197 | 225 | } |
| 226 | + |
| 227 | + @Override |
| 228 | + public void handle(final HttpExchange exchange) throws IOException { |
| 229 | + validateAuthHeader(exchange); |
| 230 | + super.handle(exchange); |
| 231 | + } |
| 232 | + |
| 233 | + private void validateAuthHeader(HttpExchange exchange) { |
| 234 | + final String authorizationHeaderV4 = exchange.getRequestHeaders().getFirst("Authorization"); |
| 235 | + final String authorizationHeaderV3 = exchange.getRequestHeaders().getFirst("X-amzn-authorization"); |
| 236 | + |
| 237 | + if ("AWS3SignerType".equals(signerOverride)) { |
| 238 | + assertThat(authorizationHeaderV3, startsWith("AWS3")); |
| 239 | + } else if ("AWS4SignerType".equals(signerOverride)) { |
| 240 | + assertThat(authorizationHeaderV4, containsString("aws4_request")); |
| 241 | + } |
| 242 | + if (region != null && authorizationHeaderV4 != null) { |
| 243 | + assertThat(authorizationHeaderV4, containsString("/" + region + "/s3/")); |
| 244 | + } |
| 245 | + } |
198 | 246 | } |
199 | 247 |
|
200 | 248 | /** |
|
0 commit comments