Skip to content

Commit

Permalink
✨ Authorizers are executed on secured services even if no Authenticat…
Browse files Browse the repository at this point in the history
…or is enabled
  • Loading branch information
ujibang committed Nov 4, 2021
1 parent 9792221 commit 23bd408
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 64 deletions.
18 changes: 16 additions & 2 deletions commons/src/main/java/org/restheart/utils/PluginUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Service> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,40 +35,6 @@
* @author Andrea Di Cesare {@literal <andrea@softinstigate.com>}
*/
public class SecurityHandler extends PipelinedHandler {

private static PipelinedHandler buildSecurityHandlersChain(
PipelinedHandler next,
final Set<PluginRecord<AuthMechanism>> mechanisms,
final Set<PluginRecord<Authorizer>> authorizers,
final PluginRecord<TokenManager> 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<PluginRecord<AuthMechanism>> mechanisms;
private final Set<PluginRecord<Authorizer>> authorizers;
private final PluginRecord<TokenManager> tokenManager;
Expand Down Expand Up @@ -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<PluginRecord<AuthMechanism>> mechanisms,
final Set<PluginRecord<Authorizer>> authorizers,
final PluginRecord<TokenManager> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -54,24 +53,21 @@ public class IdentityAuthMechanism implements AuthMechanism {
private List<String> roles;

@InjectConfiguration
public void init(Map<String, Object> confArgs)
throws ConfigurationException {
public void init(Map<String, Object> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,7 @@ public void init(Map<String, Object> args) throws ConfigurationException {
jwtPayload
);

sc.authenticationComplete(account,
"JwtAuthenticationManager", false);
sc.authenticationComplete(account, "JwtAuthenticationManager", false);

Request.of(hse).addXForwardedHeader("Jwt-Payload", jwtPayload);

Expand All @@ -209,8 +208,7 @@ public void init(Map<String, Object> 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);
}

Expand Down

0 comments on commit 23bd408

Please sign in to comment.