Integ test snapshot and restore for native realm (#39123)

This commit adds a simple integ test that exercises the flow:
* snapshot .security
* delete .security
* restore .security

, checking that the Native Realm works as expected.

Relates #34454
This commit is contained in:
Albert Zaharovits 2019-02-28 14:40:16 +02:00 committed by Albert Zaharovits
parent 30e5c11cc2
commit 8a19d981db
1 changed files with 71 additions and 0 deletions

View File

@ -8,6 +8,8 @@ package org.elasticsearch.xpack.security.authc.esnative;
import org.apache.lucene.util.CollectionUtil; import org.apache.lucene.util.CollectionUtil;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.action.support.PlainActionFuture;
@ -17,7 +19,10 @@ import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.snapshots.SnapshotInfo;
import org.elasticsearch.snapshots.SnapshotState;
import org.elasticsearch.test.NativeRealmIntegTestCase; import org.elasticsearch.test.NativeRealmIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.SecuritySettingsSourceField; import org.elasticsearch.test.SecuritySettingsSourceField;
@ -46,6 +51,7 @@ import org.elasticsearch.xpack.core.security.user.KibanaUser;
import org.elasticsearch.xpack.core.security.user.SystemUser; import org.elasticsearch.xpack.core.security.user.SystemUser;
import org.elasticsearch.xpack.core.security.user.User; import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.security.authz.store.NativeRolesStore; import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -58,12 +64,14 @@ import java.util.Optional;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoTimeout;
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME; import static org.elasticsearch.xpack.security.support.SecurityIndexManager.SECURITY_INDEX_NAME;
import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_SECURITY_INDEX; import static org.elasticsearch.xpack.security.support.SecurityIndexManager.INTERNAL_SECURITY_INDEX;
import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
@ -379,6 +387,69 @@ public class NativeRealmIntegTests extends NativeRealmIntegTestCase {
} }
} }
public void testSnapshotDeleteRestore() {
logger.error("--> creating role");
securityClient().preparePutRole("test_role")
.cluster("all")
.addIndices(new String[]{"*"}, new String[]{"create_index"}, null, null, null, true)
.get();
logger.error("--> creating user");
securityClient().preparePutUser("joe", "s3krit".toCharArray(), hasher, "test_role", "snapshot_user").get();
logger.error("--> waiting for .security index");
ensureGreen(SECURITY_INDEX_NAME);
logger.info("--> creating repository");
assertAcked(client().admin().cluster()
.preparePutRepository("test-repo")
.setType("fs").setSettings(Settings.builder()
.put("location", randomRepoPath())
.put("compress", randomBoolean())
.put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES)));
final String token = basicAuthHeaderValue("joe", new SecureString("s3krit".toCharArray()));
// joe can snapshot all indices, including '.security'
SnapshotInfo snapshotInfo = client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin().cluster()
.prepareCreateSnapshot("test-repo", "test-snap-1")
.setWaitForCompletion(true)
.setIncludeGlobalState(false)
.setIndices(SECURITY_INDEX_NAME)
.get().getSnapshotInfo();
assertThat(snapshotInfo.state(), is(SnapshotState.SUCCESS));
assertThat(snapshotInfo.indices(), contains(SecurityIndexManager.INTERNAL_SECURITY_INDEX));
deleteSecurityIndex();
// the realm cache should clear itself but we don't wish to race it
securityClient().prepareClearRealmCache().get();
// authn fails
final ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, () -> client()
.filterWithHeader(Collections.singletonMap("Authorization", token)).admin().indices().prepareCreate("idx").get());
assertThat(e.status(), is(RestStatus.UNAUTHORIZED));
// users and roles are missing
GetUsersResponse getUsersResponse = securityClient().prepareGetUsers("joe").get();
assertThat(getUsersResponse.users().length, is(0));
GetRolesResponse getRolesResponse = securityClient().prepareGetRoles("test_role").get();
assertThat(getRolesResponse.roles().length, is(0));
// restore
RestoreSnapshotResponse response = client().admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap-1")
.setWaitForCompletion(true).setIncludeAliases(true).get();
assertThat(response.status(), equalTo(RestStatus.OK));
assertThat(response.getRestoreInfo().indices(), contains(SecurityIndexManager.INTERNAL_SECURITY_INDEX));
// the realm cache should clear itself but we don't wish to race it
securityClient().prepareClearRealmCache().get();
// users and roles are retrievable
getUsersResponse = securityClient().prepareGetUsers("joe").get();
assertThat(getUsersResponse.users().length, is(1));
assertThat(Arrays.asList(getUsersResponse.users()[0].roles()), contains("test_role", "snapshot_user"));
getRolesResponse = securityClient().prepareGetRoles("test_role").get();
assertThat(getRolesResponse.roles().length, is(1));
assertThat(Arrays.asList(getRolesResponse.roles()[0].getClusterPrivileges()), contains("all"));
assertThat(getRolesResponse.roles()[0].getIndicesPrivileges().length, is(1));
assertThat(Arrays.asList(getRolesResponse.roles()[0].getIndicesPrivileges()[0].getPrivileges()), contains("create_index"));
assertThat(Arrays.asList(getRolesResponse.roles()[0].getIndicesPrivileges()[0].getIndices()), contains("*"));
// joe can create indices
CreateIndexResponse createIndexResponse = client().filterWithHeader(Collections.singletonMap("Authorization", token)).admin()
.indices().prepareCreate("idx").get();
assertThat(createIndexResponse.isAcknowledged(), is (true));
assertAcked(client().admin().cluster().prepareDeleteRepository("test-repo"));
}
public void testAuthenticateWithDeletedRole() { public void testAuthenticateWithDeletedRole() {
SecurityClient c = securityClient(); SecurityClient c = securityClient();
logger.error("--> creating role"); logger.error("--> creating role");