Browse Source

New upstream version 9.0.30

tags/upstream/9.0.30^0
Emmanuel Bourg 1 year ago
parent
commit
ebba2dc295
100 changed files with 2544 additions and 1595 deletions
  1. +1
    -0
      .gitignore
  2. +1
    -1
      CONTRIBUTING.md
  3. +10
    -10
      MERGE.txt
  4. +1
    -0
      RELEASE-NOTES
  5. +6
    -2
      bin/catalina.sh
  6. +34
    -32
      bin/daemon.sh
  7. +4
    -4
      bin/tool-wrapper.sh
  8. +1
    -1
      build.properties.default
  9. +18
    -0
      build.xml
  10. +1
    -0
      conf/catalina.properties
  11. +33
    -0
      java/org/apache/catalina/Manager.java
  12. +20
    -0
      java/org/apache/catalina/Realm.java
  13. +120
    -23
      java/org/apache/catalina/authenticator/AuthenticatorBase.java
  14. +18
    -30
      java/org/apache/catalina/authenticator/Constants.java
  15. +44
    -63
      java/org/apache/catalina/authenticator/FormAuthenticator.java
  16. +4
    -5
      java/org/apache/catalina/connector/Request.java
  17. +1
    -1
      java/org/apache/catalina/connector/mbeans-descriptors.xml
  18. +4
    -0
      java/org/apache/catalina/core/LocalStrings_fr.properties
  19. +4
    -0
      java/org/apache/catalina/core/LocalStrings_ko.properties
  20. +1
    -1
      java/org/apache/catalina/filters/Constants.java
  21. +8
    -59
      java/org/apache/catalina/filters/CorsFilter.java
  22. +78
    -6
      java/org/apache/catalina/filters/CsrfPreventionFilter.java
  23. +0
    -10
      java/org/apache/catalina/filters/CsrfPreventionFilterBase.java
  24. +12
    -0
      java/org/apache/catalina/filters/RestCsrfPreventionFilter.java
  25. +1
    -0
      java/org/apache/catalina/ha/deploy/LocalStrings_zh_CN.properties
  26. +51
    -9
      java/org/apache/catalina/realm/CombinedRealm.java
  27. +1
    -0
      java/org/apache/catalina/realm/LocalStrings_zh_CN.properties
  28. +13
    -0
      java/org/apache/catalina/realm/LockOutRealm.java
  29. +53
    -10
      java/org/apache/catalina/realm/RealmBase.java
  30. +6
    -1
      java/org/apache/catalina/servlets/WebdavServlet.java
  31. +13
    -18
      java/org/apache/catalina/session/FileStore.java
  32. +1
    -0
      java/org/apache/catalina/session/LocalStrings_zh_CN.properties
  33. +7
    -0
      java/org/apache/catalina/session/ManagerBase.java
  34. +1
    -0
      java/org/apache/catalina/startup/LocalStrings_zh_CN.properties
  35. +1
    -0
      java/org/apache/catalina/valves/LocalStrings_zh_CN.properties
  36. +93
    -14
      java/org/apache/catalina/webresources/CachedResource.java
  37. +40
    -0
      java/org/apache/coyote/CompressionConfig.java
  38. +4
    -0
      java/org/apache/coyote/LocalStrings_fr.properties
  39. +4
    -0
      java/org/apache/coyote/LocalStrings_ko.properties
  40. +3
    -0
      java/org/apache/coyote/LocalStrings_zh_CN.properties
  41. +3
    -0
      java/org/apache/coyote/ajp/AjpProcessor.java
  42. +1
    -0
      java/org/apache/coyote/ajp/LocalStrings_zh_CN.properties
  43. +10
    -0
      java/org/apache/coyote/http11/AbstractHttp11Protocol.java
  44. +1
    -0
      java/org/apache/coyote/http11/LocalStrings_zh_CN.properties
  45. +10
    -0
      java/org/apache/coyote/http2/Http2Protocol.java
  46. +5
    -0
      java/org/apache/coyote/http2/LocalStrings_zh_CN.properties
  47. +1
    -0
      java/org/apache/jasper/resources/LocalStrings_zh_CN.properties
  48. +46
    -46
      java/org/apache/tomcat/dbcp/dbcp2/AbandonedTrace.java
  49. +2
    -0
      java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java
  50. +1
    -0
      java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
  51. +140
    -87
      java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
  52. +77
    -61
      java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
  53. +11
    -15
      java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
  54. +2
    -1
      java/org/apache/tomcat/dbcp/pool2/PooledObject.java
  55. +2
    -0
      java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
  56. +1
    -0
      java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
  57. +3
    -6
      java/org/apache/tomcat/dbcp/pool2/impl/EvictionTimer.java
  58. +21
    -4
      java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
  59. +15
    -14
      java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
  60. +1
    -0
      java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java
  61. +4
    -0
      java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java
  62. +1
    -6
      java/org/apache/tomcat/dbcp/pool2/impl/SecurityManagerCallStack.java
  63. +3
    -0
      java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java
  64. +8
    -6
      java/org/apache/tomcat/util/bcel/Const.java
  65. +1
    -1
      java/org/apache/tomcat/util/bcel/classfile/ConstantClass.java
  66. +1
    -1
      java/org/apache/tomcat/util/bcel/classfile/ConstantDouble.java
  67. +1
    -1
      java/org/apache/tomcat/util/bcel/classfile/ConstantFloat.java
  68. +1
    -1
      java/org/apache/tomcat/util/bcel/classfile/ConstantInteger.java
  69. +1
    -1
      java/org/apache/tomcat/util/bcel/classfile/ConstantLong.java
  70. +17
    -11
      java/org/apache/tomcat/util/codec/binary/Base64.java
  71. +85
    -15
      java/org/apache/tomcat/util/codec/binary/BaseNCodec.java
  72. +1
    -1
      java/org/apache/tomcat/util/compat/GraalCompat.java
  73. +1
    -1
      java/org/apache/tomcat/util/compat/JreCompat.java
  74. +94
    -0
      java/org/apache/tomcat/util/http/RequestUtil.java
  75. +47
    -2
      java/org/apache/tomcat/util/http/fileupload/FileItemIterator.java
  76. +10
    -692
      java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
  77. +5
    -5
      java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
  78. +2
    -1
      java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java
  79. +339
    -0
      java/org/apache/tomcat/util/http/fileupload/impl/FileItemIteratorImpl.java
  80. +213
    -0
      java/org/apache/tomcat/util/http/fileupload/impl/FileItemStreamImpl.java
  81. +94
    -0
      java/org/apache/tomcat/util/http/fileupload/impl/FileSizeLimitExceededException.java
  82. +63
    -0
      java/org/apache/tomcat/util/http/fileupload/impl/FileUploadIOException.java
  83. +62
    -0
      java/org/apache/tomcat/util/http/fileupload/impl/IOFileUploadException.java
  84. +62
    -0
      java/org/apache/tomcat/util/http/fileupload/impl/InvalidContentTypeException.java
  85. +75
    -0
      java/org/apache/tomcat/util/http/fileupload/impl/SizeException.java
  86. +43
    -0
      java/org/apache/tomcat/util/http/fileupload/impl/SizeLimitExceededException.java
  87. +1
    -0
      java/org/apache/tomcat/util/http/parser/LocalStrings_zh_CN.properties
  88. +1
    -1
      java/org/apache/tomcat/util/modeler/Registry.java
  89. +20
    -11
      java/org/apache/tomcat/util/net/AbstractEndpoint.java
  90. +61
    -115
      java/org/apache/tomcat/util/net/AprEndpoint.java
  91. +2
    -0
      java/org/apache/tomcat/util/net/LocalStrings_fr.properties
  92. +2
    -0
      java/org/apache/tomcat/util/net/LocalStrings_ko.properties
  93. +17
    -13
      java/org/apache/tomcat/util/net/Nio2Endpoint.java
  94. +38
    -31
      java/org/apache/tomcat/util/net/NioEndpoint.java
  95. +53
    -119
      java/org/apache/tomcat/util/net/SocketWrapperBase.java
  96. +2
    -2
      java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java
  97. +1
    -0
      java/org/apache/tomcat/websocket/pojo/LocalStrings_zh_CN.properties
  98. +1
    -1
      modules/owb/pom.xml
  99. +19
    -0
      res/bnd/catalina-ssi.jar.tmp.bnd
  100. +23
    -23
      res/findbugs/filter-false-positives.xml

+ 1
- 0
.gitignore View File

@@ -23,6 +23,7 @@ output
work
build.properties
mvn.properties
.ant-targets-build.xml
.checkstyle
.classpath
.fbprefs


+ 1
- 1
CONTRIBUTING.md View File

@@ -9,7 +9,7 @@ for more information on how to contribute.

## Code of Conduct

