diff --git a/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java index ae3d1c9128..c90dd32ea0 100644 --- a/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java @@ -173,6 +173,12 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T return authCredentials; } + public static boolean isAuthTokenEndpoint(final SecurityRequest request) { + Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); + final String suffix = matcher.matches() ? matcher.group(2) : null; + return API_AUTHTOKEN_SUFFIX.equals(suffix); + } + @Override public String getType() { return "saml"; @@ -181,10 +187,7 @@ public String getType() { @Override public Optional reRequestAuthentication(final SecurityRequest request, final AuthCredentials authCredentials) { try { - Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); - final String suffix = matcher.matches() ? matcher.group(2) : null; - - if (API_AUTHTOKEN_SUFFIX.equals(suffix)) { + if (isAuthTokenEndpoint(request)) { // Verficiation of SAML ASC endpoint only works with RestRequests if (!(request instanceof OpenSearchRequest)) { throw new SecurityRequestChannelUnsupported( diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 688b797e85..ee9966349b 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -159,6 +159,7 @@ import org.opensearch.security.privileges.RestLayerPrivilegesEvaluator; import org.opensearch.security.resolver.IndexResolverReplacer; import org.opensearch.security.rest.DashboardsInfoAction; +import org.opensearch.security.rest.FailOnAnonymousAction; import org.opensearch.security.rest.SecurityConfigUpdateAction; import org.opensearch.security.rest.SecurityHealthAction; import org.opensearch.security.rest.SecurityInfoAction; @@ -562,6 +563,7 @@ public List getRestHandlers( handlers.add( new SecurityInfoAction(settings, restController, Objects.requireNonNull(evaluator), Objects.requireNonNull(threadPool)) ); + handlers.add(new FailOnAnonymousAction()); handlers.add(new SecurityHealthAction(settings, restController, Objects.requireNonNull(backendRegistry))); handlers.add( new DashboardsInfoAction( diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 3ab9a2afc9..ae9c2d507a 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -71,6 +71,8 @@ import static org.apache.http.HttpStatus.SC_FORBIDDEN; import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE; import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; +import static org.opensearch.security.rest.FailOnAnonymousAction.isFailOnAnonymousEndpoint; +import static com.amazon.dlic.auth.http.saml.HTTPSamlAuthenticator.isAuthTokenEndpoint; public class BackendRegistry { @@ -286,7 +288,7 @@ public boolean authenticate(final SecurityRequestChannel request) { if (ac == null) { // no credentials found in request - if (anonymousAuthEnabled) { + if (anonymousAuthEnabled && !(isFailOnAnonymousEndpoint(request) || isAuthTokenEndpoint(request))) { continue; } @@ -386,7 +388,7 @@ public boolean authenticate(final SecurityRequestChannel request) { log.debug("User still not authenticated after checking {} auth domains", restAuthDomains.size()); } - if (authCredentials == null && anonymousAuthEnabled) { + if (authCredentials == null && anonymousAuthEnabled && !(isFailOnAnonymousEndpoint(request) || isAuthTokenEndpoint(request))) { final String tenant = resolveTenantFrom(request); User anonymousUser = new User(User.ANONYMOUS.getName(), new HashSet(User.ANONYMOUS.getRoles()), null); anonymousUser.setRequestedTenant(tenant); diff --git a/src/main/java/org/opensearch/security/rest/FailOnAnonymousAction.java b/src/main/java/org/opensearch/security/rest/FailOnAnonymousAction.java new file mode 100644 index 0000000000..e73f6581e7 --- /dev/null +++ b/src/main/java/org/opensearch/security/rest/FailOnAnonymousAction.java @@ -0,0 +1,90 @@ +/* + * 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.rest; + +import java.io.IOException; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.common.collect.ImmutableList; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import org.opensearch.client.node.NodeClient; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.rest.BaseRestHandler; +import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; + +import static org.opensearch.rest.RestRequest.Method.GET; +import static org.opensearch.security.OpenSearchSecurityPlugin.LEGACY_OPENDISTRO_PREFIX; +import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX; +import static org.opensearch.security.dlic.rest.support.Utils.addRoutesPrefix; + +public class FailOnAnonymousAction extends BaseRestHandler { + private static final List routes = addRoutesPrefix( + ImmutableList.of(new Route(GET, "/failonanonymous")), + "/_opendistro/_security", + "/_plugins/_security" + ); + + private static final String FAILONANONYMOUS_SUFFIX = "failonanonymous"; + private static final String REGEX_PATH_PREFIX = "/(" + LEGACY_OPENDISTRO_PREFIX + "|" + PLUGINS_PREFIX + ")/" + "(.*)"; + private static final Pattern PATTERN_PATH_PREFIX = Pattern.compile(REGEX_PATH_PREFIX); + + public static boolean isFailOnAnonymousEndpoint(final SecurityRequest request) { + Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); + final String suffix = matcher.matches() ? matcher.group(2) : null; + return FAILONANONYMOUS_SUFFIX.equals(suffix); + } + + private final Logger log = LogManager.getLogger(this.getClass()); + + public FailOnAnonymousAction() { + super(); + } + + @Override + public List routes() { + return routes; + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + return new RestChannelConsumer() { + + @Override + public void accept(RestChannel channel) throws Exception { + XContentBuilder builder = channel.newBuilder(); // NOSONAR + BytesRestResponse response = null; + + builder.startObject(); + builder.field("success", "true"); + + builder.endObject(); + + response = new BytesRestResponse(RestStatus.OK, builder); + + channel.sendResponse(response); + } + }; + } + + @Override + public String getName() { + return "OpenSearch Security Fail on Anonymous Action"; + } +}