diff --git a/src/integrationTest/java/org/opensearch/security/legacy/LegacyConfigV6AutoConversionTest.java b/src/integrationTest/java/org/opensearch/security/legacy/LegacyConfigV6AutoConversionTest.java new file mode 100644 index 0000000000..35fd179019 --- /dev/null +++ b/src/integrationTest/java/org/opensearch/security/legacy/LegacyConfigV6AutoConversionTest.java @@ -0,0 +1,79 @@ +/* + * 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.legacy; + +import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.opensearch.test.framework.TestSecurityConfig; +import org.opensearch.test.framework.cluster.ClusterManager; +import org.opensearch.test.framework.cluster.LocalCluster; +import org.opensearch.test.framework.cluster.TestRestClient; + +@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) +@ThreadLeakScope(ThreadLeakScope.Scope.NONE) +public class LegacyConfigV6AutoConversionTest { + static final TestSecurityConfig LEGACY_CONFIG = new TestSecurityConfig()// + .rawConfigurationDocumentYaml("config", """ + opendistro_security: + dynamic: + authc: + basic_internal_auth_domain: + http_enabled: true + order: 4 + http_authenticator: + type: basic + challenge: true + authentication_backend: + type: intern + """)// + .rawConfigurationDocumentYaml("internalusers", """ + admin: + readonly: true + hash: $2a$12$VcCDgh2NDk07JGN0rjGbM.Ad41qVR/YFJcgHp0UGns5JDymv..TOG + roles: + - admin + attributes: + attribute1: value1 + """)// + .rawConfigurationDocumentYaml("roles", """ + all_access: + readonly: true + cluster: + - UNLIMITED + indices: + '*': + '*': + - UNLIMITED + tenants: + admin_tenant: RW + """)// + .rawConfigurationDocumentYaml("rolesmapping", """ + all_access: + readonly: true + backendroles: + - admin + """); + + @ClassRule + public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS) + .config(LEGACY_CONFIG) + .build(); + + @Test + public void checkAuthc() { + try (TestRestClient client = cluster.getRestClient("admin", "admin")) { + TestRestClient.HttpResponse response = client.get("_opendistro/_security/authinfo"); + System.out.println(response.getBody()); + } + } +} diff --git a/src/integrationTest/java/org/opensearch/test/framework/TestSecurityConfig.java b/src/integrationTest/java/org/opensearch/test/framework/TestSecurityConfig.java index a1ea3720ba..9edf77f75c 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/TestSecurityConfig.java +++ b/src/integrationTest/java/org/opensearch/test/framework/TestSecurityConfig.java @@ -43,6 +43,9 @@ import java.util.function.Supplier; import java.util.stream.Collectors; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -94,6 +97,13 @@ public class TestSecurityConfig { private Map actionGroups = new LinkedHashMap<>(); + /** + * A map from document id to a string containing config JSON. + * If this is not null, it will be used ALTERNATIVELY to all other configuration contained in this class. + * Can be used to simulate invalid configuration or legacy configuration. + */ + private Map rawConfigurationDocuments; + private String indexName = ".opendistro_security"; public TestSecurityConfig() { @@ -212,6 +222,27 @@ public List actionGroups() { return List.copyOf(actionGroups.values()); } + /** + * Specifies raw document content for the configuration index as YAML document. If this method is used, + * then ONLY the raw documents will be written to the configuration index. Any other configuration specified + * by the roles() or users() method will be ignored. + * Can be used to simulate invalid configuration or legacy configuration. + */ + public TestSecurityConfig rawConfigurationDocumentYaml(String configTypeId, String configDocumentAsYaml) { + try { + if (this.rawConfigurationDocuments == null) { + this.rawConfigurationDocuments = new LinkedHashMap<>(); + } + + JsonNode node = new ObjectMapper(new YAMLFactory()).readTree(configDocumentAsYaml); + + this.rawConfigurationDocuments.put(configTypeId, new ObjectMapper().writeValueAsString(node)); + return this; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + public static class Config implements ToXContentObject { private boolean anonymousAuth; @@ -964,15 +995,24 @@ public void initIndex(Client client) { } client.admin().indices().create(new CreateIndexRequest(indexName).settings(settings)).actionGet(); - writeSingleEntryConfigToIndex(client, CType.CONFIG, config); - if (auditConfiguration != null) { - writeSingleEntryConfigToIndex(client, CType.AUDIT, "config", auditConfiguration); + if (rawConfigurationDocuments == null) { + writeSingleEntryConfigToIndex(client, CType.CONFIG, config); + if (auditConfiguration != null) { + writeSingleEntryConfigToIndex(client, CType.AUDIT, "config", auditConfiguration); + } + writeConfigToIndex(client, CType.ROLES, roles); + writeConfigToIndex(client, CType.INTERNALUSERS, internalUsers); + writeConfigToIndex(client, CType.ROLESMAPPING, rolesMapping); + writeEmptyConfigToIndex(client, CType.ACTIONGROUPS); + writeEmptyConfigToIndex(client, CType.TENANTS); + } else { + // Write raw configuration alternatively to the normal configuration + + for (Map.Entry entry : this.rawConfigurationDocuments.entrySet()) { + writeConfigToIndex(client, entry.getKey(), entry.getValue()); + } } - writeConfigToIndex(client, CType.ROLES, roles); - writeConfigToIndex(client, CType.INTERNALUSERS, internalUsers); - writeConfigToIndex(client, CType.ROLESMAPPING, rolesMapping); - writeEmptyConfigToIndex(client, CType.ACTIONGROUPS); - writeEmptyConfigToIndex(client, CType.TENANTS); + } public void updateInternalUsersConfiguration(Client client, List users) { @@ -987,11 +1027,11 @@ static String hashPassword(final String clearTextPassword) { return passwordHasher.hash(clearTextPassword.toCharArray()); } - private void writeEmptyConfigToIndex(Client client, CType configType) { + private void writeEmptyConfigToIndex(Client client, CType configType) { writeConfigToIndex(client, configType, Collections.emptyMap()); } - private void writeConfigToIndex(Client client, CType configType, Map config) { + private void writeConfigToIndex(Client client, CType configType, Map config) { try { String json = configToJson(configType, config); @@ -1008,11 +1048,23 @@ private void writeConfigToIndex(Client client, CType configType, Map config) { + private void updateConfigInIndex(Client client, CType configType, Map config) { try { String json = configToJson(configType, config); BytesReference bytesReference = toByteReference(json); @@ -1025,7 +1077,7 @@ private void updateConfigInIndex(Client client, CType configType, Map config) throws IOException { + private static String configToJson(CType configType, Map config) throws IOException { XContentBuilder builder = XContentFactory.jsonBuilder(); builder.startObject(); @@ -1043,11 +1095,11 @@ private static String configToJson(CType configType, Map configType, ToXContentObject config) { writeSingleEntryConfigToIndex(client, configType, configType.toLCString(), config); } - private void writeSingleEntryConfigToIndex(Client client, CType configType, String configurationRoot, ToXContentObject config) { + private void writeSingleEntryConfigToIndex(Client client, CType configType, String configurationRoot, ToXContentObject config) { try { XContentBuilder builder = XContentFactory.jsonBuilder();