Skip to content

Commit

Permalink
Configuration to restrict the hosts and ports accessible by the http …
Browse files Browse the repository at this point in the history
…proxy servlet (geonetwork#7326)

* Configuration to restrict the hosts and ports accessible by the http proxy servlet

---------

Co-authored-by: François Prunayre <[email protected]>
  • Loading branch information
josegar74 and fxprunayre authored Jan 5, 2024
1 parent dc5df0c commit 802e098
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 0 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,12 @@
* allow only host registered in metadata link table
-->
<proxy.securityMode>DB_LINK_CHECK</proxy.securityMode>
<!-- Hosts to exclude from http proxy access: typically localhost, intranet resources -->
<proxy.excludeHosts>^(localhost|127\..*|0\..*|255\.255\.255\.255|.*\.local|.*\.localhost|0:0:0:0:0:0:1|::1)$</proxy.excludeHosts>

<!-- Additional ports (separated by | char) allowed to be access through the http proxy. 80 and 443 are always allowed -->
<proxy.allowPorts></proxy.allowPorts>
<!--<proxy.allowPorts>8443|8080</proxy.allowPorts>-->

<!-- Jetty plugin port configuration -->
<jetty.port>8080</jetty.port>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;

/**
* This is a class extending the real proxy to make sure we can tweak specifics like removing the CSRF token on requests
Expand All @@ -77,6 +81,10 @@ public class URITemplateProxyServlet extends org.mitre.dsmiley.httpproxy.URITemp

private static final String TARGET_URI_NAME = "targetUri";

private static final String P_EXCLUDE_HOSTS = "excludeHosts";

private static final String P_ALLOW_PORTS = "allowPorts";

/*
* These are the "hop-by-hop" headers that should not be copied.
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html Overriding
Expand Down Expand Up @@ -104,6 +112,12 @@ public class URITemplateProxyServlet extends org.mitre.dsmiley.httpproxy.URITemp
private String username;
private String password;

// Regular expression pattern with the hosts to prevent access through the proxy
private Pattern excludeHostsPattern;

// Allowed ports allowed to access through the proxy
private Set<Integer> allowPorts = new HashSet<>(Arrays.asList(80, 443));

/**
* Init some properties from the servlet's init parameters. They try to be resolved the same way other GeoNetwork
* configuration properties are resolved. If after checking externally no configuration can be found it relies into
Expand Down Expand Up @@ -166,6 +180,29 @@ protected void initTarget() throws ServletException {
isSecured = Boolean.parseBoolean(doIsSecured);
}

String excludeHosts = getConfigValue(P_EXCLUDE_HOSTS);
if (StringUtils.isBlank(excludeHosts)) {
excludeHosts = getConfigParam(P_EXCLUDE_HOSTS);
}

if (StringUtils.isNotBlank(excludeHosts)) {
try {
this.excludeHostsPattern = Pattern.compile(excludeHosts);
} catch (PatternSyntaxException ex) {
throw new ServletException(P_EXCLUDE_HOSTS + " doesn't contain a valid regular expression");
}
}

String additionalAllowPorts = getConfigValue(P_ALLOW_PORTS);
if (StringUtils.isBlank(additionalAllowPorts)) {
additionalAllowPorts = getConfigParam(P_EXCLUDE_HOSTS);
}

if (StringUtils.isNotBlank(additionalAllowPorts)) {
Set<Integer> validPorts = Arrays.stream(additionalAllowPorts.split("\\|"))
.filter(StringUtils::isNumeric).map(Integer::valueOf).collect(Collectors.toSet());
this.allowPorts.addAll(validPorts);
}
}

private String getConfigValue(String suffix) {
Expand Down Expand Up @@ -346,6 +383,16 @@ protected HttpRequest newProxyRequestWithEntity(String method, String proxyReque
protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
throws ServletException, IOException {

// Check that the url host or port is not forbidden to access by the proxy
if (!isUrlAllowed(servletRequest)) {
String message = String.format(
"The proxy does not allow to access '%s' .",
servletRequest.getParameter("url")
);
servletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, message);
return;
}

switch (securityMode) {
case NONE:
super.service(servletRequest, servletResponse);
Expand Down Expand Up @@ -404,6 +451,37 @@ protected void service(HttpServletRequest servletRequest, HttpServletResponse se
}
}

private boolean isUrlAllowed(HttpServletRequest servletRequest) {
String url = servletRequest.getParameter("url");
if (StringUtils.isBlank(url)) {
return true;
}

try {
URI uri = new URI(url);

if (this.excludeHostsPattern != null) {
Matcher matcher = this.excludeHostsPattern.matcher(uri.getHost());

if (matcher.matches()) {
return false;
}
}

int port = uri.getPort();

// Default port for the protocol has value -1
return (port == -1) || this.allowPorts.contains(port);
} catch (URISyntaxException e) {
throw new IllegalArgumentException(String.format(
"'%s' is invalid. Error is: '%s'",
url,
e.getMessage()
));
}
}


private enum SECURITY_MODE {
NONE,
/**
Expand Down
8 changes: 8 additions & 0 deletions web/src/main/webResources/WEB-INF/web.xml
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,14 @@
<param-name>securityMode</param-name>
<param-value>${proxy.securityMode}</param-value>
</init-param>
<init-param>
<param-name>excludeHosts</param-name>
<param-value>${proxy.excludeHosts}</param-value>
</init-param>
<init-param>
<param-name>allowPorts</param-name>
<param-value>${proxy.allowPorts}</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>HttpProxy</servlet-name>
Expand Down

0 comments on commit 802e098

Please sign in to comment.