Add support for jakarta.servlet.request.secure_protocol
This request attribute is new in Servlet 6.1. The Tomcat specific
request attribute org.apache.tomcat.util.net.secure_protocol_version has
been deprecated and will be removed in Tomcat 12.
diff --git a/java/org/apache/catalina/Globals.java b/java/org/apache/catalina/Globals.java
index 0e52e18..a3c127e 100644
--- a/java/org/apache/catalina/Globals.java
+++ b/java/org/apache/catalina/Globals.java
@@ -130,6 +130,13 @@
/**
+ * The request attribute under which we store the name of the security protocol (e.g. TLSv1.3) being used on a
+ * secured connection (as an object of type {@link String}).
+ */
+ public static final String SECURE_PROTOCOL_ATTR = "jakarta.servlet.request.secure_protocol";
+
+
+ /**
* The request attribute under which we store the name of the cipher suite
* being used on an SSL connection (as an object of type {@link String}).
*/
diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
index 7883212..508b279 100644
--- a/java/org/apache/catalina/connector/Request.java
+++ b/java/org/apache/catalina/connector/Request.java
@@ -836,6 +836,7 @@
*
* @param name Name of the request attribute to return
*/
+ @SuppressWarnings("deprecation")
@Override
public Object getAttribute(String name) {
// Special attributes
@@ -860,6 +861,11 @@
if (attr != null) {
attributes.put(Globals.CERTIFICATES_ATTR, attr);
}
+ attr = coyoteRequest.getAttribute(Globals.SECURE_PROTOCOL_ATTR);
+ if (attr != null) {
+ attributes.put(Globals.SECURE_PROTOCOL_ATTR, attr);
+ attributes.put(SSLSupport.PROTOCOL_VERSION_KEY, attr);
+ }
attr = coyoteRequest.getAttribute(Globals.CIPHER_SUITE_ATTR);
if (attr != null) {
attributes.put(Globals.CIPHER_SUITE_ATTR, attr);
@@ -876,10 +882,6 @@
if (attr != null) {
attributes.put(Globals.SSL_SESSION_MGR_ATTR, attr);
}
- attr = coyoteRequest.getAttribute(SSLSupport.PROTOCOL_VERSION_KEY);
- if (attr != null) {
- attributes.put(SSLSupport.PROTOCOL_VERSION_KEY, attr);
- }
attr = coyoteRequest.getAttribute(SSLSupport.REQUESTED_PROTOCOL_VERSIONS_KEY);
if (attr != null) {
attributes.put(SSLSupport.REQUESTED_PROTOCOL_VERSIONS_KEY, attr);
@@ -911,6 +913,7 @@
* <li>{@link Globals#DISPATCHER_REQUEST_PATH_ATTR}</li>
* <li>{@link Globals#ASYNC_SUPPORTED_ATTR}</li>
* <li>{@link Globals#CERTIFICATES_ATTR} (SSL connections only)</li>
+ * <li>{@link Globals#SECURE_PROTOCOL_ATTR} (SSL connections only)</li>
* <li>{@link Globals#CIPHER_SUITE_ATTR} (SSL connections only)</li>
* <li>{@link Globals#KEY_SIZE_ATTR} (SSL connections only)</li>
* <li>{@link Globals#SSL_SESSION_ID_ATTR} (SSL connections only)</li>
diff --git a/java/org/apache/catalina/util/TLSUtil.java b/java/org/apache/catalina/util/TLSUtil.java
index 7f895dd..43644d9 100644
--- a/java/org/apache/catalina/util/TLSUtil.java
+++ b/java/org/apache/catalina/util/TLSUtil.java
@@ -32,9 +32,11 @@
* @return {@code true} if the attribute is used to pass TLS configuration
* information, otherwise {@code false}
*/
+ @SuppressWarnings("deprecation")
public static boolean isTLSRequestAttribute(String name) {
switch (name) {
case Globals.CERTIFICATES_ATTR:
+ case Globals.SECURE_PROTOCOL_ATTR:
case Globals.CIPHER_SUITE_ATTR:
case Globals.KEY_SIZE_ATTR:
case Globals.SSL_SESSION_ID_ATTR:
diff --git a/java/org/apache/catalina/valves/SSLValve.java b/java/org/apache/catalina/valves/SSLValve.java
index 2daeb5e..e5a8878 100644
--- a/java/org/apache/catalina/valves/SSLValve.java
+++ b/java/org/apache/catalina/valves/SSLValve.java
@@ -46,6 +46,7 @@
* <pre>
* <IfModule ssl_module>
* RequestHeader set SSL_CLIENT_CERT "%{SSL_CLIENT_CERT}s"
+ * RequestHeader set SSL_SECURE_PROTOCOL "%{SSL_PROTOCOL}s"
* RequestHeader set SSL_CIPHER "%{SSL_CIPHER}s"
* RequestHeader set SSL_SESSION_ID "%{SSL_SESSION_ID}s"
* RequestHeader set SSL_CIPHER_USEKEYSIZE "%{SSL_CIPHER_USEKEYSIZE}s"
@@ -67,6 +68,7 @@
private String sslClientCertHeader = "ssl_client_cert";
private String sslClientEscapedCertHeader = "ssl_client_escaped_cert";
+ private String sslSecureProtocolHeader = "ssl_secure_protocol";
private String sslCipherHeader = "ssl_cipher";
private String sslSessionIdHeader = "ssl_session_id";
private String sslCipherUserKeySizeHeader = "ssl_cipher_usekeysize";
@@ -93,6 +95,14 @@
this.sslClientEscapedCertHeader = sslClientEscapedCertHeader;
}
+ public String getSslSecureProtocolHeader() {
+ return sslSecureProtocolHeader;
+ }
+
+ public void setSslSecureProtocolHeader(String sslSecureProtocolHeader) {
+ this.sslSecureProtocolHeader = sslSecureProtocolHeader;
+ }
+
public String getSslCipherHeader() {
return sslCipherHeader;
}
@@ -178,6 +188,10 @@
request.setAttribute(Globals.CERTIFICATES_ATTR, jsseCerts);
}
}
+ headerValue = mygetHeader(request, sslSecureProtocolHeader);
+ if (headerValue != null) {
+ request.setAttribute(Globals.SECURE_PROTOCOL_ATTR, headerValue);
+ }
headerValue = mygetHeader(request, sslCipherHeader);
if (headerValue != null) {
request.setAttribute(Globals.CIPHER_SUITE_ATTR, headerValue);
diff --git a/java/org/apache/coyote/AbstractProcessor.java b/java/org/apache/coyote/AbstractProcessor.java
index 4e26dca..6cb85ff 100644
--- a/java/org/apache/coyote/AbstractProcessor.java
+++ b/java/org/apache/coyote/AbstractProcessor.java
@@ -764,10 +764,16 @@
* Populate the TLS related request attributes from the {@link SSLSupport} instance associated with this processor.
* Protocols that populate TLS attributes from a different source (e.g. AJP) should override this method.
*/
+ @SuppressWarnings("deprecation")
protected void populateSslRequestAttributes() {
try {
if (sslSupport != null) {
- Object sslO = sslSupport.getCipherSuite();
+ Object sslO = sslSupport.getProtocol();
+ if (sslO != null) {
+ request.setAttribute(SSLSupport.SECURE_PROTOCOL_KEY, sslO);
+ request.setAttribute(SSLSupport.PROTOCOL_VERSION_KEY, sslO);
+ }
+ sslO = sslSupport.getCipherSuite();
if (sslO != null) {
request.setAttribute(SSLSupport.CIPHER_SUITE_KEY, sslO);
}
@@ -783,10 +789,6 @@
if (sslO != null) {
request.setAttribute(SSLSupport.SESSION_ID_KEY, sslO);
}
- sslO = sslSupport.getProtocol();
- if (sslO != null) {
- request.setAttribute(SSLSupport.PROTOCOL_VERSION_KEY, sslO);
- }
sslO = sslSupport.getRequestedProtocols();
if (sslO != null) {
request.setAttribute(SSLSupport.REQUESTED_PROTOCOL_VERSIONS_KEY, sslO);
diff --git a/java/org/apache/coyote/ajp/AjpProcessor.java b/java/org/apache/coyote/ajp/AjpProcessor.java
index ef22da9..c8a070b 100644
--- a/java/org/apache/coyote/ajp/AjpProcessor.java
+++ b/java/org/apache/coyote/ajp/AjpProcessor.java
@@ -132,6 +132,7 @@
// Build Map of Java Servlet to Jakarta Servlet attribute names
Map<String, String> m = new HashMap<>();
+ m.put("jakarta.servlet.request.secure_protocol", "jakarta.servlet.request.secure_protocol");
m.put("jakarta.servlet.request.cipher_suite", "jakarta.servlet.request.cipher_suite");
m.put("jakarta.servlet.request.key_size", "jakarta.servlet.request.key_size");
m.put("jakarta.servlet.request.ssl_session", "jakarta.servlet.request.ssl_session");
@@ -643,6 +644,7 @@
/**
* After reading the request headers, we have to setup the request filters.
*/
+ @SuppressWarnings("deprecation")
private void prepareRequest() {
// Translate the HTTP method code to a String.
@@ -751,6 +753,7 @@
// Ignore invalid value
}
} else if (n.equals(Constants.SC_A_SSL_PROTOCOL)) {
+ request.setAttribute(SSLSupport.SECURE_PROTOCOL_KEY, v);
request.setAttribute(SSLSupport.PROTOCOL_VERSION_KEY, v);
} else if (n.equals("JK_LB_ACTIVATION")) {
request.setAttribute(n, v);
diff --git a/java/org/apache/tomcat/util/net/SSLSupport.java b/java/org/apache/tomcat/util/net/SSLSupport.java
index d98e205..528df94 100644
--- a/java/org/apache/tomcat/util/net/SSLSupport.java
+++ b/java/org/apache/tomcat/util/net/SSLSupport.java
@@ -26,6 +26,13 @@
/**
* The Request attribute key for the cipher suite.
*/
+ String SECURE_PROTOCOL_KEY =
+ "jakarta.servlet.request.secure_protocol";
+
+
+ /**
+ * The Request attribute key for the cipher suite.
+ */
String CIPHER_SUITE_KEY =
"jakarta.servlet.request.cipher_suite";
@@ -57,7 +64,10 @@
/**
* The request attribute key under which the String indicating the protocol
* that created the SSL socket is recorded - e.g. TLSv1 or TLSv1.2 etc.
+ *
+ * @deprecated Replaced by {@link #SECURE_PROTOCOL_KEY}. This constant will be removed in Tomcat 12.
*/
+ @Deprecated
String PROTOCOL_VERSION_KEY =
"org.apache.tomcat.util.net.secure_protocol_version";
diff --git a/test/org/apache/catalina/valves/TestSSLValve.java b/test/org/apache/catalina/valves/TestSSLValve.java
index 5c7753e..702606e 100644
--- a/test/org/apache/catalina/valves/TestSSLValve.java
+++ b/test/org/apache/catalina/valves/TestSSLValve.java
@@ -269,6 +269,17 @@
@Test
+ public void testSslSecureProtocolHeaderPresent() throws Exception {
+ String protocol = "secured-with";
+ mockRequest.setHeader(valve.getSslSecureProtocolHeader(), protocol);
+
+ valve.invoke(mockRequest, null);
+
+ Assert.assertEquals(protocol, mockRequest.getAttribute(Globals.SECURE_PROTOCOL_ATTR));
+ }
+
+
+ @Test
public void testSslCipherHeaderPresent() throws Exception {
String cipher = "ciphered-with";
mockRequest.setHeader(valve.getSslCipherHeader(), cipher);
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 9ae0584..9a7e836 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -111,6 +111,12 @@
Background processes should not be run concurrently with lifecycle
oprations of a container. (remm)
</fix>
+ <add>
+ Add support for the <code>jakarta.servlet.request.secure_protocol</code>
+ request attribute that has been added in Jakarta Servlet 6.1. This
+ replaces the now deprecated Tomcat specific request attribute
+ <code>org.apache.tomcat.util.net.secure_protocol_version</code>. (markt)
+ </add>
</changelog>
</subsection>
<subsection name="Coyote">