This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 7.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/7.0.x by this push: new b99fba5 Add new AJP attribute allowedArbitraryRequestAttributes b99fba5 is described below commit b99fba5bd796d876ea536e83299603443842feba Author: Mark Thomas <ma...@apache.org> AuthorDate: Tue Jan 21 15:04:12 2020 +0000 Add new AJP attribute allowedArbitraryRequestAttributes Requests with unrecognised attributes will be blocked with a 403 --- .../apache/coyote/ajp/AbstractAjpProcessor.java | 43 +++++++++++++++++++++- .../org/apache/coyote/ajp/AbstractAjpProtocol.java | 14 +++++++ java/org/apache/coyote/ajp/AjpAprProtocol.java | 1 + java/org/apache/coyote/ajp/AjpNioProtocol.java | 1 + java/org/apache/coyote/ajp/AjpProtocol.java | 1 + .../coyote/ajp/TestAbstractAjpProcessor.java | 1 + webapps/docs/changelog.xml | 5 +++ webapps/docs/config/ajp.xml | 19 ++++++++++ 8 files changed, 83 insertions(+), 2 deletions(-) diff --git a/java/org/apache/coyote/ajp/AbstractAjpProcessor.java b/java/org/apache/coyote/ajp/AbstractAjpProcessor.java index e17b5a2..e68b458 100644 --- a/java/org/apache/coyote/ajp/AbstractAjpProcessor.java +++ b/java/org/apache/coyote/ajp/AbstractAjpProcessor.java @@ -23,7 +23,12 @@ import java.net.InetAddress; import java.security.NoSuchProviderException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.servlet.http.HttpServletResponse; @@ -79,6 +84,9 @@ public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> { protected static final byte[] pongMessageArray; + private static final Set<String> javaxAttributes; + + static { // Allocate the end message array AjpMessage endMessage = new AjpMessage(16); @@ -119,6 +127,14 @@ public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> { pongMessageArray = new byte[pongMessage.getLen()]; System.arraycopy(pongMessage.getBuffer(), 0, pongMessageArray, 0, pongMessage.getLen()); + + // Build the Set of javax attributes + Set<String> s = new HashSet<String>(); + s.add("javax.servlet.request.cipher_suite"); + s.add("javax.servlet.request.key_size"); + s.add("javax.servlet.request.ssl_session"); + s.add("javax.servlet.request.X509Certificate"); + javaxAttributes= Collections.unmodifiableSet(s); } @@ -326,8 +342,14 @@ public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> { public String getClientCertProvider() { return clientCertProvider; } public void setClientCertProvider(String s) { this.clientCertProvider = s; } - // --------------------------------------------------------- Public Methods + private Pattern allowedRequestAttributesPatternPattern; + public void setAllowedRequestAttributesPatternPattern(Pattern allowedRequestAttributesPatternPattern) { + this.allowedRequestAttributesPatternPattern = allowedRequestAttributesPatternPattern; + } + + + // --------------------------------------------------------- Public Methods /** * Send an action to the connector. @@ -867,8 +889,25 @@ public abstract class AbstractAjpProcessor<S> extends AbstractProcessor<S> { } } else if(n.equals(Constants.SC_A_SSL_PROTOCOL)) { request.setAttribute(SSLSupport.PROTOCOL_VERSION_KEY, v); + } else if (n.equals("JK_LB_ACTIVATION")) { + request.setAttribute(n, v); + } else if (javaxAttributes.contains(n)) { + request.setAttribute(n, v); } else { - request.setAttribute(n, v ); + // All 'known' attributes will be processed by the previous + // blocks. Any remaining attribute is an 'arbitrary' one. + if (allowedRequestAttributesPatternPattern == null) { + response.setStatus(403); + setErrorState(ErrorState.CLOSE_CLEAN, null); + } else { + Matcher m = allowedRequestAttributesPatternPattern.matcher(n); + if (m.matches()) { + request.setAttribute(n, v); + } else { + response.setStatus(403); + setErrorState(ErrorState.CLOSE_CLEAN, null); + } + } } break; diff --git a/java/org/apache/coyote/ajp/AbstractAjpProtocol.java b/java/org/apache/coyote/ajp/AbstractAjpProtocol.java index c5e7335..e27c623 100644 --- a/java/org/apache/coyote/ajp/AbstractAjpProtocol.java +++ b/java/org/apache/coyote/ajp/AbstractAjpProtocol.java @@ -16,6 +16,8 @@ */ package org.apache.coyote.ajp; +import java.util.regex.Pattern; + import org.apache.coyote.AbstractProtocol; import org.apache.coyote.Processor; import org.apache.coyote.http11.upgrade.servlet31.HttpUpgradeHandler; @@ -141,6 +143,18 @@ public abstract class AbstractAjpProtocol<S> extends AbstractProtocol<S> { } + private Pattern allowedRequestAttributesPatternPattern; + public void setAllowedRequestAttributesPattern(String allowedRequestAttributesPattern) { + this.allowedRequestAttributesPatternPattern = Pattern.compile(allowedRequestAttributesPattern); + } + public String getAllowedRequestAttributesPattern() { + return allowedRequestAttributesPatternPattern.pattern(); + } + protected Pattern getAllowedRequestAttributesPatternPattern() { + return allowedRequestAttributesPatternPattern; + } + + /** * AJP packet size. */ diff --git a/java/org/apache/coyote/ajp/AjpAprProtocol.java b/java/org/apache/coyote/ajp/AjpAprProtocol.java index 887a343..dd6400a 100644 --- a/java/org/apache/coyote/ajp/AjpAprProtocol.java +++ b/java/org/apache/coyote/ajp/AjpAprProtocol.java @@ -154,6 +154,7 @@ public class AjpAprProtocol extends AbstractAjpProtocol<Long> { processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); processor.setClientCertProvider(proto.getClientCertProvider()); processor.setMaxCookieCount(proto.getMaxCookieCount()); + processor.setAllowedRequestAttributesPatternPattern(proto.getAllowedRequestAttributesPatternPattern()); register(processor); return processor; } diff --git a/java/org/apache/coyote/ajp/AjpNioProtocol.java b/java/org/apache/coyote/ajp/AjpNioProtocol.java index c6f4843..1241987 100644 --- a/java/org/apache/coyote/ajp/AjpNioProtocol.java +++ b/java/org/apache/coyote/ajp/AjpNioProtocol.java @@ -184,6 +184,7 @@ public class AjpNioProtocol extends AbstractAjpProtocol<NioChannel> { processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); processor.setClientCertProvider(proto.getClientCertProvider()); processor.setMaxCookieCount(proto.getMaxCookieCount()); + processor.setAllowedRequestAttributesPatternPattern(proto.getAllowedRequestAttributesPatternPattern()); register(processor); return processor; } diff --git a/java/org/apache/coyote/ajp/AjpProtocol.java b/java/org/apache/coyote/ajp/AjpProtocol.java index 37a7e93..81d6dbb 100644 --- a/java/org/apache/coyote/ajp/AjpProtocol.java +++ b/java/org/apache/coyote/ajp/AjpProtocol.java @@ -144,6 +144,7 @@ public class AjpProtocol extends AbstractAjpProtocol<Socket> { processor.setKeepAliveTimeout(proto.getKeepAliveTimeout()); processor.setClientCertProvider(proto.getClientCertProvider()); processor.setMaxCookieCount(proto.getMaxCookieCount()); + processor.setAllowedRequestAttributesPatternPattern(proto.getAllowedRequestAttributesPatternPattern()); register(processor); return processor; } diff --git a/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java b/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java index 08dc455..66ef3a3 100644 --- a/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java +++ b/test/org/apache/coyote/ajp/TestAbstractAjpProcessor.java @@ -47,6 +47,7 @@ public class TestAbstractAjpProcessor extends TomcatBaseTest { Connector c = getTomcatInstance().getConnector(); c.setProperty("secretRequired", "false"); + c.setProperty("allowedRequestAttributesPattern", "MYATTRIBUTE.*"); } @Override diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 1aa5114..4adc3f1 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -155,6 +155,11 @@ will not start unless the <code>secret</code> attribute is configured to a non-null, non-zero length String. (markt) </add> + <add> + Add a new attribute, <code>allowedRequestAttributesPattern</code> to + the AJP/1.3 Connector. Requests with unreconised attributes will be + blocked with a 403. (markt) + </add> </changelog> </subsection> <subsection name="Jasper"> diff --git a/webapps/docs/config/ajp.xml b/webapps/docs/config/ajp.xml index 615a0f3..a3bcb62 100644 --- a/webapps/docs/config/ajp.xml +++ b/webapps/docs/config/ajp.xml @@ -309,6 +309,25 @@ port. By default, the loopback address will be used.</p> </attribute> + <attribute name="allowedRequestAttributesPattern" required="false"> + <p>The AJP protocol passes some information from the reverse proxy to the + AJP connector using request attributes. These attributes are:</p> + <ul> + <li>javax.servlet.request.cipher_suite</li> + <li>javax.servlet.request.key_size</li> + <li>javax.servlet.request.ssl_session</li> + <li>javax.servlet.request.X509Certificate</li> + <li>AJP_LOCAL_ADDR</li> + <li>AJP_REMOTE_PORT</li> + <li>AJP_SSL_PROTOCOL</li> + <li>JK_LB_ACTIVATION</li> + </ul> + <p>The AJP protocol supports the passing of arbitrary request attributes. + Requests containing arbitrary request attributes will be rejected with a + 403 response unless the entire attribute name matches this regular + expression. If not specified, the default value is <code>null</code>.</p> + </attribute> + <attribute name="bindOnInit" required="false"> <p>Controls when the socket used by the connector is bound. By default it is bound when the connector is initiated and unbound when the connector is --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org