This project and everyone participating in it is governed by the Apache
This project and everyone participating in it are governed by the Apache
software Foundation's
[Code of Conduct](https://www.apache.org/foundation/policies/conduct.html). By
participating, you are expected to adhere to this code. If you are aware of


+ 10
- 10
MERGE.txt View File

@@ -36,14 +36,14 @@ BCEL
Sub-tree:
src/main/java/org/apache/bcel
The SHA1 ID for the most recent commit to be merged to Tomcat is:
4b760bb53b57b704006a0a33f7ec187b7e7f5ebc (2019-08-01)
ff6941e4491c68f6eaf270ff03c1bc1e554c7b42 (2019-12-06)

Codec
-----
Sub-tree:
src/main/java/org/apache/commons/codec
The SHA1 ID for the most recent commit to be merged to Tomcat is:
3ebef4ad92e31697fb52ca7cc71904c68654c2c8 (2019-08-01)
9637dd44fa0e2d5a6ddb45791e3cd78298842d95 (2019-12-06)
Note: Only classes required for Base64 encoding/decoding. The rest are removed.

FileUpload
@@ -51,22 +51,22 @@ FileUpload
Sub-tree:
src/main/java/org/apache/commons/fileupload2
The SHA1 ID for the most recent commit to be merged to Tomcat is:
9958ea2426ec5682a7c929a13372c04426ee3818 (2019-08-01)
2317552993fd5180a84083d599b8cbdb05a07bab (2019-12-06)

Note: Tomcat's copy of fileupload also includes classes copied manually from
Commons IO.

DBCP
----
DBCP2
Pool2
Sub-tree
src/main/java/org/apache/commons/dbcp2
src/main/resources/org/apache/commons/dbcp2
src/main/java/org/apache/commons/pool2
The SHA1 ID for the most recent commit to be merged to Tomcat is:
4813b7f5456c1f4fecc4f701ac731a71f57db249 (2019-08-09)
6092f924b36061353ff92b18c88400ab3bc05327 (2019-12-06)

Pool2
DBCP2
Sub-tree
src/main/java/org/apache/commons/pool2
src/main/java/org/apache/commons/dbcp2
src/main/resources/org/apache/commons/dbcp2
The SHA1 ID for the most recent commit to be merged to Tomcat is:
796e32d53cc0d870ba0db3a7faf4c5b24ff76f3f (2019-08-01)
a363906bf7a039f79c07fa3c68b082a69ae035d7 (2019-12-06)

+ 1
- 0
RELEASE-NOTES View File

@@ -70,6 +70,7 @@ for use by web applications (by placing them in "lib"):
* catalina.jar (Tomcat Catalina implementation)
* catalina-ant.jar (Tomcat Catalina Ant tasks)
* catalina-ha.jar (High availability package)
* catalina-ssi.jar (Server-side Includes module)
* catalina-storeconfig.jar (Generation of XML configuration from current state)
* catalina-tribes.jar (Group communication)
* ecj-@JDT_VERSION@.jar (Eclipse JDT Java compiler)


+ 6
- 2
bin/catalina.sh View File

@@ -343,6 +343,10 @@ if [ "$1" = "jpda" ] ; then
shift
fi

# TODO: Bugzilla 63815
# This doesn't currently work (and can't be made to work) if values used in
# CATALINA_OPTS and/or JAVA_OPTS require quoting. See:
# https://bugs.openjdk.java.net/browse/JDK-8234808
if [ "$1" = "debug" ] ; then
if $os400; then
echo "Debug command not available on OS400"
@@ -354,7 +358,7 @@ if [ "$1" = "debug" ] ; then
echo "Using Security Manager"
fi
shift
exec "$_RUNJDB" "$LOGGING_CONFIG" $LOGGING_MANAGER "$JAVA_OPTS" "$CATALINA_OPTS" \
exec "$_RUNJDB" "$LOGGING_CONFIG" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
-D$ENDORSED_PROP="$JAVA_ENDORSED_DIRS" \
-classpath "$CLASSPATH" \
-sourcepath "$CATALINA_HOME"/../../java \
@@ -365,7 +369,7 @@ if [ "$1" = "debug" ] ; then
-Djava.io.tmpdir="$CATALINA_TMPDIR" \
org.apache.catalina.startup.Bootstrap "$@" start
else
exec "$_RUNJDB" "$LOGGING_CONFIG" $LOGGING_MANAGER "$JAVA_OPTS" "$CATALINA_OPTS" \
exec "$_RUNJDB" "$LOGGING_CONFIG" $LOGGING_MANAGER $JAVA_OPTS $CATALINA_OPTS \
-D$ENDORSED_PROP="$JAVA_ENDORSED_DIRS" \
-classpath "$CLASSPATH" \
-sourcepath "$CATALINA_HOME"/../../java \


+ 34
- 32
bin/daemon.sh View File

@@ -199,49 +199,51 @@ fi
case "$1" in
run )
shift
"$JSVC" $* \
$JSVC_OPTS \
-java-home "$JAVA_HOME" \
-pidfile "$CATALINA_PID" \
-wait "$SERVICE_START_WAIT_TIME" \
eval exec "\"$JSVC\"" $* \
"$JSVC_OPTS" \
-java-home "\"$JAVA_HOME\"" \
-pidfile "\"$CATALINA_PID\"" \
-wait $SERVICE_START_WAIT_TIME \
-nodetach \
-outfile "&1" \
-errfile "&2" \
-classpath "$CLASSPATH" \
"$LOGGING_CONFIG" "$JAVA_OPTS" "$CATALINA_OPTS" \
-D$ENDORSED_PROP="$JAVA_ENDORSED_DIRS" \
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMP" \
-outfile "\"&1\"" \
-errfile "\"&2\"" \
-classpath "\"$CLASSPATH\"" \
"\"$LOGGING_CONFIG\"" "$JAVA_OPTS" "$CATALINA_OPTS" \
-D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
-Dcatalina.base="\"$CATALINA_BASE\"" \
-Dcatalina.home="\"$CATALINA_HOME\"" \
-Djava.io.tmpdir="\"$CATALINA_TMP\"" \
$CATALINA_MAIN
exit $?
;;
start )
"$JSVC" $JSVC_OPTS \
-java-home "$JAVA_HOME" \
eval "\"$JSVC\"" \
"$JSVC_OPTS" \
-java-home "\"$JAVA_HOME\"" \
-user $TOMCAT_USER \
-pidfile "$CATALINA_PID" \
-wait "$SERVICE_START_WAIT_TIME" \
-outfile "$CATALINA_OUT" \
-errfile "&1" \
-classpath "$CLASSPATH" \
"$LOGGING_CONFIG" "$JAVA_OPTS" "$CATALINA_OPTS" \
-D$ENDORSED_PROP="$JAVA_ENDORSED_DIRS" \
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMP" \
-pidfile "\"$CATALINA_PID\"" \
-wait $SERVICE_START_WAIT_TIME \
-outfile "\"$CATALINA_OUT\"" \
-errfile "\"&1\"" \
-classpath "\"$CLASSPATH\"" \
"\"$LOGGING_CONFIG\"" "$JAVA_OPTS" "$CATALINA_OPTS" \
-D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
-Dcatalina.base="\"$CATALINA_BASE"\" \
-Dcatalina.home="\"$CATALINA_HOME\"" \
-Djava.io.tmpdir="\"$CATALINA_TMP\"" \
$CATALINA_MAIN
exit $?
;;
stop )
"$JSVC" $JSVC_OPTS \
eval "\"$JSVC\"" \
"$JSVC_OPTS" \
-stop \
-pidfile "$CATALINA_PID" \
-classpath "$CLASSPATH" \
-D$ENDORSED_PROP="$JAVA_ENDORSED_DIRS" \
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMP" \
-pidfile "\"$CATALINA_PID\"" \
-classpath "\"$CLASSPATH\"" \
-D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
-Dcatalina.base="\"$CATALINA_BASE\"" \
-Dcatalina.home="\"$CATALINA_HOME\"" \
-Djava.io.tmpdir="\"$CATALINA_TMP\"" \
$CATALINA_MAIN
exit $?
;;


+ 4
- 4
bin/tool-wrapper.sh View File

@@ -146,8 +146,8 @@ JAVA_OPTS="$JAVA_OPTS -Djava.util.logging.manager=org.apache.juli.ClassLoaderLog

# ----- Execute The Requested Command -----------------------------------------

exec "$_RUNJAVA" "$JAVA_OPTS" $TOOL_OPTS \
-D$ENDORSED_PROP="$JAVA_ENDORSED_DIRS" \
-classpath "$CLASSPATH" \
-Dcatalina.home="$CATALINA_HOME" \
eval exec "\"$_RUNJAVA\"" "$JAVA_OPTS" "$TOOL_OPTS" \
-D$ENDORSED_PROP="\"$JAVA_ENDORSED_DIRS\"" \
-classpath "\"$CLASSPATH\"" \
-Dcatalina.home="\"$CATALINA_HOME\"" \
org.apache.catalina.startup.Tool "$@"

