httponly, ie keycloak.js fix

This commit is contained in:
Bill Burke 2014-05-13 22:06:32 -04:00
parent e8f8829a76
commit b30809d681
6 changed files with 64 additions and 20 deletions

View file

@ -89,6 +89,9 @@ var Keycloak = function (config) {
kc.iframe.setAttribute('src', src ); kc.iframe.setAttribute('src', src );
kc.iframe.style.display = "none"; kc.iframe.style.display = "none";
doc.body.appendChild(kc.iframe); doc.body.appendChild(kc.iframe);
if (!kc.iframe.contentWindow.location.origin) {
kc.iframe.contentWindow.location.origin = kc.iframe.contentWindow.location.protocol + "//" + kc.iframe.contentWindow.location.host;
}
var messageCallback = function(event) { var messageCallback = function(event) {
if (event.origin !== kc.iframe.contentWindow.location.origin) { if (event.origin !== kc.iframe.contentWindow.location.origin) {
@ -114,6 +117,7 @@ var Keycloak = function (config) {
} }
kc.checkLoginIframe = function(success, failure) { kc.checkLoginIframe = function(success, failure) {
var msg = {}; var msg = {};
if (!success) { if (!success) {
throw "You must define a success method"; throw "You must define a success method";
@ -125,7 +129,10 @@ var Keycloak = function (config) {
msg.failureId = createCallbackId(); msg.failureId = createCallbackId();
kc.callbackMap[msg.successId] = success; kc.callbackMap[msg.successId] = success;
kc.callbackMap[msg.failureId] = failure; kc.callbackMap[msg.failureId] = failure;
kc.iframe.contentWindow.postMessage(msg, kc.iframe.contentWindow.location.origin); var origin = kc.iframe.contentWindow.location.origin;
console.log('*** origin: ' + origin);
var iframe = kc.iframe;
iframe.contentWindow.postMessage(msg, origin);
} }
kc.createLoginUrl = function(options) { kc.createLoginUrl = function(options) {

View file

@ -21,6 +21,7 @@ import org.keycloak.services.resources.RealmsResource;
import org.keycloak.authentication.AuthProviderStatus; import org.keycloak.authentication.AuthProviderStatus;
import org.keycloak.authentication.AuthUser; import org.keycloak.authentication.AuthUser;
import org.keycloak.authentication.AuthenticationProviderManager; import org.keycloak.authentication.AuthenticationProviderManager;
import org.keycloak.services.util.CookieHelper;
import org.keycloak.util.Time; import org.keycloak.util.Time;
import javax.ws.rs.core.Cookie; import javax.ws.rs.core.Cookie;
@ -89,22 +90,24 @@ public class AuthenticationManager {
maxAge = realm.getCentralLoginLifespan(); maxAge = realm.getCentralLoginLifespan();
logger.info("createLoginCookie maxAge: " + maxAge); logger.info("createLoginCookie maxAge: " + maxAge);
} }
builder.cookie(new NewCookie(cookieName, encoded, cookiePath, null, null, maxAge, secureOnly));// todo httponly , true); CookieHelper.addCookie(cookieName, encoded, cookiePath, null, null, maxAge, secureOnly, true);
//builder.cookie(new NewCookie(cookieName, encoded, cookiePath, null, null, maxAge, secureOnly));// todo httponly , true);
String sessionCookieValue = realm.getName() + "-" + user.getId(); String sessionCookieValue = realm.getName() + "-" + user.getId();
if (session != null) { if (session != null) {
sessionCookieValue += "-" + session.getId(); sessionCookieValue += "-" + session.getId();
} }
builder.cookie(new NewCookie(KEYCLOAK_SESSION_COOKIE, sessionCookieValue, cookiePath, null, null, maxAge, secureOnly));// todo httponly , true); // THIS SHOULD NOT BE A HTTPONLY COOKIE! It is used for OpenID Connect Iframe Session support!
builder.cookie(new NewCookie(KEYCLOAK_SESSION_COOKIE, sessionCookieValue, cookiePath, null, null, maxAge, secureOnly));
} }
public NewCookie createRememberMeCookie(RealmModel realm, UriInfo uriInfo) { public void createRememberMeCookie(HttpResponse response, RealmModel realm, UriInfo uriInfo) {
String path = getIdentityCookiePath(realm, uriInfo); String path = getIdentityCookiePath(realm, uriInfo);
boolean secureOnly = !realm.isSslNotRequired(); boolean secureOnly = !realm.isSslNotRequired();
// remember me cookie should be persistent // remember me cookie should be persistent
NewCookie cookie = new NewCookie(KEYCLOAK_REMEMBER_ME, "true", path, null, null, realm.getCentralLoginLifespan(), secureOnly);// todo httponly , true); //NewCookie cookie = new NewCookie(KEYCLOAK_REMEMBER_ME, "true", path, null, null, realm.getCentralLoginLifespan(), secureOnly);// todo httponly , true);
return cookie; CookieHelper.addCookie(KEYCLOAK_REMEMBER_ME, "true", path, null, null, realm.getCentralLoginLifespan(), secureOnly, true);
} }
protected String encodeToken(RealmModel realm, Object token) { protected String encodeToken(RealmModel realm, Object token) {
@ -117,15 +120,14 @@ public class AuthenticationManager {
public void expireIdentityCookie(RealmModel realm, UriInfo uriInfo) { public void expireIdentityCookie(RealmModel realm, UriInfo uriInfo) {
logger.debug("Expiring identity cookie"); logger.debug("Expiring identity cookie");
String path = getIdentityCookiePath(realm, uriInfo); String path = getIdentityCookiePath(realm, uriInfo);
String cookieName = KEYCLOAK_IDENTITY_COOKIE; expireCookie(realm, KEYCLOAK_IDENTITY_COOKIE, path, true);
expireCookie(cookieName, path); expireCookie(realm, KEYCLOAK_SESSION_COOKIE, path, false);
expireCookie(KEYCLOAK_SESSION_COOKIE, path);
} }
public void expireRememberMeCookie(RealmModel realm, UriInfo uriInfo) { public void expireRememberMeCookie(RealmModel realm, UriInfo uriInfo) {
logger.debug("Expiring remember me cookie"); logger.debug("Expiring remember me cookie");
String path = getIdentityCookiePath(realm, uriInfo); String path = getIdentityCookiePath(realm, uriInfo);
String cookieName = KEYCLOAK_REMEMBER_ME; String cookieName = KEYCLOAK_REMEMBER_ME;
expireCookie(cookieName, path); expireCookie(realm, cookieName, path, true);
} }
protected String getIdentityCookiePath(RealmModel realm, UriInfo uriInfo) { protected String getIdentityCookiePath(RealmModel realm, UriInfo uriInfo) {
@ -133,15 +135,10 @@ public class AuthenticationManager {
return uri.getRawPath(); return uri.getRawPath();
} }
public void expireCookie(String cookieName, String path) { public void expireCookie(RealmModel realm, String cookieName, String path, boolean httpOnly) {
HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
if (response == null) {
logger.debug("can't expire identity cookie, no HttpResponse");
return;
}
logger.debugv("Expiring cookie: {0} path: {1}", cookieName, path); logger.debugv("Expiring cookie: {0} path: {1}", cookieName, path);
NewCookie expireIt = new NewCookie(cookieName, "", path, null, "Expiring cookie", 0, false); boolean secureOnly = !realm.isSslNotRequired();
response.addNewCookie(expireIt); CookieHelper.addCookie(cookieName, "", path, null, "Expiring cookie", 0, secureOnly, httpOnly);
} }
public AuthResult authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) { public AuthResult authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {

View file

@ -99,6 +99,7 @@ public class RealmsResource {
@NoCache @NoCache
public String getLoginStatusIframe(final @PathParam("realm") String name, public String getLoginStatusIframe(final @PathParam("realm") String name,
@QueryParam("client_id") String client_id) { @QueryParam("client_id") String client_id) {
logger.info("getLoginStatusIframe");
AuthenticationManager auth = new AuthenticationManager(providers); AuthenticationManager auth = new AuthenticationManager(providers);
//logger.info("getting login-status-iframe.html for client_id: " + client_id); //logger.info("getting login-status-iframe.html for client_id: " + client_id);

View file

@ -374,8 +374,7 @@ public class TokenService {
AuthenticationStatus status = authManager.authenticateForm(clientConnection, realm, formData); AuthenticationStatus status = authManager.authenticateForm(clientConnection, realm, formData);
if (remember) { if (remember) {
NewCookie cookie = authManager.createRememberMeCookie(realm, uriInfo); authManager.createRememberMeCookie(response, realm, uriInfo);
response.addNewCookie(cookie);
} else { } else {
authManager.expireRememberMeCookie(realm, uriInfo); authManager.expireRememberMeCookie(realm, uriInfo);
} }

View file

@ -258,6 +258,7 @@ public class AdminConsole {
@Path("js/keycloak.js") @Path("js/keycloak.js")
@Produces("text/javascript") @Produces("text/javascript")
public Response getKeycloakJs() { public Response getKeycloakJs() {
logger.info("**** getting console keycloak.js");
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("keycloak.js"); InputStream inputStream = getClass().getClassLoader().getResourceAsStream("keycloak.js");
if (inputStream != null) { if (inputStream != null) {
return Response.ok(inputStream).build(); return Response.ok(inputStream).build();

View file

@ -0,0 +1,39 @@
package org.keycloak.services.util;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CookieHelper {
/**
* Set a response cookie. This solely exists because JAX-RS 1.1 does not support setting HttpOnly cookies
*
* @param name
* @param value
* @param path
* @param domain
* @param comment
* @param maxAge
* @param secure
* @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);
response.addCookie(cookie);
}
}