From 483b9e2335ccf81e473b04fa1d9fd8c3f0a2dbc6 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 27 Mar 2023 11:02:20 -0400 Subject: [PATCH 01/45] Add extensionsManager into GuiceHolder Signed-off-by: Stephen Crawford --- .../org/opensearch/security/OpenSearchSecurityPlugin.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 87ca878fc6..191d75dd22 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -94,6 +94,7 @@ import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; import org.opensearch.env.NodeEnvironment; +import org.opensearch.extensions.ExtensionsManager; import org.opensearch.http.HttpServerTransport; import org.opensearch.http.HttpServerTransport.Dispatcher; import org.opensearch.index.Index; @@ -1187,13 +1188,16 @@ public static class GuiceHolder implements LifecycleComponent { private static IndicesService indicesService; private static PitService pitService; + private static ExtensionsManager extensionsManager; + @Inject public GuiceHolder(final RepositoriesService repositoriesService, - final TransportService remoteClusterService, IndicesService indicesService, PitService pitService) { + final TransportService remoteClusterService, IndicesService indicesService, PitService pitService, ExtensionsManager extensionsManager) { GuiceHolder.repositoriesService = repositoriesService; GuiceHolder.remoteClusterService = remoteClusterService.getRemoteClusterService(); GuiceHolder.indicesService = indicesService; GuiceHolder.pitService = pitService; + GuiceHolder.extensionsManager = extensionsManager; } public static RepositoriesService getRepositoriesService() { @@ -1210,6 +1214,7 @@ public static IndicesService getIndicesService() { public static PitService getPitService() { return pitService; } + public static ExtensionsManager getExtensionsManager() { return extensionsManager; } @Override public void close() { From 6d58e08c5f07a9a1c76aea64dbc890e61fd02668 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 27 Mar 2023 13:04:22 -0400 Subject: [PATCH 02/45] Basic outline of functions for making service accounts Signed-off-by: Stephen Crawford --- .../security/extensions/ExtensionHelper.java | 75 +++++++++++++++++++ .../ExtensionRegistrationException.java | 25 +++++++ .../ExtensionRegistrationResponse.java | 34 +++++++++ 3 files changed, 134 insertions(+) create mode 100644 src/main/java/org/opensearch/security/extensions/ExtensionHelper.java create mode 100644 src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java create mode 100644 src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionHelper.java b/src/main/java/org/opensearch/security/extensions/ExtensionHelper.java new file mode 100644 index 0000000000..973c88561e --- /dev/null +++ b/src/main/java/org/opensearch/security/extensions/ExtensionHelper.java @@ -0,0 +1,75 @@ +package org.opensearch.security.extensions; + +import org.apache.hc.core5.http.HttpStatus; +import org.opensearch.action.ActionRequest; +import org.opensearch.action.admin.indices.segments.PitSegmentsRequest; +import org.opensearch.action.index.IndexResponse; +import org.opensearch.action.search.CreatePitRequest; +import org.opensearch.action.search.DeletePitRequest; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.unit.TimeValue; +import org.opensearch.common.xcontent.XContentType; +import org.opensearch.extensions.DiscoveryExtensionNode; +import org.opensearch.security.DefaultObjectMapper; +import org.opensearch.security.OpenSearchSecurityPlugin; +import org.opensearch.security.dlic.rest.api.AbstractApiAction; +import org.opensearch.security.privileges.PrivilegesEvaluatorResponse; +import org.opensearch.security.resolver.IndexResolverReplacer; +import org.opensearch.security.securityconf.SecurityRoles; +import org.opensearch.security.securityconf.impl.CType; +import org.opensearch.security.user.User; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * This class handles extension registration and operations on behalf of the Security Plugin. + */ +public class ExtensionHelper { + + public ExtensionRegistrationResponse register(String extensionUniqueId) throws ExtensionRegistrationException { + + ExtensionRegistrationResponse registrationResponse = new ExtensionRegistrationResponse(extensionUniqueId); + addServiceAccount(extensionUniqueId); + if (registrationResponse.extensionIsRegistered()) { // Check if this is an old extension + return registrationResponse; + } + addServiceAccount(extensionUniqueId); + if (registrationResponse.extensionIsRegistered()) { // Confirm it was added + return registrationResponse; + } + else { // Throw if failed to add + throw new ExtensionRegistrationException("An error occurred when registering extension " + extensionUniqueId); + } + } + + private void addServiceAccount(String extensionUniqueId) { + + final String serviceAccountName = extensionUniqueId; + final DiscoveryExtensionNode extensionInformation = OpenSearchSecurityPlugin.GuiceHolder.getExtensionsManager().getExtensionIdMap().get(extensionUniqueId); + // extensionInformation.getSecurityConfiguration(); TODO: Need to make it so that we can get the extension configuration information + final String extensionRole = "opendistro_security_all_access"; // TODO: Swap this to be parsed role with name equal to extension name once configuration reading is live + final Map extensionAttributes = new HashMap<>(); + extensionAttributes.put("service", "true"); // This attribute signifies that the account is a service account + + final String createServiceAccountPayload = "{\n" + + " \"opendistro_security_roles\": [\"" + extensionRole + "\"],\n" + + " \"attributes\": {\n" + extensionAttributes.toString() + "\n" + + " }\n" + + "}"; + + // checks complete, create or update the user + internalUsersConfiguration.putCObject(serviceAccountName, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass())); + + saveAnUpdateConfigs(client, request, CType.INTERNALUSERS, internalUsersConfiguration, new AbstractApiAction.OnSucessActionListener(channel)); + } + + public static boolean extensionServiceAccountExists(String extensionUniqueId) { + + return true; + } +} + + diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java b/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java new file mode 100644 index 0000000000..b94dd57358 --- /dev/null +++ b/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java @@ -0,0 +1,25 @@ +package org.opensearch.security.extensions; + +public class ExtensionRegistrationException extends Exception { + + public ExtensionRegistrationException() { + super(); + } + + public ExtensionRegistrationException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public ExtensionRegistrationException(String message, Throwable cause) { + super(message, cause); + } + + public ExtensionRegistrationException(String message) { + super(message); + } + + public ExtensionRegistrationException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java b/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java new file mode 100644 index 0000000000..3602ae4e28 --- /dev/null +++ b/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java @@ -0,0 +1,34 @@ +package org.opensearch.security.extensions; + +import static org.opensearch.security.extensions.ExtensionHelper.extensionServiceAccountExists; + +public class ExtensionRegistrationResponse { + + //TODO: May not need this class; could move into ExtensionHelper + private final String extensionUniqueId; + + private boolean registrationComplete; + + public ExtensionRegistrationResponse(String extensionUniqueId) { + this.extensionUniqueId = extensionUniqueId; + this.registrationComplete = extensionIsRegistered(); + } + + public boolean extensionIsRegistered(){ // Todo: This should make sure that the registration is propagated to all nodes, not sure how to do that + + if (registrationComplete) { + return true; + } + if (extensionServiceAccountExists(this.extensionUniqueId)) { + this.registrationComplete = true; + return true; + } + return false; + } + + public String getExtensionUniqueId() { return extensionUniqueId; } + + public boolean getRegistrationComplete() { return registrationComplete; } + + +} From 42f460fd5663faf03f69519d685eaec0b787be5a Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 27 Mar 2023 18:42:38 -0400 Subject: [PATCH 03/45] Outline of service account creation Signed-off-by: Stephen Crawford --- .../security/OpenSearchSecurityPlugin.java | 1 - .../security/extensions/ExtensionHelper.java | 70 ++++++++++++++----- 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 191d75dd22..d442b448e9 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -1187,7 +1187,6 @@ public static class GuiceHolder implements LifecycleComponent { private static RemoteClusterService remoteClusterService; private static IndicesService indicesService; private static PitService pitService; - private static ExtensionsManager extensionsManager; @Inject diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionHelper.java b/src/main/java/org/opensearch/security/extensions/ExtensionHelper.java index 973c88561e..c65cc12dd9 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionHelper.java +++ b/src/main/java/org/opensearch/security/extensions/ExtensionHelper.java @@ -1,34 +1,33 @@ package org.opensearch.security.extensions; -import org.apache.hc.core5.http.HttpStatus; -import org.opensearch.action.ActionRequest; -import org.opensearch.action.admin.indices.segments.PitSegmentsRequest; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import org.opensearch.action.index.IndexResponse; -import org.opensearch.action.search.CreatePitRequest; -import org.opensearch.action.search.DeletePitRequest; -import org.opensearch.cluster.metadata.IndexNameExpressionResolver; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.settings.Settings; -import org.opensearch.common.unit.TimeValue; -import org.opensearch.common.xcontent.XContentType; import org.opensearch.extensions.DiscoveryExtensionNode; import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.OpenSearchSecurityPlugin; import org.opensearch.security.dlic.rest.api.AbstractApiAction; -import org.opensearch.security.privileges.PrivilegesEvaluatorResponse; -import org.opensearch.security.resolver.IndexResolverReplacer; -import org.opensearch.security.securityconf.SecurityRoles; import org.opensearch.security.securityconf.impl.CType; -import org.opensearch.security.user.User; +import org.opensearch.security.support.SecurityJsonNode; import java.util.*; -import java.util.concurrent.TimeUnit; /** * This class handles extension registration and operations on behalf of the Security Plugin. */ public class ExtensionHelper { + protected String getResourceName() { + return "serviceAccount"; + } + protected CType getConfigName() { + return CType.INTERNALUSERS; + } + + ObjectMapper mapper = new ObjectMapper(); + public ExtensionRegistrationResponse register(String extensionUniqueId) throws ExtensionRegistrationException { ExtensionRegistrationResponse registrationResponse = new ExtensionRegistrationResponse(extensionUniqueId); @@ -45,7 +44,7 @@ public ExtensionRegistrationResponse register(String extensionUniqueId) throws E } } - private void addServiceAccount(String extensionUniqueId) { + private void addServiceAccount(String extensionUniqueId) throws JsonProcessingException, ExtensionRegistrationException { final String serviceAccountName = extensionUniqueId; final DiscoveryExtensionNode extensionInformation = OpenSearchSecurityPlugin.GuiceHolder.getExtensionsManager().getExtensionIdMap().get(extensionUniqueId); @@ -60,10 +59,43 @@ private void addServiceAccount(String extensionUniqueId) { " }\n" + "}"; - // checks complete, create or update the user - internalUsersConfiguration.putCObject(serviceAccountName, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass())); + //TODO: Need to add service account to internal authentication backend + + JsonNode actualObj; + + try { + actualObj = mapper.readTree(createServiceAccountPayload); + } catch (JsonProcessingException ex) { + throw new ExtensionRegistrationException("Failed to parse the provided configuration settings. Failed to register extension: " + extensionUniqueId); + } + + ObjectNode content = (ObjectNode) actualObj; + final SecurityJsonNode securityJsonNode = new SecurityJsonNode(content); + + // A password cannot be provided for a Service account. + final String plainTextPassword = securityJsonNode.get("password").asString(); + final String origHash = securityJsonNode.get("hash").asString(); + if (plainTextPassword != null && plainTextPassword.length() > 0) { + throw new ExtensionRegistrationException("A password cannot be provided for extensions. Failed to register extension: " + extensionUniqueId); + } else if (origHash != null && origHash.length() > 0) { + throw new ExtensionRegistrationException("A password hash cannot be provided for extensions. Failed to register extension: " + extensionUniqueId); + } + + //TODO: This needs to be able to respond back to core once the account is created. + // This needs to create the user and put in the configuration, then save and update config for all nodes + internalUsersConfiguration.putCObject(serviceAccountName, DefaultObjectMapper.readTree(content, internalUsersConfiguration.getImplementingClass())); + saveAnUpdateConfigs(client, request, CType.INTERNALUSERS, internalUsersConfiguration, new AbstractApiAction.OnSucessActionListener(channel) { + + public void onResponse(IndexResponse response) { + ExtensionRegistrationResponse extensionRegistrationResponse = new ExtensionRegistrationResponse(extensionUniqueId); + } + }); + + /* + 1. Could try to call InternalUsersApiAction and use handlePut() to add the service account + 2. Could try to use the pieces of handlePut() directly + */ - saveAnUpdateConfigs(client, request, CType.INTERNALUSERS, internalUsersConfiguration, new AbstractApiAction.OnSucessActionListener(channel)); } public static boolean extensionServiceAccountExists(String extensionUniqueId) { From b6ab47a407651b7a3a5600aa27a31407ecc489fd Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Tue, 28 Mar 2023 12:09:59 -0400 Subject: [PATCH 04/45] Extension Service Outline Signed-off-by: Stephen Crawford --- .../ConfigurationRepository.java | 29 +++++ .../ExtensionRegistrationResponse.java | 22 +++- .../extensions/ExtensionsConfigConstants.java | 6 + ...sionHelper.java => ExtensionsService.java} | 112 ++++++++++++++---- 4 files changed, 144 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java rename src/main/java/org/opensearch/security/extensions/{ExtensionHelper.java => ExtensionsService.java} (50%) diff --git a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java index 31e2a7d16f..26bca1242b 100644 --- a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java +++ b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java @@ -68,12 +68,14 @@ import org.opensearch.rest.RestStatus; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.auditlog.config.AuditConfig; +import org.opensearch.security.extensions.ExtensionsConfigConstants; import org.opensearch.security.securityconf.DynamicConfigFactory; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.ConfigHelper; +import org.opensearch.security.support.SecurityJsonNode; import org.opensearch.security.support.SecurityUtils; import org.opensearch.threadpool.ThreadPool; @@ -405,4 +407,31 @@ private static String formatDate(long date) { public static int getDefaultConfigVersion() { return ConfigurationRepository.DEFAULT_CONFIG_VERSION; } + + public Map> getConfigurationsFromIndex(Collection configTypes) { + + final ThreadContext threadContext = threadPool.getThreadContext(); + final Map> retVal = new HashMap<>(); + + try (StoredContext ctx = threadContext.stashContext()) { + threadContext.putHeader(ExtensionsConfigConstants.EXTENSIONS_CONF_REQUEST_HEADER, "true"); + + IndexMetadata securityMetadata = clusterService.state().metadata().index(this.securityIndex); + MappingMetadata mappingMetadata = securityMetadata == null ? null : securityMetadata.mapping(); + + if (securityMetadata != null && mappingMetadata != null) { + retVal.putAll(validate(cl.load(configTypes.toArray(new CType[0]), 5, TimeUnit.SECONDS, false), configTypes.size())); + + } else { + // wait (and use new layout) + LOGGER.debug("Could not access the Security Index"); + retVal.putAll(validate(cl.load(configTypes.toArray(new CType[0]), 5, TimeUnit.SECONDS, false), configTypes.size())); + } + + } catch (Exception e) { + throw new OpenSearchException(e); + } + + return retVal; + } } diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java b/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java index 3602ae4e28..5dff247ada 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java +++ b/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java @@ -1,6 +1,8 @@ package org.opensearch.security.extensions; -import static org.opensearch.security.extensions.ExtensionHelper.extensionServiceAccountExists; +import org.opensearch.security.privileges.DocumentAllowList; + +import static org.opensearch.security.extensions.ExtensionsService.extensionServiceAccountExists; public class ExtensionRegistrationResponse { @@ -30,5 +32,21 @@ public boolean extensionIsRegistered(){ // Todo: This should make sure that the public boolean getRegistrationComplete() { return registrationComplete; } - + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (this.getClass() != obj.getClass()) { + return false; + } + ExtensionRegistrationResponse otherExReg = (ExtensionRegistrationResponse) (obj); + if (!this.extensionUniqueId.equals(otherExReg.extensionUniqueId)) { + return false; + } + return true; + } } diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java b/src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java new file mode 100644 index 0000000000..5d0f9858e2 --- /dev/null +++ b/src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java @@ -0,0 +1,6 @@ +package org.opensearch.security.extensions; + +public class ExtensionsConfigConstants { + public static final String EXTENSIONS_CONFIG_PREFIX = "_extensions_"; + public static final String EXTENSIONS_CONF_REQUEST_HEADER = EXTENSIONS_CONFIG_PREFIX + "conf_request"; +} diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionHelper.java b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java similarity index 50% rename from src/main/java/org/opensearch/security/extensions/ExtensionHelper.java rename to src/main/java/org/opensearch/security/extensions/ExtensionsService.java index c65cc12dd9..fb12e789c7 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionHelper.java +++ b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java @@ -4,34 +4,108 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.opensearch.ExceptionsHelper; +import org.opensearch.action.index.IndexRequest; import org.opensearch.action.index.IndexResponse; +import org.opensearch.action.search.SearchTransportService; +import org.opensearch.action.support.WriteRequest; +import org.opensearch.client.Client; +import org.opensearch.client.node.NodeClient; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.inject.Inject; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.xcontent.XContentHelper; +import org.opensearch.common.xcontent.XContentType; import org.opensearch.extensions.DiscoveryExtensionNode; +import org.opensearch.rest.RestRequest; import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.OpenSearchSecurityPlugin; +import org.opensearch.security.configuration.ConfigurationRepository; import org.opensearch.security.dlic.rest.api.AbstractApiAction; import org.opensearch.security.securityconf.impl.CType; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.SecurityJsonNode; +import org.opensearch.transport.TransportService; +import java.io.IOException; import java.util.*; /** * This class handles extension registration and operations on behalf of the Security Plugin. */ -public class ExtensionHelper { +public class ExtensionsService { + + ClusterService clusterService; + TransportService transportService; + NodeClient nodeClient; + static ConfigurationRepository configurationRepository; + String securityIndex; + + Client client; protected String getResourceName() { return "serviceAccount"; } - protected CType getConfigName() { + protected static CType getConfigName() { return CType.INTERNALUSERS; } + @Inject + public ExtensionsService( + ClusterService clusterService, + TransportService transportService, + NodeClient nodeClient, + ConfigurationRepository configurationRepository, + Settings settings, + Client client + ) { + this.clusterService = clusterService; + this.transportService = transportService; + this.nodeClient = nodeClient; + this.configurationRepository = configurationRepository; + this.securityIndex = settings.get(ConfigConstants.SECURITY_CONFIG_INDEX_NAME, + ConfigConstants.OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX); + this.client = client; + } + + protected void saveAndUpdateConfiguration(final Client client, final CType cType, + final SecurityDynamicConfiguration configuration) { + final IndexRequest ir = new IndexRequest(this.securityIndex); + + //final String type = "_doc"; + final String id = cType.toLCString(); + + configuration.removeStatic(); + + try { + client.index(ir.id(id) + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .setIfSeqNo(configuration.getSeqNo()) + .setIfPrimaryTerm(configuration.getPrimaryTerm()) + .source(id, XContentHelper.toXContent(configuration, XContentType.JSON, false))); + } catch (IOException e) { + throw ExceptionsHelper.convertToOpenSearchException(e); + } + } + + /** + * Load data for a given CType + * @param config CType whose data is to be loaded in-memory + * @return configuration loaded with given CType data + */ + protected static final SecurityDynamicConfiguration load(final CType config) { + SecurityDynamicConfiguration loaded = configurationRepository.getConfigurationsFromIndex(Collections.singleton(config)) + .get(config) + .deepClone(); + return loaded; + } + ObjectMapper mapper = new ObjectMapper(); - public ExtensionRegistrationResponse register(String extensionUniqueId) throws ExtensionRegistrationException { + public ExtensionRegistrationResponse register(String extensionUniqueId) throws ExtensionRegistrationException, IOException { ExtensionRegistrationResponse registrationResponse = new ExtensionRegistrationResponse(extensionUniqueId); - addServiceAccount(extensionUniqueId); if (registrationResponse.extensionIsRegistered()) { // Check if this is an old extension return registrationResponse; } @@ -44,11 +118,14 @@ public ExtensionRegistrationResponse register(String extensionUniqueId) throws E } } - private void addServiceAccount(String extensionUniqueId) throws JsonProcessingException, ExtensionRegistrationException { + private void addServiceAccount(String extensionUniqueId) throws ExtensionRegistrationException, IOException { final String serviceAccountName = extensionUniqueId; final DiscoveryExtensionNode extensionInformation = OpenSearchSecurityPlugin.GuiceHolder.getExtensionsManager().getExtensionIdMap().get(extensionUniqueId); // extensionInformation.getSecurityConfiguration(); TODO: Need to make it so that we can get the extension configuration information + // extensionInformation.parseToJson(); + // TODO: Add check for backend role (illegal) and more than one role (illegal) + // Add default role option for extensions which do not specify their own role final String extensionRole = "opendistro_security_all_access"; // TODO: Swap this to be parsed role with name equal to extension name once configuration reading is live final Map extensionAttributes = new HashMap<>(); extensionAttributes.put("service", "true"); // This attribute signifies that the account is a service account @@ -59,8 +136,6 @@ private void addServiceAccount(String extensionUniqueId) throws JsonProcessingEx " }\n" + "}"; - //TODO: Need to add service account to internal authentication backend - JsonNode actualObj; try { @@ -70,37 +145,28 @@ private void addServiceAccount(String extensionUniqueId) throws JsonProcessingEx } ObjectNode content = (ObjectNode) actualObj; - final SecurityJsonNode securityJsonNode = new SecurityJsonNode(content); + final SecurityJsonNode securityJsonNode = new SecurityJsonNode(actualObj); // A password cannot be provided for a Service account. final String plainTextPassword = securityJsonNode.get("password").asString(); final String origHash = securityJsonNode.get("hash").asString(); if (plainTextPassword != null && plainTextPassword.length() > 0) { throw new ExtensionRegistrationException("A password cannot be provided for extensions. Failed to register extension: " + extensionUniqueId); - } else if (origHash != null && origHash.length() > 0) { + } + if (origHash != null && origHash.length() > 0) { throw new ExtensionRegistrationException("A password hash cannot be provided for extensions. Failed to register extension: " + extensionUniqueId); } + final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName()); - //TODO: This needs to be able to respond back to core once the account is created. - // This needs to create the user and put in the configuration, then save and update config for all nodes internalUsersConfiguration.putCObject(serviceAccountName, DefaultObjectMapper.readTree(content, internalUsersConfiguration.getImplementingClass())); - saveAnUpdateConfigs(client, request, CType.INTERNALUSERS, internalUsersConfiguration, new AbstractApiAction.OnSucessActionListener(channel) { - - public void onResponse(IndexResponse response) { - ExtensionRegistrationResponse extensionRegistrationResponse = new ExtensionRegistrationResponse(extensionUniqueId); - } - }); - - /* - 1. Could try to call InternalUsersApiAction and use handlePut() to add the service account - 2. Could try to use the pieces of handlePut() directly - */ + saveAndUpdateConfiguration(client, CType.INTERNALUSERS, internalUsersConfiguration); } public static boolean extensionServiceAccountExists(String extensionUniqueId) { - return true; + final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName()); + return internalUsersConfiguration.exists(extensionUniqueId); } } From e1422fb36369e1977e20ed475591a0a6176156ea Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Tue, 28 Mar 2023 12:41:07 -0400 Subject: [PATCH 05/45] Add test method names and pass through Signed-off-by: Stephen Crawford --- .../extensions/ExtensionsService.java | 3 - .../extensions/ExtensionRegistrationIT.java | 15 ++++ .../ExtensionRegistrationUnitTests.java | 81 +++++++++++++++++++ 3 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java create mode 100644 src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionsService.java b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java index fb12e789c7..48135a9ab0 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionsService.java +++ b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java @@ -17,11 +17,9 @@ import org.opensearch.common.xcontent.XContentHelper; import org.opensearch.common.xcontent.XContentType; import org.opensearch.extensions.DiscoveryExtensionNode; -import org.opensearch.rest.RestRequest; import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.OpenSearchSecurityPlugin; import org.opensearch.security.configuration.ConfigurationRepository; -import org.opensearch.security.dlic.rest.api.AbstractApiAction; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; import org.opensearch.security.support.ConfigConstants; @@ -41,7 +39,6 @@ public class ExtensionsService { NodeClient nodeClient; static ConfigurationRepository configurationRepository; String securityIndex; - Client client; protected String getResourceName() { diff --git a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java new file mode 100644 index 0000000000..59ac69c100 --- /dev/null +++ b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java @@ -0,0 +1,15 @@ +package org.opensearch.security.extensions; + + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ExtensionRegistrationIT { + + //TODO: Add integration tests once core side is implemented + @Test + public void testPassThrough() { + assertEquals(true, true); + } +} diff --git a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java new file mode 100644 index 0000000000..23b4956172 --- /dev/null +++ b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java @@ -0,0 +1,81 @@ +package org.opensearch.security.extensions; + + +import org.junit.Before; +import org.junit.Test; +import org.opensearch.client.Client; +import org.opensearch.cluster.metadata.IndexNameExpressionResolver; +import org.opensearch.cluster.routing.allocation.decider.Decision; +import org.opensearch.cluster.service.ClusterService; +import org.opensearch.common.io.stream.NamedWriteableRegistry; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.env.Environment; +import org.opensearch.env.NodeEnvironment; +import org.opensearch.plugins.ActionPlugin; +import org.opensearch.plugins.Plugin; +import org.opensearch.repositories.RepositoriesService; +import org.opensearch.script.ScriptService; +import org.opensearch.security.auth.internal.InternalAuthenticationBackend; +import org.opensearch.security.securityconf.InternalUsersModel; +import org.opensearch.security.support.ConfigConstants; +import org.opensearch.security.test.SingleClusterTest; +import org.opensearch.threadpool.ThreadPool; +import org.opensearch.watcher.ResourceWatcherService; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.function.Supplier; + +import static org.junit.Assert.assertEquals; + +public class ExtensionRegistrationUnitTests extends SingleClusterTest { + + //TODO: Figure out how to build these tests when normally inject + + + public Collection createComponents(Client client, ClusterService clusterService, ThreadPool threadPool, + ResourceWatcherService resourceWatcherService, ScriptService scriptService, + NamedXContentRegistry xContentRegistry, Environment environment, + NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, + IndexNameExpressionResolver indexNameExpressionResolver, + Supplier repositoriesServiceSupplier) { + + return new ArrayList<>(); + } + + @Test + public void testRegisterExtensionExtensionExists() { + + assertEquals(true, true); + } + + @Test + public void testRegisterExtensionExtensionDoesNotExist() { + assertEquals(true, true); + } + + @Test + public void testExtensionIsRegisteredRegisteredCheck() { + assertEquals(true, true); + } + + @Test + public void testExtensionIsNotRegisteredRegisteredCheck() { + assertEquals(true, true); + } + + @Test + public void testAddValidServiceAccount() { + assertEquals(true, true); + } + + @Test + public void testAddInvalidServiceAccount() { + assertEquals(true, true); + } + + @Test + public void testServiceAccountWasAddedToConfig() { + assertEquals(true, true); + } +} From 882b652657b7c5da94d740985925ab22a56e3f7a Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Tue, 28 Mar 2023 12:58:03 -0400 Subject: [PATCH 06/45] add licenses and spotless Signed-off-by: Stephen Crawford --- .../ExtensionRegistrationException.java | 26 ++++++++++++++ .../ExtensionRegistrationResponse.java | 27 ++++++++++++++ .../extensions/ExtensionsConfigConstants.java | 27 ++++++++++++++ .../extensions/ExtensionsService.java | 35 ++++++++++++++++--- .../extensions/ExtensionRegistrationIT.java | 27 +++++++++++++- .../ExtensionRegistrationUnitTests.java | 35 ++++++++++++++++--- 6 files changed, 167 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java b/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java index b94dd57358..fe0f6ef859 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java +++ b/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java @@ -1,3 +1,29 @@ +/* + * Copyright 2015-2018 _floragunn_ GmbH + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + package org.opensearch.security.extensions; public class ExtensionRegistrationException extends Exception { diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java b/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java index 5dff247ada..5f0c493312 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java +++ b/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java @@ -1,5 +1,32 @@ +/* + * Copyright 2015-2018 _floragunn_ GmbH + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + package org.opensearch.security.extensions; + import org.opensearch.security.privileges.DocumentAllowList; import static org.opensearch.security.extensions.ExtensionsService.extensionServiceAccountExists; diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java b/src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java index 5d0f9858e2..92e445b730 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java +++ b/src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java @@ -1,5 +1,32 @@ +/* + * Copyright 2015-2018 _floragunn_ GmbH + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + package org.opensearch.security.extensions; + public class ExtensionsConfigConstants { public static final String EXTENSIONS_CONFIG_PREFIX = "_extensions_"; public static final String EXTENSIONS_CONF_REQUEST_HEADER = EXTENSIONS_CONFIG_PREFIX + "conf_request"; diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionsService.java b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java index 48135a9ab0..4cf03c6295 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionsService.java +++ b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java @@ -1,9 +1,39 @@ +/* + * Copyright 2015-2018 _floragunn_ GmbH + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + package org.opensearch.security.extensions; +import java.io.IOException; +import java.util.*; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; + import org.opensearch.ExceptionsHelper; import org.opensearch.action.index.IndexRequest; import org.opensearch.action.index.IndexResponse; @@ -26,9 +56,6 @@ import org.opensearch.security.support.SecurityJsonNode; import org.opensearch.transport.TransportService; -import java.io.IOException; -import java.util.*; - /** * This class handles extension registration and operations on behalf of the Security Plugin. */ @@ -166,5 +193,3 @@ public static boolean extensionServiceAccountExists(String extensionUniqueId) { return internalUsersConfiguration.exists(extensionUniqueId); } } - - diff --git a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java index 59ac69c100..78c66ff40c 100644 --- a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java +++ b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java @@ -1,5 +1,30 @@ -package org.opensearch.security.extensions; +/* + * Copyright 2015-2018 _floragunn_ GmbH + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ +package org.opensearch.security.extensions; import org.junit.Test; diff --git a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java index 23b4956172..7067eaf418 100644 --- a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java +++ b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java @@ -1,8 +1,39 @@ +/* + * Copyright 2015-2018 _floragunn_ GmbH + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + package org.opensearch.security.extensions; +import java.util.ArrayList; +import java.util.Collection; +import java.util.function.Supplier; + import org.junit.Before; import org.junit.Test; + import org.opensearch.client.Client; import org.opensearch.cluster.metadata.IndexNameExpressionResolver; import org.opensearch.cluster.routing.allocation.decider.Decision; @@ -22,10 +53,6 @@ import org.opensearch.threadpool.ThreadPool; import org.opensearch.watcher.ResourceWatcherService; -import java.util.ArrayList; -import java.util.Collection; -import java.util.function.Supplier; - import static org.junit.Assert.assertEquals; public class ExtensionRegistrationUnitTests extends SingleClusterTest { From 8297b841e180b5c0b2eb11d98acdf95519711e48 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Wed, 29 Mar 2023 09:09:36 -0400 Subject: [PATCH 07/45] Test notes Signed-off-by: Stephen Crawford --- .../org/opensearch/security/extensions/ExtensionsService.java | 4 +++- .../security/extensions/ExtensionRegistrationUnitTests.java | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionsService.java b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java index 4cf03c6295..54b09e8a41 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionsService.java +++ b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java @@ -97,7 +97,7 @@ protected void saveAndUpdateConfiguration(final Client client, final CType cType final SecurityDynamicConfiguration configuration) { final IndexRequest ir = new IndexRequest(this.securityIndex); - //final String type = "_doc"; + // final String type = "_doc"; final String id = cType.toLCString(); configuration.removeStatic(); @@ -185,6 +185,7 @@ private void addServiceAccount(String extensionUniqueId) throws ExtensionRegistr internalUsersConfiguration.putCObject(serviceAccountName, DefaultObjectMapper.readTree(content, internalUsersConfiguration.getImplementingClass())); saveAndUpdateConfiguration(client, CType.INTERNALUSERS, internalUsersConfiguration); + } public static boolean extensionServiceAccountExists(String extensionUniqueId) { @@ -192,4 +193,5 @@ public static boolean extensionServiceAccountExists(String extensionUniqueId) { final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName()); return internalUsersConfiguration.exists(extensionUniqueId); } + } diff --git a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java index 7067eaf418..1b4780912c 100644 --- a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java +++ b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java @@ -59,7 +59,6 @@ public class ExtensionRegistrationUnitTests extends SingleClusterTest { //TODO: Figure out how to build these tests when normally inject - public Collection createComponents(Client client, ClusterService clusterService, ThreadPool threadPool, ResourceWatcherService resourceWatcherService, ScriptService scriptService, NamedXContentRegistry xContentRegistry, Environment environment, From 2ddfc0659d89aee48dc587032ace166dcd0402d9 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Thu, 30 Mar 2023 09:33:38 -0400 Subject: [PATCH 08/45] Update Signed-off-by: Stephen Crawford --- .../extensions/ExtensionsService.java | 3 +- .../api/ServiceAccountGetAction.java | 39 ++++++++++ .../api/ServiceAccountGetRequest.java | 75 +++++++++++++++++++ .../api/ServiceAccountGetResponse.java | 68 +++++++++++++++++ 4 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetAction.java create mode 100644 src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetRequest.java create mode 100644 src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetResponse.java diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionsService.java b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java index 54b09e8a41..fe32c3ef46 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionsService.java +++ b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java @@ -148,7 +148,6 @@ private void addServiceAccount(String extensionUniqueId) throws ExtensionRegistr final DiscoveryExtensionNode extensionInformation = OpenSearchSecurityPlugin.GuiceHolder.getExtensionsManager().getExtensionIdMap().get(extensionUniqueId); // extensionInformation.getSecurityConfiguration(); TODO: Need to make it so that we can get the extension configuration information // extensionInformation.parseToJson(); - // TODO: Add check for backend role (illegal) and more than one role (illegal) // Add default role option for extensions which do not specify their own role final String extensionRole = "opendistro_security_all_access"; // TODO: Swap this to be parsed role with name equal to extension name once configuration reading is live final Map extensionAttributes = new HashMap<>(); @@ -177,6 +176,7 @@ private void addServiceAccount(String extensionUniqueId) throws ExtensionRegistr if (plainTextPassword != null && plainTextPassword.length() > 0) { throw new ExtensionRegistrationException("A password cannot be provided for extensions. Failed to register extension: " + extensionUniqueId); } + if (origHash != null && origHash.length() > 0) { throw new ExtensionRegistrationException("A password hash cannot be provided for extensions. Failed to register extension: " + extensionUniqueId); } @@ -193,5 +193,4 @@ public static boolean extensionServiceAccountExists(String extensionUniqueId) { final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName()); return internalUsersConfiguration.exists(extensionUniqueId); } - } diff --git a/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetAction.java b/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetAction.java new file mode 100644 index 0000000000..3193aac8aa --- /dev/null +++ b/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetAction.java @@ -0,0 +1,39 @@ +/* + * Copyright 2015-2018 _floragunn_ GmbH + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.extensions.api; + +import org.opensearch.action.ActionType; + +public class ServiceAccountGetAction extends ActionType { + + public static final ServiceAccountGetAction INSTANCE = new ServiceAccountGetAction(); + public static final String NAME = "cluster:admin/security/extensions/service_account/get"; + + protected ServiceAccountGetAction() { + super(NAME, ServiceAccountGetResponse::new); + } +} diff --git a/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetRequest.java b/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetRequest.java new file mode 100644 index 0000000000..3edef25617 --- /dev/null +++ b/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetRequest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2015-2018 _floragunn_ GmbH + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.extensions.api; + +import org.opensearch.action.ActionRequest; +import org.opensearch.action.ActionRequestValidationException; +import org.opensearch.action.support.nodes.BaseNodesRequest; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; +import org.opensearch.security.action.configupdate.ConfigUpdateRequest; + +import java.io.IOException; + +public class ServiceAccountGetRequest extends ActionRequest { + + private String extensionId; + + public ServiceAccountGetRequest(StreamInput in) throws IOException { + this.extensionId = in.readString(); + } + + public ServiceAccountGetRequest() { + super(); + } + + public ServiceAccountGetRequest(String extensionId) { + this(); + setExtensionId(extensionId); + } + + + public void writeTo(final StreamOutput out) throws IOException { + out.writeStringArray(extensionId.split("")); + } + + public String getExtensionId() { + return extensionId; + } + + public void setExtensionId(final String extensionId) { + this.extensionId = extensionId; + } + + public ActionRequestValidationException validate() { + if (extensionId == null || extensionId.length() == 0) { + return new ActionRequestValidationException(); + } + return null; + } +} + diff --git a/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetResponse.java b/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetResponse.java new file mode 100644 index 0000000000..7184cf548b --- /dev/null +++ b/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetResponse.java @@ -0,0 +1,68 @@ +/* + * Copyright 2015-2018 _floragunn_ GmbH + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.extensions.api; + +import org.opensearch.action.ActionResponse; +import org.opensearch.common.io.stream.StreamInput; +import org.opensearch.common.io.stream.StreamOutput; +import org.opensearch.core.xcontent.ToXContent; +import org.opensearch.core.xcontent.XContentBuilder; + +import java.io.IOException; + +public class ServiceAccountGetResponse extends ActionResponse { + + private String message; + + public ServiceAccountGetResponse(StreamInput in) throws IOException { + this.message = in.readOptionalString(); + } + + public ServiceAccountGetResponse(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + + public void writeTo(StreamOutput out) throws IOException { + out.writeOptionalString(message); + } + + @Override + public String toString() { + return "ServiceAccountGetResponse, message=" + message + ""; + } + + public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { + builder.startObject(); + builder.field("message", message); + builder.endObject(); + return builder; + } +} From 3af1e8dec822b4d7fc38697167d7b03e445b789e Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Fri, 31 Mar 2023 16:15:46 -0400 Subject: [PATCH 09/45] clear Signed-off-by: Stephen Crawford --- .../dlic/rest/api/InternalUsersApiAction.java | 3 + .../extensions/ExtensionsService.java | 196 ------------------ .../api/ServiceAccountGetAction.java | 39 ---- .../api/ServiceAccountGetRequest.java | 75 ------- .../api/ServiceAccountGetResponse.java | 68 ------ .../user/AccountCreateOrUpdateException.java} | 27 ++- .../ServiceAccountRegistrationException.java} | 14 +- .../ServiceAccountRegistrationResponse.java} | 14 +- .../opensearch/security/user/UserService.java | 58 +++++- .../ExtensionRegistrationUnitTests.java | 107 ---------- 10 files changed, 89 insertions(+), 512 deletions(-) delete mode 100644 src/main/java/org/opensearch/security/extensions/ExtensionsService.java delete mode 100644 src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetAction.java delete mode 100644 src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetRequest.java delete mode 100644 src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetResponse.java rename src/{test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java => main/java/org/opensearch/security/user/AccountCreateOrUpdateException.java} (55%) rename src/main/java/org/opensearch/security/{extensions/ExtensionRegistrationException.java => user/ServiceAccountRegistrationException.java} (70%) rename src/main/java/org/opensearch/security/{extensions/ExtensionRegistrationResponse.java => user/ServiceAccountRegistrationResponse.java} (81%) delete mode 100644 src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 0551c108a1..42a32280c0 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -100,8 +100,11 @@ protected Endpoint getEndpoint() { @Override protected void handlePut(RestChannel channel, final RestRequest request, final Client client, final JsonNode content) throws IOException { + String details = request.toString(); + final String username = request.param("name"); + SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName(), false); if (!isWriteable(channel, internalUsersConfiguration, username)) { diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionsService.java b/src/main/java/org/opensearch/security/extensions/ExtensionsService.java deleted file mode 100644 index fe32c3ef46..0000000000 --- a/src/main/java/org/opensearch/security/extensions/ExtensionsService.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2015-2018 _floragunn_ GmbH - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.extensions; - -import java.io.IOException; -import java.util.*; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import org.opensearch.ExceptionsHelper; -import org.opensearch.action.index.IndexRequest; -import org.opensearch.action.index.IndexResponse; -import org.opensearch.action.search.SearchTransportService; -import org.opensearch.action.support.WriteRequest; -import org.opensearch.client.Client; -import org.opensearch.client.node.NodeClient; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.inject.Inject; -import org.opensearch.common.settings.Settings; -import org.opensearch.common.xcontent.XContentHelper; -import org.opensearch.common.xcontent.XContentType; -import org.opensearch.extensions.DiscoveryExtensionNode; -import org.opensearch.security.DefaultObjectMapper; -import org.opensearch.security.OpenSearchSecurityPlugin; -import org.opensearch.security.configuration.ConfigurationRepository; -import org.opensearch.security.securityconf.impl.CType; -import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; -import org.opensearch.security.support.ConfigConstants; -import org.opensearch.security.support.SecurityJsonNode; -import org.opensearch.transport.TransportService; - -/** - * This class handles extension registration and operations on behalf of the Security Plugin. - */ -public class ExtensionsService { - - ClusterService clusterService; - TransportService transportService; - NodeClient nodeClient; - static ConfigurationRepository configurationRepository; - String securityIndex; - Client client; - - protected String getResourceName() { - return "serviceAccount"; - } - protected static CType getConfigName() { - return CType.INTERNALUSERS; - } - - @Inject - public ExtensionsService( - ClusterService clusterService, - TransportService transportService, - NodeClient nodeClient, - ConfigurationRepository configurationRepository, - Settings settings, - Client client - ) { - this.clusterService = clusterService; - this.transportService = transportService; - this.nodeClient = nodeClient; - this.configurationRepository = configurationRepository; - this.securityIndex = settings.get(ConfigConstants.SECURITY_CONFIG_INDEX_NAME, - ConfigConstants.OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX); - this.client = client; - } - - protected void saveAndUpdateConfiguration(final Client client, final CType cType, - final SecurityDynamicConfiguration configuration) { - final IndexRequest ir = new IndexRequest(this.securityIndex); - - // final String type = "_doc"; - final String id = cType.toLCString(); - - configuration.removeStatic(); - - try { - client.index(ir.id(id) - .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) - .setIfSeqNo(configuration.getSeqNo()) - .setIfPrimaryTerm(configuration.getPrimaryTerm()) - .source(id, XContentHelper.toXContent(configuration, XContentType.JSON, false))); - } catch (IOException e) { - throw ExceptionsHelper.convertToOpenSearchException(e); - } - } - - /** - * Load data for a given CType - * @param config CType whose data is to be loaded in-memory - * @return configuration loaded with given CType data - */ - protected static final SecurityDynamicConfiguration load(final CType config) { - SecurityDynamicConfiguration loaded = configurationRepository.getConfigurationsFromIndex(Collections.singleton(config)) - .get(config) - .deepClone(); - return loaded; - } - - ObjectMapper mapper = new ObjectMapper(); - - public ExtensionRegistrationResponse register(String extensionUniqueId) throws ExtensionRegistrationException, IOException { - - ExtensionRegistrationResponse registrationResponse = new ExtensionRegistrationResponse(extensionUniqueId); - if (registrationResponse.extensionIsRegistered()) { // Check if this is an old extension - return registrationResponse; - } - addServiceAccount(extensionUniqueId); - if (registrationResponse.extensionIsRegistered()) { // Confirm it was added - return registrationResponse; - } - else { // Throw if failed to add - throw new ExtensionRegistrationException("An error occurred when registering extension " + extensionUniqueId); - } - } - - private void addServiceAccount(String extensionUniqueId) throws ExtensionRegistrationException, IOException { - - final String serviceAccountName = extensionUniqueId; - final DiscoveryExtensionNode extensionInformation = OpenSearchSecurityPlugin.GuiceHolder.getExtensionsManager().getExtensionIdMap().get(extensionUniqueId); - // extensionInformation.getSecurityConfiguration(); TODO: Need to make it so that we can get the extension configuration information - // extensionInformation.parseToJson(); - // Add default role option for extensions which do not specify their own role - final String extensionRole = "opendistro_security_all_access"; // TODO: Swap this to be parsed role with name equal to extension name once configuration reading is live - final Map extensionAttributes = new HashMap<>(); - extensionAttributes.put("service", "true"); // This attribute signifies that the account is a service account - - final String createServiceAccountPayload = "{\n" + - " \"opendistro_security_roles\": [\"" + extensionRole + "\"],\n" + - " \"attributes\": {\n" + extensionAttributes.toString() + "\n" + - " }\n" + - "}"; - - JsonNode actualObj; - - try { - actualObj = mapper.readTree(createServiceAccountPayload); - } catch (JsonProcessingException ex) { - throw new ExtensionRegistrationException("Failed to parse the provided configuration settings. Failed to register extension: " + extensionUniqueId); - } - - ObjectNode content = (ObjectNode) actualObj; - final SecurityJsonNode securityJsonNode = new SecurityJsonNode(actualObj); - - // A password cannot be provided for a Service account. - final String plainTextPassword = securityJsonNode.get("password").asString(); - final String origHash = securityJsonNode.get("hash").asString(); - if (plainTextPassword != null && plainTextPassword.length() > 0) { - throw new ExtensionRegistrationException("A password cannot be provided for extensions. Failed to register extension: " + extensionUniqueId); - } - - if (origHash != null && origHash.length() > 0) { - throw new ExtensionRegistrationException("A password hash cannot be provided for extensions. Failed to register extension: " + extensionUniqueId); - } - final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName()); - - internalUsersConfiguration.putCObject(serviceAccountName, DefaultObjectMapper.readTree(content, internalUsersConfiguration.getImplementingClass())); - - saveAndUpdateConfiguration(client, CType.INTERNALUSERS, internalUsersConfiguration); - - } - - public static boolean extensionServiceAccountExists(String extensionUniqueId) { - - final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName()); - return internalUsersConfiguration.exists(extensionUniqueId); - } -} diff --git a/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetAction.java b/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetAction.java deleted file mode 100644 index 3193aac8aa..0000000000 --- a/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetAction.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2015-2018 _floragunn_ GmbH - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.extensions.api; - -import org.opensearch.action.ActionType; - -public class ServiceAccountGetAction extends ActionType { - - public static final ServiceAccountGetAction INSTANCE = new ServiceAccountGetAction(); - public static final String NAME = "cluster:admin/security/extensions/service_account/get"; - - protected ServiceAccountGetAction() { - super(NAME, ServiceAccountGetResponse::new); - } -} diff --git a/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetRequest.java b/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetRequest.java deleted file mode 100644 index 3edef25617..0000000000 --- a/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetRequest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2015-2018 _floragunn_ GmbH - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.extensions.api; - -import org.opensearch.action.ActionRequest; -import org.opensearch.action.ActionRequestValidationException; -import org.opensearch.action.support.nodes.BaseNodesRequest; -import org.opensearch.common.io.stream.StreamInput; -import org.opensearch.common.io.stream.StreamOutput; -import org.opensearch.security.action.configupdate.ConfigUpdateRequest; - -import java.io.IOException; - -public class ServiceAccountGetRequest extends ActionRequest { - - private String extensionId; - - public ServiceAccountGetRequest(StreamInput in) throws IOException { - this.extensionId = in.readString(); - } - - public ServiceAccountGetRequest() { - super(); - } - - public ServiceAccountGetRequest(String extensionId) { - this(); - setExtensionId(extensionId); - } - - - public void writeTo(final StreamOutput out) throws IOException { - out.writeStringArray(extensionId.split("")); - } - - public String getExtensionId() { - return extensionId; - } - - public void setExtensionId(final String extensionId) { - this.extensionId = extensionId; - } - - public ActionRequestValidationException validate() { - if (extensionId == null || extensionId.length() == 0) { - return new ActionRequestValidationException(); - } - return null; - } -} - diff --git a/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetResponse.java b/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetResponse.java deleted file mode 100644 index 7184cf548b..0000000000 --- a/src/main/java/org/opensearch/security/extensions/api/ServiceAccountGetResponse.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2015-2018 _floragunn_ GmbH - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.extensions.api; - -import org.opensearch.action.ActionResponse; -import org.opensearch.common.io.stream.StreamInput; -import org.opensearch.common.io.stream.StreamOutput; -import org.opensearch.core.xcontent.ToXContent; -import org.opensearch.core.xcontent.XContentBuilder; - -import java.io.IOException; - -public class ServiceAccountGetResponse extends ActionResponse { - - private String message; - - public ServiceAccountGetResponse(StreamInput in) throws IOException { - this.message = in.readOptionalString(); - } - - public ServiceAccountGetResponse(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - - public void writeTo(StreamOutput out) throws IOException { - out.writeOptionalString(message); - } - - @Override - public String toString() { - return "ServiceAccountGetResponse, message=" + message + ""; - } - - public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { - builder.startObject(); - builder.field("message", message); - builder.endObject(); - return builder; - } -} diff --git a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java b/src/main/java/org/opensearch/security/user/AccountCreateOrUpdateException.java similarity index 55% rename from src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java rename to src/main/java/org/opensearch/security/user/AccountCreateOrUpdateException.java index 78c66ff40c..576ab3f6c6 100644 --- a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationIT.java +++ b/src/main/java/org/opensearch/security/user/AccountCreateOrUpdateException.java @@ -24,17 +24,28 @@ * GitHub history for details. */ -package org.opensearch.security.extensions; +package org.opensearch.security.user; -import org.junit.Test; +public class AccountCreateOrUpdateException extends Exception { -import static org.junit.Assert.assertEquals; + public AccountCreateOrUpdateException() { + super(); + } + + public AccountCreateOrUpdateException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } -public class ExtensionRegistrationIT { + public AccountCreateOrUpdateException(String message, Throwable cause) { + super(message, cause); + } + + public AccountCreateOrUpdateException(String message) { + super(message); + } - //TODO: Add integration tests once core side is implemented - @Test - public void testPassThrough() { - assertEquals(true, true); + public AccountCreateOrUpdateException(Throwable cause) { + super(cause); } } diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java b/src/main/java/org/opensearch/security/user/ServiceAccountRegistrationException.java similarity index 70% rename from src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java rename to src/main/java/org/opensearch/security/user/ServiceAccountRegistrationException.java index fe0f6ef859..d4c7e8acd5 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationException.java +++ b/src/main/java/org/opensearch/security/user/ServiceAccountRegistrationException.java @@ -24,28 +24,28 @@ * GitHub history for details. */ -package org.opensearch.security.extensions; +package org.opensearch.security.user; -public class ExtensionRegistrationException extends Exception { +public class ServiceAccountRegistrationException extends Exception { - public ExtensionRegistrationException() { + public ServiceAccountRegistrationException() { super(); } - public ExtensionRegistrationException(String message, Throwable cause, boolean enableSuppression, + public ServiceAccountRegistrationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } - public ExtensionRegistrationException(String message, Throwable cause) { + public ServiceAccountRegistrationException(String message, Throwable cause) { super(message, cause); } - public ExtensionRegistrationException(String message) { + public ServiceAccountRegistrationException(String message) { super(message); } - public ExtensionRegistrationException(Throwable cause) { + public ServiceAccountRegistrationException(Throwable cause) { super(cause); } } diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java b/src/main/java/org/opensearch/security/user/ServiceAccountRegistrationResponse.java similarity index 81% rename from src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java rename to src/main/java/org/opensearch/security/user/ServiceAccountRegistrationResponse.java index 5f0c493312..fd10429a09 100644 --- a/src/main/java/org/opensearch/security/extensions/ExtensionRegistrationResponse.java +++ b/src/main/java/org/opensearch/security/user/ServiceAccountRegistrationResponse.java @@ -24,21 +24,17 @@ * GitHub history for details. */ -package org.opensearch.security.extensions; +package org.opensearch.security.user; -import org.opensearch.security.privileges.DocumentAllowList; - -import static org.opensearch.security.extensions.ExtensionsService.extensionServiceAccountExists; - -public class ExtensionRegistrationResponse { +public class ServiceAccountRegistrationResponse { //TODO: May not need this class; could move into ExtensionHelper private final String extensionUniqueId; private boolean registrationComplete; - public ExtensionRegistrationResponse(String extensionUniqueId) { + public ServiceAccountRegistrationResponse(String extensionUniqueId) { this.extensionUniqueId = extensionUniqueId; this.registrationComplete = extensionIsRegistered(); } @@ -48,7 +44,7 @@ public boolean extensionIsRegistered(){ // Todo: This should make sure that the if (registrationComplete) { return true; } - if (extensionServiceAccountExists(this.extensionUniqueId)) { + if (UserService.accountExists(this.extensionUniqueId)) { this.registrationComplete = true; return true; } @@ -70,7 +66,7 @@ public boolean equals(Object obj) { if (this.getClass() != obj.getClass()) { return false; } - ExtensionRegistrationResponse otherExReg = (ExtensionRegistrationResponse) (obj); + ServiceAccountRegistrationResponse otherExReg = (ServiceAccountRegistrationResponse) (obj); if (!this.extensionUniqueId.equals(otherExReg.extensionUniqueId)) { return false; } diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index c6eea8ef4c..bb7b800287 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -1,4 +1,22 @@ /* +<<<<<<< HEAD +======= + * Copyright 2015-2018 _floragunn_ GmbH + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +>>>>>>> e8c75356f51 (clear) * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to @@ -21,6 +39,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.opensearch.ExceptionsHelper; +import org.opensearch.action.index.IndexRequest; +import org.opensearch.action.support.WriteRequest; import org.opensearch.client.Client; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; @@ -31,6 +52,14 @@ import org.opensearch.security.securityconf.Hashed; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.common.xcontent.XContentHelper; +import org.opensearch.common.xcontent.XContentType; +import org.opensearch.security.DefaultObjectMapper; +import org.opensearch.security.configuration.ConfigurationRepository; +import org.opensearch.security.securityconf.Hashed; +import org.opensearch.security.securityconf.impl.CType; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.securityconf.impl.v7.InternalUserV7; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.SecurityJsonNode; @@ -42,10 +71,12 @@ public class UserService { protected final Logger log = LogManager.getLogger(this.getClass()); + ClusterService clusterService; static ConfigurationRepository configurationRepository; String securityIndex; Client client; + final static String NO_PASSWORD_OR_HASH_MESSAGE = "Please specify either 'hash' or 'password' when creating a new internal user."; final static String RESTRICTED_CHARACTER_USE_MESSAGE = "A restricted character(s) was detected in the account name. Please remove: "; @@ -54,9 +85,8 @@ public class UserService { final static String SERVICE_ACCOUNT_HASH_MESSAGE = "A password hash cannot be provided for service account. Failed to register service account: "; final static String NO_ACCOUNT_NAME_MESSAGE = "No account name was specified in the request."; - private static CType getConfigName() { - return CType.INTERNALUSERS; - } + + protected static CType getConfigName() { return CType.INTERNALUSERS;} static final List RESTRICTED_FROM_USERNAME = ImmutableList.of( ":" // Not allowed in basic auth, see https://stackoverflow.com/a/33391003/533057 @@ -86,9 +116,31 @@ protected static final SecurityDynamicConfiguration load(final CType config, return DynamicConfigFactory.addStatics(loaded); } + + protected void saveAndUpdateConfiguration(final Client client, final CType cType, + final SecurityDynamicConfiguration configuration) { + final IndexRequest ir = new IndexRequest(this.securityIndex); + + // final String type = "_doc"; + final String id = cType.toLCString(); + + configuration.removeStatic(); + + try { + client.index(ir.id(id) + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .setIfSeqNo(configuration.getSeqNo()) + .setIfPrimaryTerm(configuration.getPrimaryTerm()) + .source(id, XContentHelper.toXContent(configuration, XContentType.JSON, false))); + } catch (IOException e) { + throw ExceptionsHelper.convertToOpenSearchException(e); + } + } + /** * This function will handle the creation or update of a user account. * +<<<<<<< HEAD * @param contentAsNode An object node of different account configurations. * @return InternalUserConfiguration with the new/updated user * @throws UserServiceException diff --git a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java b/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java deleted file mode 100644 index 1b4780912c..0000000000 --- a/src/test/java/org/opensearch/security/extensions/ExtensionRegistrationUnitTests.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2015-2018 _floragunn_ GmbH - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.extensions; - - -import java.util.ArrayList; -import java.util.Collection; -import java.util.function.Supplier; - -import org.junit.Before; -import org.junit.Test; - -import org.opensearch.client.Client; -import org.opensearch.cluster.metadata.IndexNameExpressionResolver; -import org.opensearch.cluster.routing.allocation.decider.Decision; -import org.opensearch.cluster.service.ClusterService; -import org.opensearch.common.io.stream.NamedWriteableRegistry; -import org.opensearch.core.xcontent.NamedXContentRegistry; -import org.opensearch.env.Environment; -import org.opensearch.env.NodeEnvironment; -import org.opensearch.plugins.ActionPlugin; -import org.opensearch.plugins.Plugin; -import org.opensearch.repositories.RepositoriesService; -import org.opensearch.script.ScriptService; -import org.opensearch.security.auth.internal.InternalAuthenticationBackend; -import org.opensearch.security.securityconf.InternalUsersModel; -import org.opensearch.security.support.ConfigConstants; -import org.opensearch.security.test.SingleClusterTest; -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.watcher.ResourceWatcherService; - -import static org.junit.Assert.assertEquals; - -public class ExtensionRegistrationUnitTests extends SingleClusterTest { - - //TODO: Figure out how to build these tests when normally inject - - public Collection createComponents(Client client, ClusterService clusterService, ThreadPool threadPool, - ResourceWatcherService resourceWatcherService, ScriptService scriptService, - NamedXContentRegistry xContentRegistry, Environment environment, - NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry, - IndexNameExpressionResolver indexNameExpressionResolver, - Supplier repositoriesServiceSupplier) { - - return new ArrayList<>(); - } - - @Test - public void testRegisterExtensionExtensionExists() { - - assertEquals(true, true); - } - - @Test - public void testRegisterExtensionExtensionDoesNotExist() { - assertEquals(true, true); - } - - @Test - public void testExtensionIsRegisteredRegisteredCheck() { - assertEquals(true, true); - } - - @Test - public void testExtensionIsNotRegisteredRegisteredCheck() { - assertEquals(true, true); - } - - @Test - public void testAddValidServiceAccount() { - assertEquals(true, true); - } - - @Test - public void testAddInvalidServiceAccount() { - assertEquals(true, true); - } - - @Test - public void testServiceAccountWasAddedToConfig() { - assertEquals(true, true); - } -} From d689d23377ad11563c3e3babf149897d968ef28b Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Fri, 31 Mar 2023 16:35:52 -0400 Subject: [PATCH 10/45] Checkstyle Signed-off-by: Stephen Crawford --- .../security/configuration/ConfigurationRepository.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java index 26bca1242b..b137549511 100644 --- a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java +++ b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java @@ -75,7 +75,6 @@ import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.ConfigHelper; -import org.opensearch.security.support.SecurityJsonNode; import org.opensearch.security.support.SecurityUtils; import org.opensearch.threadpool.ThreadPool; From 5d4cc8f1eb2bb7b824a3f3961de2abf7b5230c50 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 3 Apr 2023 10:35:57 -0400 Subject: [PATCH 11/45] Comment out test Signed-off-by: Stephen Crawford --- .../opensearch/security/TransportUserInjectorIntegTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java index a3e08d5234..fea9768e70 100644 --- a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java +++ b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java @@ -95,7 +95,7 @@ public void testSecurityUserInjection() throws Exception { Assert.assertTrue(cir.isAcknowledged()); } - + /* // 2. with invalid backend roles UserInjectorPlugin.injectedUser = "ttt|kkk"; Exception exception = null; @@ -110,6 +110,8 @@ public void testSecurityUserInjection() throws Exception { Assert.assertNotNull(exception); Assert.assertTrue(exception.getMessage().toString().contains("no permissions for [indices:admin/create]")); } + */ + // 3. with valid backend roles for injected user From 13f3819048e4a5483925fe232edd5274060883ea Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 3 Apr 2023 10:54:34 -0400 Subject: [PATCH 12/45] spotless Signed-off-by: Stephen Crawford --- .../security/DlsIntegrationTests.java | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java b/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java index a99d584a50..a172a20ec3 100644 --- a/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java +++ b/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java @@ -52,6 +52,7 @@ import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS; import static org.opensearch.test.framework.cluster.SearchRequestFactory.averageAggregationRequest; +import static org.opensearch.test.framework.cluster.SearchRequestFactory.statsAggregationRequest; import static org.opensearch.test.framework.matcher.SearchResponseMatchers.containAggregationWithNameAndType; import static org.opensearch.test.framework.matcher.SearchResponseMatchers.isSuccessfulSearchResponse; import static org.opensearch.test.framework.matcher.SearchResponseMatchers.numberOfTotalHitsIsEqualTo; @@ -476,4 +477,129 @@ public void testAggregateAndComputeStarRatings() throws IOException { assertThat(((ParsedAvg) actualAggregation).getValue(), is(1.5)); } } + + @Test + public void testSearchForAllDocumentsWithAlias() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); + assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); + assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); + assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); + + searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); + } + } + + @Test + public void testSearchForAllDocumentsWithAlias() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); + assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); + assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); + assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); + + searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); + } + } + + @Test + public void testSearchForAllDocumentsWithAlias() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); + assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); + assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); + assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); + + searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); + } + } + + @Test + public void testSearchForAllDocumentsWithAlias() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); + assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); + assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); + assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); + + searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); + } + } + + @Test + public void testSearchForAllDocumentsWithAlias() throws IOException { + + try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { + SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); + SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); + assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); + assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); + assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); + assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); + assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); + + searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); + searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); + + assertThat(searchResponse, isSuccessfulSearchResponse()); + assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); + assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); + } + } } From 34b4e4be2d19678011591de21dc5f3ed08355e4a Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 3 Apr 2023 11:09:05 -0400 Subject: [PATCH 13/45] Remove extra tests Signed-off-by: Stephen Crawford --- .../security/DlsIntegrationTests.java | 125 ------------------ 1 file changed, 125 deletions(-) diff --git a/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java b/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java index a172a20ec3..1d615360f4 100644 --- a/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java +++ b/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java @@ -477,129 +477,4 @@ public void testAggregateAndComputeStarRatings() throws IOException { assertThat(((ParsedAvg) actualAggregation).getValue(), is(1.5)); } } - - @Test - public void testSearchForAllDocumentsWithAlias() throws IOException { - - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { - SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); - assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); - assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); - assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); - assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); - assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); - - searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); - searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); - } - } - - @Test - public void testSearchForAllDocumentsWithAlias() throws IOException { - - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { - SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); - assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); - assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); - assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); - assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); - assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); - - searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); - searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); - } - } - - @Test - public void testSearchForAllDocumentsWithAlias() throws IOException { - - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { - SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); - assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); - assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); - assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); - assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); - assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); - - searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); - searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); - } - } - - @Test - public void testSearchForAllDocumentsWithAlias() throws IOException { - - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { - SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); - assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); - assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); - assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); - assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); - assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); - - searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); - searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); - } - } - - @Test - public void testSearchForAllDocumentsWithAlias() throws IOException { - - try (RestHighLevelClient restHighLevelClient = cluster.getRestHighLevelClient(READ_ALL_USER)) { - SearchRequest searchRequest = new SearchRequest(FIRST_INDEX_ALIAS); - SearchResponse searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(6)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_FIRST)); - assertThat(searchResponse, searchHitContainsFieldWithValue(1, FIELD_ARTIST, ARTIST_STRING)); - assertThat(searchResponse, searchHitContainsFieldWithValue(2, FIELD_ARTIST, ARTIST_TWINS)); - assertThat(searchResponse, searchHitContainsFieldWithValue(3, FIELD_ARTIST, ARTIST_NO)); - assertThat(searchResponse, searchHitContainsFieldWithValue(4, FIELD_ARTIST, ARTIST_YES)); - assertThat(searchResponse, searchHitContainsFieldWithValue(5, FIELD_ARTIST, ARTIST_UNKNOWN)); - - searchRequest = new SearchRequest("*".concat(SECOND_INDEX_NAME)); - searchResponse = restHighLevelClient.search(searchRequest, DEFAULT); - - assertThat(searchResponse, isSuccessfulSearchResponse()); - assertThat(searchResponse, numberOfTotalHitsIsEqualTo(4)); - assertThat(searchResponse, searchHitContainsFieldWithValue(0, FIELD_ARTIST, ARTIST_NO)); - } - } } From 10bd3bbdc4cc6ebf4321c24d6770a149be19044d Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 3 Apr 2023 16:26:37 -0400 Subject: [PATCH 14/45] Update imports Signed-off-by: Stephen Crawford --- .../java/org/opensearch/security/DlsIntegrationTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java b/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java index 1d615360f4..a99d584a50 100644 --- a/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java +++ b/src/integrationTest/java/org/opensearch/security/DlsIntegrationTests.java @@ -52,7 +52,6 @@ import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; import static org.opensearch.test.framework.TestSecurityConfig.Role.ALL_ACCESS; import static org.opensearch.test.framework.cluster.SearchRequestFactory.averageAggregationRequest; -import static org.opensearch.test.framework.cluster.SearchRequestFactory.statsAggregationRequest; import static org.opensearch.test.framework.matcher.SearchResponseMatchers.containAggregationWithNameAndType; import static org.opensearch.test.framework.matcher.SearchResponseMatchers.isSuccessfulSearchResponse; import static org.opensearch.test.framework.matcher.SearchResponseMatchers.numberOfTotalHitsIsEqualTo; From 0f7f62fea04d896b59a9f41bc468b3241d636665 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 3 Apr 2023 16:30:08 -0400 Subject: [PATCH 15/45] Update imports Signed-off-by: Stephen Crawford --- .../org/opensearch/security/TransportUserInjectorIntegTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java index fea9768e70..fe781bd443 100644 --- a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java +++ b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java @@ -19,7 +19,7 @@ import org.junit.Assert; import org.junit.Test; -import org.opensearch.OpenSearchSecurityException; +//import org.opensearch.OpenSearchSecurityException; import org.opensearch.action.admin.indices.create.CreateIndexRequest; import org.opensearch.action.admin.indices.create.CreateIndexResponse; import org.opensearch.client.Client; From 0327f3b4f0bde5ed0e2510a35bb3726a08a8c36f Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 3 Apr 2023 16:32:16 -0400 Subject: [PATCH 16/45] Update imports Signed-off-by: Stephen Crawford --- .../org/opensearch/security/TransportUserInjectorIntegTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java index fe781bd443..44ebbb9956 100644 --- a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java +++ b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java @@ -19,7 +19,6 @@ import org.junit.Assert; import org.junit.Test; -//import org.opensearch.OpenSearchSecurityException; import org.opensearch.action.admin.indices.create.CreateIndexRequest; import org.opensearch.action.admin.indices.create.CreateIndexResponse; import org.opensearch.client.Client; From 2263129d42306fa8a09c9965ec6c455cc8dc6d6e Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Tue, 4 Apr 2023 12:14:38 -0400 Subject: [PATCH 17/45] Update contains Signed-off-by: Stephen Crawford --- .../java/org/opensearch/security/user/UserService.java | 1 - .../security/TransportUserInjectorIntegTest.java | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index bb7b800287..1d40f7b3c8 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -148,7 +148,6 @@ protected void saveAndUpdateConfiguration(final Client client, final CType cType */ public SecurityDynamicConfiguration createOrUpdateAccount(ObjectNode contentAsNode) throws IOException { - SecurityJsonNode securityJsonNode = new SecurityJsonNode(contentAsNode); final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName(), false); diff --git a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java index 44ebbb9956..077a26e4dd 100644 --- a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java +++ b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java @@ -19,6 +19,7 @@ import org.junit.Assert; import org.junit.Test; +import org.opensearch.OpenSearchSecurityException; import org.opensearch.action.admin.indices.create.CreateIndexRequest; import org.opensearch.action.admin.indices.create.CreateIndexResponse; import org.opensearch.client.Client; @@ -94,7 +95,7 @@ public void testSecurityUserInjection() throws Exception { Assert.assertTrue(cir.isAcknowledged()); } - /* + // 2. with invalid backend roles UserInjectorPlugin.injectedUser = "ttt|kkk"; Exception exception = null; @@ -107,9 +108,9 @@ public void testSecurityUserInjection() throws Exception { exception = ex; log.debug(ex.toString()); Assert.assertNotNull(exception); - Assert.assertTrue(exception.getMessage().toString().contains("no permissions for [indices:admin/create]")); + Assert.assertTrue(exception.getMessage().contains("no permissions for [indices:admin/create] and User [name=ttt, backend_roles=[kkk], requestedTenant=null]")); + } - */ From 9d2ec1d5e646183bed5025044499041386d18830 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Tue, 4 Apr 2023 13:55:34 -0400 Subject: [PATCH 18/45] fix service Signed-off-by: Stephen Crawford --- src/main/java/org/opensearch/security/user/UserService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 1d40f7b3c8..948f88b1bb 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -56,6 +56,7 @@ >>>>>>> e8c75356f51 (clear) import org.opensearch.common.xcontent.XContentType; import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.configuration.ConfigurationRepository; +import org.opensearch.security.securityconf.DynamicConfigFactory; import org.opensearch.security.securityconf.Hashed; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; @@ -202,6 +203,8 @@ public SecurityDynamicConfiguration createOrUpdateAccount(ObjectNode contentA internalUsersConfiguration.remove(accountName); contentAsNode.remove("name"); + internalUsersConfiguration.remove(accountName); + contentAsNode.remove("name"); internalUsersConfiguration.putCObject(accountName, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass())); return internalUsersConfiguration; } From b1ffa6df2844e18dfefaeb924bc2fae9627bb4ad Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Wed, 5 Apr 2023 09:44:50 -0400 Subject: [PATCH 19/45] Fix tests Signed-off-by: Stephen Crawford --- .../dlic/rest/api/InternalUsersApiAction.java | 2 +- .../opensearch/security/user/UserService.java | 22 +++++++++++++++++-- .../security/dlic/rest/api/UserApiTest.java | 14 ++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 42a32280c0..50a3100092 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -104,7 +104,6 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C final String username = request.param("name"); - SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName(), false); if (!isWriteable(channel, internalUsersConfiguration, username)) { @@ -137,6 +136,7 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C ((ObjectNode) content).put("isEnabled", request.param("isEnabled")); } ((ObjectNode) content).put("name", username); + internalUsersConfiguration = userService.createOrUpdateAccount((ObjectNode) content); } catch (UserServiceException ex) { diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 948f88b1bb..95a037a50c 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -141,6 +141,7 @@ protected void saveAndUpdateConfiguration(final Client client, final CType cType /** * This function will handle the creation or update of a user account. * +<<<<<<< HEAD <<<<<<< HEAD * @param contentAsNode An object node of different account configurations. * @return InternalUserConfiguration with the new/updated user @@ -203,8 +204,6 @@ public SecurityDynamicConfiguration createOrUpdateAccount(ObjectNode contentA internalUsersConfiguration.remove(accountName); contentAsNode.remove("name"); - internalUsersConfiguration.remove(accountName); - contentAsNode.remove("name"); internalUsersConfiguration.putCObject(accountName, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass())); return internalUsersConfiguration; } @@ -232,4 +231,23 @@ private String generatePassword() { String generatedPassword = "superSecurePassword"; return generatedPassword; } + + public String getNO_PASSWORD_OR_HASH_MESSAGE() { + return NO_PASSWORD_OR_HASH_MESSAGE; + } + + public String getRESTRICTED_CHARACTER_USE_MESSAGE() { + return RESTRICTED_CHARACTER_USE_MESSAGE; + } + + public String getSERVICE_ACCOUNT_PASSWORD_MESSAGE() { + return SERVICE_ACCOUNT_PASSWORD_MESSAGE; + } + + public String getSERVICE_ACCOUNT_HASH_MESSAGE() { + return SERVICE_ACCOUNT_HASH_MESSAGE; + } + public String getNO_ACCOUNT_NAME_MESSAGE() { + return NO_ACCOUNT_NAME_MESSAGE; + } } diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java index d755751e54..a51aceb3b2 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java @@ -376,33 +376,45 @@ private void verifyPatch(final boolean sendAdminCert, Header... restAdminHeader) Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); Assert.assertTrue(response.getBody().contains("'q' deleted.")); // now really remove user + System.out.println("Removing Nagilum"); deleteUser("nagilum"); // Access must be forbidden now rh.sendAdminCertificate = false; + System.out.println("Making sure access is forbidden"); checkGeneralAccess(HttpStatus.SC_UNAUTHORIZED, "nagilum", "nagilum"); // use password instead of hash rh.sendAdminCertificate = sendAdminCert; + System.out.println("Using password instead of hash"); addUserWithPassword("nagilum", "correctpassword", HttpStatus.SC_CREATED); rh.sendAdminCertificate = false; + System.out.println("Checking general access"); + System.out.println("Use wrongpass"); checkGeneralAccess(HttpStatus.SC_UNAUTHORIZED, "nagilum", "wrongpassword"); + System.out.println("use correct pass"); checkGeneralAccess(HttpStatus.SC_OK, "nagilum", "correctpassword"); + System.out.println("Delete Nagilum"); deleteUser("nagilum"); // Check unchanged password functionality + System.out.println("Check unchanged pass functionality"); rh.sendAdminCertificate = sendAdminCert; // new user, password or hash is mandatory + System.out.println("Add Nagilum without pass or hash"); addUserWithoutPasswordOrHash("nagilum", new String[]{"starfleet"}, HttpStatus.SC_BAD_REQUEST); // new user, add hash + System.out.println("Add Nagilum with hash"); addUserWithHash("nagilum", "$2a$12$n5nubfWATfQjSYHiWtUyeOxMIxFInUHOAx8VMmGmxFNPGpaBmeB.m", HttpStatus.SC_CREATED); + System.out.println("Update Nagilum without specifying hash"); // update user, do not specify hash or password, hash must remain the same addUserWithoutPasswordOrHash("nagilum", new String[]{"starfleet"}, HttpStatus.SC_OK); // get user, check hash, must be untouched + System.out.println("Get Nagilum make sure hash is untouched"); response = rh.executeGetRequest(ENDPOINT + "/internalusers/nagilum", restAdminHeader); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); @@ -510,8 +522,10 @@ public void testUserApiWithRestInternalUsersAdminPermissions() throws Exception final Header restApiInternalUsersAdminHeader = encodeBasicHeader("rest_api_admin_internalusers", "rest_api_admin_internalusers"); // initial configuration HttpResponse response = rh.executeGetRequest(ENDPOINT + "/" + CType.INTERNALUSERS.toLCString(), restApiInternalUsersAdminHeader); + System.out.println("Rest response in test is: " + response.toString()); Assert.assertEquals(response.getBody(), HttpStatus.SC_OK, response.getStatusCode()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); + System.out.println("Settings size in test is: " + settings.size()); Assert.assertEquals(133, settings.size()); verifyGet(restApiInternalUsersAdminHeader); verifyPut(restApiInternalUsersAdminHeader); From 9b59a769a1e54830fce6e9274a4da3633d3fbafd Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Wed, 5 Apr 2023 09:46:34 -0400 Subject: [PATCH 20/45] remove prints Signed-off-by: Stephen Crawford --- .../security/dlic/rest/api/UserApiTest.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java index a51aceb3b2..d755751e54 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java @@ -376,45 +376,33 @@ private void verifyPatch(final boolean sendAdminCert, Header... restAdminHeader) Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); Assert.assertTrue(response.getBody().contains("'q' deleted.")); // now really remove user - System.out.println("Removing Nagilum"); deleteUser("nagilum"); // Access must be forbidden now rh.sendAdminCertificate = false; - System.out.println("Making sure access is forbidden"); checkGeneralAccess(HttpStatus.SC_UNAUTHORIZED, "nagilum", "nagilum"); // use password instead of hash rh.sendAdminCertificate = sendAdminCert; - System.out.println("Using password instead of hash"); addUserWithPassword("nagilum", "correctpassword", HttpStatus.SC_CREATED); rh.sendAdminCertificate = false; - System.out.println("Checking general access"); - System.out.println("Use wrongpass"); checkGeneralAccess(HttpStatus.SC_UNAUTHORIZED, "nagilum", "wrongpassword"); - System.out.println("use correct pass"); checkGeneralAccess(HttpStatus.SC_OK, "nagilum", "correctpassword"); - System.out.println("Delete Nagilum"); deleteUser("nagilum"); // Check unchanged password functionality - System.out.println("Check unchanged pass functionality"); rh.sendAdminCertificate = sendAdminCert; // new user, password or hash is mandatory - System.out.println("Add Nagilum without pass or hash"); addUserWithoutPasswordOrHash("nagilum", new String[]{"starfleet"}, HttpStatus.SC_BAD_REQUEST); // new user, add hash - System.out.println("Add Nagilum with hash"); addUserWithHash("nagilum", "$2a$12$n5nubfWATfQjSYHiWtUyeOxMIxFInUHOAx8VMmGmxFNPGpaBmeB.m", HttpStatus.SC_CREATED); - System.out.println("Update Nagilum without specifying hash"); // update user, do not specify hash or password, hash must remain the same addUserWithoutPasswordOrHash("nagilum", new String[]{"starfleet"}, HttpStatus.SC_OK); // get user, check hash, must be untouched - System.out.println("Get Nagilum make sure hash is untouched"); response = rh.executeGetRequest(ENDPOINT + "/internalusers/nagilum", restAdminHeader); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); @@ -522,10 +510,8 @@ public void testUserApiWithRestInternalUsersAdminPermissions() throws Exception final Header restApiInternalUsersAdminHeader = encodeBasicHeader("rest_api_admin_internalusers", "rest_api_admin_internalusers"); // initial configuration HttpResponse response = rh.executeGetRequest(ENDPOINT + "/" + CType.INTERNALUSERS.toLCString(), restApiInternalUsersAdminHeader); - System.out.println("Rest response in test is: " + response.toString()); Assert.assertEquals(response.getBody(), HttpStatus.SC_OK, response.getStatusCode()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); - System.out.println("Settings size in test is: " + settings.size()); Assert.assertEquals(133, settings.size()); verifyGet(restApiInternalUsersAdminHeader); verifyPut(restApiInternalUsersAdminHeader); From 6b52eebcd8fa0d3c3629b5f3ce3538734ae3e2ff Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Thu, 6 Apr 2023 16:35:11 -0400 Subject: [PATCH 21/45] Clean service Signed-off-by: Stephen Crawford --- .../security/OpenSearchSecurityPlugin.java | 6 +- .../ConfigurationRepository.java | 27 ------- .../dlic/rest/api/InternalUsersApiAction.java | 1 + .../extensions/ExtensionsConfigConstants.java | 33 -------- .../user/AccountCreateOrUpdateException.java | 51 ------------- .../ServiceAccountRegistrationException.java | 51 ------------- .../ServiceAccountRegistrationResponse.java | 75 ------------------- .../opensearch/security/user/UserService.java | 4 +- 8 files changed, 3 insertions(+), 245 deletions(-) delete mode 100644 src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java delete mode 100644 src/main/java/org/opensearch/security/user/AccountCreateOrUpdateException.java delete mode 100644 src/main/java/org/opensearch/security/user/ServiceAccountRegistrationException.java delete mode 100644 src/main/java/org/opensearch/security/user/ServiceAccountRegistrationResponse.java diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index d442b448e9..87ca878fc6 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -94,7 +94,6 @@ import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.env.Environment; import org.opensearch.env.NodeEnvironment; -import org.opensearch.extensions.ExtensionsManager; import org.opensearch.http.HttpServerTransport; import org.opensearch.http.HttpServerTransport.Dispatcher; import org.opensearch.index.Index; @@ -1187,16 +1186,14 @@ public static class GuiceHolder implements LifecycleComponent { private static RemoteClusterService remoteClusterService; private static IndicesService indicesService; private static PitService pitService; - private static ExtensionsManager extensionsManager; @Inject public GuiceHolder(final RepositoriesService repositoriesService, - final TransportService remoteClusterService, IndicesService indicesService, PitService pitService, ExtensionsManager extensionsManager) { + final TransportService remoteClusterService, IndicesService indicesService, PitService pitService) { GuiceHolder.repositoriesService = repositoriesService; GuiceHolder.remoteClusterService = remoteClusterService.getRemoteClusterService(); GuiceHolder.indicesService = indicesService; GuiceHolder.pitService = pitService; - GuiceHolder.extensionsManager = extensionsManager; } public static RepositoriesService getRepositoriesService() { @@ -1213,7 +1210,6 @@ public static IndicesService getIndicesService() { public static PitService getPitService() { return pitService; } - public static ExtensionsManager getExtensionsManager() { return extensionsManager; } @Override public void close() { diff --git a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java index b137549511..3f959fcdec 100644 --- a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java +++ b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java @@ -406,31 +406,4 @@ private static String formatDate(long date) { public static int getDefaultConfigVersion() { return ConfigurationRepository.DEFAULT_CONFIG_VERSION; } - - public Map> getConfigurationsFromIndex(Collection configTypes) { - - final ThreadContext threadContext = threadPool.getThreadContext(); - final Map> retVal = new HashMap<>(); - - try (StoredContext ctx = threadContext.stashContext()) { - threadContext.putHeader(ExtensionsConfigConstants.EXTENSIONS_CONF_REQUEST_HEADER, "true"); - - IndexMetadata securityMetadata = clusterService.state().metadata().index(this.securityIndex); - MappingMetadata mappingMetadata = securityMetadata == null ? null : securityMetadata.mapping(); - - if (securityMetadata != null && mappingMetadata != null) { - retVal.putAll(validate(cl.load(configTypes.toArray(new CType[0]), 5, TimeUnit.SECONDS, false), configTypes.size())); - - } else { - // wait (and use new layout) - LOGGER.debug("Could not access the Security Index"); - retVal.putAll(validate(cl.load(configTypes.toArray(new CType[0]), 5, TimeUnit.SECONDS, false), configTypes.size())); - } - - } catch (Exception e) { - throw new OpenSearchException(e); - } - - return retVal; - } } diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 50a3100092..7915c8aad7 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -12,6 +12,7 @@ package org.opensearch.security.dlic.rest.api; import java.io.IOException; +import java.net.UnknownServiceException; import java.nio.file.Path; import java.util.List; diff --git a/src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java b/src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java deleted file mode 100644 index 92e445b730..0000000000 --- a/src/main/java/org/opensearch/security/extensions/ExtensionsConfigConstants.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2015-2018 _floragunn_ GmbH - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.extensions; - - -public class ExtensionsConfigConstants { - public static final String EXTENSIONS_CONFIG_PREFIX = "_extensions_"; - public static final String EXTENSIONS_CONF_REQUEST_HEADER = EXTENSIONS_CONFIG_PREFIX + "conf_request"; -} diff --git a/src/main/java/org/opensearch/security/user/AccountCreateOrUpdateException.java b/src/main/java/org/opensearch/security/user/AccountCreateOrUpdateException.java deleted file mode 100644 index 576ab3f6c6..0000000000 --- a/src/main/java/org/opensearch/security/user/AccountCreateOrUpdateException.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015-2018 _floragunn_ GmbH - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.user; - -public class AccountCreateOrUpdateException extends Exception { - - public AccountCreateOrUpdateException() { - super(); - } - - public AccountCreateOrUpdateException(String message, Throwable cause, boolean enableSuppression, - boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - - public AccountCreateOrUpdateException(String message, Throwable cause) { - super(message, cause); - } - - public AccountCreateOrUpdateException(String message) { - super(message); - } - - public AccountCreateOrUpdateException(Throwable cause) { - super(cause); - } -} diff --git a/src/main/java/org/opensearch/security/user/ServiceAccountRegistrationException.java b/src/main/java/org/opensearch/security/user/ServiceAccountRegistrationException.java deleted file mode 100644 index d4c7e8acd5..0000000000 --- a/src/main/java/org/opensearch/security/user/ServiceAccountRegistrationException.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2015-2018 _floragunn_ GmbH - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.user; - -public class ServiceAccountRegistrationException extends Exception { - - public ServiceAccountRegistrationException() { - super(); - } - - public ServiceAccountRegistrationException(String message, Throwable cause, boolean enableSuppression, - boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } - - public ServiceAccountRegistrationException(String message, Throwable cause) { - super(message, cause); - } - - public ServiceAccountRegistrationException(String message) { - super(message); - } - - public ServiceAccountRegistrationException(Throwable cause) { - super(cause); - } -} diff --git a/src/main/java/org/opensearch/security/user/ServiceAccountRegistrationResponse.java b/src/main/java/org/opensearch/security/user/ServiceAccountRegistrationResponse.java deleted file mode 100644 index fd10429a09..0000000000 --- a/src/main/java/org/opensearch/security/user/ServiceAccountRegistrationResponse.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2015-2018 _floragunn_ GmbH - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.user; - - -public class ServiceAccountRegistrationResponse { - - //TODO: May not need this class; could move into ExtensionHelper - private final String extensionUniqueId; - - private boolean registrationComplete; - - public ServiceAccountRegistrationResponse(String extensionUniqueId) { - this.extensionUniqueId = extensionUniqueId; - this.registrationComplete = extensionIsRegistered(); - } - - public boolean extensionIsRegistered(){ // Todo: This should make sure that the registration is propagated to all nodes, not sure how to do that - - if (registrationComplete) { - return true; - } - if (UserService.accountExists(this.extensionUniqueId)) { - this.registrationComplete = true; - return true; - } - return false; - } - - public String getExtensionUniqueId() { return extensionUniqueId; } - - public boolean getRegistrationComplete() { return registrationComplete; } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (this.getClass() != obj.getClass()) { - return false; - } - ServiceAccountRegistrationResponse otherExReg = (ServiceAccountRegistrationResponse) (obj); - if (!this.extensionUniqueId.equals(otherExReg.extensionUniqueId)) { - return false; - } - return true; - } -} diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 95a037a50c..0316724b6a 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -30,6 +30,7 @@ >>>>>>> e8c75356f51 (clear) package org.opensearch.security.user; import java.io.IOException; +import java.net.UnknownServiceException; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -77,7 +78,6 @@ public class UserService { static ConfigurationRepository configurationRepository; String securityIndex; Client client; - final static String NO_PASSWORD_OR_HASH_MESSAGE = "Please specify either 'hash' or 'password' when creating a new internal user."; final static String RESTRICTED_CHARACTER_USE_MESSAGE = "A restricted character(s) was detected in the account name. Please remove: "; @@ -141,8 +141,6 @@ protected void saveAndUpdateConfiguration(final Client client, final CType cType /** * This function will handle the creation or update of a user account. * -<<<<<<< HEAD -<<<<<<< HEAD * @param contentAsNode An object node of different account configurations. * @return InternalUserConfiguration with the new/updated user * @throws UserServiceException From cd36a68b7c7c0ac3ee574de431069c63c46947db Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Thu, 6 Apr 2023 16:35:25 -0400 Subject: [PATCH 22/45] Clean service Signed-off-by: Stephen Crawford --- src/main/java/org/opensearch/security/user/UserService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 0316724b6a..58d9b11aef 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -122,7 +122,6 @@ protected void saveAndUpdateConfiguration(final Client client, final CType cType final SecurityDynamicConfiguration configuration) { final IndexRequest ir = new IndexRequest(this.securityIndex); - // final String type = "_doc"; final String id = cType.toLCString(); configuration.removeStatic(); From cd452010203dc0128ac74c12cb2db6ba6c67ea5b Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Thu, 6 Apr 2023 16:38:23 -0400 Subject: [PATCH 23/45] Clean service Signed-off-by: Stephen Crawford --- .../security/configuration/ConfigurationRepository.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java index 3f959fcdec..31e2a7d16f 100644 --- a/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java +++ b/src/main/java/org/opensearch/security/configuration/ConfigurationRepository.java @@ -68,7 +68,6 @@ import org.opensearch.rest.RestStatus; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.auditlog.config.AuditConfig; -import org.opensearch.security.extensions.ExtensionsConfigConstants; import org.opensearch.security.securityconf.DynamicConfigFactory; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; From 7ab1862f24c13af2de436807cebd8e4f17123447 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Thu, 6 Apr 2023 16:41:19 -0400 Subject: [PATCH 24/45] remove unused import Signed-off-by: Stephen Crawford --- .../security/dlic/rest/api/InternalUsersApiAction.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 7915c8aad7..50a3100092 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -12,7 +12,6 @@ package org.opensearch.security.dlic.rest.api; import java.io.IOException; -import java.net.UnknownServiceException; import java.nio.file.Path; import java.util.List; From 518ef9079d64cc9b1bd03067c8ba249daa4aa4a3 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Thu, 6 Apr 2023 17:02:07 -0400 Subject: [PATCH 25/45] remove imports Signed-off-by: Stephen Crawford --- src/main/java/org/opensearch/security/user/UserService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 58d9b11aef..3984eaa3af 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -30,7 +30,6 @@ >>>>>>> e8c75356f51 (clear) package org.opensearch.security.user; import java.io.IOException; -import java.net.UnknownServiceException; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -61,7 +60,6 @@ >>>>>>> e8c75356f51 (clear) import org.opensearch.security.securityconf.Hashed; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; -import org.opensearch.security.securityconf.impl.v7.InternalUserV7; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.SecurityJsonNode; From c8df4fca03263529423decb1aac39424632da994 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Fri, 7 Apr 2023 16:18:09 -0400 Subject: [PATCH 26/45] fix user service and add tests Signed-off-by: Stephen Crawford --- .../security/dlic/rest/api/InternalUsersApiAction.java | 6 +++++- .../java/org/opensearch/security/user/UserService.java | 5 ++++- .../security/dlic/rest/api/AbstractRestApiUnitTest.java | 9 +++++++++ .../opensearch/security/dlic/rest/api/UserApiTest.java | 4 +--- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 50a3100092..f36c487912 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -100,7 +100,9 @@ protected Endpoint getEndpoint() { @Override protected void handlePut(RestChannel channel, final RestRequest request, final Client client, final JsonNode content) throws IOException { - String details = request.toString(); + System.out.println("In handle put"); + System.out.println("Request details are: " + request.params().keySet()); + System.out.println("JsonNode content is: " + content.toString()); final String username = request.param("name"); @@ -152,8 +154,10 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C @Override public void onResponse(IndexResponse response) { if (userExisted) { + System.out.println("System response is success response"); successResponse(channel, "'" + username + "' updated."); } else { + System.out.println("System response is created response"); createdResponse(channel, "'" + username + "' created."); } diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 3984eaa3af..1894424789 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -1,5 +1,6 @@ /* <<<<<<< HEAD +<<<<<<< HEAD ======= * Copyright 2015-2018 _floragunn_ GmbH * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,6 +18,8 @@ /* >>>>>>> e8c75356f51 (clear) +======= +>>>>>>> b07f0f8f0c2 (fix user service and add tests) * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to @@ -115,7 +118,6 @@ protected static final SecurityDynamicConfiguration load(final CType config, return DynamicConfigFactory.addStatics(loaded); } - protected void saveAndUpdateConfiguration(final Client client, final CType cType, final SecurityDynamicConfiguration configuration) { final IndexRequest ir = new IndexRequest(this.securityIndex); @@ -227,6 +229,7 @@ private String generatePassword() { return generatedPassword; } + public String getNO_PASSWORD_OR_HASH_MESSAGE() { return NO_PASSWORD_OR_HASH_MESSAGE; } diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/AbstractRestApiUnitTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/AbstractRestApiUnitTest.java index a1cb20d99c..30e388fd6a 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/AbstractRestApiUnitTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/AbstractRestApiUnitTest.java @@ -192,6 +192,15 @@ protected void addUserWithPasswordAndHash(String username, String password, Stri rh.sendAdminCertificate = sendAdminCertificate; } + protected void addUserWithBody(String username, String body, int status) throws Exception { + boolean sendAdminCertificate = rh.sendAdminCertificate; + rh.sendAdminCertificate = true; + HttpResponse response = rh.executePutRequest("/_opendistro/_security/api/internalusers/" + username, body, + new Header[0]); + Assert.assertEquals(status, response.getStatusCode()); + rh.sendAdminCertificate = sendAdminCertificate; + } + protected void checkGeneralAccess(int status, String username, String password) throws Exception { boolean sendAdminCertificate = rh.sendAdminCertificate; rh.sendAdminCertificate = false; diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java index d755751e54..611c1db921 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java @@ -322,14 +322,13 @@ private void verifyPatch(final boolean sendAdminCert, Header... restAdminHeader) HttpStatus.SC_CREATED); // Add enabled service account then get it + response = rh.executePutRequest(ENDPOINT + "/internalusers/happyServiceLive", ENABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); response = rh.executeGetRequest(ENDPOINT + "/internalusers/happyServiceLive", restAdminHeader); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); - - // Add disabled service account response = rh.executePutRequest(ENDPOINT + "/internalusers/happyServiceDead", DISABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); @@ -340,7 +339,6 @@ private void verifyPatch(final boolean sendAdminCert, Header... restAdminHeader) Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); // Add service account with password -- Should Fail - response = rh.executePutRequest(ENDPOINT + "/internalusers/passwordService", PASSWORD_SERVICE, restAdminHeader); Assert.assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatusCode()); From 4605b55dfb13b0eb841770e03c4b8c1c526528bd Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Fri, 7 Apr 2023 16:19:50 -0400 Subject: [PATCH 27/45] fix user service and add tests Signed-off-by: Stephen Crawford --- .../security/dlic/rest/api/InternalUsersApiAction.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index f36c487912..0f854c890b 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -100,10 +100,6 @@ protected Endpoint getEndpoint() { @Override protected void handlePut(RestChannel channel, final RestRequest request, final Client client, final JsonNode content) throws IOException { - System.out.println("In handle put"); - System.out.println("Request details are: " + request.params().keySet()); - System.out.println("JsonNode content is: " + content.toString()); - final String username = request.param("name"); SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName(), false); @@ -149,15 +145,14 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C throw new IOException(ex); } + saveAndUpdateConfigs(this.securityIndexName,client, CType.INTERNALUSERS, internalUsersConfiguration, new OnSucessActionListener(channel) { @Override public void onResponse(IndexResponse response) { if (userExisted) { - System.out.println("System response is success response"); successResponse(channel, "'" + username + "' updated."); } else { - System.out.println("System response is created response"); createdResponse(channel, "'" + username + "' created."); } From eb826d81872eb8494425f8d1ee1b3369faeed118 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Fri, 7 Apr 2023 16:28:38 -0400 Subject: [PATCH 28/45] resolve conflict Signed-off-by: Stephen Crawford --- .../security/dlic/rest/api/InternalUsersApiAction.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 0f854c890b..c1cd8180b6 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -31,6 +31,7 @@ import org.opensearch.rest.RestController; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; +import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.configuration.ConfigurationRepository; From abecea76e0893674dd5c481191c3c2a4273fb28a Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Fri, 7 Apr 2023 16:44:52 -0400 Subject: [PATCH 29/45] Remove dangling test helper Signed-off-by: Stephen Crawford --- .../security/dlic/rest/api/AbstractRestApiUnitTest.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/AbstractRestApiUnitTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/AbstractRestApiUnitTest.java index 30e388fd6a..a1cb20d99c 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/AbstractRestApiUnitTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/AbstractRestApiUnitTest.java @@ -192,15 +192,6 @@ protected void addUserWithPasswordAndHash(String username, String password, Stri rh.sendAdminCertificate = sendAdminCertificate; } - protected void addUserWithBody(String username, String body, int status) throws Exception { - boolean sendAdminCertificate = rh.sendAdminCertificate; - rh.sendAdminCertificate = true; - HttpResponse response = rh.executePutRequest("/_opendistro/_security/api/internalusers/" + username, body, - new Header[0]); - Assert.assertEquals(status, response.getStatusCode()); - rh.sendAdminCertificate = sendAdminCertificate; - } - protected void checkGeneralAccess(int status, String username, String password) throws Exception { boolean sendAdminCertificate = rh.sendAdminCertificate; rh.sendAdminCertificate = false; From 1c3ac14d52c725bcb6ff0f795942185a6998ace2 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 10 Apr 2023 12:26:49 -0400 Subject: [PATCH 30/45] fix tests Signed-off-by: Stephen Crawford --- .../security/dlic/rest/api/InternalUsersApiAction.java | 1 - .../auditlog/compliance/RestApiComplianceAuditlogTest.java | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index c1cd8180b6..0f854c890b 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -31,7 +31,6 @@ import org.opensearch.rest.RestController; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; -import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.configuration.ConfigurationRepository; diff --git a/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java b/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java index 0a90f2f396..c2d428112a 100644 --- a/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java +++ b/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java @@ -46,7 +46,7 @@ public void testRestApiRolesEnabled() throws Exception { HttpResponse response = rh.executePutRequest("_opendistro/_security/api/internalusers/compuser?pretty", body, encodeBasicHeader("admin", "admin")); Thread.sleep(1500); System.out.println(TestAuditlogImpl.sb.toString()); - Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); + Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); Assert.assertTrue(TestAuditlogImpl.messages.size()+"",TestAuditlogImpl.messages.size() == 1); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("audit_request_effective_user")); Assert.assertFalse(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_READ")); @@ -81,7 +81,7 @@ public void testRestApiRolesDisabled() throws Exception { HttpResponse response = rh.executePutRequest("_opendistro/_security/api/internalusers/compuser?pretty", body); Thread.sleep(1500); System.out.println(TestAuditlogImpl.sb.toString()); - Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); + Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); Assert.assertTrue(TestAuditlogImpl.messages.size()+"",TestAuditlogImpl.messages.size() == 1); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("audit_request_effective_user")); Assert.assertFalse(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_READ")); @@ -242,7 +242,7 @@ public void testBCryptHashRedaction() throws Exception { // create internal user and verify no BCrypt hash is present in audit logs TestAuditlogImpl.clear(); rh.executePutRequest("/_opendistro/_security/api/internalusers/test", "{ \"password\":\"test\"}"); - Assert.assertEquals(1, TestAuditlogImpl.messages.size()); + Assert.assertEquals("Message is " + TestAuditlogImpl.messages.toString(), 1, TestAuditlogImpl.messages.size()); Assert.assertFalse(AuditMessage.BCRYPT_HASH.matcher(TestAuditlogImpl.sb.toString()).matches()); } } From f9020b01555d8016abc193f27603754729ce0cb8 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 10 Apr 2023 12:35:51 -0400 Subject: [PATCH 31/45] remove messaging Signed-off-by: Stephen Crawford --- .../auditlog/compliance/RestApiComplianceAuditlogTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java b/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java index c2d428112a..3ad8dbe542 100644 --- a/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java +++ b/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java @@ -46,8 +46,8 @@ public void testRestApiRolesEnabled() throws Exception { HttpResponse response = rh.executePutRequest("_opendistro/_security/api/internalusers/compuser?pretty", body, encodeBasicHeader("admin", "admin")); Thread.sleep(1500); System.out.println(TestAuditlogImpl.sb.toString()); - Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); - Assert.assertTrue(TestAuditlogImpl.messages.size()+"",TestAuditlogImpl.messages.size() == 1); + Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); + Assert.assertTrue(TestAuditlogImpl.messages.size() == 1); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("audit_request_effective_user")); Assert.assertFalse(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_READ")); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_WRITE")); @@ -81,7 +81,7 @@ public void testRestApiRolesDisabled() throws Exception { HttpResponse response = rh.executePutRequest("_opendistro/_security/api/internalusers/compuser?pretty", body); Thread.sleep(1500); System.out.println(TestAuditlogImpl.sb.toString()); - Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); + Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); Assert.assertTrue(TestAuditlogImpl.messages.size()+"",TestAuditlogImpl.messages.size() == 1); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("audit_request_effective_user")); Assert.assertFalse(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_READ")); From a1ab91032193e19cbf66f14022c352dc42663f54 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 10 Apr 2023 12:37:13 -0400 Subject: [PATCH 32/45] reset auditlog file Signed-off-by: Stephen Crawford --- .../RestApiComplianceAuditlogTest.java | 6 ++-- .../integration/TestAuditlogImpl.java | 28 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java b/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java index 3ad8dbe542..46056bd845 100644 --- a/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java +++ b/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java @@ -47,7 +47,7 @@ public void testRestApiRolesEnabled() throws Exception { Thread.sleep(1500); System.out.println(TestAuditlogImpl.sb.toString()); Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); - Assert.assertTrue(TestAuditlogImpl.messages.size() == 1); + Assert.assertTrue(TestAuditlogImpl.messages.size()+"",TestAuditlogImpl.messages.size() == 1); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("audit_request_effective_user")); Assert.assertFalse(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_READ")); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_WRITE")); @@ -82,7 +82,7 @@ public void testRestApiRolesDisabled() throws Exception { Thread.sleep(1500); System.out.println(TestAuditlogImpl.sb.toString()); Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); - Assert.assertTrue(TestAuditlogImpl.messages.size()+"",TestAuditlogImpl.messages.size() == 1); + Assert.assertTrue(TestAuditlogImpl.messages.size() == 1); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("audit_request_effective_user")); Assert.assertFalse(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_READ")); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_WRITE")); @@ -242,7 +242,7 @@ public void testBCryptHashRedaction() throws Exception { // create internal user and verify no BCrypt hash is present in audit logs TestAuditlogImpl.clear(); rh.executePutRequest("/_opendistro/_security/api/internalusers/test", "{ \"password\":\"test\"}"); - Assert.assertEquals("Message is " + TestAuditlogImpl.messages.toString(), 1, TestAuditlogImpl.messages.size()); + Assert.assertEquals(1, TestAuditlogImpl.messages.size()); Assert.assertFalse(AuditMessage.BCRYPT_HASH.matcher(TestAuditlogImpl.sb.toString()).matches()); } } diff --git a/src/test/java/org/opensearch/security/auditlog/integration/TestAuditlogImpl.java b/src/test/java/org/opensearch/security/auditlog/integration/TestAuditlogImpl.java index 0502f078d9..ba094e23a1 100644 --- a/src/test/java/org/opensearch/security/auditlog/integration/TestAuditlogImpl.java +++ b/src/test/java/org/opensearch/security/auditlog/integration/TestAuditlogImpl.java @@ -82,13 +82,13 @@ public static List doThenWaitForMessages(final Runnable action, fi Thread.sleep(100); if (missedMessages.size() != 0) { final String missedMessagesErrorMessage = new StringBuilder() - .append("Audit messages were missed! ") - .append("Found " + (missedMessages.size()) + " messages.") - .append("Messages found during this time: \n\n") - .append(missedMessages.stream() - .map(AuditMessage::toString) - .collect(Collectors.joining("\n"))) - .toString(); + .append("Audit messages were missed! ") + .append("Found " + (missedMessages.size()) + " messages.") + .append("Messages found during this time: \n\n") + .append(missedMessages.stream() + .map(AuditMessage::toString) + .collect(Collectors.joining("\n"))) + .toString(); throw new RuntimeException(missedMessagesErrorMessage); } @@ -155,13 +155,13 @@ public List getFoundMessages() { private static String createDetailMessage(final int expectedCount, final List foundMessages) { return new StringBuilder() - .append("Did not receive all " + expectedCount + " audit messages after a short wait. ") - .append("Missing " + (expectedCount - foundMessages.size()) + " messages.") - .append("Messages found during this time: \n\n") - .append(foundMessages.stream() - .map(AuditMessage::toString) - .collect(Collectors.joining("\n"))) - .toString(); + .append("Did not receive all " + expectedCount + " audit messages after a short wait. ") + .append("Missing " + (expectedCount - foundMessages.size()) + " messages.") + .append("Messages found during this time: \n\n") + .append(foundMessages.stream() + .map(AuditMessage::toString) + .collect(Collectors.joining("\n"))) + .toString(); } } } From 114f05d7b8a42f1dd2637d1decab7380c71bcc6c Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 10 Apr 2023 12:37:55 -0400 Subject: [PATCH 33/45] reset auditlog file Signed-off-by: Stephen Crawford --- .../auditlog/compliance/RestApiComplianceAuditlogTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java b/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java index 46056bd845..3ad8dbe542 100644 --- a/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java +++ b/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java @@ -47,7 +47,7 @@ public void testRestApiRolesEnabled() throws Exception { Thread.sleep(1500); System.out.println(TestAuditlogImpl.sb.toString()); Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); - Assert.assertTrue(TestAuditlogImpl.messages.size()+"",TestAuditlogImpl.messages.size() == 1); + Assert.assertTrue(TestAuditlogImpl.messages.size() == 1); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("audit_request_effective_user")); Assert.assertFalse(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_READ")); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_WRITE")); @@ -82,7 +82,7 @@ public void testRestApiRolesDisabled() throws Exception { Thread.sleep(1500); System.out.println(TestAuditlogImpl.sb.toString()); Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); - Assert.assertTrue(TestAuditlogImpl.messages.size() == 1); + Assert.assertTrue(TestAuditlogImpl.messages.size()+"",TestAuditlogImpl.messages.size() == 1); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("audit_request_effective_user")); Assert.assertFalse(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_READ")); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_WRITE")); @@ -242,7 +242,7 @@ public void testBCryptHashRedaction() throws Exception { // create internal user and verify no BCrypt hash is present in audit logs TestAuditlogImpl.clear(); rh.executePutRequest("/_opendistro/_security/api/internalusers/test", "{ \"password\":\"test\"}"); - Assert.assertEquals(1, TestAuditlogImpl.messages.size()); + Assert.assertEquals("Message is " + TestAuditlogImpl.messages.toString(), 1, TestAuditlogImpl.messages.size()); Assert.assertFalse(AuditMessage.BCRYPT_HASH.matcher(TestAuditlogImpl.sb.toString()).matches()); } } From 7c4a4642ff3373180378ed1f5ccd5de24f4a1684 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 10 Apr 2023 12:38:39 -0400 Subject: [PATCH 34/45] reset auditlog file Signed-off-by: Stephen Crawford --- .../auditlog/compliance/RestApiComplianceAuditlogTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java b/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java index 3ad8dbe542..0a90f2f396 100644 --- a/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java +++ b/src/test/java/org/opensearch/security/auditlog/compliance/RestApiComplianceAuditlogTest.java @@ -47,7 +47,7 @@ public void testRestApiRolesEnabled() throws Exception { Thread.sleep(1500); System.out.println(TestAuditlogImpl.sb.toString()); Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); - Assert.assertTrue(TestAuditlogImpl.messages.size() == 1); + Assert.assertTrue(TestAuditlogImpl.messages.size()+"",TestAuditlogImpl.messages.size() == 1); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("audit_request_effective_user")); Assert.assertFalse(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_READ")); Assert.assertTrue(TestAuditlogImpl.sb.toString().contains("COMPLIANCE_INTERNAL_CONFIG_WRITE")); @@ -242,7 +242,7 @@ public void testBCryptHashRedaction() throws Exception { // create internal user and verify no BCrypt hash is present in audit logs TestAuditlogImpl.clear(); rh.executePutRequest("/_opendistro/_security/api/internalusers/test", "{ \"password\":\"test\"}"); - Assert.assertEquals("Message is " + TestAuditlogImpl.messages.toString(), 1, TestAuditlogImpl.messages.size()); + Assert.assertEquals(1, TestAuditlogImpl.messages.size()); Assert.assertFalse(AuditMessage.BCRYPT_HASH.matcher(TestAuditlogImpl.sb.toString()).matches()); } } From 5983d98a754550768be40909e217927516160a02 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Wed, 12 Apr 2023 11:57:13 -0400 Subject: [PATCH 35/45] Cast message to string Signed-off-by: Stephen Crawford --- .../security/TransportUserInjectorIntegTest.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java index 077a26e4dd..fc61a3f127 100644 --- a/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java +++ b/src/test/java/org/opensearch/security/TransportUserInjectorIntegTest.java @@ -73,7 +73,7 @@ public void testSecurityUserInjection() throws Exception { .put(ConfigConstants.SECURITY_UNSUPPORTED_INJECT_USER_ENABLED, true) .build(); setup(clusterNodeSettings, new DynamicSecurityConfig().setSecurityRolesMapping("roles_transport_inject_user.yml"), Settings.EMPTY); - final Settings tcSettings = AbstractSecurityUnitTest.nodeRolesSettings(Settings.builder(), false, false) + final Settings tcSettings = AbstractSecurityUnitTest.nodeRolesSettings(Settings.builder(), false, false) .put(minimumSecuritySettings(Settings.EMPTY).get(0)) .put("cluster.name", clusterInfo.clustername) .put("path.data", "./target/data/" + clusterInfo.clustername + "/cert/data") @@ -108,12 +108,10 @@ public void testSecurityUserInjection() throws Exception { exception = ex; log.debug(ex.toString()); Assert.assertNotNull(exception); - Assert.assertTrue(exception.getMessage().contains("no permissions for [indices:admin/create] and User [name=ttt, backend_roles=[kkk], requestedTenant=null]")); - + Assert.assertTrue(exception.getMessage().toString().contains("no permissions for [indices:admin/create]")); } - // 3. with valid backend roles for injected user UserInjectorPlugin.injectedUser = "injectedadmin|injecttest"; try (Node node = new PluginAwareNode(false, tcSettings, Netty4ModulePlugin.class, @@ -130,7 +128,7 @@ public void testSecurityUserInjectionWithConfigDisabled() throws Exception { .put(ConfigConstants.SECURITY_UNSUPPORTED_INJECT_USER_ENABLED, false) .build(); setup(clusterNodeSettings, new DynamicSecurityConfig().setSecurityRolesMapping("roles_transport_inject_user.yml"), Settings.EMPTY); - final Settings tcSettings = AbstractSecurityUnitTest.nodeRolesSettings(Settings.builder(), false, false) + final Settings tcSettings = AbstractSecurityUnitTest.nodeRolesSettings(Settings.builder(), false, false) .put(minimumSecuritySettings(Settings.EMPTY).get(0)) .put("cluster.name", clusterInfo.clustername) .put("path.data", "./target/data/" + clusterInfo.clustername + "/cert/data") @@ -150,7 +148,7 @@ public void testSecurityUserInjectionWithConfigDisabled() throws Exception { CreateIndexResponse cir = node.client().admin().indices().create(new CreateIndexRequest("captain-logs-1")).actionGet(); Assert.assertTrue(cir.isAcknowledged()); } - + // with invalid backend roles UserInjectorPlugin.injectedUser = "ttt|kkk"; try (Node node = new PluginAwareNode(false, tcSettings, Netty4ModulePlugin.class, From 9639f873e237f75e8d061eb78a38002d9fad71d8 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Wed, 12 Apr 2023 15:44:23 -0400 Subject: [PATCH 36/45] Swap tenancy action names Signed-off-by: Stephen Crawford --- .../security/action/tenancy/TenancyConfigRetrieveActions.java | 2 +- .../security/action/tenancy/TenancyConfigUpdateAction.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java index 796f233f13..6eef8efb09 100644 --- a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java @@ -16,7 +16,7 @@ public class TenancyConfigRetrieveActions extends ActionType { public static final TenancyConfigRetrieveActions INSTANCE = new TenancyConfigRetrieveActions(); - public static final String NAME = "cluster:feature/tenancy/config/read"; + public static final String NAME = "cluster:admin/tenancy/config/read"; protected TenancyConfigRetrieveActions() { super(NAME, TenancyConfigRetrieveResponse::new); diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java index 73d515b7d8..66fe4ca4c9 100644 --- a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java @@ -16,7 +16,7 @@ public class TenancyConfigUpdateAction extends ActionType { public static final TenancyConfigUpdateAction INSTANCE = new TenancyConfigUpdateAction(); - public static final String NAME = "cluster:feature/tenancy/config/update"; + public static final String NAME = "cluster:admin/tenancy/config/update"; protected TenancyConfigUpdateAction() From cd5c4e3c9d1fb7f9d4ce5eba42a69fe6c6ce8085 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Fri, 14 Apr 2023 15:48:27 -0400 Subject: [PATCH 37/45] reset tenancy action naem Signed-off-by: Stephen Crawford --- .../security/action/tenancy/TenancyConfigRetrieveActions.java | 2 +- .../security/action/tenancy/TenancyConfigUpdateAction.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java index 6eef8efb09..796f233f13 100644 --- a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigRetrieveActions.java @@ -16,7 +16,7 @@ public class TenancyConfigRetrieveActions extends ActionType { public static final TenancyConfigRetrieveActions INSTANCE = new TenancyConfigRetrieveActions(); - public static final String NAME = "cluster:admin/tenancy/config/read"; + public static final String NAME = "cluster:feature/tenancy/config/read"; protected TenancyConfigRetrieveActions() { super(NAME, TenancyConfigRetrieveResponse::new); diff --git a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java index 66fe4ca4c9..73d515b7d8 100644 --- a/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/action/tenancy/TenancyConfigUpdateAction.java @@ -16,7 +16,7 @@ public class TenancyConfigUpdateAction extends ActionType { public static final TenancyConfigUpdateAction INSTANCE = new TenancyConfigUpdateAction(); - public static final String NAME = "cluster:admin/tenancy/config/update"; + public static final String NAME = "cluster:feature/tenancy/config/update"; protected TenancyConfigUpdateAction() From 80bb066091e4bfc10516666b8cd923a18124f1a6 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Mon, 17 Apr 2023 11:34:27 -0400 Subject: [PATCH 38/45] Swap to node instead of parsing string and remove uneccessary addition of fields Signed-off-by: Stephen Crawford --- .../security/dlic/rest/api/InternalUsersApiAction.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 0f854c890b..4507429a3a 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -134,7 +134,6 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C ((ObjectNode) content).put("isEnabled", request.param("isEnabled")); } ((ObjectNode) content).put("name", username); - internalUsersConfiguration = userService.createOrUpdateAccount((ObjectNode) content); } catch (UserServiceException ex) { From 6d8cb97e3a18e5792cceb53d969393efb42d1725 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Tue, 18 Apr 2023 10:39:55 -0400 Subject: [PATCH 39/45] update checks Signed-off-by: Stephen Crawford --- .../dlic/rest/api/InternalUsersApiAction.java | 54 ++++++++++- .../opensearch/security/user/UserService.java | 90 ++++++++++++++++--- .../security/dlic/rest/api/UserApiTest.java | 64 ++++++++++++- 3 files changed, 189 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index 4507429a3a..e93c960058 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -50,17 +50,19 @@ public class InternalUsersApiAction extends PatchableResourceApiAction { static final List RESTRICTED_FROM_USERNAME = ImmutableList.of( - ":" // Not allowed in basic auth, see https://stackoverflow.com/a/33391003/533057 + ":" // Not allowed in basic auth, see https://stackoverflow.com/a/33391003/533057 ); private static final List routes = addRoutesPrefix(ImmutableList.of( new Route(Method.GET, "/user/{name}"), new Route(Method.GET, "/user/"), + new Route(Method.GET, "/user/{name}/authtoken"), new Route(Method.DELETE, "/user/{name}"), new Route(Method.PUT, "/user/{name}"), // corrected mapping, introduced in OpenSearch Security new Route(Method.GET, "/internalusers/{name}"), + new Route(Method.GET, "/internalusers/{name}/authtoken"), new Route(Method.GET, "/internalusers/"), new Route(Method.DELETE, "/internalusers/{name}"), new Route(Method.PUT, "/internalusers/{name}"), @@ -147,6 +149,7 @@ protected void handlePut(RestChannel channel, final RestRequest request, final C saveAndUpdateConfigs(this.securityIndexName,client, CType.INTERNALUSERS, internalUsersConfiguration, new OnSucessActionListener(channel) { + @Override public void onResponse(IndexResponse response) { if (userExisted) { @@ -159,6 +162,55 @@ public void onResponse(IndexResponse response) { }); } + @Override + protected void handleGet(final RestChannel channel, RestRequest request, Client client, final JsonNode content) throws IOException{ + + final String username = request.param("name"); + + final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName(), true); + filter(internalUsersConfiguration); + + // no specific resource requested, return complete config + if (username == null || username.length() == 0) { + + successResponse(channel, internalUsersConfiguration); + return; + } + + final boolean userExisted = internalUsersConfiguration.exists(username); + + if (!userExisted) { + notFound(channel, "Resource '" + username + "' not found."); + return; + } + + String authToken = ""; + try { + if (request.uri().contains("/internalusers/" + username + "/authtoken")) { + + authToken = userService.generateAuthToken(username); + } else { + + internalUsersConfiguration.removeOthers(username); + successResponse(channel, internalUsersConfiguration); + return; + } + } catch (UserServiceException ex) { + badRequestResponse(channel, ex.getMessage()); + return; + } + catch (IOException ex) { + throw new IOException(ex); + } + + if (!authToken.isEmpty()) { + createdResponse(channel, "'" + username + "' authtoken updated generated " + authToken); + } else { + badRequestResponse(channel, "'" + username + "' authtoken failed to be created."); + } + } + + @Override protected void filter(SecurityDynamicConfiguration builder) { super.filter(builder); diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 1894424789..80e1d61193 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -33,10 +33,14 @@ >>>>>>> b07f0f8f0c2 (fix user service and add tests) package org.opensearch.security.user; import java.io.IOException; +import java.util.Base64; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.ImmutableList; import org.apache.logging.log4j.LogManager; @@ -49,6 +53,8 @@ >>>>>>> b07f0f8f0c2 (fix user service and add tests) import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.inject.Inject; import org.opensearch.common.settings.Settings; +import org.opensearch.common.xcontent.XContentHelper; +import org.opensearch.common.xcontent.XContentType; import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.configuration.ConfigurationRepository; import org.opensearch.security.securityconf.DynamicConfigFactory; @@ -78,7 +84,10 @@ public class UserService { ClusterService clusterService; static ConfigurationRepository configurationRepository; String securityIndex; + String tokenIndex; Client client; + + User tokenUser; final static String NO_PASSWORD_OR_HASH_MESSAGE = "Please specify either 'hash' or 'password' when creating a new internal user."; final static String RESTRICTED_CHARACTER_USE_MESSAGE = "A restricted character(s) was detected in the account name. Please remove: "; @@ -87,6 +96,8 @@ public class UserService { final static String SERVICE_ACCOUNT_HASH_MESSAGE = "A password hash cannot be provided for service account. Failed to register service account: "; final static String NO_ACCOUNT_NAME_MESSAGE = "No account name was specified in the request."; + final static String FAILED_ACCOUNT_RETRIEVAL_MESSAGE = "The account specified could not be accessed at this time."; + final static String AUTH_TOKEN_GENERATION_MESSAGE = "An auth token could not be generated for the specified account."; protected static CType getConfigName() { return CType.INTERNALUSERS;} @@ -156,7 +167,7 @@ public SecurityDynamicConfiguration createOrUpdateAccount(ObjectNode contentA throw new UserServiceException(NO_ACCOUNT_NAME_MESSAGE); } - if (!securityJsonNode.get("attributes").get("owner").isNull() && !securityJsonNode.get("attributes").get("owner").equals(accountName)) { // If this is a service account + if (!securityJsonNode.get("attributes").get("owner").isNull() && !securityJsonNode.get("attributes").get("owner").asString().equals(accountName)) { // If this is a service account verifyServiceAccount(securityJsonNode, accountName); String password = generatePassword(); contentAsNode.put("hash", hash(password.toCharArray())); @@ -207,6 +218,7 @@ public SecurityDynamicConfiguration createOrUpdateAccount(ObjectNode contentA private void verifyServiceAccount(SecurityJsonNode securityJsonNode, String accountName) { + final String plainTextPassword = securityJsonNode.get("password").asString(); final String origHash = securityJsonNode.get("hash").asString(); @@ -229,23 +241,73 @@ private String generatePassword() { return generatedPassword; } + /** + * This function retrieves the auth token associated with a service account. + * Fails if the provided account is not a service account or account is not enabled. + * + * @param accountName A string representing the name of the account + * @return A string auth token + */ + public String generateAuthToken(String accountName) throws IOException { - public String getNO_PASSWORD_OR_HASH_MESSAGE() { - return NO_PASSWORD_OR_HASH_MESSAGE; - } + final SecurityDynamicConfiguration internalUsersConfiguration = load(getConfigName(), false); - public String getRESTRICTED_CHARACTER_USE_MESSAGE() { - return RESTRICTED_CHARACTER_USE_MESSAGE; - } + if (!internalUsersConfiguration.exists(accountName)) { + throw new UserServiceException(FAILED_ACCOUNT_RETRIEVAL_MESSAGE); + } - public String getSERVICE_ACCOUNT_PASSWORD_MESSAGE() { - return SERVICE_ACCOUNT_PASSWORD_MESSAGE; - } + String authToken = null; + try { + ObjectMapper mapper = new ObjectMapper(); + JsonNode accountDetails = mapper.readTree(internalUsersConfiguration.getCEntry(accountName).toString()); + final ObjectNode contentAsNode = (ObjectNode) accountDetails; + SecurityJsonNode securityJsonNode = new SecurityJsonNode(contentAsNode); + + if (securityJsonNode.get("attributes").get("owner").isNull()) { // If this is not a service account + throw new UserServiceException(AUTH_TOKEN_GENERATION_MESSAGE); + } + if (securityJsonNode.get("attributes").get("owner").asString().equals(accountName)) { // If this is not a service account + throw new UserServiceException(AUTH_TOKEN_GENERATION_MESSAGE); + } + if (securityJsonNode.get("attributes").get("isEnabled").asString().equals("false")) { // If the service account is not active + throw new UserServiceException(AUTH_TOKEN_GENERATION_MESSAGE); + } - public String getSERVICE_ACCOUNT_HASH_MESSAGE() { - return SERVICE_ACCOUNT_HASH_MESSAGE; + // Generate a new password for the account and store the hash of it + String plainTextPassword = generatePassword(); + contentAsNode.put("hash", hash(plainTextPassword.toCharArray())); + + // Update the internal user associated with the auth token + internalUsersConfiguration.remove(accountName); + contentAsNode.remove("name"); + internalUsersConfiguration.putCObject(accountName, DefaultObjectMapper.readTree(contentAsNode, internalUsersConfiguration.getImplementingClass())); + saveAndUpdateConfigs(getConfigName().toString(), client, CType.INTERNALUSERS, internalUsersConfiguration); + + + authToken = Base64.getUrlEncoder().encodeToString((accountName + ":" + plainTextPassword).getBytes()); + return authToken; + + } catch (JsonProcessingException ex) { + throw new UserServiceException(FAILED_ACCOUNT_RETRIEVAL_MESSAGE); + } catch (Exception e) { + throw new UserServiceException(AUTH_TOKEN_GENERATION_MESSAGE); + } } - public String getNO_ACCOUNT_NAME_MESSAGE() { - return NO_ACCOUNT_NAME_MESSAGE; + + public static void saveAndUpdateConfigs(final String indexName, final Client client, final CType cType, final SecurityDynamicConfiguration configuration) { + final IndexRequest ir = new IndexRequest(indexName); + final String id = cType.toLCString(); + + configuration.removeStatic(); + + try { + client.index(ir.id(id) + .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) + .setIfSeqNo(configuration.getSeqNo()) + .setIfPrimaryTerm(configuration.getPrimaryTerm()) + .source(id, XContentHelper.toXContent(configuration, XContentType.JSON, false))); + } catch (IOException e) { + throw ExceptionsHelper.convertToOpenSearchException(e); + } } } diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java index 611c1db921..4298df3f00 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java @@ -12,6 +12,7 @@ package org.opensearch.security.dlic.rest.api; import java.net.URLEncoder; +import java.util.Base64; import java.util.List; import org.apache.hc.core5.http.Header; @@ -37,7 +38,7 @@ public class UserApiTest extends AbstractRestApiUnitTest { - private final String ENDPOINT; + private final String ENDPOINT; protected String getEndpointPrefix() { return PLUGINS_PREFIX; } @@ -99,9 +100,9 @@ public void testSecurityRoles() throws Exception { @Test public void testParallelPutRequests() throws Exception { - + setup(); - + rh.keystore = "restapi/kirk-keystore.jks"; rh.sendAdminCertificate = true; @@ -323,6 +324,10 @@ private void verifyPatch(final boolean sendAdminCert, Header... restAdminHeader) // Add enabled service account then get it +<<<<<<< HEAD +======= + rh.sendAdminCertificate = sendAdminCert; +>>>>>>> ea3cae2b9a9 (update checks) response = rh.executePutRequest(ENDPOINT + "/internalusers/happyServiceLive", ENABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); @@ -334,7 +339,12 @@ private void verifyPatch(final boolean sendAdminCert, Header... restAdminHeader) Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); // Add enabled non-service account +<<<<<<< HEAD response = rh.executePutRequest(ENDPOINT + "/internalusers/user_is_owner_1", +======= + rh.sendAdminCertificate = sendAdminCert; + response = rh.executePutRequest(ENDPOINT + "/internalusers/user_is_owner_2", +>>>>>>> ea3cae2b9a9 (update checks) ENABLED_NOT_SERVICE_ACCOUNT_BODY, restAdminHeader); Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); @@ -407,6 +417,52 @@ private void verifyPatch(final boolean sendAdminCert, Header... restAdminHeader) Assert.assertTrue(settings.get("nagilum.hash").equals("")); } + private void verifyAuthToken(final boolean sendAdminCert, Header... restAdminHeader) throws Exception { + + // Add enabled service account then generate auth token + + rh.sendAdminCertificate = sendAdminCert; + HttpResponse response = rh.executePutRequest(ENDPOINT + "/internalusers/happyServiceLive", + ENABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); + Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); + rh.sendAdminCertificate = sendAdminCert; + response = rh.executeGetRequest(ENDPOINT + "/internalusers/happyServiceLive", restAdminHeader); + Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + + response = rh.executeGetRequest(ENDPOINT + "/internalusers/happyServiceLive/authtoken", + ENABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); + Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); + String tokenFromResponse = response.getBody(); + byte[] decodedResponse = Base64.getUrlDecoder().decode(tokenFromResponse); + String[] decodedResponseString = new String(decodedResponse).split(":", 2); + String username = decodedResponseString[0]; + String password = decodedResponseString[1]; + Assert.assertEquals("Username is: " + username,username, "happyServiceLive"); + + + // Add disabled service account then try to get its auth token + rh.sendAdminCertificate = sendAdminCert; + response = rh.executePutRequest(ENDPOINT + "/internalusers/happyServiceDead", + DISABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); + Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); + + response = rh.executeGetRequest(ENDPOINT + "/internalusers/happyServiceDead/authtoken", + ENABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); + Assert.assertEquals(response.getBody(), HttpStatus.SC_BAD_REQUEST, response.getStatusCode()); + + + // Add enabled non-service account + rh.sendAdminCertificate = sendAdminCert; + response = rh.executePutRequest(ENDPOINT + "/internalusers/user_is_owner_1", + ENABLED_NOT_SERVICE_ACCOUNT_BODY, restAdminHeader); + Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); + + response = rh.executeGetRequest(ENDPOINT + "/internalusers/user_is_owner_1/authtoken", + ENABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); + Assert.assertEquals(response.getBody(), HttpStatus.SC_BAD_REQUEST, response.getStatusCode()); + + } + private void verifyRoles(final boolean sendAdminCert, Header... header) throws Exception { // wrong datatypes in roles file rh.sendAdminCertificate = sendAdminCert; @@ -720,7 +776,7 @@ public void testUserApiForNonSuperAdmin() throws Exception { // Put reserved role is forbidden for non-superadmin response = rh.executePutRequest(ENDPOINT + "/internalusers/nagilum", "{ \"opendistro_security_roles\": [\"opendistro_security_reserved\"]}", - new Header[0]); + new Header[0]); Assert.assertEquals(HttpStatus.SC_FORBIDDEN, response.getStatusCode()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); Assert.assertEquals(settings.get("message"), "Resource 'opendistro_security_reserved' is read-only."); From 5e2410fa6471f9709d2af6a0cb3cad900a8a0ff9 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Tue, 18 Apr 2023 10:47:09 -0400 Subject: [PATCH 40/45] remove unused variable Signed-off-by: Stephen Crawford --- src/main/java/org/opensearch/security/user/UserService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 80e1d61193..9b6a57a73a 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -84,7 +84,6 @@ public class UserService { ClusterService clusterService; static ConfigurationRepository configurationRepository; String securityIndex; - String tokenIndex; Client client; User tokenUser; From 1cec4e422ecb3bea2b9da33c61928c7d78b9ac3b Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Tue, 18 Apr 2023 16:34:22 -0400 Subject: [PATCH 41/45] Specify encoding Signed-off-by: Stephen Crawford --- src/main/java/org/opensearch/security/user/UserService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 9b6a57a73a..40f7ff3606 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -33,6 +33,7 @@ >>>>>>> b07f0f8f0c2 (fix user service and add tests) package org.opensearch.security.user; import java.io.IOException; +import java.nio.charset.Charset; import java.util.Base64; import java.util.Collections; import java.util.List; @@ -283,7 +284,7 @@ public String generateAuthToken(String accountName) throws IOException { saveAndUpdateConfigs(getConfigName().toString(), client, CType.INTERNALUSERS, internalUsersConfiguration); - authToken = Base64.getUrlEncoder().encodeToString((accountName + ":" + plainTextPassword).getBytes()); + authToken = Base64.getUrlEncoder().encodeToString((accountName + ":" + plainTextPassword).getBytes(Charset.forName("UTF-8"))); return authToken; } catch (JsonProcessingException ex) { From 4ede132f204164abaa600cfc4347611353373168 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Thu, 20 Apr 2023 10:11:07 -0400 Subject: [PATCH 42/45] remove uneccessary lines Signed-off-by: Stephen Crawford --- .../security/dlic/rest/api/UserApiTest.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java index 4298df3f00..8b750e7591 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java @@ -323,28 +323,20 @@ private void verifyPatch(final boolean sendAdminCert, Header... restAdminHeader) HttpStatus.SC_CREATED); // Add enabled service account then get it - -<<<<<<< HEAD -======= - rh.sendAdminCertificate = sendAdminCert; ->>>>>>> ea3cae2b9a9 (update checks) response = rh.executePutRequest(ENDPOINT + "/internalusers/happyServiceLive", ENABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); response = rh.executeGetRequest(ENDPOINT + "/internalusers/happyServiceLive", restAdminHeader); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + // Add disabled service account response = rh.executePutRequest(ENDPOINT + "/internalusers/happyServiceDead", DISABLED_SERVICE_ACCOUNT_BODY, restAdminHeader); Assert.assertEquals(response.getBody(), HttpStatus.SC_CREATED, response.getStatusCode()); // Add enabled non-service account -<<<<<<< HEAD - response = rh.executePutRequest(ENDPOINT + "/internalusers/user_is_owner_1", -======= rh.sendAdminCertificate = sendAdminCert; response = rh.executePutRequest(ENDPOINT + "/internalusers/user_is_owner_2", ->>>>>>> ea3cae2b9a9 (update checks) ENABLED_NOT_SERVICE_ACCOUNT_BODY, restAdminHeader); Assert.assertEquals(HttpStatus.SC_CREATED, response.getStatusCode()); @@ -439,7 +431,6 @@ private void verifyAuthToken(final boolean sendAdminCert, Header... restAdminHea String password = decodedResponseString[1]; Assert.assertEquals("Username is: " + username,username, "happyServiceLive"); - // Add disabled service account then try to get its auth token rh.sendAdminCertificate = sendAdminCert; response = rh.executePutRequest(ENDPOINT + "/internalusers/happyServiceDead", From cd5f3b9ca802cc149d7067f212fda876127480ea Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Thu, 20 Apr 2023 17:06:47 -0400 Subject: [PATCH 43/45] Add interface for intenral user provider Signed-off-by: Stephen Crawford --- .../security/OpenSearchSecurityPlugin.java | 5 +- .../dlic/rest/api/InternalUsersApiAction.java | 4 ++ .../security/user/InternalUserProvider.java | 20 ++++++ .../user/SecurityInternalUserProvider.java | 63 +++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/opensearch/security/user/InternalUserProvider.java create mode 100644 src/main/java/org/opensearch/security/user/SecurityInternalUserProvider.java diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 87ca878fc6..bb2fa88fde 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -175,6 +175,7 @@ import org.opensearch.security.transport.DefaultInterClusterRequestEvaluator; import org.opensearch.security.transport.InterClusterRequestEvaluator; import org.opensearch.security.transport.SecurityInterceptor; +import org.opensearch.security.user.SecurityInternalUserProvider; import org.opensearch.security.user.User; import org.opensearch.security.user.UserService; import org.opensearch.tasks.Task; @@ -821,6 +822,8 @@ public Collection createComponents(Client localClient, ClusterService cl userService = new UserService(cs, cr, settings, localClient); + SecurityInternalUserProvider securityInternalUserProvider = new SecurityInternalUserProvider(userService); + final XFFResolver xffResolver = new XFFResolver(threadPool); backendRegistry = new BackendRegistry(settings, adminDns, xffResolver, auditLog, threadPool); @@ -878,7 +881,7 @@ public Collection createComponents(Client localClient, ClusterService cl components.add(si); components.add(dcf); components.add(userService); - + components.add(securityInternalUserProvider); return components; diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java index e93c960058..1caa7461ab 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/InternalUsersApiAction.java @@ -246,6 +246,10 @@ protected AbstractConfigurationValidator postProcessApplyPatchResult(RestChannel return null; } + public InternalUsersApiAction getAction(){ + return this; + } + @Override protected String getResourceName() { return "user"; diff --git a/src/main/java/org/opensearch/security/user/InternalUserProvider.java b/src/main/java/org/opensearch/security/user/InternalUserProvider.java new file mode 100644 index 0000000000..01227c182e --- /dev/null +++ b/src/main/java/org/opensearch/security/user/InternalUserProvider.java @@ -0,0 +1,20 @@ +package org.opensearch.security.user; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.IOException; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; + +/** + * This interface will be defined in core following these changes. For now this is used for testing in the Security Plugin. + * + */ +public interface InternalUserProvider { + + public void putInternalUser(String userInfo) throws java.io.IOException; + + public SecurityDynamicConfiguration getInternalUser(String userInfo); + + public void removeInternalUser(String userInfo); + + public String getInternalUserAuthToken(String userInfo) throws IOException; +} diff --git a/src/main/java/org/opensearch/security/user/SecurityInternalUserProvider.java b/src/main/java/org/opensearch/security/user/SecurityInternalUserProvider.java new file mode 100644 index 0000000000..ed624bcb9a --- /dev/null +++ b/src/main/java/org/opensearch/security/user/SecurityInternalUserProvider.java @@ -0,0 +1,63 @@ +package org.opensearch.security.user; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.IOException; +import org.opensearch.common.inject.Inject; +import org.opensearch.security.DefaultObjectMapper; +import org.opensearch.security.securityconf.impl.CType; +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; + +public class SecurityInternalUserProvider implements InternalUserProvider{ + + UserService userService; + + @Inject + public SecurityInternalUserProvider(UserService userService) { + this.userService = userService; + } + + @Override + public void putInternalUser(String userInfo) throws IOException { + + JsonNode content = null; + content = DefaultObjectMapper.readTree(userInfo); + final ObjectNode contentAsNode = (ObjectNode) content; + + SecurityDynamicConfiguration internalUsersConfiguration = userService.load(userService.getUserConfigName(), true); + internalUsersConfiguration = userService.createOrUpdateAccount((ObjectNode) content); + userService.saveAndUpdateConfigs(userService.getUserConfigName().toString(), userService.client, CType.INTERNALUSERS, internalUsersConfiguration); + } + + @Override + public SecurityDynamicConfiguration getInternalUser(String username) { + + final SecurityDynamicConfiguration internalUsersConfiguration = userService.load(userService.getUserConfigName(), true); + + // no specific resource requested, return complete config + if (username == null || username.length() == 0) { + return internalUsersConfiguration; + } + + final boolean userExisted = internalUsersConfiguration.exists(username); + + if (!userExisted) { + throw new UserServiceException("Failed to retrieve requested internal user."); + } + + internalUsersConfiguration.removeOthers(username); + return internalUsersConfiguration; + } + + @Override + public void removeInternalUser(String username) { + final SecurityDynamicConfiguration internalUsersConfiguration = userService.load(userService.getUserConfigName(), true); + internalUsersConfiguration.remove(username); + } + + @Override + public String getInternalUserAuthToken(String username) throws IOException { + return userService.generateAuthToken(username); + } + +} From 1577af555d347f3044a005b45988e199b6c55fd7 Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Fri, 21 Apr 2023 11:15:35 -0400 Subject: [PATCH 44/45] update methods and add basic tests Signed-off-by: Stephen Crawford --- .../user/SecurityInternalUserProvider.java | 7 +- .../opensearch/security/user/UserService.java | 4 +- .../security/user/UserProviderTest.java | 106 ++++++++++++++++++ 3 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 src/test/java/org/opensearch/security/user/UserProviderTest.java diff --git a/src/main/java/org/opensearch/security/user/SecurityInternalUserProvider.java b/src/main/java/org/opensearch/security/user/SecurityInternalUserProvider.java index ed624bcb9a..d3543b0607 100644 --- a/src/main/java/org/opensearch/security/user/SecurityInternalUserProvider.java +++ b/src/main/java/org/opensearch/security/user/SecurityInternalUserProvider.java @@ -20,12 +20,10 @@ public SecurityInternalUserProvider(UserService userService) { @Override public void putInternalUser(String userInfo) throws IOException { - JsonNode content = null; - content = DefaultObjectMapper.readTree(userInfo); + JsonNode content = DefaultObjectMapper.readTree(userInfo); final ObjectNode contentAsNode = (ObjectNode) content; - SecurityDynamicConfiguration internalUsersConfiguration = userService.load(userService.getUserConfigName(), true); - internalUsersConfiguration = userService.createOrUpdateAccount((ObjectNode) content); + SecurityDynamicConfiguration internalUsersConfiguration = userService.createOrUpdateAccount(contentAsNode); userService.saveAndUpdateConfigs(userService.getUserConfigName().toString(), userService.client, CType.INTERNALUSERS, internalUsersConfiguration); } @@ -59,5 +57,4 @@ public void removeInternalUser(String username) { public String getInternalUserAuthToken(String username) throws IOException { return userService.generateAuthToken(username); } - } diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 40f7ff3606..9925a39315 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -124,7 +124,7 @@ public UserService( * @param config CType whose data is to be loaded in-memory * @return configuration loaded with given CType data */ - protected static final SecurityDynamicConfiguration load(final CType config, boolean logComplianceEvent) { + protected final SecurityDynamicConfiguration load(final CType config, boolean logComplianceEvent) { SecurityDynamicConfiguration loaded = configurationRepository.getConfigurationsFromIndex(Collections.singleton(config), logComplianceEvent).get(config).deepClone(); return DynamicConfigFactory.addStatics(loaded); } @@ -294,7 +294,7 @@ public String generateAuthToken(String accountName) throws IOException { } } - public static void saveAndUpdateConfigs(final String indexName, final Client client, final CType cType, final SecurityDynamicConfiguration configuration) { + public void saveAndUpdateConfigs(final String indexName, final Client client, final CType cType, final SecurityDynamicConfiguration configuration) { final IndexRequest ir = new IndexRequest(indexName); final String id = cType.toLCString(); diff --git a/src/test/java/org/opensearch/security/user/UserProviderTest.java b/src/test/java/org/opensearch/security/user/UserProviderTest.java new file mode 100644 index 0000000000..44b78f8205 --- /dev/null +++ b/src/test/java/org/opensearch/security/user/UserProviderTest.java @@ -0,0 +1,106 @@ +package org.opensearch.security.user; + +import java.io.File; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; +import org.opensearch.security.test.SingleClusterTest; +import org.opensearch.security.test.helper.cluster.ClusterHelper; + +public class UserProviderTest extends SingleClusterTest { + + private static final String ENABLED_SERVICE_ACCOUNT_BODY = "{" + + " \"username\": \"enabledService1\", " + + " \"attributes\": { \"owner\": \"test_owner\", " + + "\"isEnabled\": \"true\"}" + + " }\n"; + + private static final String DISABLED_SERVICE_ACCOUNT_BODY = "{" + + " \"username\": \"disabledService1\", " + + " \"attributes\": { \"owner\": \"test_owner\", " + + "\"isEnabled\": \"false\"}" + + " }\n"; + private static final String ENABLED_NOT_SERVICE_ACCOUNT_BODY = "{" + + " \"username\": \"enabledNotService1\", " + + " \"attributes\": { \"owner\": \"user_is_owner_1\", " + + "\"isEnabled\": \"true\"}" + + " }\n"; + private static final String PASSWORD_SERVICE = "{ \"password\" : \"test\"," + + " \"username\": \"passwordService1\", " + + " \"attributes\": { \"owner\": \"test_owner\", " + + "\"isEnabled\": \"true\"}" + + " }\n"; + private static final String HASH_SERVICE = "{ \"owner\" : \"test_owner\"," + + " \"username\": \"hashService1\", " + + " \"attributes\": { \"owner\": \"test_owner\", " + + "\"isEnabled\": \"true\"}" + + " }\n"; + private static final String PASSWORD_HASH_SERVICE = "{ \"password\" : \"test\", \"hash\" : \"123\"," + + " \"username\": \"passwordHashService1\", " + + " \"attributes\": { \"owner\": \"test_owner\", " + + "\"isEnabled\": \"true\"}" + + " }\n"; + + private UserService userService; + + private SecurityInternalUserProvider userProvider; + + @Test + public void testAddConfigurationInfo() { + + try { + userProvider.putInternalUser(ENABLED_SERVICE_ACCOUNT_BODY); + userProvider.putInternalUser(DISABLED_SERVICE_ACCOUNT_BODY); + userProvider.putInternalUser(ENABLED_NOT_SERVICE_ACCOUNT_BODY); + userProvider.putInternalUser(PASSWORD_HASH_SERVICE); + userProvider.putInternalUser(HASH_SERVICE); + userProvider.putInternalUser(PASSWORD_HASH_SERVICE); + } catch (java.io.IOException ex){ + throw new RuntimeException(ex); + } + } + + @Test + public void testAddThenRetrieveConfigurationInfo() { + + try { + userProvider.putInternalUser(ENABLED_SERVICE_ACCOUNT_BODY); + userProvider.putInternalUser(DISABLED_SERVICE_ACCOUNT_BODY); + userProvider.putInternalUser(ENABLED_NOT_SERVICE_ACCOUNT_BODY); + userProvider.putInternalUser(PASSWORD_HASH_SERVICE); + userProvider.putInternalUser(HASH_SERVICE); + userProvider.putInternalUser(PASSWORD_HASH_SERVICE); + } catch (java.io.IOException ex){ + throw new RuntimeException(ex); + } + + SecurityDynamicConfiguration response = userProvider.getInternalUser("enabledService1"); + assert(response.exists("enabledService1")); + assert(response.getCEntries().size() == 1); + + response = userProvider.getInternalUser("disabledService1"); + assert(response.exists("disabledService1")); + assert(response.getCEntries().size() == 1); + + response = userProvider.getInternalUser("enabledNotService1"); + assert(response.exists("enabledNotService1")); + assert(response.getCEntries().size() == 1); + + response = userProvider.getInternalUser("passwordHashService1"); + assert(!response.exists("passwordHashService1")); + assert(response.getCEntries().size() == 0); + + response = userProvider.getInternalUser("passwordService1"); + assert(!response.exists("passwordService1")); + assert(response.getCEntries().size() == 0); + + response = userProvider.getInternalUser("hashService1"); + assert(!response.exists("hashService1")); + assert(response.getCEntries().size() == 0); + + userProvider.getInternalUser(""); + assert(response.getCEntries().size() == 3); + } +} From b47a8020e40a7c05ce4712b52580939b038a6e2b Mon Sep 17 00:00:00 2001 From: Stephen Crawford Date: Fri, 28 Apr 2023 16:58:10 -0400 Subject: [PATCH 45/45] Swap to InternalUser Attributes Signed-off-by: Stephen Crawford --- .../opensearch/security/user/UserService.java | 11 +++++--- .../security/dlic/rest/api/UserApiTest.java | 26 +++++++++---------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/opensearch/security/user/UserService.java b/src/main/java/org/opensearch/security/user/UserService.java index 9925a39315..e991e0f2f5 100644 --- a/src/main/java/org/opensearch/security/user/UserService.java +++ b/src/main/java/org/opensearch/security/user/UserService.java @@ -33,7 +33,7 @@ >>>>>>> b07f0f8f0c2 (fix user service and add tests) package org.opensearch.security.user; import java.io.IOException; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Collections; import java.util.List; @@ -167,7 +167,8 @@ public SecurityDynamicConfiguration createOrUpdateAccount(ObjectNode contentA throw new UserServiceException(NO_ACCOUNT_NAME_MESSAGE); } - if (!securityJsonNode.get("attributes").get("owner").isNull() && !securityJsonNode.get("attributes").get("owner").asString().equals(accountName)) { // If this is a service account + if (!securityJsonNode.get("attributes").get("isService").isNull() && securityJsonNode.get("attributes").get("isService").asString().equalsIgnoreCase("true")) + { // If this is a service account verifyServiceAccount(securityJsonNode, accountName); String password = generatePassword(); contentAsNode.put("hash", hash(password.toCharArray())); @@ -192,6 +193,10 @@ public SecurityDynamicConfiguration createOrUpdateAccount(ObjectNode contentA contentAsNode.remove("password"); } + if (!securityJsonNode.get("attributes").get("isEnabled").isNull()) { + contentAsNode.put("isEnabled", securityJsonNode.get("isEnabled").asString()); + } + final boolean userExisted = internalUsersConfiguration.exists(accountName); // sanity checks, hash is mandatory for newly created users @@ -284,7 +289,7 @@ public String generateAuthToken(String accountName) throws IOException { saveAndUpdateConfigs(getConfigName().toString(), client, CType.INTERNALUSERS, internalUsersConfiguration); - authToken = Base64.getUrlEncoder().encodeToString((accountName + ":" + plainTextPassword).getBytes(Charset.forName("UTF-8"))); + authToken = Base64.getUrlEncoder().encodeToString((accountName + ":" + plainTextPassword).getBytes(StandardCharsets.UTF_8)); return authToken; } catch (JsonProcessingException ex) { diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java index 8b750e7591..bdc8fd5d9b 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/UserApiTest.java @@ -45,28 +45,28 @@ protected String getEndpointPrefix() { private static final String ENABLED_SERVICE_ACCOUNT_BODY = "{" - + " \"attributes\": { \"owner\": \"test_owner\", " + + " \"attributes\": { \"isService\": \"true\", " + "\"isEnabled\": \"true\"}" + " }\n"; private static final String DISABLED_SERVICE_ACCOUNT_BODY = "{" - + " \"attributes\": { \"owner\": \"test_owner\", " + + " \"attributes\": { \"isService\": \"true\", " + "\"isEnabled\": \"false\"}" + " }\n"; private static final String ENABLED_NOT_SERVICE_ACCOUNT_BODY = "{" - + " \"attributes\": { \"owner\": \"user_is_owner_1\", " + + " \"attributes\": { \"isService\": \"false\", " + "\"isEnabled\": \"true\"}" + " }\n"; private static final String PASSWORD_SERVICE = "{ \"password\" : \"test\"," - + " \"attributes\": { \"owner\": \"test_owner\", " + + " \"attributes\": { \"isService\": \"true\", " + "\"isEnabled\": \"true\"}" + " }\n"; private static final String HASH_SERVICE = "{ \"owner\" : \"test_owner\"," - + " \"attributes\": { \"owner\": \"test_owner\", " + + " \"attributes\": { \"isService\": \"true\", " + "\"isEnabled\": \"true\"}" + " }\n"; private static final String PASSWORD_HASH_SERVICE = "{ \"password\" : \"test\", \"hash\" : \"123\"," - + " \"attributes\": { \"owner\": \"test_owner\", " + + " \"attributes\": { \"isService\": \"true\", " + "\"isEnabled\": \"true\"}" + " }\n"; @@ -87,7 +87,7 @@ public void testSecurityRoles() throws Exception { .executeGetRequest(ENDPOINT + "/" + CType.INTERNALUSERS.toLCString()); Assert.assertEquals(response.getBody(), HttpStatus.SC_OK, response.getStatusCode()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); - Assert.assertEquals(133, settings.size()); + Assert.assertEquals(171, settings.size()); response = rh.executePatchRequest(ENDPOINT + "/internalusers", "[{ \"op\": \"add\", \"path\": \"/newuser\", \"value\": {\"password\": \"newuser\", \"opendistro_security_roles\": [\"opendistro_security_all_access\"] } }]", new Header[0]); Assert.assertEquals(response.getBody(), HttpStatus.SC_OK, response.getStatusCode()); @@ -137,7 +137,7 @@ public void testUserApi() throws Exception { HttpResponse response = rh.executeGetRequest(ENDPOINT + "/" + CType.INTERNALUSERS.toLCString()); Assert.assertEquals(response.getBody(), HttpStatus.SC_OK, response.getStatusCode()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); - Assert.assertEquals(133, settings.size()); + Assert.assertEquals(171, settings.size()); verifyGet(); verifyPut(); verifyPatch(true); @@ -152,7 +152,7 @@ private void verifyGet(final Header... header) throws Exception { HttpResponse response = rh.executeGetRequest(ENDPOINT + "/internalusers/admin", header); Assert.assertEquals(response.getBody(), HttpStatus.SC_OK, response.getStatusCode()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); - Assert.assertEquals(7, settings.size()); + Assert.assertEquals(9, settings.size()); // hash must be filtered Assert.assertEquals("", settings.get("admin.hash")); @@ -539,7 +539,7 @@ public void testUserApiWithRestAdminPermissions() throws Exception { HttpResponse response = rh.executeGetRequest(ENDPOINT + "/" + CType.INTERNALUSERS.toLCString(), restApiAdminHeader); Assert.assertEquals(response.getBody(), HttpStatus.SC_OK, response.getStatusCode()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); - Assert.assertEquals(133, settings.size()); + Assert.assertEquals(171, settings.size()); verifyGet(restApiAdminHeader); verifyPut(restApiAdminHeader); verifyPatch(false, restApiAdminHeader); @@ -557,7 +557,7 @@ public void testUserApiWithRestInternalUsersAdminPermissions() throws Exception HttpResponse response = rh.executeGetRequest(ENDPOINT + "/" + CType.INTERNALUSERS.toLCString(), restApiInternalUsersAdminHeader); Assert.assertEquals(response.getBody(), HttpStatus.SC_OK, response.getStatusCode()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); - Assert.assertEquals(133, settings.size()); + Assert.assertEquals(171, settings.size()); verifyGet(restApiInternalUsersAdminHeader); verifyPut(restApiInternalUsersAdminHeader); verifyPatch(false, restApiInternalUsersAdminHeader); @@ -586,7 +586,7 @@ public void testPasswordRules() throws Exception { .executeGetRequest("_plugins/_security/api/" + CType.INTERNALUSERS.toLCString()); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); - Assert.assertEquals(133, settings.size()); + Assert.assertEquals(171, settings.size()); addUserWithPassword("tooshoort", "", HttpStatus.SC_BAD_REQUEST); addUserWithPassword("tooshoort", "123", HttpStatus.SC_BAD_REQUEST); @@ -666,7 +666,7 @@ public void testUserApiWithDots() throws Exception { .executeGetRequest(ENDPOINT + "/" + CType.INTERNALUSERS.toLCString()); Assert.assertEquals(HttpStatus.SC_OK, response.getStatusCode()); Settings settings = Settings.builder().loadFromSource(response.getBody(), XContentType.JSON).build(); - Assert.assertEquals(133, settings.size()); + Assert.assertEquals(171, settings.size()); addUserWithPassword(".my.dotuser0", "$2a$12$n5nubfWATfQjSYHiWtUyeOxMIxFInUHOAx8VMmGmxFNPGpaBmeB.m", HttpStatus.SC_CREATED);