+ 1
- 1
build.properties.default View File

@@ -25,7 +25,7 @@
# ----- Version Control Flags -----
version.major=9
version.minor=0
version.build=29
version.build=30
version.patch=0
version.suffix=



+ 18
- 0
build.xml View File

@@ -110,6 +110,7 @@
<property name="tomcat-websocket.jar" value="${tomcat.build}/lib/tomcat-websocket.jar"/>
<property name="catalina.jar" value="${tomcat.build}/lib/catalina.jar"/>
<property name="catalina-tribes.jar" value="${tomcat.build}/lib/catalina-tribes.jar"/>
<property name="catalina-ssi.jar" value="${tomcat.build}/lib/catalina-ssi.jar"/>
<property name="catalina-ha.jar" value="${tomcat.build}/lib/catalina-ha.jar"/>
<property name="catalina-ant.jar" value="${tomcat.build}/lib/catalina-ant.jar"/>
<property name="catalina-storeconfig.jar" value="${tomcat.build}/lib/catalina-storeconfig.jar"/>
@@ -136,6 +137,7 @@
<property name="tomcat-websocket-src.jar" value="${tomcat.src.jars}/tomcat-websocket-src.jar"/>
<property name="catalina-src.jar" value="${tomcat.src.jars}/catalina-src.jar"/>
<property name="catalina-tribes-src.jar" value="${tomcat.src.jars}/catalina-tribes-src.jar"/>
<property name="catalina-ssi-src.jar" value="${tomcat.src.jars}/catalina-ssi-src.jar"/>
<property name="catalina-ha-src.jar" value="${tomcat.src.jars}/catalina-ha-src.jar"/>
<property name="catalina-ant-src.jar" value="${tomcat.src.jars}/catalina-ant-src.jar"/>
<property name="catalina-storeconfig-src.jar" value="${tomcat.src.jars}/catalina-storeconfig-src.jar"/>
@@ -420,12 +422,17 @@
<exclude name="org/apache/catalina/ha/**" />
<exclude name="org/apache/catalina/tribes/**" />
<exclude name="org/apache/catalina/storeconfig/**" />
<exclude name="org/apache/catalina/ssi/**" />
</patternset>

<patternset id="files.catalina-tribes">
<include name="org/apache/catalina/tribes/**" />
</patternset>

<patternset id="files.catalina-ssi">
<include name="org/apache/catalina/ssi/**" />
</patternset>

<patternset id="files.catalina-ha">
<include name="org/apache/catalina/ha/**" />
</patternset>
@@ -834,6 +841,12 @@
filesId="files.catalina-tribes"
addOSGi="true" />

<!-- Server-Side Includes (SSI) -->
<jarIt jarfile="${catalina-ssi.jar}"
filesDir="${tomcat.classes}"
filesId="files.catalina-ssi"
addOSGi="true" />

<!-- Catalina Cluster/HA JAR File -->
<jarIt jarfile="${catalina-ha.jar}"
filesDir="${tomcat.classes}"
@@ -2644,6 +2657,11 @@ skip.installer property in build.properties" />
filesDir="java"
filesId="files.catalina-tribes" />

<!-- Catalina SSI JAR File -->
<jarIt jarfile="${catalina-ssi-src.jar}"
filesDir="java"
filesId="files.catalina-ssi" />

<!-- Catalina Cluster/HA JAR File -->
<jarIt jarfile="${catalina-ha-src.jar}"
filesDir="java"


+ 1
- 0
conf/catalina.properties View File

@@ -115,6 +115,7 @@ aspectj*.jar,\
bootstrap.jar,\
catalina-ant.jar,\
catalina-ha.jar,\
catalina-ssi.jar,\
catalina-storeconfig.jar,\
catalina-tribes.jar,\
catalina.jar,\


+ 33
- 0
java/org/apache/catalina/Manager.java View File

