Skip to content

Commit

Permalink
♻️ Refactor ACLRegistry to use Predicate<Request<?>>
Browse files Browse the repository at this point in the history
  • Loading branch information
ujibang committed Apr 18, 2024
1 parent b4fa8c2 commit 6850303
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 36 deletions.
10 changes: 6 additions & 4 deletions commons/src/main/java/org/restheart/security/ACLRegistry.java
Expand Up @@ -19,7 +19,9 @@
*/
package org.restheart.security;

import io.undertow.predicate.Predicate;
import java.util.function.Predicate;

import org.restheart.exchange.Request;

/**
* Registry for defining Access Control Lists (ACLs) programmatically.
Expand Down Expand Up @@ -57,7 +59,7 @@ public interface ACLRegistry {
* @param veto The veto predicate to register. This predicate should return true to veto (deny) the request,
* and false to let the decision be further evaluated by allow predicates or other authorizers.
*/
public void registerVeto(Predicate veto);
public void registerVeto(Predicate<Request<?>> veto);

/**
* Registers an allow predicate that determines if a request should be authorized.
Expand All @@ -68,7 +70,7 @@ public interface ACLRegistry {
* @param allow The allow predicate to register. This predicate should return true to authorize the request,
* unless it is vetoed by any veto predicates or other vetoing conditions.
*/
public void registerAllow(Predicate allow);
public void registerAllow(Predicate<Request<?>> allow);

/**
* Registers a predicate that determines whether requests handled by the ACLRegistryAllower
Expand All @@ -81,6 +83,6 @@ public interface ACLRegistry {
* It should return true if the request must be authenticated,
* otherwise false if unauthenticated requests might be allowed.
*/
public void registerAuthenticationRequirement(Predicate authenticationRequired);
public void registerAuthenticationRequirement(Predicate<Request<?>> authenticationRequired);

}
Expand Up @@ -23,11 +23,11 @@
import java.util.function.Predicate;

import org.restheart.exchange.Request;
import io.undertow.util.AttachmentKey;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.undertow.util.AttachmentKey;

