Skip to content

Commit

Permalink
Fix cluster default initialization Part 1 (opensearch-project#4002)
Browse files Browse the repository at this point in the history
Signed-off-by: Andrey Pleskach <[email protected]>
  • Loading branch information
willyborankin authored Mar 27, 2024
1 parent dc8bd61 commit b0d26dd
Show file tree
Hide file tree
Showing 20 changed files with 1,930 additions and 94 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,7 @@ dependencies {

//OpenSAML
implementation 'net.shibboleth.utilities:java-support:8.4.1'
runtimeOnly "io.dropwizard.metrics:metrics-core:4.2.15"
implementation "com.onelogin:java-saml:${one_login_java_saml}"
implementation "com.onelogin:java-saml-core:${one_login_java_saml}"
implementation "org.opensaml:opensaml-core:${open_saml_version}"
Expand All @@ -638,7 +639,6 @@ dependencies {
runtimeOnly 'com.google.j2objc:j2objc-annotations:2.8'
compileOnly 'com.google.code.findbugs:jsr305:3.0.2'
runtimeOnly 'org.lz4:lz4-java:1.8.0'
runtimeOnly 'io.dropwizard.metrics:metrics-core:4.2.25'
runtimeOnly 'org.slf4j:slf4j-api:1.7.36'
runtimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:${versions.log4j}"
runtimeOnly 'org.xerial.snappy:snappy-java:1.1.10.5'
Expand Down Expand Up @@ -699,12 +699,12 @@ dependencies {
exclude(group:'org.springframework', module: 'spring-jcl' )
}
testRuntimeOnly 'org.scala-lang:scala-library:2.13.13'
testRuntimeOnly 'com.yammer.metrics:metrics-core:2.2.0'
testRuntimeOnly 'com.typesafe.scala-logging:scala-logging_3:3.9.5'
testRuntimeOnly('org.apache.zookeeper:zookeeper:3.9.2') {
exclude(group:'ch.qos.logback', module: 'logback-classic' )
exclude(group:'ch.qos.logback', module: 'logback-core' )
}
testRuntimeOnly 'com.yammer.metrics:metrics-core:2.2.0'
testRuntimeOnly "org.apache.kafka:kafka-metadata:${kafka_version}"
testRuntimeOnly "org.apache.kafka:kafka-storage:${kafka_version}"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.security;

import java.io.IOException;
Expand All @@ -19,47 +19,39 @@
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.io.FileUtils;
import org.apache.http.HttpStatus;
import org.awaitility.Awaitility;
import org.junit.AfterClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.opensearch.test.framework.TestSecurityConfig.User;
import org.opensearch.test.framework.cluster.ClusterManager;
import org.opensearch.security.state.SecurityMetadata;
import org.opensearch.test.framework.TestSecurityConfig;
import org.opensearch.test.framework.cluster.LocalCluster;
import org.opensearch.test.framework.cluster.TestRestClient;
import org.opensearch.test.framework.cluster.TestRestClient.HttpResponse;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.aMapWithSize;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class)
@ThreadLeakScope(ThreadLeakScope.Scope.NONE)
public class DefaultConfigurationTests {

private final static Path configurationFolder = ConfigurationFiles.createConfigurationDirectory();
private static final User ADMIN_USER = new User("admin");
private static final User NEW_USER = new User("new-user");
private static final User LIMITED_USER = new User("limited-user");

@ClassRule
public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE)
.nodeSettings(
Map.of(
"plugins.security.allow_default_init_securityindex",
true,
"plugins.security.restapi.roles_enabled",
List.of("user_admin__all_access")
)
)
.defaultConfigurationInitDirectory(configurationFolder.toString())
.loadConfigurationIntoIndex(false)
.build();
public abstract class AbstractDefaultConfigurationTests {
public final static Path configurationFolder = ConfigurationFiles.createConfigurationDirectory();
private static final TestSecurityConfig.User ADMIN_USER = new TestSecurityConfig.User("admin");
private static final TestSecurityConfig.User NEW_USER = new TestSecurityConfig.User("new-user");
private static final TestSecurityConfig.User LIMITED_USER = new TestSecurityConfig.User("limited-user");

private final LocalCluster cluster;

protected AbstractDefaultConfigurationTests(LocalCluster cluster) {
this.cluster = cluster;
}

@AfterClass
public static void cleanConfigurationDirectory() throws IOException {
Expand All @@ -73,18 +65,43 @@ public void shouldLoadDefaultConfiguration() {
}
try (TestRestClient client = cluster.getRestClient(ADMIN_USER)) {
client.confirmCorrectCredentials(ADMIN_USER.getName());
HttpResponse response = client.get("_plugins/_security/api/internalusers");
response.assertStatusCode(200);
TestRestClient.HttpResponse response = client.get("_plugins/_security/api/internalusers");
response.assertStatusCode(HttpStatus.SC_OK);
Map<String, Object> users = response.getBodyAs(Map.class);
assertThat(
response.getBody(),
users,
allOf(aMapWithSize(3), hasKey(ADMIN_USER.getName()), hasKey(NEW_USER.getName()), hasKey(LIMITED_USER.getName()))
);
}
}

void assertClusterState(final TestRestClient client) {
if (cluster.node().settings().getAsBoolean("plugins.security.allow_default_init_securityindex.use_cluster_state", false)) {
final TestRestClient.HttpResponse response = client.get("_cluster/state");
response.assertStatusCode(HttpStatus.SC_OK);
final var clusterState = response.getBodyAs(Map.class);
assertTrue(response.getBody(), clusterState.containsKey(SecurityMetadata.TYPE));
@SuppressWarnings("unchecked")
final var securityClusterState = (Map<String, Object>) clusterState.get(SecurityMetadata.TYPE);
@SuppressWarnings("unchecked")
final var securityConfiguration = (Map<String, Object>) ((Map<?, ?>) clusterState.get(SecurityMetadata.TYPE)).get(
"configuration"
);
assertTrue(response.getBody(), securityClusterState.containsKey("created"));
assertNotNull(response.getBody(), securityClusterState.get("created"));

for (final var k : securityConfiguration.keySet()) {
@SuppressWarnings("unchecked")
final var sc = (Map<String, Object>) securityConfiguration.get(k);
assertTrue(response.getBody(), sc.containsKey("hash"));
assertTrue(response.getBody(), sc.containsKey("last_modified"));
}
}
}

@Test
public void securityRolesUgrade() throws Exception {
public void securityRolesUpgrade() throws Exception {
try (var client = cluster.getRestClient(ADMIN_USER)) {
// Setup: Make sure the config is ready before starting modifications
Awaitility.await().alias("Load default configuration").until(() -> client.getAuthInfo().getStatusCode(), equalTo(200));
Expand Down Expand Up @@ -159,4 +176,5 @@ private Set<String> extractFieldNames(final JsonNode json) {
json.fieldNames().forEachRemaining(set::add);
return set;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.security;

import java.util.List;
import java.util.Map;

import org.junit.ClassRule;

import org.opensearch.test.framework.cluster.ClusterManager;
import org.opensearch.test.framework.cluster.LocalCluster;

public class DefaultConfigurationMultiNodeClusterTests extends AbstractDefaultConfigurationTests {

@ClassRule
public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS)
.nodeSettings(
Map.of(
"plugins.security.allow_default_init_securityindex",
true,
"plugins.security.restapi.roles_enabled",
List.of("user_admin__all_access")
)
)
.defaultConfigurationInitDirectory(configurationFolder.toString())
.loadConfigurationIntoIndex(false)
.build();

public DefaultConfigurationMultiNodeClusterTests() {
super(cluster);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.security;

import java.util.List;
import java.util.Map;

import org.junit.ClassRule;

import org.opensearch.test.framework.cluster.ClusterManager;
import org.opensearch.test.framework.cluster.LocalCluster;

public class DefaultConfigurationMultiNodeClusterUseClusterStateTests extends AbstractDefaultConfigurationTests {

@ClassRule
public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS)
.nodeSettings(
Map.of(
"plugins.security.allow_default_init_securityindex",
true,
"plugins.security.allow_default_init_securityindex.use_cluster_state",
true,
"plugins.security.restapi.roles_enabled",
List.of("user_admin__all_access")
)
)
.defaultConfigurationInitDirectory(configurationFolder.toString())
.loadConfigurationIntoIndex(false)
.build();

public DefaultConfigurationMultiNodeClusterUseClusterStateTests() {
super(cluster);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.security;

import java.util.List;
import java.util.Map;

import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
import org.junit.ClassRule;
import org.junit.runner.RunWith;

import org.opensearch.test.framework.cluster.ClusterManager;
import org.opensearch.test.framework.cluster.LocalCluster;

@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class)
@ThreadLeakScope(ThreadLeakScope.Scope.NONE)
public class DefaultConfigurationSingleNodeClusterTests extends AbstractDefaultConfigurationTests {

@ClassRule
public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE)
.nodeSettings(
Map.of(
"plugins.security.allow_default_init_securityindex",
true,
"plugins.security.restapi.roles_enabled",
List.of("user_admin__all_access")
)
)
.defaultConfigurationInitDirectory(configurationFolder.toString())
.loadConfigurationIntoIndex(false)
.build();

public DefaultConfigurationSingleNodeClusterTests() {
super(cluster);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/
package org.opensearch.security;

import java.util.List;
import java.util.Map;

import org.junit.ClassRule;

import org.opensearch.test.framework.cluster.ClusterManager;
import org.opensearch.test.framework.cluster.LocalCluster;

public class DefaultConfigurationSingleNodeClusterUseClusterStateTests extends AbstractDefaultConfigurationTests {

@ClassRule
public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.SINGLENODE)
.nodeSettings(
Map.of(
"plugins.security.allow_default_init_securityindex",
true,
"plugins.security.allow_default_init_securityindex.use_cluster_state",
true,
"plugins.security.restapi.roles_enabled",
List.of("user_admin__all_access")
)
)
.defaultConfigurationInitDirectory(configurationFolder.toString())
.loadConfigurationIntoIndex(false)
.build();

public DefaultConfigurationSingleNodeClusterUseClusterStateTests() {
super(cluster);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public void shouldStillLoadSecurityConfigDuringBootstrapAndActiveConfigUpdateReq
.put("action_groups.yml", CType.ACTIONGROUPS)
.put("config.yml", CType.CONFIG)
.put("roles.yml", CType.ROLES)
.put("roles_mapping.yml", CType.ROLESMAPPING)
.put("tenants.yml", CType.TENANTS)
.build();

Expand All @@ -146,7 +147,7 @@ public void shouldStillLoadSecurityConfigDuringBootstrapAndActiveConfigUpdateReq
// 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),
List.of(CType.ACTIONGROUPS, CType.CONFIG, CType.ROLES, CType.ROLESMAPPING, CType.TENANTS),
true
);
try (final TestRestClient freshClient = cluster.getRestClient(USER_ADMIN)) {
Expand Down
Loading

0 comments on commit b0d26dd

Please sign in to comment.