fix cookie parsing problem

This commit is contained in:
Bill Burke 2014-08-18 18:36:36 -04:00
parent 2dc32fb8c9
commit faf18dfdfd
5 changed files with 300 additions and 347 deletions

View file

@ -173,7 +173,7 @@ public class AuthenticationManager {
public AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, HttpHeaders headers, boolean checkActive) {
logger.info("authenticateIdentityCookie");
Cookie cookie = headers.getCookies().get(KEYCLOAK_IDENTITY_COOKIE);
if (cookie == null) {
if (cookie == null || "".equals(cookie.getValue())) {
logger.infov("authenticateCookie could not find cookie: {0}", KEYCLOAK_IDENTITY_COOKIE);
return null;
}

View file

@ -96,7 +96,10 @@ public class OAuthFlows {
Cookie sessionCookie = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_SESSION_COOKIE);
if (sessionCookie != null) {
String oldSessionId = sessionCookie.getValue().split("/")[2];
String[] split = sessionCookie.getValue().split("/");
if (split.length >= 3) {
String oldSessionId = split[2];
if (!oldSessionId.equals(userSession.getId())) {
UserSessionModel oldSession = session.sessions().getUserSession(realm, oldSessionId);
if (oldSession != null) {
@ -105,6 +108,7 @@ public class OAuthFlows {
}
}
}
}
// refresh the cookies!
authManager.createLoginCookie(realm, accessCode.getUser(), userSession, uriInfo, clientConnection);

View file

@ -29,7 +29,7 @@ public class CookieHelper {
* @param secure
* @param httpOnly
*/
public static void addCookie2(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) {
public static void addCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) {
HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
StringBuffer cookieBuf = new StringBuffer();
ServerCookie.appendCookieValue(cookieBuf, 1, name, value, path, domain, comment, maxAge, secure, httpOnly);
@ -37,19 +37,5 @@ public class CookieHelper {
response.getOutputHeaders().add(HttpHeaders.SET_COOKIE, cookie);
}
public static void addCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly) {
HttpServletResponse response = ResteasyProviderFactory.getContextData(HttpServletResponse.class);
Cookie cookie = new Cookie(name, value);
if (path != null) cookie.setPath(path);
if (domain != null) cookie.setDomain(domain);
if (comment != null) cookie.setComment(comment);
cookie.setMaxAge(maxAge);
cookie.setSecure(secure);
cookie.setHttpOnly(httpOnly);
response.addCookie(cookie);
}
}

View file

@ -11,8 +11,7 @@ import java.util.TimeZone;
/**
* Server-side cookie representation. borrowed from Tomcat.
*/
public class ServerCookie implements Serializable
{
public class ServerCookie implements Serializable {
private static final String tspecials = ",; ";
private static final String tspecials2 = "()<>@,;:\\\"/[]?={} \t";
@ -25,13 +24,11 @@ public class ServerCookie implements Serializable
* @return <code>true</code> if the <code>String</code> is a reserved
* token; <code>false</code> if it is not
*/
public static boolean isToken(String value)
{
public static boolean isToken(String value) {
if (value == null) return true;
int len = value.length();
for (int i = 0; i < len; i++)
{
for (int i = 0; i < len; i++) {
char c = value.charAt(i);
if (tspecials.indexOf(c) != -1)
@ -40,15 +37,12 @@ public class ServerCookie implements Serializable
return true;
}
public static boolean containsCTL(String value, int version)
{
public static boolean containsCTL(String value, int version) {
if (value == null) return false;
int len = value.length();
for (int i = 0; i < len; i++)
{
for (int i = 0; i < len; i++) {
char c = value.charAt(i);
if (c < 0x20 || c >= 0x7f)
{
if (c < 0x20 || c >= 0x7f) {
if (c == 0x09)
continue; //allow horizontal tabs
return true;
@ -58,13 +52,11 @@ public class ServerCookie implements Serializable
}
public static boolean isToken2(String value)
{
public static boolean isToken2(String value) {
if (value == null) return true;
int len = value.length();
for (int i = 0; i < len; i++)
{
for (int i = 0; i < len; i++) {
char c = value.charAt(i);
if (tspecials2.indexOf(c) != -1)
return false;
@ -75,8 +67,7 @@ public class ServerCookie implements Serializable
/**
* @deprecated - Not used
*/
public static boolean checkName(String name)
{
public static boolean checkName(String name) {
if (!isToken(name)
|| name.equalsIgnoreCase("Comment") // rfc2019
|| name.equalsIgnoreCase("Discard") // rfc2965
@ -87,8 +78,7 @@ public class ServerCookie implements Serializable
|| name.equalsIgnoreCase("Secure") // rfc2019
|| name.equalsIgnoreCase("Version") // rfc2019
// TODO remaining RFC2965 attributes
)
{
) {
return false;
}
return true;
@ -100,12 +90,10 @@ public class ServerCookie implements Serializable
/**
* Return the header name to set the cookie, based on cookie version.
*/
public static String getCookieHeaderName(int version)
{
public static String getCookieHeaderName(int version) {
// TODO Re-enable logging when RFC2965 is implemented
// log( (version==1) ? "Set-Cookie2" : "Set-Cookie");
if (version == 1)
{
if (version == 1) {
// XXX RFC2965 not referenced in Servlet Spec
// Set-Cookie2 is not supported by Netscape 4, 6, IE 3, 5
// Set-Cookie2 is supported by Lynx and Opera
@ -113,9 +101,7 @@ public class ServerCookie implements Serializable
// RFC2109
return "Set-Cookie";
// return "Set-Cookie2";
}
else
{
} else {
// Old Netscape
return "Set-Cookie";
}
@ -138,21 +124,17 @@ public class ServerCookie implements Serializable
private final static DateFormat oldCookieFormat = new SimpleDateFormat(OLD_COOKIE_PATTERN, LOCALE_US);
public static String formatOldCookie(Date d)
{
public static String formatOldCookie(Date d) {
String ocf = null;
synchronized (oldCookieFormat)
{
synchronized (oldCookieFormat) {
ocf = oldCookieFormat.format(d);
}
return ocf;
}
public static void formatOldCookie(Date d, StringBuffer sb,
FieldPosition fp)
{
synchronized (oldCookieFormat)
{
FieldPosition fp) {
synchronized (oldCookieFormat) {
oldCookieFormat.format(d, sb, fp);
}
}
@ -171,41 +153,40 @@ public class ServerCookie implements Serializable
String comment,
int maxAge,
boolean isSecure,
boolean httpOnly)
{
boolean httpOnly) {
StringBuffer buf = new StringBuffer();
// Servlet implementation checks name
buf.append(name);
buf.append("=");
// Servlet implementation does not check anything else
maybeQuote2(version, buf, value);
// NOTE!!! BROWSERS REALLY DON'T LIKE QUOTING
//maybeQuote2(version, buf, value);
buf.append(value);
// Add version 1 specific information
if (version == 1)
{
if (version == 1) {
// Version=1 ... required
buf.append("; Version=1");
// Comment=comment
if (comment != null)
{
if (comment != null) {
buf.append("; Comment=");
maybeQuote2(version, buf, comment);
//maybeQuote2(version, buf, comment);
buf.append(comment);
}
}
// Add domain information, if present
if (domain != null)
{
if (domain != null) {
buf.append("; Domain=");
maybeQuote2(version, buf, domain);
//maybeQuote2(version, buf, domain);
buf.append(domain);
}
// Max-Age=secs ... or use old "Expires" format
// TODO RFC2965 Discard
if (maxAge >= 0)
{
if (maxAge >= 0) {
// 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
@ -222,21 +203,18 @@ public class ServerCookie implements Serializable
}
// Path=path
if (path != null)
{
if (path != null) {
buf.append("; Path=");
buf.append(path);
}
// Secure
if (isSecure)
{
if (isSecure) {
buf.append("; Secure");
}
// HttpOnly
if (httpOnly)
{
if (httpOnly) {
buf.append("; HttpOnly");
}
@ -247,23 +225,18 @@ public class ServerCookie implements Serializable
* @deprecated - Not used
*/
@Deprecated
public static void maybeQuote(int version, StringBuffer buf, String value)
{
public static void maybeQuote(int version, StringBuffer buf, String value) {
// special case - a \n or \r shouldn't happen in any case
if (isToken(value))
{
if (isToken(value)) {
buf.append(value);
}
else
{
} else {
buf.append('"');
buf.append(escapeDoubleQuotes(value, 0, value.length()));
buf.append('"');
}
}
public static boolean alreadyQuoted(String value)
{
public static boolean alreadyQuoted(String value) {
if (value == null || value.length() == 0) return false;
return (value.charAt(0) == '\"' && value.charAt(value.length() - 1) == '\"');
}
@ -275,34 +248,24 @@ public class ServerCookie implements Serializable
* @param buf
* @param value
*/
public static void maybeQuote2(int version, StringBuffer buf, String value)
{
if (value == null || value.length() == 0)
{
public static void maybeQuote2(int version, StringBuffer buf, String value) {
if (value == null || value.length() == 0) {
buf.append("\"\"");
}
else if (containsCTL(value, version))
} else if (containsCTL(value, version))
throw new IllegalArgumentException("Control character in cookie value, consider BASE64 encoding your value");
else if (alreadyQuoted(value))
{
else if (alreadyQuoted(value)) {
buf.append('"');
buf.append(escapeDoubleQuotes(value, 1, value.length() - 1));
buf.append('"');
}
else if (version == 0 && !isToken(value))
{
} else if (version == 0 && !isToken(value)) {
buf.append('"');
buf.append(escapeDoubleQuotes(value, 0, value.length()));
buf.append('"');
}
else if (version == 1 && !isToken2(value))
{
} else if (version == 1 && !isToken2(value)) {
buf.append('"');
buf.append(escapeDoubleQuotes(value, 0, value.length()));
buf.append('"');
}
else
{
} else {
buf.append(value);
}
}
@ -316,26 +279,21 @@ public class ServerCookie implements Serializable
* @param endIndex exclusive
* @return The (possibly) escaped string
*/
private static String escapeDoubleQuotes(String s, int beginIndex, int endIndex)
{
private static String escapeDoubleQuotes(String s, int beginIndex, int endIndex) {
if (s == null || s.length() == 0 || s.indexOf('"') == -1)
{
if (s == null || s.length() == 0 || s.indexOf('"') == -1) {
return s;
}
StringBuffer b = new StringBuffer();
for (int i = beginIndex; i < endIndex; i++)
{
for (int i = beginIndex; i < endIndex; i++) {
char c = s.charAt(i);
if (c == '\\')
{
if (c == '\\') {
b.append(c);
//ignore the character after an escape, just append it
if (++i >= endIndex) throw new IllegalArgumentException("Invalid escape character in cookie value.");
b.append(s.charAt(i));
}
else if (c == '"')
} else if (c == '"')
b.append('\\').append('"');
else
b.append(c);

View file

@ -180,6 +180,11 @@ public class AccessTokenPerfTest {
}
Assert.assertEquals(302, response.getStatus());
uri = response.getLocation();
for (String header : response.getHeaders().keySet()) {
for (Object value : response.getHeaders().get(header)) {
System.out.println(header + ": " + value);
}
}
response.close();
Assert.assertNotNull(uri);