@@ -215,10 +215,43 @@ public interface Manager {
* session ID.
*
* @param session The session to change the session ID for
*
* @deprecated Use {@link #rotateSessionId(Session)}.
* Will be removed in Tomcat 10
*/
@Deprecated
public void changeSessionId(Session session);


/**
* Change the session ID of the current session to a new randomly generated
* session ID.
*
* @param session The session to change the session ID for
*
* @return The new session ID
*/
public default String rotateSessionId(Session session) {
String newSessionId = null;
// Assume there new Id is a duplicate until we prove it isn't. The
// chances of a duplicate are extremely low but the current ManagerBase
// code protects against duplicates so this default method does too.
boolean duplicate = true;
do {
newSessionId = getSessionIdGenerator().generateSessionId();
try {
if (findSession(newSessionId) == null) {
duplicate = false;
}
} catch (IOException ioe) {
// Swallow. An IOE means the ID was known so continue looping
}
} while (duplicate);
changeSessionId(session, newSessionId);
return newSessionId;
}


/**
* Change the session ID of the current session to a specified session ID.
*


+ 20
- 0
java/org/apache/catalina/Realm.java View File

@@ -25,6 +25,8 @@ import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSName;

/**
* A <b>Realm</b> is a read-only facade for an underlying security realm
@@ -116,6 +118,22 @@ public interface Realm extends Contained {
public Principal authenticate(GSSContext gssContext, boolean storeCreds);


/**
* Try to authenticate using a {@link GSSName}
*
* Note that this default method will be turned into an abstract one in
* Tomcat 10.
*
* @param gssName The {@link GSSName} of the principal to look up
* @param gssCredential The {@link GSSCredential} of the principal, may be
* {@code null}
* @return the associated principal, or {@code null} if there is none
*/
public default Principal authenticate(GSSName gssName, GSSCredential gssCredential) {
return null;
}


/**
* Try to authenticate using {@link X509Certificate}s
*
@@ -211,7 +229,9 @@ public interface Realm extends Contained {
* Return roles associated with given principal
* @param principal the {@link Principal} to get the roles for.
* @return principal roles
* @deprecated This will be removed in Tomcat 10.
*/
@Deprecated
public String[] getRoles(Principal principal);




+ 120
- 23
java/org/apache/catalina/authenticator/AuthenticatorBase.java View File

@@ -19,6 +19,7 @@ package org.apache.catalina.authenticator;
import java.io.IOException;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -33,6 +34,7 @@ import javax.security.auth.message.config.AuthConfigProvider;
import javax.security.auth.message.config.RegistrationListener;
import javax.security.auth.message.config.ServerAuthConfig;
import javax.security.auth.message.config.ServerAuthContext;
import javax.servlet.DispatcherType;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
@@ -44,7 +46,6 @@ import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Manager;
import org.apache.catalina.Realm;
import org.apache.catalina.Session;
import org.apache.catalina.TomcatPrincipal;
@@ -53,6 +54,7 @@ import org.apache.catalina.authenticator.jaspic.CallbackHandlerImpl;
import org.apache.catalina.authenticator.jaspic.MessageInfoImpl;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.filters.CorsFilter;
import org.apache.catalina.filters.RemoteIpFilter;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.catalina.util.SessionIdGeneratorBase;
@@ -63,9 +65,12 @@ import org.apache.coyote.ActionCode;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.apache.tomcat.util.descriptor.web.LoginConfig;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.apache.tomcat.util.http.FastHttpDateFormat;
import org.apache.tomcat.util.http.RequestUtil;
import org.apache.tomcat.util.res.StringManager;

/**
@@ -237,12 +242,22 @@ public abstract class AuthenticatorBase extends ValveBase
*/
protected SingleSignOn sso = null;

private AllowCorsPreflight allowCorsPreflight = AllowCorsPreflight.NEVER;

private volatile String jaspicAppContextID = null;
private volatile Optional<AuthConfigProvider> jaspicProvider = null;


// ------------------------------------------------------------- Properties

public String getAllowCorsPreflight() {
return allowCorsPreflight.name().toLowerCase(Locale.ENGLISH);
}

public void setAllowCorsPreflight(String allowCorsPreflight) {
this.allowCorsPreflight = AllowCorsPreflight.valueOf(allowCorsPreflight.trim().toUpperCase(Locale.ENGLISH));
}

public boolean getAlwaysUseSession() {
return alwaysUseSession;
}
@@ -521,7 +536,7 @@ public abstract class AuthenticatorBase extends ValveBase

if (constraints == null && !context.getPreemptiveAuthentication() && !authRequired) {
if (log.isDebugEnabled()) {
log.debug(" Not subject to any constraint");
log.debug("Not subject to any constraint");
}
getNext().invoke(request, response);
return;
@@ -544,11 +559,11 @@ public abstract class AuthenticatorBase extends ValveBase
if (constraints != null) {
// Enforce any user data constraint for this security constraint
if (log.isDebugEnabled()) {
log.debug(" Calling hasUserDataPermission()");
log.debug("Calling hasUserDataPermission()");
}
if (!realm.hasUserDataPermission(request, response, constraints)) {
if (log.isDebugEnabled()) {
log.debug(" Failed hasUserDataPermission() test");
log.debug("Failed hasUserDataPermission() test");
}
/*
* ASSERT: Authenticator already set the appropriate HTTP status
@@ -593,9 +608,17 @@ public abstract class AuthenticatorBase extends ValveBase

JaspicState jaspicState = null;

if ((authRequired || constraints != null) && allowCorsPreflightBypass(request)) {
if (log.isDebugEnabled()) {
log.debug("CORS Preflight request bypassing authentication");
}
getNext().invoke(request, response);
return;
}

if (authRequired) {
if (log.isDebugEnabled()) {
log.debug(" Calling authenticate()");
log.debug("Calling authenticate()");
}

if (jaspicProvider != null) {
@@ -609,7 +632,7 @@ public abstract class AuthenticatorBase extends ValveBase
jaspicProvider != null &&
!authenticateJaspic(request, response, jaspicState, false)) {
if (log.isDebugEnabled()) {
log.debug(" Failed authenticate() test");
log.debug("Failed authenticate() test");
}
/*
* ASSERT: Authenticator already set the appropriate HTTP status
@@ -622,11 +645,11 @@ public abstract class AuthenticatorBase extends ValveBase

if (constraints != null) {
if (log.isDebugEnabled()) {
log.debug(" Calling accessControl()");
log.debug("Calling accessControl()");
}
if (!realm.hasResourcePermission(request, response, constraints, this.context)) {
if (log.isDebugEnabled()) {
log.debug(" Failed accessControl() test");
log.debug("Failed accessControl() test");
}
/*
* ASSERT: AccessControl method has already set the appropriate
@@ -638,7 +661,7 @@ public abstract class AuthenticatorBase extends ValveBase

// Any and all specified constraints have been satisfied
if (log.isDebugEnabled()) {
log.debug(" Successfully passed all security constraints");
log.debug("Successfully passed all security constraints");
}
getNext().invoke(request, response);

@@ -648,6 +671,64 @@ public abstract class AuthenticatorBase extends ValveBase
}


protected boolean allowCorsPreflightBypass(Request request) {
boolean allowBypass = false;

if (allowCorsPreflight != AllowCorsPreflight.NEVER) {
// First check to see if this is a CORS Preflight request
// This is a subset of the tests in CorsFilter.checkRequestType
if ("OPTIONS".equals(request.getMethod())) {
String originHeader = request.getHeader(CorsFilter.REQUEST_HEADER_ORIGIN);
if (originHeader != null &&
!originHeader.isEmpty() &&
RequestUtil.isValidOrigin(originHeader) &&
!RequestUtil.isSameOrigin(request, originHeader)) {
String accessControlRequestMethodHeader =
request.getHeader(CorsFilter.REQUEST_HEADER_ACCESS_CONTROL_REQUEST_METHOD);
if (accessControlRequestMethodHeader != null &&
!accessControlRequestMethodHeader.isEmpty()) {
// This appears to be a CORS Preflight request
if (allowCorsPreflight == AllowCorsPreflight.ALWAYS) {
allowBypass = true;
} else if (allowCorsPreflight == AllowCorsPreflight.FILTER) {
if (DispatcherType.REQUEST == request.getDispatcherType()) {
// Look at Filter configuration for the Context
// Can't cache this unless we add a listener to
// the Context to clear the cache on reload
for (FilterDef filterDef : request.getContext().findFilterDefs()) {
if (CorsFilter.class.getName().equals(filterDef.getFilterClass())) {
for (FilterMap filterMap : context.findFilterMaps()) {
if (filterMap.getFilterName().equals(filterDef.getFilterName())) {
if ((filterMap.getDispatcherMapping() & FilterMap.REQUEST) > 0) {
for (String urlPattern : filterMap.getURLPatterns()) {
if ("/*".equals(urlPattern)) {
allowBypass = true;
// No need to check other patterns
break;
}
}
}
// Found mappings for CORS filter.
// No need to look further
break;
}
}
// Found the CORS filter. No need to look further.
break;
}
}
}
} else {
// Unexpected enum type
}
}
}
}
}
return allowBypass;
}


@Override
public boolean authenticate(Request request, HttpServletResponse httpResponse)
throws IOException {
@@ -986,7 +1067,7 @@ public abstract class AuthenticatorBase extends ValveBase
associate(ssoId, request.getSessionInternal(true));

if (log.isDebugEnabled()) {
log.debug(" Reauthenticated cached principal '" +
log.debug("Reauthenticated cached principal '" +
request.getUserPrincipal().getName() +
"' with auth type '" + request.getAuthType() + "'");
}
@@ -1044,17 +1125,11 @@ public abstract class AuthenticatorBase extends ValveBase
if (session != null) {
// If the principal is null then this is a logout. No need to change
// the session ID. See BZ 59043.
if (changeSessionIdOnAuthentication && principal != null) {
String oldId = null;
if (log.isDebugEnabled()) {
oldId = session.getId();
}
Manager manager = request.getContext().getManager();
manager.changeSessionId(session);
request.changeSessionId(session.getId());
if (log.isDebugEnabled()) {
log.debug(sm.getString("authenticator.changeSessionId",
oldId, session.getId()));
if (getChangeSessionIdOnAuthentication() && principal != null) {
String newSessionId = changeSessionID(request, session);
// If the current session ID is being tracked, update it.
if (session.getNote(Constants.SESSION_ID_NOTE) != null) {
session.setNote(Constants.SESSION_ID_NOTE, newSessionId);
}
}
} else if (alwaysUseSession) {
@@ -1062,10 +1137,11 @@ public abstract class AuthenticatorBase extends ValveBase
}

// Cache the authentication information in our session, if any
if (cache) {
if (session != null) {
if (session != null) {
if (cache) {
session.setAuthType(authType);
session.setPrincipal(principal);
} else {
if (username != null) {
session.setNote(Constants.SESS_USERNAME_NOTE, username);
} else {
@@ -1142,6 +1218,20 @@ public abstract class AuthenticatorBase extends ValveBase

}


protected String changeSessionID(Request request, Session session) {
String oldId = null;
if (log.isDebugEnabled()) {
oldId = session.getId();
}
String newId = request.changeSessionId();
if (log.isDebugEnabled()) {
log.debug(sm.getString("authenticator.changeSessionId", oldId, newId));
}
return newId;
}


@Override
public void login(String username, String password, Request request) throws ServletException {
Principal principal = doLogin(request, username, password);
@@ -1301,4 +1391,11 @@ public abstract class AuthenticatorBase extends ValveBase
public MessageInfo messageInfo = null;
public ServerAuthContext serverAuthContext = null;
}


protected enum AllowCorsPreflight {
NEVER,
FILTER,
ALWAYS
}
}

+ 18
- 30
java/org/apache/catalina/authenticator/Constants.java View File

@@ -14,11 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/


package org.apache.catalina.authenticator;


public class Constants {
// Authentication methods for login configuration
// Servlet spec schemes are defined in HttpServletRequest
@@ -33,17 +30,13 @@ public class Constants {
// SPNEGO authentication constants
public static final String KRB5_CONF_PROPERTY = "java.security.krb5.conf";
public static final String DEFAULT_KRB5_CONF = "conf/krb5.ini";
public static final String JAAS_CONF_PROPERTY =
"java.security.auth.login.config";
public static final String JAAS_CONF_PROPERTY = "java.security.auth.login.config";
public static final String DEFAULT_JAAS_CONF = "conf/jaas.conf";
public static final String DEFAULT_LOGIN_MODULE_NAME =
"com.sun.security.jgss.krb5.accept";
public static final String DEFAULT_LOGIN_MODULE_NAME = "com.sun.security.jgss.krb5.accept";

// Cookie name for single sign on support
public static final String SINGLE_SIGN_ON_COOKIE =
System.getProperty(
"org.apache.catalina.authenticator.Constants.SSO_SESSION_COOKIE_NAME",
"JSESSIONIDSSO");
public static final String SINGLE_SIGN_ON_COOKIE = System.getProperty(
"org.apache.catalina.authenticator.Constants.SSO_SESSION_COOKIE_NAME", "JSESSIONIDSSO");


// --------------------------------------------------------- Request Notes
@@ -52,16 +45,18 @@ public class Constants {
* The notes key to track the single-sign-on identity with which this
* request is associated.
*/
public static final String REQ_SSOID_NOTE =
"org.apache.catalina.request.SSOID";

public static final String REQ_SSOID_NOTE = "org.apache.catalina.request.SSOID";

public static final String REQ_JASPIC_SUBJECT_NOTE =
"org.apache.catalina.authenticator.jaspic.SUBJECT";
public static final String REQ_JASPIC_SUBJECT_NOTE = "org.apache.catalina.authenticator.jaspic.SUBJECT";


// ---------------------------------------------------------- Session Notes

/**
* The session id used as a CSRF marker when redirecting a user's request.
*/
public static final String SESSION_ID_NOTE = "org.apache.catalina.authenticator.SESSION_ID";


/**
* If the <code>cache</code> property of our authenticator is set, and
@@ -70,19 +65,15 @@ public class Constants {
* <code>Realm.authenticate()</code>, under the following keys:
*/


/**
* The notes key for the password used to authenticate this user.
*/
public static final String SESS_PASSWORD_NOTE =
"org.apache.catalina.session.PASSWORD";

public static final String SESS_PASSWORD_NOTE = "org.apache.catalina.session.PASSWORD";

/**
* The notes key for the username used to authenticate this user.
*/
public static final String SESS_USERNAME_NOTE =
"org.apache.catalina.session.USERNAME";
public static final String SESS_USERNAME_NOTE = "org.apache.catalina.session.USERNAME";


/**
@@ -90,20 +81,17 @@ public class Constants {
* cache required information prior to the completion of authentication.
*/


/**
* The previously authenticated principal (if caching is disabled).
*
* @deprecated Unused. Will be removed in Tomcat 10.
*/
public static final String FORM_PRINCIPAL_NOTE =
"org.apache.catalina.authenticator.PRINCIPAL";

@Deprecated
public static final String FORM_PRINCIPAL_NOTE = "org.apache.catalina.authenticator.PRINCIPAL";

/**
* The original request information, to which the user will be
* redirected if authentication succeeds.
*/
public static final String FORM_REQUEST_NOTE =
"org.apache.catalina.authenticator.REQUEST";


public static final String FORM_REQUEST_NOTE = "org.apache.catalina.authenticator.REQUEST";
}

+ 44
- 63
java/org/apache/catalina/authenticator/FormAuthenticator.java View File

@@ -28,7 +28,6 @@ import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.Manager;
import org.apache.catalina.Realm;
import org.apache.catalina.Session;
import org.apache.catalina.connector.Request;
@@ -133,10 +132,6 @@ public class FormAuthenticator
protected boolean doAuthenticate(Request request, HttpServletResponse response)
throws IOException {

if (checkForCachedAuthentication(request, response, true)) {
return true;
}

// References to objects we will need later
Session session = null;
Principal principal = null;
@@ -147,22 +142,16 @@ public class FormAuthenticator
if (log.isDebugEnabled()) {
log.debug("Checking for reauthenticate in session " + session);
}
String username =
(String) session.getNote(Constants.SESS_USERNAME_NOTE);
String password =
(String) session.getNote(Constants.SESS_PASSWORD_NOTE);
if ((username != null) && (password != null)) {
String username = (String) session.getNote(Constants.SESS_USERNAME_NOTE);
String password = (String) session.getNote(Constants.SESS_PASSWORD_NOTE);
if (username != null && password != null) {
if (log.isDebugEnabled()) {
log.debug("Reauthenticating username '" + username + "'");
}
principal =
context.getRealm().authenticate(username, password);
principal = context.getRealm().authenticate(username, password);
if (principal != null) {
session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password);
if (!matchRequest(request)) {
register(request, response, principal,
HttpServletRequest.FORM_AUTH,
username, password);
return true;
}
}
@@ -177,20 +166,7 @@ public class FormAuthenticator
if (matchRequest(request)) {
session = request.getSessionInternal(true);
if (log.isDebugEnabled()) {
log.debug("Restore request from session '"
+ session.getIdInternal()
+ "'");
}
principal = (Principal)
session.getNote(Constants.FORM_PRINCIPAL_NOTE);
register(request, response, principal, HttpServletRequest.FORM_AUTH,
(String) session.getNote(Constants.SESS_USERNAME_NOTE),
(String) session.getNote(Constants.SESS_PASSWORD_NOTE));
// If we're caching principals we no longer need the username
// and password in the session, so remove them
if (cache) {
session.removeNote(Constants.SESS_USERNAME_NOTE);
session.removeNote(Constants.SESS_PASSWORD_NOTE);
log.debug("Restore request from session '" + session.getIdInternal() + "'");
}
if (restoreRequest(request, session)) {
if (log.isDebugEnabled()) {
@@ -206,14 +182,18 @@ public class FormAuthenticator
}
}

// This check has to be after the previous check for a matching request
// because that matching request may also include a cached Principal.
if (checkForCachedAuthentication(request, response, true)) {
return true;
}

// Acquire references to objects we will need to evaluate
String contextPath = request.getContextPath();
String requestURI = request.getDecodedRequestURI();

// Is this the action request from the login page?
boolean loginAction =
requestURI.startsWith(contextPath) &&
requestURI.endsWith(Constants.FORM_ACTION);
boolean loginAction = requestURI.startsWith(contextPath) && requestURI.endsWith(Constants.FORM_ACTION);

LoginConfig config = context.getLoginConfig();

@@ -241,8 +221,7 @@ public class FormAuthenticator
saveRequest(request, session);
} catch (IOException ioe) {
log.debug("Request body too big to save during authentication");
response.sendError(HttpServletResponse.SC_FORBIDDEN,
sm.getString("authenticator.requestBodyTooBig"));
response.sendError(HttpServletResponse.SC_FORBIDDEN, sm.getString("authenticator.requestBodyTooBig"));
return false;
}
forwardToLoginPage(request, response, config);
@@ -274,14 +253,21 @@ public class FormAuthenticator
if (session == null) {
session = request.getSessionInternal(false);
}
if (session != null && getChangeSessionIdOnAuthentication()) {
// Does session id match?
String expectedSessionId = (String) session.getNote(Constants.SESSION_ID_NOTE);
if (expectedSessionId == null || !expectedSessionId.equals(request.getRequestedSessionId())) {
session.expire();
session = null;
}
}
if (session == null) {
if (containerLog.isDebugEnabled()) {
containerLog.debug
("User took so long to log on the session expired");
containerLog.debug("User took so long to log on the session expired");
}
if (landingPage == null) {
response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT,
sm.getString("authenticator.sessionExpired"));
response.sendError(
HttpServletResponse.SC_REQUEST_TIMEOUT, sm.getString("authenticator.sessionExpired"));
} else {
// Make the authenticator think the user originally requested
// the landing page
@@ -290,19 +276,13 @@ public class FormAuthenticator
saved.setMethod("GET");
saved.setRequestURI(uri);
saved.setDecodedRequestURI(uri);
request.getSessionInternal(true).setNote(
Constants.FORM_REQUEST_NOTE, saved);
request.getSessionInternal(true).setNote(Constants.FORM_REQUEST_NOTE, saved);
response.sendRedirect(response.encodeRedirectURL(uri));
}
return false;
}

// Save the authenticated Principal in our session
session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);

// Save the username and password as well
session.setNote(Constants.SESS_USERNAME_NOTE, username);
session.setNote(Constants.SESS_PASSWORD_NOTE, password);
register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password);

// Redirect the user to the original request URI (which will cause
// the original request to be restored)
@@ -312,8 +292,7 @@ public class FormAuthenticator
}
if (requestURI == null) {
if (landingPage == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
sm.getString("authenticator.formlogin"));
response.sendError(HttpServletResponse.SC_BAD_REQUEST, sm.getString("authenticator.formlogin"));
} else {
// Make the authenticator think the user originally requested
// the landing page
@@ -331,15 +310,12 @@ public class FormAuthenticator
Response internalResponse = request.getResponse();
String location = response.encodeRedirectURL(requestURI);
if ("HTTP/1.1".equals(request.getProtocol())) {
internalResponse.sendRedirect(location,
HttpServletResponse.SC_SEE_OTHER);
internalResponse.sendRedirect(location, HttpServletResponse.SC_SEE_OTHER);
} else {
internalResponse.sendRedirect(location,
HttpServletResponse.SC_FOUND);
internalResponse.sendRedirect(location, HttpServletResponse.SC_FOUND);
}
}
return false;

}


@@ -414,9 +390,8 @@ public class FormAuthenticator
if (getChangeSessionIdOnAuthentication()) {
Session session = request.getSessionInternal(false);
if (session != null) {
Manager manager = request.getContext().getManager();
manager.changeSessionId(session);
request.changeSessionId(session.getId());
String newSessionId = changeSessionID(request, session);
session.setNote(Constants.SESSION_ID_NOTE, newSessionId);
}
}

@@ -503,17 +478,24 @@ public class FormAuthenticator
}

