From ab693c612fcdaf369356e2e1a5728c89673163c3 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Fri, 29 Sep 2023 13:46:49 +0000 Subject: [PATCH 01/50] Removed http channel Signed-off-by: Peter Nied --- .../security/auditlog/AuditLog.java | 17 +++++ .../auditlog/AuditLogSslExceptionHandler.java | 2 +- .../security/auth/BackendRegistry.java | 42 ++++++------- .../security/auth/UserInjector.java | 3 +- .../rest/api/RestApiPrivilegesEvaluator.java | 4 +- .../security/filter/SecurityRequest.java | 62 +++++++++++++++++++ .../security/filter/SecurityRestFilter.java | 8 ++- .../security/http/AuthenicationVerifier.java | 47 ++++++++++++++ .../security/http/RemoteIpDetector.java | 18 ++++-- .../SecurityNonSslHttpServerTransport.java | 8 +++ .../opensearch/security/http/XFFResolver.java | 23 +++---- .../rest/SecurityConfigUpdateAction.java | 4 +- .../security/rest/SecurityWhoAmIAction.java | 5 +- .../security/ssl/SslExceptionHandler.java | 5 ++ .../SecuritySSLNettyHttpServerTransport.java | 9 +++ .../ssl/http/netty/ValidatingDispatcher.java | 4 +- .../ssl/rest/SecuritySSLInfoAction.java | 5 +- .../security/ssl/util/SSLRequestHelper.java | 20 +----- .../security/support/HTTPHelper.java | 3 +- 19 files changed, 220 insertions(+), 69 deletions(-) create mode 100644 src/main/java/org/opensearch/security/filter/SecurityRequest.java create mode 100644 src/main/java/org/opensearch/security/http/AuthenicationVerifier.java diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLog.java b/src/main/java/org/opensearch/security/auditlog/AuditLog.java index 612b790686..edf06a7143 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLog.java @@ -38,6 +38,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; @@ -46,8 +47,16 @@ public interface AuditLog extends Closeable { // login void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, RestRequest request); + default void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { + this.logFailedLogin(effectiveUser, securityadmin, initiatingUser, request.asRestRequest()); + } + void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, RestRequest request); + default void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { + logSucceededLogin(effectiveUser, securityadmin, initiatingUser, request.asRestRequest()); + } + // privs void logMissingPrivileges(String privilege, String effectiveUser, RestRequest request); @@ -65,12 +74,20 @@ public interface AuditLog extends Closeable { void logBadHeaders(RestRequest request); + default void logBadHeaders(SecurityRequest request) { + this.logBadHeaders(request.asRestRequest()); + } + void logSecurityIndexAttempt(TransportRequest request, String action, Task task); void logSSLException(TransportRequest request, Throwable t, String action, Task task); void logSSLException(RestRequest request, Throwable t); + default void logSSLException(SecurityRequest request, Throwable t) { + this.logSSLException(request.asRestRequest(), t); + } + void logDocumentRead(String index, String id, ShardId shardId, Map fieldNameValues); void logDocumentWritten(ShardId shardId, GetResult originalIndex, Index currentIndex, IndexResult result); diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java b/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java index 942f06804f..30cef3a84a 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java @@ -58,7 +58,7 @@ public void logError(Throwable t, RestRequest request, int type) { @Override public void logError(Throwable t, boolean isRest) { if (isRest) { - auditLog.logSSLException(null, t); + auditLog.logSSLException((RestRequest)null, t); } else { auditLog.logSSLException(null, t, null, null); } diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index ad1406426b..6eb4c450a9 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -59,6 +59,7 @@ import org.opensearch.security.auth.blocking.ClientBlockRegistry; import org.opensearch.security.auth.internal.NoOpAuthenticationBackend; import org.opensearch.security.configuration.AdminDNs; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.http.OnBehalfOfAuthenticator; import org.opensearch.security.http.XFFResolver; import org.opensearch.security.securityconf.DynamicConfigModel; @@ -185,15 +186,18 @@ public void onDynamicConfigModelChanged(DynamicConfigModel dcm) { * @return The authenticated user, null means another roundtrip * @throws OpenSearchSecurityException */ - public boolean authenticate(final RestRequest request, final RestChannel channel, final ThreadContext threadContext) { + public boolean authenticate(final SecurityRequest request, final ThreadContext threadContext) { final boolean isDebugEnabled = log.isDebugEnabled(); - if (request.getHttpChannel().getRemoteAddress() instanceof InetSocketAddress - && isBlocked(((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).getAddress())) { + final boolean isBlockedBasedOnAddress = request.getRemoteAddress() + .map(InetSocketAddress::getAddress) + .map(address -> isBlocked(address)) + .orElse(false); + if (isBlockedBasedOnAddress) { if (isDebugEnabled) { - log.debug("Rejecting REST request because of blocked address: {}", request.getHttpChannel().getRemoteAddress()); + log.debug("Rejecting REST request because of blocked address: {}", request.getRemoteAddress().orElse(null)); } - channel.sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, "Authentication finally failed")); + request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, "Authentication finally failed")); return false; } @@ -214,14 +218,14 @@ && isBlocked(((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).g if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); - channel.sendResponse(new BytesRestResponse(RestStatus.SERVICE_UNAVAILABLE, "OpenSearch Security not initialized.")); + request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.SERVICE_UNAVAILABLE, "OpenSearch Security not initialized.")); return false; } final TransportAddress remoteAddress = xffResolver.resolve(request); final boolean isTraceEnabled = log.isTraceEnabled(); if (isTraceEnabled) { - log.trace("Rest authentication request from {} [original: {}]", remoteAddress, request.getHttpChannel().getRemoteAddress()); + log.trace("Rest authentication request from {} [original: {}]", remoteAddress, request.getRemoteAddress().orElse(null)); } threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS, remoteAddress); @@ -256,7 +260,7 @@ && isBlocked(((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).g } final AuthCredentials ac; try { - ac = httpAuthenticator.extractCredentials(request, threadContext); + ac = httpAuthenticator.extractCredentials(request.asRestRequest(), threadContext); } catch (Exception e1) { if (isDebugEnabled) { log.debug("'{}' extracting credentials from {} http authenticator", e1.toString(), httpAuthenticator.getType(), e1); @@ -280,7 +284,7 @@ && isBlocked(((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).g continue; } - if (authDomain.isChallenge() && httpAuthenticator.reRequestAuthentication(channel, null)) { + if (authDomain.isChallenge() && httpAuthenticator.reRequestAuthentication(request.getRestChannel(), null)) { auditLog.logFailedLogin("", false, null, request); if (isTraceEnabled) { log.trace("No 'Authorization' header, send 401 and 'WWW-Authenticate Basic'"); @@ -297,7 +301,7 @@ && isBlocked(((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).g org.apache.logging.log4j.ThreadContext.put("user", ac.getUsername()); if (!ac.isComplete()) { // credentials found in request but we need another client challenge - if (httpAuthenticator.reRequestAuthentication(channel, ac)) { + if (httpAuthenticator.reRequestAuthentication(request.getRestChannel(), ac)) { // auditLog.logFailedLogin(ac.getUsername()+" ", request); --noauditlog return false; } else { @@ -325,9 +329,7 @@ && isBlocked(((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).g authDomain.getBackend().getClass().getName() )) { authFailureListener.onAuthFailure( - (request.getHttpChannel().getRemoteAddress() instanceof InetSocketAddress) - ? ((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).getAddress() - : null, + request.getRemoteAddress().map(InetSocketAddress::getAddress).orElse(null), ac, request ); @@ -338,7 +340,7 @@ && isBlocked(((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).g if (adminDns.isAdmin(authenticatedUser)) { log.error("Cannot authenticate rest user because admin user is not permitted to login via HTTP"); auditLog.logFailedLogin(authenticatedUser.getName(), true, null, request); - channel.sendResponse( + request.getRestChannel().sendResponse( new BytesRestResponse( RestStatus.FORBIDDEN, "Cannot authenticate user because admin user is not permitted to login via HTTP" @@ -395,7 +397,7 @@ && isBlocked(((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).g log.debug("Rerequest with {}", firstChallengingHttpAuthenticator.getClass()); } - if (firstChallengingHttpAuthenticator.reRequestAuthentication(channel, null)) { + if (firstChallengingHttpAuthenticator.reRequestAuthentication(request.getRestChannel(), null)) { if (isDebugEnabled) { log.debug("Rerequest {} failed", firstChallengingHttpAuthenticator.getClass()); } @@ -419,18 +421,16 @@ && isBlocked(((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).g notifyIpAuthFailureListeners(request, authCredenetials); - channel.sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, "Authentication finally failed")); + request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, "Authentication finally failed")); return false; } return authenticated; } - private void notifyIpAuthFailureListeners(RestRequest request, AuthCredentials authCredentials) { + private void notifyIpAuthFailureListeners(SecurityRequest request, AuthCredentials authCredentials) { notifyIpAuthFailureListeners( - (request.getHttpChannel().getRemoteAddress() instanceof InetSocketAddress) - ? ((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).getAddress() - : null, + request.getRemoteAddress().map(InetSocketAddress::getAddress).orElse(null), authCredentials, request ); @@ -580,7 +580,7 @@ public User call() throws Exception { } } - private User impersonate(final RestRequest request, final User originalUser) throws OpenSearchSecurityException { + private User impersonate(final SecurityRequest request, final User originalUser) throws OpenSearchSecurityException { final String impersonatedUserHeader = request.header("opendistro_security_impersonate_as"); diff --git a/src/main/java/org/opensearch/security/auth/UserInjector.java b/src/main/java/org/opensearch/security/auth/UserInjector.java index 3e89a52e93..f724578323 100644 --- a/src/main/java/org/opensearch/security/auth/UserInjector.java +++ b/src/main/java/org/opensearch/security/auth/UserInjector.java @@ -40,6 +40,7 @@ import org.opensearch.core.common.transport.TransportAddress; import org.opensearch.rest.RestRequest; import org.opensearch.security.auditlog.AuditLog; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.http.XFFResolver; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.SecurityUtils; @@ -172,7 +173,7 @@ public InjectedUser getInjectedUser() { return injectedUser; } - boolean injectUser(RestRequest request) { + boolean injectUser(SecurityRequest request) { InjectedUser injectedUser = getInjectedUser(); if (injectedUser == null) { return false; diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java index 35f4332520..2acefe3c1c 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java @@ -35,6 +35,7 @@ import org.opensearch.rest.RestRequest.Method; import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.dlic.rest.support.Utils; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.privileges.PrivilegesEvaluator; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; @@ -446,7 +447,8 @@ private String checkAdminCertBasedAccessPermissions(RestRequest request) throws } // Certificate based access, Check if we have an admin TLS certificate - SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, request, principalExtractor); + final SecurityRequest securityRequest = SecurityRequest.from(request); + SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { // here we log on error level, since authentication finally failed diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java new file mode 100644 index 0000000000..cc1a783cca --- /dev/null +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -0,0 +1,62 @@ +package org.opensearch.security.filter; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.net.ssl.SSLEngine; + +import org.opensearch.http.HttpChannel; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestRequest.Method; + +public class SecurityRequest { + + public Map> getHeaders() { + return null; + } + + public SSLEngine getSSLEngine() { + return null; + } + + public RestChannel getRestChannel() { + return null; + } + + public CharSequence path() { + return null; + } + + public Method method() { + return null; + } + + public Optional getRemoteAddress() { + return null; + } + + public boolean sourcedFromNetty() { + return false; + } + + public Object uri() { + return null; + } + + public RestRequest asRestRequest() { + return null; + } + + public static SecurityRequest from(RestRequest request) { + return null; + } + + public String header(String string) { + return null; + } + +} diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 54d98ffe13..163c24117f 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -131,7 +131,7 @@ public SecurityRestFilter( public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return (request, channel, client) -> { org.apache.logging.log4j.ThreadContext.clearAll(); - if (!checkAndAuthenticateRequest(request, channel)) { + if (!checkAndAuthenticateRequest(SecurityRequest.from(request))) { User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); boolean isSuperAdminUser = userIsSuperAdmin(user, adminDNs); if (isSuperAdminUser @@ -199,7 +199,9 @@ private boolean authorizeRequest(RestHandler original, RestRequest request, Rest return true; } - private boolean checkAndAuthenticateRequest(RestRequest request, RestChannel channel) throws Exception { + private boolean checkAndAuthenticateRequest(SecurityRequest request) throws Exception { + + RestChannel channel = request.getRestChannel(); threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, Origin.REST.toString()); @@ -246,7 +248,7 @@ private boolean checkAndAuthenticateRequest(RestRequest request, RestChannel cha Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; if (request.method() != Method.OPTIONS && !(HEALTH_SUFFIX.equals(suffix)) && !(WHO_AM_I_SUFFIX.equals(suffix))) { - if (!registry.authenticate(request, channel, threadContext)) { + if (!registry.authenticate(request, threadContext)) { // another roundtrip org.apache.logging.log4j.ThreadContext.remove("user"); return true; diff --git a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java new file mode 100644 index 0000000000..f834f7b0fa --- /dev/null +++ b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java @@ -0,0 +1,47 @@ +package org.opensearch.security.http; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.util.ReferenceCountUtil; + +public class AuthenicationVerifier extends ChannelInboundHandlerAdapter { + + final static Logger log = LogManager.getLogger(AuthenicationVerifier.class); + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (!(msg instanceof HttpRequest)) { + ctx.fireChannelRead(msg); + } + + HttpRequest request = (HttpRequest) msg; + if (!isAuthenticated(request)) { + final FullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.UNAUTHORIZED); + ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + ReferenceCountUtil.release(msg); + } else { + // Lets the request pass to the next channel handler + ctx.fireChannelRead(msg); + } + } + + private boolean isAuthenticated(HttpRequest request) { + log.info("Checking if request is authenticated:\n" + request); + + final boolean shouldBlock = request.headers().contains("blockme"); + + return !shouldBlock; + } + +} diff --git a/src/main/java/org/opensearch/security/http/RemoteIpDetector.java b/src/main/java/org/opensearch/security/http/RemoteIpDetector.java index f464c0653a..f38e66362c 100644 --- a/src/main/java/org/opensearch/security/http/RemoteIpDetector.java +++ b/src/main/java/org/opensearch/security/http/RemoteIpDetector.java @@ -43,6 +43,7 @@ package org.opensearch.security.http; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.LinkedList; import java.util.List; @@ -53,6 +54,7 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.ConfigConstants; final class RemoteIpDetector { @@ -115,8 +117,12 @@ public String getRemoteIpHeader() { return remoteIpHeader; } - String detect(RestRequest request, ThreadContext threadContext) { - final String originalRemoteAddr = ((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).getAddress().getHostAddress(); + String detect(SecurityRequest request, ThreadContext threadContext) { + + final String originalRemoteAddr = request.getRemoteAddress() + .map(InetSocketAddress::getAddress) + .map(InetAddress::getHostAddress) + .orElseThrow(); final boolean isTraceEnabled = log.isTraceEnabled(); if (isTraceEnabled) { @@ -173,8 +179,10 @@ String detect(RestRequest request, ThreadContext threadContext) { if (remoteIp != null) { if (isTraceEnabled) { - final String originalRemoteHost = ((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).getAddress() - .getHostName(); + final String originalRemoteHost = request.getRemoteAddress() + .map(InetSocketAddress::getAddress) + .map(InetAddress::getHostName) + .orElseThrow(); log.trace( "Incoming request {} with originalRemoteAddr '{}', originalRemoteHost='{}', will be seen as newRemoteAddr='{}'", request.uri(), @@ -196,7 +204,7 @@ String detect(RestRequest request, ThreadContext threadContext) { log.trace( "Skip RemoteIpDetector for request {} with originalRemoteAddr '{}' cause no internal proxy matches", request.uri(), - request.getHttpChannel().getRemoteAddress() + request.getRemoteAddress().orElse(null) ); } } diff --git a/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java b/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java index a8e675ec74..467d25b16a 100644 --- a/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java +++ b/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java @@ -28,6 +28,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelInboundHandlerAdapter; import org.opensearch.common.network.NetworkService; import org.opensearch.common.settings.ClusterSettings; @@ -71,6 +72,11 @@ public ChannelHandler configureServerChannelHandler() { return new NonSslHttpChannelHandler(this, handlingSettings); } + @Override + protected ChannelInboundHandlerAdapter createHeaderVerifier() { + return new AuthenicationVerifier(); + } + protected class NonSslHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler { protected NonSslHttpChannelHandler(Netty4HttpServerTransport transport, final HttpHandlingSettings handlingSettings) { @@ -82,4 +88,6 @@ protected void initChannel(Channel ch) throws Exception { super.initChannel(ch); } } + + } diff --git a/src/main/java/org/opensearch/security/http/XFFResolver.java b/src/main/java/org/opensearch/security/http/XFFResolver.java index ddb7255179..7a81aea8f7 100644 --- a/src/main/java/org/opensearch/security/http/XFFResolver.java +++ b/src/main/java/org/opensearch/security/http/XFFResolver.java @@ -37,6 +37,7 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.http.netty4.Netty4HttpChannel; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.securityconf.DynamicConfigModel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.threadpool.ThreadPool; @@ -53,19 +54,17 @@ public XFFResolver(final ThreadPool threadPool) { this.threadContext = threadPool.getThreadContext(); } - public TransportAddress resolve(final RestRequest request) throws OpenSearchSecurityException { + public TransportAddress resolve(final SecurityRequest request) throws OpenSearchSecurityException { final boolean isTraceEnabled = log.isTraceEnabled(); if (isTraceEnabled) { - log.trace("resolve {}", request.getHttpChannel().getRemoteAddress()); + log.trace("resolve {}", request.getRemoteAddress().orElse(null)); } - if (enabled - && request.getHttpChannel().getRemoteAddress() instanceof InetSocketAddress - && request.getHttpChannel() instanceof Netty4HttpChannel) { - + if (enabled && request.getRemoteAddress().isPresent() && request.sourcedFromNetty()) { + final InetSocketAddress remoteAddress = request.getRemoteAddress().get(); final InetSocketAddress isa = new InetSocketAddress( detector.detect(request, threadContext), - ((InetSocketAddress) request.getHttpChannel().getRemoteAddress()).getPort() + remoteAddress.getPort() ); if (isa.isUnresolved()) { @@ -74,23 +73,21 @@ public TransportAddress resolve(final RestRequest request) throws OpenSearchSecu if (isTraceEnabled) { if (threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_XFF_DONE) == Boolean.TRUE) { - log.trace("xff resolved {} to {}", request.getHttpChannel().getRemoteAddress(), isa); + log.trace("xff resolved {} to {}", remoteAddress, isa); } else { log.trace("no xff done for {}", request.getClass()); } } return new TransportAddress(isa); - } else if (request.getHttpChannel().getRemoteAddress() instanceof InetSocketAddress) { - + } else if (request.getRemoteAddress().isPresent()) { if (isTraceEnabled) { log.trace("no xff done (enabled or no netty request) {},{},{},{}", enabled, request.getClass()); - } - return new TransportAddress((InetSocketAddress) request.getHttpChannel().getRemoteAddress()); + return new TransportAddress((InetSocketAddress) request.getRemoteAddress().get()); } else { throw new OpenSearchSecurityException( "Cannot handle this request. Remote address is " - + request.getHttpChannel().getRemoteAddress() + + request.getRemoteAddress().orElse(null) + " with request class " + request.getClass() ); diff --git a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java index c582c9f51b..4876209dbd 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java @@ -29,6 +29,7 @@ import org.opensearch.security.action.configupdate.ConfigUpdateAction; import org.opensearch.security.action.configupdate.ConfigUpdateRequest; import org.opensearch.security.configuration.AdminDNs; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; import org.opensearch.security.support.ConfigConstants; @@ -73,7 +74,8 @@ public List routes() { protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { String[] configTypes = request.paramAsStringArrayOrEmptyIfAll("config_types"); - SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, request, principalExtractor); + final SecurityRequest securityRequest = SecurityRequest.from(request); + SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); diff --git a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java index 8bab16484d..619ff06ed4 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java @@ -32,6 +32,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.configuration.AdminDNs; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; import org.opensearch.security.ssl.util.SSLRequestHelper.SSLInfo; @@ -97,8 +98,8 @@ public void accept(RestChannel channel) throws Exception { BytesRestResponse response = null; try { - - SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, request, principalExtractor); + final SecurityRequest securityRequest = SecurityRequest.from(request); + SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { response = new BytesRestResponse(RestStatus.FORBIDDEN, "No security data"); diff --git a/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java b/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java index 90f01df9b5..d12422800e 100644 --- a/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java +++ b/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java @@ -18,6 +18,7 @@ package org.opensearch.security.ssl; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; @@ -34,4 +35,8 @@ default void logError(Throwable t, boolean isRest) { default void logError(Throwable t, final TransportRequest request, String action, Task task, int type) { // no-op } + + default void logError(Throwable t, SecurityRequest request, int type) { + this.logError(t, request.asRestRequest(), type); + } } diff --git a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java index 081cc13f3e..bf87cc9bd6 100644 --- a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java +++ b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java @@ -20,6 +20,7 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.DecoderException; import io.netty.handler.ssl.ApplicationProtocolNames; import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler; @@ -36,6 +37,7 @@ import org.opensearch.http.HttpHandlingSettings; import org.opensearch.http.netty4.Netty4HttpChannel; import org.opensearch.http.netty4.Netty4HttpServerTransport; +import org.opensearch.security.http.AuthenicationVerifier; import org.opensearch.security.ssl.SecurityKeyStore; import org.opensearch.security.ssl.SslExceptionHandler; import org.opensearch.telemetry.tracing.Tracer; @@ -94,6 +96,11 @@ public void onException(HttpChannel channel, Exception cause0) { super.onException(channel, cause0); } + @Override + protected ChannelInboundHandlerAdapter createHeaderVerifier() { + return new AuthenicationVerifier(); + } + protected class SSLHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler { /** * Application negotiation handler to select either HTTP 1.1 or HTTP 2 protocol, based @@ -149,4 +156,6 @@ protected void configurePipeline(Channel ch) { ch.pipeline().addLast(new Http2OrHttpHandler()); } } + + } diff --git a/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java b/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java index e053da7787..fac256d69e 100644 --- a/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java +++ b/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java @@ -33,6 +33,7 @@ import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.ssl.SslExceptionHandler; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.ssl.util.SSLRequestHelper; @@ -83,7 +84,8 @@ protected void checkRequest(final RestRequest request, final RestChannel channel } try { - if (SSLRequestHelper.getSSLInfo(settings, configPath, request, null) == null) { + final SecurityRequest securityReqest = SecurityRequest.from(request); + if (SSLRequestHelper.getSSLInfo(settings, configPath, securityReqest, null) == null) { logger.error("Not an SSL request"); throw new OpenSearchSecurityException("Not an SSL request", RestStatus.INTERNAL_SERVER_ERROR); } diff --git a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java index 54d109f497..b053c0de51 100644 --- a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java +++ b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java @@ -39,6 +39,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; import org.opensearch.core.rest.RestStatus; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.ssl.SecurityKeyStore; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; @@ -84,8 +85,8 @@ public void accept(RestChannel channel) throws Exception { BytesRestResponse response = null; try { - - SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, request, principalExtractor); + final SecurityRequest securityRequest = SecurityRequest.from(request); + SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); X509Certificate[] certs = sslInfo == null ? null : sslInfo.getX509Certs(); X509Certificate[] localCerts = sslInfo == null ? null : sslInfo.getLocalCertificates(); diff --git a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java index 1a23d0bb59..d841ec228d 100644 --- a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java +++ b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java @@ -47,6 +47,7 @@ import org.opensearch.env.Environment; import org.opensearch.http.netty4.Netty4HttpChannel; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.transport.PrincipalExtractor.Type; @@ -121,25 +122,10 @@ public String toString() { public static SSLInfo getSSLInfo( final Settings settings, final Path configPath, - final RestRequest request, + final SecurityRequest request, PrincipalExtractor principalExtractor ) throws SSLPeerUnverifiedException { - - if (request == null || request.getHttpChannel() == null || !(request.getHttpChannel() instanceof Netty4HttpChannel)) { - return null; - } - - final Netty4HttpChannel httpChannel = (Netty4HttpChannel) request.getHttpChannel(); - SslHandler sslhandler = (SslHandler) httpChannel.getNettyChannel().pipeline().get("ssl_http"); - if (sslhandler == null && httpChannel.inboundPipeline() != null) { - sslhandler = (SslHandler) httpChannel.inboundPipeline().get("ssl_http"); - } - - if (sslhandler == null) { - return null; - } - - final SSLEngine engine = sslhandler.engine(); + final SSLEngine engine = request.getSSLEngine(); final SSLSession session = engine.getSession(); X509Certificate[] x509Certs = null; diff --git a/src/main/java/org/opensearch/security/support/HTTPHelper.java b/src/main/java/org/opensearch/security/support/HTTPHelper.java index c3b191f770..c9672bb97f 100644 --- a/src/main/java/org/opensearch/security/support/HTTPHelper.java +++ b/src/main/java/org/opensearch/security/support/HTTPHelper.java @@ -34,6 +34,7 @@ import org.apache.logging.log4j.Logger; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; public class HTTPHelper { @@ -86,7 +87,7 @@ public static AuthCredentials extractCredentials(String authorizationHeader, Log } } - public static boolean containsBadHeader(final RestRequest request) { + public static boolean containsBadHeader(final SecurityRequest request) { final Map> headers; From 6abd939713e4ce44ad7ed7913ce62ec0ef590800 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Fri, 29 Sep 2023 15:47:43 +0000 Subject: [PATCH 02/50] Add request source from the netty channel Signed-off-by: Peter Nied --- .../security/filter/SecurityRequest.java | 55 +++---- .../filter/SecurityRequestFactory.java | 140 ++++++++++++++++++ .../security/http/AuthenicationVerifier.java | 3 + 3 files changed, 161 insertions(+), 37 deletions(-) create mode 100644 src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java index cc1a783cca..1e8d2fa7fd 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -1,62 +1,43 @@ package org.opensearch.security.filter; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.stream.Stream; import javax.net.ssl.SSLEngine; -import org.opensearch.http.HttpChannel; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; -public class SecurityRequest { +public interface SecurityRequest { - public Map> getHeaders() { - return null; - } + public Map> getHeaders(); - public SSLEngine getSSLEngine() { - return null; - } + public SSLEngine getSSLEngine(); - public RestChannel getRestChannel() { - return null; - } + public RestChannel getRestChannel(); - public CharSequence path() { - return null; - } + public CharSequence path(); - public Method method() { - return null; - } + public Method method(); - public Optional getRemoteAddress() { - return null; - } + public Optional getRemoteAddress(); - public boolean sourcedFromNetty() { - return false; - } + public boolean sourcedFromNetty(); - public Object uri() { - return null; - } + public String uri(); - public RestRequest asRestRequest() { - return null; - } - - public static SecurityRequest from(RestRequest request) { - return null; - } + public Optional asRestRequest(); - public String header(String string) { - return null; + default public String header(final String headerName) { + final Optional>> headersMap = Optional.ofNullable(getHeaders()); + return headersMap + .map(headers -> headers.get(headerName)) + .map(List::stream) + .flatMap(Stream::findFirst) + .orElse(null); } - } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java new file mode 100644 index 0000000000..e2387af010 --- /dev/null +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -0,0 +1,140 @@ +package org.opensearch.security.filter; + +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.net.ssl.SSLEngine; + +import org.opensearch.http.netty4.Netty4HttpChannel; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestRequest.Method; + +import io.netty.handler.codec.http.HttpRequest; + +public class SecurityRequestFactory { + + public static SecurityRequest from() { + return null; + } + + public static SecurityRequest from(final RestRequest request, final RestChannel channel) { + return new SecurityRestRequest(request, channel); + } + + protected static class SecurityRestRequest implements SecurityRequest { + private final RestRequest underlyingRequest; + private final RestChannel underlyingChannel; + SecurityRestRequest(final RestRequest request, final RestChannel channel) { + underlyingRequest = request; + underlyingChannel = channel; + } + + @Override + public Map> getHeaders() { + return underlyingRequest.getHeaders(); + } + + @Override + public SSLEngine getSSLEngine() { + // TODO: this doesn't seem properly handled + + throw new UnsupportedOperationException("Unimplemented method 'getSSLEngine'"); + } + + @Override + public RestChannel getRestChannel() { + return underlyingChannel; + } + + @Override + public CharSequence path() { + return underlyingRequest.path(); + } + + @Override + public Method method() { + return underlyingRequest.method(); + } + + @Override + public Optional getRemoteAddress() { + return Optional.ofNullable(this.underlyingRequest.getHttpChannel().getRemoteAddress()); + } + + @Override + public boolean sourcedFromNetty() { + return underlyingRequest.getHttpChannel() instanceof Netty4HttpChannel; + } + + @Override + public String uri() { + return underlyingRequest.uri(); + } + + @Override + public Optional asRestRequest() { + return Optional.of(underlyingRequest); + } + } + + + protected static class NettyRequest implements SecurityRequest { + @Override + public Map> getHeaders() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getHeaders'"); + } + + @Override + public SSLEngine getSSLEngine() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getSSLEngine'"); + } + + @Override + public RestChannel getRestChannel() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getRestChannel'"); + } + + @Override + public CharSequence path() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'path'"); + } + + @Override + public Method method() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'method'"); + } + + @Override + public Optional getRemoteAddress() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getRemoteAddress'"); + } + + @Override + public boolean sourcedFromNetty() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'sourcedFromNetty'"); + } + + @Override + public String uri() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'uri'"); + } + + @Override + public Optional asRestRequest() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'asRestRequest'"); + } + + } +} diff --git a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java index f834f7b0fa..f67c126b62 100644 --- a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java +++ b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java @@ -37,6 +37,9 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception } private boolean isAuthenticated(HttpRequest request) { + + + log.info("Checking if request is authenticated:\n" + request); final boolean shouldBlock = request.headers().contains("blockme"); From da8d0cbbbaf94c56b9e132c22bddf5ed716455db Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Fri, 29 Sep 2023 16:25:33 +0000 Subject: [PATCH 03/50] Plumb SecurityRequest into HTTPAuthenticator interface Signed-off-by: Peter Nied --- .../jwt/AbstractHTTPJwtAuthenticator.java | 7 +++--- .../auth/http/jwt/HTTPJwtAuthenticator.java | 9 +++---- .../kerberos/HTTPSpnegoAuthenticator.java | 5 ++-- .../auth/http/saml/HTTPSamlAuthenticator.java | 11 +++++---- .../security/auditlog/AuditLog.java | 8 +++---- .../security/auth/BackendRegistry.java | 10 ++++---- .../security/auth/HTTPAuthenticator.java | 3 ++- .../rest/api/RestApiPrivilegesEvaluator.java | 4 +++- .../security/filter/SecurityRequest.java | 4 ++++ .../filter/SecurityRequestFactory.java | 24 +++++++++++++++++++ .../security/filter/SecurityRestFilter.java | 4 ++-- .../security/http/AuthenicationVerifier.java | 2 +- .../security/http/HTTPBasicAuthenticator.java | 3 ++- .../http/HTTPClientCertAuthenticator.java | 3 ++- .../security/http/HTTPProxyAuthenticator.java | 3 ++- .../http/OnBehalfOfAuthenticator.java | 9 +++---- .../proxy/HTTPExtendedProxyAuthenticator.java | 3 ++- .../rest/SecurityConfigUpdateAction.java | 4 +++- .../security/rest/SecurityWhoAmIAction.java | 3 ++- .../security/ssl/SslExceptionHandler.java | 2 +- .../ssl/http/netty/ValidatingDispatcher.java | 3 ++- .../ssl/rest/SecuritySSLInfoAction.java | 3 ++- .../cache/DummyHTTPAuthenticator.java | 3 ++- 23 files changed, 88 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java index 4dab3c7740..7a9c4bce67 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java @@ -40,6 +40,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; public abstract class AbstractHTTPJwtAuthenticator implements HTTPAuthenticator { @@ -83,7 +84,7 @@ public AbstractHTTPJwtAuthenticator(Settings settings, Path configPath) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(RestRequest request, ThreadContext context) throws OpenSearchSecurityException { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -100,7 +101,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final RestRequest request) throws OpenSearchSecurityException { + private AuthCredentials extractCredentials0(final SecurityRequest request) throws OpenSearchSecurityException { String jwtString = getJwtTokenString(request); @@ -141,7 +142,7 @@ private AuthCredentials extractCredentials0(final RestRequest request) throws Op } - protected String getJwtTokenString(RestRequest request) { + protected String getJwtTokenString(SecurityRequest request) { String jwtToken = request.header(jwtHeaderName); if (isDefaultAuthHeader && jwtToken != null && BASIC.matcher(jwtToken).matches()) { jwtToken = null; diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java index 03e385d5c0..35b203b4e5 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java @@ -35,6 +35,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.KeyUtils; @@ -84,7 +85,7 @@ public HTTPJwtAuthenticator(final Settings settings, final Path configPath) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(RestRequest request, ThreadContext context) throws OpenSearchSecurityException { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -101,7 +102,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final RestRequest request) { + private AuthCredentials extractCredentials0(final SecurityRequest request) { if (jwtParser == null) { log.error("Missing Signing Key. JWT authentication will not work"); return null; @@ -183,7 +184,7 @@ public String getType() { return "jwt"; } - protected String extractSubject(final Claims claims, final RestRequest request) { + protected String extractSubject(final Claims claims, final SecurityRequest request) { String subject = claims.getSubject(); if (subjectKey != null) { // try to get roles from claims, first as Object to avoid having to catch the ExpectedTypeException @@ -207,7 +208,7 @@ protected String extractSubject(final Claims claims, final RestRequest request) } @SuppressWarnings("unchecked") - protected String[] extractRoles(final Claims claims, final RestRequest request) { + protected String[] extractRoles(final Claims claims, final SecurityRequest request) { // no roles key specified if (rolesKey == null) { return new String[0]; diff --git a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java index 29f537e899..4aa2a6c8d5 100644 --- a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java @@ -53,6 +53,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; public class HTTPSpnegoAuthenticator implements HTTPAuthenticator { @@ -171,7 +172,7 @@ public Void run() { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final RestRequest request, ThreadContext threadContext) { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -188,7 +189,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final RestRequest request) { + private AuthCredentials extractCredentials0(final SecurityRequest request) { if (acceptorPrincipal == null || acceptorKeyTabPath == null) { log.error("Missing acceptor principal or keytab configuration. Kerberos authentication will not work"); 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 cd6209952f..f23042febc 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 @@ -61,6 +61,7 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.Destroyable; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.PemKeyReader; import org.opensearch.security.user.AuthCredentials; @@ -149,17 +150,17 @@ public HTTPSamlAuthenticator(final Settings settings, final Path configPath) { } @Override - public AuthCredentials extractCredentials(RestRequest restRequest, ThreadContext threadContext) throws OpenSearchSecurityException { - Matcher matcher = PATTERN_PATH_PREFIX.matcher(restRequest.path()); + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) throws OpenSearchSecurityException { + Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; if (API_AUTHTOKEN_SUFFIX.equals(suffix)) { return null; } - AuthCredentials authCredentials = this.httpJwtAuthenticator.extractCredentials(restRequest, threadContext); + AuthCredentials authCredentials = this.httpJwtAuthenticator.extractCredentials(request, threadContext); if (AUTHINFO_SUFFIX.equals(suffix)) { - this.initLogoutUrl(restRequest, threadContext, authCredentials); + this.initLogoutUrl(request, threadContext, authCredentials); } return authCredentials; @@ -398,7 +399,7 @@ String buildLogoutUrl(AuthCredentials authCredentials) { } - private void initLogoutUrl(RestRequest restRequest, ThreadContext threadContext, AuthCredentials authCredentials) { + private void initLogoutUrl(SecurityRequest restRequest, ThreadContext threadContext, AuthCredentials authCredentials) { threadContext.putTransient(ConfigConstants.SSO_LOGOUT_URL, buildLogoutUrl(authCredentials)); } diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLog.java b/src/main/java/org/opensearch/security/auditlog/AuditLog.java index edf06a7143..41c45ac789 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLog.java @@ -48,13 +48,13 @@ public interface AuditLog extends Closeable { void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, RestRequest request); default void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { - this.logFailedLogin(effectiveUser, securityadmin, initiatingUser, request.asRestRequest()); + this.logFailedLogin(effectiveUser, securityadmin, initiatingUser, request.asRestRequest().get()); } void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, RestRequest request); default void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { - logSucceededLogin(effectiveUser, securityadmin, initiatingUser, request.asRestRequest()); + logSucceededLogin(effectiveUser, securityadmin, initiatingUser, request.asRestRequest().get()); } // privs @@ -75,7 +75,7 @@ default void logSucceededLogin(String effectiveUser, boolean securityadmin, Stri void logBadHeaders(RestRequest request); default void logBadHeaders(SecurityRequest request) { - this.logBadHeaders(request.asRestRequest()); + this.logBadHeaders(request.asRestRequest().get()); } void logSecurityIndexAttempt(TransportRequest request, String action, Task task); @@ -85,7 +85,7 @@ default void logBadHeaders(SecurityRequest request) { void logSSLException(RestRequest request, Throwable t); default void logSSLException(SecurityRequest request, Throwable t) { - this.logSSLException(request.asRestRequest(), t); + this.logSSLException(request.asRestRequest().get(), t); } void logDocumentRead(String index, String id, ShardId shardId, Map fieldNameValues); diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 6eb4c450a9..50c2bb2354 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -186,7 +186,7 @@ public void onDynamicConfigModelChanged(DynamicConfigModel dcm) { * @return The authenticated user, null means another roundtrip * @throws OpenSearchSecurityException */ - public boolean authenticate(final SecurityRequest request, final ThreadContext threadContext) { + public boolean authenticate(final SecurityRequest request, final ThreadContext _DO_NOT_USE) { final boolean isDebugEnabled = log.isDebugEnabled(); final boolean isBlockedBasedOnAddress = request.getRemoteAddress() .map(InetSocketAddress::getAddress) @@ -228,7 +228,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext t log.trace("Rest authentication request from {} [original: {}]", remoteAddress, request.getRemoteAddress().orElse(null)); } - threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS, remoteAddress); + threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS, remoteAddress); boolean authenticated = false; @@ -260,7 +260,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext t } final AuthCredentials ac; try { - ac = httpAuthenticator.extractCredentials(request.asRestRequest(), threadContext); + ac = httpAuthenticator.extractCredentials(request, threadPool.getThreadContext()); } catch (Exception e1) { if (isDebugEnabled) { log.debug("'{}' extracting credentials from {} http authenticator", e1.toString(), httpAuthenticator.getType(), e1); @@ -363,7 +363,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext t if (authenticated) { final User impersonatedUser = impersonate(request, authenticatedUser); - threadContext.putTransient( + threadPool.getThreadContext().putTransient( ConfigConstants.OPENDISTRO_SECURITY_USER, impersonatedUser == null ? authenticatedUser : impersonatedUser ); @@ -383,7 +383,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext t User anonymousUser = new User(User.ANONYMOUS.getName(), new HashSet(User.ANONYMOUS.getRoles()), null); anonymousUser.setRequestedTenant(tenant); - threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, anonymousUser); + threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, anonymousUser); auditLog.logSucceededLogin(anonymousUser.getName(), false, null, request); if (isDebugEnabled) { log.debug("Anonymous User is authenticated"); diff --git a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java index fa5065ef68..1ddc006445 100644 --- a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java +++ b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java @@ -30,6 +30,7 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; /** @@ -67,7 +68,7 @@ public interface HTTPAuthenticator { * If the authentication flow needs another roundtrip with the request originator do not mark it as complete. * @throws OpenSearchSecurityException */ - AuthCredentials extractCredentials(RestRequest request, ThreadContext context) throws OpenSearchSecurityException; + AuthCredentials extractCredentials(SecurityRequest request, ThreadContext context) throws OpenSearchSecurityException; /** * If the {@code extractCredentials()} call was not successful or the authentication flow needs another roundtrip this method diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java index 2acefe3c1c..45a9920443 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java @@ -36,6 +36,7 @@ import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.dlic.rest.support.Utils; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.privileges.PrivilegesEvaluator; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; @@ -447,7 +448,8 @@ private String checkAdminCertBasedAccessPermissions(RestRequest request) throws } // Certificate based access, Check if we have an admin TLS certificate - final SecurityRequest securityRequest = SecurityRequest.from(request); + // TODO: Doesn't seem like the channel is needed here, but need to make sure this works correctly. + final SecurityRequest securityRequest = SecurityRequestFactory.from(request, null); SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java index 1e8d2fa7fd..7122dcd2d6 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -40,4 +40,8 @@ default public String header(final String headerName) { .flatMap(Stream::findFirst) .orElse(null); } + + public boolean paramAsBoolean(String string, boolean b); + + public String param(String jwtUrlParameter); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index e2387af010..c1f165e4be 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -78,6 +78,18 @@ public String uri() { public Optional asRestRequest() { return Optional.of(underlyingRequest); } + + @Override + public boolean paramAsBoolean(String string, boolean b) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'paramAsBoolean'"); + } + + @Override + public String param(String jwtUrlParameter) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'param'"); + } } @@ -136,5 +148,17 @@ public Optional asRestRequest() { throw new UnsupportedOperationException("Unimplemented method 'asRestRequest'"); } + @Override + public boolean paramAsBoolean(String string, boolean b) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'paramAsBoolean'"); + } + + @Override + public String param(String jwtUrlParameter) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'param'"); + } + } } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 163c24117f..38fa009b2f 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -131,7 +131,7 @@ public SecurityRestFilter( public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return (request, channel, client) -> { org.apache.logging.log4j.ThreadContext.clearAll(); - if (!checkAndAuthenticateRequest(SecurityRequest.from(request))) { + if (!checkAndAuthenticateRequest(SecurityRequestFactory.from(request, channel))) { User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); boolean isSuperAdminUser = userIsSuperAdmin(user, adminDNs); if (isSuperAdminUser @@ -199,7 +199,7 @@ private boolean authorizeRequest(RestHandler original, RestRequest request, Rest return true; } - private boolean checkAndAuthenticateRequest(SecurityRequest request) throws Exception { + public boolean checkAndAuthenticateRequest(SecurityRequest request) throws Exception { RestChannel channel = request.getRestChannel(); diff --git a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java index f67c126b62..af1f281187 100644 --- a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java +++ b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java @@ -37,7 +37,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception } private boolean isAuthenticated(HttpRequest request) { - + log.info("Checking if request is authenticated:\n" + request); diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index 4be83bc2e2..53fe33c9f2 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -38,6 +38,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.HTTPHelper; import org.opensearch.security.user.AuthCredentials; @@ -51,7 +52,7 @@ public HTTPBasicAuthenticator(final Settings settings, final Path configPath) { } @Override - public AuthCredentials extractCredentials(final RestRequest request, ThreadContext threadContext) { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) { final boolean forceLogin = request.paramAsBoolean("force_login", false); diff --git a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java index b1e5d4ef40..fb34162827 100644 --- a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java @@ -44,6 +44,7 @@ import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -57,7 +58,7 @@ public HTTPClientCertAuthenticator(final Settings settings, final Path configPat } @Override - public AuthCredentials extractCredentials(final RestRequest request, final ThreadContext threadContext) { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) { final String principal = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_SSL_PRINCIPAL); diff --git a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java index a58a842394..ad6d4a1608 100644 --- a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java @@ -40,6 +40,7 @@ import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -56,7 +57,7 @@ public HTTPProxyAuthenticator(Settings settings, final Path configPath) { } @Override - public AuthCredentials extractCredentials(final RestRequest request, ThreadContext context) { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) { if (context.getTransient(ConfigConstants.OPENDISTRO_SECURITY_XFF_DONE) != Boolean.TRUE) { throw new OpenSearchSecurityException("xff not done"); diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java index 467edd8ac4..a4699412b9 100644 --- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java @@ -37,6 +37,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.KeyUtils; @@ -121,7 +122,7 @@ private String[] extractBackendRolesFromClaims(Claims claims) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(RestRequest request, ThreadContext context) throws OpenSearchSecurityException { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -138,7 +139,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final RestRequest request) { + private AuthCredentials extractCredentials0(final SecurityRequest request) { if (!oboEnabled) { log.error("On-behalf-of authentication is disabled"); return null; @@ -202,7 +203,7 @@ private AuthCredentials extractCredentials0(final RestRequest request) { return null; } - private String extractJwtFromHeader(RestRequest request) { + private String extractJwtFromHeader(SecurityRequest request) { String jwtToken = request.header(HttpHeaders.AUTHORIZATION); if (jwtToken == null || jwtToken.isEmpty()) { @@ -230,7 +231,7 @@ private void logDebug(String message, Object... args) { } } - public Boolean isRequestAllowed(final RestRequest request) { + public Boolean isRequestAllowed(final SecurityRequest request) { Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; if (request.method() == RestRequest.Method.POST && ON_BEHALF_OF_SUFFIX.equals(suffix) diff --git a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java index ef20374d69..d2dd692184 100644 --- a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java @@ -39,6 +39,7 @@ import org.opensearch.core.common.Strings; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.http.HTTPProxyAuthenticator; import org.opensearch.security.user.AuthCredentials; @@ -55,7 +56,7 @@ public HTTPExtendedProxyAuthenticator(Settings settings, final Path configPath) } @Override - public AuthCredentials extractCredentials(final RestRequest request, ThreadContext context) { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) { AuthCredentials credentials = super.extractCredentials(request, context); if (credentials == null) { return null; diff --git a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java index 4876209dbd..05f4d7ef20 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java @@ -30,6 +30,7 @@ import org.opensearch.security.action.configupdate.ConfigUpdateRequest; import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; import org.opensearch.security.support.ConfigConstants; @@ -74,7 +75,8 @@ public List routes() { protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { String[] configTypes = request.paramAsStringArrayOrEmptyIfAll("config_types"); - final SecurityRequest securityRequest = SecurityRequest.from(request); + // TODO: Need to re-write with a RestChannelConsumer + final SecurityRequest securityRequest = SecurityRequestFactory.from(request, null); SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { diff --git a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java index 619ff06ed4..e4f0fb6d06 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java @@ -33,6 +33,7 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; import org.opensearch.security.ssl.util.SSLRequestHelper.SSLInfo; @@ -98,7 +99,7 @@ public void accept(RestChannel channel) throws Exception { BytesRestResponse response = null; try { - final SecurityRequest securityRequest = SecurityRequest.from(request); + final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel);; SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { diff --git a/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java b/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java index d12422800e..be120b2acd 100644 --- a/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java +++ b/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java @@ -37,6 +37,6 @@ default void logError(Throwable t, final TransportRequest request, String action } default void logError(Throwable t, SecurityRequest request, int type) { - this.logError(t, request.asRestRequest(), type); + this.logError(t, request.asRestRequest().get(), type); } } diff --git a/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java b/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java index fac256d69e..af17607468 100644 --- a/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java +++ b/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java @@ -34,6 +34,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.SslExceptionHandler; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.ssl.util.SSLRequestHelper; @@ -84,7 +85,7 @@ protected void checkRequest(final RestRequest request, final RestChannel channel } try { - final SecurityRequest securityReqest = SecurityRequest.from(request); + final SecurityRequest securityReqest = SecurityRequestFactory.from(request, channel); if (SSLRequestHelper.getSSLInfo(settings, configPath, securityReqest, null) == null) { logger.error("Not an SSL request"); throw new OpenSearchSecurityException("Not an SSL request", RestStatus.INTERNAL_SERVER_ERROR); diff --git a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java index b053c0de51..a3bed2674d 100644 --- a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java +++ b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java @@ -40,6 +40,7 @@ import org.opensearch.rest.RestRequest.Method; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.SecurityKeyStore; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; @@ -85,7 +86,7 @@ public void accept(RestChannel channel) throws Exception { BytesRestResponse response = null; try { - final SecurityRequest securityRequest = SecurityRequest.from(request); + final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel);; SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); X509Certificate[] certs = sslInfo == null ? null : sslInfo.getX509Certs(); X509Certificate[] localCerts = sslInfo == null ? null : sslInfo.getLocalCertificates(); diff --git a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java index 55c2e789c6..aa9c9106ea 100644 --- a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java +++ b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java @@ -19,6 +19,7 @@ import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; public class DummyHTTPAuthenticator implements HTTPAuthenticator { @@ -33,7 +34,7 @@ public String getType() { } @Override - public AuthCredentials extractCredentials(RestRequest request, ThreadContext context) throws OpenSearchSecurityException { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { count++; return new AuthCredentials("dummy").markComplete(); } From 26c6b8351404700d49c9140f9f80ad9aed29cab4 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Fri, 29 Sep 2023 17:04:56 +0000 Subject: [PATCH 04/50] Fix all tests Signed-off-by: Peter Nied --- .../jwt/AbstractHTTPJwtAuthenticator.java | 4 +-- .../auth/http/jwt/HTTPJwtAuthenticator.java | 4 +-- .../security/auditlog/AuditLog.java | 28 ++++----------- .../auditlog/AuditLogSslExceptionHandler.java | 5 +-- .../security/auditlog/NullAuditLog.java | 13 +++---- .../auditlog/impl/AbstractAuditLog.java | 15 ++++---- .../security/auditlog/impl/AuditLogImpl.java | 13 +++---- .../security/auditlog/impl/AuditMessage.java | 10 +++--- .../dlic/rest/api/AbstractApiAction.java | 9 +++-- .../security/filter/SecurityRequest.java | 6 ++-- .../filter/SecurityRequestFactory.java | 25 ++++---------- .../security/filter/SecurityRestFilter.java | 10 +++--- .../security/http/HTTPBasicAuthenticator.java | 2 +- .../http/jwt/HTTPJwtAuthenticatorTest.java | 18 +++++----- ...wtKeyByOpenIdConnectAuthenticatorTest.java | 34 +++++++++---------- ...wtKeyByOpenIdConnectAuthenticatorTest.java | 18 +++++----- .../auditlog/helper/MockRestRequest.java | 6 ++++ .../security/auditlog/impl/AuditlogTest.java | 3 +- .../auditlog/impl/DisabledCategoriesTest.java | 8 ++--- .../api/RestApiPrivilegesEvaluatorTest.java | 1 + .../http/OnBehalfOfAuthenticatorTest.java | 18 +++++----- .../HTTPExtendedProxyAuthenticatorTest.java | 15 +++++--- .../security/util/FakeRestRequest.java | 5 +++ 23 files changed, 135 insertions(+), 135 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java index 7a9c4bce67..69fb4515d8 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java @@ -150,10 +150,10 @@ protected String getJwtTokenString(SecurityRequest request) { if (jwtUrlParameter != null) { if (jwtToken == null || jwtToken.isEmpty()) { - jwtToken = request.param(jwtUrlParameter); + jwtToken = request.params().get(jwtUrlParameter); } else { // just consume to avoid "contains unrecognized parameter" - request.param(jwtUrlParameter); + request.params().get(jwtUrlParameter); } } diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java index 35b203b4e5..28e831c70b 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java @@ -114,10 +114,10 @@ private AuthCredentials extractCredentials0(final SecurityRequest request) { } if ((jwtToken == null || jwtToken.isEmpty()) && jwtUrlParameter != null) { - jwtToken = request.param(jwtUrlParameter); + jwtToken = request.params().get(jwtUrlParameter); } else { // just consume to avoid "contains unrecognized parameter" - request.param(jwtUrlParameter); + request.params().get(jwtUrlParameter); } if (jwtToken == null || jwtToken.length() == 0) { diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLog.java b/src/main/java/org/opensearch/security/auditlog/AuditLog.java index 41c45ac789..d6c182eada 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLog.java @@ -45,22 +45,14 @@ public interface AuditLog extends Closeable { // login - void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, RestRequest request); + void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request); - default void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { - this.logFailedLogin(effectiveUser, securityadmin, initiatingUser, request.asRestRequest().get()); - } - - void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, RestRequest request); - - default void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { - logSucceededLogin(effectiveUser, securityadmin, initiatingUser, request.asRestRequest().get()); - } + void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request); // privs - void logMissingPrivileges(String privilege, String effectiveUser, RestRequest request); + void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request); - void logGrantedPrivileges(String effectiveUser, RestRequest request); + void logGrantedPrivileges(String effectiveUser, SecurityRequest request); void logMissingPrivileges(String privilege, TransportRequest request, Task task); @@ -72,21 +64,13 @@ default void logSucceededLogin(String effectiveUser, boolean securityadmin, Stri // spoof void logBadHeaders(TransportRequest request, String action, Task task); - void logBadHeaders(RestRequest request); - - default void logBadHeaders(SecurityRequest request) { - this.logBadHeaders(request.asRestRequest().get()); - } + void logBadHeaders(SecurityRequest request); void logSecurityIndexAttempt(TransportRequest request, String action, Task task); void logSSLException(TransportRequest request, Throwable t, String action, Task task); - void logSSLException(RestRequest request, Throwable t); - - default void logSSLException(SecurityRequest request, Throwable t) { - this.logSSLException(request.asRestRequest().get(), t); - } + void logSSLException(SecurityRequest request, Throwable t); void logDocumentRead(String index, String id, ShardId shardId, Map fieldNameValues); diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java b/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java index 30cef3a84a..4d535856e8 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java @@ -28,6 +28,7 @@ import org.opensearch.OpenSearchException; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.ssl.SslExceptionHandler; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; @@ -42,7 +43,7 @@ public AuditLogSslExceptionHandler(final AuditLog auditLog) { } @Override - public void logError(Throwable t, RestRequest request, int type) { + public void logError(Throwable t, SecurityRequest request, int type) { switch (type) { case 0: auditLog.logSSLException(request, t); @@ -58,7 +59,7 @@ public void logError(Throwable t, RestRequest request, int type) { @Override public void logError(Throwable t, boolean isRest) { if (isRest) { - auditLog.logSSLException((RestRequest)null, t); + auditLog.logSSLException(null, t); } else { auditLog.logSSLException(null, t, null, null); } diff --git a/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java b/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java index 809951d48a..a4d5a969c1 100644 --- a/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java @@ -38,6 +38,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; @@ -49,12 +50,12 @@ public void close() throws IOException { } @Override - public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, RestRequest request) { + public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { // noop, intentionally left empty } @Override - public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, RestRequest request) { + public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { // noop, intentionally left empty } @@ -79,7 +80,7 @@ public void logBadHeaders(TransportRequest request, String action, Task task) { } @Override - public void logBadHeaders(RestRequest request) { + public void logBadHeaders(SecurityRequest request) { // noop, intentionally left empty } @@ -94,17 +95,17 @@ public void logSSLException(TransportRequest request, Throwable t, String action } @Override - public void logSSLException(RestRequest request, Throwable t) { + public void logSSLException(SecurityRequest request, Throwable t) { // noop, intentionally left empty } @Override - public void logMissingPrivileges(String privilege, String effectiveUser, RestRequest request) { + public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request) { // noop, intentionally left empty } @Override - public void logGrantedPrivileges(String effectiveUser, RestRequest request) { + public void logGrantedPrivileges(String effectiveUser, SecurityRequest request) { // noop, intentionally left empty } diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java index 804e0a2114..c6752be8b2 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java @@ -66,6 +66,7 @@ import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; import org.opensearch.security.dlic.rest.support.Utils; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.Base64Helper; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.User; @@ -139,7 +140,7 @@ public ComplianceConfig getComplianceConfig() { } @Override - public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, RestRequest request) { + public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { if (!checkRestFilter(AuditCategory.FAILED_LOGIN, effectiveUser, request)) { return; @@ -157,7 +158,7 @@ public void logFailedLogin(String effectiveUser, boolean securityadmin, String i } @Override - public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, RestRequest request) { + public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { if (!checkRestFilter(AuditCategory.AUTHENTICATED, effectiveUser, request)) { return; @@ -174,7 +175,7 @@ public void logSucceededLogin(String effectiveUser, boolean securityadmin, Strin } @Override - public void logMissingPrivileges(String privilege, String effectiveUser, RestRequest request) { + public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request) { if (!checkRestFilter(AuditCategory.MISSING_PRIVILEGES, effectiveUser, request)) { return; } @@ -189,7 +190,7 @@ public void logMissingPrivileges(String privilege, String effectiveUser, RestReq } @Override - public void logGrantedPrivileges(String effectiveUser, RestRequest request) { + public void logGrantedPrivileges(String effectiveUser, SecurityRequest request) { if (!checkRestFilter(AuditCategory.GRANTED_PRIVILEGES, effectiveUser, request)) { return; } @@ -348,7 +349,7 @@ public void logBadHeaders(TransportRequest request, String action, Task task) { } @Override - public void logBadHeaders(RestRequest request) { + public void logBadHeaders(SecurityRequest request) { if (!checkRestFilter(AuditCategory.BAD_HEADERS, getUser(), request)) { return; @@ -437,7 +438,7 @@ public void logSSLException(TransportRequest request, Throwable t, String action } @Override - public void logSSLException(RestRequest request, Throwable t) { + public void logSSLException(SecurityRequest request, Throwable t) { if (!checkRestFilter(AuditCategory.SSL_EXCEPTION, getUser(), request)) { return; @@ -896,7 +897,7 @@ private boolean checkComplianceFilter( } @VisibleForTesting - boolean checkRestFilter(final AuditCategory category, final String effectiveUser, RestRequest request) { + boolean checkRestFilter(final AuditCategory category, final String effectiveUser, SecurityRequest request) { final boolean isTraceEnabled = log.isTraceEnabled(); if (isTraceEnabled) { log.trace( diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java index c88f1fca3f..13c137ced7 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java @@ -34,6 +34,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.auditlog.routing.AuditMessageRouter; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportRequest; @@ -131,28 +132,28 @@ protected void save(final AuditMessage msg) { } @Override - public void logFailedLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, RestRequest request) { + public void logFailedLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequest request) { if (enabled) { super.logFailedLogin(effectiveUser, securityAdmin, initiatingUser, request); } } @Override - public void logSucceededLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, RestRequest request) { + public void logSucceededLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequest request) { if (enabled) { super.logSucceededLogin(effectiveUser, securityAdmin, initiatingUser, request); } } @Override - public void logMissingPrivileges(String privilege, String effectiveUser, RestRequest request) { + public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request) { if (enabled) { super.logMissingPrivileges(privilege, effectiveUser, request); } } @Override - public void logGrantedPrivileges(String effectiveUser, RestRequest request) { + public void logGrantedPrivileges(String effectiveUser, SecurityRequest request) { if (enabled) { super.logGrantedPrivileges(effectiveUser, request); } @@ -187,7 +188,7 @@ public void logBadHeaders(TransportRequest request, String action, Task task) { } @Override - public void logBadHeaders(RestRequest request) { + public void logBadHeaders(SecurityRequest request) { if (enabled) { super.logBadHeaders(request); } @@ -208,7 +209,7 @@ public void logSSLException(TransportRequest request, Throwable t, String action } @Override - public void logSSLException(RestRequest request, Throwable t) { + public void logSSLException(SecurityRequest request, Throwable t) { if (enabled) { super.logSSLException(request, t); } diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java index 7c3bf5c77f..9211107d08 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java @@ -48,6 +48,7 @@ import org.opensearch.security.auditlog.AuditLog.Origin; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.dlic.rest.support.Utils; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.support.WildcardMatcher; @@ -369,16 +370,17 @@ void addRestMethod(final RestRequest.Method method) { } } - void addRestRequestInfo(final RestRequest request, final AuditConfig.Filter filter) { + void addRestRequestInfo(final SecurityRequest request, final AuditConfig.Filter filter) { if (request != null) { - final String path = request.path(); + final String path = request.path().toString(); addPath(path); addRestHeaders(request.getHeaders(), filter.shouldExcludeSensitiveHeaders()); addRestParams(request.params()); addRestMethod(request.method()); - if (filter.shouldLogRequestBody() && request.hasContentOrSourceParam()) { + + if (filter.shouldLogRequestBody() && request.asRestRequest().isPresent() && request.asRestRequest().get().hasContentOrSourceParam()) { try { - final Tuple xContentTuple = request.contentOrSourceParam(); + final Tuple xContentTuple = request.asRestRequest().get().contentOrSourceParam(); final String requestBody = XContentHelper.convertToJson(xContentTuple.v2(), false, xContentTuple.v1()); if (path != null && requestBody != null diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index 293f934434..5f0ea37ac3 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -49,6 +49,8 @@ import org.opensearch.security.dlic.rest.validation.EndpointValidator; import org.opensearch.security.dlic.rest.validation.RequestContentValidator; import org.opensearch.security.dlic.rest.validation.ValidationResult; +import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.securityconf.DynamicConfigFactory; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; @@ -535,6 +537,9 @@ public void onFailure(Exception e) { @Override protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + // Fix channel ordering + final SecurityRequest securityRequest = SecurityRequestFactory.from(request, null); + // consume all parameters first so we can return a correct HTTP status, // not 400 consumeParameters(request); @@ -551,12 +556,12 @@ protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClie final String userName = user == null ? null : user.getName(); if (authError != null) { LOGGER.error("No permission to access REST API: " + authError); - securityApiDependencies.auditLog().logMissingPrivileges(authError, userName, request); + securityApiDependencies.auditLog().logMissingPrivileges(authError, userName, securityRequest); // for rest request request.params().clear(); return channel -> forbidden(channel, "No permission to access REST API: " + authError); } else { - securityApiDependencies.auditLog().logGrantedPrivileges(userName, request); + securityApiDependencies.auditLog().logGrantedPrivileges(userName, securityRequest); } final var originalUserAndRemoteAddress = Utils.userAndRemoteAddressFrom(threadPool.getThreadContext()); diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java index 7122dcd2d6..8c06ece226 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -20,7 +20,7 @@ public interface SecurityRequest { public RestChannel getRestChannel(); - public CharSequence path(); + public String path(); public Method method(); @@ -41,7 +41,5 @@ default public String header(final String headerName) { .orElse(null); } - public boolean paramAsBoolean(String string, boolean b); - - public String param(String jwtUrlParameter); + public Map params(); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index c1f165e4be..00bbeeb9dc 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -50,7 +50,7 @@ public RestChannel getRestChannel() { } @Override - public CharSequence path() { + public String path() { return underlyingRequest.path(); } @@ -80,15 +80,9 @@ public Optional asRestRequest() { } @Override - public boolean paramAsBoolean(String string, boolean b) { + public Map params() { // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'paramAsBoolean'"); - } - - @Override - public String param(String jwtUrlParameter) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'param'"); + throw new UnsupportedOperationException("Unimplemented method 'params'"); } } @@ -113,7 +107,7 @@ public RestChannel getRestChannel() { } @Override - public CharSequence path() { + public String path() { // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'path'"); } @@ -149,16 +143,9 @@ public Optional asRestRequest() { } @Override - public boolean paramAsBoolean(String string, boolean b) { + public Map params() { // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'paramAsBoolean'"); + throw new UnsupportedOperationException("Unimplemented method 'params'"); } - - @Override - public String param(String jwtUrlParameter) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'param'"); - } - } } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 38fa009b2f..56ebd7bd49 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -131,13 +131,15 @@ public SecurityRestFilter( public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return (request, channel, client) -> { org.apache.logging.log4j.ThreadContext.clearAll(); - if (!checkAndAuthenticateRequest(SecurityRequestFactory.from(request, channel))) { + final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel); + if (!checkAndAuthenticateRequest(securityRequest)) { User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); boolean isSuperAdminUser = userIsSuperAdmin(user, adminDNs); if (isSuperAdminUser || (whitelistingSettings.checkRequestIsAllowed(request, channel, client) && allowlistingSettings.checkRequestIsAllowed(request, channel, client))) { - if (isSuperAdminUser || authorizeRequest(original, request, channel, user)) { + SecurityRequestFactory.from(request, channel); + if (isSuperAdminUser || authorizeRequest(original, securityRequest, user)) { original.handleRequest(request, channel, client); } } @@ -152,7 +154,7 @@ private boolean userIsSuperAdmin(User user, AdminDNs adminDNs) { return user != null && adminDNs.isAdmin(user); } - private boolean authorizeRequest(RestHandler original, RestRequest request, RestChannel channel, User user) { + private boolean authorizeRequest(RestHandler original, SecurityRequest request, User user) { List restRoutes = original.routes(); Optional handler = restRoutes.stream() @@ -190,7 +192,7 @@ private boolean authorizeRequest(RestHandler original, RestRequest request, Rest err = String.format("no permissions for %s and %s", pres.getMissingPrivileges(), user); } log.debug(err); - channel.sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, err)); + request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, err)); return false; } } diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index 53fe33c9f2..6c4b0fa87c 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -54,7 +54,7 @@ public HTTPBasicAuthenticator(final Settings settings, final Path configPath) { @Override public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) { - final boolean forceLogin = request.paramAsBoolean("force_login", false); + final boolean forceLogin = Boolean.getBoolean(request.params().get("force_login")); if (forceLogin) { return null; diff --git a/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java index 04a30ba2db..a9e35a0d48 100644 --- a/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java @@ -85,7 +85,7 @@ public void testTokenMissing() throws Exception { HTTPJwtAuthenticator jwtAuth = new HTTPJwtAuthenticator(settings, null); Map headers = new HashMap(); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNull(credentials); } @@ -101,7 +101,7 @@ public void testInvalid() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNull(credentials); } @@ -120,7 +120,7 @@ public void testBearer() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNotNull(credentials); Assert.assertEquals("Leonard McCoy", credentials.getUsername()); @@ -139,7 +139,7 @@ public void testBearerWrongPosition() throws Exception { Map headers = new HashMap(); headers.put("Authorization", jwsToken + "Bearer " + " 123"); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNull(credentials); } @@ -152,7 +152,7 @@ public void testBasicAuthHeader() throws Exception { String basicAuth = BaseEncoding.base64().encode("user:password".getBytes(StandardCharsets.UTF_8)); Map headers = Collections.singletonMap(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, Collections.emptyMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, Collections.emptyMap()).asSecurityRequest(), null); Assert.assertNull(credentials); } @@ -261,7 +261,7 @@ public void testUrlParam() throws Exception { FakeRestRequest req = new FakeRestRequest(headers, new HashMap()); req.params().put("abc", jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(req, null); + AuthCredentials credentials = jwtAuth.extractCredentials(req.asSecurityRequest(), null); Assert.assertNotNull(credentials); Assert.assertEquals("Leonard McCoy", credentials.getUsername()); @@ -311,7 +311,7 @@ public void testRS256() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials creds = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials creds = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNotNull(creds); Assert.assertEquals("Leonard McCoy", creds.getUsername()); @@ -334,7 +334,7 @@ public void testES512() throws Exception { Map headers = new HashMap(); headers.put("Authorization", jwsToken); - AuthCredentials creds = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials creds = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNotNull(creds); Assert.assertEquals("Leonard McCoy", creds.getUsername()); @@ -411,7 +411,7 @@ private AuthCredentials extractCredentialsFromJwtHeader(final Settings.Builder s final String jwsToken = jwtBuilder.signWith(secretKey, SignatureAlgorithm.HS512).compact(); final HTTPJwtAuthenticator jwtAuth = new HTTPJwtAuthenticator(settings, null); final Map headers = Map.of("Authorization", jwsToken); - return jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap<>()), null); + return jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap<>()).asSecurityRequest(), null); } } diff --git a/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/HTTPJwtKeyByOpenIdConnectAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/HTTPJwtKeyByOpenIdConnectAuthenticatorTest.java index ccdab8d77a..99d052c5f6 100644 --- a/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/HTTPJwtKeyByOpenIdConnectAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/HTTPJwtKeyByOpenIdConnectAuthenticatorTest.java @@ -52,7 +52,7 @@ public void basicTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()).asSecurityRequest(), null ); @@ -74,7 +74,7 @@ public void jwksUriTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_2), new HashMap<>()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_2), new HashMap<>()).asSecurityRequest(), null ); @@ -95,7 +95,7 @@ public void jwksMissingRequiredIssuerInClaimTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_NO_ISSUER_OCT_1), new HashMap<>()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_NO_ISSUER_OCT_1), new HashMap<>()).asSecurityRequest(), null ); @@ -109,7 +109,7 @@ public void jwksNotMatchingRequiredIssuerInClaimTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_2), new HashMap<>()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_2), new HashMap<>()).asSecurityRequest(), null ); @@ -126,7 +126,7 @@ public void jwksMissingRequiredAudienceInClaimTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_NO_AUDIENCE_OCT_1), new HashMap<>()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_NO_AUDIENCE_OCT_1), new HashMap<>()).asSecurityRequest(), null ); @@ -143,7 +143,7 @@ public void jwksNotMatchingRequiredAudienceInClaimTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_2), new HashMap<>()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_2), new HashMap<>()).asSecurityRequest(), null ); @@ -155,7 +155,7 @@ public void jwksUriMissingTest() { var exception = Assert.assertThrows(Exception.class, () -> { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(Settings.builder().build(), null); jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_1), new HashMap<>()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_1), new HashMap<>()).asSecurityRequest(), null ); }); @@ -178,7 +178,7 @@ public void testEscapeKid() { new FakeRestRequest( ImmutableMap.of("Authorization", "Bearer " + TestJwts.MC_COY_SIGNED_OCT_1_INVALID_KID), new HashMap() - ), + ).asSecurityRequest(), null ); @@ -200,7 +200,7 @@ public void bearerTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", "Bearer " + TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", "Bearer " + TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()).asSecurityRequest(), null ); @@ -223,7 +223,7 @@ public void testRoles() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()).asSecurityRequest(), null ); @@ -242,7 +242,7 @@ public void testExp() throws Exception { new FakeRestRequest( ImmutableMap.of("Authorization", "Bearer " + TestJwts.MC_COY_EXPIRED_SIGNED_OCT_1), new HashMap() - ), + ).asSecurityRequest(), null ); @@ -267,7 +267,7 @@ public void testExpInSkew() throws Exception { new FakeRestRequest( ImmutableMap.of("Authorization", "Bearer " + TestJwts.createMcCoySignedOct1(notBeforeDate, expiringDate)), new HashMap() - ), + ).asSecurityRequest(), null ); @@ -292,7 +292,7 @@ public void testNbf() throws Exception { new FakeRestRequest( ImmutableMap.of("Authorization", "Bearer " + TestJwts.createMcCoySignedOct1(notBeforeDate, expiringDate)), new HashMap() - ), + ).asSecurityRequest(), null ); @@ -317,7 +317,7 @@ public void testNbfInSkew() throws Exception { new FakeRestRequest( ImmutableMap.of("Authorization", "Bearer " + TestJwts.createMcCoySignedOct1(notBeforeDate, expiringDate)), new HashMap() - ), + ).asSecurityRequest(), null ); @@ -336,7 +336,7 @@ public void testRS256() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), null ); @@ -355,7 +355,7 @@ public void testBadSignature() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_X), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_X), new HashMap()).asSecurityRequest(), null ); @@ -376,7 +376,7 @@ public void testPeculiarJsonEscaping() { new FakeRestRequest( ImmutableMap.of("Authorization", TestJwts.PeculiarEscaping.MC_COY_SIGNED_RSA_1), new HashMap() - ), + ).asSecurityRequest(), null ); diff --git a/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/SingleKeyHTTPJwtKeyByOpenIdConnectAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/SingleKeyHTTPJwtKeyByOpenIdConnectAuthenticatorTest.java index a30e43f9fa..9248b2b2bb 100644 --- a/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/SingleKeyHTTPJwtKeyByOpenIdConnectAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/SingleKeyHTTPJwtKeyByOpenIdConnectAuthenticatorTest.java @@ -32,7 +32,7 @@ public void basicTest() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), null ); @@ -58,7 +58,7 @@ public void wrongSigTest() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_X), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_X), new HashMap()).asSecurityRequest(), null ); @@ -80,7 +80,7 @@ public void noAlgTest() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), null ); @@ -105,7 +105,7 @@ public void mismatchedAlgTest() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), null ); @@ -128,7 +128,7 @@ public void keyExchangeTest() throws Exception { try { AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), null ); @@ -139,21 +139,21 @@ public void keyExchangeTest() throws Exception { Assert.assertEquals(4, creds.getAttributes().size()); creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_2), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_2), new HashMap()).asSecurityRequest(), null ); Assert.assertNull(creds); creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_X), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_X), new HashMap()).asSecurityRequest(), null ); Assert.assertNull(creds); creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), null ); @@ -175,7 +175,7 @@ public void keyExchangeTest() throws Exception { try { AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_2), new HashMap()), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_2), new HashMap()).asSecurityRequest(), null ); diff --git a/src/test/java/org/opensearch/security/auditlog/helper/MockRestRequest.java b/src/test/java/org/opensearch/security/auditlog/helper/MockRestRequest.java index 458e240596..2679457864 100644 --- a/src/test/java/org/opensearch/security/auditlog/helper/MockRestRequest.java +++ b/src/test/java/org/opensearch/security/auditlog/helper/MockRestRequest.java @@ -16,6 +16,8 @@ import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestFactory; public class MockRestRequest extends RestRequest { @@ -44,4 +46,8 @@ public boolean hasContent() { public BytesReference content() { return null; } + + public SecurityRequest asSecurityRequest() { + return SecurityRequestFactory.from(this, null); + } } diff --git a/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java b/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java index bbdbc3aefd..a9f58f682e 100644 --- a/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java +++ b/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java @@ -25,6 +25,7 @@ import org.opensearch.security.auditlog.AuditTestUtils; import org.opensearch.security.auditlog.helper.RetrySink; import org.opensearch.security.auditlog.integration.TestAuditlogImpl; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.test.AbstractSecurityUnitTest; import org.opensearch.transport.TransportRequest; @@ -132,7 +133,7 @@ public void testRestFilterEnabledCheck() { final Settings settings = Settings.builder().put(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_ENABLE_REST, false).build(); final AbstractAuditLog al = AuditTestUtils.createAuditLog(settings, null, null, AbstractSecurityUnitTest.MOCK_POOL, null, cs); for (AuditCategory category : AuditCategory.values()) { - Assert.assertFalse(al.checkRestFilter(category, "user", mock(RestRequest.class))); + Assert.assertFalse(al.checkRestFilter(category, "user", mock(SecurityRequest.class))); } } diff --git a/src/test/java/org/opensearch/security/auditlog/impl/DisabledCategoriesTest.java b/src/test/java/org/opensearch/security/auditlog/impl/DisabledCategoriesTest.java index 0d08abaeea..5cd12d97d8 100644 --- a/src/test/java/org/opensearch/security/auditlog/impl/DisabledCategoriesTest.java +++ b/src/test/java/org/opensearch/security/auditlog/impl/DisabledCategoriesTest.java @@ -227,11 +227,11 @@ protected void logAll(AuditLog auditLog) { } protected void logRestSucceededLogin(AuditLog auditLog) { - auditLog.logSucceededLogin("testuser.rest.succeededlogin", false, "testuser.rest.succeededlogin", new MockRestRequest()); + auditLog.logSucceededLogin("testuser.rest.succeededlogin", false, "testuser.rest.succeededlogin", new MockRestRequest().asSecurityRequest()); } protected void logRestFailedLogin(AuditLog auditLog) { - auditLog.logFailedLogin("testuser.rest.failedlogin", false, "testuser.rest.failedlogin", new MockRestRequest()); + auditLog.logFailedLogin("testuser.rest.failedlogin", false, "testuser.rest.failedlogin", new MockRestRequest().asSecurityRequest()); } protected void logMissingPrivileges(AuditLog auditLog) { @@ -243,7 +243,7 @@ protected void logTransportBadHeaders(AuditLog auditLog) { } protected void logRestBadHeaders(AuditLog auditLog) { - auditLog.logBadHeaders(new MockRestRequest()); + auditLog.logBadHeaders(new MockRestRequest().asSecurityRequest()); } protected void logSecurityIndexAttempt(AuditLog auditLog) { @@ -251,7 +251,7 @@ protected void logSecurityIndexAttempt(AuditLog auditLog) { } protected void logRestSSLException(AuditLog auditLog) { - auditLog.logSSLException(new MockRestRequest(), new Exception()); + auditLog.logSSLException(new MockRestRequest().asSecurityRequest(), new Exception()); } protected void logTransportSSLException(AuditLog auditLog) { diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluatorTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluatorTest.java index bbe1bf90f8..004db5e91a 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluatorTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluatorTest.java @@ -20,6 +20,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.rest.RestRequest; import org.opensearch.security.configuration.AdminDNs; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.privileges.PrivilegesEvaluator; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.threadpool.ThreadPool; diff --git a/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java b/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java index fbb03bf7c3..b8bda3468f 100644 --- a/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java +++ b/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java @@ -95,7 +95,7 @@ public void testTokenMissing() throws Exception { OnBehalfOfAuthenticator jwtAuth = new OnBehalfOfAuthenticator(defaultSettings(), clusterName); Map headers = new HashMap(); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNull(credentials); } @@ -109,7 +109,7 @@ public void testInvalid() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNull(credentials); } @@ -126,7 +126,7 @@ public void testDisabled() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNull(credentials); } @@ -143,7 +143,7 @@ public void testNonSpecifyOBOSetting() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNotNull(credentials); } @@ -165,7 +165,7 @@ public void testBearer() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNotNull(credentials); Assert.assertEquals("Leonard McCoy", credentials.getUsername()); @@ -188,7 +188,7 @@ public void testBearerWrongPosition() throws Exception { Map headers = new HashMap(); headers.put("Authorization", jwsToken + "Bearer " + " 123"); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNull(credentials); } @@ -205,7 +205,7 @@ public void testBasicAuthHeader() throws Exception { Map headers = Collections.singletonMap(HttpHeaders.AUTHORIZATION, "Basic " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, Collections.emptyMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, Collections.emptyMap()).asSecurityRequest(), null); Assert.assertNull(credentials); } @@ -349,7 +349,7 @@ public void testDifferentIssuer() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()), null); + AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); Assert.assertNull(credentials); } @@ -375,7 +375,7 @@ private AuthCredentials extractCredentialsFromJwtHeader( SignatureAlgorithm.HS512 ).compact(); final Map headers = Map.of("Authorization", "Bearer " + jwsToken); - return jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap<>()), null); + return jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap<>()).asSecurityRequest(), null); } private Settings defaultSettings() { diff --git a/src/test/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticatorTest.java b/src/test/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticatorTest.java index d3bf10d943..5a71c7ff7e 100644 --- a/src/test/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticatorTest.java +++ b/src/test/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticatorTest.java @@ -47,6 +47,8 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; import org.opensearch.core.rest.RestStatus; +import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -77,19 +79,19 @@ public void testGetType() { @Test(expected = OpenSearchSecurityException.class) public void testThrowsExceptionWhenMissingXFFDone() { authenticator = new HTTPExtendedProxyAuthenticator(Settings.EMPTY, null); - authenticator.extractCredentials(new TestRestRequest(), new ThreadContext(Settings.EMPTY)); + authenticator.extractCredentials(new TestRestRequest().asSecurityRequest(), new ThreadContext(Settings.EMPTY)); } @Test public void testReturnsNullWhenUserHeaderIsUnconfigured() { authenticator = new HTTPExtendedProxyAuthenticator(Settings.EMPTY, null); - assertNull(authenticator.extractCredentials(new TestRestRequest(), context)); + assertNull(authenticator.extractCredentials(new TestRestRequest().asSecurityRequest(), context)); } @Test public void testReturnsNullWhenUserHeaderIsMissing() { - assertNull(authenticator.extractCredentials(new TestRestRequest(), context)); + assertNull(authenticator.extractCredentials(new TestRestRequest().asSecurityRequest(), context)); } @Test @@ -105,7 +107,7 @@ public void testReturnsCredentials() { settings = Settings.builder().put(settings).put("attr_header_prefix", "proxy_").build(); authenticator = new HTTPExtendedProxyAuthenticator(settings, null); - AuthCredentials creds = authenticator.extractCredentials(new TestRestRequest(headers), context); + AuthCredentials creds = authenticator.extractCredentials(new TestRestRequest(headers).asSecurityRequest(), context); assertNotNull(creds); assertEquals("aValidUser", creds.getUsername()); assertEquals("123,456", creds.getAttributes().get("attr.proxy.uid")); @@ -122,7 +124,7 @@ public void testTrimOnRoles() { settings = Settings.builder().put(settings).put("roles_header", "roles").put("roles_separator", ",").build(); authenticator = new HTTPExtendedProxyAuthenticator(settings, null); - AuthCredentials creds = authenticator.extractCredentials(new TestRestRequest(headers), context); + AuthCredentials creds = authenticator.extractCredentials(new TestRestRequest(headers).asSecurityRequest(), context); assertNotNull(creds); assertEquals("aValidUser", creds.getUsername()); assertEquals(ImmutableSet.of("role1", "role2"), creds.getBackendRoles()); @@ -163,6 +165,9 @@ public boolean hasContent() { return false; } + public SecurityRequest asSecurityRequest() { + return SecurityRequestFactory.from(this, null); + } } static class HttpRequestImpl implements HttpRequest { diff --git a/src/test/java/org/opensearch/security/util/FakeRestRequest.java b/src/test/java/org/opensearch/security/util/FakeRestRequest.java index f8d8aca508..db7538bcdb 100644 --- a/src/test/java/org/opensearch/security/util/FakeRestRequest.java +++ b/src/test/java/org/opensearch/security/util/FakeRestRequest.java @@ -18,6 +18,8 @@ import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestFactory; public class FakeRestRequest extends RestRequest { @@ -117,4 +119,7 @@ private static Map> convert(Map headers) { return ret; } + public SecurityRequest asSecurityRequest() { + return SecurityRequestFactory.from(this, null); + } } From a825d83a3a163583349673d9a17b43ef46fa5cef Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Fri, 29 Sep 2023 17:35:35 +0000 Subject: [PATCH 05/50] Prevent build break for generalized testing associated with SecurityRequest Signed-off-by: Peter Nied --- .../security/http/SecurityNonSslHttpServerTransport.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java b/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java index 467d25b16a..d9edb74f4f 100644 --- a/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java +++ b/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java @@ -72,10 +72,11 @@ public ChannelHandler configureServerChannelHandler() { return new NonSslHttpChannelHandler(this, handlingSettings); } - @Override - protected ChannelInboundHandlerAdapter createHeaderVerifier() { - return new AuthenicationVerifier(); - } + // TODO: Disabled for confirming refactor around SecurityRequest is working as expected + // @Override + // protected ChannelInboundHandlerAdapter createHeaderVerifier() { + // return new AuthenicationVerifier(); + // } protected class NonSslHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler { From 095d4e5075975943ee1c40c879d360a2d8a6a66a Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Fri, 29 Sep 2023 17:57:40 +0000 Subject: [PATCH 06/50] Spotless Signed-off-by: Peter Nied --- .../jwt/AbstractHTTPJwtAuthenticator.java | 4 +- .../auth/http/jwt/HTTPJwtAuthenticator.java | 4 +- .../kerberos/HTTPSpnegoAuthenticator.java | 1 - .../auth/http/saml/HTTPSamlAuthenticator.java | 3 +- .../security/auditlog/AuditLog.java | 1 - .../auditlog/AuditLogSslExceptionHandler.java | 1 - .../security/auditlog/NullAuditLog.java | 1 - .../auditlog/impl/AbstractAuditLog.java | 1 - .../security/auditlog/impl/AuditLogImpl.java | 1 - .../security/auditlog/impl/AuditMessage.java | 4 +- .../security/auth/BackendRegistry.java | 30 ++++++-------- .../security/auth/UserInjector.java | 1 - .../security/filter/SecurityRequest.java | 6 +-- .../filter/SecurityRequestFactory.java | 4 +- .../security/filter/SecurityRestFilter.java | 1 - .../security/http/AuthenicationVerifier.java | 6 +-- .../security/http/HTTPBasicAuthenticator.java | 1 - .../http/HTTPClientCertAuthenticator.java | 1 - .../security/http/HTTPProxyAuthenticator.java | 1 - .../http/OnBehalfOfAuthenticator.java | 3 +- .../security/http/RemoteIpDetector.java | 3 +- .../SecurityNonSslHttpServerTransport.java | 4 +- .../opensearch/security/http/XFFResolver.java | 7 +--- .../proxy/HTTPExtendedProxyAuthenticator.java | 1 - .../security/rest/SecurityWhoAmIAction.java | 3 +- .../SecuritySSLNettyHttpServerTransport.java | 1 - .../ssl/rest/SecuritySSLInfoAction.java | 3 +- .../security/ssl/util/SSLRequestHelper.java | 3 -- .../security/support/HTTPHelper.java | 1 - .../http/jwt/HTTPJwtAuthenticatorTest.java | 35 ++++++++++++---- ...wtKeyByOpenIdConnectAuthenticatorTest.java | 21 ++++++---- ...wtKeyByOpenIdConnectAuthenticatorTest.java | 27 ++++++++----- .../security/auditlog/impl/AuditlogTest.java | 1 - .../auditlog/impl/DisabledCategoriesTest.java | 7 +++- .../cache/DummyHTTPAuthenticator.java | 4 +- .../api/RestApiPrivilegesEvaluatorTest.java | 1 - .../http/OnBehalfOfAuthenticatorTest.java | 40 +++++++++++++++---- 37 files changed, 133 insertions(+), 104 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java index 69fb4515d8..33a031a228 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java @@ -37,7 +37,6 @@ import org.opensearch.core.common.Strings; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; @@ -84,7 +83,8 @@ public AbstractHTTPJwtAuthenticator(Settings settings, Path configPath) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) + throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java index 28e831c70b..2b13dea63e 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java @@ -32,7 +32,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; @@ -85,7 +84,8 @@ public HTTPJwtAuthenticator(final Settings settings, final Path configPath) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) + throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { diff --git a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java index 4aa2a6c8d5..af822e9c43 100644 --- a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java @@ -50,7 +50,6 @@ import org.opensearch.env.Environment; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; 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 f23042febc..27a7dd10f7 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 @@ -150,7 +150,8 @@ public HTTPSamlAuthenticator(final Settings settings, final Path configPath) { } @Override - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) throws OpenSearchSecurityException { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) + throws OpenSearchSecurityException { Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; if (API_AUTHTOKEN_SUFFIX.equals(suffix)) { diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLog.java b/src/main/java/org/opensearch/security/auditlog/AuditLog.java index d6c182eada..997b9e4b87 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLog.java @@ -35,7 +35,6 @@ import org.opensearch.index.engine.Engine.IndexResult; import org.opensearch.index.get.GetResult; import org.opensearch.core.index.shard.ShardId; -import org.opensearch.rest.RestRequest; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; import org.opensearch.security.filter.SecurityRequest; diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java b/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java index 4d535856e8..a794be3a2c 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java @@ -27,7 +27,6 @@ package org.opensearch.security.auditlog; import org.opensearch.OpenSearchException; -import org.opensearch.rest.RestRequest; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.ssl.SslExceptionHandler; import org.opensearch.tasks.Task; diff --git a/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java b/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java index a4d5a969c1..1ac4492a94 100644 --- a/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java @@ -35,7 +35,6 @@ import org.opensearch.index.engine.Engine.IndexResult; import org.opensearch.index.get.GetResult; import org.opensearch.core.index.shard.ShardId; -import org.opensearch.rest.RestRequest; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; import org.opensearch.security.filter.SecurityRequest; diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java index c6752be8b2..2813f82e98 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java @@ -60,7 +60,6 @@ import org.opensearch.index.engine.Engine.IndexResult; import org.opensearch.index.get.GetResult; import org.opensearch.core.index.shard.ShardId; -import org.opensearch.rest.RestRequest; import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.auditlog.config.AuditConfig; diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java index 13c137ced7..8da4b13d4c 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java @@ -31,7 +31,6 @@ import org.opensearch.index.engine.Engine.IndexResult; import org.opensearch.index.get.GetResult; import org.opensearch.core.index.shard.ShardId; -import org.opensearch.rest.RestRequest; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.auditlog.routing.AuditMessageRouter; import org.opensearch.security.filter.SecurityRequest; diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java index 9211107d08..b4f35ef90f 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java @@ -378,7 +378,9 @@ void addRestRequestInfo(final SecurityRequest request, final AuditConfig.Filter addRestParams(request.params()); addRestMethod(request.method()); - if (filter.shouldLogRequestBody() && request.asRestRequest().isPresent() && request.asRestRequest().get().hasContentOrSourceParam()) { + if (filter.shouldLogRequestBody() + && request.asRestRequest().isPresent() + && request.asRestRequest().get().hasContentOrSourceParam()) { try { final Tuple xContentTuple = request.asRestRequest().get().contentOrSourceParam(); final String requestBody = XContentHelper.convertToJson(xContentTuple.v2(), false, xContentTuple.v1()); diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 50c2bb2354..cdfa74655c 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -52,8 +52,6 @@ import org.opensearch.core.common.transport.TransportAddress; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.auth.blocking.ClientBlockRegistry; @@ -218,7 +216,8 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); - request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.SERVICE_UNAVAILABLE, "OpenSearch Security not initialized.")); + request.getRestChannel() + .sendResponse(new BytesRestResponse(RestStatus.SERVICE_UNAVAILABLE, "OpenSearch Security not initialized.")); return false; } @@ -340,12 +339,13 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ if (adminDns.isAdmin(authenticatedUser)) { log.error("Cannot authenticate rest user because admin user is not permitted to login via HTTP"); auditLog.logFailedLogin(authenticatedUser.getName(), true, null, request); - request.getRestChannel().sendResponse( - new BytesRestResponse( - RestStatus.FORBIDDEN, - "Cannot authenticate user because admin user is not permitted to login via HTTP" - ) - ); + request.getRestChannel() + .sendResponse( + new BytesRestResponse( + RestStatus.FORBIDDEN, + "Cannot authenticate user because admin user is not permitted to login via HTTP" + ) + ); return false; } @@ -363,10 +363,8 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ if (authenticated) { final User impersonatedUser = impersonate(request, authenticatedUser); - threadPool.getThreadContext().putTransient( - ConfigConstants.OPENDISTRO_SECURITY_USER, - impersonatedUser == null ? authenticatedUser : impersonatedUser - ); + threadPool.getThreadContext() + .putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, impersonatedUser == null ? authenticatedUser : impersonatedUser); auditLog.logSucceededLogin( (impersonatedUser == null ? authenticatedUser : impersonatedUser).getName(), false, @@ -429,11 +427,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ } private void notifyIpAuthFailureListeners(SecurityRequest request, AuthCredentials authCredentials) { - notifyIpAuthFailureListeners( - request.getRemoteAddress().map(InetSocketAddress::getAddress).orElse(null), - authCredentials, - request - ); + notifyIpAuthFailureListeners(request.getRemoteAddress().map(InetSocketAddress::getAddress).orElse(null), authCredentials, request); } private void notifyIpAuthFailureListeners(InetAddress remoteAddress, AuthCredentials authCredentials, Object request) { diff --git a/src/main/java/org/opensearch/security/auth/UserInjector.java b/src/main/java/org/opensearch/security/auth/UserInjector.java index f724578323..79b84fe237 100644 --- a/src/main/java/org/opensearch/security/auth/UserInjector.java +++ b/src/main/java/org/opensearch/security/auth/UserInjector.java @@ -38,7 +38,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.common.transport.TransportAddress; -import org.opensearch.rest.RestRequest; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.http.XFFResolver; diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java index 8c06ece226..69d2e0be4d 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -34,11 +34,7 @@ public interface SecurityRequest { default public String header(final String headerName) { final Optional>> headersMap = Optional.ofNullable(getHeaders()); - return headersMap - .map(headers -> headers.get(headerName)) - .map(List::stream) - .flatMap(Stream::findFirst) - .orElse(null); + return headersMap.map(headers -> headers.get(headerName)).map(List::stream).flatMap(Stream::findFirst).orElse(null); } public Map params(); diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index 00bbeeb9dc..bdc391ec7f 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -12,8 +12,6 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; -import io.netty.handler.codec.http.HttpRequest; - public class SecurityRequestFactory { public static SecurityRequest from() { @@ -27,6 +25,7 @@ public static SecurityRequest from(final RestRequest request, final RestChannel protected static class SecurityRestRequest implements SecurityRequest { private final RestRequest underlyingRequest; private final RestChannel underlyingChannel; + SecurityRestRequest(final RestRequest request, final RestChannel channel) { underlyingRequest = request; underlyingChannel = channel; @@ -86,7 +85,6 @@ public Map params() { } } - protected static class NettyRequest implements SecurityRequest { @Override public Map> getHeaders() { diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 56ebd7bd49..52119e3c5c 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -46,7 +46,6 @@ import org.opensearch.rest.NamedRoute; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestHandler; -import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auditlog.AuditLog; diff --git a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java index af1f281187..9acbfb5141 100644 --- a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java +++ b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java @@ -25,9 +25,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception HttpRequest request = (HttpRequest) msg; if (!isAuthenticated(request)) { - final FullHttpResponse response = new DefaultFullHttpResponse( - HttpVersion.HTTP_1_1, - HttpResponseStatus.UNAUTHORIZED); + final FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.UNAUTHORIZED); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); ReferenceCountUtil.release(msg); } else { @@ -38,8 +36,6 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception private boolean isAuthenticated(HttpRequest request) { - - log.info("Checking if request is authenticated:\n" + request); final boolean shouldBlock = request.headers().contains("blockme"); diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index 6c4b0fa87c..ae393e5028 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -35,7 +35,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; diff --git a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java index fb34162827..03221e810b 100644 --- a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java @@ -42,7 +42,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.ConfigConstants; diff --git a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java index ad6d4a1608..d835a6a081 100644 --- a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java @@ -38,7 +38,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.ConfigConstants; diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java index a4699412b9..2a47853ec2 100644 --- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java @@ -122,7 +122,8 @@ private String[] extractBackendRolesFromClaims(Claims claims) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) + throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { diff --git a/src/main/java/org/opensearch/security/http/RemoteIpDetector.java b/src/main/java/org/opensearch/security/http/RemoteIpDetector.java index f38e66362c..7b76a82c42 100644 --- a/src/main/java/org/opensearch/security/http/RemoteIpDetector.java +++ b/src/main/java/org/opensearch/security/http/RemoteIpDetector.java @@ -53,7 +53,6 @@ import org.apache.logging.log4j.Logger; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.RestRequest; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.ConfigConstants; @@ -118,7 +117,7 @@ public String getRemoteIpHeader() { } String detect(SecurityRequest request, ThreadContext threadContext) { - + final String originalRemoteAddr = request.getRemoteAddress() .map(InetSocketAddress::getAddress) .map(InetAddress::getHostAddress) diff --git a/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java b/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java index d9edb74f4f..72fd5bf61d 100644 --- a/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java +++ b/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java @@ -28,7 +28,6 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelInboundHandlerAdapter; import org.opensearch.common.network.NetworkService; import org.opensearch.common.settings.ClusterSettings; @@ -75,7 +74,7 @@ public ChannelHandler configureServerChannelHandler() { // TODO: Disabled for confirming refactor around SecurityRequest is working as expected // @Override // protected ChannelInboundHandlerAdapter createHeaderVerifier() { - // return new AuthenicationVerifier(); + // return new AuthenicationVerifier(); // } protected class NonSslHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler { @@ -90,5 +89,4 @@ protected void initChannel(Channel ch) throws Exception { } } - } diff --git a/src/main/java/org/opensearch/security/http/XFFResolver.java b/src/main/java/org/opensearch/security/http/XFFResolver.java index 7a81aea8f7..68fe0307cd 100644 --- a/src/main/java/org/opensearch/security/http/XFFResolver.java +++ b/src/main/java/org/opensearch/security/http/XFFResolver.java @@ -35,8 +35,6 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.core.common.transport.TransportAddress; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.http.netty4.Netty4HttpChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.securityconf.DynamicConfigModel; import org.opensearch.security.support.ConfigConstants; @@ -62,10 +60,7 @@ public TransportAddress resolve(final SecurityRequest request) throws OpenSearch if (enabled && request.getRemoteAddress().isPresent() && request.sourcedFromNetty()) { final InetSocketAddress remoteAddress = request.getRemoteAddress().get(); - final InetSocketAddress isa = new InetSocketAddress( - detector.detect(request, threadContext), - remoteAddress.getPort() - ); + final InetSocketAddress isa = new InetSocketAddress(detector.detect(request, threadContext), remoteAddress.getPort()); if (isa.isUnresolved()) { throw new OpenSearchSecurityException("Cannot resolve address " + isa.getHostString()); diff --git a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java index d2dd692184..4231bf6c57 100644 --- a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java @@ -38,7 +38,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.http.HTTPProxyAuthenticator; import org.opensearch.security.user.AuthCredentials; diff --git a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java index e4f0fb6d06..a7f92f306b 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java @@ -99,7 +99,8 @@ public void accept(RestChannel channel) throws Exception { BytesRestResponse response = null; try { - final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel);; + final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel); + ; SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { diff --git a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java index bf87cc9bd6..f7aaabe1f6 100644 --- a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java +++ b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java @@ -157,5 +157,4 @@ protected void configurePipeline(Channel ch) { } } - } diff --git a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java index a3bed2674d..982fea2d5d 100644 --- a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java +++ b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java @@ -86,7 +86,8 @@ public void accept(RestChannel channel) throws Exception { BytesRestResponse response = null; try { - final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel);; + final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel); + ; SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); X509Certificate[] certs = sslInfo == null ? null : sslInfo.getX509Certs(); X509Certificate[] localCerts = sslInfo == null ? null : sslInfo.getLocalCertificates(); diff --git a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java index d841ec228d..78b7138d09 100644 --- a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java +++ b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java @@ -36,7 +36,6 @@ import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; -import io.netty.handler.ssl.SslHandler; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -45,8 +44,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.env.Environment; -import org.opensearch.http.netty4.Netty4HttpChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.transport.PrincipalExtractor.Type; diff --git a/src/main/java/org/opensearch/security/support/HTTPHelper.java b/src/main/java/org/opensearch/security/support/HTTPHelper.java index c9672bb97f..10763ce35b 100644 --- a/src/main/java/org/opensearch/security/support/HTTPHelper.java +++ b/src/main/java/org/opensearch/security/support/HTTPHelper.java @@ -33,7 +33,6 @@ import org.apache.logging.log4j.Logger; -import org.opensearch.rest.RestRequest; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; diff --git a/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java index a9e35a0d48..4a28c0a752 100644 --- a/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java @@ -85,7 +85,10 @@ public void testTokenMissing() throws Exception { HTTPJwtAuthenticator jwtAuth = new HTTPJwtAuthenticator(settings, null); Map headers = new HashMap(); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNull(credentials); } @@ -101,7 +104,10 @@ public void testInvalid() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNull(credentials); } @@ -120,7 +126,10 @@ public void testBearer() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNotNull(credentials); Assert.assertEquals("Leonard McCoy", credentials.getUsername()); @@ -139,7 +148,10 @@ public void testBearerWrongPosition() throws Exception { Map headers = new HashMap(); headers.put("Authorization", jwsToken + "Bearer " + " 123"); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNull(credentials); } @@ -152,7 +164,10 @@ public void testBasicAuthHeader() throws Exception { String basicAuth = BaseEncoding.base64().encode("user:password".getBytes(StandardCharsets.UTF_8)); Map headers = Collections.singletonMap(HttpHeaders.AUTHORIZATION, "Basic " + basicAuth); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, Collections.emptyMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, Collections.emptyMap()).asSecurityRequest(), + null + ); Assert.assertNull(credentials); } @@ -311,7 +326,10 @@ public void testRS256() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials creds = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials creds = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNotNull(creds); Assert.assertEquals("Leonard McCoy", creds.getUsername()); @@ -334,7 +352,10 @@ public void testES512() throws Exception { Map headers = new HashMap(); headers.put("Authorization", jwsToken); - AuthCredentials creds = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials creds = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNotNull(creds); Assert.assertEquals("Leonard McCoy", creds.getUsername()); diff --git a/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/HTTPJwtKeyByOpenIdConnectAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/HTTPJwtKeyByOpenIdConnectAuthenticatorTest.java index 99d052c5f6..d483a2ec81 100644 --- a/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/HTTPJwtKeyByOpenIdConnectAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/HTTPJwtKeyByOpenIdConnectAuthenticatorTest.java @@ -52,7 +52,8 @@ public void basicTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()) + .asSecurityRequest(), null ); @@ -95,7 +96,8 @@ public void jwksMissingRequiredIssuerInClaimTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_NO_ISSUER_OCT_1), new HashMap<>()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_NO_ISSUER_OCT_1), new HashMap<>()) + .asSecurityRequest(), null ); @@ -126,7 +128,8 @@ public void jwksMissingRequiredAudienceInClaimTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_NO_AUDIENCE_OCT_1), new HashMap<>()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_NO_AUDIENCE_OCT_1), new HashMap<>()) + .asSecurityRequest(), null ); @@ -200,7 +203,8 @@ public void bearerTest() { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", "Bearer " + TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", "Bearer " + TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()) + .asSecurityRequest(), null ); @@ -223,7 +227,8 @@ public void testRoles() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_OCT_1), new HashMap()) + .asSecurityRequest(), null ); @@ -336,7 +341,8 @@ public void testRS256() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()) + .asSecurityRequest(), null ); @@ -355,7 +361,8 @@ public void testBadSignature() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_X), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_X), new HashMap()) + .asSecurityRequest(), null ); diff --git a/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/SingleKeyHTTPJwtKeyByOpenIdConnectAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/SingleKeyHTTPJwtKeyByOpenIdConnectAuthenticatorTest.java index 9248b2b2bb..6b5c541981 100644 --- a/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/SingleKeyHTTPJwtKeyByOpenIdConnectAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/jwt/keybyoidc/SingleKeyHTTPJwtKeyByOpenIdConnectAuthenticatorTest.java @@ -32,7 +32,8 @@ public void basicTest() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()) + .asSecurityRequest(), null ); @@ -58,7 +59,8 @@ public void wrongSigTest() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_X), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_X), new HashMap()) + .asSecurityRequest(), null ); @@ -80,7 +82,8 @@ public void noAlgTest() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.MC_COY_SIGNED_RSA_1), new HashMap()) + .asSecurityRequest(), null ); @@ -105,7 +108,8 @@ public void mismatchedAlgTest() throws Exception { HTTPJwtKeyByOpenIdConnectAuthenticator jwtAuth = new HTTPJwtKeyByOpenIdConnectAuthenticator(settings, null); AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()) + .asSecurityRequest(), null ); @@ -128,7 +132,8 @@ public void keyExchangeTest() throws Exception { try { AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()) + .asSecurityRequest(), null ); @@ -139,21 +144,24 @@ public void keyExchangeTest() throws Exception { Assert.assertEquals(4, creds.getAttributes().size()); creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_2), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_2), new HashMap()) + .asSecurityRequest(), null ); Assert.assertNull(creds); creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_X), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_X), new HashMap()) + .asSecurityRequest(), null ); Assert.assertNull(creds); creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_1), new HashMap()) + .asSecurityRequest(), null ); @@ -175,7 +183,8 @@ public void keyExchangeTest() throws Exception { try { AuthCredentials creds = jwtAuth.extractCredentials( - new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_2), new HashMap()).asSecurityRequest(), + new FakeRestRequest(ImmutableMap.of("Authorization", TestJwts.NoKid.MC_COY_SIGNED_RSA_2), new HashMap()) + .asSecurityRequest(), null ); diff --git a/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java b/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java index a9f58f682e..1d31d3c425 100644 --- a/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java +++ b/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java @@ -21,7 +21,6 @@ import org.opensearch.cluster.node.DiscoveryNode; import org.opensearch.cluster.service.ClusterService; import org.opensearch.common.settings.Settings; -import org.opensearch.rest.RestRequest; import org.opensearch.security.auditlog.AuditTestUtils; import org.opensearch.security.auditlog.helper.RetrySink; import org.opensearch.security.auditlog.integration.TestAuditlogImpl; diff --git a/src/test/java/org/opensearch/security/auditlog/impl/DisabledCategoriesTest.java b/src/test/java/org/opensearch/security/auditlog/impl/DisabledCategoriesTest.java index 5cd12d97d8..ba4ee7b55d 100644 --- a/src/test/java/org/opensearch/security/auditlog/impl/DisabledCategoriesTest.java +++ b/src/test/java/org/opensearch/security/auditlog/impl/DisabledCategoriesTest.java @@ -227,7 +227,12 @@ protected void logAll(AuditLog auditLog) { } protected void logRestSucceededLogin(AuditLog auditLog) { - auditLog.logSucceededLogin("testuser.rest.succeededlogin", false, "testuser.rest.succeededlogin", new MockRestRequest().asSecurityRequest()); + auditLog.logSucceededLogin( + "testuser.rest.succeededlogin", + false, + "testuser.rest.succeededlogin", + new MockRestRequest().asSecurityRequest() + ); } protected void logRestFailedLogin(AuditLog auditLog) { diff --git a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java index aa9c9106ea..5651b25e8b 100644 --- a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java +++ b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java @@ -17,7 +17,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; @@ -34,7 +33,8 @@ public String getType() { } @Override - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) + throws OpenSearchSecurityException { count++; return new AuthCredentials("dummy").markComplete(); } diff --git a/src/test/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluatorTest.java b/src/test/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluatorTest.java index 004db5e91a..bbe1bf90f8 100644 --- a/src/test/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluatorTest.java +++ b/src/test/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluatorTest.java @@ -20,7 +20,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.rest.RestRequest; import org.opensearch.security.configuration.AdminDNs; -import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.privileges.PrivilegesEvaluator; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.threadpool.ThreadPool; diff --git a/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java b/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java index b8bda3468f..1ff6adee3a 100644 --- a/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java +++ b/src/test/java/org/opensearch/security/http/OnBehalfOfAuthenticatorTest.java @@ -95,7 +95,10 @@ public void testTokenMissing() throws Exception { OnBehalfOfAuthenticator jwtAuth = new OnBehalfOfAuthenticator(defaultSettings(), clusterName); Map headers = new HashMap(); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNull(credentials); } @@ -109,7 +112,10 @@ public void testInvalid() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNull(credentials); } @@ -126,7 +132,10 @@ public void testDisabled() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNull(credentials); } @@ -143,7 +152,10 @@ public void testNonSpecifyOBOSetting() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNotNull(credentials); } @@ -165,7 +177,10 @@ public void testBearer() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNotNull(credentials); Assert.assertEquals("Leonard McCoy", credentials.getUsername()); @@ -188,7 +203,10 @@ public void testBearerWrongPosition() throws Exception { Map headers = new HashMap(); headers.put("Authorization", jwsToken + "Bearer " + " 123"); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNull(credentials); } @@ -205,7 +223,10 @@ public void testBasicAuthHeader() throws Exception { Map headers = Collections.singletonMap(HttpHeaders.AUTHORIZATION, "Basic " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, Collections.emptyMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, Collections.emptyMap()).asSecurityRequest(), + null + ); Assert.assertNull(credentials); } @@ -349,7 +370,10 @@ public void testDifferentIssuer() throws Exception { Map headers = new HashMap(); headers.put("Authorization", "Bearer " + jwsToken); - AuthCredentials credentials = jwtAuth.extractCredentials(new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), null); + AuthCredentials credentials = jwtAuth.extractCredentials( + new FakeRestRequest(headers, new HashMap()).asSecurityRequest(), + null + ); Assert.assertNull(credentials); } From 6580e7f41288af6bba9030bf94e1ed4da388d3ad Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Fri, 29 Sep 2023 20:21:20 +0000 Subject: [PATCH 07/50] Disable createHeaderVerifier so builds can pass Signed-off-by: Peter Nied --- .../http/netty/SecuritySSLNettyHttpServerTransport.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java index f7aaabe1f6..3f5f7198fd 100644 --- a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java +++ b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java @@ -96,10 +96,11 @@ public void onException(HttpChannel channel, Exception cause0) { super.onException(channel, cause0); } - @Override - protected ChannelInboundHandlerAdapter createHeaderVerifier() { - return new AuthenicationVerifier(); - } + // TODO: Disable since changes in core aren't avaliable yet + // @Override + // protected ChannelInboundHandlerAdapter createHeaderVerifier() { + // return new AuthenicationVerifier(); + // } protected class SSLHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler { /** From 8c44278f296605beda65cfcb84154d0fff3246c8 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Fri, 29 Sep 2023 22:06:20 +0000 Subject: [PATCH 08/50] Implement SecurityRequest gaps Signed-off-by: Peter Nied --- .../security/filter/SecurityRequestFactory.java | 17 +++++++++++++---- .../security/ssl/util/SSLRequestHelper.java | 4 ++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index bdc391ec7f..36f3399e26 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -12,6 +12,8 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; +import io.netty.handler.ssl.SslHandler; + public class SecurityRequestFactory { public static SecurityRequest from() { @@ -38,9 +40,17 @@ public Map> getHeaders() { @Override public SSLEngine getSSLEngine() { - // TODO: this doesn't seem properly handled + if (underlyingRequest == null || underlyingRequest.getHttpChannel() == null || !(underlyingRequest.getHttpChannel() instanceof Netty4HttpChannel)) { + return null; + } - throw new UnsupportedOperationException("Unimplemented method 'getSSLEngine'"); + final Netty4HttpChannel httpChannel = (Netty4HttpChannel) underlyingRequest.getHttpChannel(); + SslHandler sslhandler = (SslHandler) httpChannel.getNettyChannel().pipeline().get("ssl_http"); + if (sslhandler == null && httpChannel.inboundPipeline() != null) { + sslhandler = (SslHandler) httpChannel.inboundPipeline().get("ssl_http"); + } + + return sslhandler != null ? sslhandler.engine() : null; } @Override @@ -80,8 +90,7 @@ public Optional asRestRequest() { @Override public Map params() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'params'"); + return underlyingRequest.params(); } } diff --git a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java index 78b7138d09..df92bfc703 100644 --- a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java +++ b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java @@ -123,6 +123,10 @@ public static SSLInfo getSSLInfo( PrincipalExtractor principalExtractor ) throws SSLPeerUnverifiedException { final SSLEngine engine = request.getSSLEngine(); + if (engine == null) { + return null; + } + final SSLSession session = engine.getSession(); X509Certificate[] x509Certs = null; From 9b5fe42b14d4e37fada8e01951c242c74eee3f5f Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Fri, 29 Sep 2023 22:13:10 +0000 Subject: [PATCH 09/50] Fix spotless Signed-off-by: Peter Nied --- .../opensearch/security/filter/SecurityRequestFactory.java | 4 +++- .../ssl/http/netty/SecuritySSLNettyHttpServerTransport.java | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index 36f3399e26..72727ff3bc 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -40,7 +40,9 @@ public Map> getHeaders() { @Override public SSLEngine getSSLEngine() { - if (underlyingRequest == null || underlyingRequest.getHttpChannel() == null || !(underlyingRequest.getHttpChannel() instanceof Netty4HttpChannel)) { + if (underlyingRequest == null + || underlyingRequest.getHttpChannel() == null + || !(underlyingRequest.getHttpChannel() instanceof Netty4HttpChannel)) { return null; } diff --git a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java index 3f5f7198fd..6d53c47a8a 100644 --- a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java +++ b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java @@ -20,7 +20,6 @@ import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.DecoderException; import io.netty.handler.ssl.ApplicationProtocolNames; import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler; @@ -37,7 +36,6 @@ import org.opensearch.http.HttpHandlingSettings; import org.opensearch.http.netty4.Netty4HttpChannel; import org.opensearch.http.netty4.Netty4HttpServerTransport; -import org.opensearch.security.http.AuthenicationVerifier; import org.opensearch.security.ssl.SecurityKeyStore; import org.opensearch.security.ssl.SslExceptionHandler; import org.opensearch.telemetry.tracing.Tracer; @@ -99,7 +97,7 @@ public void onException(HttpChannel channel, Exception cause0) { // TODO: Disable since changes in core aren't avaliable yet // @Override // protected ChannelInboundHandlerAdapter createHeaderVerifier() { - // return new AuthenicationVerifier(); + // return new AuthenicationVerifier(); // } protected class SSLHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler { From 9f369cbad476935455e381b720e8a2a5540ca8c3 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Sun, 1 Oct 2023 22:21:09 +0000 Subject: [PATCH 10/50] Redo how reRequestAuthentication works Signed-off-by: Peter Nied --- build.gradle | 27 ++-- .../security/auth/BackendRegistry.java | 141 +++++++----------- .../security/auth/HTTPAuthenticator.java | 13 +- .../security/filter/SecurityRequest.java | 3 - .../filter/SecurityRequestFactory.java | 79 ++++++---- .../security/filter/SecurityResponse.java | 67 +++++++++ .../security/filter/SecurityRestFilter.java | 71 ++++----- .../security/http/AuthenicationVerifier.java | 4 + .../security/http/HTTPBasicAuthenticator.java | 13 +- .../http/HTTPClientCertAuthenticator.java | 7 +- .../security/http/HTTPProxyAuthenticator.java | 6 +- .../http/OnBehalfOfAuthenticator.java | 6 +- .../proxy/HTTPExtendedProxyAuthenticator.java | 6 +- 13 files changed, 267 insertions(+), 176 deletions(-) create mode 100644 src/main/java/org/opensearch/security/filter/SecurityResponse.java diff --git a/build.gradle b/build.gradle index d3b3846edd..c2695cfd81 100644 --- a/build.gradle +++ b/build.gradle @@ -198,10 +198,11 @@ test { if (JavaVersion.current() > JavaVersion.VERSION_1_8) { jvmArgs += "--add-opens=java.base/java.io=ALL-UNNAMED" } - retry { - failOnPassedAfterRetry = false - maxRetries = 5 - } + // retry { + + // failOnPassedAfterRetry = false + // maxRetries = 5 + // } jacoco { excludes = [ "com.sun.jndi.dns.*", @@ -245,10 +246,10 @@ def setCommonTestConfig(Test task) { if (JavaVersion.current() > JavaVersion.VERSION_1_8) { task.jvmArgs += "--add-opens=java.base/java.io=ALL-UNNAMED" } - task.retry { - failOnPassedAfterRetry = false - maxRetries = 5 - } + // task.retry { + // failOnPassedAfterRetry = false + // maxRetries = 5 + // } task.jacoco { excludes = [ "com.sun.jndi.dns.*", @@ -464,11 +465,11 @@ task integrationTest(type: Test) { systemProperty "java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager" testClassesDirs = sourceSets.integrationTest.output.classesDirs classpath = sourceSets.integrationTest.runtimeClasspath - retry { - failOnPassedAfterRetry = false - maxRetries = 2 - maxFailures = 10 - } + // retry { + // failOnPassedAfterRetry = false + // maxRetries = 2 + // maxFailures = 10 + // } //run the integrationTest task after the test task shouldRunAfter test } diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index cdfa74655c..c137c5afec 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -32,6 +32,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.SortedSet; import java.util.concurrent.Callable; @@ -43,6 +44,8 @@ import com.google.common.cache.RemovalListener; import com.google.common.cache.RemovalNotification; import com.google.common.collect.Multimap; + +import org.apache.hc.core5.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.greenrobot.eventbus.Subscribe; @@ -57,6 +60,7 @@ import org.opensearch.security.auth.blocking.ClientBlockRegistry; import org.opensearch.security.auth.internal.NoOpAuthenticationBackend; import org.opensearch.security.configuration.AdminDNs; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.http.OnBehalfOfAuthenticator; import org.opensearch.security.http.XFFResolver; @@ -177,14 +181,7 @@ public void onDynamicConfigModelChanged(DynamicConfigModel dcm) { initialized = !restAuthDomains.isEmpty() || anonymousAuthEnabled || injectedUserEnabled; } - /** - * - * @param request - * @param channel - * @return The authenticated user, null means another roundtrip - * @throws OpenSearchSecurityException - */ - public boolean authenticate(final SecurityRequest request, final ThreadContext _DO_NOT_USE) { + public Optional authenticate(final SecurityRequest request) { final boolean isDebugEnabled = log.isDebugEnabled(); final boolean isBlockedBasedOnAddress = request.getRemoteAddress() .map(InetSocketAddress::getAddress) @@ -195,9 +192,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ log.debug("Rejecting REST request because of blocked address: {}", request.getRemoteAddress().orElse(null)); } - request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, "Authentication finally failed")); - - return false; + return new SecurityResponse.Builder().code(HttpStatus.SC_UNAUTHORIZED).buildAsOptional(); } final String sslPrincipal = (String) threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_SSL_PRINCIPAL); @@ -206,19 +201,18 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ // PKI authenticated REST call threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, new User(sslPrincipal)); auditLog.logSucceededLogin(sslPrincipal, true, null, request); - return true; + return Optional.empty(); } if (userInjector.injectUser(request)) { // ThreadContext injected user - return true; + return Optional.empty(); } if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); - request.getRestChannel() - .sendResponse(new BytesRestResponse(RestStatus.SERVICE_UNAVAILABLE, "OpenSearch Security not initialized.")); - return false; + // "OpenSearch Security not initialized." + return new SecurityResponse.Builder().code(HttpStatus.SC_UNAUTHORIZED).buildAsOptional(); } final TransportAddress remoteAddress = xffResolver.resolve(request); @@ -283,31 +277,19 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ continue; } - if (authDomain.isChallenge() && httpAuthenticator.reRequestAuthentication(request.getRestChannel(), null)) { - auditLog.logFailedLogin("", false, null, request); - if (isTraceEnabled) { - log.trace("No 'Authorization' header, send 401 and 'WWW-Authenticate Basic'"); - } - return false; - } else { - // no reRequest possible - if (isTraceEnabled) { - log.trace("No 'Authorization' header, send 403"); + if (authDomain.isChallenge()) { + final Optional reauthResponse = httpAuthenticator.reRequestAuthentication(null); + if (reauthResponse.isPresent()){ + return reauthResponse; } - continue; - } } else { org.apache.logging.log4j.ThreadContext.put("user", ac.getUsername()); if (!ac.isComplete()) { // credentials found in request but we need another client challenge - if (httpAuthenticator.reRequestAuthentication(request.getRestChannel(), ac)) { - // auditLog.logFailedLogin(ac.getUsername()+" ", request); --noauditlog - return false; - } else { - // no reRequest possible - continue; + final Optional reauthResponse = httpAuthenticator.reRequestAuthentication(null); + if (reauthResponse.isPresent()){ + return reauthResponse; } - } } @@ -339,14 +321,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ if (adminDns.isAdmin(authenticatedUser)) { log.error("Cannot authenticate rest user because admin user is not permitted to login via HTTP"); auditLog.logFailedLogin(authenticatedUser.getName(), true, null, request); - request.getRestChannel() - .sendResponse( - new BytesRestResponse( - RestStatus.FORBIDDEN, - "Cannot authenticate user because admin user is not permitted to login via HTTP" - ) - ); - return false; + return new SecurityResponse.Builder().code(HttpStatus.SC_FORBIDDEN).buildAsOptional(); } final String tenant = Utils.coalesce(request.header("securitytenant"), request.header("security_tenant")); @@ -360,6 +335,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ authenticated = true; break; }// end looping auth domains + } if (authenticated) { final User impersonatedUser = impersonate(request, authenticatedUser); @@ -371,59 +347,58 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ authenticatedUser.getName(), request ); - } else { + return Optional.empty(); + } + + if (isDebugEnabled) { + log.debug("User still not authenticated after checking {} auth domains", restAuthDomains.size()); + } + + if (authCredenetials == null && anonymousAuthEnabled) { + final String tenant = Utils.coalesce(request.header("securitytenant"), request.header("security_tenant")); + User anonymousUser = new User(User.ANONYMOUS.getName(), new HashSet(User.ANONYMOUS.getRoles()), null); + anonymousUser.setRequestedTenant(tenant); + + threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, anonymousUser); + auditLog.logSucceededLogin(anonymousUser.getName(), false, null, request); if (isDebugEnabled) { - log.debug("User still not authenticated after checking {} auth domains", restAuthDomains.size()); + log.debug("Anonymous User is authenticated"); } + return Optional.empty(); + } - if (authCredenetials == null && anonymousAuthEnabled) { - final String tenant = Utils.coalesce(request.header("securitytenant"), request.header("security_tenant")); - User anonymousUser = new User(User.ANONYMOUS.getName(), new HashSet(User.ANONYMOUS.getRoles()), null); - anonymousUser.setRequestedTenant(tenant); + if (firstChallengingHttpAuthenticator != null) { - threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, anonymousUser); - auditLog.logSucceededLogin(anonymousUser.getName(), false, null, request); - if (isDebugEnabled) { - log.debug("Anonymous User is authenticated"); - } - return true; + if (isDebugEnabled) { + log.debug("Rerequest with {}", firstChallengingHttpAuthenticator.getClass()); } - if (firstChallengingHttpAuthenticator != null) { - + final Optional response = firstChallengingHttpAuthenticator.reRequestAuthentication(null); + if (response.isPresent()) { if (isDebugEnabled) { - log.debug("Rerequest with {}", firstChallengingHttpAuthenticator.getClass()); + log.debug("Rerequest {} failed", firstChallengingHttpAuthenticator.getClass()); } - if (firstChallengingHttpAuthenticator.reRequestAuthentication(request.getRestChannel(), null)) { - if (isDebugEnabled) { - log.debug("Rerequest {} failed", firstChallengingHttpAuthenticator.getClass()); - } - - log.warn( - "Authentication finally failed for {} from {}", - authCredenetials == null ? null : authCredenetials.getUsername(), - remoteAddress - ); - auditLog.logFailedLogin(authCredenetials == null ? null : authCredenetials.getUsername(), false, null, request); - return false; - } + log.warn( + "Authentication finally failed for {} from {}", + authCredenetials == null ? null : authCredenetials.getUsername(), + remoteAddress + ); + auditLog.logFailedLogin(authCredenetials == null ? null : authCredenetials.getUsername(), false, null, request); + return response; } + } - log.warn( - "Authentication finally failed for {} from {}", - authCredenetials == null ? null : authCredenetials.getUsername(), - remoteAddress - ); - auditLog.logFailedLogin(authCredenetials == null ? null : authCredenetials.getUsername(), false, null, request); - - notifyIpAuthFailureListeners(request, authCredenetials); + log.warn( + "Authentication finally failed for {} from {}", + authCredenetials == null ? null : authCredenetials.getUsername(), + remoteAddress + ); + auditLog.logFailedLogin(authCredenetials == null ? null : authCredenetials.getUsername(), false, null, request); - request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, "Authentication finally failed")); - return false; - } + notifyIpAuthFailureListeners(request, authCredenetials); - return authenticated; + return new SecurityResponse.Builder().code(HttpStatus.SC_UNAUTHORIZED).buildAsOptional(); } private void notifyIpAuthFailureListeners(SecurityRequest request, AuthCredentials authCredentials) { diff --git a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java index 1ddc006445..85496ccbbc 100644 --- a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java +++ b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java @@ -26,13 +26,18 @@ package org.opensearch.security.auth; +import java.util.Optional; + import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; +import static org.apache.hc.core5.http.HttpStatus.SC_UNAUTHORIZED; + /** * OpenSearch Security custom HTTP authenticators need to implement this interface. *

@@ -51,6 +56,12 @@ */ public interface HTTPAuthenticator { + public static SecurityResponse wwwAuthenticateResponse = new SecurityResponse.Builder() + .code(SC_UNAUTHORIZED) + .body("Unauthorized") + .header("WWW-Authenticate", "Basic realm=\"OpenSearch Security\"") + .build(); + /** * The type (name) of the authenticator. Only for logging. * @return the type @@ -82,5 +93,5 @@ public interface HTTPAuthenticator { * @return false if re-request is not supported/necessary, true otherwise. * If true is returned {@code channel.sendResponse()} must be called so that the request completes. */ - boolean reRequestAuthentication(final RestChannel channel, AuthCredentials credentials); + Optional reRequestAuthentication(AuthCredentials credentials); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java index 69d2e0be4d..8402acc409 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -8,7 +8,6 @@ import javax.net.ssl.SSLEngine; -import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; @@ -18,8 +17,6 @@ public interface SecurityRequest { public SSLEngine getSSLEngine(); - public RestChannel getRestChannel(); - public String path(); public Method method(); diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index 72727ff3bc..9b7dce127d 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -1,6 +1,7 @@ package org.opensearch.security.filter; import java.net.InetSocketAddress; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -12,12 +13,14 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.ssl.SslHandler; public class SecurityRequestFactory { - public static SecurityRequest from() { - return null; + public static SecurityRequest from(final HttpRequest request) { + return new SecurityNettyRequest(request); } public static SecurityRequest from(final RestRequest request, final RestChannel channel) { @@ -55,10 +58,10 @@ public SSLEngine getSSLEngine() { return sslhandler != null ? sslhandler.engine() : null; } - @Override - public RestChannel getRestChannel() { - return underlyingChannel; - } + // @Override + // public RestChannel getRestChannel() { + // return underlyingChannel; + // } @Override public String path() { @@ -96,11 +99,18 @@ public Map params() { } } - protected static class NettyRequest implements SecurityRequest { + protected static class SecurityNettyRequest implements SecurityRequest { + private final HttpRequest underlyingRequset; + + protected SecurityNettyRequest(final HttpRequest request) { + underlyingRequset = request; + } + @Override public Map> getHeaders() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getHeaders'"); + final Map> headerMap = new HashMap<>(); + underlyingRequset.headers().forEach(entry -> headerMap.put(entry.getKey(), List.of(entry.getValue()))); + return headerMap; } @Override @@ -109,52 +119,65 @@ public SSLEngine getSSLEngine() { throw new UnsupportedOperationException("Unimplemented method 'getSSLEngine'"); } - @Override - public RestChannel getRestChannel() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getRestChannel'"); - } + // @Override + // public RestChannel getRestChannel() { + // // TODO Auto-generated method stub + // throw new UnsupportedOperationException("Unimplemented method 'getRestChannel'"); + // } @Override public String path() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'path'"); + return underlyingRequset.uri(); } @Override public Method method() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'method'"); + if (underlyingRequset.method() == HttpMethod.CONNECT) { + return Method.CONNECT; + } else if (underlyingRequset.method() == HttpMethod.DELETE) { + return Method.DELETE; + } else if (underlyingRequset.method() == HttpMethod.GET) { + return Method.GET; + } else if (underlyingRequset.method() == HttpMethod.HEAD) { + return Method.HEAD; + } else if (underlyingRequset.method() == HttpMethod.OPTIONS) { + return Method.OPTIONS; + } else if (underlyingRequset.method() == HttpMethod.PATCH) { + return Method.PATCH; + } else if (underlyingRequset.method() == HttpMethod.POST) { + return Method.POST; + } else if (underlyingRequset.method() == HttpMethod.PUT) { + return Method.PUT; + } else if (underlyingRequset.method() == HttpMethod.TRACE) { + return Method.TRACE; + } + return null; } @Override public Optional getRemoteAddress() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getRemoteAddress'"); + return Optional.empty(); } @Override public boolean sourcedFromNetty() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'sourcedFromNetty'"); + return true; } @Override public String uri() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'uri'"); + return underlyingRequset.uri(); } @Override public Optional asRestRequest() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'asRestRequest'"); + return Optional.empty(); } @Override public Map params() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'params'"); + //TODO: Support this? + return null; } } } diff --git a/src/main/java/org/opensearch/security/filter/SecurityResponse.java b/src/main/java/org/opensearch/security/filter/SecurityResponse.java new file mode 100644 index 0000000000..4112d0396c --- /dev/null +++ b/src/main/java/org/opensearch/security/filter/SecurityResponse.java @@ -0,0 +1,67 @@ +package org.opensearch.security.filter; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import org.opensearch.core.rest.RestStatus; + +public class SecurityResponse { + private final int code; + final Exception ex; + protected SecurityResponse(final int code, final Exception ex){ + this.code = code; + this.ex = ex; + } + + public int getCode() { + return code; + } + + public Exception getException() { + return ex; + } + + public static class Builder { + private int code; + private Map headers; + private String body; + public Builder() { + code = -1; + headers = new HashMap<>(); + body = ""; + } + + public Builder code(final int code) { + this.code = code; + return this; + } + + public Builder code(final RestStatus code) { + this.code = code.getStatus(); + return this; + } + + public Builder header(final String key, final String value) { + this.headers.put(key, value); + return this; + } + + public Builder body(final String body) { + this.body = body; + return this; + } + + public SecurityResponse build() { + if (code == -1) { + throw new IllegalArgumentException("No response code set"); + } + + return new SecurityResponse(code, null); + } + + public Optional buildAsOptional() { + return Optional.of(build()); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 52119e3c5c..23c3e1d634 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -35,6 +35,7 @@ import javax.net.ssl.SSLPeerUnverifiedException; +import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.greenrobot.eventbus.Subscribe; @@ -67,6 +68,8 @@ import org.opensearch.security.user.User; import org.opensearch.threadpool.ThreadPool; +import com.onelogin.saml2.Auth; + import static org.opensearch.security.OpenSearchSecurityPlugin.LEGACY_OPENDISTRO_PREFIX; import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX; @@ -131,29 +134,37 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return (request, channel, client) -> { org.apache.logging.log4j.ThreadContext.clearAll(); final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel); - if (!checkAndAuthenticateRequest(securityRequest)) { - User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); - boolean isSuperAdminUser = userIsSuperAdmin(user, adminDNs); - if (isSuperAdminUser - || (whitelistingSettings.checkRequestIsAllowed(request, channel, client) - && allowlistingSettings.checkRequestIsAllowed(request, channel, client))) { - SecurityRequestFactory.from(request, channel); - if (isSuperAdminUser || authorizeRequest(original, securityRequest, user)) { - original.handleRequest(request, channel, client); - } + Optional failureResponse = checkAndAuthenticateRequest(securityRequest); + if (failureResponse.isEmpty()) { + final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); + if (userIsSuperAdmin(user, adminDNs)) { + original.handleRequest(request, channel, client); + } else { + + } + + if (whitelistingSettings.checkRequestIsAllowed(request, channel, client) + && allowlistingSettings.checkRequestIsAllowed(request, channel, client)) { + failureResponse = authorizeRequest(original, securityRequest, user); } } + + failureResponse.ifPresent(response -> { + // TODO: Wrong kind of reponse body + channel.sendResponse(new BytesRestResponse(RestStatus.fromCode(response.getCode()), response.ex.toString())); + }); + }; } /** * Checks if a given user is a SuperAdmin */ - private boolean userIsSuperAdmin(User user, AdminDNs adminDNs) { + private boolean userIsSuperAdmin(final User user, final AdminDNs adminDNs) { return user != null && adminDNs.isAdmin(user); } - private boolean authorizeRequest(RestHandler original, SecurityRequest request, User user) { + private Optional authorizeRequest(RestHandler original, SecurityRequest request, User user) { List restRoutes = original.routes(); Optional handler = restRoutes.stream() @@ -190,36 +201,27 @@ private boolean authorizeRequest(RestHandler original, SecurityRequest request, } else { err = String.format("no permissions for %s and %s", pres.getMissingPrivileges(), user); } - log.debug(err); - request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, err)); - return false; + // TODO: Make correct exception type + return Optional.of(new SecurityResponse(RestStatus.UNAUTHORIZED.getStatus(), new RuntimeException(err))); } } // if handler is not an instance of NamedRoute then we pass through to eval at Transport Layer. - return true; + return Optional.empty(); } - public boolean checkAndAuthenticateRequest(SecurityRequest request) throws Exception { - - RestChannel channel = request.getRestChannel(); + public Optional checkAndAuthenticateRequest(SecurityRequest request) throws Exception { threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, Origin.REST.toString()); if (HTTPHelper.containsBadHeader(request)) { final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); - log.error(exception.toString()); - auditLog.logBadHeaders(request); - channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, exception)); - return true; + return Optional.of(new SecurityResponse(RestStatus.FORBIDDEN.getStatus(), exception)); } if (SSLRequestHelper.containsBadHeader(threadContext, ConfigConstants.OPENDISTRO_SECURITY_CONFIG_PREFIX)) { final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); - log.error(exception.toString()); - auditLog.logBadHeaders(request); - channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, exception)); - return true; + return Optional.of(new SecurityResponse(RestStatus.FORBIDDEN.getStatus(), exception)); } final SSLInfo sslInfo; @@ -236,23 +238,23 @@ public boolean checkAndAuthenticateRequest(SecurityRequest request) throws Excep threadContext.putTransient("_opendistro_security_ssl_cipher", sslInfo.getCipher()); } } catch (SSLPeerUnverifiedException e) { - log.error("No ssl info", e); auditLog.logSSLException(request, e); - channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, e)); - return true; + return Optional.of(new SecurityResponse(RestStatus.FORBIDDEN.getStatus(), e)); } if (!compatConfig.restAuthEnabled()) { - return false; + // Authentication is disabled + return Optional.empty(); } Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; if (request.method() != Method.OPTIONS && !(HEALTH_SUFFIX.equals(suffix)) && !(WHO_AM_I_SUFFIX.equals(suffix))) { - if (!registry.authenticate(request, threadContext)) { + final Optional backAuthFailure = registry.authenticate(request); + if (backAuthFailure.isPresent()) { // another roundtrip org.apache.logging.log4j.ThreadContext.remove("user"); - return true; + return backAuthFailure; } else { // make it possible to filter logs by username org.apache.logging.log4j.ThreadContext.put( @@ -262,7 +264,8 @@ public boolean checkAndAuthenticateRequest(SecurityRequest request) throws Excep } } - return false; + // User was authenticated + return Optional.empty(); } @Subscribe diff --git a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java index 9acbfb5141..d058be5cac 100644 --- a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java +++ b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java @@ -2,6 +2,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestFactory; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; @@ -36,6 +38,8 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception private boolean isAuthenticated(HttpRequest request) { + final SecurityRequest securityRequset = SecurityRequestFactory.from(request); + log.info("Checking if request is authenticated:\n" + request); final boolean shouldBlock = request.headers().contains("blockme"); diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index ae393e5028..74196d4dc4 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -27,6 +27,7 @@ package org.opensearch.security.http; import java.nio.file.Path; +import java.util.Optional; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -38,6 +39,7 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.HTTPHelper; import org.opensearch.security.user.AuthCredentials; @@ -65,11 +67,12 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { - final BytesRestResponse wwwAuthenticateResponse = new BytesRestResponse(RestStatus.UNAUTHORIZED, "Unauthorized"); - wwwAuthenticateResponse.addHeader("WWW-Authenticate", "Basic realm=\"OpenSearch Security\""); - channel.sendResponse(wwwAuthenticateResponse); - return true; + public Optional reRequestAuthentication(final AuthCredentials creds) { + return new SecurityResponse.Builder() + .code(RestStatus.UNAUTHORIZED) + .body("Unauthorized") + .header("WWW-Authenticate", "Basic realm=\"OpenSearch Security\"") + .buildAsOptional(); } @Override diff --git a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java index 03221e810b..c955af72e1 100644 --- a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; @@ -41,9 +42,9 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; -import org.opensearch.rest.RestChannel; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -98,8 +99,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { - return false; + public Optional reRequestAuthentication(AuthCredentials creds) { + return Optional.empty(); } @Override diff --git a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java index d835a6a081..15c3d79897 100644 --- a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java @@ -27,6 +27,7 @@ package org.opensearch.security.http; import java.nio.file.Path; +import java.util.Optional; import java.util.regex.Pattern; import com.google.common.base.Predicates; @@ -40,6 +41,7 @@ import org.opensearch.rest.RestChannel; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -89,8 +91,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { - return false; + public Optional reRequestAuthentication(final AuthCredentials creds) { + return Optional.empty(); } @Override diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java index 2a47853ec2..3d03108c3c 100644 --- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java @@ -16,6 +16,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map.Entry; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -38,6 +39,7 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.KeyUtils; @@ -245,8 +247,8 @@ public Boolean isRequestAllowed(final SecurityRequest request) { } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { - return false; + public Optional reRequestAuthentication(final AuthCredentials creds) { + return Optional.empty(); } @Override diff --git a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java index 4231bf6c57..b510c10dcf 100644 --- a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java @@ -28,6 +28,7 @@ import java.nio.file.Path; import java.util.List; +import java.util.Optional; import java.util.Map.Entry; import com.google.common.base.Joiner; @@ -39,6 +40,7 @@ import org.opensearch.core.common.Strings; import org.opensearch.rest.RestChannel; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.http.HTTPProxyAuthenticator; import org.opensearch.security.user.AuthCredentials; @@ -85,8 +87,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { - return false; + public Optional reRequestAuthentication(final AuthCredentials creds) { + return Optional.empty(); } @Override From 46358a2a98565c7a79542e1c83eee2bdb00b754d Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Sun, 1 Oct 2023 22:22:42 +0000 Subject: [PATCH 11/50] Nix that idea Signed-off-by: Peter Nied --- .../security/auth/BackendRegistry.java | 141 +++++++++++------- .../security/auth/HTTPAuthenticator.java | 13 +- .../security/filter/SecurityRequest.java | 3 + .../filter/SecurityRequestFactory.java | 79 ++++------ .../security/filter/SecurityResponse.java | 67 --------- .../security/filter/SecurityRestFilter.java | 71 +++++---- .../security/http/AuthenicationVerifier.java | 4 - .../security/http/HTTPBasicAuthenticator.java | 13 +- .../http/HTTPClientCertAuthenticator.java | 7 +- .../security/http/HTTPProxyAuthenticator.java | 6 +- .../http/OnBehalfOfAuthenticator.java | 6 +- .../proxy/HTTPExtendedProxyAuthenticator.java | 6 +- 12 files changed, 163 insertions(+), 253 deletions(-) delete mode 100644 src/main/java/org/opensearch/security/filter/SecurityResponse.java diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index c137c5afec..cdfa74655c 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -32,7 +32,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; -import java.util.Optional; import java.util.Set; import java.util.SortedSet; import java.util.concurrent.Callable; @@ -44,8 +43,6 @@ import com.google.common.cache.RemovalListener; import com.google.common.cache.RemovalNotification; import com.google.common.collect.Multimap; - -import org.apache.hc.core5.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.greenrobot.eventbus.Subscribe; @@ -60,7 +57,6 @@ import org.opensearch.security.auth.blocking.ClientBlockRegistry; import org.opensearch.security.auth.internal.NoOpAuthenticationBackend; import org.opensearch.security.configuration.AdminDNs; -import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.http.OnBehalfOfAuthenticator; import org.opensearch.security.http.XFFResolver; @@ -181,7 +177,14 @@ public void onDynamicConfigModelChanged(DynamicConfigModel dcm) { initialized = !restAuthDomains.isEmpty() || anonymousAuthEnabled || injectedUserEnabled; } - public Optional authenticate(final SecurityRequest request) { + /** + * + * @param request + * @param channel + * @return The authenticated user, null means another roundtrip + * @throws OpenSearchSecurityException + */ + public boolean authenticate(final SecurityRequest request, final ThreadContext _DO_NOT_USE) { final boolean isDebugEnabled = log.isDebugEnabled(); final boolean isBlockedBasedOnAddress = request.getRemoteAddress() .map(InetSocketAddress::getAddress) @@ -192,7 +195,9 @@ public Optional authenticate(final SecurityRequest request) { log.debug("Rejecting REST request because of blocked address: {}", request.getRemoteAddress().orElse(null)); } - return new SecurityResponse.Builder().code(HttpStatus.SC_UNAUTHORIZED).buildAsOptional(); + request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, "Authentication finally failed")); + + return false; } final String sslPrincipal = (String) threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_SSL_PRINCIPAL); @@ -201,18 +206,19 @@ public Optional authenticate(final SecurityRequest request) { // PKI authenticated REST call threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, new User(sslPrincipal)); auditLog.logSucceededLogin(sslPrincipal, true, null, request); - return Optional.empty(); + return true; } if (userInjector.injectUser(request)) { // ThreadContext injected user - return Optional.empty(); + return true; } if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); - // "OpenSearch Security not initialized." - return new SecurityResponse.Builder().code(HttpStatus.SC_UNAUTHORIZED).buildAsOptional(); + request.getRestChannel() + .sendResponse(new BytesRestResponse(RestStatus.SERVICE_UNAVAILABLE, "OpenSearch Security not initialized.")); + return false; } final TransportAddress remoteAddress = xffResolver.resolve(request); @@ -277,19 +283,31 @@ public Optional authenticate(final SecurityRequest request) { continue; } - if (authDomain.isChallenge()) { - final Optional reauthResponse = httpAuthenticator.reRequestAuthentication(null); - if (reauthResponse.isPresent()){ - return reauthResponse; + if (authDomain.isChallenge() && httpAuthenticator.reRequestAuthentication(request.getRestChannel(), null)) { + auditLog.logFailedLogin("", false, null, request); + if (isTraceEnabled) { + log.trace("No 'Authorization' header, send 401 and 'WWW-Authenticate Basic'"); + } + return false; + } else { + // no reRequest possible + if (isTraceEnabled) { + log.trace("No 'Authorization' header, send 403"); } + continue; + } } else { org.apache.logging.log4j.ThreadContext.put("user", ac.getUsername()); if (!ac.isComplete()) { // credentials found in request but we need another client challenge - final Optional reauthResponse = httpAuthenticator.reRequestAuthentication(null); - if (reauthResponse.isPresent()){ - return reauthResponse; + if (httpAuthenticator.reRequestAuthentication(request.getRestChannel(), ac)) { + // auditLog.logFailedLogin(ac.getUsername()+" ", request); --noauditlog + return false; + } else { + // no reRequest possible + continue; } + } } @@ -321,7 +339,14 @@ public Optional authenticate(final SecurityRequest request) { if (adminDns.isAdmin(authenticatedUser)) { log.error("Cannot authenticate rest user because admin user is not permitted to login via HTTP"); auditLog.logFailedLogin(authenticatedUser.getName(), true, null, request); - return new SecurityResponse.Builder().code(HttpStatus.SC_FORBIDDEN).buildAsOptional(); + request.getRestChannel() + .sendResponse( + new BytesRestResponse( + RestStatus.FORBIDDEN, + "Cannot authenticate user because admin user is not permitted to login via HTTP" + ) + ); + return false; } final String tenant = Utils.coalesce(request.header("securitytenant"), request.header("security_tenant")); @@ -335,7 +360,6 @@ public Optional authenticate(final SecurityRequest request) { authenticated = true; break; }// end looping auth domains - } if (authenticated) { final User impersonatedUser = impersonate(request, authenticatedUser); @@ -347,58 +371,59 @@ public Optional authenticate(final SecurityRequest request) { authenticatedUser.getName(), request ); - return Optional.empty(); - } - - if (isDebugEnabled) { - log.debug("User still not authenticated after checking {} auth domains", restAuthDomains.size()); - } - - if (authCredenetials == null && anonymousAuthEnabled) { - final String tenant = Utils.coalesce(request.header("securitytenant"), request.header("security_tenant")); - User anonymousUser = new User(User.ANONYMOUS.getName(), new HashSet(User.ANONYMOUS.getRoles()), null); - anonymousUser.setRequestedTenant(tenant); - - threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, anonymousUser); - auditLog.logSucceededLogin(anonymousUser.getName(), false, null, request); + } else { if (isDebugEnabled) { - log.debug("Anonymous User is authenticated"); + log.debug("User still not authenticated after checking {} auth domains", restAuthDomains.size()); } - return Optional.empty(); - } - if (firstChallengingHttpAuthenticator != null) { + if (authCredenetials == null && anonymousAuthEnabled) { + final String tenant = Utils.coalesce(request.header("securitytenant"), request.header("security_tenant")); + User anonymousUser = new User(User.ANONYMOUS.getName(), new HashSet(User.ANONYMOUS.getRoles()), null); + anonymousUser.setRequestedTenant(tenant); - if (isDebugEnabled) { - log.debug("Rerequest with {}", firstChallengingHttpAuthenticator.getClass()); + threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, anonymousUser); + auditLog.logSucceededLogin(anonymousUser.getName(), false, null, request); + if (isDebugEnabled) { + log.debug("Anonymous User is authenticated"); + } + return true; } - final Optional response = firstChallengingHttpAuthenticator.reRequestAuthentication(null); - if (response.isPresent()) { + if (firstChallengingHttpAuthenticator != null) { + if (isDebugEnabled) { - log.debug("Rerequest {} failed", firstChallengingHttpAuthenticator.getClass()); + log.debug("Rerequest with {}", firstChallengingHttpAuthenticator.getClass()); } - log.warn( - "Authentication finally failed for {} from {}", - authCredenetials == null ? null : authCredenetials.getUsername(), - remoteAddress - ); - auditLog.logFailedLogin(authCredenetials == null ? null : authCredenetials.getUsername(), false, null, request); - return response; + if (firstChallengingHttpAuthenticator.reRequestAuthentication(request.getRestChannel(), null)) { + if (isDebugEnabled) { + log.debug("Rerequest {} failed", firstChallengingHttpAuthenticator.getClass()); + } + + log.warn( + "Authentication finally failed for {} from {}", + authCredenetials == null ? null : authCredenetials.getUsername(), + remoteAddress + ); + auditLog.logFailedLogin(authCredenetials == null ? null : authCredenetials.getUsername(), false, null, request); + return false; + } } - } - log.warn( - "Authentication finally failed for {} from {}", - authCredenetials == null ? null : authCredenetials.getUsername(), - remoteAddress - ); - auditLog.logFailedLogin(authCredenetials == null ? null : authCredenetials.getUsername(), false, null, request); + log.warn( + "Authentication finally failed for {} from {}", + authCredenetials == null ? null : authCredenetials.getUsername(), + remoteAddress + ); + auditLog.logFailedLogin(authCredenetials == null ? null : authCredenetials.getUsername(), false, null, request); + + notifyIpAuthFailureListeners(request, authCredenetials); - notifyIpAuthFailureListeners(request, authCredenetials); + request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, "Authentication finally failed")); + return false; + } - return new SecurityResponse.Builder().code(HttpStatus.SC_UNAUTHORIZED).buildAsOptional(); + return authenticated; } private void notifyIpAuthFailureListeners(SecurityRequest request, AuthCredentials authCredentials) { diff --git a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java index 85496ccbbc..1ddc006445 100644 --- a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java +++ b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java @@ -26,18 +26,13 @@ package org.opensearch.security.auth; -import java.util.Optional; - import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; -import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; -import static org.apache.hc.core5.http.HttpStatus.SC_UNAUTHORIZED; - /** * OpenSearch Security custom HTTP authenticators need to implement this interface. *

@@ -56,12 +51,6 @@ */ public interface HTTPAuthenticator { - public static SecurityResponse wwwAuthenticateResponse = new SecurityResponse.Builder() - .code(SC_UNAUTHORIZED) - .body("Unauthorized") - .header("WWW-Authenticate", "Basic realm=\"OpenSearch Security\"") - .build(); - /** * The type (name) of the authenticator. Only for logging. * @return the type @@ -93,5 +82,5 @@ public interface HTTPAuthenticator { * @return false if re-request is not supported/necessary, true otherwise. * If true is returned {@code channel.sendResponse()} must be called so that the request completes. */ - Optional reRequestAuthentication(AuthCredentials credentials); + boolean reRequestAuthentication(final RestChannel channel, AuthCredentials credentials); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java index 8402acc409..69d2e0be4d 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -8,6 +8,7 @@ import javax.net.ssl.SSLEngine; +import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; @@ -17,6 +18,8 @@ public interface SecurityRequest { public SSLEngine getSSLEngine(); + public RestChannel getRestChannel(); + public String path(); public Method method(); diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index 9b7dce127d..72727ff3bc 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -1,7 +1,6 @@ package org.opensearch.security.filter; import java.net.InetSocketAddress; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -13,14 +12,12 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; -import io.netty.handler.codec.http.HttpMethod; -import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.ssl.SslHandler; public class SecurityRequestFactory { - public static SecurityRequest from(final HttpRequest request) { - return new SecurityNettyRequest(request); + public static SecurityRequest from() { + return null; } public static SecurityRequest from(final RestRequest request, final RestChannel channel) { @@ -58,10 +55,10 @@ public SSLEngine getSSLEngine() { return sslhandler != null ? sslhandler.engine() : null; } - // @Override - // public RestChannel getRestChannel() { - // return underlyingChannel; - // } + @Override + public RestChannel getRestChannel() { + return underlyingChannel; + } @Override public String path() { @@ -99,18 +96,11 @@ public Map params() { } } - protected static class SecurityNettyRequest implements SecurityRequest { - private final HttpRequest underlyingRequset; - - protected SecurityNettyRequest(final HttpRequest request) { - underlyingRequset = request; - } - + protected static class NettyRequest implements SecurityRequest { @Override public Map> getHeaders() { - final Map> headerMap = new HashMap<>(); - underlyingRequset.headers().forEach(entry -> headerMap.put(entry.getKey(), List.of(entry.getValue()))); - return headerMap; + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getHeaders'"); } @Override @@ -119,65 +109,52 @@ public SSLEngine getSSLEngine() { throw new UnsupportedOperationException("Unimplemented method 'getSSLEngine'"); } - // @Override - // public RestChannel getRestChannel() { - // // TODO Auto-generated method stub - // throw new UnsupportedOperationException("Unimplemented method 'getRestChannel'"); - // } + @Override + public RestChannel getRestChannel() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getRestChannel'"); + } @Override public String path() { - return underlyingRequset.uri(); + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'path'"); } @Override public Method method() { - if (underlyingRequset.method() == HttpMethod.CONNECT) { - return Method.CONNECT; - } else if (underlyingRequset.method() == HttpMethod.DELETE) { - return Method.DELETE; - } else if (underlyingRequset.method() == HttpMethod.GET) { - return Method.GET; - } else if (underlyingRequset.method() == HttpMethod.HEAD) { - return Method.HEAD; - } else if (underlyingRequset.method() == HttpMethod.OPTIONS) { - return Method.OPTIONS; - } else if (underlyingRequset.method() == HttpMethod.PATCH) { - return Method.PATCH; - } else if (underlyingRequset.method() == HttpMethod.POST) { - return Method.POST; - } else if (underlyingRequset.method() == HttpMethod.PUT) { - return Method.PUT; - } else if (underlyingRequset.method() == HttpMethod.TRACE) { - return Method.TRACE; - } - return null; + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'method'"); } @Override public Optional getRemoteAddress() { - return Optional.empty(); + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getRemoteAddress'"); } @Override public boolean sourcedFromNetty() { - return true; + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'sourcedFromNetty'"); } @Override public String uri() { - return underlyingRequset.uri(); + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'uri'"); } @Override public Optional asRestRequest() { - return Optional.empty(); + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'asRestRequest'"); } @Override public Map params() { - //TODO: Support this? - return null; + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'params'"); } } } diff --git a/src/main/java/org/opensearch/security/filter/SecurityResponse.java b/src/main/java/org/opensearch/security/filter/SecurityResponse.java deleted file mode 100644 index 4112d0396c..0000000000 --- a/src/main/java/org/opensearch/security/filter/SecurityResponse.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.opensearch.security.filter; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -import org.opensearch.core.rest.RestStatus; - -public class SecurityResponse { - private final int code; - final Exception ex; - protected SecurityResponse(final int code, final Exception ex){ - this.code = code; - this.ex = ex; - } - - public int getCode() { - return code; - } - - public Exception getException() { - return ex; - } - - public static class Builder { - private int code; - private Map headers; - private String body; - public Builder() { - code = -1; - headers = new HashMap<>(); - body = ""; - } - - public Builder code(final int code) { - this.code = code; - return this; - } - - public Builder code(final RestStatus code) { - this.code = code.getStatus(); - return this; - } - - public Builder header(final String key, final String value) { - this.headers.put(key, value); - return this; - } - - public Builder body(final String body) { - this.body = body; - return this; - } - - public SecurityResponse build() { - if (code == -1) { - throw new IllegalArgumentException("No response code set"); - } - - return new SecurityResponse(code, null); - } - - public Optional buildAsOptional() { - return Optional.of(build()); - } - } -} \ No newline at end of file diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 23c3e1d634..52119e3c5c 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -35,7 +35,6 @@ import javax.net.ssl.SSLPeerUnverifiedException; -import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.greenrobot.eventbus.Subscribe; @@ -68,8 +67,6 @@ import org.opensearch.security.user.User; import org.opensearch.threadpool.ThreadPool; -import com.onelogin.saml2.Auth; - import static org.opensearch.security.OpenSearchSecurityPlugin.LEGACY_OPENDISTRO_PREFIX; import static org.opensearch.security.OpenSearchSecurityPlugin.PLUGINS_PREFIX; @@ -134,37 +131,29 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return (request, channel, client) -> { org.apache.logging.log4j.ThreadContext.clearAll(); final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel); - Optional failureResponse = checkAndAuthenticateRequest(securityRequest); - if (failureResponse.isEmpty()) { - final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); - if (userIsSuperAdmin(user, adminDNs)) { - original.handleRequest(request, channel, client); - } else { - - } - - if (whitelistingSettings.checkRequestIsAllowed(request, channel, client) - && allowlistingSettings.checkRequestIsAllowed(request, channel, client)) { - failureResponse = authorizeRequest(original, securityRequest, user); + if (!checkAndAuthenticateRequest(securityRequest)) { + User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); + boolean isSuperAdminUser = userIsSuperAdmin(user, adminDNs); + if (isSuperAdminUser + || (whitelistingSettings.checkRequestIsAllowed(request, channel, client) + && allowlistingSettings.checkRequestIsAllowed(request, channel, client))) { + SecurityRequestFactory.from(request, channel); + if (isSuperAdminUser || authorizeRequest(original, securityRequest, user)) { + original.handleRequest(request, channel, client); + } } } - - failureResponse.ifPresent(response -> { - // TODO: Wrong kind of reponse body - channel.sendResponse(new BytesRestResponse(RestStatus.fromCode(response.getCode()), response.ex.toString())); - }); - }; } /** * Checks if a given user is a SuperAdmin */ - private boolean userIsSuperAdmin(final User user, final AdminDNs adminDNs) { + private boolean userIsSuperAdmin(User user, AdminDNs adminDNs) { return user != null && adminDNs.isAdmin(user); } - private Optional authorizeRequest(RestHandler original, SecurityRequest request, User user) { + private boolean authorizeRequest(RestHandler original, SecurityRequest request, User user) { List restRoutes = original.routes(); Optional handler = restRoutes.stream() @@ -201,27 +190,36 @@ private Optional authorizeRequest(RestHandler original, Securi } else { err = String.format("no permissions for %s and %s", pres.getMissingPrivileges(), user); } - // TODO: Make correct exception type - return Optional.of(new SecurityResponse(RestStatus.UNAUTHORIZED.getStatus(), new RuntimeException(err))); + log.debug(err); + request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, err)); + return false; } } // if handler is not an instance of NamedRoute then we pass through to eval at Transport Layer. - return Optional.empty(); + return true; } - public Optional checkAndAuthenticateRequest(SecurityRequest request) throws Exception { + public boolean checkAndAuthenticateRequest(SecurityRequest request) throws Exception { + + RestChannel channel = request.getRestChannel(); threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, Origin.REST.toString()); if (HTTPHelper.containsBadHeader(request)) { final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); - return Optional.of(new SecurityResponse(RestStatus.FORBIDDEN.getStatus(), exception)); + log.error(exception.toString()); + auditLog.logBadHeaders(request); + channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, exception)); + return true; } if (SSLRequestHelper.containsBadHeader(threadContext, ConfigConstants.OPENDISTRO_SECURITY_CONFIG_PREFIX)) { final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); - return Optional.of(new SecurityResponse(RestStatus.FORBIDDEN.getStatus(), exception)); + log.error(exception.toString()); + auditLog.logBadHeaders(request); + channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, exception)); + return true; } final SSLInfo sslInfo; @@ -238,23 +236,23 @@ public Optional checkAndAuthenticateRequest(SecurityRequest re threadContext.putTransient("_opendistro_security_ssl_cipher", sslInfo.getCipher()); } } catch (SSLPeerUnverifiedException e) { + log.error("No ssl info", e); auditLog.logSSLException(request, e); - return Optional.of(new SecurityResponse(RestStatus.FORBIDDEN.getStatus(), e)); + channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, e)); + return true; } if (!compatConfig.restAuthEnabled()) { - // Authentication is disabled - return Optional.empty(); + return false; } Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; if (request.method() != Method.OPTIONS && !(HEALTH_SUFFIX.equals(suffix)) && !(WHO_AM_I_SUFFIX.equals(suffix))) { - final Optional backAuthFailure = registry.authenticate(request); - if (backAuthFailure.isPresent()) { + if (!registry.authenticate(request, threadContext)) { // another roundtrip org.apache.logging.log4j.ThreadContext.remove("user"); - return backAuthFailure; + return true; } else { // make it possible to filter logs by username org.apache.logging.log4j.ThreadContext.put( @@ -264,8 +262,7 @@ public Optional checkAndAuthenticateRequest(SecurityRequest re } } - // User was authenticated - return Optional.empty(); + return false; } @Subscribe diff --git a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java index d058be5cac..9acbfb5141 100644 --- a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java +++ b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java @@ -2,8 +2,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestFactory; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; @@ -38,8 +36,6 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception private boolean isAuthenticated(HttpRequest request) { - final SecurityRequest securityRequset = SecurityRequestFactory.from(request); - log.info("Checking if request is authenticated:\n" + request); final boolean shouldBlock = request.headers().contains("blockme"); diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index 74196d4dc4..ae393e5028 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -27,7 +27,6 @@ package org.opensearch.security.http; import java.nio.file.Path; -import java.util.Optional; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -39,7 +38,6 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.HTTPHelper; import org.opensearch.security.user.AuthCredentials; @@ -67,12 +65,11 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public Optional reRequestAuthentication(final AuthCredentials creds) { - return new SecurityResponse.Builder() - .code(RestStatus.UNAUTHORIZED) - .body("Unauthorized") - .header("WWW-Authenticate", "Basic realm=\"OpenSearch Security\"") - .buildAsOptional(); + public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { + final BytesRestResponse wwwAuthenticateResponse = new BytesRestResponse(RestStatus.UNAUTHORIZED, "Unauthorized"); + wwwAuthenticateResponse.addHeader("WWW-Authenticate", "Basic realm=\"OpenSearch Security\""); + channel.sendResponse(wwwAuthenticateResponse); + return true; } @Override diff --git a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java index c955af72e1..03221e810b 100644 --- a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java @@ -30,7 +30,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Optional; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; @@ -42,9 +41,9 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; +import org.opensearch.rest.RestChannel; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -99,8 +98,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public Optional reRequestAuthentication(AuthCredentials creds) { - return Optional.empty(); + public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { + return false; } @Override diff --git a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java index 15c3d79897..d835a6a081 100644 --- a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java @@ -27,7 +27,6 @@ package org.opensearch.security.http; import java.nio.file.Path; -import java.util.Optional; import java.util.regex.Pattern; import com.google.common.base.Predicates; @@ -41,7 +40,6 @@ import org.opensearch.rest.RestChannel; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -91,8 +89,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public Optional reRequestAuthentication(final AuthCredentials creds) { - return Optional.empty(); + public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { + return false; } @Override diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java index 3d03108c3c..2a47853ec2 100644 --- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java @@ -16,7 +16,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map.Entry; -import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -39,7 +38,6 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.KeyUtils; @@ -247,8 +245,8 @@ public Boolean isRequestAllowed(final SecurityRequest request) { } @Override - public Optional reRequestAuthentication(final AuthCredentials creds) { - return Optional.empty(); + public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { + return false; } @Override diff --git a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java index b510c10dcf..4231bf6c57 100644 --- a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java @@ -28,7 +28,6 @@ import java.nio.file.Path; import java.util.List; -import java.util.Optional; import java.util.Map.Entry; import com.google.common.base.Joiner; @@ -40,7 +39,6 @@ import org.opensearch.core.common.Strings; import org.opensearch.rest.RestChannel; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.http.HTTPProxyAuthenticator; import org.opensearch.security.user.AuthCredentials; @@ -87,8 +85,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public Optional reRequestAuthentication(final AuthCredentials creds) { - return Optional.empty(); + public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { + return false; } @Override From fa98ba90be3266ac1229daebae8753d8299d4fb0 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Sun, 1 Oct 2023 23:08:30 +0000 Subject: [PATCH 12/50] Cleaning up some Signed-off-by: Peter Nied --- .../security/filter/SecurityRestFilter.java | 79 ++++++++++++------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 52119e3c5c..2b7d101653 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -26,10 +26,12 @@ package org.opensearch.security.filter; +import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.BiConsumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -131,18 +133,29 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return (request, channel, client) -> { org.apache.logging.log4j.ThreadContext.clearAll(); final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel); - if (!checkAndAuthenticateRequest(securityRequest)) { - User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); - boolean isSuperAdminUser = userIsSuperAdmin(user, adminDNs); - if (isSuperAdminUser - || (whitelistingSettings.checkRequestIsAllowed(request, channel, client) - && allowlistingSettings.checkRequestIsAllowed(request, channel, client))) { - SecurityRequestFactory.from(request, channel); - if (isSuperAdminUser || authorizeRequest(original, securityRequest, user)) { - original.handleRequest(request, channel, client); - } + Optional failureResponse = checkAndAuthenticateRequest(securityRequest); + if (failureResponse.isEmpty()) { + final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); + if (userIsSuperAdmin(user, adminDNs)) { + original.handleRequest(request, channel, client); + } else { + + } + + if (whitelistingSettings.checkRequestIsAllowed(request, channel, client) + && allowlistingSettings.checkRequestIsAllowed(request, channel, client)) { + // TODO: ???? + authorizeRequest(original, securityRequest, user); } } + + failureResponse.ifPresent(response -> { + try { + response.act(channel, log, auditLog); + } catch (final IOException ioe) { + log.error(ioe); + } + }); }; } @@ -200,26 +213,32 @@ private boolean authorizeRequest(RestHandler original, SecurityRequest request, return true; } - public boolean checkAndAuthenticateRequest(SecurityRequest request) throws Exception { + @FunctionalInterface + public interface ResponseAction { + void act(RestChannel channel, Logger log, AuditLog auditLog) throws IOException; - RestChannel channel = request.getRestChannel(); + } + public Optional checkAndAuthenticateRequest(SecurityRequest request) throws Exception { threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, Origin.REST.toString()); if (HTTPHelper.containsBadHeader(request)) { final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); - log.error(exception.toString()); - auditLog.logBadHeaders(request); - channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, exception)); - return true; + + return Optional.of((channel, logger, auditLog) -> { + log.error(exception.toString()); + auditLog.logBadHeaders(request); + channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, exception)); + }); } if (SSLRequestHelper.containsBadHeader(threadContext, ConfigConstants.OPENDISTRO_SECURITY_CONFIG_PREFIX)) { final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); - log.error(exception.toString()); - auditLog.logBadHeaders(request); - channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, exception)); - return true; + return Optional.of((channel, logger, auditLog) -> { + log.error(exception.toString()); + auditLog.logBadHeaders(request); + channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, exception)); + }); } final SSLInfo sslInfo; @@ -236,23 +255,26 @@ public boolean checkAndAuthenticateRequest(SecurityRequest request) throws Excep threadContext.putTransient("_opendistro_security_ssl_cipher", sslInfo.getCipher()); } } catch (SSLPeerUnverifiedException e) { - log.error("No ssl info", e); - auditLog.logSSLException(request, e); - channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, e)); - return true; + return Optional.of((channel, logger, auditLog) -> { + log.error("No ssl info", e); + auditLog.logSSLException(request, e); + channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, e)); + }); } if (!compatConfig.restAuthEnabled()) { - return false; + // Authentication is disabled + return Optional.empty(); } Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; if (request.method() != Method.OPTIONS && !(HEALTH_SUFFIX.equals(suffix)) && !(WHO_AM_I_SUFFIX.equals(suffix))) { - if (!registry.authenticate(request, threadContext)) { + final Optional backAuthFailure = null;//registry.authenticate(request); + if (backAuthFailure.isPresent()) { // another roundtrip org.apache.logging.log4j.ThreadContext.remove("user"); - return true; + return backAuthFailure; } else { // make it possible to filter logs by username org.apache.logging.log4j.ThreadContext.put( @@ -262,7 +284,8 @@ public boolean checkAndAuthenticateRequest(SecurityRequest request) throws Excep } } - return false; + // User was authenticated + return Optional.empty(); } @Subscribe From 9844df9ba058ade6158c41c194a7997f182aaf35 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Mon, 2 Oct 2023 15:31:04 +0000 Subject: [PATCH 13/50] Mild switch to RequestChannel Signed-off-by: Peter Nied --- .../jwt/AbstractHTTPJwtAuthenticator.java | 20 +++--- .../auth/http/jwt/HTTPJwtAuthenticator.java | 22 +++--- .../kerberos/HTTPSpnegoAuthenticator.java | 38 +++++------ .../auth/http/saml/HTTPSamlAuthenticator.java | 36 ++++++---- .../security/auditlog/AuditLog.java | 14 ++-- .../auditlog/AuditLogSslExceptionHandler.java | 4 +- .../security/auditlog/NullAuditLog.java | 14 ++-- .../auditlog/impl/AbstractAuditLog.java | 16 ++--- .../security/auditlog/impl/AuditLogImpl.java | 14 ++-- .../security/auditlog/impl/AuditMessage.java | 4 +- .../security/auth/BackendRegistry.java | 34 +++++----- .../security/auth/HTTPAuthenticator.java | 9 ++- .../security/auth/UserInjector.java | 4 +- .../dlic/rest/api/AbstractApiAction.java | 4 +- .../rest/api/RestApiPrivilegesEvaluator.java | 4 +- ...quest.java => SecurityRequestChannel.java} | 13 ++-- .../filter/SecurityRequestFactory.java | 68 +++++++++++++++---- .../security/filter/SecurityRestFilter.java | 9 +-- .../security/http/HTTPBasicAuthenticator.java | 16 +++-- .../http/HTTPClientCertAuthenticator.java | 6 +- .../security/http/HTTPProxyAuthenticator.java | 7 +- .../http/OnBehalfOfAuthenticator.java | 13 ++-- .../security/http/RemoteIpDetector.java | 4 +- .../opensearch/security/http/XFFResolver.java | 4 +- .../proxy/HTTPExtendedProxyAuthenticator.java | 7 +- .../rest/SecurityConfigUpdateAction.java | 4 +- .../security/rest/SecurityWhoAmIAction.java | 4 +- .../security/ssl/SslExceptionHandler.java | 4 +- .../ssl/http/netty/ValidatingDispatcher.java | 4 +- .../ssl/rest/SecuritySSLInfoAction.java | 4 +- .../security/ssl/util/SSLRequestHelper.java | 4 +- .../security/support/HTTPHelper.java | 4 +- .../auditlog/helper/MockRestRequest.java | 4 +- .../security/auditlog/impl/AuditlogTest.java | 4 +- .../cache/DummyHTTPAuthenticator.java | 4 +- .../HTTPExtendedProxyAuthenticatorTest.java | 4 +- .../security/util/FakeRestRequest.java | 4 +- 37 files changed, 246 insertions(+), 186 deletions(-) rename src/main/java/org/opensearch/security/filter/{SecurityRequest.java => SecurityRequestChannel.java} (74%) diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java index 33a031a228..15e5d9546d 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java @@ -15,6 +15,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; +import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; @@ -22,6 +23,7 @@ import org.apache.cxf.rs.security.jose.jwt.JwtClaims; import org.apache.cxf.rs.security.jose.jwt.JwtToken; import org.apache.hc.core5.http.HttpHeaders; +import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -39,7 +41,7 @@ import org.opensearch.rest.RestChannel; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; public abstract class AbstractHTTPJwtAuthenticator implements HTTPAuthenticator { @@ -83,7 +85,7 @@ public AbstractHTTPJwtAuthenticator(Settings settings, Path configPath) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) + public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); @@ -101,7 +103,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final SecurityRequest request) throws OpenSearchSecurityException { + private AuthCredentials extractCredentials0(final SecurityRequestChannel request) throws OpenSearchSecurityException { String jwtString = getJwtTokenString(request); @@ -142,7 +144,7 @@ private AuthCredentials extractCredentials0(final SecurityRequest request) throw } - protected String getJwtTokenString(SecurityRequest request) { + protected String getJwtTokenString(SecurityRequestChannel request) { String jwtToken = request.header(jwtHeaderName); if (isDefaultAuthHeader && jwtToken != null && BASIC.matcher(jwtToken).matches()) { jwtToken = null; @@ -237,11 +239,11 @@ public String[] extractRoles(JwtClaims claims) { protected abstract KeyProvider initKeyProvider(Settings settings, Path configPath) throws Exception; @Override - public boolean reRequestAuthentication(RestChannel channel, AuthCredentials authCredentials) { - final BytesRestResponse wwwAuthenticateResponse = new BytesRestResponse(RestStatus.UNAUTHORIZED, ""); - wwwAuthenticateResponse.addHeader("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""); - channel.sendResponse(wwwAuthenticateResponse); - return true; + public boolean reRequestAuthentication(final SecurityRequestChannel request, AuthCredentials authCredentials) { + return request.completeWithResponse( + HttpStatus.SC_UNAUTHORIZED, + Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), + ""); } public String getRequiredAudience() { diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java index 2b13dea63e..2c60e96c48 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java @@ -15,6 +15,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; +import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; @@ -23,6 +24,7 @@ import io.jsonwebtoken.JwtParserBuilder; import io.jsonwebtoken.security.WeakKeyException; import org.apache.hc.core5.http.HttpHeaders; +import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -34,7 +36,7 @@ import org.opensearch.rest.RestChannel; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.KeyUtils; @@ -84,7 +86,7 @@ public HTTPJwtAuthenticator(final Settings settings, final Path configPath) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) + public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); @@ -102,7 +104,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final SecurityRequest request) { + private AuthCredentials extractCredentials0(final SecurityRequestChannel request) { if (jwtParser == null) { log.error("Missing Signing Key. JWT authentication will not work"); return null; @@ -172,11 +174,11 @@ private AuthCredentials extractCredentials0(final SecurityRequest request) { } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { - final BytesRestResponse wwwAuthenticateResponse = new BytesRestResponse(RestStatus.UNAUTHORIZED, ""); - wwwAuthenticateResponse.addHeader("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""); - channel.sendResponse(wwwAuthenticateResponse); - return true; + public boolean reRequestAuthentication(final SecurityRequestChannel channel, AuthCredentials creds) { + return channel.completeWithResponse( + HttpStatus.SC_UNAUTHORIZED, + Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), + ""); } @Override @@ -184,7 +186,7 @@ public String getType() { return "jwt"; } - protected String extractSubject(final Claims claims, final SecurityRequest request) { + protected String extractSubject(final Claims claims, final SecurityRequestChannel request) { String subject = claims.getSubject(); if (subjectKey != null) { // try to get roles from claims, first as Object to avoid having to catch the ExpectedTypeException @@ -208,7 +210,7 @@ protected String extractSubject(final Claims claims, final SecurityRequest reque } @SuppressWarnings("unchecked") - protected String[] extractRoles(final Claims claims, final SecurityRequest request) { + protected String[] extractRoles(final Claims claims, final SecurityRequestChannel request) { // no roles key specified if (rolesKey == null) { return new String[0]; diff --git a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java index af822e9c43..bf3002146a 100644 --- a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java @@ -22,13 +22,17 @@ import java.security.PrivilegedExceptionAction; import java.util.Base64; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.login.LoginException; import com.google.common.base.Strings; + +import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.ietf.jgss.GSSContext; @@ -52,12 +56,11 @@ import org.opensearch.rest.RestChannel; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; public class HTTPSpnegoAuthenticator implements HTTPAuthenticator { - private static final String EMPTY_STRING = ""; private static final Oid[] KRB_OIDS = new Oid[] { KrbConstants.SPNEGO, KrbConstants.KRB5MECH }; protected final Logger log = LogManager.getLogger(this.getClass()); @@ -171,7 +174,7 @@ public Void run() { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) { + public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext threadContext) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -188,7 +191,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final SecurityRequest request) { + private AuthCredentials extractCredentials0(final SecurityRequestChannel request) { if (acceptorPrincipal == null || acceptorKeyTabPath == null) { log.error("Missing acceptor principal or keytab configuration. Kerberos authentication will not work"); @@ -280,27 +283,24 @@ public GSSCredential run() throws GSSException { } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { - - final BytesRestResponse wwwAuthenticateResponse; - XContentBuilder response = getNegotiateResponseBody(); - - if (response != null) { - wwwAuthenticateResponse = new BytesRestResponse(RestStatus.UNAUTHORIZED, response); - } else { - wwwAuthenticateResponse = new BytesRestResponse(RestStatus.UNAUTHORIZED, EMPTY_STRING); + public boolean reRequestAuthentication(final SecurityRequestChannel request, AuthCredentials creds) { + String responseBody = ""; + final String negotiateResponseBody = getNegotiateResponseBody(); + if (negotiateResponseBody != null) { + responseBody = negotiateResponseBody; } + final Map headers = new HashMap<>(); if (creds == null || creds.getNativeCredentials() == null) { - wwwAuthenticateResponse.addHeader("WWW-Authenticate", "Negotiate"); + headers.put("WWW-Authenticate", "Negotiate"); } else { - wwwAuthenticateResponse.addHeader( + headers.put( "WWW-Authenticate", "Negotiate " + Base64.getEncoder().encodeToString((byte[]) creds.getNativeCredentials()) ); } - channel.sendResponse(wwwAuthenticateResponse); - return true; + + return request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, headers, responseBody); } @Override @@ -372,7 +372,7 @@ private static String getUsernameFromGSSContext(final GSSContext gssContext, fin return null; } - private XContentBuilder getNegotiateResponseBody() { + private String getNegotiateResponseBody() { try { XContentBuilder negotiateResponseBody = XContentFactory.jsonBuilder(); negotiateResponseBody.startObject(); @@ -384,7 +384,7 @@ private XContentBuilder getNegotiateResponseBody() { negotiateResponseBody.endObject(); negotiateResponseBody.endObject(); negotiateResponseBody.endObject(); - return negotiateResponseBody; + return negotiateResponseBody.toString(); } catch (Exception ex) { log.error("Can't construct response body", ex); return null; 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 27a7dd10f7..b8be0c5051 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 @@ -18,6 +18,7 @@ import java.security.PrivateKey; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -35,6 +36,7 @@ import net.shibboleth.utilities.java.support.xml.BasicParserPool; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.cxf.rs.security.jose.jwk.JsonWebKey; +import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensaml.core.config.InitializationException; @@ -61,7 +63,8 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.Destroyable; import org.opensearch.security.auth.HTTPAuthenticator; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.PemKeyReader; import org.opensearch.security.user.AuthCredentials; @@ -150,7 +153,7 @@ public HTTPSamlAuthenticator(final Settings settings, final Path configPath) { } @Override - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) + public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext threadContext) throws OpenSearchSecurityException { Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; @@ -173,23 +176,28 @@ public String getType() { } @Override - public boolean reRequestAuthentication(RestChannel restChannel, AuthCredentials authCredentials) { + public boolean reRequestAuthentication(final SecurityRequestChannel request, final AuthCredentials authCredentials) { try { - RestRequest restRequest = restChannel.request(); - Matcher matcher = PATTERN_PATH_PREFIX.matcher(restRequest.path()); + Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; - if (API_AUTHTOKEN_SUFFIX.equals(suffix) && this.authTokenProcessorHandler.handle(restRequest, restChannel)) { - return true; + + if (request instanceof SecurityRestRequest) { + final SecurityRestRequest securityRequestChannel = (SecurityRestRequest)request; + final RestRequest restRequest = securityRequestChannel.breakEncapulation().v1(); + final RestChannel channel = securityRequestChannel.breakEncapulation().v2(); + // TODO: This codebase REQUIRES the body of the request, seems like we need to escape the SecurityRequestChannel + if (API_AUTHTOKEN_SUFFIX.equals(suffix) && this.authTokenProcessorHandler.handle(restRequest, channel)) { + return true; + } + } else { + // If the request is not SecurityRestRequest type, we could not read the body to process the response, this + // means were are in a potential exit early flow + return false; } Saml2Settings saml2Settings = this.saml2SettingsProvider.getCached(); - BytesRestResponse authenticateResponse = new BytesRestResponse(RestStatus.UNAUTHORIZED, ""); - - authenticateResponse.addHeader("WWW-Authenticate", getWwwAuthenticateHeader(saml2Settings)); - - restChannel.sendResponse(authenticateResponse); - return true; + return request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", getWwwAuthenticateHeader(saml2Settings)), ""); } catch (Exception e) { log.error("Error in reRequestAuthentication()", e); return false; @@ -400,7 +408,7 @@ String buildLogoutUrl(AuthCredentials authCredentials) { } - private void initLogoutUrl(SecurityRequest restRequest, ThreadContext threadContext, AuthCredentials authCredentials) { + private void initLogoutUrl(SecurityRequestChannel restRequest, ThreadContext threadContext, AuthCredentials authCredentials) { threadContext.putTransient(ConfigConstants.SSO_LOGOUT_URL, buildLogoutUrl(authCredentials)); } diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLog.java b/src/main/java/org/opensearch/security/auditlog/AuditLog.java index 997b9e4b87..d861af14bd 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLog.java @@ -37,21 +37,21 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; public interface AuditLog extends Closeable { // login - void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request); + void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request); - void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request); + void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request); // privs - void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request); + void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequestChannel request); - void logGrantedPrivileges(String effectiveUser, SecurityRequest request); + void logGrantedPrivileges(String effectiveUser, SecurityRequestChannel request); void logMissingPrivileges(String privilege, TransportRequest request, Task task); @@ -63,13 +63,13 @@ public interface AuditLog extends Closeable { // spoof void logBadHeaders(TransportRequest request, String action, Task task); - void logBadHeaders(SecurityRequest request); + void logBadHeaders(SecurityRequestChannel request); void logSecurityIndexAttempt(TransportRequest request, String action, Task task); void logSSLException(TransportRequest request, Throwable t, String action, Task task); - void logSSLException(SecurityRequest request, Throwable t); + void logSSLException(SecurityRequestChannel request, Throwable t); void logDocumentRead(String index, String id, ShardId shardId, Map fieldNameValues); diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java b/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java index a794be3a2c..df96400f96 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLogSslExceptionHandler.java @@ -27,7 +27,7 @@ package org.opensearch.security.auditlog; import org.opensearch.OpenSearchException; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.ssl.SslExceptionHandler; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; @@ -42,7 +42,7 @@ public AuditLogSslExceptionHandler(final AuditLog auditLog) { } @Override - public void logError(Throwable t, SecurityRequest request, int type) { + public void logError(Throwable t, SecurityRequestChannel request, int type) { switch (type) { case 0: auditLog.logSSLException(request, t); diff --git a/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java b/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java index 1ac4492a94..440a2eafd5 100644 --- a/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java @@ -37,7 +37,7 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; @@ -49,12 +49,12 @@ public void close() throws IOException { } @Override - public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { + public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request) { // noop, intentionally left empty } @Override - public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { + public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request) { // noop, intentionally left empty } @@ -79,7 +79,7 @@ public void logBadHeaders(TransportRequest request, String action, Task task) { } @Override - public void logBadHeaders(SecurityRequest request) { + public void logBadHeaders(SecurityRequestChannel request) { // noop, intentionally left empty } @@ -94,17 +94,17 @@ public void logSSLException(TransportRequest request, Throwable t, String action } @Override - public void logSSLException(SecurityRequest request, Throwable t) { + public void logSSLException(SecurityRequestChannel request, Throwable t) { // noop, intentionally left empty } @Override - public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request) { + public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequestChannel request) { // noop, intentionally left empty } @Override - public void logGrantedPrivileges(String effectiveUser, SecurityRequest request) { + public void logGrantedPrivileges(String effectiveUser, SecurityRequestChannel request) { // noop, intentionally left empty } diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java index 2813f82e98..a3983c11e3 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java @@ -65,7 +65,7 @@ import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; import org.opensearch.security.dlic.rest.support.Utils; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.Base64Helper; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.User; @@ -139,7 +139,7 @@ public ComplianceConfig getComplianceConfig() { } @Override - public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { + public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request) { if (!checkRestFilter(AuditCategory.FAILED_LOGIN, effectiveUser, request)) { return; @@ -157,7 +157,7 @@ public void logFailedLogin(String effectiveUser, boolean securityadmin, String i } @Override - public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { + public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request) { if (!checkRestFilter(AuditCategory.AUTHENTICATED, effectiveUser, request)) { return; @@ -174,7 +174,7 @@ public void logSucceededLogin(String effectiveUser, boolean securityadmin, Strin } @Override - public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request) { + public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequestChannel request) { if (!checkRestFilter(AuditCategory.MISSING_PRIVILEGES, effectiveUser, request)) { return; } @@ -189,7 +189,7 @@ public void logMissingPrivileges(String privilege, String effectiveUser, Securit } @Override - public void logGrantedPrivileges(String effectiveUser, SecurityRequest request) { + public void logGrantedPrivileges(String effectiveUser, SecurityRequestChannel request) { if (!checkRestFilter(AuditCategory.GRANTED_PRIVILEGES, effectiveUser, request)) { return; } @@ -348,7 +348,7 @@ public void logBadHeaders(TransportRequest request, String action, Task task) { } @Override - public void logBadHeaders(SecurityRequest request) { + public void logBadHeaders(SecurityRequestChannel request) { if (!checkRestFilter(AuditCategory.BAD_HEADERS, getUser(), request)) { return; @@ -437,7 +437,7 @@ public void logSSLException(TransportRequest request, Throwable t, String action } @Override - public void logSSLException(SecurityRequest request, Throwable t) { + public void logSSLException(SecurityRequestChannel request, Throwable t) { if (!checkRestFilter(AuditCategory.SSL_EXCEPTION, getUser(), request)) { return; @@ -896,7 +896,7 @@ private boolean checkComplianceFilter( } @VisibleForTesting - boolean checkRestFilter(final AuditCategory category, final String effectiveUser, SecurityRequest request) { + boolean checkRestFilter(final AuditCategory category, final String effectiveUser, SecurityRequestChannel request) { final boolean isTraceEnabled = log.isTraceEnabled(); if (isTraceEnabled) { log.trace( diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java index 8da4b13d4c..1677ebb86a 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java @@ -33,7 +33,7 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.auditlog.routing.AuditMessageRouter; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportRequest; @@ -131,28 +131,28 @@ protected void save(final AuditMessage msg) { } @Override - public void logFailedLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequest request) { + public void logFailedLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequestChannel request) { if (enabled) { super.logFailedLogin(effectiveUser, securityAdmin, initiatingUser, request); } } @Override - public void logSucceededLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequest request) { + public void logSucceededLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequestChannel request) { if (enabled) { super.logSucceededLogin(effectiveUser, securityAdmin, initiatingUser, request); } } @Override - public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request) { + public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequestChannel request) { if (enabled) { super.logMissingPrivileges(privilege, effectiveUser, request); } } @Override - public void logGrantedPrivileges(String effectiveUser, SecurityRequest request) { + public void logGrantedPrivileges(String effectiveUser, SecurityRequestChannel request) { if (enabled) { super.logGrantedPrivileges(effectiveUser, request); } @@ -187,7 +187,7 @@ public void logBadHeaders(TransportRequest request, String action, Task task) { } @Override - public void logBadHeaders(SecurityRequest request) { + public void logBadHeaders(SecurityRequestChannel request) { if (enabled) { super.logBadHeaders(request); } @@ -208,7 +208,7 @@ public void logSSLException(TransportRequest request, Throwable t, String action } @Override - public void logSSLException(SecurityRequest request, Throwable t) { + public void logSSLException(SecurityRequestChannel request, Throwable t) { if (enabled) { super.logSSLException(request, t); } diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java index b4f35ef90f..983f841cad 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java @@ -48,7 +48,7 @@ import org.opensearch.security.auditlog.AuditLog.Origin; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.dlic.rest.support.Utils; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.support.WildcardMatcher; @@ -370,7 +370,7 @@ void addRestMethod(final RestRequest.Method method) { } } - void addRestRequestInfo(final SecurityRequest request, final AuditConfig.Filter filter) { + void addRestRequestInfo(final SecurityRequestChannel request, final AuditConfig.Filter filter) { if (request != null) { final String path = request.path().toString(); addPath(path); diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index cdfa74655c..9aaac7751e 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -43,6 +43,8 @@ import com.google.common.cache.RemovalListener; import com.google.common.cache.RemovalNotification; import com.google.common.collect.Multimap; + +import org.apache.hc.core5.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.greenrobot.eventbus.Subscribe; @@ -57,7 +59,7 @@ import org.opensearch.security.auth.blocking.ClientBlockRegistry; import org.opensearch.security.auth.internal.NoOpAuthenticationBackend; import org.opensearch.security.configuration.AdminDNs; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.http.OnBehalfOfAuthenticator; import org.opensearch.security.http.XFFResolver; import org.opensearch.security.securityconf.DynamicConfigModel; @@ -184,7 +186,7 @@ public void onDynamicConfigModelChanged(DynamicConfigModel dcm) { * @return The authenticated user, null means another roundtrip * @throws OpenSearchSecurityException */ - public boolean authenticate(final SecurityRequest request, final ThreadContext _DO_NOT_USE) { + public boolean authenticate(final SecurityRequestChannel request, final ThreadContext _DO_NOT_USE) { final boolean isDebugEnabled = log.isDebugEnabled(); final boolean isBlockedBasedOnAddress = request.getRemoteAddress() .map(InetSocketAddress::getAddress) @@ -195,7 +197,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ log.debug("Rejecting REST request because of blocked address: {}", request.getRemoteAddress().orElse(null)); } - request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, "Authentication finally failed")); + request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, null, "Authentication finally failed"); return false; } @@ -216,8 +218,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); - request.getRestChannel() - .sendResponse(new BytesRestResponse(RestStatus.SERVICE_UNAVAILABLE, "OpenSearch Security not initialized.")); + request.completeWithResponse(HttpStatus.SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized."); return false; } @@ -283,12 +284,11 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ continue; } - if (authDomain.isChallenge() && httpAuthenticator.reRequestAuthentication(request.getRestChannel(), null)) { + if (authDomain.isChallenge() && httpAuthenticator.reRequestAuthentication(request, null)) { auditLog.logFailedLogin("", false, null, request); if (isTraceEnabled) { log.trace("No 'Authorization' header, send 401 and 'WWW-Authenticate Basic'"); } - return false; } else { // no reRequest possible if (isTraceEnabled) { @@ -300,7 +300,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ org.apache.logging.log4j.ThreadContext.put("user", ac.getUsername()); if (!ac.isComplete()) { // credentials found in request but we need another client challenge - if (httpAuthenticator.reRequestAuthentication(request.getRestChannel(), ac)) { + if (httpAuthenticator.reRequestAuthentication(request, ac)) { // auditLog.logFailedLogin(ac.getUsername()+" ", request); --noauditlog return false; } else { @@ -339,12 +339,10 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ if (adminDns.isAdmin(authenticatedUser)) { log.error("Cannot authenticate rest user because admin user is not permitted to login via HTTP"); auditLog.logFailedLogin(authenticatedUser.getName(), true, null, request); - request.getRestChannel() - .sendResponse( - new BytesRestResponse( - RestStatus.FORBIDDEN, - "Cannot authenticate user because admin user is not permitted to login via HTTP" - ) + request.completeWithResponse( + HttpStatus.SC_FORBIDDEN, + null, + "Cannot authenticate user because admin user is not permitted to login via HTTP" ); return false; } @@ -395,7 +393,7 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ log.debug("Rerequest with {}", firstChallengingHttpAuthenticator.getClass()); } - if (firstChallengingHttpAuthenticator.reRequestAuthentication(request.getRestChannel(), null)) { + if (firstChallengingHttpAuthenticator.reRequestAuthentication(request, null)) { if (isDebugEnabled) { log.debug("Rerequest {} failed", firstChallengingHttpAuthenticator.getClass()); } @@ -419,14 +417,14 @@ public boolean authenticate(final SecurityRequest request, final ThreadContext _ notifyIpAuthFailureListeners(request, authCredenetials); - request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, "Authentication finally failed")); + request.completeWithResponse(org.apache.http.HttpStatus.SC_UNAUTHORIZED, null, "Authentication finally failed"); return false; } return authenticated; } - private void notifyIpAuthFailureListeners(SecurityRequest request, AuthCredentials authCredentials) { + private void notifyIpAuthFailureListeners(SecurityRequestChannel request, AuthCredentials authCredentials) { notifyIpAuthFailureListeners(request.getRemoteAddress().map(InetSocketAddress::getAddress).orElse(null), authCredentials, request); } @@ -574,7 +572,7 @@ public User call() throws Exception { } } - private User impersonate(final SecurityRequest request, final User originalUser) throws OpenSearchSecurityException { + private User impersonate(final SecurityRequestChannel request, final User originalUser) throws OpenSearchSecurityException { final String impersonatedUserHeader = request.header("opendistro_security_impersonate_as"); diff --git a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java index 1ddc006445..4946982396 100644 --- a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java +++ b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java @@ -28,9 +28,8 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; /** @@ -68,7 +67,7 @@ public interface HTTPAuthenticator { * If the authentication flow needs another roundtrip with the request originator do not mark it as complete. * @throws OpenSearchSecurityException */ - AuthCredentials extractCredentials(SecurityRequest request, ThreadContext context) throws OpenSearchSecurityException; + AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) throws OpenSearchSecurityException; /** * If the {@code extractCredentials()} call was not successful or the authentication flow needs another roundtrip this method @@ -77,10 +76,10 @@ public interface HTTPAuthenticator { * If the custom HTTP authenticator does support re-request authentication or supports authentication flows with multiple roundtrips * then the response should be sent (through the channel) and true must be returned. * - * @param channel The rest channel to sent back the response via {@code channel.sendResponse()} + * @param channel The channel to sent back the response * @param credentials The credentials from the prior authentication attempt * @return false if re-request is not supported/necessary, true otherwise. * If true is returned {@code channel.sendResponse()} must be called so that the request completes. */ - boolean reRequestAuthentication(final RestChannel channel, AuthCredentials credentials); + boolean reRequestAuthentication(final SecurityRequestChannel channel, AuthCredentials credentials); } diff --git a/src/main/java/org/opensearch/security/auth/UserInjector.java b/src/main/java/org/opensearch/security/auth/UserInjector.java index 79b84fe237..57bc86e270 100644 --- a/src/main/java/org/opensearch/security/auth/UserInjector.java +++ b/src/main/java/org/opensearch/security/auth/UserInjector.java @@ -39,7 +39,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.common.transport.TransportAddress; import org.opensearch.security.auditlog.AuditLog; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.http.XFFResolver; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.SecurityUtils; @@ -172,7 +172,7 @@ public InjectedUser getInjectedUser() { return injectedUser; } - boolean injectUser(SecurityRequest request) { + boolean injectUser(SecurityRequestChannel request) { InjectedUser injectedUser = getInjectedUser(); if (injectedUser == null) { return false; diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index 5f0ea37ac3..1e374ca303 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -49,7 +49,7 @@ import org.opensearch.security.dlic.rest.validation.EndpointValidator; import org.opensearch.security.dlic.rest.validation.RequestContentValidator; import org.opensearch.security.dlic.rest.validation.ValidationResult; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.securityconf.DynamicConfigFactory; import org.opensearch.security.securityconf.impl.CType; @@ -538,7 +538,7 @@ public void onFailure(Exception e) { protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { // Fix channel ordering - final SecurityRequest securityRequest = SecurityRequestFactory.from(request, null); + final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, null); // consume all parameters first so we can return a correct HTTP status, // not 400 diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java index 45a9920443..4a427245a6 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java @@ -35,7 +35,7 @@ import org.opensearch.rest.RestRequest.Method; import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.dlic.rest.support.Utils; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.privileges.PrivilegesEvaluator; import org.opensearch.security.ssl.transport.PrincipalExtractor; @@ -449,7 +449,7 @@ private String checkAdminCertBasedAccessPermissions(RestRequest request) throws // Certificate based access, Check if we have an admin TLS certificate // TODO: Doesn't seem like the channel is needed here, but need to make sure this works correctly. - final SecurityRequest securityRequest = SecurityRequestFactory.from(request, null); + final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, null); SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java similarity index 74% rename from src/main/java/org/opensearch/security/filter/SecurityRequest.java rename to src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java index 69d2e0be4d..1059226a40 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java @@ -8,18 +8,22 @@ import javax.net.ssl.SSLEngine; -import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; -public interface SecurityRequest { +/** + * When a request is recieved by the security plugin this governs getting information about the request as well as a way to complet + */ +public interface SecurityRequestChannel { + + public boolean hasCompleted(); + + public boolean completeWithResponse(final int statusCode, final Map headers, final String body); public Map> getHeaders(); public SSLEngine getSSLEngine(); - public RestChannel getRestChannel(); - public String path(); public Method method(); @@ -37,5 +41,6 @@ default public String header(final String headerName) { return headersMap.map(headers -> headers.get(headerName)).map(List::stream).flatMap(Stream::findFirst).orElse(null); } + public Map params(); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index 72727ff3bc..ebf9358f8b 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -4,9 +4,13 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; import javax.net.ssl.SSLEngine; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.common.collect.Tuple; import org.opensearch.http.netty4.Netty4HttpChannel; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; @@ -16,15 +20,19 @@ public class SecurityRequestFactory { - public static SecurityRequest from() { + public static SecurityRequestChannel from() { return null; } - public static SecurityRequest from(final RestRequest request, final RestChannel channel) { + public static SecurityRequestChannel from(final RestRequest request, final RestChannel channel) { return new SecurityRestRequest(request, channel); } - protected static class SecurityRestRequest implements SecurityRequest { + public static class SecurityRestRequest implements SecurityRequestChannel { + + private final Logger log = LogManager.getLogger(SecurityRestRequest.class); + + private AtomicBoolean hasCompleted = new AtomicBoolean(false); private final RestRequest underlyingRequest; private final RestChannel underlyingChannel; @@ -55,11 +63,6 @@ public SSLEngine getSSLEngine() { return sslhandler != null ? sslhandler.engine() : null; } - @Override - public RestChannel getRestChannel() { - return underlyingChannel; - } - @Override public String path() { return underlyingRequest.path(); @@ -94,9 +97,34 @@ public Optional asRestRequest() { public Map params() { return underlyingRequest.params(); } + + @Override + public boolean hasCompleted() { + return hasCompleted.get(); + } + + @Override + public boolean completeWithResponse(int statusCode, Map headers, String body) { + try { + underlyingChannel.sendResponse(null); + return true; + } catch (final Exception e){ + log.error("Error when attempting to send response", e); + throw new RuntimeException(e); + } finally { + hasCompleted.set(true); + } + } + + /** + * Breaks the encapustion of the interface to get access to the underlying RestRequest / RestChannel. + */ + public Tuple breakEncapulation() { + return Tuple.tuple(underlyingRequest, underlyingChannel); + } } - protected static class NettyRequest implements SecurityRequest { + protected static class NettyRequest implements SecurityRequestChannel { @Override public Map> getHeaders() { // TODO Auto-generated method stub @@ -109,11 +137,11 @@ public SSLEngine getSSLEngine() { throw new UnsupportedOperationException("Unimplemented method 'getSSLEngine'"); } - @Override - public RestChannel getRestChannel() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getRestChannel'"); - } + // @Override + // public RestChannel getRestChannel() { + // // TODO Auto-generated method stub + // throw new UnsupportedOperationException("Unimplemented method 'getRestChannel'"); + // } @Override public String path() { @@ -156,5 +184,17 @@ public Map params() { // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'params'"); } + + @Override + public boolean hasCompleted() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'hasCompleted'"); + } + + @Override + public boolean completeWithResponse(int statusCode, Map headers, String body) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'completeWithResponse'"); + } } } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 2b7d101653..0bbc17840e 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -37,6 +37,7 @@ import javax.net.ssl.SSLPeerUnverifiedException; +import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.greenrobot.eventbus.Subscribe; @@ -132,7 +133,7 @@ public SecurityRestFilter( public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return (request, channel, client) -> { org.apache.logging.log4j.ThreadContext.clearAll(); - final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel); + final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); Optional failureResponse = checkAndAuthenticateRequest(securityRequest); if (failureResponse.isEmpty()) { final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); @@ -166,7 +167,7 @@ private boolean userIsSuperAdmin(User user, AdminDNs adminDNs) { return user != null && adminDNs.isAdmin(user); } - private boolean authorizeRequest(RestHandler original, SecurityRequest request, User user) { + private boolean authorizeRequest(RestHandler original, SecurityRequestChannel request, User user) { List restRoutes = original.routes(); Optional handler = restRoutes.stream() @@ -204,7 +205,7 @@ private boolean authorizeRequest(RestHandler original, SecurityRequest request, err = String.format("no permissions for %s and %s", pres.getMissingPrivileges(), user); } log.debug(err); - request.getRestChannel().sendResponse(new BytesRestResponse(RestStatus.UNAUTHORIZED, err)); + request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, null, err); return false; } } @@ -219,7 +220,7 @@ public interface ResponseAction { } - public Optional checkAndAuthenticateRequest(SecurityRequest request) throws Exception { + public Optional checkAndAuthenticateRequest(SecurityRequestChannel request) throws Exception { threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, Origin.REST.toString()); if (HTTPHelper.containsBadHeader(request)) { diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index ae393e5028..6c67050ecc 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -27,7 +27,9 @@ package org.opensearch.security.http; import java.nio.file.Path; +import java.util.Map; +import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -37,7 +39,7 @@ import org.opensearch.rest.RestChannel; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.HTTPHelper; import org.opensearch.security.user.AuthCredentials; @@ -51,7 +53,7 @@ public HTTPBasicAuthenticator(final Settings settings, final Path configPath) { } @Override - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) { + public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext threadContext) { final boolean forceLogin = Boolean.getBoolean(request.params().get("force_login")); @@ -65,11 +67,11 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { - final BytesRestResponse wwwAuthenticateResponse = new BytesRestResponse(RestStatus.UNAUTHORIZED, "Unauthorized"); - wwwAuthenticateResponse.addHeader("WWW-Authenticate", "Basic realm=\"OpenSearch Security\""); - channel.sendResponse(wwwAuthenticateResponse); - return true; + public boolean reRequestAuthentication(final SecurityRequestChannel request, AuthCredentials creds) { + return request.completeWithResponse( + HttpStatus.SC_UNAUTHORIZED, + Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), + ""); } @Override diff --git a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java index 03221e810b..5be9b23739 100644 --- a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java @@ -43,7 +43,7 @@ import org.opensearch.core.common.Strings; import org.opensearch.rest.RestChannel; import org.opensearch.security.auth.HTTPAuthenticator; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -57,7 +57,7 @@ public HTTPClientCertAuthenticator(final Settings settings, final Path configPat } @Override - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) { + public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext threadContext) { final String principal = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_SSL_PRINCIPAL); @@ -98,7 +98,7 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { + public boolean reRequestAuthentication(final SecurityRequestChannel response, AuthCredentials creds) { return false; } diff --git a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java index d835a6a081..c9c7309ce1 100644 --- a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java @@ -39,7 +39,7 @@ import org.opensearch.core.common.Strings; import org.opensearch.rest.RestChannel; import org.opensearch.security.auth.HTTPAuthenticator; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -56,7 +56,7 @@ public HTTPProxyAuthenticator(Settings settings, final Path configPath) { } @Override - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) { + public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) { if (context.getTransient(ConfigConstants.OPENDISTRO_SECURITY_XFF_DONE) != Boolean.TRUE) { throw new OpenSearchSecurityException("xff not done"); @@ -89,7 +89,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { + public boolean reRequestAuthentication(final +SecurityRequestChannel response, AuthCredentials creds) { return false; } diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java index 2a47853ec2..2033054c3e 100644 --- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java @@ -37,7 +37,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.KeyUtils; @@ -122,7 +122,7 @@ private String[] extractBackendRolesFromClaims(Claims claims) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) + public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); @@ -140,7 +140,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final SecurityRequest request) { + private AuthCredentials extractCredentials0(final SecurityRequestChannel request) { if (!oboEnabled) { log.error("On-behalf-of authentication is disabled"); return null; @@ -204,7 +204,7 @@ private AuthCredentials extractCredentials0(final SecurityRequest request) { return null; } - private String extractJwtFromHeader(SecurityRequest request) { + private String extractJwtFromHeader(SecurityRequestChannel request) { String jwtToken = request.header(HttpHeaders.AUTHORIZATION); if (jwtToken == null || jwtToken.isEmpty()) { @@ -232,7 +232,7 @@ private void logDebug(String message, Object... args) { } } - public Boolean isRequestAllowed(final SecurityRequest request) { + public Boolean isRequestAllowed(final SecurityRequestChannel request) { Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; if (request.method() == RestRequest.Method.POST && ON_BEHALF_OF_SUFFIX.equals(suffix) @@ -245,7 +245,8 @@ public Boolean isRequestAllowed(final SecurityRequest request) { } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { + public boolean reRequestAuthentication(final +SecurityRequestChannel response, AuthCredentials creds) { return false; } diff --git a/src/main/java/org/opensearch/security/http/RemoteIpDetector.java b/src/main/java/org/opensearch/security/http/RemoteIpDetector.java index 7b76a82c42..2aba89f79b 100644 --- a/src/main/java/org/opensearch/security/http/RemoteIpDetector.java +++ b/src/main/java/org/opensearch/security/http/RemoteIpDetector.java @@ -53,7 +53,7 @@ import org.apache.logging.log4j.Logger; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.ConfigConstants; final class RemoteIpDetector { @@ -116,7 +116,7 @@ public String getRemoteIpHeader() { return remoteIpHeader; } - String detect(SecurityRequest request, ThreadContext threadContext) { + String detect(SecurityRequestChannel request, ThreadContext threadContext) { final String originalRemoteAddr = request.getRemoteAddress() .map(InetSocketAddress::getAddress) diff --git a/src/main/java/org/opensearch/security/http/XFFResolver.java b/src/main/java/org/opensearch/security/http/XFFResolver.java index 68fe0307cd..90e373a874 100644 --- a/src/main/java/org/opensearch/security/http/XFFResolver.java +++ b/src/main/java/org/opensearch/security/http/XFFResolver.java @@ -35,7 +35,7 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.core.common.transport.TransportAddress; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.securityconf.DynamicConfigModel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.threadpool.ThreadPool; @@ -52,7 +52,7 @@ public XFFResolver(final ThreadPool threadPool) { this.threadContext = threadPool.getThreadContext(); } - public TransportAddress resolve(final SecurityRequest request) throws OpenSearchSecurityException { + public TransportAddress resolve(final SecurityRequestChannel request) throws OpenSearchSecurityException { final boolean isTraceEnabled = log.isTraceEnabled(); if (isTraceEnabled) { log.trace("resolve {}", request.getRemoteAddress().orElse(null)); diff --git a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java index 4231bf6c57..cd08b4ca95 100644 --- a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java @@ -38,7 +38,7 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; import org.opensearch.rest.RestChannel; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.http.HTTPProxyAuthenticator; import org.opensearch.security.user.AuthCredentials; @@ -55,7 +55,7 @@ public HTTPExtendedProxyAuthenticator(Settings settings, final Path configPath) } @Override - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) { + public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) { AuthCredentials credentials = super.extractCredentials(request, context); if (credentials == null) { return null; @@ -85,7 +85,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final RestChannel channel, AuthCredentials creds) { + public boolean reRequestAuthentication(final +SecurityRequestChannel response, AuthCredentials creds) { return false; } diff --git a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java index 05f4d7ef20..c87e421f44 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java @@ -29,7 +29,7 @@ import org.opensearch.security.action.configupdate.ConfigUpdateAction; import org.opensearch.security.action.configupdate.ConfigUpdateRequest; import org.opensearch.security.configuration.AdminDNs; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; @@ -76,7 +76,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli String[] configTypes = request.paramAsStringArrayOrEmptyIfAll("config_types"); // TODO: Need to re-write with a RestChannelConsumer - final SecurityRequest securityRequest = SecurityRequestFactory.from(request, null); + final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, null); SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { diff --git a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java index a7f92f306b..bfc2b99a0e 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java @@ -32,7 +32,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.configuration.AdminDNs; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; @@ -99,7 +99,7 @@ public void accept(RestChannel channel) throws Exception { BytesRestResponse response = null; try { - final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel); + final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); ; SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); diff --git a/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java b/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java index be120b2acd..73f4aceb4d 100644 --- a/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java +++ b/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java @@ -18,7 +18,7 @@ package org.opensearch.security.ssl; import org.opensearch.rest.RestRequest; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; @@ -36,7 +36,7 @@ default void logError(Throwable t, final TransportRequest request, String action // no-op } - default void logError(Throwable t, SecurityRequest request, int type) { + default void logError(Throwable t, SecurityRequestChannel request, int type) { this.logError(t, request.asRestRequest().get(), type); } } diff --git a/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java b/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java index af17607468..91126d6596 100644 --- a/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java +++ b/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java @@ -33,7 +33,7 @@ import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.SslExceptionHandler; import org.opensearch.security.ssl.util.ExceptionUtils; @@ -85,7 +85,7 @@ protected void checkRequest(final RestRequest request, final RestChannel channel } try { - final SecurityRequest securityReqest = SecurityRequestFactory.from(request, channel); + final SecurityRequestChannel securityReqest = SecurityRequestFactory.from(request, channel); if (SSLRequestHelper.getSSLInfo(settings, configPath, securityReqest, null) == null) { logger.error("Not an SSL request"); throw new OpenSearchSecurityException("Not an SSL request", RestStatus.INTERNAL_SERVER_ERROR); diff --git a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java index 982fea2d5d..863d1dbab2 100644 --- a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java +++ b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java @@ -39,7 +39,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; import org.opensearch.core.rest.RestStatus; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.SecurityKeyStore; import org.opensearch.security.ssl.transport.PrincipalExtractor; @@ -86,7 +86,7 @@ public void accept(RestChannel channel) throws Exception { BytesRestResponse response = null; try { - final SecurityRequest securityRequest = SecurityRequestFactory.from(request, channel); + final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); ; SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); X509Certificate[] certs = sslInfo == null ? null : sslInfo.getX509Certs(); diff --git a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java index df92bfc703..3d896fe0b7 100644 --- a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java +++ b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java @@ -44,7 +44,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.env.Environment; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.transport.PrincipalExtractor.Type; @@ -119,7 +119,7 @@ public String toString() { public static SSLInfo getSSLInfo( final Settings settings, final Path configPath, - final SecurityRequest request, + final SecurityRequestChannel request, PrincipalExtractor principalExtractor ) throws SSLPeerUnverifiedException { final SSLEngine engine = request.getSSLEngine(); diff --git a/src/main/java/org/opensearch/security/support/HTTPHelper.java b/src/main/java/org/opensearch/security/support/HTTPHelper.java index 10763ce35b..8e2de6daa6 100644 --- a/src/main/java/org/opensearch/security/support/HTTPHelper.java +++ b/src/main/java/org/opensearch/security/support/HTTPHelper.java @@ -33,7 +33,7 @@ import org.apache.logging.log4j.Logger; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; public class HTTPHelper { @@ -86,7 +86,7 @@ public static AuthCredentials extractCredentials(String authorizationHeader, Log } } - public static boolean containsBadHeader(final SecurityRequest request) { + public static boolean containsBadHeader(final SecurityRequestChannel request) { final Map> headers; diff --git a/src/test/java/org/opensearch/security/auditlog/helper/MockRestRequest.java b/src/test/java/org/opensearch/security/auditlog/helper/MockRestRequest.java index 2679457864..80c8fd7b17 100644 --- a/src/test/java/org/opensearch/security/auditlog/helper/MockRestRequest.java +++ b/src/test/java/org/opensearch/security/auditlog/helper/MockRestRequest.java @@ -16,7 +16,7 @@ import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.rest.RestRequest; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; public class MockRestRequest extends RestRequest { @@ -47,7 +47,7 @@ public BytesReference content() { return null; } - public SecurityRequest asSecurityRequest() { + public SecurityRequestChannel asSecurityRequest() { return SecurityRequestFactory.from(this, null); } } diff --git a/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java b/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java index 1d31d3c425..935fb924a3 100644 --- a/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java +++ b/src/test/java/org/opensearch/security/auditlog/impl/AuditlogTest.java @@ -24,7 +24,7 @@ import org.opensearch.security.auditlog.AuditTestUtils; import org.opensearch.security.auditlog.helper.RetrySink; import org.opensearch.security.auditlog.integration.TestAuditlogImpl; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.test.AbstractSecurityUnitTest; import org.opensearch.transport.TransportRequest; @@ -132,7 +132,7 @@ public void testRestFilterEnabledCheck() { final Settings settings = Settings.builder().put(ConfigConstants.OPENDISTRO_SECURITY_AUDIT_ENABLE_REST, false).build(); final AbstractAuditLog al = AuditTestUtils.createAuditLog(settings, null, null, AbstractSecurityUnitTest.MOCK_POOL, null, cs); for (AuditCategory category : AuditCategory.values()) { - Assert.assertFalse(al.checkRestFilter(category, "user", mock(SecurityRequest.class))); + Assert.assertFalse(al.checkRestFilter(category, "user", mock(SecurityRequestChannel.class))); } } diff --git a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java index 5651b25e8b..67bbc3879b 100644 --- a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java +++ b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java @@ -18,7 +18,7 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.RestChannel; import org.opensearch.security.auth.HTTPAuthenticator; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; public class DummyHTTPAuthenticator implements HTTPAuthenticator { @@ -33,7 +33,7 @@ public String getType() { } @Override - public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) + public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) throws OpenSearchSecurityException { count++; return new AuthCredentials("dummy").markComplete(); diff --git a/src/test/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticatorTest.java b/src/test/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticatorTest.java index 5a71c7ff7e..f7a2011a68 100644 --- a/src/test/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticatorTest.java +++ b/src/test/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticatorTest.java @@ -47,7 +47,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; import org.opensearch.core.rest.RestStatus; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -165,7 +165,7 @@ public boolean hasContent() { return false; } - public SecurityRequest asSecurityRequest() { + public SecurityRequestChannel asSecurityRequest() { return SecurityRequestFactory.from(this, null); } } diff --git a/src/test/java/org/opensearch/security/util/FakeRestRequest.java b/src/test/java/org/opensearch/security/util/FakeRestRequest.java index db7538bcdb..121ddf778e 100644 --- a/src/test/java/org/opensearch/security/util/FakeRestRequest.java +++ b/src/test/java/org/opensearch/security/util/FakeRestRequest.java @@ -18,7 +18,7 @@ import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.rest.RestRequest; -import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; public class FakeRestRequest extends RestRequest { @@ -119,7 +119,7 @@ private static Map> convert(Map headers) { return ret; } - public SecurityRequest asSecurityRequest() { + public SecurityRequestChannel asSecurityRequest() { return SecurityRequestFactory.from(this, null); } } From cafe1c79f1477c0b8b319b3769c467e768174ea9 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Mon, 2 Oct 2023 19:41:47 +0000 Subject: [PATCH 14/50] Handle unsupported scenarios Signed-off-by: Peter Nied --- .../auth/http/saml/HTTPSamlAuthenticator.java | 28 ++++++++++--------- .../filter/SecurityRequestFactory.java | 5 ++++ .../SecurityRequetChannelUnsupported.java | 6 ++++ 3 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java 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 b8be0c5051..a680b0b19a 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 @@ -65,6 +65,7 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; +import org.opensearch.security.filter.SecurityRequetChannelUnsupported; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.PemKeyReader; import org.opensearch.security.user.AuthCredentials; @@ -181,22 +182,23 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, fin Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; - if (request instanceof SecurityRestRequest) { - final SecurityRestRequest securityRequestChannel = (SecurityRestRequest)request; - final RestRequest restRequest = securityRequestChannel.breakEncapulation().v1(); - final RestChannel channel = securityRequestChannel.breakEncapulation().v2(); - // TODO: This codebase REQUIRES the body of the request, seems like we need to escape the SecurityRequestChannel - if (API_AUTHTOKEN_SUFFIX.equals(suffix) && this.authTokenProcessorHandler.handle(restRequest, channel)) { - return true; + if (API_AUTHTOKEN_SUFFIX.equals(suffix)) { + // Verficiation of SAML ASC endpoint only works with RestRequests + if (!(request instanceof SecurityRestRequest)) { + throw new SecurityRequetChannelUnsupported(); + } else { + final SecurityRestRequest securityRequestChannel = (SecurityRestRequest)request; + final RestRequest restRequest = securityRequestChannel.breakEncapulation().v1(); + final RestChannel channel = securityRequestChannel.breakEncapulation().v2(); + if (this.authTokenProcessorHandler.handle(restRequest, channel)) { + // The ACS response was accepted + securityRequestChannel.markCompleted(); + return true; + } } - } else { - // If the request is not SecurityRestRequest type, we could not read the body to process the response, this - // means were are in a potential exit early flow - return false; } - Saml2Settings saml2Settings = this.saml2SettingsProvider.getCached(); - + final Saml2Settings saml2Settings = this.saml2SettingsProvider.getCached(); return request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", getWwwAuthenticateHeader(saml2Settings)), ""); } catch (Exception e) { log.error("Error in reRequestAuthentication()", e); diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index ebf9358f8b..fcac866e6d 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -122,6 +122,11 @@ public boolean completeWithResponse(int statusCode, Map headers, public Tuple breakEncapulation() { return Tuple.tuple(underlyingRequest, underlyingChannel); } + + /** Marks a request completed */ + public void markCompleted() { + hasCompleted.set(true); + } } protected static class NettyRequest implements SecurityRequestChannel { diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java b/src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java new file mode 100644 index 0000000000..51934cc83c --- /dev/null +++ b/src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java @@ -0,0 +1,6 @@ +package org.opensearch.security.filter; + +/** Thrown when a security rest channel is not supported */ +public class SecurityRequetChannelUnsupported extends RuntimeException { + +} From 2beb434c9c19a4f2368484f08721d2b075f02a61 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Mon, 2 Oct 2023 21:22:14 +0000 Subject: [PATCH 15/50] Tests compile again Signed-off-by: Peter Nied --- .../security/auth/BackendRegistry.java | 23 ++-- .../security/filter/SecurityRestFilter.java | 82 +++++--------- .../http/saml/HTTPSamlAuthenticatorTest.java | 107 ++++++------------ .../cache/DummyHTTPAuthenticator.java | 3 +- 4 files changed, 75 insertions(+), 140 deletions(-) diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 9aaac7751e..cf89d1f874 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -186,7 +186,7 @@ public void onDynamicConfigModelChanged(DynamicConfigModel dcm) { * @return The authenticated user, null means another roundtrip * @throws OpenSearchSecurityException */ - public boolean authenticate(final SecurityRequestChannel request, final ThreadContext _DO_NOT_USE) { + public void authenticate(final SecurityRequestChannel request, final ThreadContext _DO_NOT_USE) { final boolean isDebugEnabled = log.isDebugEnabled(); final boolean isBlockedBasedOnAddress = request.getRemoteAddress() .map(InetSocketAddress::getAddress) @@ -198,8 +198,7 @@ public boolean authenticate(final SecurityRequestChannel request, final ThreadCo } request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, null, "Authentication finally failed"); - - return false; + return; } final String sslPrincipal = (String) threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_SSL_PRINCIPAL); @@ -208,18 +207,18 @@ public boolean authenticate(final SecurityRequestChannel request, final ThreadCo // PKI authenticated REST call threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, new User(sslPrincipal)); auditLog.logSucceededLogin(sslPrincipal, true, null, request); - return true; + return; } if (userInjector.injectUser(request)) { // ThreadContext injected user - return true; + return; } if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); request.completeWithResponse(HttpStatus.SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized."); - return false; + return; } final TransportAddress remoteAddress = xffResolver.resolve(request); @@ -302,7 +301,7 @@ public boolean authenticate(final SecurityRequestChannel request, final ThreadCo // credentials found in request but we need another client challenge if (httpAuthenticator.reRequestAuthentication(request, ac)) { // auditLog.logFailedLogin(ac.getUsername()+" ", request); --noauditlog - return false; + return; } else { // no reRequest possible continue; @@ -344,7 +343,7 @@ public boolean authenticate(final SecurityRequestChannel request, final ThreadCo null, "Cannot authenticate user because admin user is not permitted to login via HTTP" ); - return false; + return; } final String tenant = Utils.coalesce(request.header("securitytenant"), request.header("security_tenant")); @@ -369,6 +368,7 @@ public boolean authenticate(final SecurityRequestChannel request, final ThreadCo authenticatedUser.getName(), request ); + return; } else { if (isDebugEnabled) { log.debug("User still not authenticated after checking {} auth domains", restAuthDomains.size()); @@ -384,7 +384,7 @@ public boolean authenticate(final SecurityRequestChannel request, final ThreadCo if (isDebugEnabled) { log.debug("Anonymous User is authenticated"); } - return true; + return; } if (firstChallengingHttpAuthenticator != null) { @@ -404,7 +404,7 @@ public boolean authenticate(final SecurityRequestChannel request, final ThreadCo remoteAddress ); auditLog.logFailedLogin(authCredenetials == null ? null : authCredenetials.getUsername(), false, null, request); - return false; + return; } } @@ -418,10 +418,7 @@ public boolean authenticate(final SecurityRequestChannel request, final ThreadCo notifyIpAuthFailureListeners(request, authCredenetials); request.completeWithResponse(org.apache.http.HttpStatus.SC_UNAUTHORIZED, null, "Authentication finally failed"); - return false; } - - return authenticated; } private void notifyIpAuthFailureListeners(SecurityRequestChannel request, AuthCredentials authCredentials) { diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 0bbc17840e..60fb7dc52a 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -133,9 +133,9 @@ public SecurityRestFilter( public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return (request, channel, client) -> { org.apache.logging.log4j.ThreadContext.clearAll(); - final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); - Optional failureResponse = checkAndAuthenticateRequest(securityRequest); - if (failureResponse.isEmpty()) { + final SecurityRequestChannel requestChannel = SecurityRequestFactory.from(request, channel); + checkAndAuthenticateRequest(requestChannel); + if (!requestChannel.hasCompleted()) { final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); if (userIsSuperAdmin(user, adminDNs)) { original.handleRequest(request, channel, client); @@ -145,18 +145,13 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { if (whitelistingSettings.checkRequestIsAllowed(request, channel, client) && allowlistingSettings.checkRequestIsAllowed(request, channel, client)) { - // TODO: ???? - authorizeRequest(original, securityRequest, user); + authorizeRequest(original, requestChannel, user); } } - failureResponse.ifPresent(response -> { - try { - response.act(channel, log, auditLog); - } catch (final IOException ioe) { - log.error(ioe); - } - }); + if(!(requestChannel.hasCompleted())) { + + } }; } @@ -167,8 +162,7 @@ private boolean userIsSuperAdmin(User user, AdminDNs adminDNs) { return user != null && adminDNs.isAdmin(user); } - private boolean authorizeRequest(RestHandler original, SecurityRequestChannel request, User user) { - + private void authorizeRequest(RestHandler original, SecurityRequestChannel request, User user) { List restRoutes = original.routes(); Optional handler = restRoutes.stream() .filter(rh -> rh.getMethod().equals(request.method())) @@ -206,45 +200,33 @@ private boolean authorizeRequest(RestHandler original, SecurityRequestChannel re } log.debug(err); request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, null, err); - return false; + return; } } - - // if handler is not an instance of NamedRoute then we pass through to eval at Transport Layer. - return true; - } - - @FunctionalInterface - public interface ResponseAction { - void act(RestChannel channel, Logger log, AuditLog auditLog) throws IOException; - } - public Optional checkAndAuthenticateRequest(SecurityRequestChannel request) throws Exception { + public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) throws Exception { threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, Origin.REST.toString()); - if (HTTPHelper.containsBadHeader(request)) { + if (HTTPHelper.containsBadHeader(requestChannel)) { final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); - - return Optional.of((channel, logger, auditLog) -> { - log.error(exception.toString()); - auditLog.logBadHeaders(request); - channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, exception)); - }); + log.error(exception.toString()); + auditLog.logBadHeaders(requestChannel); + requestChannel.completeWithResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString()); + return; } if (SSLRequestHelper.containsBadHeader(threadContext, ConfigConstants.OPENDISTRO_SECURITY_CONFIG_PREFIX)) { final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); - return Optional.of((channel, logger, auditLog) -> { - log.error(exception.toString()); - auditLog.logBadHeaders(request); - channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, exception)); - }); + log.error(exception.toString()); + auditLog.logBadHeaders(requestChannel); + requestChannel.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, null, exception.toString()); + return; } final SSLInfo sslInfo; try { - if ((sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, request, principalExtractor)) != null) { + if ((sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, requestChannel, principalExtractor)) != null) { if (sslInfo.getPrincipal() != null) { threadContext.putTransient("_opendistro_security_ssl_principal", sslInfo.getPrincipal()); } @@ -256,26 +238,25 @@ public Optional checkAndAuthenticateRequest(SecurityRequestChann threadContext.putTransient("_opendistro_security_ssl_cipher", sslInfo.getCipher()); } } catch (SSLPeerUnverifiedException e) { - return Optional.of((channel, logger, auditLog) -> { - log.error("No ssl info", e); - auditLog.logSSLException(request, e); - channel.sendResponse(new BytesRestResponse(channel, RestStatus.FORBIDDEN, e)); - }); + log.error("No ssl info", e); + auditLog.logSSLException(requestChannel, e); + requestChannel.completeWithResponse(HttpStatus.SC_FORBIDDEN, null, null); + return; } if (!compatConfig.restAuthEnabled()) { // Authentication is disabled - return Optional.empty(); + return; } - Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); + Matcher matcher = PATTERN_PATH_PREFIX.matcher(requestChannel.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; - if (request.method() != Method.OPTIONS && !(HEALTH_SUFFIX.equals(suffix)) && !(WHO_AM_I_SUFFIX.equals(suffix))) { - final Optional backAuthFailure = null;//registry.authenticate(request); - if (backAuthFailure.isPresent()) { + if (requestChannel.method() != Method.OPTIONS && !(HEALTH_SUFFIX.equals(suffix)) && !(WHO_AM_I_SUFFIX.equals(suffix))) { + registry.authenticate(requestChannel, null); + if (requestChannel.hasCompleted()) { // another roundtrip org.apache.logging.log4j.ThreadContext.remove("user"); - return backAuthFailure; + return; } else { // make it possible to filter logs by username org.apache.logging.log4j.ThreadContext.put( @@ -284,9 +265,6 @@ public Optional checkAndAuthenticateRequest(SecurityRequestChann ); } } - - // User was authenticated - return Optional.empty(); } @Subscribe diff --git a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java index ff9ec19b09..f8da4a9812 100644 --- a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java @@ -53,12 +53,16 @@ import org.opensearch.rest.RestResponse; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.DefaultObjectMapper; +import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityRequestFactory; +import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; import org.opensearch.security.test.helper.file.FileHelper; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.FakeRestRequest; import static com.amazon.dlic.auth.http.saml.HTTPSamlAuthenticator.IDP_METADATA_CONTENT; import static com.amazon.dlic.auth.http.saml.HTTPSamlAuthenticator.IDP_METADATA_URL; +import static org.mockito.ArgumentMatchers.nullable; public class HTTPSamlAuthenticatorTest { protected MockSamlIdpServer mockSamlIdpServer; @@ -139,11 +143,8 @@ public void basicTest() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -159,6 +160,19 @@ public void basicTest() throws Exception { Assert.assertEquals("horst", jwt.getClaim("sub")); } + private TestRestChannel sendToAuthenticator(HTTPSamlAuthenticator samlAuthenticator, RestRequest request) { + TestRestChannel testChannel = new TestRestChannel(request); + SecurityRestRequest tokenRestChannel = (SecurityRestRequest) SecurityRequestFactory.from(request, testChannel); + + samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); + return testChannel; + } + + private String getResponse(HTTPSamlAuthenticator samlAuthenticator, RestRequest request) throws Exception { + TestRestChannel testChannel = sendToAuthenticator(samlAuthenticator, request); + return new String(BytesReference.toBytes(testChannel.response.content())); + } + @Test public void decryptAssertionsTest() throws Exception { mockSamlIdpServer.setAuthenticateUser("horst"); @@ -186,11 +200,7 @@ public void decryptAssertionsTest() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -234,11 +244,7 @@ public void shouldUnescapeSamlEntitiesTest() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -285,11 +291,7 @@ public void shouldUnescapeSamlEntitiesTest2() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -336,11 +338,7 @@ public void shouldNotEscapeSamlEntities() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -387,11 +385,7 @@ public void shouldNotTrimWhitespaceInJwtRoles() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -434,11 +428,7 @@ public void testMetadataBody() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -499,11 +489,7 @@ public void unsolicitedSsoTest() throws Exception { null, "/opendistrosecurity/saml/acs/idpinitiated" ); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -550,9 +536,7 @@ public void badUnsolicitedSsoTest() throws Exception { authenticateHeaders, "/opendistrosecurity/saml/acs/idpinitiated" ); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); + TestRestChannel tokenRestChannel = sendToAuthenticator(samlAuthenticator, tokenRestRequest); Assert.assertEquals(RestStatus.UNAUTHORIZED, tokenRestChannel.response.status()); } @@ -582,9 +566,7 @@ public void wrongCertTest() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); + TestRestChannel tokenRestChannel = sendToAuthenticator(samlAuthenticator, tokenRestRequest); Assert.assertEquals(401, tokenRestChannel.response.status().getStatus()); } @@ -611,9 +593,7 @@ public void noSignatureTest() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); + TestRestChannel tokenRestChannel = sendToAuthenticator(samlAuthenticator, tokenRestRequest); Assert.assertEquals(401, tokenRestChannel.response.status().getStatus()); } @@ -644,11 +624,7 @@ public void rolesTest() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -691,11 +667,7 @@ public void idpEndpointWithQueryStringTest() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -745,11 +717,7 @@ private void commaSeparatedRoles(final String rolesAsString, final Settings.Buil String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -849,8 +817,7 @@ public void initialConnectionFailureTest() throws Exception { HTTPSamlAuthenticator samlAuthenticator = new HTTPSamlAuthenticator(settings, null); RestRequest restRequest = new FakeRestRequest(ImmutableMap.of(), new HashMap()); - TestRestChannel restChannel = new TestRestChannel(restRequest); - samlAuthenticator.reRequestAuthentication(restChannel, null); + TestRestChannel restChannel = sendToAuthenticator(samlAuthenticator, restRequest); Assert.assertNull(restChannel.response); @@ -868,11 +835,7 @@ public void initialConnectionFailureTest() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = new TestRestChannel(tokenRestRequest); - - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - - String responseJson = new String(BytesReference.toBytes(tokenRestChannel.response.content())); + String responseJson = getResponse(samlAuthenticator, tokenRestRequest); HashMap response = DefaultObjectMapper.objectMapper.readValue( responseJson, new TypeReference>() { @@ -891,9 +854,7 @@ public void initialConnectionFailureTest() throws Exception { private AuthenticateHeaders getAutenticateHeaders(HTTPSamlAuthenticator samlAuthenticator) { RestRequest restRequest = new FakeRestRequest(ImmutableMap.of(), new HashMap()); - TestRestChannel restChannel = new TestRestChannel(restRequest); - - samlAuthenticator.reRequestAuthentication(restChannel, null); + TestRestChannel restChannel = sendToAuthenticator(samlAuthenticator, restRequest); List wwwAuthenticateHeaders = restChannel.response.getHeaders().get("WWW-Authenticate"); diff --git a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java index 67bbc3879b..4d2b997db9 100644 --- a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java +++ b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java @@ -16,7 +16,6 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.RestChannel; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; @@ -40,7 +39,7 @@ public AuthCredentials extractCredentials(final SecurityRequestChannel request, } @Override - public boolean reRequestAuthentication(RestChannel channel, AuthCredentials credentials) { + public boolean reRequestAuthentication(SecurityRequestChannel channel, AuthCredentials credentials) { return false; } From 2ef4c3f43b75c4b186ea9126d5b0a9e3a31ab1e1 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Mon, 2 Oct 2023 21:38:39 +0000 Subject: [PATCH 16/50] Fix spotless issues Signed-off-by: Peter Nied --- .../auth/http/jwt/AbstractHTTPJwtAuthenticator.java | 5 ++--- .../dlic/auth/http/jwt/HTTPJwtAuthenticator.java | 6 ++---- .../auth/http/kerberos/HTTPSpnegoAuthenticator.java | 8 +------- .../dlic/auth/http/saml/HTTPSamlAuthenticator.java | 10 ++++++---- .../org/opensearch/security/auth/BackendRegistry.java | 3 +-- .../opensearch/security/auth/HTTPAuthenticator.java | 3 ++- .../security/filter/SecurityRequestChannel.java | 1 - .../security/filter/SecurityRequestFactory.java | 8 ++++---- .../opensearch/security/filter/SecurityRestFilter.java | 9 ++------- .../security/http/HTTPBasicAuthenticator.java | 6 ++---- .../security/http/HTTPClientCertAuthenticator.java | 1 - .../security/http/HTTPProxyAuthenticator.java | 4 +--- .../security/http/OnBehalfOfAuthenticator.java | 4 +--- .../http/proxy/HTTPExtendedProxyAuthenticator.java | 4 +--- .../dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java | 2 -- 15 files changed, 25 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java index 15e5d9546d..fbc6dc1055 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java @@ -37,8 +37,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequestChannel; @@ -243,7 +241,8 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, Aut return request.completeWithResponse( HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), - ""); + "" + ); } public String getRequiredAudience() { diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java index 2c60e96c48..6ce6ee86d1 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java @@ -32,9 +32,6 @@ import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; -import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; @@ -178,7 +175,8 @@ public boolean reRequestAuthentication(final SecurityRequestChannel channel, Aut return channel.completeWithResponse( HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), - ""); + "" + ); } @Override diff --git a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java index bf3002146a..f48b80ab07 100644 --- a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java @@ -52,9 +52,6 @@ import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.env.Environment; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; -import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; @@ -294,10 +291,7 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, Aut if (creds == null || creds.getNativeCredentials() == null) { headers.put("WWW-Authenticate", "Negotiate"); } else { - headers.put( - "WWW-Authenticate", - "Negotiate " + Base64.getEncoder().encodeToString((byte[]) creds.getNativeCredentials()) - ); + headers.put("WWW-Authenticate", "Negotiate " + Base64.getEncoder().encodeToString((byte[]) creds.getNativeCredentials())); } return request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, headers, responseBody); 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 a680b0b19a..87ffbfe435 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 @@ -57,10 +57,8 @@ import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; -import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.Destroyable; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequestChannel; @@ -187,7 +185,7 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, fin if (!(request instanceof SecurityRestRequest)) { throw new SecurityRequetChannelUnsupported(); } else { - final SecurityRestRequest securityRequestChannel = (SecurityRestRequest)request; + final SecurityRestRequest securityRequestChannel = (SecurityRestRequest) request; final RestRequest restRequest = securityRequestChannel.breakEncapulation().v1(); final RestChannel channel = securityRequestChannel.breakEncapulation().v2(); if (this.authTokenProcessorHandler.handle(restRequest, channel)) { @@ -199,7 +197,11 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, fin } final Saml2Settings saml2Settings = this.saml2SettingsProvider.getCached(); - return request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", getWwwAuthenticateHeader(saml2Settings)), ""); + return request.completeWithResponse( + HttpStatus.SC_UNAUTHORIZED, + Map.of("WWW-Authenticate", getWwwAuthenticateHeader(saml2Settings)), + "" + ); } catch (Exception e) { log.error("Error in reRequestAuthentication()", e); return false; diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index cf89d1f874..7446149a37 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -53,7 +53,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.common.transport.TransportAddress; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.BytesRestResponse; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.auth.blocking.ClientBlockRegistry; @@ -342,7 +341,7 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte HttpStatus.SC_FORBIDDEN, null, "Cannot authenticate user because admin user is not permitted to login via HTTP" - ); + ); return; } diff --git a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java index 4946982396..ad1742b17f 100644 --- a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java +++ b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java @@ -67,7 +67,8 @@ public interface HTTPAuthenticator { * If the authentication flow needs another roundtrip with the request originator do not mark it as complete. * @throws OpenSearchSecurityException */ - AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) throws OpenSearchSecurityException; + AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) + throws OpenSearchSecurityException; /** * If the {@code extractCredentials()} call was not successful or the authentication flow needs another roundtrip this method diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java index 1059226a40..e3b5839f5f 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java @@ -41,6 +41,5 @@ default public String header(final String headerName) { return headersMap.map(headers -> headers.get(headerName)).map(List::stream).flatMap(Stream::findFirst).orElse(null); } - public Map params(); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index fcac866e6d..e6a316a182 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -107,8 +107,8 @@ public boolean hasCompleted() { public boolean completeWithResponse(int statusCode, Map headers, String body) { try { underlyingChannel.sendResponse(null); - return true; - } catch (final Exception e){ + return true; + } catch (final Exception e) { log.error("Error when attempting to send response", e); throw new RuntimeException(e); } finally { @@ -144,8 +144,8 @@ public SSLEngine getSSLEngine() { // @Override // public RestChannel getRestChannel() { - // // TODO Auto-generated method stub - // throw new UnsupportedOperationException("Unimplemented method 'getRestChannel'"); + // // TODO Auto-generated method stub + // throw new UnsupportedOperationException("Unimplemented method 'getRestChannel'"); // } @Override diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 60fb7dc52a..8ee11d5cd4 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -26,12 +26,10 @@ package org.opensearch.security.filter; -import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.function.BiConsumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -45,12 +43,9 @@ import org.opensearch.OpenSearchException; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.NamedRoute; -import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestHandler; import org.opensearch.rest.RestRequest.Method; -import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.auditlog.AuditLog.Origin; import org.opensearch.security.auth.BackendRegistry; @@ -144,12 +139,12 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { } if (whitelistingSettings.checkRequestIsAllowed(request, channel, client) - && allowlistingSettings.checkRequestIsAllowed(request, channel, client)) { + && allowlistingSettings.checkRequestIsAllowed(request, channel, client)) { authorizeRequest(original, requestChannel, user); } } - if(!(requestChannel.hasCompleted())) { + if (!(requestChannel.hasCompleted())) { } }; diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index 6c67050ecc..13c42b2f58 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -35,9 +35,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; -import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.HTTPHelper; @@ -71,7 +68,8 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, Aut return request.completeWithResponse( HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), - ""); + "" + ); } @Override diff --git a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java index 5be9b23739..61b428dd06 100644 --- a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java @@ -41,7 +41,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; -import org.opensearch.rest.RestChannel; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.ConfigConstants; diff --git a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java index c9c7309ce1..2fb568e3eb 100644 --- a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java @@ -37,7 +37,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; -import org.opensearch.rest.RestChannel; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.ConfigConstants; @@ -89,8 +88,7 @@ public AuthCredentials extractCredentials(final SecurityRequestChannel request, } @Override - public boolean reRequestAuthentication(final -SecurityRequestChannel response, AuthCredentials creds) { + public boolean reRequestAuthentication(final SecurityRequestChannel response, AuthCredentials creds) { return false; } diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java index 2033054c3e..7a924f6c92 100644 --- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java @@ -33,7 +33,6 @@ import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil; @@ -245,8 +244,7 @@ public Boolean isRequestAllowed(final SecurityRequestChannel request) { } @Override - public boolean reRequestAuthentication(final -SecurityRequestChannel response, AuthCredentials creds) { + public boolean reRequestAuthentication(final SecurityRequestChannel response, AuthCredentials creds) { return false; } diff --git a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java index cd08b4ca95..4eb615c23f 100644 --- a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java @@ -37,7 +37,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; -import org.opensearch.rest.RestChannel; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.http.HTTPProxyAuthenticator; import org.opensearch.security.user.AuthCredentials; @@ -85,8 +84,7 @@ public AuthCredentials extractCredentials(final SecurityRequestChannel request, } @Override - public boolean reRequestAuthentication(final -SecurityRequestChannel response, AuthCredentials creds) { + public boolean reRequestAuthentication(final SecurityRequestChannel response, AuthCredentials creds) { return false; } diff --git a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java index f8da4a9812..fecc8d834c 100644 --- a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java @@ -53,7 +53,6 @@ import org.opensearch.rest.RestResponse; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.DefaultObjectMapper; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; import org.opensearch.security.test.helper.file.FileHelper; @@ -62,7 +61,6 @@ import static com.amazon.dlic.auth.http.saml.HTTPSamlAuthenticator.IDP_METADATA_CONTENT; import static com.amazon.dlic.auth.http.saml.HTTPSamlAuthenticator.IDP_METADATA_URL; -import static org.mockito.ArgumentMatchers.nullable; public class HTTPSamlAuthenticatorTest { protected MockSamlIdpServer mockSamlIdpServer; From 87646d7d662f6281e495e18262b162878b323f49 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Mon, 2 Oct 2023 21:44:20 +0000 Subject: [PATCH 17/50] Fix merging from main changes Signed-off-by: Peter Nied --- .../opensearch/security/http/OnBehalfOfAuthenticator.java | 1 - .../java/org/opensearch/security/util/AuthTokenUtils.java | 4 ++-- .../security/authtoken/jwt/AuthTokenUtilsTest.java | 7 ++++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java index 3e54e325db..1499afa0ea 100644 --- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java @@ -33,7 +33,6 @@ import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil; import org.opensearch.security.filter.SecurityRequestChannel; diff --git a/src/main/java/org/opensearch/security/util/AuthTokenUtils.java b/src/main/java/org/opensearch/security/util/AuthTokenUtils.java index 30f331d3a7..a938375a9e 100644 --- a/src/main/java/org/opensearch/security/util/AuthTokenUtils.java +++ b/src/main/java/org/opensearch/security/util/AuthTokenUtils.java @@ -12,7 +12,7 @@ package org.opensearch.security.util; import org.opensearch.common.settings.Settings; -import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequestChannel; import static org.opensearch.rest.RestRequest.Method.POST; import static org.opensearch.rest.RestRequest.Method.PUT; @@ -21,7 +21,7 @@ public class AuthTokenUtils { private static final String ON_BEHALF_OF_SUFFIX = "api/generateonbehalfoftoken"; private static final String ACCOUNT_SUFFIX = "api/account"; - public static Boolean isAccessToRestrictedEndpoints(final RestRequest request, final String suffix) { + public static Boolean isAccessToRestrictedEndpoints(final SecurityRequestChannel request, final String suffix) { if (suffix == null) { return false; } diff --git a/src/test/java/org/opensearch/security/authtoken/jwt/AuthTokenUtilsTest.java b/src/test/java/org/opensearch/security/authtoken/jwt/AuthTokenUtilsTest.java index d563308e31..1db187e7b6 100644 --- a/src/test/java/org/opensearch/security/authtoken/jwt/AuthTokenUtilsTest.java +++ b/src/test/java/org/opensearch/security/authtoken/jwt/AuthTokenUtilsTest.java @@ -14,6 +14,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.xcontent.NamedXContentRegistry; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.util.AuthTokenUtils; import org.opensearch.test.rest.FakeRestRequest; import org.junit.Test; @@ -33,7 +34,7 @@ public void testIsAccessToRestrictedEndpointsForOnBehalfOfToken() { .withMethod(RestRequest.Method.POST) .build(); - assertTrue(AuthTokenUtils.isAccessToRestrictedEndpoints(request, "api/generateonbehalfoftoken")); + assertTrue(AuthTokenUtils.isAccessToRestrictedEndpoints(SecurityRequestFactory.from(request, null), "api/generateonbehalfoftoken")); } @Test @@ -44,7 +45,7 @@ public void testIsAccessToRestrictedEndpointsForAccount() { .withMethod(RestRequest.Method.PUT) .build(); - assertTrue(AuthTokenUtils.isAccessToRestrictedEndpoints(request, "api/account")); + assertTrue(AuthTokenUtils.isAccessToRestrictedEndpoints(SecurityRequestFactory.from(request, null), "api/account")); } @Test @@ -55,7 +56,7 @@ public void testIsAccessToRestrictedEndpointsFalseCase() { .withMethod(RestRequest.Method.GET) .build(); - assertFalse(AuthTokenUtils.isAccessToRestrictedEndpoints(request, "api/someotherendpoint")); + assertFalse(AuthTokenUtils.isAccessToRestrictedEndpoints(SecurityRequestFactory.from(request, null), "api/someotherendpoint")); } @Test From 547218be66f67298a371782dd063328102fc9f62 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 14:08:12 +0000 Subject: [PATCH 18/50] Restore default build.gradle settings Signed-off-by: Peter Nied --- build.gradle | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index 4a0966563c..741fd41262 100644 --- a/build.gradle +++ b/build.gradle @@ -198,11 +198,10 @@ test { if (JavaVersion.current() > JavaVersion.VERSION_1_8) { jvmArgs += "--add-opens=java.base/java.io=ALL-UNNAMED" } - // retry { - - // failOnPassedAfterRetry = false - // maxRetries = 5 - // } + retry { + failOnPassedAfterRetry = false + maxRetries = 5 + } jacoco { excludes = [ "com.sun.jndi.dns.*", @@ -246,10 +245,10 @@ def setCommonTestConfig(Test task) { if (JavaVersion.current() > JavaVersion.VERSION_1_8) { task.jvmArgs += "--add-opens=java.base/java.io=ALL-UNNAMED" } - // task.retry { - // failOnPassedAfterRetry = false - // maxRetries = 5 - // } + task.retry { + failOnPassedAfterRetry = false + maxRetries = 5 + } task.jacoco { excludes = [ "com.sun.jndi.dns.*", @@ -465,11 +464,11 @@ task integrationTest(type: Test) { systemProperty "java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager" testClassesDirs = sourceSets.integrationTest.output.classesDirs classpath = sourceSets.integrationTest.runtimeClasspath - // retry { - // failOnPassedAfterRetry = false - // maxRetries = 2 - // maxFailures = 10 - // } + retry { + failOnPassedAfterRetry = false + maxRetries = 2 + maxFailures = 10 + } //run the integrationTest task after the test task shouldRunAfter test } From d44d27722bec4ed0f67d1c11a8c74d1071b8c07f Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 14:08:33 +0000 Subject: [PATCH 19/50] Fix bug in authn/z stages of handler wrapper Signed-off-by: Peter Nied --- .../security/filter/SecurityRestFilter.java | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 8ee11d5cd4..879ba4ce92 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -129,23 +129,32 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return (request, channel, client) -> { org.apache.logging.log4j.ThreadContext.clearAll(); final SecurityRequestChannel requestChannel = SecurityRequestFactory.from(request, channel); - checkAndAuthenticateRequest(requestChannel); - if (!requestChannel.hasCompleted()) { - final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); - if (userIsSuperAdmin(user, adminDNs)) { - original.handleRequest(request, channel, client); - } else { - } - - if (whitelistingSettings.checkRequestIsAllowed(request, channel, client) - && allowlistingSettings.checkRequestIsAllowed(request, channel, client)) { - authorizeRequest(original, requestChannel, user); - } + // Authenticate request + checkAndAuthenticateRequest(requestChannel); + if (requestChannel.hasCompleted()) { + // Unable to authenticate the caller + return; } - if (!(requestChannel.hasCompleted())) { + // Authorize Requset + final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); + if (userIsSuperAdmin(user, adminDNs)) { + // Super admins are always authorized + original.handleRequest(request, channel, client); + return; + } + if (whitelistingSettings.checkRequestIsAllowed(request, channel, client) + && allowlistingSettings.checkRequestIsAllowed(request, channel, client)) { + authorizeRequest(original, requestChannel, user); + if (requestChannel.hasCompleted()) { + // Caller was not authorized + return; + } else { + // Caller was authorized, forward the request to the handler + original.handleRequest(request, channel, client); + } } }; } From b960aacfe896e1327d3f3f9d729efcde163889c0 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 14:59:33 +0000 Subject: [PATCH 20/50] Focus channel implementation Signed-off-by: Peter Nied --- .../auth/http/saml/HTTPSamlAuthenticator.java | 4 +- .../security/auditlog/impl/AuditMessage.java | 21 ++++++++-- .../filter/SecurityRequestChannel.java | 5 --- .../filter/SecurityRequestFactory.java | 40 +++++-------------- .../opensearch/security/http/XFFResolver.java | 15 ++++++- .../security/ssl/SslExceptionHandler.java | 7 +--- .../ssl/http/netty/ValidatingDispatcher.java | 9 ++--- 7 files changed, 49 insertions(+), 52 deletions(-) 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 87ffbfe435..707a3c791f 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 @@ -186,8 +186,8 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, fin throw new SecurityRequetChannelUnsupported(); } else { final SecurityRestRequest securityRequestChannel = (SecurityRestRequest) request; - final RestRequest restRequest = securityRequestChannel.breakEncapulation().v1(); - final RestChannel channel = securityRequestChannel.breakEncapulation().v2(); + final RestRequest restRequest = securityRequestChannel.breakEncapsulation().v1(); + final RestChannel channel = securityRequestChannel.breakEncapsulation().v2(); if (this.authTokenProcessorHandler.handle(restRequest, channel)) { // The ACS response was accepted securityRequestChannel.markCompleted(); diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java index 983f841cad..488fbeff8e 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java @@ -49,6 +49,7 @@ import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.dlic.rest.support.Utils; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.support.WildcardMatcher; @@ -378,11 +379,23 @@ void addRestRequestInfo(final SecurityRequestChannel request, final AuditConfig. addRestParams(request.params()); addRestMethod(request.method()); - if (filter.shouldLogRequestBody() - && request.asRestRequest().isPresent() - && request.asRestRequest().get().hasContentOrSourceParam()) { + if (filter.shouldLogRequestBody()) { + + if (!(request instanceof SecurityRestRequest)) { + // The request body is only avaliable on some request sources + return; + } + + final SecurityRestRequest securityRestRequest = (SecurityRestRequest)request; + final RestRequest restRequest = securityRestRequest.breakEncapsulation().v1(); + + if (!(restRequest.hasContentOrSourceParam())) { + // If there is no content, don't attempt to save any body information + return; + } + try { - final Tuple xContentTuple = request.asRestRequest().get().contentOrSourceParam(); + final Tuple xContentTuple = restRequest.contentOrSourceParam(); final String requestBody = XContentHelper.convertToJson(xContentTuple.v2(), false, xContentTuple.v1()); if (path != null && requestBody != null diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java index e3b5839f5f..63dba6c76c 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java @@ -8,7 +8,6 @@ import javax.net.ssl.SSLEngine; -import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; /** @@ -30,12 +29,8 @@ public interface SecurityRequestChannel { public Optional getRemoteAddress(); - public boolean sourcedFromNetty(); - public String uri(); - public Optional asRestRequest(); - default public String header(final String headerName) { final Optional>> headersMap = Optional.ofNullable(getHeaders()); return headersMap.map(headers -> headers.get(headerName)).map(List::stream).flatMap(Stream::findFirst).orElse(null); diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index e6a316a182..59dd0b7d63 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -11,7 +11,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.common.collect.Tuple; +import org.opensearch.core.rest.RestStatus; import org.opensearch.http.netty4.Netty4HttpChannel; +import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; @@ -78,21 +80,16 @@ public Optional getRemoteAddress() { return Optional.ofNullable(this.underlyingRequest.getHttpChannel().getRemoteAddress()); } - @Override - public boolean sourcedFromNetty() { - return underlyingRequest.getHttpChannel() instanceof Netty4HttpChannel; - } + // @Override + // public boolean sourcedFromNetty() { + // return underlyingRequest.getHttpChannel() instanceof Netty4HttpChannel; + // } @Override public String uri() { return underlyingRequest.uri(); } - @Override - public Optional asRestRequest() { - return Optional.of(underlyingRequest); - } - @Override public Map params() { return underlyingRequest.params(); @@ -106,7 +103,10 @@ public boolean hasCompleted() { @Override public boolean completeWithResponse(int statusCode, Map headers, String body) { try { - underlyingChannel.sendResponse(null); + final BytesRestResponse restResponse = new BytesRestResponse(RestStatus.fromCode(statusCode), body); + headers.forEach(restResponse::addHeader); + underlyingChannel.sendResponse(restResponse); + return true; } catch (final Exception e) { log.error("Error when attempting to send response", e); @@ -119,7 +119,7 @@ public boolean completeWithResponse(int statusCode, Map headers, /** * Breaks the encapustion of the interface to get access to the underlying RestRequest / RestChannel. */ - public Tuple breakEncapulation() { + public Tuple breakEncapsulation() { return Tuple.tuple(underlyingRequest, underlyingChannel); } @@ -142,12 +142,6 @@ public SSLEngine getSSLEngine() { throw new UnsupportedOperationException("Unimplemented method 'getSSLEngine'"); } - // @Override - // public RestChannel getRestChannel() { - // // TODO Auto-generated method stub - // throw new UnsupportedOperationException("Unimplemented method 'getRestChannel'"); - // } - @Override public String path() { // TODO Auto-generated method stub @@ -166,24 +160,12 @@ public Optional getRemoteAddress() { throw new UnsupportedOperationException("Unimplemented method 'getRemoteAddress'"); } - @Override - public boolean sourcedFromNetty() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'sourcedFromNetty'"); - } - @Override public String uri() { // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'uri'"); } - @Override - public Optional asRestRequest() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'asRestRequest'"); - } - @Override public Map params() { // TODO Auto-generated method stub diff --git a/src/main/java/org/opensearch/security/http/XFFResolver.java b/src/main/java/org/opensearch/security/http/XFFResolver.java index 90e373a874..47a5f7c3bc 100644 --- a/src/main/java/org/opensearch/security/http/XFFResolver.java +++ b/src/main/java/org/opensearch/security/http/XFFResolver.java @@ -34,8 +34,13 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.core.common.transport.TransportAddress; +import org.opensearch.http.netty4.Netty4HttpChannel; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestRequest; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; +import org.opensearch.security.filter.SecurityRequetChannelUnsupported; import org.opensearch.security.securityconf.DynamicConfigModel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.threadpool.ThreadPool; @@ -58,7 +63,15 @@ public TransportAddress resolve(final SecurityRequestChannel request) throws Ope log.trace("resolve {}", request.getRemoteAddress().orElse(null)); } - if (enabled && request.getRemoteAddress().isPresent() && request.sourcedFromNetty()) { + boolean requestFromNetty = false; + if (request instanceof SecurityRestRequest) { + final SecurityRestRequest securityRequestChannel = (SecurityRestRequest) request; + final RestRequest restRequest = securityRequestChannel.breakEncapsulation().v1(); + + requestFromNetty = restRequest.getHttpChannel() instanceof Netty4HttpChannel; + } + + if (enabled && request.getRemoteAddress().isPresent() && requestFromNetty) { final InetSocketAddress remoteAddress = request.getRemoteAddress().get(); final InetSocketAddress isa = new InetSocketAddress(detector.detect(request, threadContext), remoteAddress.getPort()); diff --git a/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java b/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java index 73f4aceb4d..b274a2ecd3 100644 --- a/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java +++ b/src/main/java/org/opensearch/security/ssl/SslExceptionHandler.java @@ -17,14 +17,13 @@ package org.opensearch.security.ssl; -import org.opensearch.rest.RestRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; public interface SslExceptionHandler { - default void logError(Throwable t, RestRequest request, int type) { + default void logError(Throwable t, SecurityRequestChannel request, int type) { // no-op } @@ -35,8 +34,4 @@ default void logError(Throwable t, boolean isRest) { default void logError(Throwable t, final TransportRequest request, String action, Task task, int type) { // no-op } - - default void logError(Throwable t, SecurityRequestChannel request, int type) { - this.logError(t, request.asRestRequest().get(), type); - } } diff --git a/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java b/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java index 91126d6596..dcd25c2837 100644 --- a/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java +++ b/src/main/java/org/opensearch/security/ssl/http/netty/ValidatingDispatcher.java @@ -66,17 +66,17 @@ public ValidatingDispatcher( @Override public void dispatchRequest(RestRequest request, RestChannel channel, ThreadContext threadContext) { - checkRequest(request, channel); + checkRequest(SecurityRequestFactory.from(request, channel)); originalDispatcher.dispatchRequest(request, channel, threadContext); } @Override public void dispatchBadRequest(RestChannel channel, ThreadContext threadContext, Throwable cause) { - checkRequest(channel.request(), channel); + checkRequest(SecurityRequestFactory.from(channel.request(), channel)); originalDispatcher.dispatchBadRequest(channel, threadContext, cause); } - protected void checkRequest(final RestRequest request, final RestChannel channel) { + protected void checkRequest(final SecurityRequestChannel request) { if (SSLRequestHelper.containsBadHeader(threadContext, "_opendistro_security_ssl_")) { final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); @@ -85,8 +85,7 @@ protected void checkRequest(final RestRequest request, final RestChannel channel } try { - final SecurityRequestChannel securityReqest = SecurityRequestFactory.from(request, channel); - if (SSLRequestHelper.getSSLInfo(settings, configPath, securityReqest, null) == null) { + if (SSLRequestHelper.getSSLInfo(settings, configPath, request, null) == null) { logger.error("Not an SSL request"); throw new OpenSearchSecurityException("Not an SSL request", RestStatus.INTERNAL_SERVER_ERROR); } From 3111665b6147cb9c14c37962e70c3a2c66622fb5 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 15:44:39 +0000 Subject: [PATCH 21/50] Fix merge conflict related issues Signed-off-by: Peter Nied --- .../http/saml/AuthTokenProcessorHandler.java | 41 ++++++++++++++----- .../auth/http/saml/HTTPSamlAuthenticator.java | 2 +- .../security/auth/BackendRegistry.java | 10 ----- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java b/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java index 7210ed5950..3fee4a9444 100644 --- a/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java +++ b/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java @@ -23,6 +23,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; import com.fasterxml.jackson.core.JsonParseException; @@ -31,6 +32,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Strings; import com.onelogin.saml2.authn.SamlResponse; +import com.onelogin.saml2.exception.SettingsException; import com.onelogin.saml2.exception.ValidationError; import com.onelogin.saml2.settings.Saml2Settings; import com.onelogin.saml2.util.Util; @@ -47,6 +49,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.joda.time.DateTime; +import org.xml.sax.SAXException; import org.opensearch.OpenSearchSecurityException; import org.opensearch.SpecialPermission; @@ -54,6 +57,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.xcontent.XContentType; import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; import org.opensearch.core.rest.RestStatus; @@ -118,7 +122,7 @@ class AuthTokenProcessorHandler { } @SuppressWarnings("removal") - BytesRestResponse handle(RestRequest restRequest) throws Exception { + boolean handle(RestRequest restRequest, RestChannel restChannel) throws Exception { try { final SecurityManager sm = System.getSecurityManager(); @@ -126,10 +130,11 @@ BytesRestResponse handle(RestRequest restRequest) throws Exception { sm.checkPermission(new SpecialPermission()); } - return AccessController.doPrivileged(new PrivilegedExceptionAction() { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { @Override - public BytesRestResponse run() throws SamlConfigException, IOException { - return handleLowLevel(restRequest); + public Boolean run() throws XPathExpressionException, SamlConfigException, IOException, ParserConfigurationException, + SAXException, SettingsException { + return handleLowLevel(restRequest, restChannel); } }); } catch (PrivilegedActionException e) { @@ -142,11 +147,13 @@ public BytesRestResponse run() throws SamlConfigException, IOException { } private AuthTokenProcessorAction.Response handleImpl( + RestRequest restRequest, + RestChannel restChannel, String samlResponseBase64, String samlRequestId, String acsEndpoint, Saml2Settings saml2Settings - ) { + ) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException, SettingsException { if (token_log.isDebugEnabled()) { try { token_log.debug( @@ -181,7 +188,8 @@ private AuthTokenProcessorAction.Response handleImpl( } } - private BytesRestResponse handleLowLevel(RestRequest restRequest) throws SamlConfigException, IOException { + private boolean handleLowLevel(RestRequest restRequest, RestChannel restChannel) throws SamlConfigException, IOException, + XPathExpressionException, ParserConfigurationException, SAXException, SettingsException { try { if (restRequest.getMediaType() != XContentType.JSON) { @@ -226,18 +234,31 @@ private BytesRestResponse handleLowLevel(RestRequest restRequest) throws SamlCon acsEndpoint = getAbsoluteAcsEndpoint(((ObjectNode) jsonRoot).get("acsEndpoint").textValue()); } - AuthTokenProcessorAction.Response responseBody = this.handleImpl(samlResponseBase64, samlRequestId, acsEndpoint, saml2Settings); + AuthTokenProcessorAction.Response responseBody = this.handleImpl( + restRequest, + restChannel, + samlResponseBase64, + samlRequestId, + acsEndpoint, + saml2Settings + ); if (responseBody == null) { - return null; + return false; } String responseBodyString = DefaultObjectMapper.objectMapper.writeValueAsString(responseBody); - return new BytesRestResponse(RestStatus.OK, "application/json", responseBodyString); + BytesRestResponse authenticateResponse = new BytesRestResponse(RestStatus.OK, "application/json", responseBodyString); + restChannel.sendResponse(authenticateResponse); + + return true; } catch (JsonProcessingException e) { log.warn("Error while parsing JSON for /_opendistro/_security/api/authtoken", e); - return new BytesRestResponse(RestStatus.BAD_REQUEST, "JSON could not be parsed"); + + BytesRestResponse authenticateResponse = new BytesRestResponse(RestStatus.BAD_REQUEST, "JSON could not be parsed"); + restChannel.sendResponse(authenticateResponse); + return true; } } 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 8e7f3aaa13..707a3c791f 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 @@ -204,7 +204,7 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, fin ); } catch (Exception e) { log.error("Error in reRequestAuthentication()", e); - return null; + return false; } } diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 7b0c2e2faa..d1de76048b 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -297,7 +297,6 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte } else { org.apache.logging.log4j.ThreadContext.put("user", ac.getUsername()); if (!ac.isComplete()) { - final BytesRestResponse restResponse = httpAuthenticator.reRequestAuthentication(request, ac); // credentials found in request but we need another client challenge if (httpAuthenticator.reRequestAuthentication(request, ac)) { // auditLog.logFailedLogin(ac.getUsername()+" ", request); --noauditlog @@ -386,8 +385,6 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte } return; } - BytesRestResponse challengeResponse = null; - if (firstChallengingHttpAuthenticator != null) { if (isDebugEnabled) { @@ -398,13 +395,6 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte if (isDebugEnabled) { log.debug("Rerequest {} failed", firstChallengingHttpAuthenticator.getClass()); } - - log.warn( - "Authentication finally failed for {} from {}", - authCredenetials == null ? null : authCredenetials.getUsername(), - remoteAddress - ); - auditLog.logFailedLogin(authCredenetials == null ? null : authCredenetials.getUsername(), false, null, request); return; } } From 2aad250e62ca88bef7e79e384a295b2276bf0df2 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 16:18:35 +0000 Subject: [PATCH 22/50] Seperate read-only vs read-write scenarios Signed-off-by: Peter Nied --- .../jwt/AbstractHTTPJwtAuthenticator.java | 7 +- .../auth/http/jwt/HTTPJwtAuthenticator.java | 9 +- .../kerberos/HTTPSpnegoAuthenticator.java | 5 +- .../auth/http/saml/HTTPSamlAuthenticator.java | 16 ++-- .../security/auditlog/impl/AuditMessage.java | 7 +- .../security/auth/HTTPAuthenticator.java | 3 +- .../dlic/rest/api/AbstractApiAction.java | 93 ++++++++++--------- .../rest/api/RestApiPrivilegesEvaluator.java | 3 +- .../security/filter/SecurityRequest.java | 32 +++++++ .../filter/SecurityRequestChannel.java | 29 +----- .../filter/SecurityRequestFactory.java | 48 +++++++--- .../security/http/HTTPBasicAuthenticator.java | 3 +- .../http/HTTPClientCertAuthenticator.java | 3 +- .../security/http/HTTPProxyAuthenticator.java | 3 +- .../http/OnBehalfOfAuthenticator.java | 9 +- .../security/http/RemoteIpDetector.java | 4 +- .../opensearch/security/http/XFFResolver.java | 8 +- .../proxy/HTTPExtendedProxyAuthenticator.java | 3 +- .../rest/SecurityConfigUpdateAction.java | 34 +++---- .../security/util/AuthTokenUtils.java | 4 +- .../http/saml/HTTPSamlAuthenticatorTest.java | 3 +- .../authtoken/jwt/AuthTokenUtilsTest.java | 6 +- .../cache/DummyHTTPAuthenticator.java | 3 +- 23 files changed, 188 insertions(+), 147 deletions(-) create mode 100644 src/main/java/org/opensearch/security/filter/SecurityRequest.java diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java index fbc6dc1055..e74c697366 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java @@ -39,6 +39,7 @@ import org.opensearch.core.common.Strings; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; @@ -83,7 +84,7 @@ public AbstractHTTPJwtAuthenticator(Settings settings, Path configPath) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); @@ -101,7 +102,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final SecurityRequestChannel request) throws OpenSearchSecurityException { + private AuthCredentials extractCredentials0(final SecurityRequest request) throws OpenSearchSecurityException { String jwtString = getJwtTokenString(request); @@ -142,7 +143,7 @@ private AuthCredentials extractCredentials0(final SecurityRequestChannel request } - protected String getJwtTokenString(SecurityRequestChannel request) { + protected String getJwtTokenString(SecurityRequest request) { String jwtToken = request.header(jwtHeaderName); if (isDefaultAuthHeader && jwtToken != null && BASIC.matcher(jwtToken).matches()) { jwtToken = null; diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java index 6ce6ee86d1..5f7e99d373 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java @@ -33,6 +33,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.KeyUtils; @@ -83,7 +84,7 @@ public HTTPJwtAuthenticator(final Settings settings, final Path configPath) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); @@ -101,7 +102,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final SecurityRequestChannel request) { + private AuthCredentials extractCredentials0(final SecurityRequest request) { if (jwtParser == null) { log.error("Missing Signing Key. JWT authentication will not work"); return null; @@ -184,7 +185,7 @@ public String getType() { return "jwt"; } - protected String extractSubject(final Claims claims, final SecurityRequestChannel request) { + protected String extractSubject(final Claims claims, final SecurityRequest request) { String subject = claims.getSubject(); if (subjectKey != null) { // try to get roles from claims, first as Object to avoid having to catch the ExpectedTypeException @@ -208,7 +209,7 @@ protected String extractSubject(final Claims claims, final SecurityRequestChanne } @SuppressWarnings("unchecked") - protected String[] extractRoles(final Claims claims, final SecurityRequestChannel request) { + protected String[] extractRoles(final Claims claims, final SecurityRequest request) { // no roles key specified if (rolesKey == null) { return new String[0]; diff --git a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java index f48b80ab07..baeb5bb14d 100644 --- a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java @@ -53,6 +53,7 @@ import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.env.Environment; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; @@ -171,7 +172,7 @@ public Void run() { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext threadContext) { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -188,7 +189,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final SecurityRequestChannel request) { + private AuthCredentials extractCredentials0(final SecurityRequest request) { if (acceptorPrincipal == null || acceptorKeyTabPath == null) { log.error("Missing acceptor principal or keytab configuration. Kerberos authentication will not work"); 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 707a3c791f..b04cd79663 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 @@ -61,8 +61,10 @@ import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.Destroyable; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; +import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequestChannel; import org.opensearch.security.filter.SecurityRequetChannelUnsupported; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.PemKeyReader; @@ -152,7 +154,7 @@ public HTTPSamlAuthenticator(final Settings settings, final Path configPath) { } @Override - public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext threadContext) + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) throws OpenSearchSecurityException { Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; @@ -163,7 +165,7 @@ public AuthCredentials extractCredentials(final SecurityRequestChannel request, AuthCredentials authCredentials = this.httpJwtAuthenticator.extractCredentials(request, threadContext); if (AUTHINFO_SUFFIX.equals(suffix)) { - this.initLogoutUrl(request, threadContext, authCredentials); + this.initLogoutUrl(threadContext, authCredentials); } return authCredentials; @@ -182,12 +184,12 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, fin if (API_AUTHTOKEN_SUFFIX.equals(suffix)) { // Verficiation of SAML ASC endpoint only works with RestRequests - if (!(request instanceof SecurityRestRequest)) { + if (!(request instanceof SecurityRestRequestChannel)) { throw new SecurityRequetChannelUnsupported(); } else { - final SecurityRestRequest securityRequestChannel = (SecurityRestRequest) request; - final RestRequest restRequest = securityRequestChannel.breakEncapsulation().v1(); - final RestChannel channel = securityRequestChannel.breakEncapsulation().v2(); + final SecurityRestRequestChannel securityRequestChannel = (SecurityRestRequestChannel) request; + final RestRequest restRequest = securityRequestChannel.breakEncapsulationForRequest(); + final RestChannel channel = securityRequestChannel.breakEncapsulationForChannel(); if (this.authTokenProcessorHandler.handle(restRequest, channel)) { // The ACS response was accepted securityRequestChannel.markCompleted(); @@ -412,7 +414,7 @@ String buildLogoutUrl(AuthCredentials authCredentials) { } - private void initLogoutUrl(SecurityRequestChannel restRequest, ThreadContext threadContext, AuthCredentials authCredentials) { + private void initLogoutUrl(ThreadContext threadContext, AuthCredentials authCredentials) { threadContext.putTransient(ConfigConstants.SSO_LOGOUT_URL, buildLogoutUrl(authCredentials)); } diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java index 488fbeff8e..9bca3c9c11 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java @@ -50,6 +50,7 @@ import org.opensearch.security.dlic.rest.support.Utils; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; +import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequestChannel; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.support.WildcardMatcher; @@ -381,13 +382,13 @@ void addRestRequestInfo(final SecurityRequestChannel request, final AuditConfig. if (filter.shouldLogRequestBody()) { - if (!(request instanceof SecurityRestRequest)) { + if (!(request instanceof SecurityRestRequestChannel)) { // The request body is only avaliable on some request sources return; } - final SecurityRestRequest securityRestRequest = (SecurityRestRequest)request; - final RestRequest restRequest = securityRestRequest.breakEncapsulation().v1(); + final SecurityRestRequestChannel securityRestRequest = (SecurityRestRequestChannel)request; + final RestRequest restRequest = securityRestRequest.breakEncapsulationForRequest(); if (!(restRequest.hasContentOrSourceParam())) { // If there is no content, don't attempt to save any body information diff --git a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java index 4582d38651..c3960c5b4b 100644 --- a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java +++ b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java @@ -29,6 +29,7 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.RestRequest; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; @@ -67,7 +68,7 @@ public interface HTTPAuthenticator { * If the authentication flow needs another roundtrip with the request originator do not mark it as complete. * @throws OpenSearchSecurityException */ - AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) + AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException; /** diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index 1e374ca303..ca4fb93770 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -536,58 +536,59 @@ public void onFailure(Exception e) { @Override protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + return channel -> { + final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); - // Fix channel ordering - final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, null); + // consume all parameters first so we can return a correct HTTP status, + // not 400 + consumeParameters(request); - // consume all parameters first so we can return a correct HTTP status, - // not 400 - consumeParameters(request); + // check if .opendistro_security index has been initialized + if (!ensureIndexExists()) { + internalSeverError(channel, RequestContentValidator.ValidationError.SECURITY_NOT_INITIALIZED.message()); + } - // check if .opendistro_security index has been initialized - if (!ensureIndexExists()) { - return channel -> internalSeverError(channel, RequestContentValidator.ValidationError.SECURITY_NOT_INITIALIZED.message()); - } + // check if request is authorized + final String authError = securityApiDependencies.restApiPrivilegesEvaluator().checkAccessPermissions(request, endpoint); - // check if request is authorized - final String authError = securityApiDependencies.restApiPrivilegesEvaluator().checkAccessPermissions(request, endpoint); - - final User user = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); - final String userName = user == null ? null : user.getName(); - if (authError != null) { - LOGGER.error("No permission to access REST API: " + authError); - securityApiDependencies.auditLog().logMissingPrivileges(authError, userName, securityRequest); - // for rest request - request.params().clear(); - return channel -> forbidden(channel, "No permission to access REST API: " + authError); - } else { - securityApiDependencies.auditLog().logGrantedPrivileges(userName, securityRequest); - } + final User user = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); + final String userName = user == null ? null : user.getName(); - final var originalUserAndRemoteAddress = Utils.userAndRemoteAddressFrom(threadPool.getThreadContext()); - final Object originalOrigin = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN); - - return channel -> threadPool.generic().submit(() -> { - try (StoredContext ignore = threadPool.getThreadContext().stashContext()) { - threadPool.getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_CONF_REQUEST_HEADER, "true"); - threadPool.getThreadContext() - .putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, originalUserAndRemoteAddress.getLeft()); - threadPool.getThreadContext() - .putTransient(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS, originalUserAndRemoteAddress.getRight()); - threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, originalOrigin); - - requestHandlers = Optional.ofNullable(requestHandlers).orElseGet(requestHandlersBuilder::build); - final var requestHandler = requestHandlers.getOrDefault(request.method(), methodNotImplementedHandler); - requestHandler.handle(channel, request, client); - } catch (Exception e) { - LOGGER.error("Error processing request {}", request, e); - try { - channel.sendResponse(new BytesRestResponse(channel, e)); - } catch (IOException ioe) { - throw ExceptionsHelper.convertToOpenSearchException(e); - } + if (authError != null) { + LOGGER.error("No permission to access REST API: " + authError); + securityApiDependencies.auditLog().logMissingPrivileges(authError, userName, securityRequest); + // for rest request + request.params().clear(); + forbidden(channel, "No permission to access REST API: " + authError); + } else { + securityApiDependencies.auditLog().logGrantedPrivileges(userName, securityRequest); } - }); + + final var originalUserAndRemoteAddress = Utils.userAndRemoteAddressFrom(threadPool.getThreadContext()); + final Object originalOrigin = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN); + + threadPool.generic().submit(() -> { + try (StoredContext ignore = threadPool.getThreadContext().stashContext()) { + threadPool.getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_CONF_REQUEST_HEADER, "true"); + threadPool.getThreadContext() + .putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, originalUserAndRemoteAddress.getLeft()); + threadPool.getThreadContext() + .putTransient(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS, originalUserAndRemoteAddress.getRight()); + threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, originalOrigin); + + requestHandlers = Optional.ofNullable(requestHandlers).orElseGet(requestHandlersBuilder::build); + final var requestHandler = requestHandlers.getOrDefault(request.method(), methodNotImplementedHandler); + requestHandler.handle(channel, request, client); + } catch (Exception e) { + LOGGER.error("Error processing request {}", request, e); + try { + channel.sendResponse(new BytesRestResponse(channel, e)); + } catch (IOException ioe) { + throw ExceptionsHelper.convertToOpenSearchException(e); + } + } + }); + }; } /** diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java index 4a427245a6..e0171d77ce 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java @@ -448,8 +448,7 @@ private String checkAdminCertBasedAccessPermissions(RestRequest request) throws } // Certificate based access, Check if we have an admin TLS certificate - // TODO: Doesn't seem like the channel is needed here, but need to make sure this works correctly. - final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, null); + final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, /* OK to be null so long as a response isn't sent */ null); SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java new file mode 100644 index 0000000000..b95e24f059 --- /dev/null +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -0,0 +1,32 @@ +package org.opensearch.security.filter; + +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +import javax.net.ssl.SSLEngine; + +import org.opensearch.rest.RestRequest.Method; + +public interface SecurityRequest { + public Map> getHeaders(); + + public SSLEngine getSSLEngine(); + + public String path(); + + public Method method(); + + public Optional getRemoteAddress(); + + public String uri(); + + default public String header(final String headerName) { + final Optional>> headersMap = Optional.ofNullable(getHeaders()); + return headersMap.map(headers -> headers.get(headerName)).map(List::stream).flatMap(Stream::findFirst).orElse(null); + } + + public Map params(); +} \ No newline at end of file diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java index 63dba6c76c..7da675f881 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java @@ -1,40 +1,13 @@ package org.opensearch.security.filter; -import java.net.InetSocketAddress; -import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.stream.Stream; - -import javax.net.ssl.SSLEngine; - -import org.opensearch.rest.RestRequest.Method; /** * When a request is recieved by the security plugin this governs getting information about the request as well as a way to complet */ -public interface SecurityRequestChannel { +public interface SecurityRequestChannel extends SecurityRequest { public boolean hasCompleted(); public boolean completeWithResponse(final int statusCode, final Map headers, final String body); - - public Map> getHeaders(); - - public SSLEngine getSSLEngine(); - - public String path(); - - public Method method(); - - public Optional getRemoteAddress(); - - public String uri(); - - default public String header(final String headerName) { - final Optional>> headersMap = Optional.ofNullable(getHeaders()); - return headersMap.map(headers -> headers.get(headerName)).map(List::stream).flatMap(Stream::findFirst).orElse(null); - } - - public Map params(); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index 59dd0b7d63..cc406fb7ea 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -26,21 +26,22 @@ public static SecurityRequestChannel from() { return null; } + public static SecurityRequest from(final RestRequest request) { + return new SecurityRestRequest(request); + } + + public static SecurityRequestChannel from(final RestRequest request, final RestChannel channel) { - return new SecurityRestRequest(request, channel); + return new SecurityRestRequestChannel(request, channel); } - public static class SecurityRestRequest implements SecurityRequestChannel { - private final Logger log = LogManager.getLogger(SecurityRestRequest.class); + public static class SecurityRestRequest implements SecurityRequest { - private AtomicBoolean hasCompleted = new AtomicBoolean(false); - private final RestRequest underlyingRequest; - private final RestChannel underlyingChannel; + protected final RestRequest underlyingRequest; - SecurityRestRequest(final RestRequest request, final RestChannel channel) { + SecurityRestRequest(final RestRequest request) { underlyingRequest = request; - underlyingChannel = channel; } @Override @@ -80,11 +81,6 @@ public Optional getRemoteAddress() { return Optional.ofNullable(this.underlyingRequest.getHttpChannel().getRemoteAddress()); } - // @Override - // public boolean sourcedFromNetty() { - // return underlyingRequest.getHttpChannel() instanceof Netty4HttpChannel; - // } - @Override public String uri() { return underlyingRequest.uri(); @@ -94,6 +90,24 @@ public String uri() { public Map params() { return underlyingRequest.params(); } + + public RestRequest breakEncapsulationForRequest() { + return underlyingRequest; + } + } + + public static class SecurityRestRequestChannel extends SecurityRestRequest implements SecurityRequestChannel { + + private final Logger log = LogManager.getLogger(SecurityRestRequest.class); + + private AtomicBoolean hasCompleted = new AtomicBoolean(false); + private final RestChannel underlyingChannel; + + SecurityRestRequestChannel(final RestRequest request, final RestChannel channel) { + super(request); + underlyingChannel = channel; + } + @Override public boolean hasCompleted() { @@ -102,6 +116,10 @@ public boolean hasCompleted() { @Override public boolean completeWithResponse(int statusCode, Map headers, String body) { + if (underlyingChannel == null) { + throw new UnsupportedOperationException("Channel was not defined"); + } + try { final BytesRestResponse restResponse = new BytesRestResponse(RestStatus.fromCode(statusCode), body); headers.forEach(restResponse::addHeader); @@ -127,6 +145,10 @@ public Tuple breakEncapsulation() { public void markCompleted() { hasCompleted.set(true); } + + public RestChannel breakEncapsulationForChannel() { + return underlyingChannel; + } } protected static class NettyRequest implements SecurityRequestChannel { diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index 13c42b2f58..6636be53be 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -36,6 +36,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.HTTPHelper; import org.opensearch.security.user.AuthCredentials; @@ -50,7 +51,7 @@ public HTTPBasicAuthenticator(final Settings settings, final Path configPath) { } @Override - public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext threadContext) { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) { final boolean forceLogin = Boolean.getBoolean(request.params().get("force_login")); diff --git a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java index 61b428dd06..d3701d40b0 100644 --- a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java @@ -42,6 +42,7 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -56,7 +57,7 @@ public HTTPClientCertAuthenticator(final Settings settings, final Path configPat } @Override - public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext threadContext) { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext threadContext) { final String principal = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_SSL_PRINCIPAL); diff --git a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java index 2fb568e3eb..1fdf973726 100644 --- a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java @@ -38,6 +38,7 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -55,7 +56,7 @@ public HTTPProxyAuthenticator(Settings settings, final Path configPath) { } @Override - public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) { if (context.getTransient(ConfigConstants.OPENDISTRO_SECURITY_XFF_DONE) != Boolean.TRUE) { throw new OpenSearchSecurityException("xff not done"); diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java index 1499afa0ea..ac92833c6e 100644 --- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java @@ -35,6 +35,7 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.user.AuthCredentials; @@ -119,7 +120,7 @@ private String[] extractBackendRolesFromClaims(Claims claims) { @Override @SuppressWarnings("removal") - public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); @@ -137,7 +138,7 @@ public AuthCredentials run() { return creds; } - private AuthCredentials extractCredentials0(final SecurityRequestChannel request) { + private AuthCredentials extractCredentials0(final SecurityRequest request) { if (!oboEnabled) { log.error("On-behalf-of authentication is disabled"); return null; @@ -201,7 +202,7 @@ private AuthCredentials extractCredentials0(final SecurityRequestChannel request return null; } - private String extractJwtFromHeader(SecurityRequestChannel request) { + private String extractJwtFromHeader(SecurityRequest request) { String jwtToken = request.header(HttpHeaders.AUTHORIZATION); if (jwtToken == null || jwtToken.isEmpty()) { @@ -229,7 +230,7 @@ private void logDebug(String message, Object... args) { } } - public Boolean isRequestAllowed(final SecurityRequestChannel request) { + public Boolean isRequestAllowed(final SecurityRequest request) { Matcher matcher = PATTERN_PATH_PREFIX.matcher(request.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; if (isAccessToRestrictedEndpoints(request, suffix)) { diff --git a/src/main/java/org/opensearch/security/http/RemoteIpDetector.java b/src/main/java/org/opensearch/security/http/RemoteIpDetector.java index 2aba89f79b..7b76a82c42 100644 --- a/src/main/java/org/opensearch/security/http/RemoteIpDetector.java +++ b/src/main/java/org/opensearch/security/http/RemoteIpDetector.java @@ -53,7 +53,7 @@ import org.apache.logging.log4j.Logger; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.support.ConfigConstants; final class RemoteIpDetector { @@ -116,7 +116,7 @@ public String getRemoteIpHeader() { return remoteIpHeader; } - String detect(SecurityRequestChannel request, ThreadContext threadContext) { + String detect(SecurityRequest request, ThreadContext threadContext) { final String originalRemoteAddr = request.getRemoteAddress() .map(InetSocketAddress::getAddress) diff --git a/src/main/java/org/opensearch/security/http/XFFResolver.java b/src/main/java/org/opensearch/security/http/XFFResolver.java index 47a5f7c3bc..dd6f369717 100644 --- a/src/main/java/org/opensearch/security/http/XFFResolver.java +++ b/src/main/java/org/opensearch/security/http/XFFResolver.java @@ -35,12 +35,10 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.core.common.transport.TransportAddress; import org.opensearch.http.netty4.Netty4HttpChannel; -import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; -import org.opensearch.security.filter.SecurityRequetChannelUnsupported; import org.opensearch.security.securityconf.DynamicConfigModel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.threadpool.ThreadPool; @@ -57,7 +55,7 @@ public XFFResolver(final ThreadPool threadPool) { this.threadContext = threadPool.getThreadContext(); } - public TransportAddress resolve(final SecurityRequestChannel request) throws OpenSearchSecurityException { + public TransportAddress resolve(final SecurityRequest request) throws OpenSearchSecurityException { final boolean isTraceEnabled = log.isTraceEnabled(); if (isTraceEnabled) { log.trace("resolve {}", request.getRemoteAddress().orElse(null)); @@ -66,7 +64,7 @@ public TransportAddress resolve(final SecurityRequestChannel request) throws Ope boolean requestFromNetty = false; if (request instanceof SecurityRestRequest) { final SecurityRestRequest securityRequestChannel = (SecurityRestRequest) request; - final RestRequest restRequest = securityRequestChannel.breakEncapsulation().v1(); + final RestRequest restRequest = securityRequestChannel.breakEncapsulationForRequest(); requestFromNetty = restRequest.getHttpChannel() instanceof Netty4HttpChannel; } diff --git a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java index 4eb615c23f..cf5b265598 100644 --- a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java @@ -37,6 +37,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.http.HTTPProxyAuthenticator; import org.opensearch.security.user.AuthCredentials; @@ -54,7 +55,7 @@ public HTTPExtendedProxyAuthenticator(Settings settings, final Path configPath) } @Override - public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) { + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) { AuthCredentials credentials = super.extractCredentials(request, context); if (credentials == null) { return null; diff --git a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java index c87e421f44..04c9ef6bd4 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java @@ -73,27 +73,29 @@ public List routes() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { - String[] configTypes = request.paramAsStringArrayOrEmptyIfAll("config_types"); + return channel -> { + String[] configTypes = request.paramAsStringArrayOrEmptyIfAll("config_types"); - // TODO: Need to re-write with a RestChannelConsumer - final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, null); - SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); + final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); + SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); - if (sslInfo == null) { - return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); - } + if (sslInfo == null) { + channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); + return; + } - final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); + final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); - // only allowed for admins - if (user == null || !adminDns.isAdmin(user)) { - return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); - } else { - ConfigUpdateRequest configUpdateRequest = new ConfigUpdateRequest(configTypes); - return channel -> { + // only allowed for admins + if (user == null || !adminDns.isAdmin(user)) { + channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); + return; + } else { + ConfigUpdateRequest configUpdateRequest = new ConfigUpdateRequest(configTypes); client.execute(ConfigUpdateAction.INSTANCE, configUpdateRequest, new NodesResponseRestListener<>(channel)); - }; - } + return; + } + }; } @Override diff --git a/src/main/java/org/opensearch/security/util/AuthTokenUtils.java b/src/main/java/org/opensearch/security/util/AuthTokenUtils.java index a938375a9e..3884bf75fe 100644 --- a/src/main/java/org/opensearch/security/util/AuthTokenUtils.java +++ b/src/main/java/org/opensearch/security/util/AuthTokenUtils.java @@ -12,7 +12,7 @@ package org.opensearch.security.util; import org.opensearch.common.settings.Settings; -import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityRequest; import static org.opensearch.rest.RestRequest.Method.POST; import static org.opensearch.rest.RestRequest.Method.PUT; @@ -21,7 +21,7 @@ public class AuthTokenUtils { private static final String ON_BEHALF_OF_SUFFIX = "api/generateonbehalfoftoken"; private static final String ACCOUNT_SUFFIX = "api/account"; - public static Boolean isAccessToRestrictedEndpoints(final SecurityRequestChannel request, final String suffix) { + public static Boolean isAccessToRestrictedEndpoints(final SecurityRequest request, final String suffix) { if (suffix == null) { return false; } diff --git a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java index 02ea9eea62..0f3069783f 100644 --- a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java @@ -56,6 +56,7 @@ import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; +import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequestChannel; import org.opensearch.security.test.helper.file.FileHelper; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.FakeRestRequest; @@ -161,7 +162,7 @@ public void basicTest() throws Exception { private TestRestChannel sendToAuthenticator(HTTPSamlAuthenticator samlAuthenticator, RestRequest request) { TestRestChannel testChannel = new TestRestChannel(request); - SecurityRestRequest tokenRestChannel = (SecurityRestRequest) SecurityRequestFactory.from(request, testChannel); + SecurityRestRequestChannel tokenRestChannel = (SecurityRestRequestChannel) SecurityRequestFactory.from(request, testChannel); samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); return testChannel; diff --git a/src/test/java/org/opensearch/security/authtoken/jwt/AuthTokenUtilsTest.java b/src/test/java/org/opensearch/security/authtoken/jwt/AuthTokenUtilsTest.java index 1db187e7b6..4072d94436 100644 --- a/src/test/java/org/opensearch/security/authtoken/jwt/AuthTokenUtilsTest.java +++ b/src/test/java/org/opensearch/security/authtoken/jwt/AuthTokenUtilsTest.java @@ -34,7 +34,7 @@ public void testIsAccessToRestrictedEndpointsForOnBehalfOfToken() { .withMethod(RestRequest.Method.POST) .build(); - assertTrue(AuthTokenUtils.isAccessToRestrictedEndpoints(SecurityRequestFactory.from(request, null), "api/generateonbehalfoftoken")); + assertTrue(AuthTokenUtils.isAccessToRestrictedEndpoints(SecurityRequestFactory.from(request), "api/generateonbehalfoftoken")); } @Test @@ -45,7 +45,7 @@ public void testIsAccessToRestrictedEndpointsForAccount() { .withMethod(RestRequest.Method.PUT) .build(); - assertTrue(AuthTokenUtils.isAccessToRestrictedEndpoints(SecurityRequestFactory.from(request, null), "api/account")); + assertTrue(AuthTokenUtils.isAccessToRestrictedEndpoints(SecurityRequestFactory.from(request), "api/account")); } @Test @@ -56,7 +56,7 @@ public void testIsAccessToRestrictedEndpointsFalseCase() { .withMethod(RestRequest.Method.GET) .build(); - assertFalse(AuthTokenUtils.isAccessToRestrictedEndpoints(SecurityRequestFactory.from(request, null), "api/someotherendpoint")); + assertFalse(AuthTokenUtils.isAccessToRestrictedEndpoints(SecurityRequestFactory.from(request), "api/someotherendpoint")); } @Test diff --git a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java index 4d2b997db9..21cfafa03f 100644 --- a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java +++ b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java @@ -17,6 +17,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.security.auth.HTTPAuthenticator; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.user.AuthCredentials; @@ -32,7 +33,7 @@ public String getType() { } @Override - public AuthCredentials extractCredentials(final SecurityRequestChannel request, final ThreadContext context) + public AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException { count++; return new AuthCredentials("dummy").markComplete(); From 9a915e7458203d6e052dc197530e541056006bd1 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 16:20:21 +0000 Subject: [PATCH 23/50] Spotless Signed-off-by: Peter Nied --- .../amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java | 1 - .../opensearch/security/auditlog/impl/AuditMessage.java | 3 +-- .../org/opensearch/security/auth/HTTPAuthenticator.java | 3 +-- .../security/dlic/rest/api/RestApiPrivilegesEvaluator.java | 5 ++++- .../org/opensearch/security/filter/SecurityRequest.java | 2 +- .../opensearch/security/filter/SecurityRequestFactory.java | 7 ++----- .../java/org/opensearch/security/http/XFFResolver.java | 2 +- .../dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java | 2 -- 8 files changed, 10 insertions(+), 15 deletions(-) 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 b04cd79663..f987b88dbe 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 @@ -63,7 +63,6 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; -import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequestChannel; import org.opensearch.security.filter.SecurityRequetChannelUnsupported; import org.opensearch.security.support.ConfigConstants; diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java index 9bca3c9c11..c142fbc2d7 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java @@ -49,7 +49,6 @@ import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.dlic.rest.support.Utils; import org.opensearch.security.filter.SecurityRequestChannel; -import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequestChannel; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.support.WildcardMatcher; @@ -387,7 +386,7 @@ void addRestRequestInfo(final SecurityRequestChannel request, final AuditConfig. return; } - final SecurityRestRequestChannel securityRestRequest = (SecurityRestRequestChannel)request; + final SecurityRestRequestChannel securityRestRequest = (SecurityRestRequestChannel) request; final RestRequest restRequest = securityRestRequest.breakEncapsulationForRequest(); if (!(restRequest.hasContentOrSourceParam())) { diff --git a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java index c3960c5b4b..690a1415df 100644 --- a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java +++ b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java @@ -68,8 +68,7 @@ public interface HTTPAuthenticator { * If the authentication flow needs another roundtrip with the request originator do not mark it as complete. * @throws OpenSearchSecurityException */ - AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) - throws OpenSearchSecurityException; + AuthCredentials extractCredentials(final SecurityRequest request, final ThreadContext context) throws OpenSearchSecurityException; /** * If the {@code extractCredentials()} call was not successful or the authentication flow needs another roundtrip this method diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java index e0171d77ce..0e2c1b7a4d 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java @@ -448,7 +448,10 @@ private String checkAdminCertBasedAccessPermissions(RestRequest request) throws } // Certificate based access, Check if we have an admin TLS certificate - final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, /* OK to be null so long as a response isn't sent */ null); + final SecurityRequestChannel securityRequest = SecurityRequestFactory.from( + request, + /* OK to be null so long as a response isn't sent */ null + ); SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java index b95e24f059..8b9fa9bc70 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -29,4 +29,4 @@ default public String header(final String headerName) { } public Map params(); -} \ No newline at end of file +} diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index cc406fb7ea..baba40eff3 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -30,12 +30,10 @@ public static SecurityRequest from(final RestRequest request) { return new SecurityRestRequest(request); } - public static SecurityRequestChannel from(final RestRequest request, final RestChannel channel) { return new SecurityRestRequestChannel(request, channel); } - public static class SecurityRestRequest implements SecurityRequest { protected final RestRequest underlyingRequest; @@ -90,7 +88,7 @@ public String uri() { public Map params() { return underlyingRequest.params(); } - + public RestRequest breakEncapsulationForRequest() { return underlyingRequest; } @@ -108,7 +106,6 @@ public static class SecurityRestRequestChannel extends SecurityRestRequest imple underlyingChannel = channel; } - @Override public boolean hasCompleted() { return hasCompleted.get(); @@ -124,7 +121,7 @@ public boolean completeWithResponse(int statusCode, Map headers, final BytesRestResponse restResponse = new BytesRestResponse(RestStatus.fromCode(statusCode), body); headers.forEach(restResponse::addHeader); underlyingChannel.sendResponse(restResponse); - + return true; } catch (final Exception e) { log.error("Error when attempting to send response", e); diff --git a/src/main/java/org/opensearch/security/http/XFFResolver.java b/src/main/java/org/opensearch/security/http/XFFResolver.java index dd6f369717..e0f83a422f 100644 --- a/src/main/java/org/opensearch/security/http/XFFResolver.java +++ b/src/main/java/org/opensearch/security/http/XFFResolver.java @@ -68,7 +68,7 @@ public TransportAddress resolve(final SecurityRequest request) throws OpenSearch requestFromNetty = restRequest.getHttpChannel() instanceof Netty4HttpChannel; } - + if (enabled && request.getRemoteAddress().isPresent() && requestFromNetty) { final InetSocketAddress remoteAddress = request.getRemoteAddress().get(); final InetSocketAddress isa = new InetSocketAddress(detector.detect(request, threadContext), remoteAddress.getPort()); diff --git a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java index 0f3069783f..98e8172f0e 100644 --- a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java @@ -47,7 +47,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.core.xcontent.MediaType; import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; @@ -55,7 +54,6 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.filter.SecurityRequestFactory; -import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequestChannel; import org.opensearch.security.test.helper.file.FileHelper; import org.opensearch.security.user.AuthCredentials; From e749a8e818c24e5f0b6871a17b2417530c93b929 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 16:33:16 +0000 Subject: [PATCH 24/50] more cleanup Signed-off-by: Peter Nied --- .../dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java | 3 ++- .../security/http/proxy/HTTPExtendedProxyAuthenticator.java | 5 ----- .../opensearch/security/ssl/rest/SecuritySSLInfoAction.java | 1 - .../java/org/opensearch/security/support/HTTPHelper.java | 5 ++--- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java index baeb5bb14d..f9447f5e36 100644 --- a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java @@ -282,13 +282,14 @@ public GSSCredential run() throws GSSException { @Override public boolean reRequestAuthentication(final SecurityRequestChannel request, AuthCredentials creds) { + final Map headers = new HashMap<>(); String responseBody = ""; final String negotiateResponseBody = getNegotiateResponseBody(); if (negotiateResponseBody != null) { responseBody = negotiateResponseBody; + headers.put("Content-Type", "application/json"); } - final Map headers = new HashMap<>(); if (creds == null || creds.getNativeCredentials() == null) { headers.put("WWW-Authenticate", "Negotiate"); } else { diff --git a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java index cf5b265598..31908dc98f 100644 --- a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java @@ -84,11 +84,6 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T return credentials.markComplete(); } - @Override - public boolean reRequestAuthentication(final SecurityRequestChannel response, AuthCredentials creds) { - return false; - } - @Override public String getType() { return "extended-proxy"; diff --git a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java index 863d1dbab2..ebf5945a73 100644 --- a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java +++ b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java @@ -87,7 +87,6 @@ public void accept(RestChannel channel) throws Exception { try { final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); - ; SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); X509Certificate[] certs = sslInfo == null ? null : sslInfo.getX509Certs(); X509Certificate[] localCerts = sslInfo == null ? null : sslInfo.getLocalCertificates(); diff --git a/src/main/java/org/opensearch/security/support/HTTPHelper.java b/src/main/java/org/opensearch/security/support/HTTPHelper.java index 8e2de6daa6..fe590f0d34 100644 --- a/src/main/java/org/opensearch/security/support/HTTPHelper.java +++ b/src/main/java/org/opensearch/security/support/HTTPHelper.java @@ -32,8 +32,7 @@ import java.util.Map; import org.apache.logging.log4j.Logger; - -import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.user.AuthCredentials; public class HTTPHelper { @@ -86,7 +85,7 @@ public static AuthCredentials extractCredentials(String authorizationHeader, Log } } - public static boolean containsBadHeader(final SecurityRequestChannel request) { + public static boolean containsBadHeader(final SecurityRequest request) { final Map> headers; From 20c9ea77794faefd22e22274de3fdbf4ed63f248 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 16:47:52 +0000 Subject: [PATCH 25/50] Rename concrete classes Signed-off-by: Peter Nied --- .../auth/http/saml/HTTPSamlAuthenticator.java | 6 +- .../security/auditlog/AuditLog.java | 13 +- .../security/auditlog/NullAuditLog.java | 14 +- .../auditlog/impl/AbstractAuditLog.java | 15 +- .../security/auditlog/impl/AuditLogImpl.java | 13 +- .../security/auditlog/impl/AuditMessage.java | 9 +- .../security/filter/NettyRequest.java | 66 ++++++ .../security/filter/OpenSearchRequest.java | 74 +++++++ .../filter/OpenSearchRequestChannel.java | 59 ++++++ .../filter/SecurityRequestFactory.java | 191 +----------------- .../opensearch/security/http/XFFResolver.java | 6 +- .../security/rest/SecurityWhoAmIAction.java | 1 - .../http/saml/HTTPSamlAuthenticatorTest.java | 4 +- 13 files changed, 243 insertions(+), 228 deletions(-) create mode 100644 src/main/java/org/opensearch/security/filter/NettyRequest.java create mode 100644 src/main/java/org/opensearch/security/filter/OpenSearchRequest.java create mode 100644 src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java 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 f987b88dbe..d25cf0711e 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 @@ -63,8 +63,8 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; -import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequestChannel; import org.opensearch.security.filter.SecurityRequetChannelUnsupported; +import org.opensearch.security.filter.OpenSearchRequestChannel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.PemKeyReader; import org.opensearch.security.user.AuthCredentials; @@ -183,10 +183,10 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, fin if (API_AUTHTOKEN_SUFFIX.equals(suffix)) { // Verficiation of SAML ASC endpoint only works with RestRequests - if (!(request instanceof SecurityRestRequestChannel)) { + if (!(request instanceof OpenSearchRequestChannel)) { throw new SecurityRequetChannelUnsupported(); } else { - final SecurityRestRequestChannel securityRequestChannel = (SecurityRestRequestChannel) request; + final OpenSearchRequestChannel securityRequestChannel = (OpenSearchRequestChannel) request; final RestRequest restRequest = securityRequestChannel.breakEncapsulationForRequest(); final RestChannel channel = securityRequestChannel.breakEncapsulationForChannel(); if (this.authTokenProcessorHandler.handle(restRequest, channel)) { diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLog.java b/src/main/java/org/opensearch/security/auditlog/AuditLog.java index d861af14bd..6f9cfa28f7 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLog.java @@ -37,6 +37,7 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; @@ -44,14 +45,14 @@ public interface AuditLog extends Closeable { // login - void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request); + void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request); - void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request); + void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request); // privs - void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequestChannel request); + void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request); - void logGrantedPrivileges(String effectiveUser, SecurityRequestChannel request); + void logGrantedPrivileges(String effectiveUser, SecurityRequest request); void logMissingPrivileges(String privilege, TransportRequest request, Task task); @@ -63,13 +64,13 @@ public interface AuditLog extends Closeable { // spoof void logBadHeaders(TransportRequest request, String action, Task task); - void logBadHeaders(SecurityRequestChannel request); + void logBadHeaders(SecurityRequest request); void logSecurityIndexAttempt(TransportRequest request, String action, Task task); void logSSLException(TransportRequest request, Throwable t, String action, Task task); - void logSSLException(SecurityRequestChannel request, Throwable t); + void logSSLException(SecurityRequest request, Throwable t); void logDocumentRead(String index, String id, ShardId shardId, Map fieldNameValues); diff --git a/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java b/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java index 440a2eafd5..1ac4492a94 100644 --- a/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/NullAuditLog.java @@ -37,7 +37,7 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; -import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; @@ -49,12 +49,12 @@ public void close() throws IOException { } @Override - public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request) { + public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { // noop, intentionally left empty } @Override - public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request) { + public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { // noop, intentionally left empty } @@ -79,7 +79,7 @@ public void logBadHeaders(TransportRequest request, String action, Task task) { } @Override - public void logBadHeaders(SecurityRequestChannel request) { + public void logBadHeaders(SecurityRequest request) { // noop, intentionally left empty } @@ -94,17 +94,17 @@ public void logSSLException(TransportRequest request, Throwable t, String action } @Override - public void logSSLException(SecurityRequestChannel request, Throwable t) { + public void logSSLException(SecurityRequest request, Throwable t) { // noop, intentionally left empty } @Override - public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequestChannel request) { + public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request) { // noop, intentionally left empty } @Override - public void logGrantedPrivileges(String effectiveUser, SecurityRequestChannel request) { + public void logGrantedPrivileges(String effectiveUser, SecurityRequest request) { // noop, intentionally left empty } diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java index c13e6d028b..5adc1d50fe 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java @@ -65,6 +65,7 @@ import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; import org.opensearch.security.dlic.rest.support.Utils; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.Base64Helper; import org.opensearch.security.support.ConfigConstants; @@ -139,7 +140,7 @@ public ComplianceConfig getComplianceConfig() { } @Override - public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request) { + public void logFailedLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { if (!checkRestFilter(AuditCategory.FAILED_LOGIN, effectiveUser, request)) { return; @@ -157,7 +158,7 @@ public void logFailedLogin(String effectiveUser, boolean securityadmin, String i } @Override - public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequestChannel request) { + public void logSucceededLogin(String effectiveUser, boolean securityadmin, String initiatingUser, SecurityRequest request) { if (!checkRestFilter(AuditCategory.AUTHENTICATED, effectiveUser, request)) { return; @@ -174,7 +175,7 @@ public void logSucceededLogin(String effectiveUser, boolean securityadmin, Strin } @Override - public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequestChannel request) { + public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request) { if (!checkRestFilter(AuditCategory.MISSING_PRIVILEGES, effectiveUser, request)) { return; } @@ -189,7 +190,7 @@ public void logMissingPrivileges(String privilege, String effectiveUser, Securit } @Override - public void logGrantedPrivileges(String effectiveUser, SecurityRequestChannel request) { + public void logGrantedPrivileges(String effectiveUser, SecurityRequest request) { if (!checkRestFilter(AuditCategory.GRANTED_PRIVILEGES, effectiveUser, request)) { return; } @@ -348,7 +349,7 @@ public void logBadHeaders(TransportRequest request, String action, Task task) { } @Override - public void logBadHeaders(SecurityRequestChannel request) { + public void logBadHeaders(SecurityRequest request) { if (!checkRestFilter(AuditCategory.BAD_HEADERS, getUser(), request)) { return; @@ -437,7 +438,7 @@ public void logSSLException(TransportRequest request, Throwable t, String action } @Override - public void logSSLException(SecurityRequestChannel request, Throwable t) { + public void logSSLException(SecurityRequest request, Throwable t) { if (!checkRestFilter(AuditCategory.SSL_EXCEPTION, getUser(), request)) { return; @@ -898,7 +899,7 @@ private boolean checkComplianceFilter( } @VisibleForTesting - boolean checkRestFilter(final AuditCategory category, final String effectiveUser, SecurityRequestChannel request) { + boolean checkRestFilter(final AuditCategory category, final String effectiveUser, SecurityRequest request) { final boolean isTraceEnabled = log.isTraceEnabled(); if (isTraceEnabled) { log.trace( diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java index 1677ebb86a..ced86ffa14 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java @@ -33,6 +33,7 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.auditlog.routing.AuditMessageRouter; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; @@ -131,28 +132,28 @@ protected void save(final AuditMessage msg) { } @Override - public void logFailedLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequestChannel request) { + public void logFailedLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequest request) { if (enabled) { super.logFailedLogin(effectiveUser, securityAdmin, initiatingUser, request); } } @Override - public void logSucceededLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequestChannel request) { + public void logSucceededLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequest request) { if (enabled) { super.logSucceededLogin(effectiveUser, securityAdmin, initiatingUser, request); } } @Override - public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequestChannel request) { + public void logMissingPrivileges(String privilege, String effectiveUser, SecurityRequest request) { if (enabled) { super.logMissingPrivileges(privilege, effectiveUser, request); } } @Override - public void logGrantedPrivileges(String effectiveUser, SecurityRequestChannel request) { + public void logGrantedPrivileges(String effectiveUser, SecurityRequest request) { if (enabled) { super.logGrantedPrivileges(effectiveUser, request); } @@ -187,7 +188,7 @@ public void logBadHeaders(TransportRequest request, String action, Task task) { } @Override - public void logBadHeaders(SecurityRequestChannel request) { + public void logBadHeaders(SecurityRequest request) { if (enabled) { super.logBadHeaders(request); } @@ -208,7 +209,7 @@ public void logSSLException(TransportRequest request, Throwable t, String action } @Override - public void logSSLException(SecurityRequestChannel request, Throwable t) { + public void logSSLException(SecurityRequest request, Throwable t) { if (enabled) { super.logSSLException(request, t); } diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java index c142fbc2d7..d62d2088c7 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java @@ -48,8 +48,9 @@ import org.opensearch.security.auditlog.AuditLog.Origin; import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.dlic.rest.support.Utils; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; -import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequestChannel; +import org.opensearch.security.filter.OpenSearchRequest; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.support.WildcardMatcher; @@ -371,7 +372,7 @@ void addRestMethod(final RestRequest.Method method) { } } - void addRestRequestInfo(final SecurityRequestChannel request, final AuditConfig.Filter filter) { + void addRestRequestInfo(final SecurityRequest request, final AuditConfig.Filter filter) { if (request != null) { final String path = request.path().toString(); addPath(path); @@ -381,12 +382,12 @@ void addRestRequestInfo(final SecurityRequestChannel request, final AuditConfig. if (filter.shouldLogRequestBody()) { - if (!(request instanceof SecurityRestRequestChannel)) { + if (!(request instanceof OpenSearchRequest)) { // The request body is only avaliable on some request sources return; } - final SecurityRestRequestChannel securityRestRequest = (SecurityRestRequestChannel) request; + final OpenSearchRequest securityRestRequest = (OpenSearchRequest) request; final RestRequest restRequest = securityRestRequest.breakEncapsulationForRequest(); if (!(restRequest.hasContentOrSourceParam())) { diff --git a/src/main/java/org/opensearch/security/filter/NettyRequest.java b/src/main/java/org/opensearch/security/filter/NettyRequest.java new file mode 100644 index 0000000000..6e0d1a0181 --- /dev/null +++ b/src/main/java/org/opensearch/security/filter/NettyRequest.java @@ -0,0 +1,66 @@ +package org.opensearch.security.filter; + +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.net.ssl.SSLEngine; + +import org.opensearch.rest.RestRequest.Method; + +class NettyRequest implements SecurityRequestChannel { + @Override + public Map> getHeaders() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getHeaders'"); + } + + @Override + public SSLEngine getSSLEngine() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getSSLEngine'"); + } + + @Override + public String path() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'path'"); + } + + @Override + public Method method() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'method'"); + } + + @Override + public Optional getRemoteAddress() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'getRemoteAddress'"); + } + + @Override + public String uri() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'uri'"); + } + + @Override + public Map params() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'params'"); + } + + @Override + public boolean hasCompleted() { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'hasCompleted'"); + } + + @Override + public boolean completeWithResponse(int statusCode, Map headers, String body) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Unimplemented method 'completeWithResponse'"); + } +} \ No newline at end of file diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java new file mode 100644 index 0000000000..66d3f5d269 --- /dev/null +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java @@ -0,0 +1,74 @@ +package org.opensearch.security.filter; + +import java.net.InetSocketAddress; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.net.ssl.SSLEngine; + +import org.opensearch.http.netty4.Netty4HttpChannel; +import org.opensearch.rest.RestRequest; +import org.opensearch.rest.RestRequest.Method; + +import io.netty.handler.ssl.SslHandler; + +public class OpenSearchRequest implements SecurityRequest { + + protected final RestRequest underlyingRequest; + + OpenSearchRequest(final RestRequest request) { + underlyingRequest = request; + } + + @Override + public Map> getHeaders() { + return underlyingRequest.getHeaders(); + } + + @Override + public SSLEngine getSSLEngine() { + if (underlyingRequest == null + || underlyingRequest.getHttpChannel() == null + || !(underlyingRequest.getHttpChannel() instanceof Netty4HttpChannel)) { + return null; + } + + final Netty4HttpChannel httpChannel = (Netty4HttpChannel) underlyingRequest.getHttpChannel(); + SslHandler sslhandler = (SslHandler) httpChannel.getNettyChannel().pipeline().get("ssl_http"); + if (sslhandler == null && httpChannel.inboundPipeline() != null) { + sslhandler = (SslHandler) httpChannel.inboundPipeline().get("ssl_http"); + } + + return sslhandler != null ? sslhandler.engine() : null; + } + + @Override + public String path() { + return underlyingRequest.path(); + } + + @Override + public Method method() { + return underlyingRequest.method(); + } + + @Override + public Optional getRemoteAddress() { + return Optional.ofNullable(this.underlyingRequest.getHttpChannel().getRemoteAddress()); + } + + @Override + public String uri() { + return underlyingRequest.uri(); + } + + @Override + public Map params() { + return underlyingRequest.params(); + } + + public RestRequest breakEncapsulationForRequest() { + return underlyingRequest; + } +} \ No newline at end of file diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java new file mode 100644 index 0000000000..e3b49645a6 --- /dev/null +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -0,0 +1,59 @@ +package org.opensearch.security.filter; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.opensearch.common.collect.Tuple; +import org.opensearch.core.rest.RestStatus; +import org.opensearch.rest.BytesRestResponse; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestRequest; + +public class OpenSearchRequestChannel extends OpenSearchRequest implements SecurityRequestChannel { + + private final Logger log = LogManager.getLogger(OpenSearchRequest.class); + + private AtomicBoolean hasCompleted = new AtomicBoolean(false); + private final RestChannel underlyingChannel; + + OpenSearchRequestChannel(final RestRequest request, final RestChannel channel) { + super(request); + underlyingChannel = channel; + } + + @Override + public boolean hasCompleted() { + return hasCompleted.get(); + } + + @Override + public boolean completeWithResponse(int statusCode, Map headers, String body) { + if (underlyingChannel == null) { + throw new UnsupportedOperationException("Channel was not defined"); + } + + try { + final BytesRestResponse restResponse = new BytesRestResponse(RestStatus.fromCode(statusCode), body); + headers.forEach(restResponse::addHeader); + underlyingChannel.sendResponse(restResponse); + + return true; + } catch (final Exception e) { + log.error("Error when attempting to send response", e); + throw new RuntimeException(e); + } finally { + hasCompleted.set(true); + } + } + + /** Marks a request completed */ + public void markCompleted() { + hasCompleted.set(true); + } + + public RestChannel breakEncapsulationForChannel() { + return underlyingChannel; + } +} \ No newline at end of file diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index baba40eff3..80405138fd 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -1,24 +1,7 @@ package org.opensearch.security.filter; -import java.net.InetSocketAddress; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.net.ssl.SSLEngine; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.opensearch.common.collect.Tuple; -import org.opensearch.core.rest.RestStatus; -import org.opensearch.http.netty4.Netty4HttpChannel; -import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; -import org.opensearch.rest.RestRequest.Method; - -import io.netty.handler.ssl.SslHandler; public class SecurityRequestFactory { @@ -27,180 +10,10 @@ public static SecurityRequestChannel from() { } public static SecurityRequest from(final RestRequest request) { - return new SecurityRestRequest(request); + return new OpenSearchRequest(request); } public static SecurityRequestChannel from(final RestRequest request, final RestChannel channel) { - return new SecurityRestRequestChannel(request, channel); - } - - public static class SecurityRestRequest implements SecurityRequest { - - protected final RestRequest underlyingRequest; - - SecurityRestRequest(final RestRequest request) { - underlyingRequest = request; - } - - @Override - public Map> getHeaders() { - return underlyingRequest.getHeaders(); - } - - @Override - public SSLEngine getSSLEngine() { - if (underlyingRequest == null - || underlyingRequest.getHttpChannel() == null - || !(underlyingRequest.getHttpChannel() instanceof Netty4HttpChannel)) { - return null; - } - - final Netty4HttpChannel httpChannel = (Netty4HttpChannel) underlyingRequest.getHttpChannel(); - SslHandler sslhandler = (SslHandler) httpChannel.getNettyChannel().pipeline().get("ssl_http"); - if (sslhandler == null && httpChannel.inboundPipeline() != null) { - sslhandler = (SslHandler) httpChannel.inboundPipeline().get("ssl_http"); - } - - return sslhandler != null ? sslhandler.engine() : null; - } - - @Override - public String path() { - return underlyingRequest.path(); - } - - @Override - public Method method() { - return underlyingRequest.method(); - } - - @Override - public Optional getRemoteAddress() { - return Optional.ofNullable(this.underlyingRequest.getHttpChannel().getRemoteAddress()); - } - - @Override - public String uri() { - return underlyingRequest.uri(); - } - - @Override - public Map params() { - return underlyingRequest.params(); - } - - public RestRequest breakEncapsulationForRequest() { - return underlyingRequest; - } - } - - public static class SecurityRestRequestChannel extends SecurityRestRequest implements SecurityRequestChannel { - - private final Logger log = LogManager.getLogger(SecurityRestRequest.class); - - private AtomicBoolean hasCompleted = new AtomicBoolean(false); - private final RestChannel underlyingChannel; - - SecurityRestRequestChannel(final RestRequest request, final RestChannel channel) { - super(request); - underlyingChannel = channel; - } - - @Override - public boolean hasCompleted() { - return hasCompleted.get(); - } - - @Override - public boolean completeWithResponse(int statusCode, Map headers, String body) { - if (underlyingChannel == null) { - throw new UnsupportedOperationException("Channel was not defined"); - } - - try { - final BytesRestResponse restResponse = new BytesRestResponse(RestStatus.fromCode(statusCode), body); - headers.forEach(restResponse::addHeader); - underlyingChannel.sendResponse(restResponse); - - return true; - } catch (final Exception e) { - log.error("Error when attempting to send response", e); - throw new RuntimeException(e); - } finally { - hasCompleted.set(true); - } - } - - /** - * Breaks the encapustion of the interface to get access to the underlying RestRequest / RestChannel. - */ - public Tuple breakEncapsulation() { - return Tuple.tuple(underlyingRequest, underlyingChannel); - } - - /** Marks a request completed */ - public void markCompleted() { - hasCompleted.set(true); - } - - public RestChannel breakEncapsulationForChannel() { - return underlyingChannel; - } - } - - protected static class NettyRequest implements SecurityRequestChannel { - @Override - public Map> getHeaders() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getHeaders'"); - } - - @Override - public SSLEngine getSSLEngine() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getSSLEngine'"); - } - - @Override - public String path() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'path'"); - } - - @Override - public Method method() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'method'"); - } - - @Override - public Optional getRemoteAddress() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getRemoteAddress'"); - } - - @Override - public String uri() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'uri'"); - } - - @Override - public Map params() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'params'"); - } - - @Override - public boolean hasCompleted() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'hasCompleted'"); - } - - @Override - public boolean completeWithResponse(int statusCode, Map headers, String body) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'completeWithResponse'"); - } + return new OpenSearchRequestChannel(request, channel); } } diff --git a/src/main/java/org/opensearch/security/http/XFFResolver.java b/src/main/java/org/opensearch/security/http/XFFResolver.java index e0f83a422f..e9ad412831 100644 --- a/src/main/java/org/opensearch/security/http/XFFResolver.java +++ b/src/main/java/org/opensearch/security/http/XFFResolver.java @@ -38,7 +38,7 @@ import org.opensearch.rest.RestRequest; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequest; +import org.opensearch.security.filter.OpenSearchRequest; import org.opensearch.security.securityconf.DynamicConfigModel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.threadpool.ThreadPool; @@ -62,8 +62,8 @@ public TransportAddress resolve(final SecurityRequest request) throws OpenSearch } boolean requestFromNetty = false; - if (request instanceof SecurityRestRequest) { - final SecurityRestRequest securityRequestChannel = (SecurityRestRequest) request; + if (request instanceof OpenSearchRequest) { + final OpenSearchRequest securityRequestChannel = (OpenSearchRequest) request; final RestRequest restRequest = securityRequestChannel.breakEncapsulationForRequest(); requestFromNetty = restRequest.getHttpChannel() instanceof Netty4HttpChannel; diff --git a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java index bfc2b99a0e..4377215ccd 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java @@ -100,7 +100,6 @@ public void accept(RestChannel channel) throws Exception { try { final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); - ; SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { diff --git a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java index 98e8172f0e..dd030da5ed 100644 --- a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java @@ -54,7 +54,7 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.filter.SecurityRequestFactory; -import org.opensearch.security.filter.SecurityRequestFactory.SecurityRestRequestChannel; +import org.opensearch.security.filter.OpenSearchRequestChannel; import org.opensearch.security.test.helper.file.FileHelper; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.FakeRestRequest; @@ -160,7 +160,7 @@ public void basicTest() throws Exception { private TestRestChannel sendToAuthenticator(HTTPSamlAuthenticator samlAuthenticator, RestRequest request) { TestRestChannel testChannel = new TestRestChannel(request); - SecurityRestRequestChannel tokenRestChannel = (SecurityRestRequestChannel) SecurityRequestFactory.from(request, testChannel); + OpenSearchRequestChannel tokenRestChannel = (OpenSearchRequestChannel) SecurityRequestFactory.from(request, testChannel); samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); return testChannel; From 22991e3bf9b8267232a73f7f2c95ecc988473d52 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 17:42:06 +0000 Subject: [PATCH 26/50] Maybe final changes batch Signed-off-by: Peter Nied --- src/main/java/org/opensearch/security/auditlog/AuditLog.java | 1 - .../opensearch/security/auditlog/impl/AbstractAuditLog.java | 1 - .../org/opensearch/security/auditlog/impl/AuditLogImpl.java | 1 - .../org/opensearch/security/auditlog/impl/AuditMessage.java | 1 - .../java/org/opensearch/security/auth/BackendRegistry.java | 4 +++- .../opensearch/security/dlic/rest/api/AbstractApiAction.java | 2 ++ .../java/org/opensearch/security/filter/NettyRequest.java | 2 +- .../org/opensearch/security/filter/OpenSearchRequest.java | 2 +- .../opensearch/security/filter/OpenSearchRequestChannel.java | 3 +-- .../security/http/proxy/HTTPExtendedProxyAuthenticator.java | 1 - .../opensearch/security/rest/SecurityConfigUpdateAction.java | 3 ++- 11 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/opensearch/security/auditlog/AuditLog.java b/src/main/java/org/opensearch/security/auditlog/AuditLog.java index 6f9cfa28f7..997b9e4b87 100644 --- a/src/main/java/org/opensearch/security/auditlog/AuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/AuditLog.java @@ -38,7 +38,6 @@ import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.compliance.ComplianceConfig; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.tasks.Task; import org.opensearch.transport.TransportRequest; diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java index 5adc1d50fe..de53f0b744 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java @@ -66,7 +66,6 @@ import org.opensearch.security.compliance.ComplianceConfig; import org.opensearch.security.dlic.rest.support.Utils; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.support.Base64Helper; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.User; diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java index ced86ffa14..8da4b13d4c 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java @@ -34,7 +34,6 @@ import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.auditlog.routing.AuditMessageRouter; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportRequest; diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java index d62d2088c7..a41b4625c2 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditMessage.java @@ -49,7 +49,6 @@ import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.dlic.rest.support.Utils; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.OpenSearchRequest; import org.opensearch.security.securityconf.impl.CType; import org.opensearch.security.support.WildcardMatcher; diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index d1de76048b..27478707d6 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -287,6 +287,8 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte if (isTraceEnabled) { log.trace("No 'Authorization' header, send 401 and 'WWW-Authenticate Basic'"); } + notifyIpAuthFailureListeners(request, authCredentials); + return; } else { // no reRequest possible if (isTraceEnabled) { @@ -299,7 +301,7 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte if (!ac.isComplete()) { // credentials found in request but we need another client challenge if (httpAuthenticator.reRequestAuthentication(request, ac)) { - // auditLog.logFailedLogin(ac.getUsername()+" ", request); --noauditlog + notifyIpAuthFailureListeners(request, ac); return; } else { // no reRequest possible diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index ca4fb93770..15308aaa6c 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -546,6 +546,7 @@ protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClie // check if .opendistro_security index has been initialized if (!ensureIndexExists()) { internalSeverError(channel, RequestContentValidator.ValidationError.SECURITY_NOT_INITIALIZED.message()); + return; } // check if request is authorized @@ -560,6 +561,7 @@ protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClie // for rest request request.params().clear(); forbidden(channel, "No permission to access REST API: " + authError); + return; } else { securityApiDependencies.auditLog().logGrantedPrivileges(userName, securityRequest); } diff --git a/src/main/java/org/opensearch/security/filter/NettyRequest.java b/src/main/java/org/opensearch/security/filter/NettyRequest.java index 6e0d1a0181..3d1a2d028c 100644 --- a/src/main/java/org/opensearch/security/filter/NettyRequest.java +++ b/src/main/java/org/opensearch/security/filter/NettyRequest.java @@ -63,4 +63,4 @@ public boolean completeWithResponse(int statusCode, Map headers, // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'completeWithResponse'"); } -} \ No newline at end of file +} diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java index 66d3f5d269..376a46ec68 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java @@ -71,4 +71,4 @@ public Map params() { public RestRequest breakEncapsulationForRequest() { return underlyingRequest; } -} \ No newline at end of file +} diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index e3b49645a6..c47e4207dd 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -5,7 +5,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.common.collect.Tuple; import org.opensearch.core.rest.RestStatus; import org.opensearch.rest.BytesRestResponse; import org.opensearch.rest.RestChannel; @@ -56,4 +55,4 @@ public void markCompleted() { public RestChannel breakEncapsulationForChannel() { return underlyingChannel; } -} \ No newline at end of file +} diff --git a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java index 31908dc98f..9a16e6c61b 100644 --- a/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/proxy/HTTPExtendedProxyAuthenticator.java @@ -38,7 +38,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.common.Strings; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.http.HTTPProxyAuthenticator; import org.opensearch.security.user.AuthCredentials; diff --git a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java index 04c9ef6bd4..f7fe32bbfc 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java @@ -73,8 +73,9 @@ public List routes() { @Override protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + String[] configTypes = request.paramAsStringArrayOrEmptyIfAll("config_types"); + return channel -> { - String[] configTypes = request.paramAsStringArrayOrEmptyIfAll("config_types"); final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); From 828ef2be96c9d2b7977a4273a2d3634513b4bfa4 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 18:23:49 +0000 Subject: [PATCH 27/50] Fix parameter consumption Signed-off-by: Peter Nied --- .../security/dlic/rest/api/AbstractApiAction.java | 7 ++++--- .../security/filter/OpenSearchRequestChannel.java | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index 15308aaa6c..fb0e584f66 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -536,12 +536,13 @@ public void onFailure(Exception e) { @Override protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + // consume all parameters first so we can return a correct HTTP status, + // not 400 + consumeParameters(request); + return channel -> { final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); - // consume all parameters first so we can return a correct HTTP status, - // not 400 - consumeParameters(request); // check if .opendistro_security index has been initialized if (!ensureIndexExists()) { diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index c47e4207dd..50273fc137 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -35,7 +35,9 @@ public boolean completeWithResponse(int statusCode, Map headers, try { final BytesRestResponse restResponse = new BytesRestResponse(RestStatus.fromCode(statusCode), body); - headers.forEach(restResponse::addHeader); + if (headers != null) { + headers.forEach(restResponse::addHeader); + } underlyingChannel.sendResponse(restResponse); return true; From 641c1954f602ba549a333c665860da930fda5f2d Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 19:57:24 +0000 Subject: [PATCH 28/50] Fix incorrect error message Signed-off-by: Peter Nied --- .../java/org/opensearch/security/filter/SecurityRestFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 879ba4ce92..4a6513c6c8 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -224,7 +224,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); - requestChannel.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, null, exception.toString()); + requestChannel.completeWithResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString()); return; } From 74a925d0a34dc64e7f61a3a1bd9731f7aa59ac6a Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 20:15:26 +0000 Subject: [PATCH 29/50] javadoc Signed-off-by: Peter Nied --- .../security/filter/NettyRequest.java | 66 ------------------- .../security/filter/OpenSearchRequest.java | 4 ++ .../filter/OpenSearchRequestChannel.java | 5 ++ .../security/filter/SecurityRequest.java | 10 +++ .../filter/SecurityRequestChannel.java | 4 ++ .../filter/SecurityRequestFactory.java | 9 +-- 6 files changed, 28 insertions(+), 70 deletions(-) delete mode 100644 src/main/java/org/opensearch/security/filter/NettyRequest.java diff --git a/src/main/java/org/opensearch/security/filter/NettyRequest.java b/src/main/java/org/opensearch/security/filter/NettyRequest.java deleted file mode 100644 index 3d1a2d028c..0000000000 --- a/src/main/java/org/opensearch/security/filter/NettyRequest.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.opensearch.security.filter; - -import java.net.InetSocketAddress; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import javax.net.ssl.SSLEngine; - -import org.opensearch.rest.RestRequest.Method; - -class NettyRequest implements SecurityRequestChannel { - @Override - public Map> getHeaders() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getHeaders'"); - } - - @Override - public SSLEngine getSSLEngine() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getSSLEngine'"); - } - - @Override - public String path() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'path'"); - } - - @Override - public Method method() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'method'"); - } - - @Override - public Optional getRemoteAddress() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'getRemoteAddress'"); - } - - @Override - public String uri() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'uri'"); - } - - @Override - public Map params() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'params'"); - } - - @Override - public boolean hasCompleted() { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'hasCompleted'"); - } - - @Override - public boolean completeWithResponse(int statusCode, Map headers, String body) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'completeWithResponse'"); - } -} diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java index 376a46ec68..bc07871619 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java @@ -13,6 +13,9 @@ import io.netty.handler.ssl.SslHandler; +/** + * Wraps the functionality of RestRequest for use in the security plugin + */ public class OpenSearchRequest implements SecurityRequest { protected final RestRequest underlyingRequest; @@ -68,6 +71,7 @@ public Map params() { return underlyingRequest.params(); } + /** Gets access to the underlying request object */ public RestRequest breakEncapsulationForRequest() { return underlyingRequest; } diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index 50273fc137..7410b704ff 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -33,6 +33,10 @@ public boolean completeWithResponse(int statusCode, Map headers, throw new UnsupportedOperationException("Channel was not defined"); } + if (hasCompleted()) { + throw new UnsupportedOperationException("This channel has already completed"); + } + try { final BytesRestResponse restResponse = new BytesRestResponse(RestStatus.fromCode(statusCode), body); if (headers != null) { @@ -54,6 +58,7 @@ public void markCompleted() { hasCompleted.set(true); } + /** Gets access to the underlying channel object */ public RestChannel breakEncapsulationForChannel() { return underlyingChannel; } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java index 8b9fa9bc70..c3d5803860 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -10,23 +10,33 @@ import org.opensearch.rest.RestRequest.Method; +/** How the security plugin interacts with requests */ public interface SecurityRequest { + + /** Collection of headers associated with the request */ public Map> getHeaders(); + /** The SSLEngine associated with the request */ public SSLEngine getSSLEngine(); + /** The path of the request */ public String path(); + /** The method type of this request */ public Method method(); + /** The remote address of the request, possible null */ public Optional getRemoteAddress(); + /** The full uri of the request */ public String uri(); + /** Finds the first value of the matching header or null */ default public String header(final String headerName) { final Optional>> headersMap = Optional.ofNullable(getHeaders()); return headersMap.map(headers -> headers.get(headerName)).map(List::stream).flatMap(Stream::findFirst).orElse(null); } + /** The parameters associated with this request */ public Map params(); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java index 7da675f881..72f7c3b32b 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java @@ -7,7 +7,11 @@ */ public interface SecurityRequestChannel extends SecurityRequest { + /** + * If this channel has been been used to send a response + */ public boolean hasCompleted(); + /** Use this channel to send a response */ public boolean completeWithResponse(final int statusCode, final Map headers, final String body); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index 80405138fd..beb6103728 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -3,16 +3,17 @@ import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; +/** + * Generates wrapped versions of requests for use in the security plugin + */ public class SecurityRequestFactory { - public static SecurityRequestChannel from() { - return null; - } - + /** Creates a security requset from a RestRequest */ public static SecurityRequest from(final RestRequest request) { return new OpenSearchRequest(request); } + /** Creates a security request channel from a RestRequest & RestChannel */ public static SecurityRequestChannel from(final RestRequest request, final RestChannel channel) { return new OpenSearchRequestChannel(request, channel); } From 21e10305df3441cf1db07b55e207a228f5501c96 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Tue, 3 Oct 2023 20:16:10 +0000 Subject: [PATCH 30/50] Remove the Authenticatiion verifier Signed-off-by: Peter Nied --- .../security/http/AuthenicationVerifier.java | 46 ------------------- 1 file changed, 46 deletions(-) delete mode 100644 src/main/java/org/opensearch/security/http/AuthenicationVerifier.java diff --git a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java b/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java deleted file mode 100644 index 9acbfb5141..0000000000 --- a/src/main/java/org/opensearch/security/http/AuthenicationVerifier.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.opensearch.security.http; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.handler.codec.http.HttpRequest; -import io.netty.handler.codec.http.DefaultFullHttpResponse; -import io.netty.handler.codec.http.FullHttpResponse; -import io.netty.handler.codec.http.HttpResponseStatus; -import io.netty.handler.codec.http.HttpVersion; -import io.netty.util.ReferenceCountUtil; - -public class AuthenicationVerifier extends ChannelInboundHandlerAdapter { - - final static Logger log = LogManager.getLogger(AuthenicationVerifier.class); - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if (!(msg instanceof HttpRequest)) { - ctx.fireChannelRead(msg); - } - - HttpRequest request = (HttpRequest) msg; - if (!isAuthenticated(request)) { - final FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.UNAUTHORIZED); - ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); - ReferenceCountUtil.release(msg); - } else { - // Lets the request pass to the next channel handler - ctx.fireChannelRead(msg); - } - } - - private boolean isAuthenticated(HttpRequest request) { - - log.info("Checking if request is authenticated:\n" + request); - - final boolean shouldBlock = request.headers().contains("blockme"); - - return !shouldBlock; - } - -} From 09207c29977b19c7e8d6107fb365fb1cd6899df1 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 14:32:14 +0000 Subject: [PATCH 31/50] Debug statement Signed-off-by: Peter Nied --- .../opensearch/security/filter/OpenSearchRequestChannel.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index 7410b704ff..8e6a9cb8b3 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -29,6 +29,9 @@ public boolean hasCompleted() { @Override public boolean completeWithResponse(int statusCode, Map headers, String body) { + // TODO: Remove + new Exception("&&& completeWithResponse calling stack trace").printStackTrace(); + if (underlyingChannel == null) { throw new UnsupportedOperationException("Channel was not defined"); } From 659088dc0ebfa5ddb2adfa24bff0141e647b4885 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 15:17:39 +0000 Subject: [PATCH 32/50] Even more logging Signed-off-by: Peter Nied --- .../security/filter/OpenSearchRequestChannel.java | 1 + .../org/opensearch/security/filter/SecurityRestFilter.java | 6 +++++- .../security/securityconf/impl/AllowlistingSettings.java | 1 + .../security/securityconf/impl/WhitelistingSettings.java | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index 8e6a9cb8b3..f325a1a192 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -29,6 +29,7 @@ public boolean hasCompleted() { @Override public boolean completeWithResponse(int statusCode, Map headers, String body) { + System.out.println("@32 - completeWithResponse" + statusCode); // TODO: Remove new Exception("&&& completeWithResponse calling stack trace").printStackTrace(); diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 4a6513c6c8..6088f76397 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -155,7 +155,7 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { // Caller was authorized, forward the request to the handler original.handleRequest(request, channel, client); } - } + } }; } @@ -203,6 +203,7 @@ private void authorizeRequest(RestHandler original, SecurityRequestChannel reque err = String.format("no permissions for %s and %s", pres.getMissingPrivileges(), user); } log.debug(err); + System.out.println("@206 - authorizeRequest 401"); request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, null, err); return; } @@ -216,6 +217,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); + System.out.println("@220 - checkAndAuthenticateRequest 403"); requestChannel.completeWithResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString()); return; } @@ -224,6 +226,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); + System.out.println("@229 - checkAndAuthenticateRequest 403"); requestChannel.completeWithResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString()); return; } @@ -244,6 +247,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t } catch (SSLPeerUnverifiedException e) { log.error("No ssl info", e); auditLog.logSSLException(requestChannel, e); + System.out.println("@250 - authorizeRequest 403"); requestChannel.completeWithResponse(HttpStatus.SC_FORBIDDEN, null, null); return; } diff --git a/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java b/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java index 98fc7a266a..9ab023719a 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java @@ -110,6 +110,7 @@ private boolean requestIsAllowlisted(RestRequest request) { public boolean checkRequestIsAllowed(RestRequest request, RestChannel channel, NodeClient client) throws IOException { // if allowlisting is enabled but the request is not allowlisted, then return false, otherwise true. if (this.enabled && !requestIsAllowlisted(request)) { + System.out.println("@113 - checkRequestIsAllowed 403"); channel.sendResponse( new BytesRestResponse( RestStatus.FORBIDDEN, diff --git a/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java b/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java index 4462bae90f..4e6bcaf688 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java @@ -111,6 +111,7 @@ private boolean requestIsWhitelisted(RestRequest request) { public boolean checkRequestIsAllowed(RestRequest request, RestChannel channel, NodeClient client) throws IOException { // if whitelisting is enabled but the request is not whitelisted, then return false, otherwise true. if (this.enabled && !requestIsWhitelisted(request)) { + System.out.println("@114 - checkRequestIsAllowed 403"); channel.sendResponse( new BytesRestResponse( RestStatus.FORBIDDEN, From c019f02c42130b8e33dd1bb5c7953381989db0b1 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 15:23:42 +0000 Subject: [PATCH 33/50] Even more loogging Signed-off-by: Peter Nied --- .../java/org/opensearch/security/auth/BackendRegistry.java | 2 ++ .../opensearch/security/dlic/rest/api/AbstractApiAction.java | 4 ++++ .../opensearch/security/dlic/rest/api/NodesDnApiAction.java | 2 ++ .../java/org/opensearch/security/filter/SecurityFilter.java | 2 ++ .../opensearch/security/rest/SecurityConfigUpdateAction.java | 2 ++ .../org/opensearch/security/rest/SecurityWhoAmIAction.java | 1 + .../java/org/opensearch/security/rest/TenantInfoAction.java | 1 + 7 files changed, 14 insertions(+) diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 27478707d6..ef91129c4b 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -575,6 +575,7 @@ private User impersonate(final SecurityRequestChannel request, final User origin } if (adminDns.isAdminDN(impersonatedUserHeader)) { + System.out.println("@607 - impersonate, 403"); throw new OpenSearchSecurityException( "It is not allowed to impersonate as an adminuser '" + impersonatedUserHeader + "'", RestStatus.FORBIDDEN @@ -582,6 +583,7 @@ private User impersonate(final SecurityRequestChannel request, final User origin } if (!adminDns.isRestImpersonationAllowed(originalUser.getName(), impersonatedUserHeader)) { + System.out.println("@615 - impersonate, 403"); throw new OpenSearchSecurityException( "'" + originalUser.getName() + "' is not allowed to impersonate as '" + impersonatedUserHeader + "'", RestStatus.FORBIDDEN diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index fb0e584f66..933c099395 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -373,6 +373,7 @@ protected final ValidationResult> loadConfigurat ) { final var configuration = load(cType, logComplianceEvent); if (configuration.getSeqNo() < 0) { + System.out.println("@374 - abstract API action, 403"); return ValidationResult.error( RestStatus.FORBIDDEN, forbiddenMessage( @@ -413,16 +414,19 @@ public RestApiAdminPrivilegesEvaluator restApiAdminPrivilegesEvaluator() { @Override public ValidationResult onConfigDelete(SecurityConfiguration securityConfiguration) throws IOException { + System.out.println("@415 - abstract API action, 403"); return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } @Override public ValidationResult onConfigLoad(SecurityConfiguration securityConfiguration) throws IOException { + System.out.println("@421 - abstract API action, 403"); return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } @Override public ValidationResult onConfigChange(SecurityConfiguration securityConfiguration) throws IOException { + System.out.println("@427 - abstract API action, 403"); return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java index a10139b594..19b7006d8d 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java @@ -35,6 +35,7 @@ import org.opensearch.security.securityconf.impl.NodesDn; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; import org.opensearch.security.support.ConfigConstants; +import org.opensearch.security.tools.SecurityAdmin; import org.opensearch.threadpool.ThreadPool; import static org.opensearch.security.dlic.rest.api.Responses.forbiddenMessage; @@ -138,6 +139,7 @@ public RestApiAdminPrivilegesEvaluator restApiAdminPrivilegesEvaluator() { public ValidationResult isAllowedToChangeImmutableEntity(SecurityConfiguration securityConfiguration) throws IOException { if (STATIC_OPENSEARCH_YML_NODES_DN.equals(securityConfiguration.entityName())) { + System.out.println("@142 - nodes dn API action, 403"); return ValidationResult.error( RestStatus.FORBIDDEN, forbiddenMessage("Resource '" + STATIC_OPENSEARCH_YML_NODES_DN + "' is read-only.") diff --git a/src/main/java/org/opensearch/security/filter/SecurityFilter.java b/src/main/java/org/opensearch/security/filter/SecurityFilter.java index f433a5857d..34e45ffeda 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityFilter.java @@ -464,6 +464,7 @@ public void onFailure(Exception e) { : String.format("no permissions for %s and %s", pres.getMissingPrivileges(), user); } log.debug(err); + System.out.println("@467 - apply0, 403"); listener.onFailure(new OpenSearchSecurityException(err, RestStatus.FORBIDDEN)); } } catch (OpenSearchException e) { @@ -514,6 +515,7 @@ private boolean checkImmutableIndices(Object request, ActionListener listener) { || request instanceof IndicesAliasesRequest; if (isModifyIndexRequest && isRequestIndexImmutable(request)) { + System.out.println("@517 - checkImmutableIndices, 403"); listener.onFailure(new OpenSearchSecurityException("Index is immutable", RestStatus.FORBIDDEN)); return true; } diff --git a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java index f7fe32bbfc..d9a25a8c3d 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java @@ -81,6 +81,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { + System.out.println("@84 - update config action 403"); channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); return; } @@ -89,6 +90,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli // only allowed for admins if (user == null || !adminDns.isAdmin(user)) { + System.out.println("@93 - update config action 403"); channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); return; } else { diff --git a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java index 4377215ccd..d947c5c708 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java @@ -103,6 +103,7 @@ public void accept(RestChannel channel) throws Exception { SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { + System.out.println("@104 - who am i action, 403"); response = new BytesRestResponse(RestStatus.FORBIDDEN, "No security data"); } else { diff --git a/src/main/java/org/opensearch/security/rest/TenantInfoAction.java b/src/main/java/org/opensearch/security/rest/TenantInfoAction.java index f3afc0f006..d43f1c2e6e 100644 --- a/src/main/java/org/opensearch/security/rest/TenantInfoAction.java +++ b/src/main/java/org/opensearch/security/rest/TenantInfoAction.java @@ -114,6 +114,7 @@ public void accept(RestChannel channel) throws Exception { // only allowed for admins or the kibanaserveruser if (!isAuthorized()) { + System.out.println("@117 - tenant info action, 403"); response = new BytesRestResponse(RestStatus.FORBIDDEN, ""); } else { From e8e5155073c5257d59e509fc369e22da662485c2 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 15:50:32 +0000 Subject: [PATCH 34/50] Even more logging Signed-off-by: Peter Nied --- .../dlic/rest/api/AbstractApiAction.java | 91 +++++++++---------- 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index 933c099395..7733e81741 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -544,58 +544,51 @@ protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClie // not 400 consumeParameters(request); - return channel -> { - final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); - - - // check if .opendistro_security index has been initialized - if (!ensureIndexExists()) { - internalSeverError(channel, RequestContentValidator.ValidationError.SECURITY_NOT_INITIALIZED.message()); - return; - } - - // check if request is authorized - final String authError = securityApiDependencies.restApiPrivilegesEvaluator().checkAccessPermissions(request, endpoint); - - final User user = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); - final String userName = user == null ? null : user.getName(); + // check if .opendistro_security index has been initialized + if (!ensureIndexExists()) { + return channel -> internalSeverError(channel, RequestContentValidator.ValidationError.SECURITY_NOT_INITIALIZED.message()); + } - if (authError != null) { - LOGGER.error("No permission to access REST API: " + authError); - securityApiDependencies.auditLog().logMissingPrivileges(authError, userName, securityRequest); - // for rest request - request.params().clear(); - forbidden(channel, "No permission to access REST API: " + authError); - return; - } else { - securityApiDependencies.auditLog().logGrantedPrivileges(userName, securityRequest); - } + // check if request is authorized + final String authError = securityApiDependencies.restApiPrivilegesEvaluator().checkAccessPermissions(request, endpoint); + + final User user = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); + final String userName = user == null ? null : user.getName(); + if (authError != null) { + LOGGER.error("No permission to access REST API: " + authError); + securityApiDependencies.auditLog().logMissingPrivileges(authError, userName, SecurityRequestFactory.from(request)); + // for rest request + request.params().clear(); + return channel -> forbidden(channel, "No permission to access REST API: " + authError); + } else { + securityApiDependencies.auditLog().logGrantedPrivileges(userName, SecurityRequestFactory.from(request)); + } - final var originalUserAndRemoteAddress = Utils.userAndRemoteAddressFrom(threadPool.getThreadContext()); - final Object originalOrigin = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN); - - threadPool.generic().submit(() -> { - try (StoredContext ignore = threadPool.getThreadContext().stashContext()) { - threadPool.getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_CONF_REQUEST_HEADER, "true"); - threadPool.getThreadContext() - .putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, originalUserAndRemoteAddress.getLeft()); - threadPool.getThreadContext() - .putTransient(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS, originalUserAndRemoteAddress.getRight()); - threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, originalOrigin); - - requestHandlers = Optional.ofNullable(requestHandlers).orElseGet(requestHandlersBuilder::build); - final var requestHandler = requestHandlers.getOrDefault(request.method(), methodNotImplementedHandler); - requestHandler.handle(channel, request, client); - } catch (Exception e) { - LOGGER.error("Error processing request {}", request, e); - try { - channel.sendResponse(new BytesRestResponse(channel, e)); - } catch (IOException ioe) { - throw ExceptionsHelper.convertToOpenSearchException(e); - } + final var originalUserAndRemoteAddress = Utils.userAndRemoteAddressFrom(threadPool.getThreadContext()); + final Object originalOrigin = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN); + + return channel -> threadPool.generic().submit(() -> { + try (StoredContext ignore = threadPool.getThreadContext().stashContext()) { + System.out.println("Inside validation handler path"); + threadPool.getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_CONF_REQUEST_HEADER, "true"); + threadPool.getThreadContext() + .putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, originalUserAndRemoteAddress.getLeft()); + threadPool.getThreadContext() + .putTransient(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS, originalUserAndRemoteAddress.getRight()); + threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, originalOrigin); + + requestHandlers = Optional.ofNullable(requestHandlers).orElseGet(requestHandlersBuilder::build); + final var requestHandler = requestHandlers.getOrDefault(request.method(), methodNotImplementedHandler); + requestHandler.handle(channel, request, client); + } catch (Exception e) { + LOGGER.error("Error processing request {}", request, e); + try { + channel.sendResponse(new BytesRestResponse(channel, e)); + } catch (IOException ioe) { + throw ExceptionsHelper.convertToOpenSearchException(e); } - }); - }; + } + }); } /** From 9ffa147c911864e44ee065eedf6a5cef2c253d4c Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 17:23:52 +0000 Subject: [PATCH 35/50] Add more logging Signed-off-by: Peter Nied --- .../opensearch/security/dlic/rest/api/Responses.java | 1 + .../dlic/rest/validation/EndpointValidator.java | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java b/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java index 6af8f0e936..796e04b5b6 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java @@ -73,6 +73,7 @@ public static void response(RestChannel channel, RestStatus status, String messa public static void response(final RestChannel channel, final RestStatus status, final ToXContent toXContent) { try (final var builder = channel.newBuilder()) { toXContent.toXContent(builder, ToXContent.EMPTY_PARAMS); + System.out.println("@76 - responses " + status.getStatus()); channel.sendResponse(new BytesRestResponse(status, builder)); } catch (final IOException ioe) { throw ExceptionsHelper.convertToOpenSearchException(ioe); diff --git a/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java b/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java index 442d39cf43..7ff2af6dda 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java @@ -55,6 +55,7 @@ default boolean isCurrentUserAdmin() { default ValidationResult withRequiredEntityName(final String entityName) { if (entityName == null) { + System.out.println("@152 - Endpoint validator 400"); return ValidationResult.error(RestStatus.BAD_REQUEST, badRequestMessage("No " + resourceName() + " specified.")); } return ValidationResult.success(entityName); @@ -104,6 +105,7 @@ default ValidationResult entityStatic(final SecurityConfi final var configuration = securityConfiguration.configuration(); final var entityName = securityConfiguration.entityName(); if (configuration.isStatic(entityName)) { + System.out.println("@107 - Endpoint validator 403"); return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Resource '" + entityName + "' is static.")); } return ValidationResult.success(securityConfiguration); @@ -113,6 +115,11 @@ default ValidationResult entityReserved(final SecurityCon final var configuration = securityConfiguration.configuration(); final var entityName = securityConfiguration.entityName(); if (configuration.isReserved(entityName)) { + System.out.println("@117 - Endpoint validator 403"); + // TODO: Remove + new Exception("&&& entityReserved denied calling stack trace").printStackTrace(); + + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Resource '" + entityName + "' is reserved.")); } return ValidationResult.success(securityConfiguration); @@ -122,6 +129,7 @@ default ValidationResult entityHidden(final SecurityConfi final var configuration = securityConfiguration.configuration(); final var entityName = securityConfiguration.entityName(); if (configuration.isHidden(entityName)) { + System.out.println("@152 - Endpoint validator 404"); return ValidationResult.error(RestStatus.NOT_FOUND, notFoundMessage("Resource '" + entityName + "' is not available.")); } return ValidationResult.success(securityConfiguration); @@ -149,6 +157,7 @@ default ValidationResult isAllowedToChangeEntityWithRestA final var configuration = securityConfiguration.configuration(); final var existingEntity = configuration.getCEntry(securityConfiguration.entityName()); if (restApiAdminPrivilegesEvaluator().containsRestApiAdminPermissions(existingEntity)) { + System.out.println("@152 - Endpoint validator 403"); return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } } else { @@ -158,6 +167,7 @@ default ValidationResult isAllowedToChangeEntityWithRestA configuration.getImplementingClass() ); if (restApiAdminPrivilegesEvaluator().containsRestApiAdminPermissions(configEntityContent)) { + System.out.println("@162 - Endpoint validator 403"); return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } } From 613acab3d711837f6abdc6a3b3d4eaf9f4197dfa Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 17:25:12 +0000 Subject: [PATCH 36/50] move logging location Signed-off-by: Peter Nied --- .../org/opensearch/security/auditlog/impl/AuditLogImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java index 8da4b13d4c..d9e6a2225d 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java @@ -132,6 +132,7 @@ protected void save(final AuditMessage msg) { @Override public void logFailedLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequest request) { + new Exception("&&& logFailedLogin").printStackTrace(); if (enabled) { super.logFailedLogin(effectiveUser, securityAdmin, initiatingUser, request); } @@ -139,6 +140,7 @@ public void logFailedLogin(String effectiveUser, boolean securityAdmin, String i @Override public void logSucceededLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequest request) { + new Exception("&&& logSucceededLogin").printStackTrace(); if (enabled) { super.logSucceededLogin(effectiveUser, securityAdmin, initiatingUser, request); } From 2125f9fcaa1d2688e2206b15f03f368693950a5e Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 19:03:25 +0000 Subject: [PATCH 37/50] Refactor to optional in progress Signed-off-by: Peter Nied --- .../jwt/AbstractHTTPJwtAuthenticator.java | 8 ++++-- .../auth/http/jwt/HTTPJwtAuthenticator.java | 8 ++++-- .../auth/http/saml/HTTPSamlAuthenticator.java | 12 ++++---- .../security/auth/HTTPAuthenticator.java | 10 ++++--- .../filter/SecurityRequestChannel.java | 4 +-- .../security/filter/SecurityResponse.java | 28 +++++++++++++++++++ .../security/filter/SecurityRestFilter.java | 8 +++--- .../security/http/HTTPBasicAuthenticator.java | 8 ++++-- .../http/HTTPClientCertAuthenticator.java | 6 ++-- .../security/http/HTTPProxyAuthenticator.java | 6 ++-- 10 files changed, 69 insertions(+), 29 deletions(-) create mode 100644 src/main/java/org/opensearch/security/filter/SecurityResponse.java diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java index e74c697366..2ba1d4a2a2 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java @@ -16,6 +16,7 @@ import java.security.PrivilegedAction; import java.util.Collection; import java.util.Map; +import java.util.Optional; import java.util.Map.Entry; import java.util.regex.Pattern; @@ -41,6 +42,7 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.user.AuthCredentials; public abstract class AbstractHTTPJwtAuthenticator implements HTTPAuthenticator { @@ -238,12 +240,12 @@ public String[] extractRoles(JwtClaims claims) { protected abstract KeyProvider initKeyProvider(Settings settings, Path configPath) throws Exception; @Override - public boolean reRequestAuthentication(final SecurityRequestChannel request, AuthCredentials authCredentials) { - return request.completeWithResponse( + public Optional reRequestAuthentication(final SecurityRequest request, AuthCredentials authCredentials) { + return Optional.of(new SecurityResponse( HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), "" - ); + )); } public String getRequiredAudience() { diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java index 5f7e99d373..6fdf9ee075 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java @@ -16,6 +16,7 @@ import java.security.PrivilegedAction; import java.util.Collection; import java.util.Map; +import java.util.Optional; import java.util.Map.Entry; import java.util.regex.Pattern; @@ -35,6 +36,7 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.KeyUtils; @@ -172,12 +174,12 @@ private AuthCredentials extractCredentials0(final SecurityRequest request) { } @Override - public boolean reRequestAuthentication(final SecurityRequestChannel channel, AuthCredentials creds) { - return channel.completeWithResponse( + public Optional reRequestAuthentication(final SecurityRequest channel, AuthCredentials creds) { + return Optional.of(new SecurityResponse( HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), "" - ); + )); } @Override 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 d25cf0711e..0a7ae54d92 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 @@ -19,6 +19,7 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Map; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -64,6 +65,7 @@ import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequetChannelUnsupported; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.filter.OpenSearchRequestChannel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.PemKeyReader; @@ -176,7 +178,7 @@ public String getType() { } @Override - public boolean reRequestAuthentication(final SecurityRequestChannel request, final AuthCredentials authCredentials) { + 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; @@ -192,20 +194,20 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, fin if (this.authTokenProcessorHandler.handle(restRequest, channel)) { // The ACS response was accepted securityRequestChannel.markCompleted(); - return true; + return Optional.empty(); } } } final Saml2Settings saml2Settings = this.saml2SettingsProvider.getCached(); - return request.completeWithResponse( + return Optional.of(new SecurityResponse( HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", getWwwAuthenticateHeader(saml2Settings)), "" - ); + )); } catch (Exception e) { log.error("Error in reRequestAuthentication()", e); - return false; + return Optional.empty(); } } diff --git a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java index 690a1415df..014b10195b 100644 --- a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java +++ b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java @@ -26,11 +26,14 @@ package org.opensearch.security.auth; +import java.util.Optional; + import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.RestRequest; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.user.AuthCredentials; /** @@ -76,10 +79,9 @@ public interface HTTPAuthenticator { * If the custom HTTP authenticator does support re-request authentication or supports authentication flows with multiple roundtrips * then the response will be returned which can then be sent via response channel. * - * @param channel The channel to sent back the response + * @param request The request to reauthenticate or not * @param credentials The credentials from the prior authentication attempt - * @return null if re-request is not supported/necessary, response object otherwise. - * If an object is returned {@code channel.sendResponse()} must be called so that the request completes. + * @return Optional response if is not supported/necessary, response object otherwise. */ - boolean reRequestAuthentication(final SecurityRequestChannel channel, AuthCredentials credentials); + Optional reRequestAuthentication(final SecurityRequest request, AuthCredentials credentials); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java index 72f7c3b32b..d380bf38a2 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java @@ -1,7 +1,5 @@ package org.opensearch.security.filter; -import java.util.Map; - /** * When a request is recieved by the security plugin this governs getting information about the request as well as a way to complet */ @@ -13,5 +11,5 @@ public interface SecurityRequestChannel extends SecurityRequest { public boolean hasCompleted(); /** Use this channel to send a response */ - public boolean completeWithResponse(final int statusCode, final Map headers, final String body); + public boolean completeWithResponse(final SecurityResponse response); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityResponse.java b/src/main/java/org/opensearch/security/filter/SecurityResponse.java new file mode 100644 index 0000000000..15424677b6 --- /dev/null +++ b/src/main/java/org/opensearch/security/filter/SecurityResponse.java @@ -0,0 +1,28 @@ +package org.opensearch.security.filter; + +import java.util.Map; + +public class SecurityResponse { + private final int status; + private final Map headers; + private final String body; + + public SecurityResponse(final int status, final Map headers, final String body) { + this.status = status; + this.headers = headers; + this.body = body; + } + + public int getStatus() { + return status; + } + + public Map getHeaders() { + return headers; + } + + public String getBody() { + return body; + } + +} diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 6088f76397..ca1dd32140 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -204,7 +204,7 @@ private void authorizeRequest(RestHandler original, SecurityRequestChannel reque } log.debug(err); System.out.println("@206 - authorizeRequest 401"); - request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, null, err); + request.completeWithResponse(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, err)); return; } } @@ -218,7 +218,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); System.out.println("@220 - checkAndAuthenticateRequest 403"); - requestChannel.completeWithResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString()); + requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); return; } @@ -227,7 +227,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); System.out.println("@229 - checkAndAuthenticateRequest 403"); - requestChannel.completeWithResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString()); + requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); return; } @@ -248,7 +248,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t log.error("No ssl info", e); auditLog.logSSLException(requestChannel, e); System.out.println("@250 - authorizeRequest 403"); - requestChannel.completeWithResponse(HttpStatus.SC_FORBIDDEN, null, null); + requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, null)); return; } diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index 6636be53be..2c5aec3fa6 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -28,6 +28,7 @@ import java.nio.file.Path; import java.util.Map; +import java.util.Optional; import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; @@ -38,6 +39,7 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.HTTPHelper; import org.opensearch.security.user.AuthCredentials; @@ -65,12 +67,12 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final SecurityRequestChannel request, AuthCredentials creds) { - return request.completeWithResponse( + public Optional reRequestAuthentication(final SecurityRequest request, AuthCredentials creds) { + return Optional.of(new SecurityResponse( HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), "" - ); + )); } @Override diff --git a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java index d3701d40b0..4578502f0a 100644 --- a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; @@ -44,6 +45,7 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -98,8 +100,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final SecurityRequestChannel response, AuthCredentials creds) { - return false; + public Optional reRequestAuthentication(final SecurityRequest response, AuthCredentials creds) { + return Optional.empty(); } @Override diff --git a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java index 1fdf973726..fcf9104832 100644 --- a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java @@ -27,6 +27,7 @@ package org.opensearch.security.http; import java.nio.file.Path; +import java.util.Optional; import java.util.regex.Pattern; import com.google.common.base.Predicates; @@ -40,6 +41,7 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; @@ -89,8 +91,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(final SecurityRequestChannel response, AuthCredentials creds) { - return false; + public Optional reRequestAuthentication(final SecurityRequest response, AuthCredentials creds) { + return Optional.empty(); } @Override From edbe2beee141412d6a26631f6e2bc3a416eda7ea Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 21:01:07 +0000 Subject: [PATCH 38/50] Restore changes around passing unsent response Signed-off-by: Peter Nied --- .../kerberos/HTTPSpnegoAuthenticator.java | 9 ++- .../security/auth/BackendRegistry.java | 63 ++++++++++++------- .../filter/OpenSearchRequestChannel.java | 10 +-- .../security/filter/SecurityRestFilter.java | 28 +++++---- .../http/OnBehalfOfAuthenticator.java | 6 +- .../cache/DummyHTTPAuthenticator.java | 6 +- 6 files changed, 74 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java index f9447f5e36..e526defb70 100644 --- a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java @@ -11,6 +11,8 @@ package com.amazon.dlic.auth.http.kerberos; +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; + import java.io.Serializable; import java.nio.file.Files; import java.nio.file.Path; @@ -25,6 +27,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Optional; import java.util.Set; import javax.security.auth.Subject; @@ -32,7 +35,6 @@ import com.google.common.base.Strings; -import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.ietf.jgss.GSSContext; @@ -55,6 +57,7 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.user.AuthCredentials; public class HTTPSpnegoAuthenticator implements HTTPAuthenticator { @@ -281,7 +284,7 @@ public GSSCredential run() throws GSSException { } @Override - public boolean reRequestAuthentication(final SecurityRequestChannel request, AuthCredentials creds) { + public Optional reRequestAuthentication(final SecurityRequest request, AuthCredentials creds) { final Map headers = new HashMap<>(); String responseBody = ""; final String negotiateResponseBody = getNegotiateResponseBody(); @@ -296,7 +299,7 @@ public boolean reRequestAuthentication(final SecurityRequestChannel request, Aut headers.put("WWW-Authenticate", "Negotiate " + Base64.getEncoder().encodeToString((byte[]) creds.getNativeCredentials())); } - return request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, headers, responseBody); + return Optional.of(new SecurityResponse(SC_UNAUTHORIZED, headers, responseBody)); } @Override diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index ef91129c4b..9b5ef9cdca 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -32,6 +32,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.SortedSet; import java.util.concurrent.Callable; @@ -54,11 +55,13 @@ import org.opensearch.core.common.transport.TransportAddress; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.rest.RestStatus; +import org.opensearch.rest.BytesRestResponse; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.auth.blocking.ClientBlockRegistry; import org.opensearch.security.auth.internal.NoOpAuthenticationBackend; import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.http.OnBehalfOfAuthenticator; import org.opensearch.security.http.XFFResolver; import org.opensearch.security.securityconf.DynamicConfigModel; @@ -68,6 +71,8 @@ import org.opensearch.security.user.User; import org.opensearch.threadpool.ThreadPool; +import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; + public class BackendRegistry { protected final Logger log = LogManager.getLogger(this.getClass()); @@ -185,7 +190,7 @@ public void onDynamicConfigModelChanged(DynamicConfigModel dcm) { * @return The authenticated user, null means another roundtrip * @throws OpenSearchSecurityException */ - public void authenticate(final SecurityRequestChannel request, final ThreadContext _DO_NOT_USE) { + public boolean authenticate(final SecurityRequestChannel request) { final boolean isDebugEnabled = log.isDebugEnabled(); final boolean isBlockedBasedOnAddress = request.getRemoteAddress() .map(InetSocketAddress::getAddress) @@ -196,8 +201,8 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte log.debug("Rejecting REST request because of blocked address: {}", request.getRemoteAddress().orElse(null)); } - request.completeWithResponse(HttpStatus.SC_UNAUTHORIZED, null, "Authentication finally failed"); - return; + request.completeWithResponse(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, "Authentication finally failed")); + return false; } final String sslPrincipal = (String) threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_SSL_PRINCIPAL); @@ -206,18 +211,18 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte // PKI authenticated REST call threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, new User(sslPrincipal)); auditLog.logSucceededLogin(sslPrincipal, true, null, request); - return; + return true; } if (userInjector.injectUser(request)) { // ThreadContext injected user - return; + return true; } if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); - request.completeWithResponse(HttpStatus.SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized."); - return; + request.completeWithResponse(new SecurityResponse(HttpStatus.SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized.")); + return false; } final TransportAddress remoteAddress = xffResolver.resolve(request); @@ -282,13 +287,17 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte continue; } - if (authDomain.isChallenge() && httpAuthenticator.reRequestAuthentication(request, null)) { - auditLog.logFailedLogin("", false, null, request); - if (isTraceEnabled) { - log.trace("No 'Authorization' header, send 401 and 'WWW-Authenticate Basic'"); + if (authDomain.isChallenge()) { + final Optional restResponse = httpAuthenticator.reRequestAuthentication(request, null); + if (restResponse.isPresent()) { + auditLog.logFailedLogin("", false, null, request); + if (isTraceEnabled) { + log.trace("No 'Authorization' header, send 401 and 'WWW-Authenticate Basic'"); + } + notifyIpAuthFailureListeners(request, authCredentials); + request.completeWithResponse(restResponse.get()); + return false; } - notifyIpAuthFailureListeners(request, authCredentials); - return; } else { // no reRequest possible if (isTraceEnabled) { @@ -300,9 +309,11 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte org.apache.logging.log4j.ThreadContext.put("user", ac.getUsername()); if (!ac.isComplete()) { // credentials found in request but we need another client challenge - if (httpAuthenticator.reRequestAuthentication(request, ac)) { + final Optional restResponse = httpAuthenticator.reRequestAuthentication(request, ac); + if (restResponse.isPresent()) { notifyIpAuthFailureListeners(request, ac); - return; + request.completeWithResponse(restResponse.get()); + return false; } else { // no reRequest possible continue; @@ -339,12 +350,12 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte if (adminDns.isAdmin(authenticatedUser)) { log.error("Cannot authenticate rest user because admin user is not permitted to login via HTTP"); auditLog.logFailedLogin(authenticatedUser.getName(), true, null, request); - request.completeWithResponse( + request.completeWithResponse(new SecurityResponse( HttpStatus.SC_FORBIDDEN, null, "Cannot authenticate user because admin user is not permitted to login via HTTP" - ); - return; + )); + return false; } final String tenant = Utils.coalesce(request.header("securitytenant"), request.header("security_tenant")); @@ -369,7 +380,6 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte authenticatedUser.getName(), request ); - return; } else { if (isDebugEnabled) { log.debug("User still not authenticated after checking {} auth domains", restAuthDomains.size()); @@ -385,19 +395,22 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte if (isDebugEnabled) { log.debug("Anonymous User is authenticated"); } - return; + return true; } + + Optional challengeResponse = Optional.empty(); + if (firstChallengingHttpAuthenticator != null) { if (isDebugEnabled) { log.debug("Rerequest with {}", firstChallengingHttpAuthenticator.getClass()); } - if (firstChallengingHttpAuthenticator.reRequestAuthentication(request, null)) { + challengeResponse = firstChallengingHttpAuthenticator.reRequestAuthentication(request, null); + if (challengeResponse.isPresent()) { if (isDebugEnabled) { log.debug("Rerequest {} failed", firstChallengingHttpAuthenticator.getClass()); } - return; } } @@ -410,8 +423,12 @@ public void authenticate(final SecurityRequestChannel request, final ThreadConte notifyIpAuthFailureListeners(request, authCredentials); - request.completeWithResponse(org.apache.http.HttpStatus.SC_UNAUTHORIZED, null, "Authentication finally failed"); + request.completeWithResponse( + challengeResponse.orElseGet(() -> new SecurityResponse(SC_UNAUTHORIZED, null, "Authentication finally failed")) + ); + return false; } + return authenticated; } private void notifyIpAuthFailureListeners(SecurityRequestChannel request, AuthCredentials authCredentials) { diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index f325a1a192..a0629ae591 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -28,8 +28,8 @@ public boolean hasCompleted() { } @Override - public boolean completeWithResponse(int statusCode, Map headers, String body) { - System.out.println("@32 - completeWithResponse" + statusCode); + public boolean completeWithResponse(final SecurityResponse response) { + System.out.println("@32 - completeWithResponse" + response.getStatus()); // TODO: Remove new Exception("&&& completeWithResponse calling stack trace").printStackTrace(); @@ -42,9 +42,9 @@ public boolean completeWithResponse(int statusCode, Map headers, } try { - final BytesRestResponse restResponse = new BytesRestResponse(RestStatus.fromCode(statusCode), body); - if (headers != null) { - headers.forEach(restResponse::addHeader); + final BytesRestResponse restResponse = new BytesRestResponse(RestStatus.fromCode(response.getStatus()), response.getBody()); + if (response.getHeaders() != null) { + response.getHeaders().forEach(restResponse::addHeader); } underlyingChannel.sendResponse(restResponse); diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index ca1dd32140..63f1bf8312 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -145,17 +145,20 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return; } - if (whitelistingSettings.checkRequestIsAllowed(request, channel, client) - && allowlistingSettings.checkRequestIsAllowed(request, channel, client)) { - authorizeRequest(original, requestChannel, user); - if (requestChannel.hasCompleted()) { - // Caller was not authorized - return; - } else { - // Caller was authorized, forward the request to the handler - original.handleRequest(request, channel, client); - } - } + if (!(whitelistingSettings.checkRequestIsAllowed(request, channel, client) + && allowlistingSettings.checkRequestIsAllowed(request, channel, client))) { + // Request is not allowed + return; + } + + authorizeRequest(original, requestChannel, user); + if (requestChannel.hasCompleted()) { + // Caller was not authorized + return; + } + + // Caller was authorized, forward the request to the handler + original.handleRequest(request, channel, client); }; } @@ -260,8 +263,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t Matcher matcher = PATTERN_PATH_PREFIX.matcher(requestChannel.path()); final String suffix = matcher.matches() ? matcher.group(2) : null; if (requestChannel.method() != Method.OPTIONS && !(HEALTH_SUFFIX.equals(suffix)) && !(WHO_AM_I_SUFFIX.equals(suffix))) { - registry.authenticate(requestChannel, null); - if (requestChannel.hasCompleted()) { + if (!registry.authenticate(requestChannel)) { // another roundtrip org.apache.logging.log4j.ThreadContext.remove("user"); return; diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java index ac92833c6e..7278ee3976 100644 --- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java @@ -15,6 +15,7 @@ import java.security.PrivilegedAction; import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -37,6 +38,7 @@ import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.KeyUtils; @@ -242,8 +244,8 @@ public Boolean isRequestAllowed(final SecurityRequest request) { } @Override - public boolean reRequestAuthentication(final SecurityRequestChannel response, AuthCredentials creds) { - return false; + public Optional reRequestAuthentication(final SecurityRequest response, AuthCredentials creds) { + return Optional.empty(); } @Override diff --git a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java index 21cfafa03f..6cc2023eb1 100644 --- a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java +++ b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java @@ -12,6 +12,7 @@ package org.opensearch.security.cache; import java.nio.file.Path; +import java.util.Optional; import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; @@ -19,6 +20,7 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; +import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.user.AuthCredentials; public class DummyHTTPAuthenticator implements HTTPAuthenticator { @@ -40,8 +42,8 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T } @Override - public boolean reRequestAuthentication(SecurityRequestChannel channel, AuthCredentials credentials) { - return false; + public Optional reRequestAuthentication(SecurityRequest channel, AuthCredentials credentials) { + return Optional.empty(); } public static long getCount() { From 33aa8637fd8ff30db02b50d4e412384ec44a81f2 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 21:02:17 +0000 Subject: [PATCH 39/50] revert logging changes Signed-off-by: Peter Nied --- .../security/auditlog/impl/AuditLogImpl.java | 2 -- .../opensearch/security/auth/BackendRegistry.java | 4 ++-- .../security/dlic/rest/api/AbstractApiAction.java | 8 ++++---- .../security/dlic/rest/api/NodesDnApiAction.java | 2 +- .../security/dlic/rest/api/Responses.java | 2 +- .../dlic/rest/validation/EndpointValidator.java | 15 +++++---------- .../security/filter/OpenSearchRequestChannel.java | 5 +---- .../security/filter/SecurityFilter.java | 4 ++-- .../security/filter/SecurityRestFilter.java | 8 ++++---- .../security/rest/SecurityConfigUpdateAction.java | 4 ++-- .../security/rest/SecurityWhoAmIAction.java | 2 +- .../security/rest/TenantInfoAction.java | 2 +- .../securityconf/impl/AllowlistingSettings.java | 2 +- .../securityconf/impl/WhitelistingSettings.java | 2 +- 14 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java index d9e6a2225d..8da4b13d4c 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java @@ -132,7 +132,6 @@ protected void save(final AuditMessage msg) { @Override public void logFailedLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequest request) { - new Exception("&&& logFailedLogin").printStackTrace(); if (enabled) { super.logFailedLogin(effectiveUser, securityAdmin, initiatingUser, request); } @@ -140,7 +139,6 @@ public void logFailedLogin(String effectiveUser, boolean securityAdmin, String i @Override public void logSucceededLogin(String effectiveUser, boolean securityAdmin, String initiatingUser, SecurityRequest request) { - new Exception("&&& logSucceededLogin").printStackTrace(); if (enabled) { super.logSucceededLogin(effectiveUser, securityAdmin, initiatingUser, request); } diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 9b5ef9cdca..4dd22da6a8 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -592,7 +592,7 @@ private User impersonate(final SecurityRequestChannel request, final User origin } if (adminDns.isAdminDN(impersonatedUserHeader)) { - System.out.println("@607 - impersonate, 403"); + throw new OpenSearchSecurityException( "It is not allowed to impersonate as an adminuser '" + impersonatedUserHeader + "'", RestStatus.FORBIDDEN @@ -600,7 +600,7 @@ private User impersonate(final SecurityRequestChannel request, final User origin } if (!adminDns.isRestImpersonationAllowed(originalUser.getName(), impersonatedUserHeader)) { - System.out.println("@615 - impersonate, 403"); + throw new OpenSearchSecurityException( "'" + originalUser.getName() + "' is not allowed to impersonate as '" + impersonatedUserHeader + "'", RestStatus.FORBIDDEN diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index 7733e81741..111eb609dc 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -373,7 +373,7 @@ protected final ValidationResult> loadConfigurat ) { final var configuration = load(cType, logComplianceEvent); if (configuration.getSeqNo() < 0) { - System.out.println("@374 - abstract API action, 403"); + return ValidationResult.error( RestStatus.FORBIDDEN, forbiddenMessage( @@ -414,19 +414,19 @@ public RestApiAdminPrivilegesEvaluator restApiAdminPrivilegesEvaluator() { @Override public ValidationResult onConfigDelete(SecurityConfiguration securityConfiguration) throws IOException { - System.out.println("@415 - abstract API action, 403"); + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } @Override public ValidationResult onConfigLoad(SecurityConfiguration securityConfiguration) throws IOException { - System.out.println("@421 - abstract API action, 403"); + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } @Override public ValidationResult onConfigChange(SecurityConfiguration securityConfiguration) throws IOException { - System.out.println("@427 - abstract API action, 403"); + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java index 19b7006d8d..b691d96fb3 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java @@ -139,7 +139,7 @@ public RestApiAdminPrivilegesEvaluator restApiAdminPrivilegesEvaluator() { public ValidationResult isAllowedToChangeImmutableEntity(SecurityConfiguration securityConfiguration) throws IOException { if (STATIC_OPENSEARCH_YML_NODES_DN.equals(securityConfiguration.entityName())) { - System.out.println("@142 - nodes dn API action, 403"); + return ValidationResult.error( RestStatus.FORBIDDEN, forbiddenMessage("Resource '" + STATIC_OPENSEARCH_YML_NODES_DN + "' is read-only.") diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java b/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java index 796e04b5b6..0a0edee6e4 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java @@ -73,7 +73,7 @@ public static void response(RestChannel channel, RestStatus status, String messa public static void response(final RestChannel channel, final RestStatus status, final ToXContent toXContent) { try (final var builder = channel.newBuilder()) { toXContent.toXContent(builder, ToXContent.EMPTY_PARAMS); - System.out.println("@76 - responses " + status.getStatus()); + channel.sendResponse(new BytesRestResponse(status, builder)); } catch (final IOException ioe) { throw ExceptionsHelper.convertToOpenSearchException(ioe); diff --git a/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java b/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java index 7ff2af6dda..c03342630e 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java @@ -55,7 +55,7 @@ default boolean isCurrentUserAdmin() { default ValidationResult withRequiredEntityName(final String entityName) { if (entityName == null) { - System.out.println("@152 - Endpoint validator 400"); + return ValidationResult.error(RestStatus.BAD_REQUEST, badRequestMessage("No " + resourceName() + " specified.")); } return ValidationResult.success(entityName); @@ -105,7 +105,7 @@ default ValidationResult entityStatic(final SecurityConfi final var configuration = securityConfiguration.configuration(); final var entityName = securityConfiguration.entityName(); if (configuration.isStatic(entityName)) { - System.out.println("@107 - Endpoint validator 403"); + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Resource '" + entityName + "' is static.")); } return ValidationResult.success(securityConfiguration); @@ -115,11 +115,6 @@ default ValidationResult entityReserved(final SecurityCon final var configuration = securityConfiguration.configuration(); final var entityName = securityConfiguration.entityName(); if (configuration.isReserved(entityName)) { - System.out.println("@117 - Endpoint validator 403"); - // TODO: Remove - new Exception("&&& entityReserved denied calling stack trace").printStackTrace(); - - return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Resource '" + entityName + "' is reserved.")); } return ValidationResult.success(securityConfiguration); @@ -129,7 +124,7 @@ default ValidationResult entityHidden(final SecurityConfi final var configuration = securityConfiguration.configuration(); final var entityName = securityConfiguration.entityName(); if (configuration.isHidden(entityName)) { - System.out.println("@152 - Endpoint validator 404"); + return ValidationResult.error(RestStatus.NOT_FOUND, notFoundMessage("Resource '" + entityName + "' is not available.")); } return ValidationResult.success(securityConfiguration); @@ -157,7 +152,7 @@ default ValidationResult isAllowedToChangeEntityWithRestA final var configuration = securityConfiguration.configuration(); final var existingEntity = configuration.getCEntry(securityConfiguration.entityName()); if (restApiAdminPrivilegesEvaluator().containsRestApiAdminPermissions(existingEntity)) { - System.out.println("@152 - Endpoint validator 403"); + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } } else { @@ -167,7 +162,7 @@ default ValidationResult isAllowedToChangeEntityWithRestA configuration.getImplementingClass() ); if (restApiAdminPrivilegesEvaluator().containsRestApiAdminPermissions(configEntityContent)) { - System.out.println("@162 - Endpoint validator 403"); + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } } diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index a0629ae591..5230167acb 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -29,10 +29,7 @@ public boolean hasCompleted() { @Override public boolean completeWithResponse(final SecurityResponse response) { - System.out.println("@32 - completeWithResponse" + response.getStatus()); - // TODO: Remove - new Exception("&&& completeWithResponse calling stack trace").printStackTrace(); - + if (underlyingChannel == null) { throw new UnsupportedOperationException("Channel was not defined"); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityFilter.java b/src/main/java/org/opensearch/security/filter/SecurityFilter.java index 34e45ffeda..523acad108 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityFilter.java @@ -464,7 +464,7 @@ public void onFailure(Exception e) { : String.format("no permissions for %s and %s", pres.getMissingPrivileges(), user); } log.debug(err); - System.out.println("@467 - apply0, 403"); + listener.onFailure(new OpenSearchSecurityException(err, RestStatus.FORBIDDEN)); } } catch (OpenSearchException e) { @@ -515,7 +515,7 @@ private boolean checkImmutableIndices(Object request, ActionListener listener) { || request instanceof IndicesAliasesRequest; if (isModifyIndexRequest && isRequestIndexImmutable(request)) { - System.out.println("@517 - checkImmutableIndices, 403"); + listener.onFailure(new OpenSearchSecurityException("Index is immutable", RestStatus.FORBIDDEN)); return true; } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 63f1bf8312..29b91b655d 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -206,7 +206,7 @@ private void authorizeRequest(RestHandler original, SecurityRequestChannel reque err = String.format("no permissions for %s and %s", pres.getMissingPrivileges(), user); } log.debug(err); - System.out.println("@206 - authorizeRequest 401"); + request.completeWithResponse(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, err)); return; } @@ -220,7 +220,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); - System.out.println("@220 - checkAndAuthenticateRequest 403"); + requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); return; } @@ -229,7 +229,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); - System.out.println("@229 - checkAndAuthenticateRequest 403"); + requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); return; } @@ -250,7 +250,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t } catch (SSLPeerUnverifiedException e) { log.error("No ssl info", e); auditLog.logSSLException(requestChannel, e); - System.out.println("@250 - authorizeRequest 403"); + requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, null)); return; } diff --git a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java index d9a25a8c3d..0739497724 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java @@ -81,7 +81,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { - System.out.println("@84 - update config action 403"); + channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); return; } @@ -90,7 +90,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli // only allowed for admins if (user == null || !adminDns.isAdmin(user)) { - System.out.println("@93 - update config action 403"); + channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); return; } else { diff --git a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java index d947c5c708..885ae2bbc6 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java @@ -103,7 +103,7 @@ public void accept(RestChannel channel) throws Exception { SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { - System.out.println("@104 - who am i action, 403"); + response = new BytesRestResponse(RestStatus.FORBIDDEN, "No security data"); } else { diff --git a/src/main/java/org/opensearch/security/rest/TenantInfoAction.java b/src/main/java/org/opensearch/security/rest/TenantInfoAction.java index d43f1c2e6e..d6ba8aa0f2 100644 --- a/src/main/java/org/opensearch/security/rest/TenantInfoAction.java +++ b/src/main/java/org/opensearch/security/rest/TenantInfoAction.java @@ -114,7 +114,7 @@ public void accept(RestChannel channel) throws Exception { // only allowed for admins or the kibanaserveruser if (!isAuthorized()) { - System.out.println("@117 - tenant info action, 403"); + response = new BytesRestResponse(RestStatus.FORBIDDEN, ""); } else { diff --git a/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java b/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java index 9ab023719a..c4ac02d218 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java @@ -110,7 +110,7 @@ private boolean requestIsAllowlisted(RestRequest request) { public boolean checkRequestIsAllowed(RestRequest request, RestChannel channel, NodeClient client) throws IOException { // if allowlisting is enabled but the request is not allowlisted, then return false, otherwise true. if (this.enabled && !requestIsAllowlisted(request)) { - System.out.println("@113 - checkRequestIsAllowed 403"); + channel.sendResponse( new BytesRestResponse( RestStatus.FORBIDDEN, diff --git a/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java b/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java index 4e6bcaf688..c9bb99fdea 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java @@ -111,7 +111,7 @@ private boolean requestIsWhitelisted(RestRequest request) { public boolean checkRequestIsAllowed(RestRequest request, RestChannel channel, NodeClient client) throws IOException { // if whitelisting is enabled but the request is not whitelisted, then return false, otherwise true. if (this.enabled && !requestIsWhitelisted(request)) { - System.out.println("@114 - checkRequestIsAllowed 403"); + channel.sendResponse( new BytesRestResponse( RestStatus.FORBIDDEN, From 0c5a97d7ede4cabca6fd38d289e6fa3a5980387b Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 21:04:00 +0000 Subject: [PATCH 40/50] Fix spotless Signed-off-by: Peter Nied --- .../jwt/AbstractHTTPJwtAuthenticator.java | 9 +++---- .../auth/http/jwt/HTTPJwtAuthenticator.java | 9 +++---- .../kerberos/HTTPSpnegoAuthenticator.java | 1 - .../auth/http/saml/HTTPSamlAuthenticator.java | 9 +++---- .../security/auth/BackendRegistry.java | 24 ++++++++++--------- .../security/auth/HTTPAuthenticator.java | 1 - .../dlic/rest/api/AbstractApiAction.java | 11 ++++----- .../dlic/rest/api/NodesDnApiAction.java | 2 +- .../security/dlic/rest/api/Responses.java | 2 +- .../rest/validation/EndpointValidator.java | 10 ++++---- .../filter/OpenSearchRequestChannel.java | 3 +-- .../security/filter/SecurityFilter.java | 4 ++-- .../security/filter/SecurityRestFilter.java | 8 +++---- .../security/http/HTTPBasicAuthenticator.java | 9 +++---- .../http/HTTPClientCertAuthenticator.java | 1 - .../security/http/HTTPProxyAuthenticator.java | 1 - .../http/OnBehalfOfAuthenticator.java | 1 - .../rest/SecurityConfigUpdateAction.java | 4 ++-- .../security/rest/SecurityWhoAmIAction.java | 2 +- .../security/rest/TenantInfoAction.java | 2 +- .../impl/AllowlistingSettings.java | 2 +- .../impl/WhitelistingSettings.java | 2 +- .../cache/DummyHTTPAuthenticator.java | 1 - 23 files changed, 50 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java index 2ba1d4a2a2..f2a9de655e 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java @@ -41,7 +41,6 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.user.AuthCredentials; @@ -241,11 +240,9 @@ public String[] extractRoles(JwtClaims claims) { @Override public Optional reRequestAuthentication(final SecurityRequest request, AuthCredentials authCredentials) { - return Optional.of(new SecurityResponse( - HttpStatus.SC_UNAUTHORIZED, - Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), - "" - )); + return Optional.of( + new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), "") + ); } public String getRequiredAudience() { diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java index 6fdf9ee075..bd04217db7 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java @@ -35,7 +35,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.KeyUtils; @@ -175,11 +174,9 @@ private AuthCredentials extractCredentials0(final SecurityRequest request) { @Override public Optional reRequestAuthentication(final SecurityRequest channel, AuthCredentials creds) { - return Optional.of(new SecurityResponse( - HttpStatus.SC_UNAUTHORIZED, - Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), - "" - )); + return Optional.of( + new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), "") + ); } @Override diff --git a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java index e526defb70..e08860f7e2 100644 --- a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java @@ -56,7 +56,6 @@ import org.opensearch.env.Environment; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.user.AuthCredentials; 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 0a7ae54d92..ea4724c497 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 @@ -63,7 +63,6 @@ import org.opensearch.security.auth.Destroyable; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequetChannelUnsupported; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.filter.OpenSearchRequestChannel; @@ -200,11 +199,9 @@ public Optional reRequestAuthentication(final SecurityRequest } final Saml2Settings saml2Settings = this.saml2SettingsProvider.getCached(); - return Optional.of(new SecurityResponse( - HttpStatus.SC_UNAUTHORIZED, - Map.of("WWW-Authenticate", getWwwAuthenticateHeader(saml2Settings)), - "" - )); + return Optional.of( + new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", getWwwAuthenticateHeader(saml2Settings)), "") + ); } catch (Exception e) { log.error("Error in reRequestAuthentication()", e); return Optional.empty(); diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 4dd22da6a8..039f6e90ca 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -53,9 +53,7 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.transport.TransportAddress; -import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.core.rest.RestStatus; -import org.opensearch.rest.BytesRestResponse; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.auth.blocking.ClientBlockRegistry; import org.opensearch.security.auth.internal.NoOpAuthenticationBackend; @@ -221,7 +219,9 @@ public boolean authenticate(final SecurityRequestChannel request) { if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); - request.completeWithResponse(new SecurityResponse(HttpStatus.SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized.")); + request.completeWithResponse( + new SecurityResponse(HttpStatus.SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized.") + ); return false; } @@ -350,11 +350,13 @@ public boolean authenticate(final SecurityRequestChannel request) { if (adminDns.isAdmin(authenticatedUser)) { log.error("Cannot authenticate rest user because admin user is not permitted to login via HTTP"); auditLog.logFailedLogin(authenticatedUser.getName(), true, null, request); - request.completeWithResponse(new SecurityResponse( - HttpStatus.SC_FORBIDDEN, - null, - "Cannot authenticate user because admin user is not permitted to login via HTTP" - )); + request.completeWithResponse( + new SecurityResponse( + HttpStatus.SC_FORBIDDEN, + null, + "Cannot authenticate user because admin user is not permitted to login via HTTP" + ) + ); return false; } @@ -397,7 +399,7 @@ public boolean authenticate(final SecurityRequestChannel request) { } return true; } - + Optional challengeResponse = Optional.empty(); if (firstChallengingHttpAuthenticator != null) { @@ -592,7 +594,7 @@ private User impersonate(final SecurityRequestChannel request, final User origin } if (adminDns.isAdminDN(impersonatedUserHeader)) { - + throw new OpenSearchSecurityException( "It is not allowed to impersonate as an adminuser '" + impersonatedUserHeader + "'", RestStatus.FORBIDDEN @@ -600,7 +602,7 @@ private User impersonate(final SecurityRequestChannel request, final User origin } if (!adminDns.isRestImpersonationAllowed(originalUser.getName(), impersonatedUserHeader)) { - + throw new OpenSearchSecurityException( "'" + originalUser.getName() + "' is not allowed to impersonate as '" + impersonatedUserHeader + "'", RestStatus.FORBIDDEN diff --git a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java index 014b10195b..f5a4df34b5 100644 --- a/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java +++ b/src/main/java/org/opensearch/security/auth/HTTPAuthenticator.java @@ -32,7 +32,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.rest.RestRequest; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.user.AuthCredentials; diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index 111eb609dc..aa2af3f042 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -49,7 +49,6 @@ import org.opensearch.security.dlic.rest.validation.EndpointValidator; import org.opensearch.security.dlic.rest.validation.RequestContentValidator; import org.opensearch.security.dlic.rest.validation.ValidationResult; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.securityconf.DynamicConfigFactory; import org.opensearch.security.securityconf.impl.CType; @@ -373,7 +372,7 @@ protected final ValidationResult> loadConfigurat ) { final var configuration = load(cType, logComplianceEvent); if (configuration.getSeqNo() < 0) { - + return ValidationResult.error( RestStatus.FORBIDDEN, forbiddenMessage( @@ -414,19 +413,19 @@ public RestApiAdminPrivilegesEvaluator restApiAdminPrivilegesEvaluator() { @Override public ValidationResult onConfigDelete(SecurityConfiguration securityConfiguration) throws IOException { - + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } @Override public ValidationResult onConfigLoad(SecurityConfiguration securityConfiguration) throws IOException { - + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } @Override public ValidationResult onConfigChange(SecurityConfiguration securityConfiguration) throws IOException { - + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } @@ -564,7 +563,7 @@ protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClie securityApiDependencies.auditLog().logGrantedPrivileges(userName, SecurityRequestFactory.from(request)); } - final var originalUserAndRemoteAddress = Utils.userAndRemoteAddressFrom(threadPool.getThreadContext()); + final var originalUserAndRemoteAddress = Utils.userAndRemoteAddressFrom(threadPool.getThreadContext()); final Object originalOrigin = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN); return channel -> threadPool.generic().submit(() -> { diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java index b691d96fb3..30885b69f0 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java @@ -139,7 +139,7 @@ public RestApiAdminPrivilegesEvaluator restApiAdminPrivilegesEvaluator() { public ValidationResult isAllowedToChangeImmutableEntity(SecurityConfiguration securityConfiguration) throws IOException { if (STATIC_OPENSEARCH_YML_NODES_DN.equals(securityConfiguration.entityName())) { - + return ValidationResult.error( RestStatus.FORBIDDEN, forbiddenMessage("Resource '" + STATIC_OPENSEARCH_YML_NODES_DN + "' is read-only.") diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java b/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java index 0a0edee6e4..60310c7fa4 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java @@ -73,7 +73,7 @@ public static void response(RestChannel channel, RestStatus status, String messa public static void response(final RestChannel channel, final RestStatus status, final ToXContent toXContent) { try (final var builder = channel.newBuilder()) { toXContent.toXContent(builder, ToXContent.EMPTY_PARAMS); - + channel.sendResponse(new BytesRestResponse(status, builder)); } catch (final IOException ioe) { throw ExceptionsHelper.convertToOpenSearchException(ioe); diff --git a/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java b/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java index c03342630e..fa5c7052fe 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java @@ -55,7 +55,7 @@ default boolean isCurrentUserAdmin() { default ValidationResult withRequiredEntityName(final String entityName) { if (entityName == null) { - + return ValidationResult.error(RestStatus.BAD_REQUEST, badRequestMessage("No " + resourceName() + " specified.")); } return ValidationResult.success(entityName); @@ -105,7 +105,7 @@ default ValidationResult entityStatic(final SecurityConfi final var configuration = securityConfiguration.configuration(); final var entityName = securityConfiguration.entityName(); if (configuration.isStatic(entityName)) { - + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Resource '" + entityName + "' is static.")); } return ValidationResult.success(securityConfiguration); @@ -124,7 +124,7 @@ default ValidationResult entityHidden(final SecurityConfi final var configuration = securityConfiguration.configuration(); final var entityName = securityConfiguration.entityName(); if (configuration.isHidden(entityName)) { - + return ValidationResult.error(RestStatus.NOT_FOUND, notFoundMessage("Resource '" + entityName + "' is not available.")); } return ValidationResult.success(securityConfiguration); @@ -152,7 +152,7 @@ default ValidationResult isAllowedToChangeEntityWithRestA final var configuration = securityConfiguration.configuration(); final var existingEntity = configuration.getCEntry(securityConfiguration.entityName()); if (restApiAdminPrivilegesEvaluator().containsRestApiAdminPermissions(existingEntity)) { - + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } } else { @@ -162,7 +162,7 @@ default ValidationResult isAllowedToChangeEntityWithRestA configuration.getImplementingClass() ); if (restApiAdminPrivilegesEvaluator().containsRestApiAdminPermissions(configEntityContent)) { - + return ValidationResult.error(RestStatus.FORBIDDEN, forbiddenMessage("Access denied")); } } diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index 5230167acb..f8be79e093 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -1,6 +1,5 @@ package org.opensearch.security.filter; -import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.logging.log4j.LogManager; @@ -29,7 +28,7 @@ public boolean hasCompleted() { @Override public boolean completeWithResponse(final SecurityResponse response) { - + if (underlyingChannel == null) { throw new UnsupportedOperationException("Channel was not defined"); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityFilter.java b/src/main/java/org/opensearch/security/filter/SecurityFilter.java index 523acad108..d4aaa4b7ff 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityFilter.java @@ -464,7 +464,7 @@ public void onFailure(Exception e) { : String.format("no permissions for %s and %s", pres.getMissingPrivileges(), user); } log.debug(err); - + listener.onFailure(new OpenSearchSecurityException(err, RestStatus.FORBIDDEN)); } } catch (OpenSearchException e) { @@ -515,7 +515,7 @@ private boolean checkImmutableIndices(Object request, ActionListener listener) { || request instanceof IndicesAliasesRequest; if (isModifyIndexRequest && isRequestIndexImmutable(request)) { - + listener.onFailure(new OpenSearchSecurityException("Index is immutable", RestStatus.FORBIDDEN)); return true; } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 29b91b655d..4f005f3e09 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -206,7 +206,7 @@ private void authorizeRequest(RestHandler original, SecurityRequestChannel reque err = String.format("no permissions for %s and %s", pres.getMissingPrivileges(), user); } log.debug(err); - + request.completeWithResponse(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, err)); return; } @@ -220,7 +220,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); - + requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); return; } @@ -229,7 +229,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t final OpenSearchException exception = ExceptionUtils.createBadHeaderException(); log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); - + requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); return; } @@ -250,7 +250,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t } catch (SSLPeerUnverifiedException e) { log.error("No ssl info", e); auditLog.logSSLException(requestChannel, e); - + requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, null)); return; } diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index 2c5aec3fa6..81fefa7a8e 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -38,7 +38,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.HTTPHelper; import org.opensearch.security.user.AuthCredentials; @@ -68,11 +67,9 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T @Override public Optional reRequestAuthentication(final SecurityRequest request, AuthCredentials creds) { - return Optional.of(new SecurityResponse( - HttpStatus.SC_UNAUTHORIZED, - Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), - "" - )); + return Optional.of( + new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), "") + ); } @Override diff --git a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java index 4578502f0a..433ec01458 100644 --- a/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPClientCertAuthenticator.java @@ -44,7 +44,6 @@ import org.opensearch.core.common.Strings; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; diff --git a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java index fcf9104832..de57e2f9e6 100644 --- a/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPProxyAuthenticator.java @@ -40,7 +40,6 @@ import org.opensearch.core.common.Strings; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.AuthCredentials; diff --git a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java index 7278ee3976..8499b88f62 100644 --- a/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/OnBehalfOfAuthenticator.java @@ -37,7 +37,6 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.authtoken.jwt.EncryptionDecryptionUtil; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.user.AuthCredentials; diff --git a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java index 0739497724..df8b721d59 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java @@ -81,7 +81,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { - + channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); return; } @@ -90,7 +90,7 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli // only allowed for admins if (user == null || !adminDns.isAdmin(user)) { - + channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); return; } else { diff --git a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java index 885ae2bbc6..acf0249ed8 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java @@ -103,7 +103,7 @@ public void accept(RestChannel channel) throws Exception { SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { - + response = new BytesRestResponse(RestStatus.FORBIDDEN, "No security data"); } else { diff --git a/src/main/java/org/opensearch/security/rest/TenantInfoAction.java b/src/main/java/org/opensearch/security/rest/TenantInfoAction.java index d6ba8aa0f2..59831f9852 100644 --- a/src/main/java/org/opensearch/security/rest/TenantInfoAction.java +++ b/src/main/java/org/opensearch/security/rest/TenantInfoAction.java @@ -114,7 +114,7 @@ public void accept(RestChannel channel) throws Exception { // only allowed for admins or the kibanaserveruser if (!isAuthorized()) { - + response = new BytesRestResponse(RestStatus.FORBIDDEN, ""); } else { diff --git a/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java b/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java index c4ac02d218..370d13f51b 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java @@ -110,7 +110,7 @@ private boolean requestIsAllowlisted(RestRequest request) { public boolean checkRequestIsAllowed(RestRequest request, RestChannel channel, NodeClient client) throws IOException { // if allowlisting is enabled but the request is not allowlisted, then return false, otherwise true. if (this.enabled && !requestIsAllowlisted(request)) { - + channel.sendResponse( new BytesRestResponse( RestStatus.FORBIDDEN, diff --git a/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java b/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java index c9bb99fdea..182b2c87f6 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java @@ -111,7 +111,7 @@ private boolean requestIsWhitelisted(RestRequest request) { public boolean checkRequestIsAllowed(RestRequest request, RestChannel channel, NodeClient client) throws IOException { // if whitelisting is enabled but the request is not whitelisted, then return false, otherwise true. if (this.enabled && !requestIsWhitelisted(request)) { - + channel.sendResponse( new BytesRestResponse( RestStatus.FORBIDDEN, diff --git a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java index 6cc2023eb1..2cfd23fc23 100644 --- a/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java +++ b/src/test/java/org/opensearch/security/cache/DummyHTTPAuthenticator.java @@ -19,7 +19,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.user.AuthCredentials; From 2f58523205c986c41f9b69d99b3fdf5d3360950c Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 21:06:31 +0000 Subject: [PATCH 41/50] Fix exception name Signed-off-by: Peter Nied --- .../amazon/dlic/auth/http/saml/HTTPSamlAuthenticator.java | 3 ++- .../security/filter/SecurityRequestChannelUnsupported.java | 6 ++++++ .../security/filter/SecurityRequetChannelUnsupported.java | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/opensearch/security/filter/SecurityRequestChannelUnsupported.java 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 ea4724c497..eaa7ae80db 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 @@ -63,6 +63,7 @@ import org.opensearch.security.auth.Destroyable; import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityRequestChannelUnsupported; import org.opensearch.security.filter.SecurityRequetChannelUnsupported; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.filter.OpenSearchRequestChannel; @@ -185,7 +186,7 @@ public Optional reRequestAuthentication(final SecurityRequest if (API_AUTHTOKEN_SUFFIX.equals(suffix)) { // Verficiation of SAML ASC endpoint only works with RestRequests if (!(request instanceof OpenSearchRequestChannel)) { - throw new SecurityRequetChannelUnsupported(); + throw new SecurityRequestChannelUnsupported(); } else { final OpenSearchRequestChannel securityRequestChannel = (OpenSearchRequestChannel) request; final RestRequest restRequest = securityRequestChannel.breakEncapsulationForRequest(); diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestChannelUnsupported.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannelUnsupported.java new file mode 100644 index 0000000000..5989a893c0 --- /dev/null +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannelUnsupported.java @@ -0,0 +1,6 @@ +package org.opensearch.security.filter; + +/** Thrown when a security rest channel is not supported */ +public class SecurityRequestChannelUnsupported extends RuntimeException { + +} diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java b/src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java index 51934cc83c..5989a893c0 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java @@ -1,6 +1,6 @@ package org.opensearch.security.filter; /** Thrown when a security rest channel is not supported */ -public class SecurityRequetChannelUnsupported extends RuntimeException { +public class SecurityRequestChannelUnsupported extends RuntimeException { } From 5dc303328cec910ca3af669c4267c12a475951d4 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 21:09:48 +0000 Subject: [PATCH 42/50] Copyright headers Signed-off-by: Peter Nied --- .../dlic/rest/api/RestApiPrivilegesEvaluator.java | 6 ++---- .../security/filter/OpenSearchRequest.java | 11 +++++++++++ .../security/filter/OpenSearchRequestChannel.java | 11 +++++++++++ .../opensearch/security/filter/SecurityRequest.java | 13 ++++++++++++- .../security/filter/SecurityRequestChannel.java | 11 +++++++++++ .../filter/SecurityRequestChannelUnsupported.java | 11 +++++++++++ .../security/filter/SecurityRequestFactory.java | 11 +++++++++++ .../filter/SecurityRequetChannelUnsupported.java | 6 ------ .../security/filter/SecurityResponse.java | 11 +++++++++++ .../security/ssl/util/SSLRequestHelper.java | 3 ++- 10 files changed, 82 insertions(+), 12 deletions(-) delete mode 100644 src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java index 0e2c1b7a4d..922c52dbb5 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java @@ -35,6 +35,7 @@ import org.opensearch.rest.RestRequest.Method; import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.dlic.rest.support.Utils; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.privileges.PrivilegesEvaluator; @@ -448,10 +449,7 @@ private String checkAdminCertBasedAccessPermissions(RestRequest request) throws } // Certificate based access, Check if we have an admin TLS certificate - final SecurityRequestChannel securityRequest = SecurityRequestFactory.from( - request, - /* OK to be null so long as a response isn't sent */ null - ); + final SecurityRequest securityRequest = SecurityRequestFactory.from(request); SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); if (sslInfo == null) { diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java index bc07871619..430b498356 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java @@ -1,3 +1,14 @@ +/* + * 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.filter; import java.net.InetSocketAddress; diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index f8be79e093..7519c24f31 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -1,3 +1,14 @@ +/* + * 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.filter; import java.util.concurrent.atomic.AtomicBoolean; diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java index c3d5803860..19f96de8fe 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -1,4 +1,15 @@ -package org.opensearch.security.filter; +/* + * 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.filter; import java.net.InetSocketAddress; import java.util.List; diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java index d380bf38a2..1d4aba8051 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java @@ -1,3 +1,14 @@ +/* + * 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.filter; /** diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestChannelUnsupported.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannelUnsupported.java index 5989a893c0..bcacc2cf7a 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestChannelUnsupported.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannelUnsupported.java @@ -1,3 +1,14 @@ +/* + * 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.filter; /** Thrown when a security rest channel is not supported */ diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index beb6103728..5312cfbe07 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -1,3 +1,14 @@ +/* + * 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.filter; import org.opensearch.rest.RestChannel; diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java b/src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java deleted file mode 100644 index 5989a893c0..0000000000 --- a/src/main/java/org/opensearch/security/filter/SecurityRequetChannelUnsupported.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.opensearch.security.filter; - -/** Thrown when a security rest channel is not supported */ -public class SecurityRequestChannelUnsupported extends RuntimeException { - -} diff --git a/src/main/java/org/opensearch/security/filter/SecurityResponse.java b/src/main/java/org/opensearch/security/filter/SecurityResponse.java index 15424677b6..4bb8d41409 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityResponse.java +++ b/src/main/java/org/opensearch/security/filter/SecurityResponse.java @@ -1,3 +1,14 @@ +/* + * 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.filter; import java.util.Map; diff --git a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java index 3d896fe0b7..c8ced1718b 100644 --- a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java +++ b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java @@ -44,6 +44,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.env.Environment; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.transport.PrincipalExtractor.Type; @@ -119,7 +120,7 @@ public String toString() { public static SSLInfo getSSLInfo( final Settings settings, final Path configPath, - final SecurityRequestChannel request, + final SecurityRequest request, PrincipalExtractor principalExtractor ) throws SSLPeerUnverifiedException { final SSLEngine engine = request.getSSLEngine(); From e323823b269731eb4ed6340fcfb073238a4f173a Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Wed, 4 Oct 2023 21:15:19 +0000 Subject: [PATCH 43/50] PR comments Signed-off-by: Peter Nied --- .../dlic/auth/http/saml/HTTPSamlAuthenticator.java | 1 - .../opensearch/security/auth/BackendRegistry.java | 14 ++++++-------- .../security/dlic/rest/api/AbstractApiAction.java | 1 - .../dlic/rest/api/RestApiPrivilegesEvaluator.java | 1 - .../security/filter/OpenSearchRequest.java | 2 ++ .../security/filter/OpenSearchRequestChannel.java | 2 +- .../security/filter/SecurityRequest.java | 2 +- .../security/filter/SecurityRequestChannel.java | 4 ++-- .../security/filter/SecurityRequestFactory.java | 2 +- .../security/filter/SecurityRestFilter.java | 10 +++++----- .../netty/SecuritySSLNettyHttpServerTransport.java | 6 ------ .../security/ssl/util/SSLRequestHelper.java | 1 - 12 files changed, 18 insertions(+), 28 deletions(-) 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 eaa7ae80db..e511ba7bca 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 @@ -64,7 +64,6 @@ import org.opensearch.security.auth.HTTPAuthenticator; import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannelUnsupported; -import org.opensearch.security.filter.SecurityRequetChannelUnsupported; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.filter.OpenSearchRequestChannel; import org.opensearch.security.support.ConfigConstants; diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 039f6e90ca..2e2b3fb9e0 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -199,7 +199,7 @@ public boolean authenticate(final SecurityRequestChannel request) { log.debug("Rejecting REST request because of blocked address: {}", request.getRemoteAddress().orElse(null)); } - request.completeWithResponse(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, "Authentication finally failed")); + request.completeWith(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, "Authentication finally failed")); return false; } @@ -219,9 +219,7 @@ public boolean authenticate(final SecurityRequestChannel request) { if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); - request.completeWithResponse( - new SecurityResponse(HttpStatus.SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized.") - ); + request.completeWith(new SecurityResponse(HttpStatus.SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized.")); return false; } @@ -295,7 +293,7 @@ public boolean authenticate(final SecurityRequestChannel request) { log.trace("No 'Authorization' header, send 401 and 'WWW-Authenticate Basic'"); } notifyIpAuthFailureListeners(request, authCredentials); - request.completeWithResponse(restResponse.get()); + request.completeWith(restResponse.get()); return false; } } else { @@ -312,7 +310,7 @@ public boolean authenticate(final SecurityRequestChannel request) { final Optional restResponse = httpAuthenticator.reRequestAuthentication(request, ac); if (restResponse.isPresent()) { notifyIpAuthFailureListeners(request, ac); - request.completeWithResponse(restResponse.get()); + request.completeWith(restResponse.get()); return false; } else { // no reRequest possible @@ -350,7 +348,7 @@ public boolean authenticate(final SecurityRequestChannel request) { if (adminDns.isAdmin(authenticatedUser)) { log.error("Cannot authenticate rest user because admin user is not permitted to login via HTTP"); auditLog.logFailedLogin(authenticatedUser.getName(), true, null, request); - request.completeWithResponse( + request.completeWith( new SecurityResponse( HttpStatus.SC_FORBIDDEN, null, @@ -425,7 +423,7 @@ public boolean authenticate(final SecurityRequestChannel request) { notifyIpAuthFailureListeners(request, authCredentials); - request.completeWithResponse( + request.completeWith( challengeResponse.orElseGet(() -> new SecurityResponse(SC_UNAUTHORIZED, null, "Authentication finally failed")) ); return false; diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index aa2af3f042..f144e16ae0 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -568,7 +568,6 @@ protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClie return channel -> threadPool.generic().submit(() -> { try (StoredContext ignore = threadPool.getThreadContext().stashContext()) { - System.out.println("Inside validation handler path"); threadPool.getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_CONF_REQUEST_HEADER, "true"); threadPool.getThreadContext() .putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, originalUserAndRemoteAddress.getLeft()); diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java index 922c52dbb5..f1a336986b 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/RestApiPrivilegesEvaluator.java @@ -36,7 +36,6 @@ import org.opensearch.security.configuration.AdminDNs; import org.opensearch.security.dlic.rest.support.Utils; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.privileges.PrivilegesEvaluator; import org.opensearch.security.ssl.transport.PrincipalExtractor; diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java index 430b498356..85c70b8f7a 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequest.java @@ -48,6 +48,8 @@ public SSLEngine getSSLEngine() { return null; } + // We look for Ssl_handler called `ssl_http` in the outbound pipeline of Netty channel first, and if its not + // present we look for it in inbound channel. If its present in neither we return null, else we return the sslHandler. final Netty4HttpChannel httpChannel = (Netty4HttpChannel) underlyingRequest.getHttpChannel(); SslHandler sslhandler = (SslHandler) httpChannel.getNettyChannel().pipeline().get("ssl_http"); if (sslhandler == null && httpChannel.inboundPipeline() != null) { diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index 7519c24f31..ed8e0f1f9f 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -38,7 +38,7 @@ public boolean hasCompleted() { } @Override - public boolean completeWithResponse(final SecurityResponse response) { + public boolean completeWith(final SecurityResponse response) { if (underlyingChannel == null) { throw new UnsupportedOperationException("Channel was not defined"); diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequest.java b/src/main/java/org/opensearch/security/filter/SecurityRequest.java index 19f96de8fe..7e6e94e0a6 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequest.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequest.java @@ -9,7 +9,7 @@ * GitHub history for details. */ - package org.opensearch.security.filter; +package org.opensearch.security.filter; import java.net.InetSocketAddress; import java.util.List; diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java index 1d4aba8051..a1e93c59fd 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java @@ -12,7 +12,7 @@ package org.opensearch.security.filter; /** - * When a request is recieved by the security plugin this governs getting information about the request as well as a way to complet + * When a request is recieved by the security plugin this governs getting information about the request and complete with with a response */ public interface SecurityRequestChannel extends SecurityRequest { @@ -22,5 +22,5 @@ public interface SecurityRequestChannel extends SecurityRequest { public boolean hasCompleted(); /** Use this channel to send a response */ - public boolean completeWithResponse(final SecurityResponse response); + public boolean completeWith(final SecurityResponse response); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java index 5312cfbe07..de74df01ff 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestFactory.java @@ -19,7 +19,7 @@ */ public class SecurityRequestFactory { - /** Creates a security requset from a RestRequest */ + /** Creates a security request from a RestRequest */ public static SecurityRequest from(final RestRequest request) { return new OpenSearchRequest(request); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 4f005f3e09..0448a1558a 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -137,7 +137,7 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return; } - // Authorize Requset + // Authorize Request final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); if (userIsSuperAdmin(user, adminDNs)) { // Super admins are always authorized @@ -207,7 +207,7 @@ private void authorizeRequest(RestHandler original, SecurityRequestChannel reque } log.debug(err); - request.completeWithResponse(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, err)); + request.completeWith(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, err)); return; } } @@ -221,7 +221,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); - requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); + requestChannel.completeWith(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); return; } @@ -230,7 +230,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); - requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); + requestChannel.completeWith(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); return; } @@ -251,7 +251,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t log.error("No ssl info", e); auditLog.logSSLException(requestChannel, e); - requestChannel.completeWithResponse(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, null)); + requestChannel.completeWith(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, null)); return; } diff --git a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java index 6d53c47a8a..2d6ffb8d78 100644 --- a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java +++ b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java @@ -94,12 +94,6 @@ public void onException(HttpChannel channel, Exception cause0) { super.onException(channel, cause0); } - // TODO: Disable since changes in core aren't avaliable yet - // @Override - // protected ChannelInboundHandlerAdapter createHeaderVerifier() { - // return new AuthenicationVerifier(); - // } - protected class SSLHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler { /** * Application negotiation handler to select either HTTP 1.1 or HTTP 2 protocol, based diff --git a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java index c8ced1718b..df92bfc703 100644 --- a/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java +++ b/src/main/java/org/opensearch/security/ssl/util/SSLRequestHelper.java @@ -45,7 +45,6 @@ import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.env.Environment; import org.opensearch.security.filter.SecurityRequest; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.transport.PrincipalExtractor.Type; From 177ad1149d31c8b5f38ccbba84634bf360a5a559 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Thu, 5 Oct 2023 01:09:23 +0000 Subject: [PATCH 44/50] Fix issue with saml tests Signed-off-by: Peter Nied --- .../http/saml/AuthTokenProcessorHandler.java | 45 ++++++++----------- .../auth/http/saml/HTTPSamlAuthenticator.java | 15 +++---- .../http/saml/HTTPSamlAuthenticatorTest.java | 44 +++++++++--------- 3 files changed, 46 insertions(+), 58 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java b/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java index 3fee4a9444..0ef063f5e1 100644 --- a/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java +++ b/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java @@ -19,6 +19,8 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -36,6 +38,10 @@ import com.onelogin.saml2.exception.ValidationError; import com.onelogin.saml2.settings.Saml2Settings; import com.onelogin.saml2.util.Util; + +import io.netty.handler.codec.http.HttpContent; +import io.netty.handler.codec.http.HttpHeaderNames; + import org.apache.commons.lang3.StringUtils; import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter; import org.apache.cxf.rs.security.jose.jwk.JsonWebKey; @@ -46,6 +52,7 @@ import org.apache.cxf.rs.security.jose.jwt.JwtClaims; import org.apache.cxf.rs.security.jose.jwt.JwtToken; import org.apache.cxf.rs.security.jose.jwt.JwtUtils; +import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.joda.time.DateTime; @@ -63,6 +70,7 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.dlic.rest.api.AuthTokenProcessorAction; +import org.opensearch.security.filter.SecurityResponse; class AuthTokenProcessorHandler { private static final Logger log = LogManager.getLogger(AuthTokenProcessorHandler.class); @@ -122,7 +130,7 @@ class AuthTokenProcessorHandler { } @SuppressWarnings("removal") - boolean handle(RestRequest restRequest, RestChannel restChannel) throws Exception { + Optional handle(RestRequest restRequest) throws Exception { try { final SecurityManager sm = System.getSecurityManager(); @@ -130,11 +138,10 @@ boolean handle(RestRequest restRequest, RestChannel restChannel) throws Exceptio sm.checkPermission(new SpecialPermission()); } - return AccessController.doPrivileged(new PrivilegedExceptionAction() { + return AccessController.doPrivileged(new PrivilegedExceptionAction>() { @Override - public Boolean run() throws XPathExpressionException, SamlConfigException, IOException, ParserConfigurationException, - SAXException, SettingsException { - return handleLowLevel(restRequest, restChannel); + public Optional run() throws SamlConfigException, IOException { + return handleLowLevel(restRequest); } }); } catch (PrivilegedActionException e) { @@ -147,13 +154,11 @@ public Boolean run() throws XPathExpressionException, SamlConfigException, IOExc } private AuthTokenProcessorAction.Response handleImpl( - RestRequest restRequest, - RestChannel restChannel, String samlResponseBase64, String samlRequestId, String acsEndpoint, Saml2Settings saml2Settings - ) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException, SettingsException { + ) { if (token_log.isDebugEnabled()) { try { token_log.debug( @@ -188,8 +193,7 @@ private AuthTokenProcessorAction.Response handleImpl( } } - private boolean handleLowLevel(RestRequest restRequest, RestChannel restChannel) throws SamlConfigException, IOException, - XPathExpressionException, ParserConfigurationException, SAXException, SettingsException { + private Optional handleLowLevel(RestRequest restRequest) throws SamlConfigException, IOException { try { if (restRequest.getMediaType() != XContentType.JSON) { @@ -234,31 +238,18 @@ private boolean handleLowLevel(RestRequest restRequest, RestChannel restChannel) acsEndpoint = getAbsoluteAcsEndpoint(((ObjectNode) jsonRoot).get("acsEndpoint").textValue()); } - AuthTokenProcessorAction.Response responseBody = this.handleImpl( - restRequest, - restChannel, - samlResponseBase64, - samlRequestId, - acsEndpoint, - saml2Settings - ); + AuthTokenProcessorAction.Response responseBody = this.handleImpl(samlResponseBase64, samlRequestId, acsEndpoint, saml2Settings); if (responseBody == null) { - return false; + return Optional.empty(); } String responseBodyString = DefaultObjectMapper.objectMapper.writeValueAsString(responseBody); - BytesRestResponse authenticateResponse = new BytesRestResponse(RestStatus.OK, "application/json", responseBodyString); - restChannel.sendResponse(authenticateResponse); - - return true; + return Optional.of(new SecurityResponse(HttpStatus.SC_OK, Map.of(HttpHeaderNames.CONTENT_TYPE.toString(), "application/json"), responseBodyString)); } catch (JsonProcessingException e) { log.warn("Error while parsing JSON for /_opendistro/_security/api/authtoken", e); - - BytesRestResponse authenticateResponse = new BytesRestResponse(RestStatus.BAD_REQUEST, "JSON could not be parsed"); - restChannel.sendResponse(authenticateResponse); - return true; + return Optional.of(new SecurityResponse(HttpStatus.SC_BAD_REQUEST, null, "JSON could not be parsed")); } } 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 e511ba7bca..ecc2448c09 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 @@ -65,6 +65,7 @@ import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannelUnsupported; import org.opensearch.security.filter.SecurityResponse; +import org.opensearch.security.filter.OpenSearchRequest; import org.opensearch.security.filter.OpenSearchRequestChannel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.PemKeyReader; @@ -184,16 +185,14 @@ public Optional reRequestAuthentication(final SecurityRequest if (API_AUTHTOKEN_SUFFIX.equals(suffix)) { // Verficiation of SAML ASC endpoint only works with RestRequests - if (!(request instanceof OpenSearchRequestChannel)) { + if (!(request instanceof OpenSearchRequest)) { throw new SecurityRequestChannelUnsupported(); } else { - final OpenSearchRequestChannel securityRequestChannel = (OpenSearchRequestChannel) request; - final RestRequest restRequest = securityRequestChannel.breakEncapsulationForRequest(); - final RestChannel channel = securityRequestChannel.breakEncapsulationForChannel(); - if (this.authTokenProcessorHandler.handle(restRequest, channel)) { - // The ACS response was accepted - securityRequestChannel.markCompleted(); - return Optional.empty(); + final OpenSearchRequest openSearchRequest = (OpenSearchRequest) request; + final RestRequest restRequest = openSearchRequest.breakEncapsulationForRequest(); + Optional restResponse = this.authTokenProcessorHandler.handle(restRequest); + if (restResponse.isPresent()) { + return restResponse; } } } diff --git a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java index dd030da5ed..17a2148fa5 100644 --- a/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/saml/HTTPSamlAuthenticatorTest.java @@ -25,6 +25,7 @@ import java.util.Base64; import java.util.HashMap; import java.util.List; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -34,6 +35,7 @@ import com.google.common.collect.ImmutableMap; import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer; import org.apache.cxf.rs.security.jose.jwt.JwtToken; +import org.hamcrest.Matchers; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -42,7 +44,6 @@ import org.opensaml.saml.saml2.core.NameIDType; import org.opensearch.core.common.bytes.BytesArray; -import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.common.io.stream.BytesStreamOutput; import org.opensearch.common.settings.Settings; import org.opensearch.core.xcontent.MediaType; @@ -54,13 +55,15 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.security.DefaultObjectMapper; import org.opensearch.security.filter.SecurityRequestFactory; -import org.opensearch.security.filter.OpenSearchRequestChannel; +import org.opensearch.security.filter.SecurityResponse; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.test.helper.file.FileHelper; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.util.FakeRestRequest; import static com.amazon.dlic.auth.http.saml.HTTPSamlAuthenticator.IDP_METADATA_CONTENT; import static com.amazon.dlic.auth.http.saml.HTTPSamlAuthenticator.IDP_METADATA_URL; +import static org.hamcrest.MatcherAssert.assertThat; public class HTTPSamlAuthenticatorTest { protected MockSamlIdpServer mockSamlIdpServer; @@ -158,17 +161,15 @@ public void basicTest() throws Exception { Assert.assertEquals("horst", jwt.getClaim("sub")); } - private TestRestChannel sendToAuthenticator(HTTPSamlAuthenticator samlAuthenticator, RestRequest request) { - TestRestChannel testChannel = new TestRestChannel(request); - OpenSearchRequestChannel tokenRestChannel = (OpenSearchRequestChannel) SecurityRequestFactory.from(request, testChannel); + private Optional sendToAuthenticator(HTTPSamlAuthenticator samlAuthenticator, RestRequest request) { + final SecurityRequest tokenRestChannel = SecurityRequestFactory.from(request); - samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); - return testChannel; + return samlAuthenticator.reRequestAuthentication(tokenRestChannel, null); } private String getResponse(HTTPSamlAuthenticator samlAuthenticator, RestRequest request) throws Exception { - TestRestChannel testChannel = sendToAuthenticator(samlAuthenticator, request); - return new String(BytesReference.toBytes(testChannel.response.content())); + SecurityResponse response = sendToAuthenticator(samlAuthenticator, request).orElseThrow(); + return response.getBody(); } @Test @@ -534,9 +535,9 @@ public void badUnsolicitedSsoTest() throws Exception { authenticateHeaders, "/opendistrosecurity/saml/acs/idpinitiated" ); - TestRestChannel tokenRestChannel = sendToAuthenticator(samlAuthenticator, tokenRestRequest); + SecurityResponse response = sendToAuthenticator(samlAuthenticator, tokenRestRequest).orElseThrow(); - Assert.assertEquals(RestStatus.UNAUTHORIZED, tokenRestChannel.response.status()); + Assert.assertEquals(RestStatus.UNAUTHORIZED.getStatus(), response.getStatus()); } @Test @@ -564,9 +565,9 @@ public void wrongCertTest() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = sendToAuthenticator(samlAuthenticator, tokenRestRequest); + SecurityResponse response = sendToAuthenticator(samlAuthenticator, tokenRestRequest).orElseThrow(); - Assert.assertEquals(401, tokenRestChannel.response.status().getStatus()); + Assert.assertEquals(401, response.getStatus()); } @Test @@ -591,9 +592,9 @@ public void noSignatureTest() throws Exception { String encodedSamlResponse = mockSamlIdpServer.handleSsoGetRequestURI(authenticateHeaders.location); RestRequest tokenRestRequest = buildTokenExchangeRestRequest(encodedSamlResponse, authenticateHeaders); - TestRestChannel tokenRestChannel = sendToAuthenticator(samlAuthenticator, tokenRestRequest); + SecurityResponse response = sendToAuthenticator(samlAuthenticator, tokenRestRequest).orElseThrow(); - Assert.assertEquals(401, tokenRestChannel.response.status().getStatus()); + Assert.assertEquals(401, response.getStatus()); } @SuppressWarnings("unchecked") @@ -815,9 +816,9 @@ public void initialConnectionFailureTest() throws Exception { HTTPSamlAuthenticator samlAuthenticator = new HTTPSamlAuthenticator(settings, null); RestRequest restRequest = new FakeRestRequest(ImmutableMap.of(), new HashMap()); - TestRestChannel restChannel = sendToAuthenticator(samlAuthenticator, restRequest); + Optional maybeResponse = sendToAuthenticator(samlAuthenticator, restRequest); - Assert.assertNull(restChannel.response); + assertThat(maybeResponse.isPresent(), Matchers.equalTo(false)); mockSamlIdpServer.start(); @@ -852,14 +853,11 @@ public void initialConnectionFailureTest() throws Exception { private AuthenticateHeaders getAutenticateHeaders(HTTPSamlAuthenticator samlAuthenticator) { RestRequest restRequest = new FakeRestRequest(ImmutableMap.of(), new HashMap()); - TestRestChannel restChannel = sendToAuthenticator(samlAuthenticator, restRequest); + SecurityResponse response = sendToAuthenticator(samlAuthenticator, restRequest).orElseThrow(); - List wwwAuthenticateHeaders = restChannel.response.getHeaders().get("WWW-Authenticate"); + String wwwAuthenticateHeader = response.getHeaders().get("WWW-Authenticate"); - Assert.assertNotNull(wwwAuthenticateHeaders); - Assert.assertEquals("More than one WWW-Authenticate header: " + wwwAuthenticateHeaders, 1, wwwAuthenticateHeaders.size()); - - String wwwAuthenticateHeader = wwwAuthenticateHeaders.get(0); + Assert.assertNotNull(wwwAuthenticateHeader); Matcher wwwAuthenticateHeaderMatcher = WWW_AUTHENTICATE_PATTERN.matcher(wwwAuthenticateHeader); From 1312d2c98a46e09a17613ea482e1e901e53af7ac Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Thu, 5 Oct 2023 01:36:13 +0000 Subject: [PATCH 45/50] Fine tunning cr pass Signed-off-by: Peter Nied --- .../jwt/AbstractHTTPJwtAuthenticator.java | 7 +-- .../auth/http/jwt/HTTPJwtAuthenticator.java | 8 ++-- .../http/saml/AuthTokenProcessorHandler.java | 13 ++---- .../auth/http/saml/HTTPSamlAuthenticator.java | 2 - .../security/auth/BackendRegistry.java | 14 +++--- .../dlic/rest/api/AbstractApiAction.java | 1 + .../dlic/rest/api/NodesDnApiAction.java | 1 - .../security/dlic/rest/api/Responses.java | 1 - .../rest/validation/EndpointValidator.java | 1 - .../security/filter/SecurityFilter.java | 1 - .../security/filter/SecurityRestFilter.java | 1 - .../SecurityNonSslHttpServerTransport.java | 7 --- .../rest/SecurityConfigUpdateAction.java | 45 +++++++++---------- .../security/rest/SecurityWhoAmIAction.java | 10 +++-- .../security/rest/TenantInfoAction.java | 1 - .../impl/AllowlistingSettings.java | 1 - .../impl/WhitelistingSettings.java | 1 - .../SecuritySSLNettyHttpServerTransport.java | 1 - .../ssl/rest/SecuritySSLInfoAction.java | 9 ++-- 19 files changed, 53 insertions(+), 72 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java index f2a9de655e..b183593a91 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/AbstractHTTPJwtAuthenticator.java @@ -11,6 +11,8 @@ package com.amazon.dlic.auth.http.jwt; +import static org.apache.http.HttpHeaders.AUTHORIZATION; + import java.nio.file.Path; import java.security.AccessController; import java.security.PrivilegedAction; @@ -23,7 +25,6 @@ import com.google.common.annotations.VisibleForTesting; import org.apache.cxf.rs.security.jose.jwt.JwtClaims; import org.apache.cxf.rs.security.jose.jwt.JwtToken; -import org.apache.hc.core5.http.HttpHeaders; import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -65,8 +66,8 @@ public abstract class AbstractHTTPJwtAuthenticator implements HTTPAuthenticator public AbstractHTTPJwtAuthenticator(Settings settings, Path configPath) { jwtUrlParameter = settings.get("jwt_url_parameter"); - jwtHeaderName = settings.get("jwt_header", HttpHeaders.AUTHORIZATION); - isDefaultAuthHeader = HttpHeaders.AUTHORIZATION.equalsIgnoreCase(jwtHeaderName); + jwtHeaderName = settings.get("jwt_header", AUTHORIZATION); + isDefaultAuthHeader = AUTHORIZATION.equalsIgnoreCase(jwtHeaderName); rolesKey = settings.get("roles_key"); subjectKey = settings.get("subject_key"); clockSkewToleranceSeconds = settings.getAsInt("jwt_clock_skew_tolerance_seconds", DEFAULT_CLOCK_SKEW_TOLERANCE_SECONDS); diff --git a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java index bd04217db7..df1c605167 100644 --- a/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticator.java @@ -11,6 +11,8 @@ package com.amazon.dlic.auth.http.jwt; +import static org.apache.http.HttpHeaders.AUTHORIZATION; + import java.nio.file.Path; import java.security.AccessController; import java.security.PrivilegedAction; @@ -24,7 +26,7 @@ import io.jsonwebtoken.JwtParser; import io.jsonwebtoken.JwtParserBuilder; import io.jsonwebtoken.security.WeakKeyException; -import org.apache.hc.core5.http.HttpHeaders; + import org.apache.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -60,8 +62,8 @@ public HTTPJwtAuthenticator(final Settings settings, final Path configPath) { String signingKey = settings.get("signing_key"); jwtUrlParameter = settings.get("jwt_url_parameter"); - jwtHeaderName = settings.get("jwt_header", HttpHeaders.AUTHORIZATION); - isDefaultAuthHeader = HttpHeaders.AUTHORIZATION.equalsIgnoreCase(jwtHeaderName); + jwtHeaderName = settings.get("jwt_header", AUTHORIZATION); + isDefaultAuthHeader = AUTHORIZATION.equalsIgnoreCase(jwtHeaderName); rolesKey = settings.get("roles_key"); subjectKey = settings.get("subject_key"); requireAudience = settings.get("required_audience"); diff --git a/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java b/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java index 0ef063f5e1..7e7f6803f7 100644 --- a/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java +++ b/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java @@ -11,6 +11,8 @@ package com.amazon.dlic.auth.http.saml; +import static org.apache.http.HttpHeaders.CONTENT_TYPE; + import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -25,7 +27,6 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; import com.fasterxml.jackson.core.JsonParseException; @@ -34,14 +35,10 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Strings; import com.onelogin.saml2.authn.SamlResponse; -import com.onelogin.saml2.exception.SettingsException; import com.onelogin.saml2.exception.ValidationError; import com.onelogin.saml2.settings.Saml2Settings; import com.onelogin.saml2.util.Util; -import io.netty.handler.codec.http.HttpContent; -import io.netty.handler.codec.http.HttpHeaderNames; - import org.apache.commons.lang3.StringUtils; import org.apache.cxf.jaxrs.json.basic.JsonMapObjectReaderWriter; import org.apache.cxf.rs.security.jose.jwk.JsonWebKey; @@ -56,15 +53,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.joda.time.DateTime; -import org.xml.sax.SAXException; - import org.opensearch.OpenSearchSecurityException; import org.opensearch.SpecialPermission; import org.opensearch.core.common.bytes.BytesReference; import org.opensearch.common.settings.Settings; import org.opensearch.common.xcontent.XContentType; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; import org.opensearch.core.rest.RestStatus; @@ -246,7 +239,7 @@ private Optional handleLowLevel(RestRequest restRequest) throw String responseBodyString = DefaultObjectMapper.objectMapper.writeValueAsString(responseBody); - return Optional.of(new SecurityResponse(HttpStatus.SC_OK, Map.of(HttpHeaderNames.CONTENT_TYPE.toString(), "application/json"), responseBodyString)); + return Optional.of(new SecurityResponse(HttpStatus.SC_OK, Map.of(CONTENT_TYPE, "application/json"), responseBodyString)); } catch (JsonProcessingException e) { log.warn("Error while parsing JSON for /_opendistro/_security/api/authtoken", e); return Optional.of(new SecurityResponse(HttpStatus.SC_BAD_REQUEST, null, "JSON could not be parsed")); 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 ecc2448c09..a3f37ba46e 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 @@ -58,7 +58,6 @@ import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; -import org.opensearch.rest.RestChannel; import org.opensearch.rest.RestRequest; import org.opensearch.security.auth.Destroyable; import org.opensearch.security.auth.HTTPAuthenticator; @@ -66,7 +65,6 @@ import org.opensearch.security.filter.SecurityRequestChannelUnsupported; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.filter.OpenSearchRequest; -import org.opensearch.security.filter.OpenSearchRequestChannel; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.PemKeyReader; import org.opensearch.security.user.AuthCredentials; diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 2e2b3fb9e0..2a0a921883 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -45,7 +45,6 @@ import com.google.common.cache.RemovalNotification; import com.google.common.collect.Multimap; -import org.apache.hc.core5.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.greenrobot.eventbus.Subscribe; @@ -58,6 +57,7 @@ import org.opensearch.security.auth.blocking.ClientBlockRegistry; import org.opensearch.security.auth.internal.NoOpAuthenticationBackend; import org.opensearch.security.configuration.AdminDNs; +import org.opensearch.security.filter.SecurityRequest; import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityResponse; import org.opensearch.security.http.OnBehalfOfAuthenticator; @@ -69,6 +69,8 @@ import org.opensearch.security.user.User; import org.opensearch.threadpool.ThreadPool; +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; public class BackendRegistry { @@ -199,7 +201,7 @@ public boolean authenticate(final SecurityRequestChannel request) { log.debug("Rejecting REST request because of blocked address: {}", request.getRemoteAddress().orElse(null)); } - request.completeWith(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, "Authentication finally failed")); + request.completeWith(new SecurityResponse(SC_UNAUTHORIZED, null, "Authentication finally failed")); return false; } @@ -219,7 +221,7 @@ public boolean authenticate(final SecurityRequestChannel request) { if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); - request.completeWith(new SecurityResponse(HttpStatus.SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized.")); + request.completeWith(new SecurityResponse(SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized.")); return false; } @@ -350,7 +352,7 @@ public boolean authenticate(final SecurityRequestChannel request) { auditLog.logFailedLogin(authenticatedUser.getName(), true, null, request); request.completeWith( new SecurityResponse( - HttpStatus.SC_FORBIDDEN, + SC_FORBIDDEN, null, "Cannot authenticate user because admin user is not permitted to login via HTTP" ) @@ -579,7 +581,7 @@ public User call() throws Exception { } } - private User impersonate(final SecurityRequestChannel request, final User originalUser) throws OpenSearchSecurityException { + private User impersonate(final SecurityRequest request, final User originalUser) throws OpenSearchSecurityException { final String impersonatedUserHeader = request.header("opendistro_security_impersonate_as"); @@ -592,7 +594,6 @@ private User impersonate(final SecurityRequestChannel request, final User origin } if (adminDns.isAdminDN(impersonatedUserHeader)) { - throw new OpenSearchSecurityException( "It is not allowed to impersonate as an adminuser '" + impersonatedUserHeader + "'", RestStatus.FORBIDDEN @@ -600,7 +601,6 @@ private User impersonate(final SecurityRequestChannel request, final User origin } if (!adminDns.isRestImpersonationAllowed(originalUser.getName(), impersonatedUserHeader)) { - throw new OpenSearchSecurityException( "'" + originalUser.getName() + "' is not allowed to impersonate as '" + impersonatedUserHeader + "'", RestStatus.FORBIDDEN diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java index f144e16ae0..6cbd7eaf78 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AbstractApiAction.java @@ -539,6 +539,7 @@ public void onFailure(Exception e) { @Override protected final RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { + // consume all parameters first so we can return a correct HTTP status, // not 400 consumeParameters(request); diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java index 30885b69f0..ed1f3e0fbb 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/NodesDnApiAction.java @@ -139,7 +139,6 @@ public RestApiAdminPrivilegesEvaluator restApiAdminPrivilegesEvaluator() { public ValidationResult isAllowedToChangeImmutableEntity(SecurityConfiguration securityConfiguration) throws IOException { if (STATIC_OPENSEARCH_YML_NODES_DN.equals(securityConfiguration.entityName())) { - return ValidationResult.error( RestStatus.FORBIDDEN, forbiddenMessage("Resource '" + STATIC_OPENSEARCH_YML_NODES_DN + "' is read-only.") diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java b/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java index 60310c7fa4..6af8f0e936 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/Responses.java @@ -73,7 +73,6 @@ public static void response(RestChannel channel, RestStatus status, String messa public static void response(final RestChannel channel, final RestStatus status, final ToXContent toXContent) { try (final var builder = channel.newBuilder()) { toXContent.toXContent(builder, ToXContent.EMPTY_PARAMS); - channel.sendResponse(new BytesRestResponse(status, builder)); } catch (final IOException ioe) { throw ExceptionsHelper.convertToOpenSearchException(ioe); diff --git a/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java b/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java index fa5c7052fe..6eb865e937 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java +++ b/src/main/java/org/opensearch/security/dlic/rest/validation/EndpointValidator.java @@ -55,7 +55,6 @@ default boolean isCurrentUserAdmin() { default ValidationResult withRequiredEntityName(final String entityName) { if (entityName == null) { - return ValidationResult.error(RestStatus.BAD_REQUEST, badRequestMessage("No " + resourceName() + " specified.")); } return ValidationResult.success(entityName); diff --git a/src/main/java/org/opensearch/security/filter/SecurityFilter.java b/src/main/java/org/opensearch/security/filter/SecurityFilter.java index d4aaa4b7ff..00b117ebb8 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityFilter.java @@ -515,7 +515,6 @@ private boolean checkImmutableIndices(Object request, ActionListener listener) { || request instanceof IndicesAliasesRequest; if (isModifyIndexRequest && isRequestIndexImmutable(request)) { - listener.onFailure(new OpenSearchSecurityException("Index is immutable", RestStatus.FORBIDDEN)); return true; } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 0448a1558a..769bcb07e7 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -250,7 +250,6 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t } catch (SSLPeerUnverifiedException e) { log.error("No ssl info", e); auditLog.logSSLException(requestChannel, e); - requestChannel.completeWith(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, null)); return; } diff --git a/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java b/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java index 72fd5bf61d..a8e675ec74 100644 --- a/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java +++ b/src/main/java/org/opensearch/security/http/SecurityNonSslHttpServerTransport.java @@ -71,12 +71,6 @@ public ChannelHandler configureServerChannelHandler() { return new NonSslHttpChannelHandler(this, handlingSettings); } - // TODO: Disabled for confirming refactor around SecurityRequest is working as expected - // @Override - // protected ChannelInboundHandlerAdapter createHeaderVerifier() { - // return new AuthenicationVerifier(); - // } - protected class NonSslHttpChannelHandler extends Netty4HttpServerTransport.HttpChannelHandler { protected NonSslHttpChannelHandler(Netty4HttpServerTransport transport, final HttpHandlingSettings handlingSettings) { @@ -88,5 +82,4 @@ protected void initChannel(Channel ch) throws Exception { super.initChannel(ch); } } - } diff --git a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java index df8b721d59..bfbc16f98d 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityConfigUpdateAction.java @@ -29,7 +29,6 @@ import org.opensearch.security.action.configupdate.ConfigUpdateAction; import org.opensearch.security.action.configupdate.ConfigUpdateRequest; import org.opensearch.security.configuration.AdminDNs; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; @@ -75,30 +74,28 @@ public List routes() { protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { String[] configTypes = request.paramAsStringArrayOrEmptyIfAll("config_types"); - return channel -> { - - final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); - SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); - - if (sslInfo == null) { - - channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); - return; - } - - final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); - - // only allowed for admins - if (user == null || !adminDns.isAdmin(user)) { - - channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); - return; - } else { - ConfigUpdateRequest configUpdateRequest = new ConfigUpdateRequest(configTypes); + SSLRequestHelper.SSLInfo sslInfo = SSLRequestHelper.getSSLInfo( + settings, + configPath, + SecurityRequestFactory.from(request), + principalExtractor + ); + + if (sslInfo == null) { + return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); + } + + final User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); + + // only allowed for admins + if (user == null || !adminDns.isAdmin(user)) { + return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.FORBIDDEN, "")); + } else { + ConfigUpdateRequest configUpdateRequest = new ConfigUpdateRequest(configTypes); + return channel -> { client.execute(ConfigUpdateAction.INSTANCE, configUpdateRequest, new NodesResponseRestListener<>(channel)); - return; - } - }; + }; + } } @Override diff --git a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java index acf0249ed8..4f560f40b6 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityWhoAmIAction.java @@ -32,7 +32,6 @@ import org.opensearch.rest.RestRequest; import org.opensearch.core.rest.RestStatus; import org.opensearch.security.configuration.AdminDNs; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.transport.PrincipalExtractor; import org.opensearch.security.ssl.util.SSLRequestHelper; @@ -99,11 +98,14 @@ public void accept(RestChannel channel) throws Exception { BytesRestResponse response = null; try { - final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); - SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); + SSLInfo sslInfo = SSLRequestHelper.getSSLInfo( + settings, + configPath, + SecurityRequestFactory.from(request), + principalExtractor + ); if (sslInfo == null) { - response = new BytesRestResponse(RestStatus.FORBIDDEN, "No security data"); } else { diff --git a/src/main/java/org/opensearch/security/rest/TenantInfoAction.java b/src/main/java/org/opensearch/security/rest/TenantInfoAction.java index 59831f9852..f3afc0f006 100644 --- a/src/main/java/org/opensearch/security/rest/TenantInfoAction.java +++ b/src/main/java/org/opensearch/security/rest/TenantInfoAction.java @@ -114,7 +114,6 @@ public void accept(RestChannel channel) throws Exception { // only allowed for admins or the kibanaserveruser if (!isAuthorized()) { - response = new BytesRestResponse(RestStatus.FORBIDDEN, ""); } else { diff --git a/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java b/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java index 370d13f51b..98fc7a266a 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java @@ -110,7 +110,6 @@ private boolean requestIsAllowlisted(RestRequest request) { public boolean checkRequestIsAllowed(RestRequest request, RestChannel channel, NodeClient client) throws IOException { // if allowlisting is enabled but the request is not allowlisted, then return false, otherwise true. if (this.enabled && !requestIsAllowlisted(request)) { - channel.sendResponse( new BytesRestResponse( RestStatus.FORBIDDEN, diff --git a/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java b/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java index 182b2c87f6..4462bae90f 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java @@ -111,7 +111,6 @@ private boolean requestIsWhitelisted(RestRequest request) { public boolean checkRequestIsAllowed(RestRequest request, RestChannel channel, NodeClient client) throws IOException { // if whitelisting is enabled but the request is not whitelisted, then return false, otherwise true. if (this.enabled && !requestIsWhitelisted(request)) { - channel.sendResponse( new BytesRestResponse( RestStatus.FORBIDDEN, diff --git a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java index 2d6ffb8d78..081cc13f3e 100644 --- a/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java +++ b/src/main/java/org/opensearch/security/ssl/http/netty/SecuritySSLNettyHttpServerTransport.java @@ -149,5 +149,4 @@ protected void configurePipeline(Channel ch) { ch.pipeline().addLast(new Http2OrHttpHandler()); } } - } diff --git a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java index ebf5945a73..8e32893eab 100644 --- a/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java +++ b/src/main/java/org/opensearch/security/ssl/rest/SecuritySSLInfoAction.java @@ -39,7 +39,6 @@ import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestRequest.Method; import org.opensearch.core.rest.RestStatus; -import org.opensearch.security.filter.SecurityRequestChannel; import org.opensearch.security.filter.SecurityRequestFactory; import org.opensearch.security.ssl.SecurityKeyStore; import org.opensearch.security.ssl.transport.PrincipalExtractor; @@ -86,8 +85,12 @@ public void accept(RestChannel channel) throws Exception { BytesRestResponse response = null; try { - final SecurityRequestChannel securityRequest = SecurityRequestFactory.from(request, channel); - SSLInfo sslInfo = SSLRequestHelper.getSSLInfo(settings, configPath, securityRequest, principalExtractor); + SSLInfo sslInfo = SSLRequestHelper.getSSLInfo( + settings, + configPath, + SecurityRequestFactory.from(request), + principalExtractor + ); X509Certificate[] certs = sslInfo == null ? null : sslInfo.getX509Certs(); X509Certificate[] localCerts = sslInfo == null ? null : sslInfo.getLocalCertificates(); From 28f620bffcadfa3328f83eaa501232e97bdc7248 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Thu, 5 Oct 2023 04:20:15 +0000 Subject: [PATCH 46/50] Fix bad auth realm Signed-off-by: Peter Nied --- .../org/opensearch/security/http/HTTPBasicAuthenticator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java index 81fefa7a8e..ff07db147e 100644 --- a/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java +++ b/src/main/java/org/opensearch/security/http/HTTPBasicAuthenticator.java @@ -68,7 +68,7 @@ public AuthCredentials extractCredentials(final SecurityRequest request, final T @Override public Optional reRequestAuthentication(final SecurityRequest request, AuthCredentials creds) { return Optional.of( - new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Bearer realm=\"OpenSearch Security\""), "") + new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, Map.of("WWW-Authenticate", "Basic realm=\"OpenSearch Security\""), "") ); } From 38c34cb01113b8962b8ff92a7884b7c8c4868373 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Thu, 5 Oct 2023 04:26:10 +0000 Subject: [PATCH 47/50] Fix build break Signed-off-by: Peter Nied --- .../opensearch/security/OpenSearchSecurityPlugin.java | 10 +++++++--- .../security/ssl/OpenSearchSecuritySSLPlugin.java | 6 ++++-- .../ssl/transport/SecuritySSLNettyTransport.java | 7 +++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 8b1e307172..8191a2bb39 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -815,7 +815,9 @@ public Map> getTransports( PageCacheRecycler pageCacheRecycler, CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, - NetworkService networkService + NetworkService networkService, + Tracer tracer + ) { Map> transports = new HashMap>(); @@ -826,7 +828,8 @@ public Map> getTransports( pageCacheRecycler, circuitBreakerService, namedWriteableRegistry, - networkService + networkService, + tracer ); } @@ -844,7 +847,8 @@ public Map> getTransports( sks, evaluateSslExceptionHandler(), sharedGroupFactory, - SSLConfig + SSLConfig, + tracer ) ); } diff --git a/src/main/java/org/opensearch/security/ssl/OpenSearchSecuritySSLPlugin.java b/src/main/java/org/opensearch/security/ssl/OpenSearchSecuritySSLPlugin.java index bff2cf02d5..18ec7457e9 100644 --- a/src/main/java/org/opensearch/security/ssl/OpenSearchSecuritySSLPlugin.java +++ b/src/main/java/org/opensearch/security/ssl/OpenSearchSecuritySSLPlugin.java @@ -315,7 +315,8 @@ public Map> getTransports( PageCacheRecycler pageCacheRecycler, CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, - NetworkService networkService + NetworkService networkService, + Tracer tracer ) { Map> transports = new HashMap>(); @@ -333,7 +334,8 @@ public Map> getTransports( sks, NOOP_SSL_EXCEPTION_HANDLER, sharedGroupFactory, - SSLConfig + SSLConfig, + tracer ) ); diff --git a/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLNettyTransport.java b/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLNettyTransport.java index ad4ebec1c5..8a17ca8e61 100644 --- a/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLNettyTransport.java +++ b/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLNettyTransport.java @@ -63,6 +63,7 @@ import org.opensearch.transport.SharedGroupFactory; import org.opensearch.transport.TcpChannel; import org.opensearch.transport.netty4.Netty4Transport; +import org.opensearch.telemetry.tracing.Tracer; public class SecuritySSLNettyTransport extends Netty4Transport { @@ -82,7 +83,8 @@ public SecuritySSLNettyTransport( final SecurityKeyStore ossks, final SslExceptionHandler errorHandler, SharedGroupFactory sharedGroupFactory, - final SSLConfig SSLConfig + final SSLConfig SSLConfig, + final Tracer tracer ) { super( settings, @@ -92,7 +94,8 @@ public SecuritySSLNettyTransport( pageCacheRecycler, namedWriteableRegistry, circuitBreakerService, - sharedGroupFactory + sharedGroupFactory, + tracer ); this.ossks = ossks; From 641130f43783a06c7c4a586c32b89906cb149353 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Thu, 5 Oct 2023 21:28:36 +0000 Subject: [PATCH 48/50] Clean up allow list systems Signed-off-by: Peter Nied --- .../kerberos/HTTPSpnegoAuthenticator.java | 2 +- .../http/saml/AuthTokenProcessorHandler.java | 5 +- .../filter/OpenSearchRequestChannel.java | 49 +++++++++++++------ .../filter/SecurityRequestChannel.java | 15 +++--- .../security/filter/SecurityResponse.java | 5 ++ .../security/filter/SecurityRestFilter.java | 8 +-- .../impl/AllowlistingSettings.java | 44 ++++++++++------- .../impl/WhitelistingSettings.java | 32 +++++------- 8 files changed, 96 insertions(+), 64 deletions(-) diff --git a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java index e08860f7e2..ad24b8db95 100644 --- a/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java +++ b/src/main/java/com/amazon/dlic/auth/http/kerberos/HTTPSpnegoAuthenticator.java @@ -289,7 +289,7 @@ public Optional reRequestAuthentication(final SecurityRequest final String negotiateResponseBody = getNegotiateResponseBody(); if (negotiateResponseBody != null) { responseBody = negotiateResponseBody; - headers.put("Content-Type", "application/json"); + headers.putAll(SecurityResponse.CONTENT_TYPE_APP_JSON); } if (creds == null || creds.getNativeCredentials() == null) { diff --git a/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java b/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java index 7e7f6803f7..a344c653f3 100644 --- a/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java +++ b/src/main/java/com/amazon/dlic/auth/http/saml/AuthTokenProcessorHandler.java @@ -11,8 +11,6 @@ package com.amazon.dlic.auth.http.saml; -import static org.apache.http.HttpHeaders.CONTENT_TYPE; - import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -21,7 +19,6 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -239,7 +236,7 @@ private Optional handleLowLevel(RestRequest restRequest) throw String responseBodyString = DefaultObjectMapper.objectMapper.writeValueAsString(responseBody); - return Optional.of(new SecurityResponse(HttpStatus.SC_OK, Map.of(CONTENT_TYPE, "application/json"), responseBodyString)); + return Optional.of(new SecurityResponse(HttpStatus.SC_OK, SecurityResponse.CONTENT_TYPE_APP_JSON, responseBodyString)); } catch (JsonProcessingException e) { log.warn("Error while parsing JSON for /_opendistro/_security/api/authtoken", e); return Optional.of(new SecurityResponse(HttpStatus.SC_BAD_REQUEST, null, "JSON could not be parsed")); diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index ed8e0f1f9f..abd38b2617 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -11,7 +11,9 @@ package org.opensearch.security.filter; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -24,7 +26,8 @@ public class OpenSearchRequestChannel extends OpenSearchRequest implements Secur private final Logger log = LogManager.getLogger(OpenSearchRequest.class); - private AtomicBoolean hasCompleted = new AtomicBoolean(false); + private final AtomicReference responseRef = new AtomicReference(null); + private final AtomicBoolean hasCompleted = new AtomicBoolean(false); private final RestChannel underlyingChannel; OpenSearchRequestChannel(final RestRequest request, final RestChannel channel) { @@ -32,22 +35,49 @@ public class OpenSearchRequestChannel extends OpenSearchRequest implements Secur underlyingChannel = channel; } + /** Gets access to the underlying channel object */ + public RestChannel breakEncapsulationForChannel() { + return underlyingChannel; + } + @Override - public boolean hasCompleted() { - return hasCompleted.get(); + public void queueForSending(final SecurityResponse response) { + if (underlyingChannel == null) { + throw new UnsupportedOperationException("Channel was not defined"); + } + + if (hasCompleted.get()) { + throw new UnsupportedOperationException("This channel has already completed"); + } + + if (getQueuedResponse().isPresent()) { + throw new UnsupportedOperationException("Another response was already queued"); + } + + responseRef.set(response); } @Override - public boolean completeWith(final SecurityResponse response) { + public Optional getQueuedResponse() { + return Optional.ofNullable(responseRef.get()); + } + @Override + public boolean sendResponse() { if (underlyingChannel == null) { throw new UnsupportedOperationException("Channel was not defined"); } - if (hasCompleted()) { + if (hasCompleted.get()) { throw new UnsupportedOperationException("This channel has already completed"); } + if (getQueuedResponse()) { + throw new UnsupportedOperationException("No response has been associated with this channel"); + } + + final SecurityResponse response = responseRef.get(); + try { final BytesRestResponse restResponse = new BytesRestResponse(RestStatus.fromCode(response.getStatus()), response.getBody()); if (response.getHeaders() != null) { @@ -62,15 +92,6 @@ public boolean completeWith(final SecurityResponse response) { } finally { hasCompleted.set(true); } - } - - /** Marks a request completed */ - public void markCompleted() { - hasCompleted.set(true); - } - /** Gets access to the underlying channel object */ - public RestChannel breakEncapsulationForChannel() { - return underlyingChannel; } } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java index a1e93c59fd..1eec754c08 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRequestChannel.java @@ -11,16 +11,19 @@ package org.opensearch.security.filter; +import java.util.Optional; + /** * When a request is recieved by the security plugin this governs getting information about the request and complete with with a response */ public interface SecurityRequestChannel extends SecurityRequest { - /** - * If this channel has been been used to send a response - */ - public boolean hasCompleted(); + /** Associate a response with this channel */ + public void queueForSending(final SecurityResponse response); + + /** Acess the queued response */ + public Optional getQueuedResponse(); - /** Use this channel to send a response */ - public boolean completeWith(final SecurityResponse response); + /** Send the response through the channel */ + public boolean sendResponse(); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityResponse.java b/src/main/java/org/opensearch/security/filter/SecurityResponse.java index 4bb8d41409..8618be3aab 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityResponse.java +++ b/src/main/java/org/opensearch/security/filter/SecurityResponse.java @@ -13,7 +13,12 @@ import java.util.Map; +import org.apache.http.HttpHeaders; + public class SecurityResponse { + + public static final Map CONTENT_TYPE_APP_JSON = Map.of(HttpHeaders.CONTENT_TYPE, "application/json"); + private final int status; private final Map headers; private final String body; diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 769bcb07e7..9826d8d4dd 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -145,9 +145,11 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { return; } - if (!(whitelistingSettings.checkRequestIsAllowed(request, channel, client) - && allowlistingSettings.checkRequestIsAllowed(request, channel, client))) { - // Request is not allowed + final Optional deniedResponse = whitelistingSettings.checkRequestIsAllowed(requestChannel) + .or(() -> allowlistingSettings.checkRequestIsAllowed(requestChannel)); + + if (deniedResponse.isPresent()) { + requestChannel.completeWith(deniedResponse.orElseThrow()); return; } diff --git a/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java b/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java index 98fc7a266a..ba249e8c63 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/AllowlistingSettings.java @@ -15,12 +15,13 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; -import org.opensearch.client.node.NodeClient; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; +import org.apache.http.HttpStatus; +import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.core.rest.RestStatus; +import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityResponse; public class AllowlistingSettings { private boolean enabled; @@ -75,7 +76,7 @@ public String toString() { * GET /_cluster/settings - OK * GET /_cluster/settings/ - OK */ - private boolean requestIsAllowlisted(RestRequest request) { + private boolean requestIsAllowlisted(final SecurityRequest request) { // ALSO ALLOWS REQUEST TO HAVE TRAILING '/' // pathWithoutTrailingSlash stores the endpoint path without extra '/'. eg: /_cat/nodes @@ -107,21 +108,30 @@ private boolean requestIsAllowlisted(RestRequest request) { * then all PUT /_opendistro/_security/api/rolesmapping/{resource_name} work. * Currently, each resource_name has to be allowlisted separately */ - public boolean checkRequestIsAllowed(RestRequest request, RestChannel channel, NodeClient client) throws IOException { + public Optional checkRequestIsAllowed(final SecurityRequest request) { // if allowlisting is enabled but the request is not allowlisted, then return false, otherwise true. if (this.enabled && !requestIsAllowlisted(request)) { - channel.sendResponse( - new BytesRestResponse( - RestStatus.FORBIDDEN, - channel.newErrorBuilder() - .startObject() - .field("error", request.method() + " " + request.path() + " API not allowlisted") - .field("status", RestStatus.FORBIDDEN) - .endObject() - ) + return Optional.of( + new SecurityResponse(HttpStatus.SC_FORBIDDEN, SecurityResponse.CONTENT_TYPE_APP_JSON, generateFailureMessage(request)) ); - return false; } - return true; + return Optional.empty(); + } + + protected String getVerb() { + return "allowlisted"; + } + + protected String generateFailureMessage(final SecurityRequest request) { + try { + return XContentFactory.jsonBuilder() + .startObject() + .field("error", request.method() + " " + request.path() + " API not " + getVerb()) + .field("status", RestStatus.FORBIDDEN) + .endObject() + .toString(); + } catch (final IOException ioe) { + throw new RuntimeException(ioe); + } } } diff --git a/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java b/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java index 4462bae90f..2e1ab791d2 100644 --- a/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java +++ b/src/main/java/org/opensearch/security/securityconf/impl/WhitelistingSettings.java @@ -11,16 +11,14 @@ package org.opensearch.security.securityconf.impl; -import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; -import org.opensearch.client.node.NodeClient; -import org.opensearch.rest.BytesRestResponse; -import org.opensearch.rest.RestChannel; -import org.opensearch.rest.RestRequest; -import org.opensearch.core.rest.RestStatus; +import org.apache.http.HttpStatus; +import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.filter.SecurityResponse; public class WhitelistingSettings extends AllowlistingSettings { private boolean enabled; @@ -75,7 +73,7 @@ public String toString() { * GET /_cluster/settings - OK * GET /_cluster/settings/ - OK */ - private boolean requestIsWhitelisted(RestRequest request) { + private boolean requestIsWhitelisted(final SecurityRequest request) { // ALSO ALLOWS REQUEST TO HAVE TRAILING '/' // pathWithoutTrailingSlash stores the endpoint path without extra '/'. eg: /_cat/nodes @@ -108,21 +106,17 @@ private boolean requestIsWhitelisted(RestRequest request) { * Currently, each resource_name has to be whitelisted separately */ @Override - public boolean checkRequestIsAllowed(RestRequest request, RestChannel channel, NodeClient client) throws IOException { + public Optional checkRequestIsAllowed(final SecurityRequest request) { // if whitelisting is enabled but the request is not whitelisted, then return false, otherwise true. if (this.enabled && !requestIsWhitelisted(request)) { - channel.sendResponse( - new BytesRestResponse( - RestStatus.FORBIDDEN, - channel.newErrorBuilder() - .startObject() - .field("error", request.method() + " " + request.path() + " API not whitelisted") - .field("status", RestStatus.FORBIDDEN) - .endObject() - ) + return Optional.of( + new SecurityResponse(HttpStatus.SC_FORBIDDEN, SecurityResponse.CONTENT_TYPE_APP_JSON, generateFailureMessage(request)) ); - return false; } - return true; + return Optional.empty(); + } + + protected String getVerb() { + return "whitelisted"; } } From 87013596e0bbcb01d59195a6501fcaaef12115cf Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Thu, 5 Oct 2023 21:56:20 +0000 Subject: [PATCH 49/50] switch from complete to queue requests Signed-off-by: Peter Nied --- .../security/auth/BackendRegistry.java | 12 ++++++------ .../filter/OpenSearchRequestChannel.java | 2 +- .../security/filter/SecurityRestFilter.java | 19 ++++++++++--------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 2a0a921883..88e88c3c52 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -201,7 +201,7 @@ public boolean authenticate(final SecurityRequestChannel request) { log.debug("Rejecting REST request because of blocked address: {}", request.getRemoteAddress().orElse(null)); } - request.completeWith(new SecurityResponse(SC_UNAUTHORIZED, null, "Authentication finally failed")); + request.queueForSending(new SecurityResponse(SC_UNAUTHORIZED, null, "Authentication finally failed")); return false; } @@ -221,7 +221,7 @@ public boolean authenticate(final SecurityRequestChannel request) { if (!isInitialized()) { log.error("Not yet initialized (you may need to run securityadmin)"); - request.completeWith(new SecurityResponse(SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized.")); + request.queueForSending(new SecurityResponse(SC_SERVICE_UNAVAILABLE, null, "OpenSearch Security not initialized.")); return false; } @@ -295,7 +295,7 @@ public boolean authenticate(final SecurityRequestChannel request) { log.trace("No 'Authorization' header, send 401 and 'WWW-Authenticate Basic'"); } notifyIpAuthFailureListeners(request, authCredentials); - request.completeWith(restResponse.get()); + request.queueForSending(restResponse.get()); return false; } } else { @@ -312,7 +312,7 @@ public boolean authenticate(final SecurityRequestChannel request) { final Optional restResponse = httpAuthenticator.reRequestAuthentication(request, ac); if (restResponse.isPresent()) { notifyIpAuthFailureListeners(request, ac); - request.completeWith(restResponse.get()); + request.queueForSending(restResponse.get()); return false; } else { // no reRequest possible @@ -350,7 +350,7 @@ public boolean authenticate(final SecurityRequestChannel request) { if (adminDns.isAdmin(authenticatedUser)) { log.error("Cannot authenticate rest user because admin user is not permitted to login via HTTP"); auditLog.logFailedLogin(authenticatedUser.getName(), true, null, request); - request.completeWith( + request.queueForSending( new SecurityResponse( SC_FORBIDDEN, null, @@ -425,7 +425,7 @@ public boolean authenticate(final SecurityRequestChannel request) { notifyIpAuthFailureListeners(request, authCredentials); - request.completeWith( + request.queueForSending( challengeResponse.orElseGet(() -> new SecurityResponse(SC_UNAUTHORIZED, null, "Authentication finally failed")) ); return false; diff --git a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java index abd38b2617..45035e0d83 100644 --- a/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java +++ b/src/main/java/org/opensearch/security/filter/OpenSearchRequestChannel.java @@ -72,7 +72,7 @@ public boolean sendResponse() { throw new UnsupportedOperationException("This channel has already completed"); } - if (getQueuedResponse()) { + if (getQueuedResponse().isEmpty()) { throw new UnsupportedOperationException("No response has been associated with this channel"); } diff --git a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java index 9826d8d4dd..ce80a9e143 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityRestFilter.java @@ -132,8 +132,8 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { // Authenticate request checkAndAuthenticateRequest(requestChannel); - if (requestChannel.hasCompleted()) { - // Unable to authenticate the caller + if (requestChannel.getQueuedResponse().isPresent()) { + requestChannel.sendResponse(); return; } @@ -149,13 +149,14 @@ public RestHandler wrap(RestHandler original, AdminDNs adminDNs) { .or(() -> allowlistingSettings.checkRequestIsAllowed(requestChannel)); if (deniedResponse.isPresent()) { - requestChannel.completeWith(deniedResponse.orElseThrow()); + requestChannel.queueForSending(deniedResponse.orElseThrow()); + requestChannel.sendResponse(); return; } authorizeRequest(original, requestChannel, user); - if (requestChannel.hasCompleted()) { - // Caller was not authorized + if (requestChannel.getQueuedResponse().isPresent()) { + requestChannel.sendResponse(); return; } @@ -209,7 +210,7 @@ private void authorizeRequest(RestHandler original, SecurityRequestChannel reque } log.debug(err); - request.completeWith(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, err)); + request.queueForSending(new SecurityResponse(HttpStatus.SC_UNAUTHORIZED, null, err)); return; } } @@ -223,7 +224,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); - requestChannel.completeWith(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); + requestChannel.queueForSending(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); return; } @@ -232,7 +233,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t log.error(exception.toString()); auditLog.logBadHeaders(requestChannel); - requestChannel.completeWith(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); + requestChannel.queueForSending(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, exception.toString())); return; } @@ -252,7 +253,7 @@ public void checkAndAuthenticateRequest(SecurityRequestChannel requestChannel) t } catch (SSLPeerUnverifiedException e) { log.error("No ssl info", e); auditLog.logSSLException(requestChannel, e); - requestChannel.completeWith(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, null)); + requestChannel.queueForSending(new SecurityResponse(HttpStatus.SC_FORBIDDEN, null, null)); return; } From e7b09164d8371f001bbc125064118ff1e1b346c9 Mon Sep 17 00:00:00 2001 From: Peter Nied Date: Thu, 5 Oct 2023 22:24:07 +0000 Subject: [PATCH 50/50] Fix checkstyle issue Signed-off-by: Peter Nied --- .../security/ssl/transport/SecuritySSLNettyTransport.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLNettyTransport.java b/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLNettyTransport.java index 12f70b9978..7aeebdaf9f 100644 --- a/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLNettyTransport.java +++ b/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLNettyTransport.java @@ -64,7 +64,6 @@ import org.opensearch.transport.SharedGroupFactory; import org.opensearch.transport.TcpChannel; import org.opensearch.transport.netty4.Netty4Transport; -import org.opensearch.telemetry.tracing.Tracer; public class SecuritySSLNettyTransport extends Netty4Transport {