ASF Bugzilla – Attachment 23421 Details for
Bug 46597
Not all cookie changes in 6.0.x branch have been ported to 5.5.x
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
Proposed port of new cookie functionality
bug46597.patch (text/plain), 16.74 KB, created by
Mark Thomas
on 2009-03-27 07:42:04 UTC
(
hide
)
Description:
Proposed port of new cookie functionality
Filename:
MIME Type:
Creator:
Mark Thomas
Created:
2009-03-27 07:42:04 UTC
Size:
16.74 KB
patch
obsolete
>Index: connectors/util/java/org/apache/tomcat/util/http/ServerCookie.java >=================================================================== >--- connectors/util/java/org/apache/tomcat/util/http/ServerCookie.java (revision 759131) >+++ connectors/util/java/org/apache/tomcat/util/http/ServerCookie.java (working copy) >@@ -18,11 +18,14 @@ > package org.apache.tomcat.util.http; > > import java.io.Serializable; >+import java.text.DateFormat; > import java.text.FieldPosition; >+import java.text.SimpleDateFormat; > import java.util.Date; >+import java.util.Locale; >+import java.util.TimeZone; > > import org.apache.tomcat.util.buf.ByteChunk; >-import org.apache.tomcat.util.buf.DateTool; > import org.apache.tomcat.util.buf.MessageBytes; > > >@@ -50,6 +53,37 @@ > private int maxAge = -1; > private int version = 0; > >+ // Other fields >+ private static final String OLD_COOKIE_PATTERN = >+ "EEE, dd-MMM-yyyy HH:mm:ss z"; >+ private static final ThreadLocal<DateFormat> OLD_COOKIE_FORMAT = >+ new ThreadLocal<DateFormat>() { >+ protected DateFormat initialValue() { >+ DateFormat df = >+ new SimpleDateFormat(OLD_COOKIE_PATTERN, Locale.US); >+ df.setTimeZone(TimeZone.getTimeZone("GMT")); >+ return df; >+ } >+ }; >+ private static final String ancientDate; >+ >+ >+ static { >+ ancientDate = OLD_COOKIE_FORMAT.get().format(new Date(10000)); >+ } >+ >+ /** >+ * If set to true, we parse cookies according to the servlet spec, >+ */ >+ public static final boolean STRICT_SERVLET_COMPLIANCE = >+ Boolean.valueOf(System.getProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "false")).booleanValue(); >+ >+ /** >+ * If set to false, we don't use the IE6/7 Max-Age/Expires work around >+ */ >+ public static final boolean ALWAYS_ADD_EXPIRES = >+ Boolean.valueOf(System.getProperty("org.apache.tomcat.util.http.ServerCookie.ALWAYS_ADD_EXPIRES", "true")).booleanValue(); >+ > // Note: Servlet Spec =< 2.5 only refers to Netscape and RFC2109, > // not RFC2965 > >@@ -127,6 +161,7 @@ > > private static final String tspecials = ",; "; > private static final String tspecials2 = "()<>@,;:\\\"/[]?={} \t"; >+ private static final String tspecials2NoSlash = "()<>@,;:\\\"[]?={} \t"; > > /* > * Tests a string and returns true if the string counts as a >@@ -139,6 +174,11 @@ > * if it is not > */ > public static boolean isToken(String value) { >+ return isToken(value,null); >+ } >+ >+ public static boolean isToken(String value, String literals) { >+ String tspecials = (literals==null?ServerCookie.tspecials:literals); > if( value==null) return true; > int len = value.length(); > >@@ -164,9 +204,13 @@ > } > return false; > } >- >- >+ > public static boolean isToken2(String value) { >+ return isToken2(value,null); >+ } >+ >+ public static boolean isToken2(String value, String literals) { >+ String tspecials2 = (literals==null?ServerCookie.tspecials2:literals); > if( value==null) return true; > int len = value.length(); > >@@ -230,9 +274,6 @@ > } > } > >- private static final String ancientDate = >- DateTool.formatOldCookie(new Date(10000)); >- > // TODO RFC2965 fields also need to be passed > public static void appendCookieValue( StringBuffer headerBuf, > int version, >@@ -242,7 +283,8 @@ > String domain, > String comment, > int maxAge, >- boolean isSecure ) >+ boolean isSecure, >+ boolean isHttpOnly) > { > StringBuffer buf = new StringBuffer(); > // Servlet implementation checks name >@@ -250,7 +292,7 @@ > buf.append("="); > // Servlet implementation does not check anything else > >- maybeQuote2(version, buf, value); >+ version = maybeQuote2(version, buf, value,true); > > // Add version 1 specific information > if (version == 1) { >@@ -273,28 +315,34 @@ > // Max-Age=secs ... or use old "Expires" format > // TODO RFC2965 Discard > if (maxAge >= 0) { >- if (version == 0) { >+ if (version > 0) { >+ buf.append ("; Max-Age="); >+ buf.append (maxAge); >+ } >+ // IE6, IE7 and possibly other browsers don't understand Max-Age. >+ // They do understand Expires, even with V1 cookies! >+ if (version == 0 || ALWAYS_ADD_EXPIRES) { > // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format ) > buf.append ("; Expires="); > // To expire immediately we need to set the time in past > if (maxAge == 0) > buf.append( ancientDate ); > else >- DateTool.formatOldCookie >- (new Date( System.currentTimeMillis() + >- maxAge *1000L), buf, >- new FieldPosition(0)); >- >- } else { >- buf.append ("; Max-Age="); >- buf.append (maxAge); >+ OLD_COOKIE_FORMAT.get().format( >+ new Date(System.currentTimeMillis() + >+ maxAge*1000L), >+ buf, new FieldPosition(0)); > } > } > > // Path=path > if (path!=null) { > buf.append ("; Path="); >- maybeQuote2(version, buf, path); >+ if (version==0) { >+ maybeQuote2(version, buf, path); >+ } else { >+ maybeQuote2(version, buf, path, ServerCookie.tspecials2NoSlash, false); >+ } > } > > // Secure >@@ -302,6 +350,10 @@ > buf.append ("; Secure"); > } > >+ // HttpOnly >+ if (isHttpOnly) { >+ buf.append("; HttpOnly"); >+ } > headerBuf.append(buf); > } > >@@ -332,27 +384,40 @@ > * @param buf > * @param value > */ >- public static void maybeQuote2(int version, StringBuffer buf, >- String value) { >+ public static int maybeQuote2 (int version, StringBuffer buf, String value) { >+ return maybeQuote2(version,buf,value,false); >+ } >+ >+ public static int maybeQuote2 (int version, StringBuffer buf, String value, boolean allowVersionSwitch) { >+ return maybeQuote2(version,buf,value,null,allowVersionSwitch); >+ } >+ >+ public static int maybeQuote2 (int version, StringBuffer buf, String value, String literals, boolean allowVersionSwitch) { > if (value==null || value.length()==0) { > buf.append("\"\""); > } else if (containsCTL(value,version)) > throw new IllegalArgumentException("Control character in cookie value, consider BASE64 encoding your value"); > else if (alreadyQuoted(value)) { > buf.append('"'); >- buf.append(escapeDoubleQuotes(value,1,value.length()-1)); buf.append('"'); >+ buf.append(escapeDoubleQuotes(value,1,value.length()-1)); > buf.append('"'); >- } else if (version==0 && !isToken(value)) { >+ } else if (allowVersionSwitch && (!STRICT_SERVLET_COMPLIANCE) && version==0 && !isToken2(value, literals)) { > buf.append('"'); > buf.append(escapeDoubleQuotes(value,0,value.length())); > buf.append('"'); >- } else if (version==1 && !isToken2(value)) { >+ version = 1; >+ } else if (version==0 && !isToken(value,literals)) { > buf.append('"'); > buf.append(escapeDoubleQuotes(value,0,value.length())); > buf.append('"'); >+ } else if (version==1 && !isToken2(value,literals)) { >+ buf.append('"'); >+ buf.append(escapeDoubleQuotes(value,0,value.length())); >+ buf.append('"'); > } else { > buf.append(value); > } >+ return version; > } > > /** >Index: container/catalina/src/share/org/apache/catalina/Context.java >=================================================================== >--- container/catalina/src/share/org/apache/catalina/Context.java (revision 759131) >+++ container/catalina/src/share/org/apache/catalina/Context.java (working copy) >@@ -181,8 +181,24 @@ > */ > public void setCookies(boolean cookies); > >+ /** >+ * Gets the value of the use HttpOnly cookies for session cookies flag. >+ * >+ * @return <code>true</code> if the HttpOnly flag should be set on session >+ * cookies >+ */ >+ public boolean getUseHttpOnly(); > >+ > /** >+ * Sets the use HttpOnly cookies for session cookies flag. >+ * >+ * @param useHttpOnly Set to <code>true</code> to use HttpOnly cookies >+ * for session cookies >+ */ >+ public void setUseHttpOnly(boolean useHttpOnly); >+ >+ /** > * Return the "allow crossing servlet contexts" flag. > */ > public boolean getCrossContext(); >Index: container/catalina/src/share/org/apache/catalina/connector/Request.java >=================================================================== >--- container/catalina/src/share/org/apache/catalina/connector/Request.java (revision 759131) >+++ container/catalina/src/share/org/apache/catalina/connector/Request.java (working copy) >@@ -2238,7 +2238,7 @@ > Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME, > session.getIdInternal()); > configureSessionCookie(cookie); >- response.addCookie(cookie); >+ response.addCookieInternal(cookie, context.getUseHttpOnly()); > } > > if (session != null) { >Index: container/catalina/src/share/org/apache/catalina/connector/Response.java >=================================================================== >--- container/catalina/src/share/org/apache/catalina/connector/Response.java (revision 759131) >+++ container/catalina/src/share/org/apache/catalina/connector/Response.java (working copy) >@@ -932,7 +932,18 @@ > * @param cookie Cookie to be added > */ > public void addCookie(final Cookie cookie) { >+ addCookieInternal(cookie, false); >+ } > >+ /** >+ * Add the specified Cookie to those that will be included with >+ * this Response. >+ * >+ * @param cookie Cookie to be added >+ * @param httpOnly Should the httpOnly flag be set on this cookie >+ */ >+ public void addCookieInternal(final Cookie cookie, final boolean httpOnly) { >+ > if (isCommitted()) > return; > >@@ -950,7 +961,8 @@ > (sb, cookie.getVersion(), cookie.getName(), > cookie.getValue(), cookie.getPath(), > cookie.getDomain(), cookie.getComment(), >- cookie.getMaxAge(), cookie.getSecure()); >+ cookie.getMaxAge(), cookie.getSecure(), >+ httpOnly); > return null; > } > }); >@@ -958,7 +970,7 @@ > ServerCookie.appendCookieValue > (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(), > cookie.getPath(), cookie.getDomain(), cookie.getComment(), >- cookie.getMaxAge(), cookie.getSecure()); >+ cookie.getMaxAge(), cookie.getSecure(), httpOnly); > } > > // if we reached here, no exception, cookie is valid >Index: container/catalina/src/share/org/apache/catalina/core/StandardContext.java >=================================================================== >--- container/catalina/src/share/org/apache/catalina/core/StandardContext.java (revision 759131) >+++ container/catalina/src/share/org/apache/catalina/core/StandardContext.java (working copy) >@@ -656,6 +656,10 @@ > */ > private boolean saveConfig = true; > >+ /** >+ * The flag that indicates that session cookies should use HttpOnly >+ */ >+ private boolean useHttpOnly = false; > > // ----------------------------------------------------- Context Properties > >@@ -1045,9 +1049,36 @@ > new Boolean(this.cookies)); > > } >+ >+ /** >+ * Gets the value of the use HttpOnly cookies for session cookies flag. >+ * >+ * @return <code>true</code> if the HttpOnly flag should be set on session >+ * cookies >+ */ >+ public boolean getUseHttpOnly() { >+ return useHttpOnly; >+ } > > > /** >+ * Sets the use HttpOnly cookies for session cookies flag. >+ * >+ * @param useHttpOnly Set to <code>true</code> to use HttpOnly cookies >+ * for session cookies >+ */ >+ public void setUseHttpOnly(boolean useHttpOnly) { >+ boolean oldUseHttpOnly = this.useHttpOnly; >+ this.useHttpOnly = useHttpOnly; >+ support.firePropertyChange("useHttpOnly", >+ new Boolean(oldUseHttpOnly), >+ new Boolean(this.useHttpOnly)); >+ } >+ >+ >+ >+ >+ /** > * Return the "allow crossing servlet contexts" flag. > */ > public boolean getCrossContext() { >Index: container/webapps/docs/changelog.xml >=================================================================== >--- container/webapps/docs/changelog.xml (revision 759136) >+++ container/webapps/docs/changelog.xml (working copy) >@@ -54,6 +54,10 @@ > <bug>42419</bug>: Add a system property that enables the name of the > session cookie and session path parameter to be configured. (markt) > </add> >+ <add> >+ <bug>44382</bug>: Add support for using httpOnly for session cookies. >+ This is disabled by default. (markt/fhanik) >+ </add> > <fix> > <bug>45576</bug>: JAAS Realm now works with DIGEST authentication. > (markt) >@@ -67,6 +71,10 @@ > logging at the context level but the security policy prevents this. > (markt/rjung) > </fix> >+ <fix> >+ <bug>46597</bug>: Port all cookie handling changes from Tomcat 6.0.x. >+ (markt) >+ </fix> > </changelog> > </subsection> > <subsection name="Jasper"> >Index: container/webapps/docs/config/context.xml >=================================================================== >--- container/webapps/docs/config/context.xml (revision 759131) >+++ container/webapps/docs/config/context.xml (working copy) >@@ -235,6 +235,13 @@ > implementation class that will be used for servlets managed by this > Context. If not specified, a standard default value will be used.</p> > </attribute> >+ >+ <attribute name="useHttpOnly" required="false"> >+ <p>Should the HttpOnly flag be set on session cookies to prevent client >+ side script from accessing the session ID? Defaults to >+ <code>false</code>.</p> >+ </attribute> >+ > > </attributes> > >Index: container/webapps/docs/config/systemprops.xml >=================================================================== >--- container/webapps/docs/config/systemprops.xml (revision 759131) >+++ container/webapps/docs/config/systemprops.xml (working copy) >@@ -101,17 +101,32 @@ > <property name="org.apache.catalina. STRICT_SERVLET_COMPLIANCE"> > <p>If this is <code>true</code> the following actions will occur: > <ul> >- <li>any wrapped request or response object passed to an application >- dispatcher will be checked to ensure that it has wrapped the original >- request or response. (SRV.8.2 / SRV.14.2.5.1) >- </li> >- <li>when updating the access count for the session, the update will be >- synchronized. >- </li> >+ <li>any wrapped request or response object passed to an application >+ dispatcher will be checked to ensure that it has wrapped the original >+ request or response. (SRV.8.2 / SRV.14.2.5.1) >+ </li> >+ <li>when updating the access count for the session, the update will be >+ synchronized. >+ </li> >+ <li> >+ cookies will be parsed strictly, by default v0 cookies will not work >+ with any invalid characters.<br/>If set to false, any v0 cookie with >+ invalid character will be switched to a v1 cookie and the value will >+ be quoted. >+ </li> > </ul> > </p> > </property> > >+ <property >+ name="org.apache.tomcat.util.http. ServerCookie.ALWAYS_ADD_EXPIRES"> >+ <p>If this is <code>true</code> Tomcat will always add an expires >+ parameter to a SetCookie header even for cookies with version greater than >+ zero. This is to work around a known IE6 and IE7 bug that causes IE to >+ ignore the Max-Age parameter in a SetCookie header.If not specified, the >+ default value of <code>true</code> will be used.</p> >+ </property> >+ > </properties> > > </section>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 46597
:
23421
|
23498