KEYCLOAK-12125 Introduce SameSite attribute in cookies

Co-authored-by: mhajas <mhajas@redhat.com>
Co-authored-by: Peter Skopek <pskopek@redhat.com>
This commit is contained in:
vmuzikar 2020-01-14 09:27:31 +01:00 committed by Bruno Oliveira da Silva
parent 922c9260a4
commit 03306b87e8
15 changed files with 319 additions and 75 deletions

View file

@ -81,7 +81,16 @@
function getCookie() function getCookie()
{ {
var name = 'KEYCLOAK_SESSION='; var cookie = getCookieByName('KEYCLOAK_SESSION');
if (cookie === null) {
return getCookieByName('KEYCLOAK_SESSION_LEGACY');
}
return cookie;
}
function getCookieByName(name)
{
name = name + '=';
var ca = document.cookie.split(';'); var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) for(var i=0; i<ca.length; i++)
{ {

View file

@ -208,7 +208,7 @@ public class ServletHttpFacade implements HttpFacade {
@Override @Override
public void setCookie(String name, String value, String path, String domain, int maxAge, boolean secure, boolean httpOnly) { public void setCookie(String name, String value, String path, String domain, int maxAge, boolean secure, boolean httpOnly) {
StringBuffer cookieBuf = new StringBuffer(); StringBuffer cookieBuf = new StringBuffer();
ServerCookie.appendCookieValue(cookieBuf, 1, name, value, path, domain, null, maxAge, secure, httpOnly); ServerCookie.appendCookieValue(cookieBuf, 1, name, value, path, domain, null, maxAge, secure, httpOnly, null);
String cookie = cookieBuf.toString(); String cookie = cookieBuf.toString();
response.addHeader("Set-Cookie", cookie); response.addHeader("Set-Cookie", cookie);
} }

View file

@ -219,7 +219,7 @@ public class CatalinaHttpFacade implements HttpFacade {
@Override @Override
public void setCookie(String name, String value, String path, String domain, int maxAge, boolean secure, boolean httpOnly) { public void setCookie(String name, String value, String path, String domain, int maxAge, boolean secure, boolean httpOnly) {
StringBuffer cookieBuf = new StringBuffer(); StringBuffer cookieBuf = new StringBuffer();
ServerCookie.appendCookieValue(cookieBuf, 1, name, value, path, domain, null, maxAge, secure, httpOnly); ServerCookie.appendCookieValue(cookieBuf, 1, name, value, path, domain, null, maxAge, secure, httpOnly, null);
String cookie = cookieBuf.toString(); String cookie = cookieBuf.toString();
response.addHeader("Set-Cookie", cookie); response.addHeader("Set-Cookie", cookie);
} }

View file

@ -32,6 +32,20 @@ public class ServerCookie implements Serializable {
private static final String tspecials = ",; "; private static final String tspecials = ",; ";
private static final String tspecials2 = "()<>@,;:\\\"/[]?={} \t"; private static final String tspecials2 = "()<>@,;:\\\"/[]?={} \t";
public enum SameSiteAttributeValue {
NONE("None"); // we currently support only SameSite=None; this might change in the future
private final String specValue;
SameSiteAttributeValue(String specValue) {
this.specValue = specValue;
}
@Override
public java.lang.String toString() {
return specValue;
}
}
/* /*
* Tests a string and returns true if the string counts as a * Tests a string and returns true if the string counts as a
* reserved token in the Java language. * reserved token in the Java language.
@ -173,7 +187,8 @@ public class ServerCookie implements Serializable {
String comment, String comment,
int maxAge, int maxAge,
boolean isSecure, boolean isSecure,
boolean httpOnly) { boolean httpOnly,
SameSiteAttributeValue sameSite) {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
// Servlet implementation checks name // Servlet implementation checks name
buf.append(name); buf.append(name);
@ -228,6 +243,12 @@ public class ServerCookie implements Serializable {
buf.append(path); buf.append(path);
} }
// SameSite
if (sameSite != null) {
buf.append("; SameSite=");
buf.append(sameSite.toString());
}
// Secure // Secure
if (isSecure) { if (isSecure) {
buf.append("; Secure"); buf.append("; Secure");

View file

@ -96,7 +96,8 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.keycloak.protocol.oidc.endpoints.AuthorizationEndpoint.LOGIN_SESSION_NOTE_ADDITIONAL_REQ_PARAMS_PREFIX; import static org.keycloak.common.util.ServerCookie.SameSiteAttributeValue;
import static org.keycloak.services.util.CookieHelper.getCookie;
/** /**
* Stateless object that manages authentication * Stateless object that manages authentication
@ -169,7 +170,7 @@ public class AuthenticationManager {
public static void expireUserSessionCookie(KeycloakSession session, UserSessionModel userSession, RealmModel realm, UriInfo uriInfo, HttpHeaders headers, ClientConnection connection) { public static void expireUserSessionCookie(KeycloakSession session, UserSessionModel userSession, RealmModel realm, UriInfo uriInfo, HttpHeaders headers, ClientConnection connection) {
try { try {
// check to see if any identity cookie is set with the same session and expire it if necessary // check to see if any identity cookie is set with the same session and expire it if necessary
Cookie cookie = headers.getCookies().get(KEYCLOAK_IDENTITY_COOKIE); Cookie cookie = CookieHelper.getCookie(headers.getCookies(), KEYCLOAK_IDENTITY_COOKIE);
if (cookie == null) return; if (cookie == null) return;
String tokenString = cookie.getValue(); String tokenString = cookie.getValue();
@ -621,7 +622,7 @@ public class AuthenticationManager {
maxAge = realm.getSsoSessionMaxLifespanRememberMe() > 0 ? realm.getSsoSessionMaxLifespanRememberMe() : realm.getSsoSessionMaxLifespan(); maxAge = realm.getSsoSessionMaxLifespanRememberMe() > 0 ? realm.getSsoSessionMaxLifespanRememberMe() : realm.getSsoSessionMaxLifespan();
} }
logger.debugv("Create login cookie - name: {0}, path: {1}, max-age: {2}", KEYCLOAK_IDENTITY_COOKIE, cookiePath, maxAge); logger.debugv("Create login cookie - name: {0}, path: {1}, max-age: {2}", KEYCLOAK_IDENTITY_COOKIE, cookiePath, maxAge);
CookieHelper.addCookie(KEYCLOAK_IDENTITY_COOKIE, encoded, cookiePath, null, null, maxAge, secureOnly, true); CookieHelper.addCookie(KEYCLOAK_IDENTITY_COOKIE, encoded, cookiePath, null, null, maxAge, secureOnly, true, SameSiteAttributeValue.NONE);
//builder.cookie(new NewCookie(cookieName, encoded, cookiePath, null, null, maxAge, secureOnly));// todo httponly , 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();
@ -631,7 +632,7 @@ public class AuthenticationManager {
// THIS SHOULD NOT BE A HTTPONLY COOKIE! It is used for OpenID Connect Iframe Session support! // THIS SHOULD NOT BE A HTTPONLY COOKIE! It is used for OpenID Connect Iframe Session support!
// Max age should be set to the max lifespan of the session as it's used to invalidate old-sessions on re-login // Max age should be set to the max lifespan of the session as it's used to invalidate old-sessions on re-login
int sessionCookieMaxAge = session.isRememberMe() && realm.getSsoSessionMaxLifespanRememberMe() > 0 ? realm.getSsoSessionMaxLifespanRememberMe() : realm.getSsoSessionMaxLifespan(); int sessionCookieMaxAge = session.isRememberMe() && realm.getSsoSessionMaxLifespanRememberMe() > 0 ? realm.getSsoSessionMaxLifespanRememberMe() : realm.getSsoSessionMaxLifespan();
CookieHelper.addCookie(KEYCLOAK_SESSION_COOKIE, sessionCookieValue, cookiePath, null, null, sessionCookieMaxAge, secureOnly, false); CookieHelper.addCookie(KEYCLOAK_SESSION_COOKIE, sessionCookieValue, cookiePath, null, null, sessionCookieMaxAge, secureOnly, false, SameSiteAttributeValue.NONE);
P3PHelper.addP3PHeader(); P3PHelper.addP3PHeader();
} }
@ -660,19 +661,19 @@ public class AuthenticationManager {
public static void expireIdentityCookie(RealmModel realm, UriInfo uriInfo, ClientConnection connection) { public static void expireIdentityCookie(RealmModel realm, UriInfo uriInfo, ClientConnection connection) {
logger.debug("Expiring identity cookie"); logger.debug("Expiring identity cookie");
String path = getIdentityCookiePath(realm, uriInfo); String path = getIdentityCookiePath(realm, uriInfo);
expireCookie(realm, KEYCLOAK_IDENTITY_COOKIE, path, true, connection); expireCookie(realm, KEYCLOAK_IDENTITY_COOKIE, path, true, connection, SameSiteAttributeValue.NONE);
expireCookie(realm, KEYCLOAK_SESSION_COOKIE, path, false, connection); expireCookie(realm, KEYCLOAK_SESSION_COOKIE, path, false, connection, SameSiteAttributeValue.NONE);
String oldPath = getOldCookiePath(realm, uriInfo); String oldPath = getOldCookiePath(realm, uriInfo);
expireCookie(realm, KEYCLOAK_IDENTITY_COOKIE, oldPath, true, connection); expireCookie(realm, KEYCLOAK_IDENTITY_COOKIE, oldPath, true, connection, SameSiteAttributeValue.NONE);
expireCookie(realm, KEYCLOAK_SESSION_COOKIE, oldPath, false, connection); expireCookie(realm, KEYCLOAK_SESSION_COOKIE, oldPath, false, connection, SameSiteAttributeValue.NONE);
} }
public static void expireOldIdentityCookie(RealmModel realm, UriInfo uriInfo, ClientConnection connection) { public static void expireOldIdentityCookie(RealmModel realm, UriInfo uriInfo, ClientConnection connection) {
logger.debug("Expiring old identity cookie with wrong path"); logger.debug("Expiring old identity cookie with wrong path");
String oldPath = getOldCookiePath(realm, uriInfo); String oldPath = getOldCookiePath(realm, uriInfo);
expireCookie(realm, KEYCLOAK_IDENTITY_COOKIE, oldPath, true, connection); expireCookie(realm, KEYCLOAK_IDENTITY_COOKIE, oldPath, true, connection, SameSiteAttributeValue.NONE);
expireCookie(realm, KEYCLOAK_SESSION_COOKIE, oldPath, false, connection); expireCookie(realm, KEYCLOAK_SESSION_COOKIE, oldPath, false, connection, SameSiteAttributeValue.NONE);
} }
@ -680,14 +681,14 @@ public class AuthenticationManager {
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(realm, cookieName, path, true, connection); expireCookie(realm, cookieName, path, true, connection, null);
} }
public static void expireOldAuthSessionCookie(RealmModel realm, UriInfo uriInfo, ClientConnection connection) { public static void expireOldAuthSessionCookie(RealmModel realm, UriInfo uriInfo, ClientConnection connection) {
logger.debugv("Expire {1} cookie .", AuthenticationSessionManager.AUTH_SESSION_ID); logger.debugv("Expire {1} cookie .", AuthenticationSessionManager.AUTH_SESSION_ID);
String oldPath = getOldCookiePath(realm, uriInfo); String oldPath = getOldCookiePath(realm, uriInfo);
expireCookie(realm, AuthenticationSessionManager.AUTH_SESSION_ID, oldPath, true, connection); expireCookie(realm, AuthenticationSessionManager.AUTH_SESSION_ID, oldPath, true, connection, null);
} }
protected static String getIdentityCookiePath(RealmModel realm, UriInfo uriInfo) { protected static String getIdentityCookiePath(RealmModel realm, UriInfo uriInfo) {
@ -710,10 +711,10 @@ public class AuthenticationManager {
return uri.getRawPath(); return uri.getRawPath();
} }
public static void expireCookie(RealmModel realm, String cookieName, String path, boolean httpOnly, ClientConnection connection) { public static void expireCookie(RealmModel realm, String cookieName, String path, boolean httpOnly, ClientConnection connection, SameSiteAttributeValue sameSite) {
logger.debugf("Expiring cookie: %s path: %s", cookieName, path); logger.debugf("Expiring cookie: %s path: %s", cookieName, path);
boolean secureOnly = realm.getSslRequired().isRequired(connection);; boolean secureOnly = realm.getSslRequired().isRequired(connection);;
CookieHelper.addCookie(cookieName, "", path, null, "Expiring cookie", 0, secureOnly, httpOnly); CookieHelper.addCookie(cookieName, "", path, null, "Expiring cookie", 0, secureOnly, httpOnly, sameSite);
} }
public AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm) { public AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm) {
@ -721,7 +722,7 @@ public class AuthenticationManager {
} }
public static AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm, boolean checkActive) { public static AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm, boolean checkActive) {
Cookie cookie = session.getContext().getRequestHeaders().getCookies().get(KEYCLOAK_IDENTITY_COOKIE); Cookie cookie = CookieHelper.getCookie(session.getContext().getRequestHeaders().getCookies(), KEYCLOAK_IDENTITY_COOKIE);
if (cookie == null || "".equals(cookie.getValue())) { if (cookie == null || "".equals(cookie.getValue())) {
logger.debugv("Could not find cookie: {0}", KEYCLOAK_IDENTITY_COOKIE); logger.debugv("Could not find cookie: {0}", KEYCLOAK_IDENTITY_COOKIE);
return null; return null;
@ -756,7 +757,7 @@ public class AuthenticationManager {
ClientSessionContext clientSessionCtx, ClientSessionContext clientSessionCtx,
HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection, HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection,
EventBuilder event, AuthenticationSessionModel authSession, LoginProtocol protocol) { EventBuilder event, AuthenticationSessionModel authSession, LoginProtocol protocol) {
Cookie sessionCookie = request.getHttpHeaders().getCookies().get(AuthenticationManager.KEYCLOAK_SESSION_COOKIE); Cookie sessionCookie = getCookie(request.getHttpHeaders().getCookies(), AuthenticationManager.KEYCLOAK_SESSION_COOKIE);
if (sessionCookie != null) { if (sessionCookie != null) {
String[] split = sessionCookie.getValue().split("/"); String[] split = sessionCookie.getValue().split("/");
@ -801,7 +802,7 @@ public class AuthenticationManager {
} }
public static String getSessionIdFromSessionCookie(KeycloakSession session) { public static String getSessionIdFromSessionCookie(KeycloakSession session) {
Cookie cookie = session.getContext().getRequestHeaders().getCookies().get(KEYCLOAK_SESSION_COOKIE); Cookie cookie = getCookie(session.getContext().getRequestHeaders().getCookies(), KEYCLOAK_SESSION_COOKIE);
if (cookie == null || "".equals(cookie.getValue())) { if (cookie == null || "".equals(cookie.getValue())) {
logger.debugv("Could not find cookie: {0}", KEYCLOAK_SESSION_COOKIE); logger.debugv("Could not find cookie: {0}", KEYCLOAK_SESSION_COOKIE);
return null; return null;

View file

@ -17,12 +17,6 @@
package org.keycloak.services.util; package org.keycloak.services.util;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.HttpResponse; import org.jboss.resteasy.spi.HttpResponse;
import org.keycloak.common.util.Resteasy; import org.keycloak.common.util.Resteasy;
@ -30,6 +24,14 @@ import org.keycloak.common.util.ServerCookie;
import javax.ws.rs.core.Cookie; import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static org.keycloak.common.util.ServerCookie.SameSiteAttributeValue;
/** /**
@ -38,11 +40,46 @@ import javax.ws.rs.core.HttpHeaders;
*/ */
public class CookieHelper { public class CookieHelper {
public static final String LEGACY_COOKIE = "_LEGACY";
private static final Logger logger = Logger.getLogger(CookieHelper.class); private static final Logger logger = Logger.getLogger(CookieHelper.class);
/** /**
* Set a response cookie. This solely exists because JAX-RS 1.1 does not support setting HttpOnly cookies * 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
* @param sameSite
*/
public static void addCookie(String name, String value, String path, String domain, String comment, int maxAge, boolean secure, boolean httpOnly, SameSiteAttributeValue sameSite) {
SameSiteAttributeValue sameSiteParam = sameSite;
// when expiring a cookie we shouldn't set the sameSite attribute; if we set e.g. SameSite=None when expiring a cookie, the new cookie (with maxAge == 0)
// might be rejected by the browser in some cases resulting in leaving the original cookie untouched; that can even prevent user from accessing their application
if (maxAge == 0) {
sameSite = null;
}
boolean secure_sameSite = sameSite == SameSiteAttributeValue.NONE || secure; // when SameSite=None, Secure attribute must be set
HttpResponse response = Resteasy.getContextData(HttpResponse.class);
StringBuffer cookieBuf = new StringBuffer();
ServerCookie.appendCookieValue(cookieBuf, 1, name, value, path, domain, comment, maxAge, secure_sameSite, httpOnly, sameSite);
String cookie = cookieBuf.toString();
response.getOutputHeaders().add(HttpHeaders.SET_COOKIE, cookie);
// a workaround for browser in older Apple OSs browsers ignore cookies with SameSite=None
if (sameSiteParam == SameSiteAttributeValue.NONE) {
addCookie(name + LEGACY_COOKIE, value, path, domain, comment, maxAge, secure, httpOnly, null);
}
}
/**
* Set a response cookie avoiding SameSite parameter
* @param name * @param name
* @param value * @param value
* @param path * @param path
@ -53,11 +90,7 @@ public class CookieHelper {
* @param httpOnly * @param httpOnly
*/ */
public static void addCookie(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 = Resteasy.getContextData(HttpResponse.class); addCookie(name, value, path, domain, comment, maxAge, secure, httpOnly, null);
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);
} }
@ -93,4 +126,16 @@ public class CookieHelper {
return cookies; return cookies;
} }
public static Cookie getCookie(Map<String, Cookie> cookies, String name) {
Cookie cookie = cookies.get(name);
if (cookie != null) {
return cookie;
}
else {
String legacy = name + LEGACY_COOKIE;
logger.debugv("Couldn't find cookie {0}, trying {0}", name, legacy);
return cookies.get(legacy);
}
}
} }

View file

@ -58,6 +58,7 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.resource.RealmResourceProvider; import org.keycloak.services.resource.RealmResourceProvider;
import org.keycloak.services.scheduled.ClearExpiredUserSessions; import org.keycloak.services.scheduled.ClearExpiredUserSessions;
import org.keycloak.services.util.CookieHelper;
import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.UserStorageProvider;
import org.keycloak.testsuite.components.TestProvider; import org.keycloak.testsuite.components.TestProvider;
import org.keycloak.testsuite.components.TestProviderFactory; import org.keycloak.testsuite.components.TestProviderFactory;
@ -559,7 +560,7 @@ public class TestingResourceProvider implements RealmResourceProvider {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public String getSSOCookieValue() { public String getSSOCookieValue() {
Map<String, Cookie> cookies = request.getHttpHeaders().getCookies(); Map<String, Cookie> cookies = request.getHttpHeaders().getCookies();
Cookie cookie = cookies.get(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE); Cookie cookie = CookieHelper.getCookie(cookies, AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE);
if (cookie == null) return null; if (cookie == null) return null;
return cookie.getValue(); return cookie.getValue();
} }

View file

@ -43,5 +43,6 @@
<module name="org.hibernate"/> <module name="org.hibernate"/>
<module name="org.javassist"/> <module name="org.javassist"/>
<module name="org.jboss.modules"/> <module name="org.jboss.modules"/>
<module name="org.apache.httpcomponents.core"/>
</dependencies> </dependencies>
</module> </module>

View file

@ -74,6 +74,11 @@ public class ClientAttributeUpdater extends ServerResourceUpdater<ClientAttribut
return this; return this;
} }
public ClientAttributeUpdater setRedirectUris(List<String> values) {
this.rep.setRedirectUris(values);
return this;
}
public ClientAttributeUpdater removeAttribute(String name) { public ClientAttributeUpdater removeAttribute(String name) {
this.rep.getAttributes().remove(name); this.rep.getAttributes().remove(name);
return this; return this;

View file

@ -50,6 +50,11 @@ public class JSObjectBuilder {
return this; return this;
} }
public JSObjectBuilder disableCheckLoginIframe() {
arguments.put("checkLoginIframe", false);
return this;
}
public JSObjectBuilder loginRequiredOnLoad() { public JSObjectBuilder loginRequiredOnLoad() {
arguments.put("onLoad", "login-required"); arguments.put("onLoad", "login-required");
return this; return this;

View file

@ -0,0 +1,77 @@
package org.keycloak.testsuite.adapter.servlet;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.graphene.page.Page;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Test;
import org.keycloak.adapters.rotation.PublicKeyLocator;
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
import org.keycloak.testsuite.adapter.page.Employee2Servlet;
import org.keycloak.testsuite.adapter.page.EmployeeSigServlet;
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
import org.keycloak.testsuite.updaters.ClientAttributeUpdater;
import org.keycloak.testsuite.utils.arquillian.ContainerConstants;
import org.openqa.selenium.By;
import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collections;
import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.getAppServerContextRoot;
import static org.keycloak.testsuite.auth.page.AuthRealm.SAMLSERVLETDEMO;
import static org.keycloak.testsuite.saml.AbstractSamlTest.SAML_CLIENT_ID_EMPLOYEE_2;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
/**
* @author mhajas
*/
@AppServerContainer(ContainerConstants.APP_SERVER_UNDERTOW)
@AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY)
@AppServerContainer(ContainerConstants.APP_SERVER_WILDFLY_DEPRECATED)
@AppServerContainer(ContainerConstants.APP_SERVER_EAP)
@AppServerContainer(ContainerConstants.APP_SERVER_EAP6)
@AppServerContainer(ContainerConstants.APP_SERVER_EAP71)
@AppServerContainer(ContainerConstants.APP_SERVER_TOMCAT7)
@AppServerContainer(ContainerConstants.APP_SERVER_TOMCAT8)
@AppServerContainer(ContainerConstants.APP_SERVER_TOMCAT9)
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
public class SAMLSameSiteTest extends AbstractSAMLServletAdapterTest {
private static final String NIP_IO_URL = "app-saml-127-0-0-1.nip.io";
private static final String NIP_IO_EMPLOYEE2_URL = getAppServerContextRoot().replace("localhost", NIP_IO_URL) + "/employee2/";
@Deployment(name = Employee2Servlet.DEPLOYMENT_NAME)
protected static WebArchive employee2() {
return samlServletDeployment(Employee2Servlet.DEPLOYMENT_NAME, WEB_XML_WITH_ACTION_FILTER, SendUsernameServlet.class, AdapterActionsFilter.class, PublicKeyLocator.class);
}
@Page
protected Employee2Servlet employee2ServletPage;
@Test
public void samlWorksWithSameSiteCookieTest() throws URISyntaxException {
getCleanup(SAMLSERVLETDEMO).addCleanup(ClientAttributeUpdater.forClient(adminClient, SAMLSERVLETDEMO, SAML_CLIENT_ID_EMPLOYEE_2)
.setRedirectUris(Collections.singletonList(NIP_IO_EMPLOYEE2_URL + "*"))
.setAdminUrl(NIP_IO_EMPLOYEE2_URL + "saml")
.update());
// Navigate to url with nip.io to trick browser the adapter lives on different domain
driver.navigate().to(NIP_IO_EMPLOYEE2_URL);
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
// Login and check the user is successfully logged in
testRealmSAMLPostLoginPage.form().login(bburkeUser);
waitUntilElement(By.xpath("//body")).text().contains("principal=bburke@redhat.com");
// Logout
driver.navigate().to(UriBuilder.fromUri(NIP_IO_EMPLOYEE2_URL).queryParam("GLO", "true").build().toASCIIString());
waitForPageToLoad();
// Check logged out
driver.navigate().to(NIP_IO_EMPLOYEE2_URL);
assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
}
}

View file

@ -17,6 +17,13 @@
package org.keycloak.testsuite.admin; package org.keycloak.testsuite.admin;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
@ -49,6 +56,8 @@ import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher; import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
import org.keycloak.testsuite.auth.page.AuthRealm; import org.keycloak.testsuite.auth.page.AuthRealm;
import org.keycloak.testsuite.pages.AppPage; import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
@ -61,18 +70,16 @@ import org.keycloak.testsuite.util.UserBuilder;
import org.openqa.selenium.Cookie; import org.openqa.selenium.Cookie;
import javax.ws.rs.ClientErrorException; import javax.ws.rs.ClientErrorException;
import javax.ws.rs.client.Client;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude; import static org.keycloak.testsuite.util.OAuthClient.AUTH_SERVER_ROOT;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
/** /**
* Tests Undertow Adapter * Tests Undertow Adapter
@ -238,21 +245,19 @@ public class ImpersonationTest extends AbstractKeycloakTest {
} }
private Cookie impersonate(Keycloak adminClient, String admin, String adminRealm) { private Cookie impersonate(Keycloak adminClient, String admin, String adminRealm) {
Client httpClient = javax.ws.rs.client.ClientBuilder.newClient(); BasicCookieStore cookieStore = new BasicCookieStore();
try (CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build()) {
try (Response response = httpClient.target(OAuthClient.AUTH_SERVER_ROOT) HttpUriRequest req = RequestBuilder.post()
.path("admin") .setUri(AUTH_SERVER_ROOT + "/admin/realms/test/users/" + impersonatedUserId + "/impersonation")
.path("realms") .addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + adminClient.tokenManager().getAccessTokenString())
.path("test") .build();
.path("users/" + impersonatedUserId + "/impersonation")
.request()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + adminClient.tokenManager().getAccessTokenString())
.post(null)) {
Map data = response.readEntity(Map.class); HttpResponse res = httpClient.execute(req);
String resBody = EntityUtils.toString(res.getEntity());
Assert.assertNotNull(data); Assert.assertNotNull(resBody);
Assert.assertNotNull(data.get("redirect")); Assert.assertTrue(resBody.contains("redirect"));
events.expect(EventType.IMPERSONATE) events.expect(EventType.IMPERSONATE)
.session(AssertEvents.isUUID()) .session(AssertEvents.isUUID())
@ -275,10 +280,15 @@ public class ImpersonationTest extends AbstractKeycloakTest {
Assert.assertNotNull(notes.get(ImpersonationSessionNote.IMPERSONATOR_ID.toString())); Assert.assertNotNull(notes.get(ImpersonationSessionNote.IMPERSONATOR_ID.toString()));
Assert.assertEquals(admin, notes.get(ImpersonationSessionNote.IMPERSONATOR_USERNAME.toString())); Assert.assertEquals(admin, notes.get(ImpersonationSessionNote.IMPERSONATOR_USERNAME.toString()));
NewCookie cookie = response.getCookies().get(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE); org.apache.http.cookie.Cookie cookie = cookieStore.getCookies().stream()
.filter(c -> c.getName().equals(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE))
.findAny().orElse(null);
Assert.assertNotNull(cookie); Assert.assertNotNull(cookie);
return new Cookie(cookie.getName(), cookie.getValue(), cookie.getDomain(), cookie.getPath(), cookie.getExpiry(), cookie.isSecure(), cookie.isHttpOnly()); return new Cookie(cookie.getName(), cookie.getValue(), cookie.getDomain(), cookie.getPath(), cookie.getExpiryDate(), cookie.isSecure(), true);
}
catch (IOException e) {
throw new RuntimeException(e);
} }
} }

View file

@ -16,15 +16,6 @@
*/ */
package org.keycloak.testsuite.cookies; package org.keycloak.testsuite.cookies;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.auth.page.AuthRealm;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.OAuthClient.AuthorizationEndpointResponse;
import org.keycloak.testsuite.util.RealmBuilder;
import java.util.List;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.client.protocol.HttpClientContext;
@ -36,14 +27,34 @@ import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.junit.Test; import org.junit.Test;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.auth.page.AuthRealm;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.OAuthClient.AuthorizationEndpointResponse;
import org.keycloak.testsuite.util.RealmBuilder;
import org.openqa.selenium.Cookie;
import java.util.List;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.keycloak.services.managers.AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE;
import static org.keycloak.services.managers.AuthenticationManager.KEYCLOAK_SESSION_COOKIE;
import static org.keycloak.services.util.CookieHelper.LEGACY_COOKIE;
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson; import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWithLoginUrlOf;
/** /**
* *
* @author hmlnarik * @author hmlnarik
* @author Vaclav Muzikar <vmuzikar@redhat.com>
*/ */
public class CookieTest extends AbstractKeycloakTest { public class CookieTest extends AbstractKeycloakTest {
@ -58,10 +69,23 @@ public class CookieTest extends AbstractKeycloakTest {
testRealms.add(testRealm); testRealms.add(testRealm);
} }
@Override
public void setDefaultPageUriParameters() {
super.setDefaultPageUriParameters();
accountPage.setAuthRealm(AuthRealm.TEST);
}
@Test @Test
public void testCookieValue() throws Exception { public void testCookieValue() throws Exception {
accountPage.setAuthRealm(AuthRealm.TEST); testCookieValue(KEYCLOAK_IDENTITY_COOKIE);
}
@Test
public void testLegacyCookieValue() throws Exception {
testCookieValue(KEYCLOAK_IDENTITY_COOKIE + LEGACY_COOKIE);
}
private void testCookieValue(String cookieName) throws Exception {
final String accountClientId = realmsResouce().realm("test").clients().findByClientId("account").get(0).getId(); final String accountClientId = realmsResouce().realm("test").clients().findByClientId("account").get(0).getId();
final String clientSecret = realmsResouce().realm("test").clients().get(accountClientId).getSecret().getValue(); final String clientSecret = realmsResouce().realm("test").clients().get(accountClientId).getSecret().getValue();
@ -74,7 +98,7 @@ public class CookieTest extends AbstractKeycloakTest {
try (CloseableHttpClient hc = OAuthClient.newCloseableHttpClient()) { try (CloseableHttpClient hc = OAuthClient.newCloseableHttpClient()) {
BasicCookieStore cookieStore = new BasicCookieStore(); BasicCookieStore cookieStore = new BasicCookieStore();
BasicClientCookie cookie = new BasicClientCookie(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE, accessToken); BasicClientCookie cookie = new BasicClientCookie(cookieName, accessToken);
cookie.setDomain("localhost"); cookie.setDomain("localhost");
cookie.setPath("/"); cookie.setPath("/");
cookieStore.addCookie(cookie); cookieStore.addCookie(cookie);
@ -85,7 +109,7 @@ public class CookieTest extends AbstractKeycloakTest {
HttpGet get = new HttpGet(oauth.clientId("account").redirectUri(accountPage.buildUri().toString()).getLoginFormUrl()); HttpGet get = new HttpGet(oauth.clientId("account").redirectUri(accountPage.buildUri().toString()).getLoginFormUrl());
try (CloseableHttpResponse resp = hc.execute(get, localContext)) { try (CloseableHttpResponse resp = hc.execute(get, localContext)) {
final String pageContent = EntityUtils.toString(resp.getEntity()); final String pageContent = EntityUtils.toString(resp.getEntity());
// Ensure that we did not get to the account page ... // Ensure that we did not get to the account page ...
assertThat(pageContent, not(containsString("First name"))); assertThat(pageContent, not(containsString("First name")));
assertThat(pageContent, not(containsString("Last name"))); assertThat(pageContent, not(containsString("Last name")));
@ -99,8 +123,6 @@ public class CookieTest extends AbstractKeycloakTest {
@Test @Test
public void testCookieValueLoggedOut() throws Exception { public void testCookieValueLoggedOut() throws Exception {
accountPage.setAuthRealm(AuthRealm.TEST);
final String accountClientId = realmsResouce().realm("test").clients().findByClientId("account").get(0).getId(); final String accountClientId = realmsResouce().realm("test").clients().findByClientId("account").get(0).getId();
final String clientSecret = realmsResouce().realm("test").clients().get(accountClientId).getSecret().getValue(); final String clientSecret = realmsResouce().realm("test").clients().get(accountClientId).getSecret().getValue();
@ -114,7 +136,7 @@ public class CookieTest extends AbstractKeycloakTest {
try (CloseableHttpClient hc = OAuthClient.newCloseableHttpClient()) { try (CloseableHttpClient hc = OAuthClient.newCloseableHttpClient()) {
BasicCookieStore cookieStore = new BasicCookieStore(); BasicCookieStore cookieStore = new BasicCookieStore();
BasicClientCookie cookie = new BasicClientCookie(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE, accessToken); BasicClientCookie cookie = new BasicClientCookie(KEYCLOAK_IDENTITY_COOKIE, accessToken);
cookie.setDomain("localhost"); cookie.setDomain("localhost");
cookie.setPath("/"); cookie.setPath("/");
cookieStore.addCookie(cookie); cookieStore.addCookie(cookie);
@ -137,4 +159,34 @@ public class CookieTest extends AbstractKeycloakTest {
} }
} }
@Test
public void legacyCookiesTest() {
accountPage.navigateTo();
assertCurrentUrlStartsWithLoginUrlOf(accountPage);
loginPage.login("test-user@localhost", "password");
Cookie sameSiteIdentityCookie = driver.manage().getCookieNamed(KEYCLOAK_IDENTITY_COOKIE);
Cookie legacyIdentityCookie = driver.manage().getCookieNamed(KEYCLOAK_IDENTITY_COOKIE + LEGACY_COOKIE);
Cookie sameSiteSessionCookie = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE);
Cookie legacySessionCookie = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE + LEGACY_COOKIE);
assertSameSiteCookies(sameSiteIdentityCookie, legacyIdentityCookie);
assertSameSiteCookies(sameSiteSessionCookie, legacySessionCookie);
}
private void assertSameSiteCookies(Cookie sameSiteCookie, Cookie legacyCookie) {
assertNotNull("SameSite cookie shouldn't be null", sameSiteCookie);
assertNotNull("Legacy cookie shouldn't be null", legacyCookie);
assertEquals(sameSiteCookie.getValue(), legacyCookie.getValue());
assertEquals(sameSiteCookie.getDomain(), legacyCookie.getDomain());
assertEquals(sameSiteCookie.getPath(), legacyCookie.getPath());
assertEquals(sameSiteCookie.getExpiry(), legacyCookie.getExpiry());
assertTrue("SameSite cookie should always have Secure attribute", sameSiteCookie.isSecure());
assertFalse("Legacy cookie shouldn't have Secure attribute", legacyCookie.isSecure()); // this relies on test realm config
assertEquals(sameSiteCookie.isHttpOnly(), legacyCookie.isHttpOnly());
// WebDriver currently doesn't support SameSite attribute therefore we cannot check it's present in the cookie
}
} }

View file

@ -45,6 +45,7 @@ public abstract class AbstractJavascriptTest extends AbstractAuthTest {
void apply(T a, U b, V c, W d); void apply(T a, U b, V c, W d);
} }
public static final String NIP_IO_URL = "js-app-127-0-0-1.nip.io";
public static final String CLIENT_ID = "js-console"; public static final String CLIENT_ID = "js-console";
public static final String REALM_NAME = "test"; public static final String REALM_NAME = "test";
public static final String SPACE_REALM_NAME = "Example realm"; public static final String SPACE_REALM_NAME = "Example realm";
@ -112,7 +113,8 @@ public abstract class AbstractJavascriptTest extends AbstractAuthTest {
.client( .client(
ClientBuilder.create() ClientBuilder.create()
.clientId(CLIENT_ID) .clientId(CLIENT_ID)
.redirectUris(oauth.SERVER_ROOT + JAVASCRIPT_URL + "/*", oauth.SERVER_ROOT + JAVASCRIPT_ENCODED_SPACE_URL + "/*") .redirectUris(oauth.SERVER_ROOT.replace("localhost", NIP_IO_URL) + JAVASCRIPT_URL + "/*", oauth.SERVER_ROOT + JAVASCRIPT_ENCODED_SPACE_URL + "/*")
.addWebOrigin(oauth.SERVER_ROOT.replace("localhost", NIP_IO_URL))
.publicClient() .publicClient()
) )
.accessTokenLifespan(30 + TOKEN_LIFESPAN_LEEWAY) .accessTokenLifespan(30 + TOKEN_LIFESPAN_LEEWAY)

View file

@ -38,6 +38,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static java.lang.Math.toIntExact; import static java.lang.Math.toIntExact;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.both; import static org.hamcrest.CoreMatchers.both;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.greaterThan;
@ -83,12 +84,17 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
@Before @Before
public void setDefaultEnvironment() { public void setDefaultEnvironment() {
testAppUrl = authServerContextRootPage + JAVASCRIPT_URL + "/index.html"; testAppUrl = authServerContextRootPage.toString().replace("localhost", NIP_IO_URL) + JAVASCRIPT_URL + "/index.html";
jsDriverTestRealmLoginPage.setAuthRealm(REALM_NAME); jsDriverTestRealmLoginPage.setAuthRealm(REALM_NAME);
oAuthGrantPage.setAuthRealm(REALM_NAME); oAuthGrantPage.setAuthRealm(REALM_NAME);
applicationsPage.setAuthRealm(REALM_NAME); applicationsPage.setAuthRealm(REALM_NAME);
jsDriver.navigate().to(oauth.getLoginFormUrl());
waitForPageToLoad();
events.poll();
jsDriver.manage().deleteAllCookies();
jsDriver.navigate().to(testAppUrl); jsDriver.navigate().to(testAppUrl);
waitUntilElement(outputArea).is().present(); waitUntilElement(outputArea).is().present();
@ -141,8 +147,15 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
.login(this::assertOnLoginPage) .login(this::assertOnLoginPage)
.loginForm(testUser, this::assertOnTestAppUrl) .loginForm(testUser, this::assertOnTestAppUrl)
.init(defaultArguments(), this::assertSuccessfullyLoggedIn) .init(defaultArguments(), this::assertSuccessfullyLoggedIn)
.logout(this::assertOnTestAppUrl)
.init(defaultArguments(), this::assertInitNotAuth)
.login("{kcLocale: 'de'}", assertLocaleIsSet("de")) .login("{kcLocale: 'de'}", assertLocaleIsSet("de"))
.loginForm(testUser, this::assertOnTestAppUrl)
.init(defaultArguments(), this::assertSuccessfullyLoggedIn) .init(defaultArguments(), this::assertSuccessfullyLoggedIn)
.logout(this::assertOnTestAppUrl)
.init(defaultArguments(), this::assertInitNotAuth)
.login("{kcLocale: 'en'}", assertLocaleIsSet("en")); .login("{kcLocale: 'en'}", assertLocaleIsSet("en"));
} }
@ -166,7 +179,7 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
.init(checkSSO, this::assertSuccessfullyLoggedIn) .init(checkSSO, this::assertSuccessfullyLoggedIn)
.refresh() .refresh()
.init(checkSSO .init(checkSSO
.add("silentCheckSsoRedirectUri", authServerContextRootPage + JAVASCRIPT_URL + "/silent-check-sso.html") .add("silentCheckSsoRedirectUri", authServerContextRootPage.toString().replace("localhost", NIP_IO_URL) + JAVASCRIPT_URL + "/silent-check-sso.html")
, this::assertSuccessfullyLoggedIn); , this::assertSuccessfullyLoggedIn);
} }
@ -179,8 +192,8 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
.init(checkSSO, this::assertSuccessfullyLoggedIn) .init(checkSSO, this::assertSuccessfullyLoggedIn)
.refresh() .refresh()
.init(checkSSO .init(checkSSO
.add("checkLoginIframe", false) .disableCheckLoginIframe()
.add("silentCheckSsoRedirectUri", authServerContextRootPage + JAVASCRIPT_URL + "/silent-check-sso.html") .add("silentCheckSsoRedirectUri", authServerContextRootPage.toString().replace("localhost", NIP_IO_URL) + JAVASCRIPT_URL + "/silent-check-sso.html")
, this::assertSuccessfullyLoggedIn); , this::assertSuccessfullyLoggedIn);
} }
@ -205,7 +218,7 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
JSObjectBuilder checkSSO = defaultArguments().checkSSOOnLoad(); JSObjectBuilder checkSSO = defaultArguments().checkSSOOnLoad();
testExecutor.init(checkSSO testExecutor.init(checkSSO
.add("checkLoginIframe", false) .add("checkLoginIframe", false)
.add("silentCheckSsoRedirectUri", authServerContextRootPage + JAVASCRIPT_URL + "/silent-check-sso.html") .add("silentCheckSsoRedirectUri", authServerContextRootPage.toString().replace("localhost", NIP_IO_URL) + JAVASCRIPT_URL + "/silent-check-sso.html")
, this::assertInitNotAuth); , this::assertInitNotAuth);
} }
@ -378,7 +391,8 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
.addHeader("Authorization", "Bearer ' + keycloak.token + '"); .addHeader("Authorization", "Bearer ' + keycloak.token + '");
testExecutor.init(defaultArguments()) testExecutor.init(defaultArguments())
.sendXMLHttpRequest(request, assertResponseStatus(401)) // Possibility of 0 and 401 is caused by this issue: https://issues.redhat.com/browse/KEYCLOAK-12686
.sendXMLHttpRequest(request, response -> assertThat(response, hasEntry(is("status"), anyOf(is(0L), is(401L)))))
.refresh(); .refresh();
if (!"phantomjs".equals(System.getProperty("js.browser"))) { if (!"phantomjs".equals(System.getProperty("js.browser"))) {
// I have no idea why, but this request doesn't work with phantomjs, it works in chrome // I have no idea why, but this request doesn't work with phantomjs, it works in chrome
@ -422,7 +436,8 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
setTimeOffset(67); setTimeOffset(67);
testExecutor.addTimeSkew(-34) testExecutor.addTimeSkew(-34)
.sendXMLHttpRequest(request, assertResponseStatus(401)) // Possibility of 0 and 401 is caused by this issue: https://issues.redhat.com/browse/KEYCLOAK-12686
.sendXMLHttpRequest(request, response -> assertThat(response, hasEntry(is("status"), anyOf(is(0L), is(401L)))))
.refreshToken(5, assertEventsContains("Auth Refresh Success")) .refreshToken(5, assertEventsContains("Auth Refresh Success"))
.sendXMLHttpRequest(request, assertResponseStatus(200)); .sendXMLHttpRequest(request, assertResponseStatus(200));
} }