diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/MultiTenancyConfigApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/MultiTenancyConfigApiAction.java index 070cb8e94f..f1c8790023 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/MultiTenancyConfigApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/MultiTenancyConfigApiAction.java @@ -37,6 +37,7 @@ import org.opensearch.security.securityconf.impl.DashboardSignInOption; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; import org.opensearch.security.securityconf.impl.v7.ConfigV7; +import org.opensearch.security.securityconf.impl.v7.ConfigV7.Authc; import org.opensearch.security.support.ConfigConstants; import org.opensearch.threadpool.ThreadPool; @@ -185,7 +186,7 @@ private void updateAndValidatesValues(final ConfigV7 config, final JsonNode json } if (jsonContent.hasNonNull(SIGN_IN_OPTIONS) && jsonContent.findValue(SIGN_IN_OPTIONS).isEmpty() == false) { JsonNode newOptions = jsonContent.findValue(SIGN_IN_OPTIONS); - List options = getNewSignInOptions(newOptions); + List options = getNewSignInOptions(newOptions, config.dynamic.authc); config.dynamic.kibana.sign_in_options = options; } @@ -214,16 +215,29 @@ private void updateAndValidatesValues(final ConfigV7 config, final JsonNode json } } - private List getNewSignInOptions(JsonNode newOptions) { + private List getNewSignInOptions(JsonNode newOptions, Authc authc) { List options = new ArrayList<>(); for (int i = 0; i < newOptions.size(); i++) { try { String option = newOptions.get(i).asText(); - options.add(DashboardSignInOption.valueOf(option)); + if (isOptionConfiguredAtBackEnd(authc, option)) { + options.add(DashboardSignInOption.valueOf(option)); + } } catch (Exception e) { - throw new IllegalArgumentException("Invalid sign-in option. " + e.getMessage()); + throw new IllegalArgumentException("Invalid sign-in option: " + e.getMessage()); } } return options; } + + private boolean isOptionConfiguredAtBackEnd(Authc authc, String option) { + for (String key : authc.getDomains().keySet()) { + if (key.contains(option.toLowerCase())) { + return true; + } + } + throw new IllegalArgumentException( + "Validation failure: " + option.toUpperCase() + " authentication provider is not available for this cluster." + ); + } } diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/MultiTenancyConfigApiTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/MultiTenancyConfigApiTest.java index 19a6515f26..08af9bc76a 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/MultiTenancyConfigApiTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/MultiTenancyConfigApiTest.java @@ -59,10 +59,11 @@ private void verifyTenantUpdate(final Header... header) throws Exception { ); assertThat(getDashboardsinfoResponse.findArrayInJson("sign_in_options"), hasItem(DashboardSignInOption.BASIC.toString())); assertThat(getDashboardsinfoResponse.findArrayInJson("sign_in_options"), not(hasItem(DashboardSignInOption.SAML.toString()))); + assertThat(getDashboardsinfoResponse.findArrayInJson("sign_in_options"), not(hasItem(DashboardSignInOption.OPENID.toString()))); final HttpResponse updateDashboardSignInOptions = rh.executePutRequest( "/_plugins/_security/api/tenancy/config", - "{\"sign_in_options\": [\"BASIC\", \"SAML\"]}", + "{\"sign_in_options\": [\"BASIC\", \"OPENID\"]}", header ); assertThat(updateDashboardSignInOptions.getBody(), updateDashboardSignInOptions.getStatusCode(), equalTo(HttpStatus.SC_OK)); @@ -72,7 +73,27 @@ private void verifyTenantUpdate(final Header... header) throws Exception { assertThat(getDashboardsinfoResponse.findValueInJson("default_tenant"), equalTo("Private")); assertThat(getDashboardsinfoResponse.findArrayInJson("sign_in_options"), hasItem((DashboardSignInOption.BASIC.toString()))); - assertThat(getDashboardsinfoResponse.findArrayInJson("sign_in_options"), hasItem((DashboardSignInOption.SAML.toString()))); + assertThat(getDashboardsinfoResponse.findArrayInJson("sign_in_options"), hasItem((DashboardSignInOption.OPENID.toString()))); + + final HttpResponse updateUnavailableSignInOption = rh.executePutRequest( + "/_plugins/_security/api/tenancy/config", + "{\"sign_in_options\": [\"BASIC\", \"SAML\"]}", + header + ); + assertThat(updateUnavailableSignInOption.getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST)); + assertThat( + updateUnavailableSignInOption.findValueInJson("error.reason"), + containsString("Validation failure: SAML authentication provider is not available for this cluster.") + ); + + // Ensuring the sign in options array has not been modified due to the Bad Request response. + getDashboardsinfoResponse = rh.executeGetRequest("/_plugins/_security/dashboardsinfo", ADMIN_FULL_ACCESS_USER); + assertThat(getDashboardsinfoResponse.getStatusCode(), equalTo(HttpStatus.SC_OK)); + + assertThat(getDashboardsinfoResponse.findArrayInJson("sign_in_options").size(), equalTo(2)); + assertThat(getDashboardsinfoResponse.findArrayInJson("sign_in_options"), hasItem(DashboardSignInOption.BASIC.toString())); + assertThat(getDashboardsinfoResponse.findArrayInJson("sign_in_options"), hasItem(DashboardSignInOption.OPENID.toString())); + assertThat(getDashboardsinfoResponse.findArrayInJson("sign_in_options"), not(hasItem(DashboardSignInOption.SAML.toString()))); } @Test @@ -186,7 +207,7 @@ private void verifyTenantUpdateFailed(final Header... header) throws Exception { assertThat( invalidSignInOption.getBody(), invalidSignInOption.findValueInJson("error.reason"), - containsString("Invalid sign-in option.") + containsString("Invalid sign-in option") ); } diff --git a/src/test/resources/restapi/config.yml b/src/test/resources/restapi/config.yml index 2ed865657a..7a7d3d0e98 100644 --- a/src/test/resources/restapi/config.yml +++ b/src/test/resources/restapi/config.yml @@ -21,6 +21,18 @@ config: internalProxies: "192\\.168\\.0\\.10|192\\.168\\.0\\.11" remoteIpHeader: "x-forwarded-for" authc: + openid_auth_domain: + http_enabled: true + transport_enabled: true + order: 4 + http_authenticator: + type: openid + challenge: false + config: {} + authentication_backend: + type: "noop" + config: {} + description: "Migrated from v6" authentication_domain_kerb: http_enabled: false transport_enabled: false