This is an automated email from the ASF dual-hosted git repository. rjung pushed a commit to branch 8.5.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/8.5.x by this push: new 7ff1be3 Let the RemoteCIDRValve inherit from RequestFilterValve. 7ff1be3 is described below commit 7ff1be34e4b55a8a62d261c1abb7cd73c365174c Author: Rainer Jung <rainer.j...@kippdata.de> AuthorDate: Fri Dec 4 17:45:00 2020 +0100 Let the RemoteCIDRValve inherit from RequestFilterValve. Especially add support all of its features, e.g. for connector specific configuration using "addConnectorPort". --- .../apache/catalina/util/LocalStrings.properties | 1 + java/org/apache/catalina/util/NetMask.java | 74 ++++++++++++++- .../apache/catalina/valves/LocalStrings.properties | 2 + .../apache/catalina/valves/RemoteCIDRValve.java | 80 +++++++++++++--- .../apache/catalina/valves/mbeans-descriptors.xml | 63 +++++++++++++ test/org/apache/catalina/util/TestNetMask.java | 36 +++++++- .../catalina/valves/TestRequestFilterValve.java | 46 +++++++++- webapps/docs/changelog.xml | 6 ++ webapps/docs/config/valve.xml | 102 ++++++++++++++++++--- 9 files changed, 376 insertions(+), 34 deletions(-) diff --git a/java/org/apache/catalina/util/LocalStrings.properties b/java/org/apache/catalina/util/LocalStrings.properties index bd26cdb..f4f8241 100644 --- a/java/org/apache/catalina/util/LocalStrings.properties +++ b/java/org/apache/catalina/util/LocalStrings.properties @@ -47,6 +47,7 @@ netmask.cidrNegative=The CIDR [{0}] is negative netmask.cidrNotNumeric=The CIDR [{0}] is not numeric netmask.cidrTooBig=The CIDR [{0}] is greater than the address length [{1}] netmask.invalidAddress=The address [{0}] is not valid +netmask.invalidPort=The port part in the pattern [{0}] is not valid parameterMap.locked=No modifications are allowed to a locked ParameterMap diff --git a/java/org/apache/catalina/util/NetMask.java b/java/org/apache/catalina/util/NetMask.java index fc8e442..fa34065 100644 --- a/java/org/apache/catalina/util/NetMask.java +++ b/java/org/apache/catalina/util/NetMask.java @@ -18,6 +18,8 @@ package org.apache.catalina.util; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import org.apache.tomcat.util.res.StringManager; @@ -72,6 +74,16 @@ public final class NetMask { */ private final int lastByteShift; + /** + * Should we use the port pattern when matching + */ + private final boolean foundPort; + + /** + * The regular expression used to test for the server port (optional). + */ + private final Pattern portPattern; + /** * Constructor @@ -84,16 +96,36 @@ public final class NetMask { expression = input; - final int idx = input.indexOf("/"); + final int portIdx = input.indexOf(";"); + final String nonPortPart; + + if (portIdx == -1) { + foundPort = false; + nonPortPart = input; + portPattern = null; + } else { + foundPort = true; + nonPortPart = input.substring(0, portIdx); + try { + portPattern = Pattern.compile(input.substring(portIdx + 1)); + } catch (PatternSyntaxException e) { + /* + * In case of error never match any non-empty port given + */ + throw new IllegalArgumentException(sm.getString("netmask.invalidPort", input), e); + } + } + + final int idx = nonPortPart.indexOf("/"); /* * Handle the "IP only" case first */ if (idx == -1) { try { - netaddr = InetAddress.getByName(input).getAddress(); + netaddr = InetAddress.getByName(nonPortPart).getAddress(); } catch (UnknownHostException e) { - throw new IllegalArgumentException(sm.getString("netmask.invalidAddress", input)); + throw new IllegalArgumentException(sm.getString("netmask.invalidAddress", nonPortPart)); } nrBytes = netaddr.length; lastByteShift = 0; @@ -105,7 +137,7 @@ public final class NetMask { * and the CIDR. */ - final String addressPart = input.substring(0, idx), cidrPart = input.substring(idx + 1); + final String addressPart = nonPortPart.substring(0, idx), cidrPart = nonPortPart.substring(idx + 1); try { /* @@ -158,12 +190,46 @@ public final class NetMask { /** + * Test if a given address and port matches this netmask. + * + * @param addr The {@link java.net.InetAddress} to test + * @param port The port to test + * @return true on match, false otherwise + */ + public boolean matches(final InetAddress addr, int port) { + if (!foundPort) { + return false; + } + final String portString = Integer.toString(port); + if (!portPattern.matcher(portString).matches()) { + return false; + } + return matches(addr, true); + } + + + /** * Test if a given address matches this netmask. * * @param addr The {@link java.net.InetAddress} to test * @return true on match, false otherwise */ public boolean matches(final InetAddress addr) { + return matches(addr, false); + } + + + /** + * Test if a given address matches this netmask. + * + * @param addr The {@link java.net.InetAddress} to test + * @param checkedPort Indicates, whether we already checked the port + * @return true on match, false otherwise + */ + public boolean matches(final InetAddress addr, boolean checkedPort) { + if (!checkedPort && foundPort) { + return false; + } final byte[] candidate = addr.getAddress(); /* diff --git a/java/org/apache/catalina/valves/LocalStrings.properties b/java/org/apache/catalina/valves/LocalStrings.properties index c529574..2ec1abd 100644 --- a/java/org/apache/catalina/valves/LocalStrings.properties +++ b/java/org/apache/catalina/valves/LocalStrings.properties @@ -130,7 +130,9 @@ jdbcAccessLogValve.exception=Exception performing insert access entry persistentValve.filter.failure=Unable to compile filter=[{0}] remoteCidrValve.invalid=Invalid configuration provided for [{0}]. See previous messages for details. +remoteCidrValve.noPort=Request does not contain a valid server port. Request denied. remoteCidrValve.noRemoteIp=Client does not have an IP address. Request denied. +remoteCidrValve.unexpectedPort=Request contains server port, although connector configuration attribute addConnectorPort is false. Request denied. remoteIpValve.invalidHostHeader=Invalid value [{0}] found for Host in HTTP header [{1}] remoteIpValve.invalidHostWithPort=Host value [{0}] in HTTP header [{1}] included a port number which will be ignored diff --git a/java/org/apache/catalina/valves/RemoteCIDRValve.java b/java/org/apache/catalina/valves/RemoteCIDRValve.java index c29b08d..0675679 100644 --- a/java/org/apache/catalina/valves/RemoteCIDRValve.java +++ b/java/org/apache/catalina/valves/RemoteCIDRValve.java @@ -25,7 +25,6 @@ import java.util.LinkedList; import java.util.List; import javax.servlet.ServletException; -import javax.servlet.http.HttpServletResponse; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; @@ -33,7 +32,7 @@ import org.apache.catalina.util.NetMask; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; -public final class RemoteCIDRValve extends ValveBase { +public final class RemoteCIDRValve extends RequestFilterValve { /** * Our logger @@ -52,7 +51,6 @@ public final class RemoteCIDRValve extends ValveBase { public RemoteCIDRValve() { - super(true); } @@ -62,6 +60,7 @@ public final class RemoteCIDRValve extends ValveBase { * @return the #allow list as a string, without the leading '[' and trailing * ']' */ + @Override public String getAllow() { return allow.toString().replace("[", "").replace("]", ""); } @@ -74,6 +73,7 @@ public final class RemoteCIDRValve extends ValveBase { * @param input The list of netmasks, as a comma separated string * @throws IllegalArgumentException One or more netmasks are invalid */ + @Override public void setAllow(final String input) { final List<String> messages = fillFromInput(input, allow); @@ -81,6 +81,7 @@ public final class RemoteCIDRValve extends ValveBase { return; } + allowValid = false; for (final String message : messages) { log.error(message); } @@ -95,6 +96,7 @@ public final class RemoteCIDRValve extends ValveBase { * @return the #deny list as a string, without the leading '[' and trailing * ']' */ + @Override public String getDeny() { return deny.toString().replace("[", "").replace("]", ""); } @@ -107,7 +109,7 @@ public final class RemoteCIDRValve extends ValveBase { * @param input The list of netmasks, as a comma separated string * @throws IllegalArgumentException One or more netmasks are invalid */ - + @Override public void setDeny(final String input) { final List<String> messages = fillFromInput(input, deny); @@ -115,6 +117,7 @@ public final class RemoteCIDRValve extends ValveBase { return; } + denyValid = false; for (final String message : messages) { log.error(message); } @@ -125,19 +128,48 @@ public final class RemoteCIDRValve extends ValveBase { @Override public void invoke(final Request request, final Response response) throws IOException, ServletException { - - if (isAllowed(request.getRequest().getRemoteAddr())) { - getNext().invoke(request, response); + String property; + if (getAddConnectorPort()) { + property = request.getRequest().getRemoteAddr() + ";" + request.getConnector().getPort(); } else { - response.sendError(HttpServletResponse.SC_FORBIDDEN); + property = request.getRequest().getRemoteAddr(); } + process(property, request, response); } - private boolean isAllowed(final String property) { - final InetAddress addr; + @Override + public boolean isAllowed(final String property) { + + final int portIdx = property.indexOf(";"); + final int port; + final String nonPortPart; + if (portIdx == -1) { + if (getAddConnectorPort()) { + log.error(sm.getString("remoteCidrValve.noPort")); + return false; + } + port = -1; + nonPortPart = property; + } else { + if (!getAddConnectorPort()) { + log.error(sm.getString("remoteCidrValve.unexpectedPort")); + return false; + } + nonPortPart = property.substring(0, portIdx); + try { + port = Integer.parseInt(property.substring(portIdx + 1)); + } catch (NumberFormatException e) { + // This should be in the 'could never happen' category but handle it + // to be safe. + log.error(sm.getString("remoteCidrValve.noPort"), e); + return false; + } + } + + final InetAddress addr; try { - addr = InetAddress.getByName(property); + addr = InetAddress.getByName(nonPortPart); } catch (UnknownHostException e) { // This should be in the 'could never happen' category but handle it // to be safe. @@ -146,14 +178,26 @@ public final class RemoteCIDRValve extends ValveBase { } for (final NetMask nm : deny) { - if (nm.matches(addr)) { - return false; + if (getAddConnectorPort()) { + if (nm.matches(addr, port)) { + return false; + } + } else { + if (nm.matches(addr)) { + return false; + } } } for (final NetMask nm : allow) { - if (nm.matches(addr)) { - return true; + if (getAddConnectorPort()) { + if (nm.matches(addr, port)) { + return true; + } + } else { + if (nm.matches(addr)) { + return true; + } } } @@ -167,6 +211,12 @@ public final class RemoteCIDRValve extends ValveBase { } + @Override + protected Log getLog() { + return log; + } + + /** * Fill a {@link NetMask} list from a string input containing a * comma-separated list of (hopefully valid) {@link NetMask}s. diff --git a/java/org/apache/catalina/valves/mbeans-descriptors.xml b/java/org/apache/catalina/valves/mbeans-descriptors.xml index 41d1178..1fd880e 100644 --- a/java/org/apache/catalina/valves/mbeans-descriptors.xml +++ b/java/org/apache/catalina/valves/mbeans-descriptors.xml @@ -457,6 +457,69 @@ </operation> </mbean> + <mbean name="RemoteCIDRValve" + description="Concrete implementation of RequestFilterValve that filters based on the string representation of the remote client's network address in CIDR format" + domain="Catalina" + group="Valve" + type="org.apache.catalina.valves.RemoteCIDRValve"> + + <attribute name="addConnectorPort" + description="Append the server connector port to the client network CIDR separated by a semicolon" + type="boolean"/> + + <attribute name="allow" + description="The allow expression" + type="java.lang.String"/> + + <attribute name="allowValid" + description="Becomes false if assigned value of allow expression is not syntactically correct" + is="true" + type="boolean" + writeable="false"/> + + <attribute name="asyncSupported" + description="Does this valve support async reporting." + is="true" + type="boolean"/> + + <attribute name="className" + description="Fully qualified class name of the managed object" + type="java.lang.String" + writeable="false"/> + + <attribute name="deny" + description="The deny expression" + type="java.lang.String"/> + + <attribute name="denyStatus" + description="HTTP response status code that is used when rejecting denied request" + type="int"/> + + <attribute name="denyValid" + description="Becomes false if assigned value of deny expression is not syntactically correct" + is="true" + type="boolean" + writeable="false"/> + + <attribute name="invalidAuthenticationWhenDeny" + description="Send an invalid authentication header instead of deny" + type="boolean"/> + + <attribute name="stateName" + description="The name of the LifecycleState that this component is currently in" + type="java.lang.String" + writeable="false"/> + + <operation name="isAllowed" + description="Tests whether a client with this host name is allowed access by the current valve configuration" + impact="INFO" + returnType="boolean"> + <parameter name="hostName" + description="host name to be tested" + type="java.lang.String"/> + </operation> + </mbean> + <mbean name="RemoteIpValve" description="Valve that sets client information (eg IP address) based on data from a trusted proxy" domain="Catalina" diff --git a/test/org/apache/catalina/util/TestNetMask.java b/test/org/apache/catalina/util/TestNetMask.java index 2260a24..b67ae54 100644 --- a/test/org/apache/catalina/util/TestNetMask.java +++ b/test/org/apache/catalina/util/TestNetMask.java @@ -61,6 +61,9 @@ public final class TestNetMask { result.add(new Object[] { "ae31::27:ef2:1/-1", null, Boolean.FALSE, null }); result.add(new Object[] { "ae31::27:ef2:1/129", null, Boolean.FALSE, null }); + // Invalid port regex suffix after ";" + result.add(new Object[] { "1.2.3.4;[", null, Boolean.FALSE, null }); + // IPv4 result.add(new Object[] { "1.2.3.4", "1.2.3.4", Boolean.TRUE, Boolean.TRUE }); @@ -98,6 +101,16 @@ public final class TestNetMask { // Mixed result.add(new Object[] { "10.0.0.0/22", "::1", Boolean.TRUE, Boolean.FALSE }); + // port + result.add(new Object[] { "1.2.3.4;8080", "1.2.3.4", Boolean.TRUE, Boolean.FALSE }); + result.add(new Object[] { "1.2.3.4", "1.2.3.4;8080", Boolean.TRUE, Boolean.FALSE }); + result.add(new Object[] { "1.2.3.4;", "1.2.3.4;8080", Boolean.TRUE, Boolean.FALSE }); + result.add(new Object[] { "1.2.3.4;8080", "1.2.3.4;8080", Boolean.TRUE, Boolean.TRUE }); + result.add(new Object[] { "1.2.3.4;8080", "1.2.3.4;8009", Boolean.TRUE, Boolean.FALSE }); + result.add(new Object[] { "1.2.3.4;.*", "1.2.3.4;8080", Boolean.TRUE, Boolean.TRUE }); + result.add(new Object[] { "1.2.3.4;8\\d+", "1.2.3.4;8080", Boolean.TRUE, Boolean.TRUE }); + result.add(new Object[] { "1.2.3.4;8\\d+", "1.2.3.4;9090", Boolean.TRUE, Boolean.FALSE }); + return result; } @@ -109,7 +122,7 @@ public final class TestNetMask { try { netMask = new NetMask(mask); } catch (Exception e) { - exception =e; + exception = e; } if (valid.booleanValue()) { @@ -122,15 +135,32 @@ public final class TestNetMask { return; } + final int portIdx = input.indexOf(";"); + final boolean usePort = portIdx >= 0 || mask.indexOf(";") >= 0; + final int port; + final String nonPortPart; + + if (portIdx == -1) { + port = -1; + nonPortPart = input; + } else { + port = Integer.parseInt(input.substring(portIdx + 1)); + nonPortPart = input.substring(0, portIdx); + } + InetAddress inetAddress = null; try { - inetAddress = InetAddress.getByName(input); + inetAddress = InetAddress.getByName(nonPortPart); } catch (UnknownHostException e) { e.printStackTrace(); Assert.fail(); } - Assert.assertEquals(matches, Boolean.valueOf(netMask.matches(inetAddress))); + if (usePort) { + Assert.assertEquals(matches, Boolean.valueOf(netMask.matches(inetAddress, port))); + } else { + Assert.assertEquals(matches, Boolean.valueOf(netMask.matches(inetAddress))); + } Assert.assertEquals(mask, netMask.toString()); } diff --git a/test/org/apache/catalina/valves/TestRequestFilterValve.java b/test/org/apache/catalina/valves/TestRequestFilterValve.java index 6e7e106..3f076c8 100644 --- a/test/org/apache/catalina/valves/TestRequestFilterValve.java +++ b/test/org/apache/catalina/valves/TestRequestFilterValve.java @@ -52,6 +52,20 @@ public class TestRequestFilterValve { private static final String HOST_ALLOW_AND_DENY = "www.example.org"; private static final String HOST_NO_ALLOW_NO_DENY = "host.example.com"; + private static final String CIDR_ALLOW_PROP = "127.0.0.0/16"; + private static final String CIDR_DENY_PROP = "192.168.0.0/24,127.0.0.0/24"; + private static final String CIDR_ONLY_ALLOW = "127.0.1.1"; + private static final String CIDR_ONLY_DENY = "192.168.0.1"; + private static final String CIDR_ALLOW_AND_DENY = "127.0.0.1"; + private static final String CIDR_NO_ALLOW_NO_DENY = "192.168.1.1"; + + private static final String CIDR6_ALLOW_PROP = "::/96"; + private static final String CIDR6_DENY_PROP = "::f:0:0/112,::/112"; + private static final String CIDR6_ONLY_ALLOW = "0:0:0:0:0:0:148f:1"; + private static final String CIDR6_ONLY_DENY = "0:0:0:0:0:F:0:a"; + private static final String CIDR6_ALLOW_AND_DENY = "0:0:0:0:0:0:0:fA8"; + private static final String CIDR6_NO_ALLOW_NO_DENY = "1:0:0:0:0:0:0:1"; + private static final int PORT = 8080; private static final String PORT_MATCH_PATTERN = ";\\d*"; private static final String PORT_NO_MATCH_PATTERN = ";8081"; @@ -104,6 +118,10 @@ public class TestRequestFilterValve { valve = new RemoteHostValve(); request.setRemoteHost(property); msg.append(" host='" + property + "'"); + } else if (type.equals("CIDR")) { + valve = new RemoteCIDRValve(); + request.setRemoteAddr(property); + msg.append(" ip='" + property + "'"); } } Assert.assertNotNull("Invalid test type" + type, valve); @@ -129,8 +147,10 @@ public class TestRequestFilterValve { ((RemoteAddrValve)valve).setAddConnectorPort(true); } else if (valve instanceof RemoteHostValve) { ((RemoteHostValve)valve).setAddConnectorPort(true); + } else if (valve instanceof RemoteCIDRValve) { + ((RemoteCIDRValve)valve).setAddConnectorPort(true); } else { - Assert.fail("Can only set 'addConnectorPort' for RemoteAddrValve and RemoteHostValve"); + Assert.fail("Can only set 'addConnectorPort' for RemoteAddrValve, RemoteHostValve and RemoteCIDRValve"); } msg.append(" addConnectorPort='true'"); } @@ -341,4 +361,28 @@ public class TestRequestFilterValve { HOST_ALLOW_AND_DENY, HOST_NO_ALLOW_NO_DENY, true, "Host"); } + + @Test + public void testRemoteCIDRValve() { + standardTests(CIDR_ALLOW_PROP, CIDR_DENY_PROP, + CIDR_ONLY_ALLOW, CIDR_ONLY_DENY, + CIDR_ALLOW_AND_DENY, CIDR_NO_ALLOW_NO_DENY, + false, "CIDR"); + standardTests(CIDR_ALLOW_PROP, CIDR_DENY_PROP, + CIDR_ONLY_ALLOW, CIDR_ONLY_DENY, + CIDR_ALLOW_AND_DENY, CIDR_NO_ALLOW_NO_DENY, + true, "CIDR"); + } + + @Test + public void testRemoteCIDR6Valve() { + standardTests(CIDR6_ALLOW_PROP, CIDR6_DENY_PROP, + CIDR6_ONLY_ALLOW, CIDR6_ONLY_DENY, + CIDR6_ALLOW_AND_DENY, CIDR6_NO_ALLOW_NO_DENY, + false, "CIDR"); + standardTests(CIDR6_ALLOW_PROP, CIDR6_DENY_PROP, + CIDR6_ONLY_ALLOW, CIDR6_ONLY_DENY, + CIDR6_ALLOW_AND_DENY, CIDR6_NO_ALLOW_NO_DENY, + true, "CIDR"); + } } diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index b9e4544..5788e84 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -111,6 +111,12 @@ attributes that provide details of the protocols and ciphers requested by a client in the initial TLS handshake. (markt) </add> + <add> + Let the <code>RemoteCIDRValve</code> inherit from + <code>RequestFilterValve</code> and support all of its features. + Especially add support for connector specific configuration + using <code>addConnectorPort</code>. (rjung) + </add> </changelog> </subsection> </section> diff --git a/webapps/docs/config/valve.xml b/webapps/docs/config/valve.xml index e2537d7..1f9e767 100644 --- a/webapps/docs/config/valve.xml +++ b/webapps/docs/config/valve.xml @@ -515,10 +515,16 @@ package. Please consult the Java documentation for details of the expressions supported.</p> - <p>Optionally one can append the server connector port separated with a + <p>After setting the attribute <code>addConnectorPort</code> to + <code>true</code>, one can append the server connector port separated with a semicolon (";") to allow different expressions for each connector.</p> - <p>The behavior when a request is refused can be changed + <p>A refused request will be answered a response with status code + <code>403</code>. This status code can be overwritten using the attribute + <code>denyStatus</code>.</p> + + <p>By setting the attribute <code>invalidAuthenticationWhenDeny</code> to + <code>true</code>, the behavior when a request is refused can be changed to not deny but instead set an invalid <code>authentication</code> header. This is useful in combination with the context attribute <code>preemptiveAuthentication="true"</code>.</p> @@ -532,7 +538,9 @@ <code>::1</code>. Consult your access logs for the actual value.</p> <p>See also: <a href="#Remote_Host_Valve">Remote Host Valve</a>, - <a href="#Remote_IP_Valve">Remote IP Valve</a>.</p> + <a href="#Remote_CIDR_Valve">Remote CIDR Valve</a>, + <a href="#Remote_IP_Valve">Remote IP Valve</a>, + <a href="http.html">HTTP Connector</a> configuration.</p> </subsection> <subsection name="Attributes"> @@ -644,10 +652,16 @@ package. Please consult the Java documentation for details of the expressions supported.</p> - <p>Optionally one can append the server connector port separated with a + <p>After setting the attribute <code>addConnectorPort</code> to + <code>true</code>, one can append the server connector port separated with a semicolon (";") to allow different expressions for each connector.</p> - <p>The behavior when a request is refused can be changed + <p>A refused request will be answered a response with status code + <code>403</code>. This status code can be overwritten using the attribute + <code>denyStatus</code>.</p> + + <p>By setting the attribute <code>invalidAuthenticationWhenDeny</code> to + <code>true</code>, the behavior when a request is refused can be changed to not deny but instead set an invalid <code>authentication</code> header. This is useful in combination with the context attribute <code>preemptiveAuthentication="true"</code>.</p> @@ -658,6 +672,8 @@ a <strong>Connector</strong>.</p> <p>See also: <a href="#Remote_Address_Valve">Remote Address Valve</a>, + <a href="#Remote_CIDR_Valve">Remote CIDR Valve</a>, + <a href="#Remote_IP_Valve">Remote IP Valve</a>, <a href="http.html">HTTP Connector</a> configuration.</p> </subsection> @@ -758,6 +774,20 @@ </li> </ul> + <p>After setting the attribute <code>addConnectorPort</code> to + <code>true</code>, one can append the server connector port separated with a + semicolon (";") to allow different expressions for each connector.</p> + + <p>A refused request will be answered a response with status code + <code>403</code>. This status code can be overwritten using the attribute + <code>denyStatus</code>.</p> + + <p>By setting the attribute <code>invalidAuthenticationWhenDeny</code> to + <code>true</code>, the behavior when a request is refused can be changed + to not deny but instead set an invalid <code>authentication</code> + header. This is useful in combination with the context attribute + <code>preemptiveAuthentication="true"</code>.</p> + <p>Some more features of this valve are: </p> @@ -769,6 +799,10 @@ <code>fe80::/71</code>, etc).</li> </ul> + <p>See also: <a href="#Remote_Address_Valve">Remote Address Valve</a>, + <a href="#Remote_Host_Valve">Remote Host Valve</a>, + <a href="#Remote_IP_Valve">Remote IP Valve</a>, + <a href="http.html">HTTP Connector</a> configuration.</p> </subsection> <subsection name="Attributes"> @@ -803,20 +837,66 @@ </p> </attribute> + <attribute name="denyStatus" required="false"> + <p>HTTP response status code that is used when rejecting denied + request. The default value is <code>403</code>. For example, + it can be set to the value <code>404</code>.</p> + </attribute> + + <attribute name="addConnectorPort" required="false"> + <p>Append the server connector port to the client IP address separated + with a semicolon (";"). If this is set to <code>true</code>, the + expressions configured with <code>allow</code> and + <code>deny</code> is compared against <code>ADDRESS;PORT</code> + where <code>ADDRESS</code> is the client IP address and + <code>PORT</code> is the Tomcat connector port which received the + request. The default value is <code>false</code>.</p> + </attribute> + + <attribute name="invalidAuthenticationWhenDeny" required="false"> + <p>When a request should be denied, do not deny but instead + set an invalid <code>authentication</code> header. This only works + if the context has the attribute <code>preemptiveAuthentication="true"</code> + set. An already existing <code>authentication</code> header will not be + overwritten. In effect this will trigger authentication instead of deny + even if the application does not have a security constraint configured.</p> + <p>This can be combined with <code>addConnectorPort</code> to trigger authentication + depending on the client and the connector that is used to access an application.</p> + </attribute> + </attributes> </subsection> - <subsection name="Example"> + <subsection name="Example 1" anchor="Remote_CIDR_Valve/Example_localhost"> <p>To allow access only for the clients connecting from localhost:</p> - <pre> - <Valve className="org.apache.catalina.valves.RemoteCIDRValve" - allow="127.0.0.1, ::1"/> - </pre> + <source><![CDATA[<Valve className="org.apache.catalina.valves.RemoteCIDRValve" + allow="127.0.0.1, ::1"/>]]></source> </subsection> -</subsection> + <subsection name="Example 2" anchor="Remote_CIDR_Valve/Example_localhost_port"> + <p>To allow unrestricted access for the clients connecting from the local network + but for all clients in network 10. only to port 8443:</p> + <source><![CDATA[<Valve className="org.apache.catalina.valves.RemoteCIDRValve" + addConnectorPort="true" + allow="127.0.0.1;\d*|::1;\d*|10.0.0.0/8;8443"/>]]></source> + </subsection> + <subsection name="Example 3" anchor="Remote_CIDR_Valve/Example_port_auth"> + <p>To allow access to port 8009 from network 10., but trigger basic + authentication if the application is accessed on another port:</p> +<source><![CDATA[<Context> + ... + <Valve className="org.apache.catalina.valves.RemoteCIDRValve" + addConnectorPort="true" + invalidAuthenticationWhenDeny="true" + allow="10.0.0.0/8;8009"/> + <Valve className="org.apache.catalina.authenticator.BasicAuthenticator" /> + ... +</Context>]]></source> + </subsection> + +</subsection> </section> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org