// Is there a saved request?
SavedRequest sreq =
(SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
SavedRequest sreq = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
if (sreq == null) {
return false;
}

// Is there a saved principal?
if (session.getNote(Constants.FORM_PRINCIPAL_NOTE) == null) {
if (cache && session.getPrincipal() == null || !cache && request.getPrincipal() == null) {
return false;
}

// Does session id match?
if (getChangeSessionIdOnAuthentication()) {
String expectedSessionId = (String) session.getNote(Constants.SESSION_ID_NOTE);
if (expectedSessionId == null || !expectedSessionId.equals(request.getRequestedSessionId())) {
return false;
}
}

// Does the request URI match?
String decodedRequestURI = request.getDecodedRequestURI();
if (decodedRequestURI == null) {
@@ -538,10 +520,9 @@ public class FormAuthenticator
throws IOException {

// Retrieve and remove the SavedRequest object from our session
SavedRequest saved = (SavedRequest)
session.getNote(Constants.FORM_REQUEST_NOTE);
SavedRequest saved = (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE);
session.removeNote(Constants.FORM_REQUEST_NOTE);
session.removeNote(Constants.FORM_PRINCIPAL_NOTE);
session.removeNote(Constants.SESSION_ID_NOTE);
if (saved == null) {
return false;
}


+ 4
- 5
java/org/apache/catalina/connector/Request.java View File

@@ -105,10 +105,10 @@ import org.apache.tomcat.util.http.Parameters.FailReason;
import org.apache.tomcat.util.http.ServerCookie;
import org.apache.tomcat.util.http.ServerCookies;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUploadBase;
import org.apache.tomcat.util.http.fileupload.FileUploadBase.InvalidContentTypeException;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.impl.InvalidContentTypeException;
import org.apache.tomcat.util.http.fileupload.impl.SizeException;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
import org.apache.tomcat.util.http.parser.AcceptLanguage;
@@ -2675,9 +2675,8 @@ public class Request implements HttpServletRequest {
}

Manager manager = this.getContext().getManager();
manager.changeSessionId(session);

String newSessionId = session.getId();
String newSessionId = manager.rotateSessionId(session);
this.changeSessionId(newSessionId);

return newSessionId;
@@ -2906,7 +2905,7 @@ public class Request implements HttpServletRequest {
} catch (InvalidContentTypeException e) {
parameters.setParseFailedReason(FailReason.INVALID_CONTENT_TYPE);
partsParseException = new ServletException(e);
} catch (FileUploadBase.SizeException e) {
} catch (SizeException e) {
parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);
checkSwallowInput();
partsParseException = new IllegalStateException(e);


+ 1
- 1
java/org/apache/catalina/connector/mbeans-descriptors.xml View File

@@ -83,7 +83,7 @@

<!-- Common -->
<attribute name="keepAliveTimeout"
description="The number of seconds Tomcat will wait for a subsequent request before closing the connection"
description="The number of milliseconds Tomcat will wait for a subsequent request before closing the connection"
type="int"/>

<attribute name="localPort"


+ 4
- 0
java/org/apache/catalina/core/LocalStrings_fr.properties View File

@@ -94,6 +94,10 @@ aprListener.wrongFIPSMode=Valuer inattendue de l''option FIPSMode de AprLifecycl
asyncContextImpl.asyncDispachError=Erreur lors d'un dispatch asynchrone
asyncContextImpl.asyncRunnableError=Erreur lors du traitement asynchrone du Runnable via AsyncContext.start()
asyncContextImpl.dispatchingStarted=Une opération de dispatch asynchrone a déjà été appelée, plusieurs dispatch au cours d'un même cycle asynchrone n'est pas autorisé
asyncContextImpl.fireOnComplete=Déclenchement de l'évènement onComplete() sur tous les AsyncListeners
asyncContextImpl.fireOnError=Déclenchement de l'évènement onError() sur tous les AsyncListeners
asyncContextImpl.fireOnStartAsync=Déclenchement de l'évènement onStartAsync() sur tous les AsyncListeners
asyncContextImpl.fireOnTimeout=Déclenchement de l'évènement onTimeout() sur tous les AsyncListeners
asyncContextImpl.noAsyncDispatcher=Le Servlet dispatcher retourné par le ServletContext ne supporte pas de dispatch asynchrone
asyncContextImpl.onCompleteError=L''appel à onComplete() a échoué pour l''écouteur de type [{0}]
asyncContextImpl.onErrorError=L''appel à onError() a échoué pour l''écouteur de type [{0}]


+ 4
- 0
java/org/apache/catalina/core/LocalStrings_ko.properties View File

@@ -94,6 +94,10 @@ aprListener.wrongFIPSMode=예기치 않은 AprLifecycleListener의 FIPSMode 옵
asyncContextImpl.asyncDispachError=비동기 디스패치 도중 오류 발생
asyncContextImpl.asyncRunnableError=AsyncContext.start()를 통해, 비동기로 Runnable을 처리하는 도중 오류 발생
asyncContextImpl.dispatchingStarted=비동기 디스패치 오퍼레이션이 이미 호출되었습니다. 동일한 비동기 사이클 내에서, 추가적인 비동기 디스패치 오퍼레이션은 허용되지 않습니다.
asyncContextImpl.fireOnComplete=등록된 AsyncListener들에 onComplete() 이벤트를 호출합니다.
asyncContextImpl.fireOnError=등록된 AsyncListener들에 onError() 이벤트를 호출합니다.
asyncContextImpl.fireOnStartAsync=등록된 AsyncListener들에 onStartAsync() 이벤트를 호출합니다.
asyncContextImpl.fireOnTimeout=등록된 AsyncListener들에 onTimeout() 이벤트를 호출합니다.
asyncContextImpl.noAsyncDispatcher=ServletContext로부터 반환된 디스패처는 비동기 디스패치를 지원하지 않습니다.
asyncContextImpl.onCompleteError=타입 [{0}]의 리스너를 위한 onComplete() 호출이 실패했습니다.
asyncContextImpl.onErrorError=타입 [{0}]의 리스너를 위한 onError() 호출이 실패했습니다.


+ 1
- 1
java/org/apache/catalina/filters/Constants.java View File

@@ -72,6 +72,6 @@ public final class Constants {
* The servlet context attribute key under which the
* CSRF REST header name can be found.
*/
public static final String CSRF_REST_NONCE_HEDAER_NAME_KEY =
public static final String CSRF_REST_NONCE_HEADER_NAME_KEY =
"org.apache.catalina.filters.CSRF_REST_NONCE_HEADER_NAME";
}

+ 8
- 59
java/org/apache/catalina/filters/CorsFilter.java View File

@@ -19,7 +19,6 @@ package org.apache.catalina.filters;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -39,6 +38,7 @@ import javax.servlet.http.HttpServletResponse;

import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.http.RequestUtil;
import org.apache.tomcat.util.http.ResponseUtil;
import org.apache.tomcat.util.res.StringManager;

@@ -589,9 +589,9 @@ public class CorsFilter extends GenericFilter {
if (originHeader != null) {
if (originHeader.isEmpty()) {
requestType = CORSRequestType.INVALID_CORS;
} else if (!isValidOrigin(originHeader)) {
} else if (!RequestUtil.isValidOrigin(originHeader)) {
requestType = CORSRequestType.INVALID_CORS;
} else if (isLocalOrigin(request, originHeader)) {
} else if (RequestUtil.isSameOrigin(request, originHeader)) {
return CORSRequestType.NOT_CORS;
} else {
String method = request.getMethod();
@@ -634,36 +634,6 @@ public class CorsFilter extends GenericFilter {
}


private boolean isLocalOrigin(HttpServletRequest request, String origin) {

// Build scheme://host:port from request
StringBuilder target = new StringBuilder();
String scheme = request.getScheme();
if (scheme == null) {
return false;
} else {
scheme = scheme.toLowerCase(Locale.ENGLISH);
}
target.append(scheme);
target.append("://");

String host = request.getServerName();
if (host == null) {
return false;
}
target.append(host);

int port = request.getServerPort();
if ("http".equals(scheme) && port != 80 ||
"https".equals(scheme) && port != 443) {
target.append(':');
target.append(port);
}

return origin.equalsIgnoreCase(target.toString());
}


/**
* Return the lower case, trimmed value of the media type from the content
* type.
@@ -812,34 +782,13 @@ public class CorsFilter extends GenericFilter {
* @param origin The origin URI
* @return <code>true</code> if the origin was valid
* @see <a href="http://tools.ietf.org/html/rfc952">RFC952</a>
*
* @deprecated This will be removed in Tomcat 10
* Use {@link RequestUtil#isValidOrigin(String)}
*/
@Deprecated
protected static boolean isValidOrigin(String origin) {
// Checks for encoded characters. Helps prevent CRLF injection.
if (origin.contains("%")) {
return false;
}

// "null" is a valid origin
if ("null".equals(origin)) {
return true;
}

// RFC6454, section 4. "If uri-scheme is file, the implementation MAY
// return an implementation-defined value.". No limits are placed on
// that value so treat all file URIs as valid origins.
if (origin.startsWith("file://")) {
return true;
}

URI originURI;
try {
originURI = new URI(origin);
} catch (URISyntaxException e) {
return false;
}
// If scheme for URI is null, return false. Return true otherwise.
return originURI.getScheme() != null;

return RequestUtil.isValidOrigin(origin);
}




+ 78
- 6
java/org/apache/catalina/filters/CsrfPreventionFilter.java View File

@@ -24,6 +24,7 @@ import java.util.Map;
import java.util.Set;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -32,6 +33,9 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession;

import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;

/**
* Provides basic CSRF protection for a web application. The filter assumes
* that:
@@ -43,11 +47,14 @@ import javax.servlet.http.HttpSession;
* </ul>
*/
public class CsrfPreventionFilter extends CsrfPreventionFilterBase {
private final Log log = LogFactory.getLog(CsrfPreventionFilter.class);

private final Set<String> entryPoints = new HashSet<>();

private int nonceCacheSize = 5;

private String nonceRequestParameterName = Constants.CSRF_NONCE_REQUEST_PARAM;

/**
* Entry points are URLs that will not be tested for the presence of a valid
* nonce. They are used to provide a way to navigate back to a protected
@@ -78,6 +85,27 @@ public class CsrfPreventionFilter extends CsrfPreventionFilterBase {
this.nonceCacheSize = nonceCacheSize;
}

/**
* Sets the request parameter name to use for CSRF nonces.
*
* @param parameterName The request parameter name to use
* for CSRF nonces.
*/
public void setNonceRequestParameterName(String parameterName) {
this.nonceRequestParameterName = parameterName;
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Set the parameters
super.init(filterConfig);

// Put the expected request parameter name into the application scope
filterConfig.getServletContext().setAttribute(
Constants.CSRF_NONCE_REQUEST_PARAM_NAME_KEY,
nonceRequestParameterName);
}

@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
@@ -94,6 +122,10 @@ public class CsrfPreventionFilter extends CsrfPreventionFilterBase {

if (Constants.METHOD_GET.equals(req.getMethod())
&& entryPoints.contains(getRequestedPath(req))) {
if(log.isTraceEnabled()) {
log.trace("Skipping CSRF nonce-check for GET request to entry point " + getRequestedPath(req));
}

skipNonceCheck = true;
}

@@ -106,18 +138,56 @@ public class CsrfPreventionFilter extends CsrfPreventionFilterBase {

if (!skipNonceCheck) {
String previousNonce =
req.getParameter(Constants.CSRF_NONCE_REQUEST_PARAM);
req.getParameter(nonceRequestParameterName);

if(previousNonce == null) {
if(log.isDebugEnabled()) {
log.debug("Rejecting request for " + getRequestedPath(req)
+ ", session "
+ (null == session ? "(none)" : session.getId())
+ " with no CSRF nonce found in request");
}

if (nonceCache == null || previousNonce == null ||
!nonceCache.contains(previousNonce)) {
res.sendError(getDenyStatus());
return;
} else if(nonceCache == null) {
if(log.isDebugEnabled()) {
log.debug("Rejecting request for " + getRequestedPath(req)
+ ", session "
+ (null == session ? "(none)" : session.getId())
+ " due to empty / missing nonce cache");
}

res.sendError(getDenyStatus());
return;
} else if(!nonceCache.contains(previousNonce)) {
if(log.isDebugEnabled()) {
log.debug("Rejecting request for " + getRequestedPath(req)
+ ", session "
+ (null == session ? "(none)" : session.getId())
+ " due to invalid nonce " + previousNonce);
}

res.sendError(getDenyStatus());
return;
}
if(log.isTraceEnabled()) {
log.trace("Allowing request to " + getRequestedPath(req)
+ " with valid CSRF nonce " + previousNonce);
}
}

if (nonceCache == null) {
if(log.isDebugEnabled()) {
log.debug("Creating new CSRF nonce cache with size=" + nonceCacheSize + " for session " + (null == session ? "(will create)" : session.getId()));
}

nonceCache = new LruCache<>(nonceCacheSize);
if (session == null) {
if(log.isDebugEnabled()) {
log.debug("Creating new session to store CSRF nonce cache");
}

session = req.getSession(true);
}
session.setAttribute(
@@ -133,7 +203,7 @@ public class CsrfPreventionFilter extends CsrfPreventionFilterBase {
// requiring the use of response.encodeURL.
request.setAttribute(Constants.CSRF_NONCE_REQUEST_ATTR_NAME, newNonce);

wResponse = new CsrfResponseWrapper(res, newNonce);
wResponse = new CsrfResponseWrapper(res, nonceRequestParameterName, newNonce);
} else {
wResponse = response;
}
@@ -145,10 +215,12 @@ public class CsrfPreventionFilter extends CsrfPreventionFilterBase {
protected static class CsrfResponseWrapper
extends HttpServletResponseWrapper {

private final String nonceRequestParameterName;
private final String nonce;

public CsrfResponseWrapper(HttpServletResponse response, String nonce) {
public CsrfResponseWrapper(HttpServletResponse response, String nonceRequestParameterName, String nonce) {
super(response);
this.nonceRequestParameterName = nonceRequestParameterName;
this.nonce = nonce;
}

@@ -203,7 +275,7 @@ public class CsrfPreventionFilter extends CsrfPreventionFilterBase {
} else {
sb.append('?');
}
sb.append(Constants.CSRF_NONCE_REQUEST_PARAM);
sb.append(nonceRequestParameterName);
sb.append('=');
sb.append(nonce);
sb.append(anchor);


+ 0
- 10
java/org/apache/catalina/filters/CsrfPreventionFilterBase.java View File

@@ -78,16 +78,6 @@ public abstract class CsrfPreventionFilterBase extends FilterBase {
// Set the parameters
super.init(filterConfig);

// Put the expected request parameter name into the application scope
filterConfig.getServletContext().setAttribute(
Constants.CSRF_NONCE_REQUEST_PARAM_NAME_KEY,
Constants.CSRF_NONCE_REQUEST_PARAM);

// Put the expected request header name into the application scope
filterConfig.getServletContext().setAttribute(
Constants.CSRF_REST_NONCE_HEDAER_NAME_KEY,
Constants.CSRF_REST_NONCE_HEADER_NAME);

try {
Class<?> clazz = Class.forName(randomClass);
randomSource = (Random) clazz.getConstructor().newInstance();


+ 12
- 0
java/org/apache/catalina/filters/RestCsrfPreventionFilter.java View File

@@ -25,6 +25,7 @@ import java.util.function.Predicate;
import java.util.regex.Pattern;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -88,6 +89,17 @@ public class RestCsrfPreventionFilter extends CsrfPreventionFilterBase {

private String pathsDelimiter = ",";

@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Set the parameters
super.init(filterConfig);

// Put the expected request header name into the application scope
filterConfig.getServletContext().setAttribute(
Constants.CSRF_REST_NONCE_HEADER_NAME_KEY,
Constants.CSRF_REST_NONCE_HEADER_NAME);
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {


+ 1
- 0
java/org/apache/catalina/ha/deploy/LocalStrings_zh_CN.properties View File

@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

farmWarDeployer.deleteFail=无法删除 [{0}]
farmWarDeployer.hostOnly=FarmWarDeployer 只有做为 host cluster 的子元素是才生效
farmWarDeployer.mbeanNameFail=无法为引擎[{0}]和主机[{1}]构造MBean对象名
farmWarDeployer.modInstall=从 [{1}] 安装 webapp [{0}]


+ 51
- 9
java/org/apache/catalina/realm/CombinedRealm.java View File

@@ -29,9 +29,11 @@ import org.apache.catalina.Container;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Realm;
import org.apache.catalina.Wrapper;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSName;

@@ -346,22 +348,18 @@ public class CombinedRealm extends RealmBase {
public Principal authenticate(GSSContext gssContext, boolean storeCred) {
if (gssContext.isEstablished()) {
Principal authenticatedUser = null;
String username = null;

GSSName name = null;
GSSName gssName = null;
try {
name = gssContext.getSrcName();
gssName = gssContext.getSrcName();
} catch (GSSException e) {
log.warn(sm.getString("realmBase.gssNameFail"), e);
return null;
}

username = name.toString();

for (Realm realm : realms) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("combinedRealm.authStart",
username, realm.getClass().getName()));
gssName, realm.getClass().getName()));
}

authenticatedUser = realm.authenticate(gssContext, storeCred);
@@ -369,12 +367,12 @@ public class CombinedRealm extends RealmBase {
if (authenticatedUser == null) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("combinedRealm.authFail",
username, realm.getClass().getName()));
gssName, realm.getClass().getName()));
}
} else {
if (log.isDebugEnabled()) {
log.debug(sm.getString("combinedRealm.authSuccess",
username, realm.getClass().getName()));
gssName, realm.getClass().getName()));
}
break;
}
@@ -386,6 +384,50 @@ public class CombinedRealm extends RealmBase {
return null;
}

/**
* {@inheritDoc}
*/
@Override
public Principal authenticate(GSSName gssName, GSSCredential gssCredential) {
Principal authenticatedUser = null;

for (Realm realm : realms) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("combinedRealm.authStart",
gssName, realm.getClass().getName()));
}

authenticatedUser = realm.authenticate(gssName, gssCredential);

if (authenticatedUser == null) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("combinedRealm.authFail",
gssName, realm.getClass().getName()));
}
} else {
if (log.isDebugEnabled()) {
log.debug(sm.getString("combinedRealm.authSuccess",
gssName, realm.getClass().getName()));
}
break;
}
}
return authenticatedUser;
}

/**
* {@inheritDoc}
*/
@Override
public boolean hasRole(Wrapper wrapper, Principal principal, String role) {
for (Realm realm : realms) {
if (realm.hasRole(wrapper, principal, role)) {
return true;
}
}
return false;
}

@Override
protected String getPassword(String username) {
// This method should never be called


+ 1
- 0
java/org/apache/catalina/realm/LocalStrings_zh_CN.properties View File

@@ -24,6 +24,7 @@ jaasCallback.username=返回用户名 [{0}]
jaasMemoryLoginModule.invalidCredentials=用户名或密码不正确
jaasMemoryLoginModule.noConfig=无法加载配置文件 [{0}]

jaasRealm.authenticateFailure=用户 [{0}] 认证失败
jaasRealm.authenticateSuccess=用户名 [{0}] 已被成功认证为身份 [{1}] -- 主体也已创建
jaasRealm.classNotFound=找不到类 [{0}]
jaasRealm.failedLogin=由于登录失败,用户名 [{0}] 无法授权


+ 13
- 0
java/org/apache/catalina/realm/LockOutRealm.java View File

@@ -27,6 +27,7 @@ import org.apache.catalina.LifecycleException;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSName;

@@ -200,6 +201,18 @@ public class LockOutRealm extends CombinedRealm {
return null;
}

/**
* {@inheritDoc}
*/
@Override
public Principal authenticate(GSSName gssName, GSSCredential gssCredential) {
String username = gssName.toString();

Principal authenticatedUser = super.authenticate(gssName, gssCredential);

return filterLockedAccounts(username, authenticatedUser);
}


/*
* Filters authenticated principals to ensure that <code>null</code> is


+ 53
- 10
java/org/apache/catalina/realm/RealmBase.java View File

@@ -497,16 +497,7 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
}
}

String name = gssName.toString();

if (isStripRealmForGss()) {
int i = name.indexOf('@');
if (i > 0) {
// Zero so we don't leave a zero length name
name = name.substring(0, i);
}
}
return getPrincipal(name, gssCredential);
return getPrincipal(gssName, gssCredential);
}
} else {
log.error(sm.getString("realmBase.gssContextNotEstablished"));
@@ -517,6 +508,19 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
}


/**
* {@inheritDoc}
*/
@Override
public Principal authenticate(GSSName gssName, GSSCredential gssCredential) {
if (gssName == null) {
return null;
}

return getPrincipal(gssName, gssCredential);
}


/**
* Execute a periodic task, such as reloading, etc. This method will be
* invoked inside the classloading context of this container. Unexpected
@@ -1220,6 +1224,16 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
protected abstract Principal getPrincipal(String username);


/**
* Get the principal associated with the specified user name.
*
* @param username The user name
* @param gssCredential the GSS credential of the principal
* @return the principal associated with the given user name.
* @deprecated This will be removed in Tomcat 10 onwards. Use
* {@link #getPrincipal(GSSName, GSSCredential)} instead.
*/
@Deprecated
protected Principal getPrincipal(String username,
GSSCredential gssCredential) {
Principal p = getPrincipal(username);
@@ -1231,6 +1245,35 @@ public abstract class RealmBase extends LifecycleMBeanBase implements Realm {
return p;
}


/**
* Get the principal associated with the specified {@link GSSName}.
*
* @param gssName The GSS name
* @param gssCredential the GSS credential of the principal
* @return the principal associated with the given user name.
*/
protected Principal getPrincipal(GSSName gssName, GSSCredential gssCredential) {
String name = gssName.toString();

if (isStripRealmForGss()) {
int i = name.indexOf('@');
if (i > 0) {
// Zero so we don't leave a zero length name
name = name.substring(0, i);
}
}

Principal p = getPrincipal(name);

if (p instanceof GenericPrincipal) {
((GenericPrincipal) p).setGssCredential(gssCredential);
}

return p;
}


/**
* Return the Server object that is the ultimate parent for the container
* with which this Realm is associated. If the server cannot be found (eg


+ 6
- 1
java/org/apache/catalina/servlets/WebdavServlet.java View File

@@ -61,7 +61,10 @@ import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
* Servlet which adds support for WebDAV level 2. All the basic HTTP requests
* Servlet which adds support for
* <a href="https://tools.ietf.org/html/rfc4918">WebDAV</a>
* <a href="https://tools.ietf.org/html/rfc4918#section-18">level 2</a>.
* All the basic HTTP requests
* are handled by the DefaultServlet. The WebDAVServlet must not be used as the
* default servlet (ie mapped to '/') as it will not work in this configuration.
* <p>
@@ -120,6 +123,8 @@ import org.xml.sax.SAXException;
* http://host:port/context/webdavedit/content
*
* @author Remy Maucherat
*
* @see <a href="https://tools.ietf.org/html/rfc4918">RFC 4918</a>
*/
public class WebdavServlet extends DefaultServlet {



+ 13
- 18
java/org/apache/catalina/session/FileStore.java View File

@@ -127,17 +127,17 @@ public final class FileStore extends StoreBase {
@Override
public int getSize() throws IOException {
// Acquire the list of files in our storage directory
File file = directory();
if (file == null) {
File dir = directory();
if (dir == null) {
return 0;
}
String files[] = file.list();
String files[] = dir.list();

// Figure out which files are sessions
int keycount = 0;
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (files[i].endsWith(FILE_EXT)) {
for (String file : files) {
if (file.endsWith(FILE_EXT)) {
keycount++;
}
}
@@ -172,24 +172,23 @@ public final class FileStore extends StoreBase {
@Override
public String[] keys() throws IOException {
// Acquire the list of files in our storage directory
File file = directory();
if (file == null) {
File dir = directory();
if (dir == null) {
return new String[0];
}

String files[] = file.list();
String files[] = dir.list();

// Bugzilla 32130
if((files == null) || (files.length < 1)) {
if (files == null || files.length < 1) {
return new String[0];
}

// Build and return the list of session identifiers
List<String> list = new ArrayList<>();
int n = FILE_EXT.length();
for (int i = 0; i < files.length; i++) {
if (files[i].endsWith(FILE_EXT)) {
list.add(files[i].substring(0, files[i].length() - n));
for (String file : files) {
if (file.endsWith(FILE_EXT)) {
list.add (file.substring(0, file.length() - n));
}
}
return list.toArray(new String[list.size()]);
@@ -210,11 +209,7 @@ public final class FileStore extends StoreBase {
public Session load(String id) throws ClassNotFoundException, IOException {
// Open an input stream to the specified pathname, if any
File file = file(id);
if (file == null) {
return null;
}

if (!file.exists()) {
if (file == null || !file.exists()) {
return null;
}



+ 1
- 0
java/org/apache/catalina/session/LocalStrings_zh_CN.properties View File

@@ -44,6 +44,7 @@ standardManager.managerUnload=卸载会话到持久存储的异常
standardManager.unloading.nosessions=没有要卸载的持久会话

standardSession.attributeEvent=会话属性事件侦听器引发异常
standardSession.getAttribute.ise=getAttribute: 会话已失效
standardSession.getAttributeNames.ise=getAttributeNames:会话已失效
standardSession.getCreationTime.ise=getCreataionTime:会话已经无效
standardSession.getIdleTime.ise=getIdleTime: 已失效的会话


+ 7
- 0
java/org/apache/catalina/session/ManagerBase.java View File

@@ -753,8 +753,15 @@ public abstract class ManagerBase extends LifecycleMBeanBase implements Manager

@Override
public void changeSessionId(Session session) {
rotateSessionId(session);
}


@Override
public String rotateSessionId(Session session) {
String newId = generateSessionId();
changeSessionId(session, newId, true, true);
return newId;
}




+ 1
- 0
java/org/apache/catalina/startup/LocalStrings_zh_CN.properties View File

@@ -88,6 +88,7 @@ hostConfig.deployDescriptor.error=部署描述符[{0}]时出错
hostConfig.deployDescriptor.finished=部署描述符[{0}]的部署已在[{1}]ms内完成
hostConfig.deployDescriptor.localDocBaseSpecified=(:在主机appBase 中指定了docBase [{0}],将被忽略
hostConfig.deployDir=把web 应用程序部署到目录 [{0}]
hostConfig.deployDir.error=无法部署应用目录 [{0}]
hostConfig.deployWar.error=部署 Web 应用程序 archive [{0}] 时出错
hostConfig.deployWar.hiddenDir=将忽略目录[{0}],因为WAR [{1}]优先,unpackWAR为false