Skip to content

Commit

Permalink
Refactor bootstrap tests to share setup steps and add prevalidation
Browse files Browse the repository at this point in the history
Signed-off-by: Peter Nied <[email protected]>
  • Loading branch information
peternied committed Jan 4, 2024
1 parent b3b6de7 commit 2f552d3
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@

import java.io.IOException;
import java.nio.file.Path;
import java.time.Duration;
import java.util.List;
import java.util.Map;

import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils;
import org.awaitility.Awaitility;
import org.junit.AfterClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.opensearch.action.admin.cluster.health.ClusterHealthRequest;
import org.opensearch.client.Client;
import org.opensearch.security.securityconf.impl.CType;
import org.opensearch.security.support.ConfigConstants;
import org.opensearch.security.support.ConfigHelper;
Expand All @@ -33,10 +33,14 @@
import org.opensearch.test.framework.cluster.LocalCluster;
import org.opensearch.test.framework.cluster.TestRestClient;

import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.opensearch.security.configuration.ConfigurationRepository.DEFAULT_CONFIG_VERSION;
import static org.opensearch.security.support.ConfigConstants.OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX;
import static org.opensearch.security.support.ConfigConstants.SECURITY_ALLOW_DEFAULT_INIT_SECURITYINDEX;
import static org.opensearch.security.support.ConfigConstants.SECURITY_BACKGROUND_INIT_IF_SECURITYINDEX_NOT_EXIST;
import static org.opensearch.security.support.ConfigConstants.SECURITY_RESTAPI_ROLES_ENABLED;
import static org.opensearch.security.support.ConfigConstants.SECURITY_UNSUPPORTED_DELAY_INITIALIZATION_SECONDS;
import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS;
Expand All @@ -46,90 +50,110 @@
public class SecurityConfigurationBootstrapTests {

private final static Path configurationFolder = ConfigurationFiles.createConfigurationDirectory();

private static final User USER_ADMIN = new User("admin").roles(ALL_ACCESS);

@ClassRule
public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE)
.loadConfigurationIntoIndex(false)
.defaultConfigurationInitDirectory(configurationFolder.toString())
.nodeSettings(
Map.of(
SECURITY_RESTAPI_ROLES_ENABLED,
List.of("user_" + USER_ADMIN.getName() + "__" + ALL_ACCESS.getName()),
SECURITY_ALLOW_DEFAULT_INIT_SECURITYINDEX,
true,
SECURITY_UNSUPPORTED_DELAY_INITIALIZATION_SECONDS,
5
private static LocalCluster createCluster(final Map<String, Object> nodeSettings) {
var cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS)
.loadConfigurationIntoIndex(false)
.defaultConfigurationInitDirectory(configurationFolder.toString())
.nodeSettings(
ImmutableMap.<String, Object>builder()
.put(SECURITY_RESTAPI_ROLES_ENABLED, List.of("user_" + USER_ADMIN.getName() + "__" + ALL_ACCESS.getName()))
.putAll(nodeSettings)
.build()
)
)
.build();
.build();

cluster.before(); // normally invoked by JUnit rules when run as a class rule - this starts the cluster
return cluster;
}

@AfterClass
public static void cleanConfigurationDirectory() throws IOException {
FileUtils.deleteDirectory(configurationFolder.toFile());
}