/**
* ACL Permission that specifies the conditions that are necessary to perform
* the request
Expand Down Expand Up @@ -56,7 +56,7 @@ public BaseAclPermission(Predicate<Request<?>> predicate, Set<String> roles, int

/**
*
* @param exchange
* @param request
* @return the acl predicate associated with this request
*/
public static BaseAclPermission of(Request<?> request) {
Expand Down Expand Up @@ -120,6 +120,7 @@ public Object getRaw() {

/**
*
* @param request
* @return the raw permission data bound to the request
*/
public static Object getRaw(Request<?> request) {
Expand Down
Expand Up @@ -26,7 +26,6 @@
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.restheart.exchange.MongoRequest;
import org.restheart.exchange.Request;
import org.restheart.plugins.Initializer;
import org.restheart.plugins.Inject;
import org.restheart.plugins.OnInit;
Expand Down Expand Up @@ -59,10 +58,8 @@ public void onInit() {

@Override
public void init() {
this.registry.registerVeto(exchange -> {
var request = Request.of(exchange);

if (request instanceof MongoRequest mreq) {
this.registry.registerVeto(req -> {
if (req instanceof MongoRequest mreq) {
return contains(mreq.getFiltersDocument(), blacklist);
} else {
return false; // don't veto
Expand Down
Expand Up @@ -41,7 +41,7 @@ public class ACLRegistryAllower implements Authorizer {
public boolean isAllowed(Request<?> request) {
var allowPredicate = registry.allowPredicates()
.stream()
.filter(predicate -> predicate.resolve(request.getExchange()))
.filter(predicate -> predicate.test(request))
.findFirst();

LOGGER.debug("request authorized by ACLRegistryAllower? {}", allowPredicate.isPresent());
Expand All @@ -54,6 +54,6 @@ public boolean isAuthenticationRequired(Request<?> request) {
return registry.authenticationRequirements().isEmpty() ||
registry.authenticationRequirements()
.stream()
.allMatch(predicate -> predicate.resolve(request.getExchange()));
.allMatch(predicate -> predicate.test(request));
}
}
Expand Up @@ -22,17 +22,17 @@

import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.Predicate;

import org.restheart.exchange.Request;
import org.restheart.security.ACLRegistry;

import io.undertow.predicate.Predicate;

public class ACLRegistryImpl implements ACLRegistry {
private static final ACLRegistryImpl HOLDER = new ACLRegistryImpl();

private final Set<Predicate> vetoPredicates;
private final Set<Predicate> allowPredicates;
private final Set<Predicate> authenticationRequirements;
private final Set<Predicate<Request<?>>> vetoPredicates;
private final Set<Predicate<Request<?>>> allowPredicates;
private final Set<Predicate<Request<?>>> authenticationRequirements;

private ACLRegistryImpl() {
vetoPredicates = new LinkedHashSet<>();
Expand All @@ -54,7 +54,7 @@ static ACLRegistryImpl getInstance() {
* and false to let the decision be further evaluated by allow predicates or other authorizers.
*/
@Override
public void registerVeto(Predicate veto) {
public void registerVeto(Predicate<Request<?>> veto) {
this.vetoPredicates.add(veto);
}

Expand All @@ -68,7 +68,7 @@ public void registerVeto(Predicate veto) {
* unless it is vetoed by any veto predicates or other vetoing conditions.
*/
@Override
public void registerAllow(Predicate allow) {
public void registerAllow(Predicate<Request<?>> allow) {
this.allowPredicates.add(allow);
}

Expand All @@ -84,21 +84,19 @@ public void registerAllow(Predicate allow) {
* otherwise false if unauthenticated requests might be allowed.
*/
@Override
public void registerAuthenticationRequirement(Predicate authenticationRequired) {
public void registerAuthenticationRequirement(Predicate<Request<?>> authenticationRequired) {
this.authenticationRequirements.add(authenticationRequired);
}

Set<Predicate> vetoPredicates() {
Set<Predicate<Request<?>>> vetoPredicates() {
return vetoPredicates;
}

Set<Predicate> allowPredicates() {
Set<Predicate<Request<?>>> allowPredicates() {
return allowPredicates;
}

Set<Predicate> authenticationRequirements() {
Set<Predicate<Request<?>>> authenticationRequirements() {
return authenticationRequirements;
}

//Predicate<Request<?>>
}
Expand Up @@ -37,7 +37,7 @@ public class ACLRegistryVetoer implements Authorizer {
public boolean isAllowed(Request<?> request) {
return registry.vetoPredicates()
.stream()
.allMatch(predicate -> !predicate.resolve(request.getExchange()));
.allMatch(predicate -> !predicate.test(request));
}

@Override
Expand Down
Expand Up @@ -65,13 +65,10 @@ public void init() {
this.myURI = URLUtils.removeTrailingSlashes(argOrDefault(config, "uri", "/roles"));

// authorize request if authenticated and path is /roles/{username}
aclRegistry.registerAllow(e -> e.getSecurityContext().getAuthenticatedAccount() != null && e.getRequestPath().equals(myURI + "/" + e.getSecurityContext().getAuthenticatedAccount().getPrincipal().getName()));
aclRegistry.registerAllow(req -> req.isAuthenticated()&& req.getPath().equals(myURI + "/" + req.getAuthenticatedAccount().getPrincipal().getName()));

// if the request is authorized by any other authenticator (eg root role of MongoRealmAuthenticator), veto it anyway if not requesting own role
aclRegistry.registerVeto(e ->
e.getRequestPath().startsWith(myURI)
&& (e.getSecurityContext().getAuthenticatedAccount() == null
|| !e.getRequestPath().equals(myURI + "/" + e.getSecurityContext().getAuthenticatedAccount().getPrincipal().getName())));
aclRegistry.registerVeto(req -> req.getPath().startsWith(myURI) && (!req.isAuthenticated() || !req.getPath().equals(myURI + "/" + req.getAuthenticatedAccount().getPrincipal().getName())));
}

/**
Expand Down
Expand Up @@ -59,9 +59,12 @@ public void init() {
LOGGER.info("\tadds a request and a response interceptors for /iecho and /siecho");

// add a global security predicate
this.registry.registerVeto(exchange -> {
var request = JsonProxyRequest.of(exchange);
return (request.isGet() && "/secho/foo".equals(removeTrailingSlashes(request.getPath())));
this.registry.registerVeto(req -> {
if (req instanceof JsonProxyRequest jreq) {
return (jreq.isGet() && "/secho/foo".equals(removeTrailingSlashes(jreq.getPath())));
} else {
return false; // don't veto
}
});
}
}

0 comments on commit 6850303

Please sign in to comment.