Skip to content

Add support for allowedHostnames in StrictHttpFirewall #7158

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,15 @@ public String getQueryString() {
public void setQueryString(String queryString) {
this.queryString = queryString;
}

@Override
public String getServerName() {
return null;
}
}

final class UnsupportedOperationExceptionInvocationHandler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
throw new UnsupportedOperationException(method + " is not supported");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,6 +26,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

/**
* <p>
Expand Down Expand Up @@ -66,10 +67,15 @@
* Rejects URLs that contain a URL encoded percent. See
* {@link #setAllowUrlEncodedPercent(boolean)}
* </li>
* <li>
* Rejects hosts that are not allowed. See
* {@link #setAllowedHostnames(Predicate)}
* </li>
* </ul>
*
* @see DefaultHttpFirewall
* @author Rob Winch
* @author Eddú Meléndez
* @since 4.2.4
*/
public class StrictHttpFirewall implements HttpFirewall {
Expand Down Expand Up @@ -98,6 +104,8 @@ public class StrictHttpFirewall implements HttpFirewall {

private Set<String> allowedHttpMethods = createDefaultAllowedHttpMethods();

private Predicate<String> allowedHostnames = hostname -> true;

public StrictHttpFirewall() {
urlBlacklistsAddAll(FORBIDDEN_SEMICOLON);
urlBlacklistsAddAll(FORBIDDEN_FORWARDSLASH);
Expand Down Expand Up @@ -297,6 +305,13 @@ public void setAllowUrlEncodedPercent(boolean allowUrlEncodedPercent) {
}
}

public void setAllowedHostnames(Predicate<String> allowedHostnames) {
if (allowedHostnames == null) {
throw new IllegalArgumentException("allowedHostnames cannot be null");
}
this.allowedHostnames = allowedHostnames;
}

private void urlBlacklistsAddAll(Collection<String> values) {
this.encodedUrlBlacklist.addAll(values);
this.decodedUrlBlacklist.addAll(values);
Expand All @@ -311,6 +326,7 @@ private void urlBlacklistsRemoveAll(Collection<String> values) {
public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
rejectForbiddenHttpMethod(request);
rejectedBlacklistedUrls(request);
rejectedUntrustedHosts(request);

if (!isNormalized(request)) {
throw new RequestRejectedException("The request was rejected because the URL was not normalized.");
Expand Down Expand Up @@ -352,6 +368,13 @@ private void rejectedBlacklistedUrls(HttpServletRequest request) {
}
}

private void rejectedUntrustedHosts(HttpServletRequest request) {
String serverName = request.getServerName();
if (serverName != null && !this.allowedHostnames.test(serverName)) {
throw new RequestRejectedException("The request was rejected because the domain " + serverName + " is untrusted.");
}
}

@Override
public HttpServletResponse getFirewalledResponse(HttpServletResponse response) {
return new FirewalledResponse(response);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -29,6 +29,7 @@

/**
* @author Rob Winch
* @author Eddú Meléndez
*/
public class StrictHttpFirewallTests {
public String[] unnormalizedPaths = { "/..", "/./path/", "/path/path/.", "/path/path//.", "./path/../path//.",
Expand Down Expand Up @@ -524,4 +525,20 @@ public void getFirewalledRequestWhenRemoveFromDecodedUrlBlacklistThenNoException
this.firewall.getDecodedUrlBlacklist().removeAll(Arrays.asList("//"));
assertThatCode(() -> this.firewall.getFirewalledRequest(request)).doesNotThrowAnyException();
}

@Test
public void getFirewalledRequestWhenTrustedDomainThenNoException() {
this.request.addHeader("Host", "example.org");
this.firewall.setAllowedHostnames(hostname -> hostname.equals("example.org"));

assertThatCode(() -> this.firewall.getFirewalledRequest(this.request)).doesNotThrowAnyException();
}

@Test(expected = RequestRejectedException.class)
public void getFirewalledRequestWhenUntrustedDomainThenException() {
this.request.addHeader("Host", "example.org");
this.firewall.setAllowedHostnames(hostname -> hostname.equals("myexample.org"));

this.firewall.getFirewalledRequest(this.request);
}
}