@Test
public void shouldStillLoadSecurityConfigDuringBootstrapAndActiveConfigUpdateRequests() throws Exception {
cluster.getInternalNodeClient()
.admin()
.cluster()
.health(new ClusterHealthRequest(OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX).waitForGreenStatus())
.actionGet();
Client internalNodeClient = new ContextHeaderDecoratorClient(
cluster.getInternalNodeClient(),
Map.of(ConfigConstants.OPENDISTRO_SECURITY_CONF_REQUEST_HEADER, "true")
);
String cd = System.getProperty("security.default_init.dir") + "/";
ConfigHelper.uploadFile(
internalNodeClient,
cd + "action_groups.yml",
OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX,
CType.ACTIONGROUPS,
DEFAULT_CONFIG_VERSION
);
ConfigHelper.uploadFile(
internalNodeClient,
cd + "config.yml",
OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX,
CType.CONFIG,
DEFAULT_CONFIG_VERSION
);
ConfigHelper.uploadFile(
internalNodeClient,
cd + "roles.yml",
OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX,
CType.ROLES,
DEFAULT_CONFIG_VERSION
);
ConfigHelper.uploadFile(
internalNodeClient,
cd + "tenants.yml",
OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX,
CType.TENANTS,
DEFAULT_CONFIG_VERSION
);
long t = System.currentTimeMillis();
long end = t + 10000;
while (System.currentTimeMillis() < end) {
cluster.triggerConfigurationReloadForCTypes(
internalNodeClient,
List.of(CType.ACTIONGROUPS, CType.CONFIG, CType.ROLES, CType.TENANTS),
true
);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
break;
public void testInitializeWithSecurityAdminWhenNoBackgroundInitialization() throws Exception {
final var nodeSettings = ImmutableMap.<String, Object>builder()
.put(SECURITY_ALLOW_DEFAULT_INIT_SECURITYINDEX, false)
.put(SECURITY_BACKGROUND_INIT_IF_SECURITYINDEX_NOT_EXIST, false)
.build();
try (final LocalCluster cluster = createCluster(nodeSettings)) {
try (final TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
final var rolesMapsResponse = client.get("_plugins/_security/api/rolesmapping/readall");
assertThat(rolesMapsResponse.getStatusCode(), equalTo(SC_SERVICE_UNAVAILABLE));
assertThat(rolesMapsResponse.getBody(), containsString("OpenSearch Security not initialized"));
}

final var securityAdminLauncher = new SecurityAdminLauncher(cluster.getHttpPort(), cluster.getTestCertificates());
final int exitCode = securityAdminLauncher.runSecurityAdmin(configurationFolder);
assertThat(exitCode, equalTo(0));

try (final TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
Awaitility.await()
.alias("Waiting for rolemapping 'readall' availability.")
.until(() -> client.get("_plugins/_security/api/rolesmapping/readall").getStatusCode(), equalTo(200));
}
}
try (TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
Awaitility.await().alias("Load default configuration").until(() -> client.getAuthInfo().getStatusCode(), equalTo(200));
}

@Test
public void shouldStillLoadSecurityConfigDuringBootstrapAndActiveConfigUpdateRequests() throws Exception {
final var nodeSettings = ImmutableMap.<String, Object>builder()
.put(SECURITY_ALLOW_DEFAULT_INIT_SECURITYINDEX, true)
.put(SECURITY_UNSUPPORTED_DELAY_INITIALIZATION_SECONDS, 5)
.build();
try (final LocalCluster cluster = createCluster(nodeSettings)) {
try (final TestRestClient client = cluster.getRestClient(USER_ADMIN)) {
cluster.getInternalNodeClient()
.admin()
.cluster()
.health(new ClusterHealthRequest(OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX).waitForGreenStatus())
.actionGet();

TestRestClient.HttpResponse response = client.getAuthInfo();
// Make sure the cluster is unavalaible to authenticate with the security plugin even though it is green
final var authResponseWhenUnconfigured = client.getAuthInfo();
authResponseWhenUnconfigured.assertStatusCode(503);

response.assertStatusCode(200);
final var internalNodeClient = new ContextHeaderDecoratorClient(
cluster.getInternalNodeClient(),
Map.of(ConfigConstants.OPENDISTRO_SECURITY_CONF_REQUEST_HEADER, "true")
);
final var filesToUpload = ImmutableMap.<String, CType>builder()
.put("action_groups.yml", CType.ACTIONGROUPS)
.put("config.yml", CType.CONFIG)
.put("roles.yml", CType.ROLES)
.put("tenants.yml", CType.TENANTS)
.build();

final String defaultInitDirectory = System.getProperty("security.default_init.dir") + "/";
filesToUpload.forEach((fileName, ctype) -> {
try {
ConfigHelper.uploadFile(
internalNodeClient,
defaultInitDirectory + fileName,
OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX,
ctype,
DEFAULT_CONFIG_VERSION
);
} catch (final Exception ex) {
throw new RuntimeException(ex);
}
});

Awaitility.await().alias("Load default configuration").pollInterval(Duration.ofMillis(100)).until(() -> {
// After the configuration has been loaded, the rest clients should be able to connect successfully
cluster.triggerConfigurationReloadForCTypes(
internalNodeClient,
List.of(CType.ACTIONGROUPS, CType.CONFIG, CType.ROLES, CType.TENANTS),
true
);
try (final TestRestClient freshClient = cluster.getRestClient(USER_ADMIN)) {
return client.getAuthInfo().getStatusCode();
}
}, equalTo(200));
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public String getSnapshotDirPath() {
}

@Override
public void before() throws Throwable {
public void before() {
if (localOpenSearchCluster == null) {
for (LocalCluster dependency : clusterDependencies) {
if (!dependency.isStarted()) {
Expand All @@ -155,12 +155,12 @@ public void before() throws Throwable {

@Override
protected void after() {
System.clearProperty(INIT_CONFIGURATION_DIR);
close();
}

@Override
public void close() {
System.clearProperty(INIT_CONFIGURATION_DIR);
if (localOpenSearchCluster != null && localOpenSearchCluster.isStarted()) {
try {
localOpenSearchCluster.destroy();
Expand Down

0 comments on commit 2f552d3

Please sign in to comment.