Skip to content

Commit

Permalink
[UNDERTOW-1737] add failure-reason to AccessControlListHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
baranowb committed Nov 25, 2022
1 parent d24d91f commit 0ce2bb0
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
12 changes: 12 additions & 0 deletions core/src/main/java/io/undertow/Handlers.java
Expand Up @@ -331,6 +331,18 @@ public static final AccessControlListHandler acl(final HttpHandler next, boolean
return new AccessControlListHandler(next, attribute).setDefaultAllow(defaultAllow);
}

/**
* Returns a new handler that can allow or deny access to a resource based an at attribute of the exchange
*
* @param next The next handler in the chain
* @param defaultAllow Determine if a non-matching user agent will be allowed by default
* @param denyResponseCode response code that will be sent back from 400 range
* @return A new user agent access control handler
*/
public static final AccessControlListHandler acl(final HttpHandler next, boolean defaultAllow, ExchangeAttribute attribute, final int denyResponseCode) {
return new AccessControlListHandler(next, attribute, denyResponseCode).setDefaultAllow(defaultAllow);
}

/**
* A handler that automatically handles HTTP 100-continue responses, by sending a continue
* response when the first attempt is made to read from the request channel.
Expand Down
Expand Up @@ -49,15 +49,42 @@ public class AccessControlListHandler implements HttpHandler {
private volatile boolean defaultAllow = false;
private final ExchangeAttribute attribute;
private final List<AclMatch> acl = new CopyOnWriteArrayList<>();
private final int denyResponseCode;

public AccessControlListHandler(final HttpHandler next, ExchangeAttribute attribute) {
this.next = next;
this.attribute = attribute;
this.denyResponseCode = StatusCodes.FORBIDDEN;
}

public AccessControlListHandler(ExchangeAttribute attribute) {
this.attribute = attribute;
this.next = ResponseCodeHandler.HANDLE_404;
this.denyResponseCode = StatusCodes.FORBIDDEN;
}

public AccessControlListHandler(final HttpHandler next, ExchangeAttribute attribute, final int denyResponseCode) {
this.next = next;
this.attribute = attribute;
if(denyResponseCode == -1) {
this.denyResponseCode = StatusCodes.FORBIDDEN;
} else {
assert denyResponseCode > 399;
assert denyResponseCode < 500;
this.denyResponseCode = denyResponseCode;
}
}

public AccessControlListHandler(ExchangeAttribute attribute, final int denyResponseCode) {
this.attribute = attribute;
this.next = ResponseCodeHandler.HANDLE_404;
if(denyResponseCode == -1) {
this.denyResponseCode = StatusCodes.FORBIDDEN;
} else {
assert denyResponseCode > 399;
assert denyResponseCode < 500;
this.denyResponseCode = denyResponseCode;
}
}

@Override
Expand All @@ -66,7 +93,7 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception {
if (isAllowed(attribute)) {
next.handleRequest(exchange);
} else {
exchange.setStatusCode(StatusCodes.FORBIDDEN);
exchange.setStatusCode(this.denyResponseCode);
exchange.endExchange();
}
}
Expand Down Expand Up @@ -182,6 +209,7 @@ public Map<String, Class<?>> parameters() {
params.put("acl", String[].class);
params.put("default-allow", boolean.class);
params.put("attribute", ExchangeAttribute.class);
params.put("failure-status", int.class);
return params;
}

Expand Down Expand Up @@ -219,7 +247,12 @@ public HandlerWrapper build(Map<String, Object> config) {
throw UndertowMessages.MESSAGES.invalidAclRule(rule);
}
}
return new Wrapper(peerMatches, defaultAllow == null ? false : defaultAllow, attribute);
Integer failureStatus = (Integer) config.get("failure-status");
if(failureStatus == null) {
return new Wrapper(peerMatches, defaultAllow == null ? false : defaultAllow, attribute);
} else {
return new Wrapper(peerMatches, defaultAllow == null ? false : defaultAllow, attribute, failureStatus.intValue());
}
}

}
Expand All @@ -229,18 +262,25 @@ private static class Wrapper implements HandlerWrapper {
private final List<AclMatch> peerMatches;
private final boolean defaultAllow;
private final ExchangeAttribute attribute;

private final int denyResponseCode;

private Wrapper(List<AclMatch> peerMatches, boolean defaultAllow, ExchangeAttribute attribute) {
this.peerMatches = peerMatches;
this.defaultAllow = defaultAllow;
this.attribute = attribute;
this.denyResponseCode = -1;
}

private Wrapper(List<AclMatch> peerMatches, boolean defaultAllow, ExchangeAttribute attribute, final int denyResponseCode) {
this.peerMatches = peerMatches;
this.defaultAllow = defaultAllow;
this.attribute = attribute;
this.denyResponseCode = denyResponseCode;
}

@Override
public HttpHandler wrap(HttpHandler handler) {
AccessControlListHandler res = new AccessControlListHandler(handler, attribute);
AccessControlListHandler res = new AccessControlListHandler(handler, attribute, denyResponseCode);
for(AclMatch match: peerMatches) {
if(match.deny) {
res.addDeny(match.pattern.pattern());
Expand Down
Expand Up @@ -17,7 +17,12 @@
*/
package io.undertow.server.handlers;

import static org.easymock.EasyMock.*;

import io.undertow.server.HttpServerExchange;
import io.undertow.testutils.category.UnitTest;
import io.undertow.util.HeaderMap;

import org.junit.Test;
import org.junit.experimental.categories.Category;

Expand Down

0 comments on commit 0ce2bb0

Please sign in to comment.