|  | @@ -0,0 +1,97 @@
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 | 
	
		
			
				|  |  | + * or more contributor license agreements. Licensed under the "Elastic License
 | 
	
		
			
				|  |  | + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
 | 
	
		
			
				|  |  | + * Public License v 1"; you may not use this file except in compliance with, at
 | 
	
		
			
				|  |  | + * your election, the "Elastic License 2.0", the "GNU Affero General Public
 | 
	
		
			
				|  |  | + * License v3.0 only", or the "Server Side Public License, v 1".
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +package org.elasticsearch.repositories.s3;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import fixture.s3.S3HttpFixture;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import org.elasticsearch.client.Request;
 | 
	
		
			
				|  |  | +import org.elasticsearch.client.ResponseException;
 | 
	
		
			
				|  |  | +import org.elasticsearch.common.settings.Settings;
 | 
	
		
			
				|  |  | +import org.elasticsearch.test.ESTestCase;
 | 
	
		
			
				|  |  | +import org.elasticsearch.test.cluster.ElasticsearchCluster;
 | 
	
		
			
				|  |  | +import org.elasticsearch.test.cluster.MutableSettingsProvider;
 | 
	
		
			
				|  |  | +import org.elasticsearch.test.rest.ESRestTestCase;
 | 
	
		
			
				|  |  | +import org.junit.ClassRule;
 | 
	
		
			
				|  |  | +import org.junit.rules.RuleChain;
 | 
	
		
			
				|  |  | +import org.junit.rules.TestRule;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import java.io.IOException;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import static org.hamcrest.CoreMatchers.containsString;
 | 
	
		
			
				|  |  | +import static org.hamcrest.Matchers.allOf;
 | 
	
		
			
				|  |  | +import static org.hamcrest.Matchers.equalTo;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +public class RepositoryS3RestIT extends ESRestTestCase {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private static final String BUCKET = "RepositoryS3JavaRestTest-bucket";
 | 
	
		
			
				|  |  | +    private static final String BASE_PATH = "RepositoryS3JavaRestTest-base-path";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public static final S3HttpFixture s3Fixture = new S3HttpFixture(true, BUCKET, BASE_PATH, "ignored");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private static final MutableSettingsProvider keystoreSettings = new MutableSettingsProvider();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
 | 
	
		
			
				|  |  | +        .module("repository-s3")
 | 
	
		
			
				|  |  | +        .keystore(keystoreSettings)
 | 
	
		
			
				|  |  | +        .setting("s3.client.default.endpoint", s3Fixture::getAddress)
 | 
	
		
			
				|  |  | +        .build();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @ClassRule
 | 
	
		
			
				|  |  | +    public static TestRule ruleChain = RuleChain.outerRule(s3Fixture).around(cluster);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @Override
 | 
	
		
			
				|  |  | +    protected String getTestRestCluster() {
 | 
	
		
			
				|  |  | +        return cluster.getHttpAddresses();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public void testReloadCredentialsFromKeystore() throws IOException {
 | 
	
		
			
				|  |  | +        // Register repository (?verify=false because we don't have access to the blob store yet)
 | 
	
		
			
				|  |  | +        final var repositoryName = randomIdentifier();
 | 
	
		
			
				|  |  | +        registerRepository(
 | 
	
		
			
				|  |  | +            repositoryName,
 | 
	
		
			
				|  |  | +            S3Repository.TYPE,
 | 
	
		
			
				|  |  | +            false,
 | 
	
		
			
				|  |  | +            Settings.builder().put("bucket", BUCKET).put("base_path", BASE_PATH).build()
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +        final var verifyRequest = new Request("POST", "/_snapshot/" + repositoryName + "/_verify");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Set up initial credentials
 | 
	
		
			
				|  |  | +        final var accessKey1 = randomIdentifier();
 | 
	
		
			
				|  |  | +        s3Fixture.setAccessKey(accessKey1);
 | 
	
		
			
				|  |  | +        keystoreSettings.put("s3.client.default.access_key", accessKey1);
 | 
	
		
			
				|  |  | +        keystoreSettings.put("s3.client.default.secret_key", randomIdentifier());
 | 
	
		
			
				|  |  | +        cluster.updateStoredSecureSettings();
 | 
	
		
			
				|  |  | +        assertOK(client().performRequest(new Request("POST", "/_nodes/reload_secure_settings")));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Check access using initial credentials
 | 
	
		
			
				|  |  | +        assertOK(client().performRequest(verifyRequest));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Rotate credentials in blob store
 | 
	
		
			
				|  |  | +        final var accessKey2 = randomValueOtherThan(accessKey1, ESTestCase::randomIdentifier);
 | 
	
		
			
				|  |  | +        s3Fixture.setAccessKey(accessKey2);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Ensure that initial credentials now invalid
 | 
	
		
			
				|  |  | +        final var accessDeniedException2 = expectThrows(ResponseException.class, () -> client().performRequest(verifyRequest));
 | 
	
		
			
				|  |  | +        assertThat(accessDeniedException2.getResponse().getStatusLine().getStatusCode(), equalTo(500));
 | 
	
		
			
				|  |  | +        assertThat(
 | 
	
		
			
				|  |  | +            accessDeniedException2.getMessage(),
 | 
	
		
			
				|  |  | +            allOf(containsString("Bad access key"), containsString("Status Code: 403"), containsString("Error Code: AccessDenied"))
 | 
	
		
			
				|  |  | +        );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Set up refreshed credentials
 | 
	
		
			
				|  |  | +        keystoreSettings.put("s3.client.default.access_key", accessKey2);
 | 
	
		
			
				|  |  | +        cluster.updateStoredSecureSettings();
 | 
	
		
			
				|  |  | +        assertOK(client().performRequest(new Request("POST", "/_nodes/reload_secure_settings")));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // Check access using refreshed credentials
 | 
	
		
			
				|  |  | +        assertOK(client().performRequest(verifyRequest));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 |