This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 11.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 2a8394e721ffeaeef90403d241ca951123b0bcac Author: opencode <[email protected]> AuthorDate: Wed Oct 14 14:29:42 2026 +0200 Validate the cookie max-age value at deployment time SessionConfig.setCookieMaxAge(String) stored the raw string and getCookieMaxAge() parsed it lazily. The value is copied verbatim by ContextConfig into the runtime SessionCookieConfig, where ApplicationSessionCookieConfig.getMaxAge() parses it again on every session cookie creation. Web.xml XSD validation is off by default, so an invalid value such as "abc" passed parsing and then threw a raw NumberFormatException on every session creation and session id change for the application, instead of failing the deployment. The setter now validates the value with Integer.valueOf() before storing it, consistently with setSessionTimeout() in the same class. The digester wraps the resulting NumberFormatException into a SAX parse error that reports the location in the descriptor and fails the deployment cleanly. Valid values, including negative ones used to disable cookie expiry, are stored unchanged. The generic cookie attribute path (SessionConfig.setCookieAttribute, the descriptor mirror of SessionCookieConfig.setAttribute) accepts arbitrary strings and remains unvalidated, which is pre-existing and mirrors the programmatic API. Adds TestSessionConfig for the setter and parse level tests in TestWebXmlParser covering valid, invalid and empty max-age elements. --- .../tomcat/util/descriptor/web/SessionConfig.java | 5 ++ .../util/descriptor/web/TestSessionConfig.java | 82 ++++++++++++++++++++++ .../util/descriptor/web/TestWebXmlParser.java | 44 ++++++++++++ 3 files changed, 131 insertions(+) diff --git a/java/org/apache/tomcat/util/descriptor/web/SessionConfig.java b/java/org/apache/tomcat/util/descriptor/web/SessionConfig.java index 6525e6a481..898a059a56 100644 --- a/java/org/apache/tomcat/util/descriptor/web/SessionConfig.java +++ b/java/org/apache/tomcat/util/descriptor/web/SessionConfig.java @@ -176,6 +176,11 @@ public class SessionConfig { * @param cookieMaxAge the max age */ public void setCookieMaxAge(String cookieMaxAge) { + // Validate the value at deployment time, consistently with + // setSessionTimeout(), so an invalid value fails the deployment with a + // parse error instead of causing a NumberFormatException at run time + // when the value is parsed to create each session cookie + Integer.valueOf(cookieMaxAge); setCookieAttribute(Constants.COOKIE_MAX_AGE_ATTR, cookieMaxAge); } diff --git a/test/org/apache/tomcat/util/descriptor/web/TestSessionConfig.java b/test/org/apache/tomcat/util/descriptor/web/TestSessionConfig.java new file mode 100644 index 0000000000..0ab55d5589 --- /dev/null +++ b/test/org/apache/tomcat/util/descriptor/web/TestSessionConfig.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.descriptor.web; + +import org.junit.Assert; +import org.junit.Test; + +public class TestSessionConfig { + + @Test + public void testCookieMaxAgeUnset() { + SessionConfig sessionConfig = new SessionConfig(); + Assert.assertNull(sessionConfig.getCookieMaxAge()); + } + + @Test + public void testCookieMaxAgeValid() { + SessionConfig sessionConfig = new SessionConfig(); + + sessionConfig.setCookieMaxAge("60"); + Assert.assertEquals(Integer.valueOf(60), sessionConfig.getCookieMaxAge()); + Assert.assertEquals("60", sessionConfig.getCookieAttribute(Constants.COOKIE_MAX_AGE_ATTR)); + + sessionConfig.setCookieMaxAge("0"); + Assert.assertEquals(Integer.valueOf(0), sessionConfig.getCookieMaxAge()); + + // Negative values disable cookie expiry and must be accepted + sessionConfig.setCookieMaxAge("-1"); + Assert.assertEquals(Integer.valueOf(-1), sessionConfig.getCookieMaxAge()); + } + + @Test + public void testCookieMaxAgeInvalid() { + SessionConfig sessionConfig = new SessionConfig(); + + // An invalid value must be rejected at deployment time rather than + // causing a NumberFormatException whenever a session cookie is created + try { + sessionConfig.setCookieMaxAge("abc"); + Assert.fail("NumberFormatException expected"); + } catch (NumberFormatException e) { + // Expected + } + Assert.assertNull(sessionConfig.getCookieAttribute(Constants.COOKIE_MAX_AGE_ATTR)); + Assert.assertNull(sessionConfig.getCookieMaxAge()); + + try { + sessionConfig.setCookieMaxAge(""); + Assert.fail("NumberFormatException expected"); + } catch (NumberFormatException e) { + // Expected + } + Assert.assertNull(sessionConfig.getCookieAttribute(Constants.COOKIE_MAX_AGE_ATTR)); + } + + @Test + public void testCookieMaxAgeOverflow() { + SessionConfig sessionConfig = new SessionConfig(); + + try { + sessionConfig.setCookieMaxAge("2147483648"); + Assert.fail("NumberFormatException expected"); + } catch (NumberFormatException e) { + // Expected + } + Assert.assertNull(sessionConfig.getCookieAttribute(Constants.COOKIE_MAX_AGE_ATTR)); + } +} diff --git a/test/org/apache/tomcat/util/descriptor/web/TestWebXmlParser.java b/test/org/apache/tomcat/util/descriptor/web/TestWebXmlParser.java index 5bcf23a10a..3158e6368a 100644 --- a/test/org/apache/tomcat/util/descriptor/web/TestWebXmlParser.java +++ b/test/org/apache/tomcat/util/descriptor/web/TestWebXmlParser.java @@ -16,12 +16,15 @@ */ package org.apache.tomcat.util.descriptor.web; +import java.io.StringReader; import java.net.URL; import java.util.Set; import org.junit.Assert; import org.junit.Test; +import org.xml.sax.InputSource; + public class TestWebXmlParser { private static final String WEB_XML = "TestWebXmlParser-web.xml"; @@ -64,4 +67,45 @@ public class TestWebXmlParser { SecurityCollection securityCollection = securityConstraint.findCollection("resource"); Assert.assertArrayEquals(new String[] { "/secure" + expectedSuffix }, securityCollection.findPatterns()); } + + @Test + public void testCookieMaxAgeInvalidFailsParse() { + // An invalid max-age value must fail the parse so the deployment fails, + // rather than breaking session cookie creation at run time + String webXml = "<web-app><session-config><cookie-config>" + + "<max-age>abc</max-age>" + + "</cookie-config></session-config></web-app>"; + + WebXml result = new WebXml(); + WebXmlParser parser = new WebXmlParser(false, false, true); + + Assert.assertFalse(parser.parseWebXml(new InputSource(new StringReader(webXml)), result, false)); + } + + @Test + public void testCookieMaxAgeEmptyFailsParse() { + // The digester passes an empty body text to the setter, so an empty + // element must also fail the parse + String webXml = "<web-app><session-config><cookie-config>" + + "<max-age></max-age>" + + "</cookie-config></session-config></web-app>"; + + WebXml result = new WebXml(); + WebXmlParser parser = new WebXmlParser(false, false, true); + + Assert.assertFalse(parser.parseWebXml(new InputSource(new StringReader(webXml)), result, false)); + } + + @Test + public void testCookieMaxAgeValidParses() { + String webXml = "<web-app><session-config><cookie-config>" + + "<max-age>60</max-age>" + + "</cookie-config></session-config></web-app>"; + + WebXml result = new WebXml(); + WebXmlParser parser = new WebXmlParser(false, false, true); + + Assert.assertTrue(parser.parseWebXml(new InputSource(new StringReader(webXml)), result, false)); + Assert.assertEquals(Integer.valueOf(60), result.getSessionConfig().getCookieMaxAge()); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
