From 6d385f03cbfa437268822a59793baa1de58035c4 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 7 Jul 2023 12:06:43 -0400 Subject: [PATCH] Add password message to /dashboardsinfo endpoint (#2949) (#2955) * Add password message to /dashboardsinfo endpoint Signed-off-by: Craig Perkins * Update test names Signed-off-by: Craig Perkins --------- Signed-off-by: Craig Perkins (cherry picked from commit 47c4feb49175af1d4d07b4f7e8d9585eb06a97c9) Co-authored-by: Craig Perkins --- .../security/api/DashboardsInfoTest.java | 56 +++++++++++++++ .../api/DashboardsInfoWithSettingsTest.java | 68 +++++++++++++++++++ .../security/rest/DashboardsInfoAction.java | 7 ++ 3 files changed, 131 insertions(+) create mode 100644 src/integrationTest/java/org/opensearch/security/api/DashboardsInfoTest.java create mode 100644 src/integrationTest/java/org/opensearch/security/api/DashboardsInfoWithSettingsTest.java diff --git a/src/integrationTest/java/org/opensearch/security/api/DashboardsInfoTest.java b/src/integrationTest/java/org/opensearch/security/api/DashboardsInfoTest.java new file mode 100644 index 0000000000..a8936765d2 --- /dev/null +++ b/src/integrationTest/java/org/opensearch/security/api/DashboardsInfoTest.java @@ -0,0 +1,56 @@ +/* +* 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.api; + +import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; +import org.apache.hc.core5.http.HttpStatus; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.opensearch.test.framework.TestSecurityConfig; +import org.opensearch.test.framework.TestSecurityConfig.Role; +import org.opensearch.test.framework.cluster.ClusterManager; +import org.opensearch.test.framework.cluster.LocalCluster; +import org.opensearch.test.framework.cluster.TestRestClient; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.opensearch.security.rest.DashboardsInfoAction.DEFAULT_PASSWORD_MESSAGE; +import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; + +@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) +@ThreadLeakScope(ThreadLeakScope.Scope.NONE) +public class DashboardsInfoTest { + + protected final static TestSecurityConfig.User DASHBOARDS_USER = new TestSecurityConfig.User("dashboards_user").roles( + new Role("dashboards_role").indexPermissions("read").on("*").clusterPermissions("cluster_composite_ops") + ); + + @ClassRule + public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS) + .authc(AUTHC_HTTPBASIC_INTERNAL) + .users(DASHBOARDS_USER) + .build(); + + @Test + public void testDashboardsInfoValidationMessage() throws Exception { + + try (TestRestClient client = cluster.getRestClient(DASHBOARDS_USER)) { + TestRestClient.HttpResponse response = client.get("_plugins/_security/dashboardsinfo"); + assertThat(response.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(response.getBody(), containsString("password_validation_error_message")); + assertThat(response.getBody(), containsString(DEFAULT_PASSWORD_MESSAGE)); + } + } +} diff --git a/src/integrationTest/java/org/opensearch/security/api/DashboardsInfoWithSettingsTest.java b/src/integrationTest/java/org/opensearch/security/api/DashboardsInfoWithSettingsTest.java new file mode 100644 index 0000000000..01654e17cd --- /dev/null +++ b/src/integrationTest/java/org/opensearch/security/api/DashboardsInfoWithSettingsTest.java @@ -0,0 +1,68 @@ +/* +* 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.api; + +import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope; +import org.apache.hc.core5.http.HttpStatus; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.opensearch.security.support.ConfigConstants; +import org.opensearch.test.framework.TestSecurityConfig; +import org.opensearch.test.framework.TestSecurityConfig.Role; +import org.opensearch.test.framework.cluster.ClusterManager; +import org.opensearch.test.framework.cluster.LocalCluster; +import org.opensearch.test.framework.cluster.TestRestClient; + +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.opensearch.test.framework.TestSecurityConfig.AuthcDomain.AUTHC_HTTPBASIC_INTERNAL; + +@RunWith(com.carrotsearch.randomizedtesting.RandomizedRunner.class) +@ThreadLeakScope(ThreadLeakScope.Scope.NONE) +public class DashboardsInfoWithSettingsTest { + + protected final static TestSecurityConfig.User DASHBOARDS_USER = new TestSecurityConfig.User("dashboards_user").roles( + new Role("dashboards_role").indexPermissions("read").on("*").clusterPermissions("cluster_composite_ops") + ); + + private static final String CUSTOM_PASSWORD_MESSAGE = + "Password must be minimum 5 characters long and must contain at least one uppercase letter, one lowercase letter, one digit, and one special character."; + + @ClassRule + public static LocalCluster cluster = new LocalCluster.Builder().clusterManager(ClusterManager.THREE_CLUSTER_MANAGERS) + .authc(AUTHC_HTTPBASIC_INTERNAL) + .users(DASHBOARDS_USER) + .nodeSettings( + Map.of( + ConfigConstants.SECURITY_RESTAPI_PASSWORD_VALIDATION_REGEX, + "(?=.*[A-Z])(?=.*[^a-zA-Z\\d])(?=.*[0-9])(?=.*[a-z]).{5,}", + ConfigConstants.SECURITY_RESTAPI_PASSWORD_VALIDATION_ERROR_MESSAGE, + CUSTOM_PASSWORD_MESSAGE + ) + ) + .build(); + + @Test + public void testDashboardsInfoValidationMessageWithCustomMessage() throws Exception { + + try (TestRestClient client = cluster.getRestClient(DASHBOARDS_USER)) { + TestRestClient.HttpResponse response = client.get("_plugins/_security/dashboardsinfo"); + assertThat(response.getStatusCode(), equalTo(HttpStatus.SC_OK)); + assertThat(response.getBody(), containsString("password_validation_error_message")); + assertThat(response.getBody(), containsString(CUSTOM_PASSWORD_MESSAGE)); + } + } +} diff --git a/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java b/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java index 352d99b57e..ed5b965be2 100644 --- a/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java +++ b/src/main/java/org/opensearch/security/rest/DashboardsInfoAction.java @@ -65,6 +65,9 @@ public class DashboardsInfoAction extends BaseRestHandler { private final PrivilegesEvaluator evaluator; private final ThreadContext threadContext; + public static final String DEFAULT_PASSWORD_MESSAGE = "Password should be at least 8 characters long and contain at least one " + + "uppercase letter, one lowercase letter, one digit, and one special character."; + public DashboardsInfoAction( final Settings settings, final RestController controller, @@ -103,6 +106,10 @@ public void accept(RestChannel channel) throws Exception { builder.field("multitenancy_enabled", evaluator.multitenancyEnabled()); builder.field("private_tenant_enabled", evaluator.privateTenantEnabled()); builder.field("default_tenant", evaluator.dashboardsDefaultTenant()); + builder.field( + "password_validation_error_message", + client.settings().get(ConfigConstants.SECURITY_RESTAPI_PASSWORD_VALIDATION_ERROR_MESSAGE, DEFAULT_PASSWORD_MESSAGE) + ); builder.endObject(); response = new BytesRestResponse(RestStatus.OK, builder);