You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by rj...@apache.org on 2020/12/04 16:45:33 UTC
[tomcat] branch 8.5.x updated: Let the RemoteCIDRValve inherit from
RequestFilterValve.
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 <ra...@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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org