keycloak-uncached

Details

diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-menu.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-menu.html
index f527953..f34df5f 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-menu.html
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-menu.html
@@ -9,7 +9,7 @@
     </li>
     <li data-ng-show="access.viewUsers" data-ng-class="(path[2] == 'users' || path[1] == 'user') && 'active'"><a href="#/realms/{{realm.realm}}/users">Users</a>
     </li>
-    <li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'roles' || (path[1] == 'role' & path[3] != 'applications') && 'active'"><a href="#/realms/{{realm.realm}}/roles">Roles</a>
+    <li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'roles' || (path[1] == 'role' && path[3] != 'applications')) && 'active'"><a href="#/realms/{{realm.realm}}/roles">Roles</a>
     </li>
     <li data-ng-show="access.viewApplications" data-ng-class="(path[2] == 'applications' || path[1] == 'application' || path[3] == 'applications') && 'active'"><a href="#/realms/{{realm.realm}}/applications">Applications</a></li>
     <li data-ng-show="access.viewClients" data-ng-class="(path[2] == 'oauth-clients' || path[1] == 'oauth-client') && 'active'"><a href="#/realms/{{realm.realm}}/oauth-clients">OAuth Clients</a></li>
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 45f1a42..2773989 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -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;
         }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java
index 554ed7d..f03d410 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationResource.java
@@ -156,7 +156,7 @@ public class UserFederationResource {
     @GET
     @NoCache
     @Path("instances/{id}")
-    @Consumes("application/json")
+    @Produces("application/json")
     public UserFederationProviderRepresentation getProviderInstance(@PathParam("id") String id) {
         logger.info("getProvider");
         auth.requireView();
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java b/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java
index 68bf394..0b10857 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java
@@ -1,199 +1,203 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2012, Red Hat, Inc., and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.keycloak.services.resources.flows;
-
-import org.jboss.logging.Logger;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
-import org.jboss.resteasy.spi.HttpRequest;
-import org.keycloak.ClientConnection;
-import org.keycloak.OAuth2Constants;
-import org.keycloak.audit.Audit;
-import org.keycloak.audit.Details;
-import org.keycloak.audit.EventType;
-import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.ClientSessionModel;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.RequiredCredentialModel;
-import org.keycloak.models.RoleModel;
-import org.keycloak.models.UserModel;
-import org.keycloak.models.UserModel.RequiredAction;
-import org.keycloak.models.UserSessionModel;
-import org.keycloak.representations.idm.CredentialRepresentation;
-import org.keycloak.services.managers.AccessCode;
-import org.keycloak.services.managers.AuthenticationManager;
-import org.keycloak.services.managers.TokenManager;
-
-import javax.ws.rs.core.Cookie;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-/**
- * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
- * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
- */
-public class OAuthFlows {
-
-    private static final Logger log = Logger.getLogger(OAuthFlows.class);
-
-    private final KeycloakSession session;
-
-    private final RealmModel realm;
-
-    private final HttpRequest request;
-
-    private final UriInfo uriInfo;
-
-    private ClientConnection clientConnection;
-    private final AuthenticationManager authManager;
-
-    private final TokenManager tokenManager;
-
-    OAuthFlows(KeycloakSession session, RealmModel realm, HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection, AuthenticationManager authManager,
-            TokenManager tokenManager) {
-        this.session = session;
-        this.realm = realm;
-        this.request = request;
-        this.uriInfo = uriInfo;
-        this.clientConnection = clientConnection;
-        this.authManager = authManager;
-        this.tokenManager = tokenManager;
-    }
-
-    public Response redirectAccessCode(AccessCode accessCode, UserSessionModel userSession, String state, String redirect) {
-        String code = accessCode.getCode();
-        UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam(OAuth2Constants.CODE, code);
-        log.debugv("redirectAccessCode: state: {0}", state);
-        if (state != null)
-            redirectUri.queryParam(OAuth2Constants.STATE, state);
-        Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
-        Cookie remember = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_REMEMBER_ME);
-
-        Cookie sessionCookie = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_SESSION_COOKIE);
-        if (sessionCookie != null) {
-            String oldSessionId = sessionCookie.getValue().split("/")[2];
-            if (!oldSessionId.equals(userSession.getId())) {
-                UserSessionModel oldSession = session.sessions().getUserSession(realm, oldSessionId);
-                if (oldSession != null) {
-                    log.debugv("Removing old user session: session: {0}", oldSessionId);
-                    session.sessions().removeUserSession(realm, oldSession);
-                }
-            }
-        }
-
-        // refresh the cookies!
-        authManager.createLoginCookie(realm, accessCode.getUser(), userSession, uriInfo, clientConnection);
-        if (userSession.isRememberMe()) authManager.createRememberMeCookie(realm, uriInfo, clientConnection);
-        return location.build();
-    }
-
-    public Response redirectError(ClientModel client, String error, String state, String redirect) {
-        UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam(OAuth2Constants.ERROR, error);
-        if (state != null) {
-            redirectUri.queryParam(OAuth2Constants.STATE, state);
-        }
-        return Response.status(302).location(redirectUri.build()).build();
-    }
-
-    public Response processAccessCode(String scopeParam, String state, String redirect, ClientModel client, UserModel user, UserSessionModel session, Audit audit) {
-        isTotpConfigurationRequired(user);
-        isEmailVerificationRequired(user);
-
-        boolean isResource = client instanceof ApplicationModel;
-        AccessCode accessCode = tokenManager.createAccessCode(scopeParam, state, redirect, this.session, realm, client, user, session);
-
-        log.debugv("processAccessCode: isResource: {0}", isResource);
-        log.debugv("processAccessCode: go to oauth page?: {0}",
-                !isResource);
-
-        audit.detail(Details.CODE_ID, accessCode.getCodeId());
-
-        Set<RequiredAction> requiredActions = user.getRequiredActions();
-        if (!requiredActions.isEmpty()) {
-            RequiredAction action = user.getRequiredActions().iterator().next();
-            accessCode.setRequiredAction(action);
-
-            if (action.equals(RequiredAction.VERIFY_EMAIL)) {
-                audit.clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, accessCode.getUser().getEmail()).success();
-            }
-
-            return Flows.forms(this.session, realm, client, uriInfo).setAccessCode(accessCode.getCode()).setUser(user)
-                    .createResponse(action);
-        }
-
-        if (!isResource) {
-            accessCode.setAction(ClientSessionModel.Action.OAUTH_GRANT);
-
-            List<RoleModel> realmRoles = new LinkedList<RoleModel>();
-            MultivaluedMap<String, RoleModel> resourceRoles = new MultivaluedMapImpl<String, RoleModel>();
-            for (RoleModel r : accessCode.getRequestedRoles()) {
-                if (r.getContainer() instanceof RealmModel) {
-                    realmRoles.add(r);
-                } else {
-                    resourceRoles.add(((ApplicationModel) r.getContainer()).getName(), r);
-                }
-            }
-
-            return Flows.forms(this.session, realm, client, uriInfo)
-                    .setAccessCode(accessCode.getCode())
-                    .setAccessRequest(realmRoles, resourceRoles)
-                    .setClient(client)
-                    .createOAuthGrant();
-        }
-
-        if (redirect != null) {
-            audit.success();
-
-            accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN);
-            return redirectAccessCode(accessCode, session, state, redirect);
-        } else {
-            return null;
-        }
-    }
-
-    public Response forwardToSecurityFailure(String message) {
-        return Flows.forms(session, realm, null, uriInfo).setError(message).createErrorPage();
-    }
-
-    private void isTotpConfigurationRequired(UserModel user) {
-        for (RequiredCredentialModel c : realm.getRequiredCredentials()) {
-            if (c.getType().equals(CredentialRepresentation.TOTP) && !user.isTotp()) {
-                user.addRequiredAction(RequiredAction.CONFIGURE_TOTP);
-                log.debug("User is required to configure totp");
-            }
-        }
-    }
-
-    private void isEmailVerificationRequired(UserModel user) {
-        if (realm.isVerifyEmail() && !user.isEmailVerified()) {
-            user.addRequiredAction(RequiredAction.VERIFY_EMAIL);
-            log.debug("User is required to verify email");
-        }
-    }
-
-}
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.services.resources.flows;
+
+import org.jboss.logging.Logger;
+import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.ClientConnection;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.audit.Audit;
+import org.keycloak.audit.Details;
+import org.keycloak.audit.EventType;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredCredentialModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.services.managers.AccessCode;
+import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.TokenManager;
+
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class OAuthFlows {
+
+    private static final Logger log = Logger.getLogger(OAuthFlows.class);
+
+    private final KeycloakSession session;
+
+    private final RealmModel realm;
+
+    private final HttpRequest request;
+
+    private final UriInfo uriInfo;
+
+    private ClientConnection clientConnection;
+    private final AuthenticationManager authManager;
+
+    private final TokenManager tokenManager;
+
+    OAuthFlows(KeycloakSession session, RealmModel realm, HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection, AuthenticationManager authManager,
+            TokenManager tokenManager) {
+        this.session = session;
+        this.realm = realm;
+        this.request = request;
+        this.uriInfo = uriInfo;
+        this.clientConnection = clientConnection;
+        this.authManager = authManager;
+        this.tokenManager = tokenManager;
+    }
+
+    public Response redirectAccessCode(AccessCode accessCode, UserSessionModel userSession, String state, String redirect) {
+        String code = accessCode.getCode();
+        UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam(OAuth2Constants.CODE, code);
+        log.debugv("redirectAccessCode: state: {0}", state);
+        if (state != null)
+            redirectUri.queryParam(OAuth2Constants.STATE, state);
+        Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
+        Cookie remember = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_REMEMBER_ME);
+
+        Cookie sessionCookie = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_SESSION_COOKIE);
+        if (sessionCookie != null) {
+
+            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) {
+                        log.debugv("Removing old user session: session: {0}", oldSessionId);
+                        session.sessions().removeUserSession(realm, oldSession);
+                    }
+                }
+            }
+        }
+
+        // refresh the cookies!
+        authManager.createLoginCookie(realm, accessCode.getUser(), userSession, uriInfo, clientConnection);
+        if (userSession.isRememberMe()) authManager.createRememberMeCookie(realm, uriInfo, clientConnection);
+        return location.build();
+    }
+
+    public Response redirectError(ClientModel client, String error, String state, String redirect) {
+        UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam(OAuth2Constants.ERROR, error);
+        if (state != null) {
+            redirectUri.queryParam(OAuth2Constants.STATE, state);
+        }
+        return Response.status(302).location(redirectUri.build()).build();
+    }
+
+    public Response processAccessCode(String scopeParam, String state, String redirect, ClientModel client, UserModel user, UserSessionModel session, Audit audit) {
+        isTotpConfigurationRequired(user);
+        isEmailVerificationRequired(user);
+
+        boolean isResource = client instanceof ApplicationModel;
+        AccessCode accessCode = tokenManager.createAccessCode(scopeParam, state, redirect, this.session, realm, client, user, session);
+
+        log.debugv("processAccessCode: isResource: {0}", isResource);
+        log.debugv("processAccessCode: go to oauth page?: {0}",
+                !isResource);
+
+        audit.detail(Details.CODE_ID, accessCode.getCodeId());
+
+        Set<RequiredAction> requiredActions = user.getRequiredActions();
+        if (!requiredActions.isEmpty()) {
+            RequiredAction action = user.getRequiredActions().iterator().next();
+            accessCode.setRequiredAction(action);
+
+            if (action.equals(RequiredAction.VERIFY_EMAIL)) {
+                audit.clone().event(EventType.SEND_VERIFY_EMAIL).detail(Details.EMAIL, accessCode.getUser().getEmail()).success();
+            }
+
+            return Flows.forms(this.session, realm, client, uriInfo).setAccessCode(accessCode.getCode()).setUser(user)
+                    .createResponse(action);
+        }
+
+        if (!isResource) {
+            accessCode.setAction(ClientSessionModel.Action.OAUTH_GRANT);
+
+            List<RoleModel> realmRoles = new LinkedList<RoleModel>();
+            MultivaluedMap<String, RoleModel> resourceRoles = new MultivaluedMapImpl<String, RoleModel>();
+            for (RoleModel r : accessCode.getRequestedRoles()) {
+                if (r.getContainer() instanceof RealmModel) {
+                    realmRoles.add(r);
+                } else {
+                    resourceRoles.add(((ApplicationModel) r.getContainer()).getName(), r);
+                }
+            }
+
+            return Flows.forms(this.session, realm, client, uriInfo)
+                    .setAccessCode(accessCode.getCode())
+                    .setAccessRequest(realmRoles, resourceRoles)
+                    .setClient(client)
+                    .createOAuthGrant();
+        }
+
+        if (redirect != null) {
+            audit.success();
+
+            accessCode.setAction(ClientSessionModel.Action.CODE_TO_TOKEN);
+            return redirectAccessCode(accessCode, session, state, redirect);
+        } else {
+            return null;
+        }
+    }
+
+    public Response forwardToSecurityFailure(String message) {
+        return Flows.forms(session, realm, null, uriInfo).setError(message).createErrorPage();
+    }
+
+    private void isTotpConfigurationRequired(UserModel user) {
+        for (RequiredCredentialModel c : realm.getRequiredCredentials()) {
+            if (c.getType().equals(CredentialRepresentation.TOTP) && !user.isTotp()) {
+                user.addRequiredAction(RequiredAction.CONFIGURE_TOTP);
+                log.debug("User is required to configure totp");
+            }
+        }
+    }
+
+    private void isEmailVerificationRequired(UserModel user) {
+        if (realm.isVerifyEmail() && !user.isEmailVerified()) {
+            user.addRequiredAction(RequiredAction.VERIFY_EMAIL);
+            log.debug("User is required to verify email");
+        }
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/util/CookieHelper.java b/services/src/main/java/org/keycloak/services/util/CookieHelper.java
index 6d0d3a4..3b30b23 100755
--- a/services/src/main/java/org/keycloak/services/util/CookieHelper.java
+++ b/services/src/main/java/org/keycloak/services/util/CookieHelper.java
@@ -1,9 +1,9 @@
 package org.keycloak.services.util;
 
+import org.jboss.resteasy.spi.HttpResponse;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -24,16 +24,12 @@ public class CookieHelper {
      * @param httpOnly
      */
     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);
+        HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
+        StringBuffer cookieBuf = new StringBuffer();
+        ServerCookie.appendCookieValue(cookieBuf, 1, name, value, path, domain, comment, maxAge, secure, httpOnly);
+        String cookie = cookieBuf.toString();
+        response.getOutputHeaders().add(HttpHeaders.SET_COOKIE, cookie);
+    }
 
