From 23bd40853f865941361f9d3712a4883f6940c7cc Mon Sep 17 00:00:00 2001 From: Andrea Di Cesare Date: Thu, 4 Nov 2021 17:41:56 +0100 Subject: [PATCH] :sparkles: Authorizers are executed on secured services even if no Authenticator is enabled --- .../java/org/restheart/utils/PluginUtils.java | 18 ++++- .../AuthenticationConstraintHandler.java | 11 ++- .../AuthenticatorMechanismsHandler.java | 4 +- .../security/handlers/SecurityHandler.java | 68 +++++++++---------- .../handlers/SecurityInitialHandler.java | 15 ++-- .../mechanisms/IdentityAuthMechanism.java | 12 ++-- .../JwtAuthenticationMechanism.java | 6 +- 7 files changed, 70 insertions(+), 64 deletions(-) diff --git a/commons/src/main/java/org/restheart/utils/PluginUtils.java b/commons/src/main/java/org/restheart/utils/PluginUtils.java index d521f7ecab..e3363fdcc7 100644 --- a/commons/src/main/java/org/restheart/utils/PluginUtils.java +++ b/commons/src/main/java/org/restheart/utils/PluginUtils.java @@ -34,6 +34,7 @@ import org.restheart.plugins.InterceptPoint; import org.restheart.plugins.Interceptor; import org.restheart.plugins.Plugin; +import org.restheart.plugins.PluginRecord; import org.restheart.plugins.PluginsRegistry; import org.restheart.plugins.RegisterPlugin; import org.restheart.plugins.Service; @@ -261,14 +262,27 @@ public static Authorizer.TYPE authorizerType(Authorizer authorizer) { */ @SuppressWarnings("rawtypes") public static Service handlingService(PluginsRegistry registry, HttpServerExchange exchange) { + var pr = handlingServicePluginRecord(registry, exchange); + + return pr == null ? null : pr.getInstance(); + } + + /** + * + * @param registry + * @param exchange + * @return the plugin record of the service handling the exchange or null if the request is not + * handled by a service + */ + @SuppressWarnings("rawtypes") + public static PluginRecord handlingServicePluginRecord(PluginsRegistry registry, HttpServerExchange exchange) { var pi = Request.of(exchange).getPipelineInfo(); if (pi != null && pi.getType() == SERVICE) { var srvName = pi.getName(); if (srvName != null) { - var _s = registry.getServices().stream().filter(s -> srvName.equals(s.getName())) - .map(s -> s.getInstance()).findAny(); + var _s = registry.getServices().stream().filter(s -> srvName.equals(s.getName())).findAny(); if (_s.isPresent()) { return _s.get(); diff --git a/core/src/main/java/org/restheart/security/handlers/AuthenticationConstraintHandler.java b/core/src/main/java/org/restheart/security/handlers/AuthenticationConstraintHandler.java index a02a3918f5..691bbeb65a 100644 --- a/core/src/main/java/org/restheart/security/handlers/AuthenticationConstraintHandler.java +++ b/core/src/main/java/org/restheart/security/handlers/AuthenticationConstraintHandler.java @@ -20,12 +20,13 @@ */ package org.restheart.security.handlers; -import io.undertow.security.api.SecurityContext; import io.undertow.server.HttpServerExchange; import java.util.Set; + import org.restheart.exchange.Request; import org.restheart.handlers.PipelinedHandler; import org.restheart.plugins.PluginRecord; +import org.restheart.plugins.PluginsRegistryImpl; import org.restheart.plugins.security.Authorizer; import org.restheart.plugins.security.Authorizer.TYPE; import org.restheart.utils.PluginUtils; @@ -68,10 +69,16 @@ protected boolean isAuthenticationRequired(final HttpServerExchange exchange) { @Override public void handleRequest(HttpServerExchange exchange) throws Exception { if (isAuthenticationRequired(exchange)) { - SecurityContext scontext = exchange.getSecurityContext(); + var scontext = exchange.getSecurityContext(); scontext.setAuthenticationRequired(); } next(exchange); } + + private boolean isAuthorizationRequired(HttpServerExchange exchange) { + var hs = PluginUtils.handlingServicePluginRecord(PluginsRegistryImpl.getInstance(), exchange); + + return hs != null && hs.isSecure(); + } } diff --git a/core/src/main/java/org/restheart/security/handlers/AuthenticatorMechanismsHandler.java b/core/src/main/java/org/restheart/security/handlers/AuthenticatorMechanismsHandler.java index 4a6e8a0f56..527c4e60d6 100644 --- a/core/src/main/java/org/restheart/security/handlers/AuthenticatorMechanismsHandler.java +++ b/core/src/main/java/org/restheart/security/handlers/AuthenticatorMechanismsHandler.java @@ -52,9 +52,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { final var sc = exchange.getSecurityContext(); if (sc != null) { - authenticatorMechanisms.stream().forEachOrdered((mechanism) -> { - sc.addAuthenticationMechanism(new AuthenticatorMechanismWrapper(mechanism.getInstance())); - }); + authenticatorMechanisms.stream().forEachOrdered(mechanism -> sc.addAuthenticationMechanism(new AuthenticatorMechanismWrapper(mechanism.getInstance()))); } next(exchange); diff --git a/core/src/main/java/org/restheart/security/handlers/SecurityHandler.java b/core/src/main/java/org/restheart/security/handlers/SecurityHandler.java index e8167e775c..457f195271 100644 --- a/core/src/main/java/org/restheart/security/handlers/SecurityHandler.java +++ b/core/src/main/java/org/restheart/security/handlers/SecurityHandler.java @@ -35,40 +35,6 @@ * @author Andrea Di Cesare {@literal } */ public class SecurityHandler extends PipelinedHandler { - - private static PipelinedHandler buildSecurityHandlersChain( - PipelinedHandler next, - final Set> mechanisms, - final Set> authorizers, - final PluginRecord tokenManager) { - if (mechanisms != null && mechanisms.size() > 0) { - PipelinedHandler handler; - - if (authorizers == null || authorizers.isEmpty()) { - throw new IllegalArgumentException("Error, authorizers cannot " - + "be null or empty. " - + "Eventually use FullAuthorizer " - + "that gives full access power"); - } - - handler = new TokenInjector( - new AuthorizersHandler(authorizers, next), - tokenManager != null - ? tokenManager.getInstance() - : null); - - handler = new SecurityInitialHandler( - AuthenticationMode.PRO_ACTIVE, - new AuthenticatorMechanismsHandler( - new AuthenticationConstraintHandler(new AuthenticationCallHandler(handler), authorizers), - mechanisms)); - - return handler; - } else { - return next; - } - } - private final Set> mechanisms; private final Set> authorizers; private final PluginRecord tokenManager; @@ -96,4 +62,38 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { protected void setNext(PipelinedHandler next) { super.setNext(buildSecurityHandlersChain(next, mechanisms, authorizers, tokenManager)); } + + private static PipelinedHandler buildSecurityHandlersChain( + PipelinedHandler next, + final Set> mechanisms, + final Set> authorizers, + final PluginRecord tokenManager) { + if (authorizers == null || authorizers.isEmpty()) { + throw new IllegalArgumentException("Error, authorizers cannot " + + "be null or empty. " + + "Eventually use FullAuthorizer " + + "that gives full access power"); + } + + if (mechanisms != null && mechanisms.size() > 0) { + return new SecurityInitialHandler(AuthenticationMode.PRO_ACTIVE, + new AuthenticatorMechanismsHandler( + new AuthenticationConstraintHandler( + new AuthenticationCallHandler( + new TokenInjector( + new AuthorizersHandler(authorizers, next), + tokenManager != null ? tokenManager.getInstance() : null)), + authorizers), + mechanisms)); + + } else if (authorizers != null && authorizers.size() > 0) { + // if no authentication mechanism is enabled and at least one authorizer is defined + // just pipe the autorizers + // this will make the request to be authorized without any authentication mechanism + // see https://github.com/SoftInstigate/restheart/discussions/417 + return new SecurityInitialHandler(AuthenticationMode.PRO_ACTIVE, new AuthorizersHandler(authorizers, next)); + } else { + return next; + } + } } diff --git a/core/src/main/java/org/restheart/security/handlers/SecurityInitialHandler.java b/core/src/main/java/org/restheart/security/handlers/SecurityInitialHandler.java index 406fd4a75d..60a68c6005 100644 --- a/core/src/main/java/org/restheart/security/handlers/SecurityInitialHandler.java +++ b/core/src/main/java/org/restheart/security/handlers/SecurityInitialHandler.java @@ -44,8 +44,7 @@ */ public class SecurityInitialHandler extends PipelinedHandler { - static void setSecurityContext(final HttpServerExchange exchange, - final SecurityContext securityContext) { + static void setSecurityContext(final HttpServerExchange exchange, final SecurityContext securityContext) { if (System.getSecurityManager() == null) { exchange.setSecurityContext(securityContext); } else { @@ -80,19 +79,13 @@ public SecurityInitialHandler(final AuthenticationMode authenticationMode, next); } - public SecurityInitialHandler(final AuthenticationMode authenticationMode, - final PipelinedHandler next) { - this(authenticationMode, - null, - (SecurityContextFactoryImpl) SecurityContextFactoryImpl.INSTANCE, - next); + public SecurityInitialHandler(final AuthenticationMode authenticationMode, final PipelinedHandler next) { + this(authenticationMode, null, (SecurityContextFactoryImpl) SecurityContextFactoryImpl.INSTANCE, next); } @Override public void handleRequest(HttpServerExchange exchange) throws Exception { - SecurityContext newContext = this.contextFactory - .createSecurityContext(exchange, authenticationMode, null, - programaticMechName); + var newContext = this.contextFactory.createSecurityContext(exchange, authenticationMode, null, programaticMechName); setSecurityContext(exchange, newContext); next(exchange); diff --git a/security/src/main/java/org/restheart/security/mechanisms/IdentityAuthMechanism.java b/security/src/main/java/org/restheart/security/mechanisms/IdentityAuthMechanism.java index d7484a680b..0f43da26b8 100644 --- a/security/src/main/java/org/restheart/security/mechanisms/IdentityAuthMechanism.java +++ b/security/src/main/java/org/restheart/security/mechanisms/IdentityAuthMechanism.java @@ -23,7 +23,6 @@ import com.google.common.collect.Sets; import io.undertow.security.api.AuthenticationMechanism; import io.undertow.security.api.SecurityContext; -import io.undertow.security.idm.Account; import io.undertow.server.HttpServerExchange; import java.util.List; import java.util.Map; @@ -54,24 +53,21 @@ public class IdentityAuthMechanism implements AuthMechanism { private List roles; @InjectConfiguration - public void init(Map confArgs) - throws ConfigurationException { + public void init(Map confArgs) throws ConfigurationException { this.username = argValue(confArgs, "username"); this.roles = argValue(confArgs, "roles"); } @Override - public AuthenticationMechanism.AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange, - SecurityContext securityContext) { - Account sa = new BaseAccount(username, Sets.newTreeSet(roles)); + public AuthenticationMechanism.AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange, SecurityContext securityContext) { + var sa = new BaseAccount(username, Sets.newTreeSet(roles)); securityContext.authenticationComplete(sa, "IdentityAuthenticationManager", true); return AuthenticationMechanism.AuthenticationMechanismOutcome.AUTHENTICATED; } @Override - public AuthenticationMechanism.ChallengeResult sendChallenge(HttpServerExchange exchange, - SecurityContext securityContext) { + public AuthenticationMechanism.ChallengeResult sendChallenge(HttpServerExchange exchange, SecurityContext securityContext) { return new AuthenticationMechanism.ChallengeResult(true, 200); } } diff --git a/security/src/main/java/org/restheart/security/mechanisms/JwtAuthenticationMechanism.java b/security/src/main/java/org/restheart/security/mechanisms/JwtAuthenticationMechanism.java index f9c6a35105..f2e465c582 100644 --- a/security/src/main/java/org/restheart/security/mechanisms/JwtAuthenticationMechanism.java +++ b/security/src/main/java/org/restheart/security/mechanisms/JwtAuthenticationMechanism.java @@ -192,8 +192,7 @@ public void init(Map args) throws ConfigurationException { jwtPayload ); - sc.authenticationComplete(account, - "JwtAuthenticationManager", false); + sc.authenticationComplete(account, "JwtAuthenticationManager", false); Request.of(hse).addXForwardedHeader("Jwt-Payload", jwtPayload); @@ -209,8 +208,7 @@ public void init(Map args) throws ConfigurationException { } @Override - public ChallengeResult sendChallenge(final HttpServerExchange exchange, - final SecurityContext securityContext) { + public ChallengeResult sendChallenge(final HttpServerExchange exchange, final SecurityContext securityContext) { return new AuthenticationMechanism.ChallengeResult(true, 200); }