Skip to content

Commit

Permalink
Add FailOnAnonymousAction for SAML auth to get redirect
Browse files Browse the repository at this point in the history
Signed-off-by: Craig Perkins <[email protected]>
  • Loading branch information
cwperks committed Mar 18, 2024
1 parent d526c9f commit 31f713a
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -181,10 +187,7 @@ public String getType() {
@Override
public Optional<SecurityResponse> 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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -562,6 +563,7 @@ public List<RestHandler> 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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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<String>(User.ANONYMOUS.getRoles()), null);
anonymousUser.setRequestedTenant(tenant);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Route> 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<Route> 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";
}
}

0 comments on commit 31f713a

Please sign in to comment.