-        response.addCookie(cookie);
 
-    }
 }
diff --git a/services/src/main/java/org/keycloak/services/util/ServerCookie.java b/services/src/main/java/org/keycloak/services/util/ServerCookie.java
new file mode 100755
index 0000000..d41cc2e
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/util/ServerCookie.java
@@ -0,0 +1,305 @@
+package org.keycloak.services.util;
+
+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;
+
+/**
+ * Server-side cookie representation.  borrowed from Tomcat.
+ */
+public class ServerCookie implements Serializable {
+    private static final String tspecials = ",; ";
+    private static final String tspecials2 = "()<>@,;:\\\"/[]?={} \t";
+
+    /*
+    * Tests a string and returns true if the string counts as a
+    * reserved token in the Java language.
+    *
+    * @param value the <code>String</code> to be tested
+    *
+    * @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) {
+        if (value == null) return true;
+        int len = value.length();
+
+        for (int i = 0; i < len; i++) {
+            char c = value.charAt(i);
+
+            if (tspecials.indexOf(c) != -1)
+                return false;
+        }
+        return true;
+    }
+
+    public static boolean containsCTL(String value, int version) {
+        if (value == null) return false;
+        int len = value.length();
+        for (int i = 0; i < len; i++) {
+            char c = value.charAt(i);
+            if (c < 0x20 || c >= 0x7f) {
+                if (c == 0x09)
+                    continue; //allow horizontal tabs
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    public static boolean isToken2(String value) {
+        if (value == null) return true;
+        int len = value.length();
+
+        for (int i = 0; i < len; i++) {
+            char c = value.charAt(i);
+            if (tspecials2.indexOf(c) != -1)
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * @deprecated - Not used
+     */
+    public static boolean checkName(String name) {
+        if (!isToken(name)
+                || name.equalsIgnoreCase("Comment")     // rfc2019
+                || name.equalsIgnoreCase("Discard")     // rfc2965
+                || name.equalsIgnoreCase("Domain")      // rfc2019
+                || name.equalsIgnoreCase("Expires")     // Netscape
+                || name.equalsIgnoreCase("Max-Age")     // rfc2019
+                || name.equalsIgnoreCase("Path")        // rfc2019
+                || name.equalsIgnoreCase("Secure")      // rfc2019
+                || name.equalsIgnoreCase("Version")     // rfc2019
+            // TODO remaining RFC2965 attributes
+                ) {
+            return false;
+        }
+        return true;
+    }
+
+    // -------------------- Cookie parsing tools
+
+
+    /**
+     * Return the header name to set the cookie, based on cookie 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) {
+            // 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
+            // Need to check on later IE and FF releases but for now...
+            // RFC2109
+            return "Set-Cookie";
+            // return "Set-Cookie2";
+        } else {
+            // Old Netscape
+            return "Set-Cookie";
+        }
+    }
+
+    /**
+     * US locale - all HTTP dates are in english
+     */
+    private final static Locale LOCALE_US = Locale.US;
+
+    /**
+     * GMT timezone - all HTTP dates are on GMT
+     */
+    public final static TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
+    /**
+     * Pattern used for old cookies
+     */
+    private final static String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z";
+
+
+    private final static DateFormat oldCookieFormat = new SimpleDateFormat(OLD_COOKIE_PATTERN, LOCALE_US);
+
+    public static String formatOldCookie(Date d) {
+        String ocf = null;
+        synchronized (oldCookieFormat) {
+            ocf = oldCookieFormat.format(d);
+        }
+        return ocf;
+    }
+
+    public static void formatOldCookie(Date d, StringBuffer sb,
+                                       FieldPosition fp) {
+        synchronized (oldCookieFormat) {
+            oldCookieFormat.format(d, sb, fp);
+        }
+    }
+
+
+    private static final String ancientDate = formatOldCookie(new Date(10000));
+
+
+    // TODO RFC2965 fields also need to be passed
+    public static void appendCookieValue(StringBuffer headerBuf,
+                                         int version,
+                                         String name,
+                                         String value,
+                                         String path,
+                                         String domain,
+                                         String comment,
+                                         int maxAge,
+                                         boolean isSecure,
+                                         boolean httpOnly) {
+        StringBuffer buf = new StringBuffer();
+        // Servlet implementation checks name
+        buf.append(name);
+        buf.append("=");
+        // Servlet implementation does not check anything else
+
+        // NOTE!!! BROWSERS REALLY DON'T LIKE QUOTING
+        //maybeQuote2(version, buf, value);
+        buf.append(value);
+
+        // Add version 1 specific information
+        if (version == 1) {
+            // Version=1 ... required
+            buf.append("; Version=1");
+
+            // Comment=comment
+            if (comment != null) {
+                buf.append("; Comment=");
+                //maybeQuote2(version, buf, comment);
+                buf.append(comment);
+            }
+        }
+
+        // Add domain information, if present
+        if (domain != null) {
+            buf.append("; Domain=");
+            //maybeQuote2(version, buf, domain);
+            buf.append(domain);
+        }
+
+        // Max-Age=secs ... or use old "Expires" format
+        // TODO RFC2965 Discard
+        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
+            if (maxAge == 0)
+                buf.append(ancientDate);
+            else
+                formatOldCookie
+                        (new Date(System.currentTimeMillis() +
+                                        maxAge * 1000L), buf,
+                                new FieldPosition(0));
+
+            buf.append("; Max-Age=");
+            buf.append(maxAge);
+        }
+
+        // Path=path
+        if (path != null) {
+            buf.append("; Path=");
+            buf.append(path);
+        }
+
+        // Secure
+        if (isSecure) {
+            buf.append("; Secure");
+        }
+
+        // HttpOnly
+        if (httpOnly) {
+            buf.append("; HttpOnly");
+        }
+
+        headerBuf.append(buf);
+    }
+
+    /**
+     * @deprecated - Not used
+     */
+    @Deprecated
+    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)) {
+            buf.append(value);
+        } else {
+            buf.append('"');
+            buf.append(escapeDoubleQuotes(value, 0, value.length()));
+            buf.append('"');
+        }
+    }
+
+    public static boolean alreadyQuoted(String value) {
+        if (value == null || value.length() == 0) return false;
+        return (value.charAt(0) == '\"' && value.charAt(value.length() - 1) == '\"');
+    }
+
+    /**
+     * Quotes values using rules that vary depending on Cookie version.
+     *
+     * @param version
+     * @param buf
+     * @param value
+     */
+    public static void maybeQuote2(int version, StringBuffer buf, String value) {
+        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('"');
+        } else if (version == 0 && !isToken(value)) {
+            buf.append('"');
+            buf.append(escapeDoubleQuotes(value, 0, value.length()));
+            buf.append('"');
+        } else if (version == 1 && !isToken2(value)) {
+            buf.append('"');
+            buf.append(escapeDoubleQuotes(value, 0, value.length()));
+            buf.append('"');
+        } else {
+            buf.append(value);
+        }
+    }
+
+
+    /**
+     * Escapes any double quotes in the given string.
+     *
+     * @param s          the input string
+     * @param beginIndex start index inclusive
+     * @param endIndex   exclusive
+     * @return The (possibly) escaped string
+     */
+    private static String escapeDoubleQuotes(String s, int beginIndex, int endIndex) {
+
+        if (s == null || s.length() == 0 || s.indexOf('"') == -1) {
+            return s;
+        }
+
+        StringBuffer b = new StringBuffer();
+        for (int i = beginIndex; i < endIndex; i++) {
+            char c = s.charAt(i);
+            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 == '"')
+                b.append('\\').append('"');
+            else
+                b.append(c);
+        }
+
+        return b.toString();
+    }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/FederationProvidersIntegrationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/FederationProvidersIntegrationTest.java
index 99f6558..9b48590 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/FederationProvidersIntegrationTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/FederationProvidersIntegrationTest.java
@@ -3,6 +3,7 @@ package org.keycloak.testsuite.forms;
 import org.junit.Assert;
 import org.junit.ClassRule;
 import org.junit.FixMethodOrder;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
@@ -102,6 +103,13 @@ public class FederationProvidersIntegrationTest {
     @WebResource
     protected AccountPasswordPage changePasswordPage;
 
+    @Test
+    @Ignore
+    public void runit() throws Exception {
+        Thread.sleep(10000000);
+
+    }
+
     static UserModel addUser(KeycloakSession session, RealmModel realm, String username, String email, String password) {
         UserModel user = session.users().addUser(realm, username);
         user.setEmail(email);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
index b2d80fc..686b785 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java
@@ -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);