diff --git a/server-spi-private/src/main/java/org/keycloak/cookie/CookieMaxAge.java b/server-spi-private/src/main/java/org/keycloak/cookie/CookieMaxAge.java index cfd6f980a1..1023c49cf9 100644 --- a/server-spi-private/src/main/java/org/keycloak/cookie/CookieMaxAge.java +++ b/server-spi-private/src/main/java/org/keycloak/cookie/CookieMaxAge.java @@ -6,4 +6,6 @@ public interface CookieMaxAge { int SESSION = -1; + int YEAR = 365 * 24 * 60 * 60; + } diff --git a/server-spi-private/src/main/java/org/keycloak/cookie/CookiePath.java b/server-spi-private/src/main/java/org/keycloak/cookie/CookiePath.java index 33c5ce1002..0d5f5f21ee 100644 --- a/server-spi-private/src/main/java/org/keycloak/cookie/CookiePath.java +++ b/server-spi-private/src/main/java/org/keycloak/cookie/CookiePath.java @@ -1,6 +1,6 @@ package org.keycloak.cookie; -enum CookiePath { +public enum CookiePath { REALM, REQUEST } diff --git a/server-spi-private/src/main/java/org/keycloak/cookie/CookieScope.java b/server-spi-private/src/main/java/org/keycloak/cookie/CookieScope.java index 42ec185996..79ce56fb3b 100644 --- a/server-spi-private/src/main/java/org/keycloak/cookie/CookieScope.java +++ b/server-spi-private/src/main/java/org/keycloak/cookie/CookieScope.java @@ -2,7 +2,7 @@ package org.keycloak.cookie; import org.keycloak.common.util.ServerCookie; -enum CookieScope { +public enum CookieScope { // Internal cookies are only available for direct requests to Keycloak INTERNAL(ServerCookie.SameSiteAttributeValue.STRICT, true), diff --git a/server-spi-private/src/main/java/org/keycloak/cookie/CookieType.java b/server-spi-private/src/main/java/org/keycloak/cookie/CookieType.java index 8c8dc79b30..4a48d4237a 100644 --- a/server-spi-private/src/main/java/org/keycloak/cookie/CookieType.java +++ b/server-spi-private/src/main/java/org/keycloak/cookie/CookieType.java @@ -1,29 +1,48 @@ package org.keycloak.cookie; -public enum CookieType { +import jakarta.annotation.Nullable; - KEYCLOAK_LOCALE(CookiePath.REALM, CookieScope.INTERNAL, CookieMaxAge.SESSION), - WELCOME_STATE_CHECKER(CookiePath.REQUEST, CookieScope.INTERNAL, 300), - KC_AUTH_STATE(CookiePath.REALM, CookieScope.LEGACY_JS), // TODO Change CookieScope - KC_RESTART(CookiePath.REALM, CookieScope.LEGACY, CookieMaxAge.SESSION); // TODO Change CookieScope +public final class CookieType { + public static final CookieType AUTH_DETACHED = new CookieType("KC_STATE_CHECKER", false, CookiePath.REALM, CookieScope.LEGACY, null); + public static final CookieType AUTH_RESTART = new CookieType("KC_RESTART", false, CookiePath.REALM, CookieScope.LEGACY, CookieMaxAge.SESSION); + public static final CookieType AUTH_SESSION_ID = new CookieType("AUTH_SESSION_ID", true, CookiePath.REALM, CookieScope.FEDERATION, CookieMaxAge.SESSION); + public static final CookieType AUTH_STATE = new CookieType("KC_AUTH_STATE", false, CookiePath.REALM, CookieScope.LEGACY_JS, null); + public static final CookieType IDENTITY = new CookieType("KEYCLOAK_IDENTITY", true, CookiePath.REALM, CookieScope.FEDERATION, null); + public static final CookieType LOCALE = new CookieType("KEYCLOAK_LOCALE", false, CookiePath.REALM, CookieScope.LEGACY, CookieMaxAge.SESSION); + public static final CookieType LOGIN_HINT = new CookieType("KEYCLOAK_REMEMBER_ME", false, CookiePath.REALM, CookieScope.LEGACY, CookieMaxAge.YEAR); + public static final CookieType SESSION = new CookieType("KEYCLOAK_SESSION", true, CookiePath.REALM, CookieScope.FEDERATION_JS, null); + public static final CookieType WELCOME_CSRF = new CookieType("WELCOME_STATE_CHECKER", false, CookiePath.REQUEST, CookieScope.INTERNAL, 300); + + private final String name; + private final String sameSiteLegacyName; private final CookiePath path; private final CookieScope scope; private final Integer defaultMaxAge; - CookieType(CookiePath path, CookieScope scope) { - this.path = path; - this.scope = scope; - this.defaultMaxAge = null; - } - - CookieType(CookiePath path, CookieScope scope, int defaultMaxAge) { + private CookieType(String name, boolean supportsSameSiteLegacy, CookiePath path, CookieScope scope, @Nullable Integer defaultMaxAge) { + this.name = name; + this.sameSiteLegacyName = supportsSameSiteLegacy ? name + "_LEGACY" : null; this.path = path; this.scope = scope; this.defaultMaxAge = defaultMaxAge; } + public String getName() { + return name; + } + + @Deprecated + public boolean supportsSameSiteLegacy() { + return sameSiteLegacyName != null; + } + + @Deprecated + public String getSameSiteLegacyName() { + return sameSiteLegacyName; + } + public CookiePath getPath() { return path; } diff --git a/server-spi/src/main/java/org/keycloak/locale/LocaleSelectorProvider.java b/server-spi/src/main/java/org/keycloak/locale/LocaleSelectorProvider.java index bcf1628557..36641593f4 100644 --- a/server-spi/src/main/java/org/keycloak/locale/LocaleSelectorProvider.java +++ b/server-spi/src/main/java/org/keycloak/locale/LocaleSelectorProvider.java @@ -38,4 +38,4 @@ public interface LocaleSelectorProvider extends Provider { */ Locale resolveLocale(RealmModel realm, UserModel user); -} \ No newline at end of file +} diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java index c32c6f0938..72afb561a6 100755 --- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java +++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/UsernamePasswordForm.java @@ -60,7 +60,7 @@ public class UsernamePasswordForm extends AbstractUsernameFormAuthenticator impl MultivaluedMap formData = new MultivaluedMapImpl<>(); String loginHint = context.getAuthenticationSession().getClientNote(OIDCLoginProtocol.LOGIN_HINT_PARAM); - String rememberMeUsername = AuthenticationManager.getRememberMeUsername(context.getRealm(), context.getHttpRequest().getHttpHeaders()); + String rememberMeUsername = AuthenticationManager.getRememberMeUsername(context.getSession()); if (context.getUser() != null) { LoginFormsProvider form = context.form(); diff --git a/services/src/main/java/org/keycloak/cookie/DefaultCookieProvider.java b/services/src/main/java/org/keycloak/cookie/DefaultCookieProvider.java index 38c34ca67f..e4e18a8283 100644 --- a/services/src/main/java/org/keycloak/cookie/DefaultCookieProvider.java +++ b/services/src/main/java/org/keycloak/cookie/DefaultCookieProvider.java @@ -1,25 +1,30 @@ package org.keycloak.cookie; import jakarta.ws.rs.core.Cookie; +import org.jboss.logging.Logger; import org.keycloak.common.util.ServerCookie; import org.keycloak.http.HttpCookie; -import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakContext; import org.keycloak.models.RealmModel; import org.keycloak.services.resources.RealmsResource; import org.keycloak.urls.UrlType; import java.net.URI; +import java.util.Map; public class DefaultCookieProvider implements CookieProvider { - private static final String LEGACY_SUFFIX = "_LEGACY"; + private static final Logger logger = Logger.getLogger(DefaultCookieProvider.class); - private KeycloakSession session; + private final KeycloakContext context; - private boolean legacyCookiesEnabled; + private final Map cookies; - public DefaultCookieProvider(KeycloakSession session, boolean legacyCookiesEnabled) { - this.session = session; + private final boolean legacyCookiesEnabled; + + public DefaultCookieProvider(KeycloakContext context, boolean legacyCookiesEnabled) { + this.context = context; + this.cookies = context.getRequestHeaders().getCookies(); this.legacyCookiesEnabled = legacyCookiesEnabled; } @@ -34,20 +39,25 @@ public class DefaultCookieProvider implements CookieProvider { @Override public void set(CookieType cookieType, String value, int maxAge) { - String name = cookieType.name(); + String name = cookieType.getName(); ServerCookie.SameSiteAttributeValue sameSite = cookieType.getScope().getSameSite(); boolean secure = resolveSecure(sameSite); String path = resolvePath(cookieType); boolean httpOnly = cookieType.getScope().isHttpOnly(); HttpCookie newCookie = new HttpCookie(1, name, value, path, null, null, maxAge, secure, httpOnly, sameSite); - session.getContext().getHttpResponse().setCookieIfAbsent(newCookie); + context.getHttpResponse().setCookieIfAbsent(newCookie); - if (legacyCookiesEnabled) { + logger.tracef("Setting cookie: name: %s, path: %s, same-site: %s, http-only: %s, max-age: %d", name, path, sameSite, httpOnly, maxAge); + + if (legacyCookiesEnabled && cookieType.supportsSameSiteLegacy()) { if (ServerCookie.SameSiteAttributeValue.NONE.equals(sameSite)) { - String legacyName = name + LEGACY_SUFFIX; + secure = resolveSecure(null); + String legacyName = cookieType.getSameSiteLegacyName(); HttpCookie legacyCookie = new HttpCookie(1, legacyName, value, path, null, null, maxAge, secure, httpOnly, null); - session.getContext().getHttpResponse().setCookieIfAbsent(legacyCookie); + context.getHttpResponse().setCookieIfAbsent(legacyCookie); + + logger.tracef("Setting legacy cookie: name: %s, path: %s, same-site: %s, http-only: %s, max-age: %d", legacyName, path, sameSite, httpOnly, maxAge); } } else { expireLegacy(cookieType); @@ -56,29 +66,36 @@ public class DefaultCookieProvider implements CookieProvider { @Override public String get(CookieType cookieType) { - Cookie cookie = session.getContext().getRequestHeaders().getCookies().get(cookieType.name()); + Cookie cookie = cookies.get(cookieType.getName()); + if (cookie == null && cookieType.supportsSameSiteLegacy()) { + cookie = cookies.get(cookieType.getSameSiteLegacyName()); + } return cookie != null ? cookie.getValue() : null; } @Override public void expire(CookieType cookieType) { - Cookie cookie = session.getContext().getRequestHeaders().getCookies().get(cookieType.name()); + Cookie cookie = cookies.get(cookieType.getName()); expire(cookie, cookieType); expireLegacy(cookieType); } private void expireLegacy(CookieType cookieType) { - String legacyName = cookieType.name() + LEGACY_SUFFIX; - Cookie legacyCookie = session.getContext().getRequestHeaders().getCookies().get(legacyName); - expire(legacyCookie, cookieType); + if (cookieType.supportsSameSiteLegacy()) { + String legacyName = cookieType.getSameSiteLegacyName(); + Cookie legacyCookie = cookies.get(legacyName); + expire(legacyCookie, cookieType); + } } private void expire(Cookie cookie, CookieType cookieType) { if (cookie != null) { String path = resolvePath(cookieType); - HttpCookie newCookie = new HttpCookie(1, cookie.getName(), "", path, null, null, 0, false, false, null); - session.getContext().getHttpResponse().setCookieIfAbsent(newCookie); + HttpCookie newCookie = new HttpCookie(1, cookie.getName(), "", path, null, null, CookieMaxAge.EXPIRED, false, false, null); + context.getHttpResponse().setCookieIfAbsent(newCookie); + + logger.tracef("Expiring cookie: name: %s, path: %s", cookie.getName(), path); } } @@ -89,23 +106,23 @@ public class DefaultCookieProvider implements CookieProvider { private String resolvePath(CookieType cookieType) { switch (cookieType.getPath()) { case REALM: - return RealmsResource.realmBaseUrl(session.getContext().getUri()).path("/").build(session.getContext().getRealm().getName()).getRawPath(); + return RealmsResource.realmBaseUrl(context.getUri()).path("/").build(context.getRealm().getName()).getRawPath(); case REQUEST: - return session.getContext().getUri().getRequestUri().getRawPath(); + return context.getUri().getRequestUri().getRawPath(); default: throw new IllegalArgumentException("Unsupported enum value " + cookieType.getPath().name()); } } private boolean resolveSecure(ServerCookie.SameSiteAttributeValue sameSite) { - URI requestUri = session.getContext().getUri().getRequestUri(); + URI requestUri = context.getUri().getRequestUri(); // SameSite=none requires secure context if (ServerCookie.SameSiteAttributeValue.NONE.equals(sameSite)) { return true; } - RealmModel realm = session.getContext().getRealm(); + RealmModel realm = context.getRealm(); if (realm != null && realm.getSslRequired().isRequired(requestUri.getHost())) { return true; } @@ -115,7 +132,7 @@ public class DefaultCookieProvider implements CookieProvider { } // Browsers consider 127.0.0.1, localhost and *.localhost as secure contexts - String frontendHostname = session.getContext().getUri(UrlType.FRONTEND).getRequestUri().getHost(); + String frontendHostname = context.getUri(UrlType.FRONTEND).getRequestUri().getHost(); if (frontendHostname.equals("127.0.0.1") || frontendHostname.equals("localhost") || frontendHostname.endsWith(".localhost")) { return true; } diff --git a/services/src/main/java/org/keycloak/cookie/DefaultCookieProviderFactory.java b/services/src/main/java/org/keycloak/cookie/DefaultCookieProviderFactory.java index b16b0ee4a2..31b3f1e42e 100644 --- a/services/src/main/java/org/keycloak/cookie/DefaultCookieProviderFactory.java +++ b/services/src/main/java/org/keycloak/cookie/DefaultCookieProviderFactory.java @@ -10,12 +10,12 @@ public class DefaultCookieProviderFactory implements CookieProviderFactory { @Override public CookieProvider create(KeycloakSession session) { - return new DefaultCookieProvider(session, legacyCookies); + return new DefaultCookieProvider(session.getContext(), legacyCookies); } @Override public void init(Config.Scope config) { - legacyCookies = config.getBoolean("legacyCookies", false); + legacyCookies = config.getBoolean("legacyCookies", true); } @Override diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/AuthenticationStateCookie.java b/services/src/main/java/org/keycloak/forms/login/freemarker/AuthenticationStateCookie.java index 904faad8c4..1cfce9d05d 100644 --- a/services/src/main/java/org/keycloak/forms/login/freemarker/AuthenticationStateCookie.java +++ b/services/src/main/java/org/keycloak/forms/login/freemarker/AuthenticationStateCookie.java @@ -23,16 +23,10 @@ import java.io.IOException; import java.util.Set; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.ws.rs.core.UriInfo; import org.jboss.logging.Logger; -import org.keycloak.common.ClientConnection; import org.keycloak.cookie.CookieProvider; import org.keycloak.cookie.CookieType; -import org.keycloak.models.KeycloakContext; import org.keycloak.models.KeycloakSession; -import org.keycloak.models.RealmModel; -import org.keycloak.services.managers.AuthenticationManager; -import org.keycloak.services.util.CookieHelper; import org.keycloak.sessions.RootAuthenticationSessionModel; import org.keycloak.util.JsonSerialization; @@ -76,16 +70,14 @@ public class AuthenticationStateCookie { try { String encoded = JsonSerialization.writeValueAsString(cookie); - logger.tracef("Generating new %s cookie. Cookie: %s, Cookie lifespan: %d", CookieType.KC_AUTH_STATE, encoded, cookieMaxAge); - - session.getProvider(CookieProvider.class).set(CookieType.KC_AUTH_STATE, encoded, cookieMaxAge); + session.getProvider(CookieProvider.class).set(CookieType.AUTH_STATE, encoded, cookieMaxAge); } catch (IOException ioe) { throw new IllegalStateException("Exception thrown when encoding cookie", ioe); } } public static void expireCookie(KeycloakSession session) { - session.getProvider(CookieProvider.class).expire(CookieType.KC_AUTH_STATE); + session.getProvider(CookieProvider.class).expire(CookieType.AUTH_STATE); } @Override diff --git a/services/src/main/java/org/keycloak/forms/login/freemarker/DetachedInfoStateChecker.java b/services/src/main/java/org/keycloak/forms/login/freemarker/DetachedInfoStateChecker.java index 10d4edaaa1..5029c523cd 100644 --- a/services/src/main/java/org/keycloak/forms/login/freemarker/DetachedInfoStateChecker.java +++ b/services/src/main/java/org/keycloak/forms/login/freemarker/DetachedInfoStateChecker.java @@ -20,18 +20,17 @@ package org.keycloak.forms.login.freemarker; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import jakarta.ws.rs.core.UriInfo; import org.jboss.logging.Logger; import org.keycloak.common.VerificationException; +import org.keycloak.cookie.CookieProvider; +import org.keycloak.cookie.CookieType; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.utils.KeycloakModelUtils; -import org.keycloak.services.managers.AuthenticationManager; -import org.keycloak.services.util.CookieHelper; /** * @author Marek Posolda @@ -40,7 +39,6 @@ public class DetachedInfoStateChecker { private static final Logger logger = Logger.getLogger(DetachedInfoStateChecker.class); - private static final String STATE_CHECKER_COOKIE_NAME = "KC_STATE_CHECKER"; public static final String STATE_CHECKER_PARAM = "kc_state_checker"; private final KeycloakSession session; @@ -53,8 +51,6 @@ public class DetachedInfoStateChecker { public DetachedInfoStateCookie generateAndSetCookie(String messageKey, String messageType, Integer status, String clientId, Object[] messageParameters) { UriInfo uriInfo = session.getContext().getHttpRequest().getUri(); - String path = AuthenticationManager.getRealmCookiePath(realm, uriInfo); - boolean secureOnly = realm.getSslRequired().isRequired(session.getContext().getConnection()); String currentStateCheckerInUrl = uriInfo.getQueryParameters().getFirst(STATE_CHECKER_PARAM); String newStateChecker = KeycloakModelUtils.generateId(); @@ -75,14 +71,13 @@ public class DetachedInfoStateChecker { } String encoded = session.tokens().encode(cookie); - logger.tracef("Generating new %s cookie. Cookie: %s, Cookie lifespan: %d", STATE_CHECKER_COOKIE_NAME, cookie, cookieMaxAge); - CookieHelper.addCookie(STATE_CHECKER_COOKIE_NAME, encoded, path, null, null, cookieMaxAge, secureOnly, true, session); + session.getProvider(CookieProvider.class).set(CookieType.AUTH_DETACHED, encoded, cookieMaxAge); return cookie; } public DetachedInfoStateCookie verifyStateCheckerParameter(String stateCheckerParam) throws VerificationException { - String cookieVal = CookieHelper.getCookieValue(session, STATE_CHECKER_COOKIE_NAME); + String cookieVal = session.getProvider(CookieProvider.class).get(CookieType.AUTH_DETACHED); if (cookieVal == null || cookieVal.isEmpty()) { throw new VerificationException("State checker cookie is empty"); } diff --git a/services/src/main/java/org/keycloak/locale/DefaultLocaleSelectorProvider.java b/services/src/main/java/org/keycloak/locale/DefaultLocaleSelectorProvider.java index b8febd0770..ebc58ee2b5 100644 --- a/services/src/main/java/org/keycloak/locale/DefaultLocaleSelectorProvider.java +++ b/services/src/main/java/org/keycloak/locale/DefaultLocaleSelectorProvider.java @@ -132,7 +132,7 @@ public class DefaultLocaleSelectorProvider implements LocaleSelectorProvider { return null; } - String localeCookie = session.getProvider(CookieProvider.class).get(CookieType.KEYCLOAK_LOCALE); + String localeCookie = session.getProvider(CookieProvider.class).get(CookieType.LOCALE); if (localeCookie == null) { return null; } diff --git a/services/src/main/java/org/keycloak/locale/DefaultLocaleUpdaterProvider.java b/services/src/main/java/org/keycloak/locale/DefaultLocaleUpdaterProvider.java index 4bc65c9f18..d587b7382b 100644 --- a/services/src/main/java/org/keycloak/locale/DefaultLocaleUpdaterProvider.java +++ b/services/src/main/java/org/keycloak/locale/DefaultLocaleUpdaterProvider.java @@ -59,13 +59,13 @@ public class DefaultLocaleUpdaterProvider implements LocaleUpdaterProvider { @Override public void updateLocaleCookie(String locale) { - session.getProvider(CookieProvider.class).set(CookieType.KEYCLOAK_LOCALE, locale); + session.getProvider(CookieProvider.class).set(CookieType.LOCALE, locale); logger.debugv("Updating locale cookie to {0}", locale); } @Override public void expireLocaleCookie() { - session.getProvider(CookieProvider.class).expire(CookieType.KEYCLOAK_LOCALE); + session.getProvider(CookieProvider.class).expire(CookieType.LOCALE); } @Override diff --git a/services/src/main/java/org/keycloak/protocol/RestartLoginCookie.java b/services/src/main/java/org/keycloak/protocol/RestartLoginCookie.java index 178a0330d0..d676a5121f 100644 --- a/services/src/main/java/org/keycloak/protocol/RestartLoginCookie.java +++ b/services/src/main/java/org/keycloak/protocol/RestartLoginCookie.java @@ -119,15 +119,15 @@ public class RestartLoginCookie implements Token { public static void setRestartCookie(KeycloakSession session, AuthenticationSessionModel authSession) { RestartLoginCookie restart = new RestartLoginCookie(authSession); String encoded = session.tokens().encode(restart); - session.getProvider(CookieProvider.class).set(CookieType.KC_RESTART, encoded); + session.getProvider(CookieProvider.class).set(CookieType.AUTH_RESTART, encoded); } public static void expireRestartCookie(KeycloakSession session) { - session.getProvider(CookieProvider.class).expire(CookieType.KC_RESTART); + session.getProvider(CookieProvider.class).expire(CookieType.AUTH_RESTART); } public static String getRestartCookie(KeycloakSession session){ - String cook = session.getProvider(CookieProvider.class).get(CookieType.KC_RESTART); + String cook = session.getProvider(CookieProvider.class).get(CookieType.AUTH_RESTART); if (cook == null) { logger.debug("KC_RESTART cookie doesn't exist"); return null; diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java index 977516905e..2ea246a7d3 100755 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java @@ -338,7 +338,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase { } private Response buildRegister() { - authManager.expireIdentityCookie(realm, session.getContext().getUri(), session); + authManager.expireIdentityCookie(session); AuthenticationFlowModel flow = realm.getRegistrationFlow(); String flowId = flow.getId(); @@ -350,7 +350,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase { } private Response buildForgotCredential() { - authManager.expireIdentityCookie(realm, session.getContext().getUri(), session); + authManager.expireIdentityCookie(session); AuthenticationFlowModel flow = realm.getResetCredentialsFlow(); String flowId = flow.getId(); 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 74b33fa62a..6091705bee 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -17,6 +17,8 @@ package org.keycloak.services.managers; import org.jboss.logging.Logger; +import org.keycloak.cookie.CookieProvider; +import org.keycloak.cookie.CookieType; import org.keycloak.http.HttpRequest; import org.keycloak.OAuth2Constants; import org.keycloak.TokenVerifier; @@ -83,13 +85,11 @@ import org.keycloak.services.resources.IdentityBrokerService; import org.keycloak.services.resources.LoginActionsService; import org.keycloak.services.resources.RealmsResource; import org.keycloak.services.util.AuthorizationContextUtil; -import org.keycloak.services.util.CookieHelper; import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.CommonClientSessionModel; import org.keycloak.sessions.RootAuthenticationSessionModel; import org.keycloak.util.TokenUtil; -import jakarta.ws.rs.core.Cookie; import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.NewCookie; import jakarta.ws.rs.core.Response; @@ -110,7 +110,6 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.keycloak.common.util.ServerCookie.SameSiteAttributeValue; import static org.keycloak.models.light.LightweightUserAdapter.isLightweightUser; import static org.keycloak.models.UserSessionModel.CORRESPONDING_SESSION_ID; import static org.keycloak.protocol.oidc.grants.device.DeviceGrantType.isOAuth2DeviceVerificationFlow; @@ -152,11 +151,8 @@ public class AuthenticationManager { protected static final Logger logger = Logger.getLogger(AuthenticationManager.class); public static final String FORM_USERNAME = "username"; - // used for auth login - public static final String KEYCLOAK_IDENTITY_COOKIE = "KEYCLOAK_IDENTITY"; // used solely to determine is user is logged in public static final String KEYCLOAK_SESSION_COOKIE = "KEYCLOAK_SESSION"; - public static final String KEYCLOAK_REMEMBER_ME = "KEYCLOAK_REMEMBER_ME"; // ** Logout related notes **/ // Flag in the logout session to specify if we use "system" client or real client @@ -210,7 +206,7 @@ public class AuthenticationManager { public static boolean expireUserSessionCookie(KeycloakSession session, UserSessionModel userSession, RealmModel realm, UriInfo uriInfo, HttpHeaders headers, ClientConnection connection) { try { // check to see if any identity cookie is set with the same session and expire it if necessary - String tokenString = CookieHelper.getCookieValue(session, KEYCLOAK_IDENTITY_COOKIE); + String tokenString = session.getProvider(CookieProvider.class).get(CookieType.IDENTITY); if (tokenString == null) return true; TokenVerifier verifier = TokenVerifier.create(tokenString, AccessToken.class) @@ -228,7 +224,7 @@ public class AuthenticationManager { AccessToken token = verifier.verify().getToken(); UserSessionModel cookieSession = session.sessions().getUserSession(realm, token.getSessionState()); if (cookieSession == null || !cookieSession.getId().equals(userSession.getId())) return true; - expireIdentityCookie(realm, uriInfo, session); + expireIdentityCookie(session); return true; } catch (Exception e) { return false; @@ -366,7 +362,7 @@ public class AuthenticationManager { } if (browserCookie && !browserCookiePresent) { // Update cookie if needed - asm.setAuthSessionCookie(authSessionId, realm); + asm.setAuthSessionCookie(authSessionId); } // See if we have logoutAuthSession inside current rootSession. Create new if not @@ -689,8 +685,8 @@ public class AuthenticationManager { checkUserSessionOnlyHasLoggedOutClients(realm, userSession, logoutAuthSession); // For resolving artifact we don't need any cookie, all details are stored in session storage so we can remove - expireIdentityCookie(realm, uriInfo, session); - expireRememberMeCookie(realm, uriInfo, session); + expireIdentityCookie(session); + expireRememberMeCookie(session); String method = userSession.getNote(KEYCLOAK_LOGOUT_PROTOCOL); EventBuilder event = new EventBuilder(realm, session, connection); @@ -775,18 +771,14 @@ public class AuthenticationManager { } public static void createLoginCookie(KeycloakSession keycloakSession, RealmModel realm, UserModel user, UserSessionModel session, UriInfo uriInfo, ClientConnection connection) { - String cookiePath = getRealmCookiePath(realm, uriInfo); String issuer = Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()); IdentityCookieToken identityCookieToken = createIdentityToken(keycloakSession, realm, user, session, issuer); String encoded = keycloakSession.tokens().encode(identityCookieToken); - boolean secureOnly = realm.getSslRequired().isRequired(connection); int maxAge = NewCookie.DEFAULT_MAX_AGE; if (session != null && session.isRememberMe()) { 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); - CookieHelper.addCookie(KEYCLOAK_IDENTITY_COOKIE, encoded, cookiePath, null, null, maxAge, secureOnly, true, SameSiteAttributeValue.NONE, keycloakSession); - //builder.cookie(new NewCookie(cookieName, encoded, cookiePath, null, null, maxAge, secureOnly));// todo httponly , true); + keycloakSession.getProvider(CookieProvider.class).set(CookieType.IDENTITY, encoded, maxAge); // With user-storage providers, user ID can contain special characters, which need to be encoded String sessionCookieValue = realm.getName() + "/" + Encode.urlEncode(user.getId()); @@ -796,7 +788,7 @@ public class AuthenticationManager { // 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 int sessionCookieMaxAge = session.isRememberMe() && realm.getSsoSessionMaxLifespanRememberMe() > 0 ? realm.getSsoSessionMaxLifespanRememberMe() : realm.getSsoSessionMaxLifespan(); - CookieHelper.addCookie(KEYCLOAK_SESSION_COOKIE, sessionCookieValue, cookiePath, null, null, sessionCookieMaxAge, secureOnly, false, SameSiteAttributeValue.NONE, keycloakSession); + keycloakSession.getProvider(CookieProvider.class).set(CookieType.SESSION, sessionCookieValue, sessionCookieMaxAge); } public static void createRememberMeCookie(String username, UriInfo uriInfo, KeycloakSession session) { @@ -808,17 +800,16 @@ public class AuthenticationManager { // remember me cookie should be persistent (hardcoded to 365 days for now) //NewCookie cookie = new NewCookie(KEYCLOAK_REMEMBER_ME, "true", path, null, null, realm.getCentralLoginLifespan(), secureOnly);// todo httponly , true); try { - CookieHelper.addCookie(KEYCLOAK_REMEMBER_ME, "username:" + URLEncoder.encode(username, "UTF-8"), path, null, null, 31536000, secureOnly, true, session); + session.getProvider(CookieProvider.class).set(CookieType.LOGIN_HINT, "username:" + URLEncoder.encode(username, "UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Failed to urlencode", e); } } - public static String getRememberMeUsername(RealmModel realm, HttpHeaders headers) { - if (realm.isRememberMe()) { - Cookie cookie = headers.getCookies().get(AuthenticationManager.KEYCLOAK_REMEMBER_ME); - if (cookie != null) { - String value = cookie.getValue(); + public static String getRememberMeUsername(KeycloakSession session) { + if (session.getContext().getRealm().isRememberMe()) { + String value = session.getProvider(CookieProvider.class).get(CookieType.LOGIN_HINT); + if (value != null) { String[] s = value.split(":"); if (s[0].equals("username") && s.length == 2) { try { @@ -832,27 +823,17 @@ public class AuthenticationManager { return null; } - public static void expireIdentityCookie(RealmModel realm, UriInfo uriInfo, KeycloakSession session) { - ClientConnection connection = session.getContext().getConnection(); - logger.debug("Expiring identity cookie"); - String path = getRealmCookiePath(realm, uriInfo); - expireCookie(realm, KEYCLOAK_IDENTITY_COOKIE, path, true, connection, SameSiteAttributeValue.NONE, session); - expireCookie(realm, KEYCLOAK_SESSION_COOKIE, path, false, connection, SameSiteAttributeValue.NONE, session); + public static void expireIdentityCookie(KeycloakSession session) { + session.getProvider(CookieProvider.class).expire(CookieType.IDENTITY); + session.getProvider(CookieProvider.class).expire(CookieType.SESSION); } - public static void expireRememberMeCookie(RealmModel realm, UriInfo uriInfo, KeycloakSession session) { - ClientConnection connection = session.getContext().getConnection(); - logger.debug("Expiring remember me cookie"); - String path = getRealmCookiePath(realm, uriInfo); - String cookieName = KEYCLOAK_REMEMBER_ME; - expireCookie(realm, cookieName, path, true, connection, null, session); + public static void expireRememberMeCookie(KeycloakSession session) { + session.getProvider(CookieProvider.class).expire(CookieType.LOGIN_HINT); } - public static void expireAuthSessionCookie(RealmModel realm, UriInfo uriInfo, KeycloakSession session) { - logger.debugv("Expire {1} cookie .", AuthenticationSessionManager.AUTH_SESSION_ID); - ClientConnection connection = session.getContext().getConnection(); - String oldPath = getRealmCookiePath(realm, uriInfo); - expireCookie(realm, AuthenticationSessionManager.AUTH_SESSION_ID, oldPath, true, connection, SameSiteAttributeValue.NONE, session); + public static void expireAuthSessionCookie(KeycloakSession session) { + session.getProvider(CookieProvider.class).expire(CookieType.AUTH_SESSION_ID); } public static String getRealmCookiePath(RealmModel realm, UriInfo uriInfo) { @@ -861,26 +842,20 @@ public class AuthenticationManager { return uri.getRawPath() + "/"; } - public static void expireCookie(RealmModel realm, String cookieName, String path, boolean httpOnly, ClientConnection connection, SameSiteAttributeValue sameSite, KeycloakSession session) { - logger.debugf("Expiring cookie: %s path: %s", cookieName, path); - boolean secureOnly = realm.getSslRequired().isRequired(connection);; - CookieHelper.addCookie(cookieName, "", path, null, "Expiring cookie", 0, secureOnly, httpOnly, sameSite, session); - } - public AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm) { return authenticateIdentityCookie(session, realm, true); } public static AuthResult authenticateIdentityCookie(KeycloakSession session, RealmModel realm, boolean checkActive) { - String tokenString = CookieHelper.getCookieValue(session, KEYCLOAK_IDENTITY_COOKIE); + String tokenString = session.getProvider(CookieProvider.class).get(CookieType.IDENTITY); if (tokenString == null || tokenString.isEmpty()) { - logger.debugv("Could not find cookie: {0}", KEYCLOAK_IDENTITY_COOKIE); + logger.debugv("Could not find cookie: {0}", CookieType.IDENTITY.getName()); return null; } AuthResult authResult = verifyIdentityToken(session, realm, session.getContext().getUri(), session.getContext().getConnection(), checkActive, false, null, true, tokenString, session.getContext().getRequestHeaders(), VALIDATE_IDENTITY_COOKIE); if (authResult == null) { - expireIdentityCookie(realm, session.getContext().getUri(), session); + expireIdentityCookie(session); return null; } authResult.getSession().setLastSessionRefresh(Time.currentTime()); @@ -905,7 +880,7 @@ public class AuthenticationManager { ClientSessionContext clientSessionCtx, HttpRequest request, UriInfo uriInfo, ClientConnection clientConnection, EventBuilder event, AuthenticationSessionModel authSession, LoginProtocol protocol) { - String sessionCookie = CookieHelper.getCookieValue(session, AuthenticationManager.KEYCLOAK_SESSION_COOKIE); + String sessionCookie = session.getProvider(CookieProvider.class).get(CookieType.SESSION); if (sessionCookie != null) { String[] split = sessionCookie.split("/"); @@ -930,7 +905,7 @@ public class AuthenticationManager { if (userSession.isRememberMe()) { createRememberMeCookie(userSession.getLoginUsername(), uriInfo, session); } else { - expireRememberMeCookie(realm, uriInfo, session); + expireRememberMeCookie(session); } AuthenticatedClientSessionModel clientSession = clientSessionCtx.getClientSession(); @@ -954,7 +929,7 @@ public class AuthenticationManager { } public static String getSessionIdFromSessionCookie(KeycloakSession session) { - String cookie = CookieHelper.getCookieValue(session, KEYCLOAK_SESSION_COOKIE); + String cookie = session.getProvider(CookieProvider.class).get(CookieType.SESSION); if (cookie == null || cookie.isEmpty()) { logger.debugv("Could not find cookie: {0}", KEYCLOAK_SESSION_COOKIE); return null; diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java index 6fe7345951..fdd4a13032 100644 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationSessionManager.java @@ -21,6 +21,8 @@ import jakarta.ws.rs.core.UriInfo; import org.jboss.logging.Logger; import org.keycloak.common.util.ServerCookie.SameSiteAttributeValue; import org.keycloak.common.util.Time; +import org.keycloak.cookie.CookieProvider; +import org.keycloak.cookie.CookieType; import org.keycloak.forms.login.LoginFormsProvider; import org.keycloak.forms.login.freemarker.AuthenticationStateCookie; import org.keycloak.models.ClientModel; @@ -29,7 +31,6 @@ import org.keycloak.models.RealmModel; import org.keycloak.models.UserSessionModel; import org.keycloak.models.utils.SessionExpiration; import org.keycloak.protocol.RestartLoginCookie; -import org.keycloak.services.util.CookieHelper; import org.keycloak.sessions.AuthenticationSessionModel; import org.keycloak.sessions.RootAuthenticationSessionModel; import org.keycloak.sessions.StickySessionEncoderProvider; @@ -40,8 +41,6 @@ import org.keycloak.sessions.StickySessionEncoderProvider; */ public class AuthenticationSessionManager { - public static final String AUTH_SESSION_ID = "AUTH_SESSION_ID"; - private static final Logger log = Logger.getLogger(AuthenticationSessionManager.class); private final KeycloakSession session; @@ -53,7 +52,7 @@ public class AuthenticationSessionManager { /** * Creates a fresh authentication session for the given realm . Optionally sets the browser - * authentication session cookie {@link #AUTH_SESSION_ID} with the ID of the new session. + * authentication session cookie with the ID of the new session. * @param realm * @param browserCookie Set the cookie in the browser for the * @return @@ -62,7 +61,7 @@ public class AuthenticationSessionManager { RootAuthenticationSessionModel rootAuthSession = session.authenticationSessions().createRootAuthenticationSession(realm); if (browserCookie) { - setAuthSessionCookie(rootAuthSession.getId(), realm); + setAuthSessionCookie(rootAuthSession.getId()); } return rootAuthSession; @@ -115,18 +114,12 @@ public class AuthenticationSessionManager { /** * @param authSessionId decoded authSessionId (without route info attached) - * @param realm */ - public void setAuthSessionCookie(String authSessionId, RealmModel realm) { - UriInfo uriInfo = session.getContext().getUri(); - String cookiePath = AuthenticationManager.getRealmCookiePath(realm, uriInfo); - - boolean sslRequired = realm.getSslRequired().isRequired(session.getContext().getConnection()); - + public void setAuthSessionCookie(String authSessionId) { StickySessionEncoderProvider encoder = session.getProvider(StickySessionEncoderProvider.class); String encodedAuthSessionId = encoder.encodeSessionId(authSessionId); - CookieHelper.addCookie(AUTH_SESSION_ID, encodedAuthSessionId, cookiePath, null, null, -1, sslRequired, true, SameSiteAttributeValue.NONE, session); + session.getProvider(CookieProvider.class).set(CookieType.AUTH_SESSION_ID, encodedAuthSessionId); log.debugf("Set AUTH_SESSION_ID cookie with value %s", encodedAuthSessionId); } @@ -151,7 +144,7 @@ public class AuthenticationSessionManager { if (!oldEncodedAuthSessionId.equals(newAuthSessionId.getEncodedId())) { log.debugf("Route changed. Will update authentication session cookie. Old: '%s', New: '%s'", oldEncodedAuthSessionId, newAuthSessionId.getEncodedId()); - setAuthSessionCookie(newAuthSessionId.getDecodedId(), realm); + setAuthSessionCookie(newAuthSessionId.getDecodedId()); } } @@ -161,7 +154,7 @@ public class AuthenticationSessionManager { * @return the value of the AUTH_SESSION_ID cookie. It is assumed that values could be encoded with route added (EG. "5e161e00-d426-4ea6-98e9-52eb9844e2d7.node1" ) */ String getAuthSessionCookies(RealmModel realm) { - String oldEncodedId = CookieHelper.getCookieValue(session, AUTH_SESSION_ID); + String oldEncodedId = session.getProvider(CookieProvider.class).get(CookieType.AUTH_SESSION_ID); if (oldEncodedId == null || oldEncodedId.isEmpty()) { return null; } diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java index 5cd8f296f6..708c076a90 100755 --- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java +++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java @@ -313,7 +313,7 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal AuthenticationSessionModel authSession = rootAuthSession.createAuthenticationSession(client); // Refresh the cookie - new AuthenticationSessionManager(session).setAuthSessionCookie(userSession.getId(), realmModel); + new AuthenticationSessionManager(session).setAuthSessionCookie(userSession.getId()); ClientSessionCode clientSessionCode = new ClientSessionCode<>(session, realmModel, authSession); clientSessionCode.setAction(AuthenticationSessionModel.Action.AUTHENTICATE.name()); diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java index 0e2951e9d1..e488887a7e 100755 --- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java +++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java @@ -754,7 +754,7 @@ public class LoginActionsService { processLocaleParam(authSession); - AuthenticationManager.expireIdentityCookie(realm, session.getContext().getUri(), session); + AuthenticationManager.expireIdentityCookie(session); return processRegistration(checks.isActionRequest(), execution, authSession, null); } diff --git a/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java b/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java index 615630edfd..d20bb3fa3a 100755 --- a/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java +++ b/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java @@ -283,17 +283,17 @@ public class WelcomeResource { private String setCsrfCookie() { String stateChecker = Base64Url.encode(SecretGenerator.getInstance().randomBytes()); - session.getProvider(CookieProvider.class).set(CookieType.WELCOME_STATE_CHECKER, stateChecker); + session.getProvider(CookieProvider.class).set(CookieType.WELCOME_CSRF, stateChecker); return stateChecker; } private void expireCsrfCookie() { - session.getProvider(CookieProvider.class).expire(CookieType.WELCOME_STATE_CHECKER); + session.getProvider(CookieProvider.class).expire(CookieType.WELCOME_CSRF); } private void csrfCheck(final MultivaluedMap formData) { String formStateChecker = formData.getFirst("stateChecker"); - String cookieStateChecker = session.getProvider(CookieProvider.class).get(CookieType.WELCOME_STATE_CHECKER); + String cookieStateChecker = session.getProvider(CookieProvider.class).get(CookieType.WELCOME_CSRF); if (cookieStateChecker == null || !cookieStateChecker.equals(formStateChecker)) { throw new ForbiddenException(); diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java index 3886f11ee4..15f4288424 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/UserResource.java @@ -353,9 +353,9 @@ public class UserResource { if (authenticatedRealm.getId().equals(realm.getId()) && sessionState != null) { sameRealm = true; UserSessionModel userSession = session.sessions().getUserSession(authenticatedRealm, sessionState); - AuthenticationManager.expireIdentityCookie(realm, session.getContext().getUri(), session); - AuthenticationManager.expireRememberMeCookie(realm, session.getContext().getUri(), session); - AuthenticationManager.expireAuthSessionCookie(realm, session.getContext().getUri(), session); + AuthenticationManager.expireIdentityCookie(session); + AuthenticationManager.expireRememberMeCookie(session); + AuthenticationManager.expireAuthSessionCookie(session); AuthenticationManager.backchannelLogout(session, authenticatedRealm, userSession, session.getContext().getUri(), clientConnection, headers, true); } EventBuilder event = new EventBuilder(realm, session, clientConnection); diff --git a/services/src/main/java/org/keycloak/services/util/CookieHelper.java b/services/src/main/java/org/keycloak/services/util/CookieHelper.java deleted file mode 100755 index 68d036fa55..0000000000 --- a/services/src/main/java/org/keycloak/services/util/CookieHelper.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.keycloak.services.util; - -import jakarta.ws.rs.core.Cookie; -import org.keycloak.http.HttpCookie; -import org.keycloak.http.HttpResponse; -import org.keycloak.models.KeycloakSession; - -import java.util.Map; - -import static org.keycloak.common.util.ServerCookie.SameSiteAttributeValue; - - -/** - * @author Bill Burke - * @version $Revision: 1 $ - */ -public class CookieHelper { - - public static final String LEGACY_COOKIE = "_LEGACY"; - - /** - * 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, KeycloakSession session) { - 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 = session.getContext().getHttpResponse(); - HttpCookie cookie = new HttpCookie(1, name, value, path, domain, comment, maxAge, secure_sameSite, httpOnly, sameSite); - - response.setCookieIfAbsent(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, session); - } - } - - /** - * Set a response cookie avoiding SameSite parameter - * @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, KeycloakSession session) { - addCookie(name, value, path, domain, comment, maxAge, secure, httpOnly, null, session); - } - - public static String getCookieValue(KeycloakSession session, String name) { - Map cookies = session.getContext().getRequestHeaders().getCookies(); - Cookie cookie = cookies.get(name); - if (cookie == null) { - String legacy = name + LEGACY_COOKIE; - cookie = cookies.get(legacy); - } - return cookie != null ? cookie.getValue() : null; - } - -} diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java index 415b968c05..feb4b036f3 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java @@ -21,6 +21,8 @@ import static java.util.Objects.requireNonNull; import jakarta.ws.rs.core.CacheControl; import org.jboss.resteasy.reactive.NoCache; +import org.keycloak.cookie.CookieProvider; +import org.keycloak.cookie.CookieType; import org.keycloak.http.HttpRequest; import org.keycloak.Config; import org.keycloak.common.Profile; @@ -65,10 +67,8 @@ import org.keycloak.representations.idm.EventRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.services.ErrorPage; import org.keycloak.services.ErrorResponse; -import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.resource.RealmResourceProvider; import org.keycloak.services.scheduled.ClearExpiredUserSessions; -import org.keycloak.services.util.CookieHelper; import org.keycloak.sessions.RootAuthenticationSessionModel; import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.datastore.PeriodicEventInvalidation; @@ -106,7 +106,6 @@ import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; -import jakarta.ws.rs.core.Cookie; import jakarta.ws.rs.core.Response; import java.io.File; import java.io.FileInputStream; @@ -584,7 +583,7 @@ public class TestingResourceProvider implements RealmResourceProvider { @Path("/get-sso-cookie") @Produces(MediaType.APPLICATION_JSON) public String getSSOCookieValue() { - return CookieHelper.getCookieValue(session, AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE); + return session.getProvider(CookieProvider.class).get(CookieType.IDENTITY); } diff --git a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/lb/SimpleUndertowLoadBalancer.java b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/lb/SimpleUndertowLoadBalancer.java index 52d4774cdf..baf54f7ed0 100644 --- a/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/lb/SimpleUndertowLoadBalancer.java +++ b/testsuite/integration-arquillian/servers/auth-server/undertow/src/main/java/org/keycloak/testsuite/arquillian/undertow/lb/SimpleUndertowLoadBalancer.java @@ -40,6 +40,7 @@ import io.undertow.util.AttachmentKey; import io.undertow.util.Headers; import org.jboss.logging.Logger; import org.keycloak.common.util.reflections.Reflections; +import org.keycloak.cookie.CookieType; import org.keycloak.testsuite.utils.tls.TLSUtils; import io.undertow.server.handlers.proxy.RouteIteratorFactory; @@ -51,9 +52,6 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.StringTokenizer; -import static org.keycloak.services.managers.AuthenticationSessionManager.AUTH_SESSION_ID; -import static org.keycloak.services.util.CookieHelper.LEGACY_COOKIE; - /** * Loadbalancer on embedded undertow. Supports sticky session over "AUTH_SESSION_ID" cookie and failover to different node when sticky node not available. * Status 503 is returned just if all backend nodes are unavailable. @@ -177,7 +175,7 @@ public class SimpleUndertowLoadBalancer { private HttpHandler createHandler() throws Exception { // TODO: configurable options if needed - String[] sessionIds = {AUTH_SESSION_ID, AUTH_SESSION_ID + LEGACY_COOKIE}; + String[] sessionIds = {CookieType.AUTH_SESSION_ID.getName(), CookieType.AUTH_SESSION_ID.getSameSiteLegacyName()}; int connectionsPerThread = 20; int problemServerRetry = 5; // In case of unavailable node, we will try to ping him every 5 seconds to check if it's back int maxTime = 3600000; // 1 hour for proxy request timeout, so we can debug the backend keycloak servers diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java index 4add18f670..bf7c5e558b 100755 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java @@ -17,6 +17,7 @@ package org.keycloak.testsuite.client; +import jakarta.ws.rs.core.Response; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; @@ -171,6 +172,11 @@ public class KeycloakTestingClient implements AutoCloseable { } } + public Response runWithResponse(RunOnServer function) throws RunOnServerException { + String encoded = SerializationUtil.encode(function); + return testing(realm != null ? realm : "master").runOnServerWithResponse(encoded); + } + public void runModelTest(String testClassName, String testMethodName) throws RunOnServerException { String result = testing(realm != null ? realm : "master").runModelTestOnServer(testClassName, testMethodName); diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java index bbbe8cfdfa..9fe27e9eb5 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java @@ -309,6 +309,12 @@ public interface TestingResource { @Produces(MediaType.TEXT_PLAIN_UTF_8) String runOnServer(String runOnServer); + @POST + @Path("/run-on-server") + @Consumes(MediaType.TEXT_PLAIN_UTF_8) + @Produces(MediaType.TEXT_PLAIN_UTF_8) + Response runOnServerWithResponse(String runOnServer); + @POST @Path("/run-model-test-on-server") @Consumes(MediaType.TEXT_PLAIN_UTF_8) diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLServletAdapterTest.java index 3d7df90c2b..827a929e8e 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLServletAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/SAMLServletAdapterTest.java @@ -119,6 +119,7 @@ import org.keycloak.common.util.Base64; import org.keycloak.common.util.KeyUtils; import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.common.util.PemUtils; +import org.keycloak.cookie.CookieType; import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType; import org.keycloak.dom.saml.v2.protocol.AuthnRequestType; import org.keycloak.dom.saml.v2.protocol.ResponseType; @@ -144,10 +145,7 @@ import org.keycloak.saml.common.util.XmlKeyInfoKeyNameTransformer; import org.keycloak.saml.processing.core.parsers.saml.SAMLParser; import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder; import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil; -import org.keycloak.services.managers.AuthenticationManager; -import org.keycloak.services.managers.AuthenticationSessionManager; import org.keycloak.services.resources.RealmsResource; -import org.keycloak.services.util.CookieHelper; import org.keycloak.testsuite.adapter.page.*; import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.arquillian.annotation.AppServerContainer; @@ -1812,12 +1810,12 @@ public class SAMLServletAdapterTest extends AbstractSAMLServletAdapterTest { waitForPageToLoad(); infoPage.assertCurrent(); Assert.assertEquals("You are already logged in.", infoPage.getInfo()); - Cookie identityCookie = driver.manage().getCookieNamed(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE); + Cookie identityCookie = driver.manage().getCookieNamed(CookieType.IDENTITY.getName()); Assert.assertNotNull(identityCookie); - driver.manage().deleteCookieNamed(AuthenticationSessionManager.AUTH_SESSION_ID); - driver.manage().deleteCookieNamed(AuthenticationSessionManager.AUTH_SESSION_ID + CookieHelper.LEGACY_COOKIE); - driver.manage().addCookie(new Cookie(AuthenticationSessionManager.AUTH_SESSION_ID, "invalid-value", identityCookie.getPath())); - driver.manage().addCookie(new Cookie(AuthenticationSessionManager.AUTH_SESSION_ID + CookieHelper.LEGACY_COOKIE, "invalid-value", identityCookie.getPath())); + driver.manage().deleteCookieNamed(CookieType.AUTH_SESSION_ID.getName()); + driver.manage().deleteCookieNamed(CookieType.AUTH_SESSION_ID.getSameSiteLegacyName()); + driver.manage().addCookie(new Cookie(CookieType.AUTH_SESSION_ID.getName(), "invalid-value", identityCookie.getPath())); + driver.manage().addCookie(new Cookie(CookieType.AUTH_SESSION_ID.getSameSiteLegacyName(), "invalid-value", identityCookie.getPath())); // go back to the app page, re-login should work with the invalid cookie testRealmSAMLPostLoginPage.navigateTo(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java index bb62cd26ed..aa97302bd7 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java @@ -41,6 +41,7 @@ import org.keycloak.admin.client.KeycloakBuilder; import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.cookie.CookieType; import org.keycloak.events.Details; import org.keycloak.events.EventType; import org.keycloak.models.AdminRoles; @@ -52,7 +53,6 @@ import org.keycloak.models.UserModel; import org.keycloak.models.UserSessionModel; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.representations.idm.*; -import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.auth.page.AuthRealm; @@ -340,7 +340,7 @@ public class ImpersonationTest extends AbstractKeycloakTest { Assert.assertEquals(admin, notes.get(ImpersonationSessionNote.IMPERSONATOR_USERNAME.toString())); Set cookies = cookieStore.getCookies().stream() - .filter(c -> c.getName().startsWith(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE)) + .filter(c -> c.getName().startsWith(CookieType.IDENTITY.getName())) .map(c -> new Cookie(c.getName(), c.getValue(), c.getDomain(), c.getPath(), c.getExpiryDate(), c.isSecure(), true)) .collect(Collectors.toSet()); @@ -459,7 +459,7 @@ public class ImpersonationTest extends AbstractKeycloakTest { Assert.assertNotNull(resBody); Assert.assertTrue(resBody.contains("redirect")); Set cookies = cookieStore.getCookies().stream() - .filter(c -> c.getName().startsWith(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE)) + .filter(c -> c.getName().startsWith(CookieType.IDENTITY.getName())) .map(c -> new Cookie(c.getName(), c.getValue(), c.getDomain(), c.getPath(), c.getExpiryDate(), c.isSecure(), true)) .collect(Collectors.toSet()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerLogoutTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerLogoutTest.java index aaf7315ff6..49125e984a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerLogoutTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcOidcBrokerLogoutTest.java @@ -5,9 +5,8 @@ import org.junit.Test; import org.keycloak.OAuth2Constants; import org.keycloak.TokenVerifier; import org.keycloak.common.VerificationException; +import org.keycloak.cookie.CookieType; import org.keycloak.representations.IDToken; -import org.keycloak.services.managers.AuthenticationManager; -import org.keycloak.services.util.CookieHelper; import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.util.AccountHelper; import org.keycloak.testsuite.util.OAuthClient; @@ -88,10 +87,10 @@ public class KcOidcBrokerLogoutTest extends AbstractKcOidcBrokerLogoutTest { String idToken = response.getIdToken(); // simulate browser restart by deleting an identity cookie - log.debugf("Deleting %s and %s cookies", AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE, - AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE + CookieHelper.LEGACY_COOKIE); - driver.manage().deleteCookieNamed(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE); - driver.manage().deleteCookieNamed(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE + CookieHelper.LEGACY_COOKIE); + log.debugf("Deleting %s and %s cookies", CookieType.IDENTITY.getName(), + CookieType.IDENTITY.getSameSiteLegacyName()); + driver.manage().deleteCookieNamed(CookieType.IDENTITY.getName()); + driver.manage().deleteCookieNamed(CookieType.IDENTITY.getSameSiteLegacyName()); AccountHelper.logout(adminClient.realm(bc.consumerRealmName()), bc.getUserLogin()); AccountHelper.logout(adminClient.realm(bc.providerRealmName()), bc.getUserLogin()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java index 6c9416fa5a..a718cc96a9 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cluster/AuthenticationSessionFailoverClusterTest.java @@ -24,8 +24,7 @@ import java.io.IOException; import jakarta.mail.MessagingException; import org.jboss.arquillian.graphene.page.Page; import org.junit.Test; -import org.keycloak.services.managers.AuthenticationSessionManager; -import org.keycloak.services.util.CookieHelper; +import org.keycloak.cookie.CookieType; import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.pages.LoginPasswordUpdatePage; import org.keycloak.testsuite.pages.LoginUpdateProfilePage; @@ -113,9 +112,9 @@ public class AuthenticationSessionFailoverClusterTest extends AbstractFailoverCl } public static String getAuthSessionCookieValue(WebDriver driver) { - Cookie authSessionCookie = driver.manage().getCookieNamed(AuthenticationSessionManager.AUTH_SESSION_ID); + Cookie authSessionCookie = driver.manage().getCookieNamed(CookieType.AUTH_SESSION_ID.getName()); if (authSessionCookie == null) { - authSessionCookie = driver.manage().getCookieNamed(AuthenticationSessionManager.AUTH_SESSION_ID + CookieHelper.LEGACY_COOKIE); + authSessionCookie = driver.manage().getCookieNamed(CookieType.AUTH_SESSION_ID.getSameSiteLegacyName()); } Assert.assertNotNull(authSessionCookie); return authSessionCookie.getValue(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/CookieHelperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/CookieHelperTest.java deleted file mode 100644 index 8ba1fceb4c..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/CookieHelperTest.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.keycloak.testsuite.cookies; - -import jakarta.ws.rs.client.ClientRequestContext; -import jakarta.ws.rs.client.ClientRequestFilter; -import org.jboss.resteasy.client.jaxrs.ResteasyClient; -import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.services.util.CookieHelper; -import org.keycloak.testsuite.AbstractKeycloakTest; -import org.keycloak.testsuite.client.KeycloakTestingClient; - -import java.io.IOException; -import java.util.List; - -public class CookieHelperTest extends AbstractKeycloakTest { - - private KeycloakTestingClient testing; - private SetHeaderFilter filter; - - @Before - public void before() { - filter = new SetHeaderFilter(); - String serverUrl = suiteContext.getAuthServerInfo().getContextRoot().toString() + "/auth"; - ResteasyClientBuilder restEasyClientBuilder = KeycloakTestingClient.getRestEasyClientBuilder(serverUrl); - ResteasyClient resteasyClient = restEasyClientBuilder.build(); - resteasyClient.register(filter); - testing = KeycloakTestingClient.getInstance(serverUrl, resteasyClient); - } - - @After - public void after() { - testing.close(); - } - - @Test - public void testCookieHeaderWithSpaces() { - filter.setHeader("Cookie", "terms_user=; KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhZDUyMjdhMy1iY2ZkLTRjZjAtYTdiNi0zOTk4MzVhMDg1NjYifQ.eyJjaWQiOiJodHRwczovL3Nzby5qYm9zcy5vcmciLCJwdHkiOiJzYW1sIiwicnVyaSI6Imh0dHBzOi8vc3NvLmpib3NzLm9yZy9sb2dpbj9wcm92aWRlcj1SZWRIYXRFeHRlcm5hbFByb3ZpZGVyIiwiYWN0IjoiQVVUSEVOVElDQVRFIiwibm90ZXMiOnsiU0FNTF9SRVFVRVNUX0lEIjoibXBmbXBhYWxkampqa2ZmcG5oYmJoYWdmZmJwam1rbGFqbWVlb2lsaiIsInNhbWxfYmluZGluZyI6InBvc3QifX0.d0QJSOQ6pJGzqcjqDTRwkRpU6fwYeICedL6R9Gqs8CQ; AUTH_SESSION_ID=451ec4be-a0c8-430e-b489-6580f195ccf0; AUTH_SESSION_ID=55000981-8b5e-4c8d-853f-ee4c582c1d0d;AUTH_SESSION_ID=451ec4be-a0c8-430e-b489-6580f195ccf0; AUTH_SESSION_ID=55000981-8b5e-4c8d-853f-ee4c582c1d0d;AUTH_SESSION_ID=451ec4be-a0c8-430e-b489-6580f195ccf0; AUTH_SESSION_ID=55000981-8b5e-4c8d-853f-ee4c582c1d0d4;"); - - testing.server().run(session -> { - String authSessionId = CookieHelper.getCookieValue(session, "AUTH_SESSION_ID"); - Assert.assertEquals("55000981-8b5e-4c8d-853f-ee4c582c1d0d4", authSessionId); - }); - } - - @Test - public void testLegacyCookie() { - filter.setHeader("Cookie", "MYCOOKIE=new;MYCOOKIE_LEGACY=legacy"); - - testing.server().run(session -> { - Assert.assertEquals("new", CookieHelper.getCookieValue(session, "MYCOOKIE")); - }); - - filter.setHeader("Cookie", "MYCOOKIE_LEGACY=legacy"); - - testing.server().run(session -> { - Assert.assertEquals("legacy", CookieHelper.getCookieValue(session, "MYCOOKIE")); - }); - } - - @Override - public void addTestRealms(List testRealms) { - } - - public static class SetHeaderFilter implements ClientRequestFilter { - - private String key; - private String value; - - public void setHeader(String key, String value) { - this.key = key; - this.value = value; - } - - @Override - public void filter(ClientRequestContext requestContext) throws IOException { - if (key != null && value != null) { - requestContext.getHeaders().add(key, value); - } - } - } - -} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/CookieTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/CookieTest.java index 477fc6b753..fda42b80e1 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/CookieTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/CookieTest.java @@ -31,6 +31,7 @@ import org.apache.http.util.EntityUtils; import org.jboss.arquillian.graphene.page.Page; import org.junit.Before; import org.junit.Test; +import org.keycloak.cookie.CookieType; import org.keycloak.models.Constants; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; @@ -51,15 +52,9 @@ import java.util.Set; import static org.hamcrest.Matchers.containsString; 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.hamcrest.MatcherAssert.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.managers.AuthenticationSessionManager.AUTH_SESSION_ID; -import static org.keycloak.services.util.CookieHelper.LEGACY_COOKIE; import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson; import jakarta.ws.rs.core.HttpHeaders; @@ -97,12 +92,7 @@ public class CookieTest extends AbstractKeycloakTest { @Test public void testCookieValue() throws Exception { - testCookieValue(KEYCLOAK_IDENTITY_COOKIE); - } - - @Test - public void testLegacyCookieValue() throws Exception { - testCookieValue(KEYCLOAK_IDENTITY_COOKIE + LEGACY_COOKIE); + testCookieValue(CookieType.IDENTITY.getName()); } private void testCookieValue(String cookieName) throws Exception { @@ -156,7 +146,7 @@ public class CookieTest extends AbstractKeycloakTest { try (CloseableHttpClient hc = OAuthClient.newCloseableHttpClient()) { BasicCookieStore cookieStore = new BasicCookieStore(); - BasicClientCookie cookie = new BasicClientCookie(KEYCLOAK_IDENTITY_COOKIE, accessToken); + BasicClientCookie cookie = new BasicClientCookie(CookieType.IDENTITY.getName(), accessToken); cookie.setDomain("localhost"); cookie.setPath("/"); cookieStore.addCookie(cookie); @@ -179,30 +169,6 @@ public class CookieTest extends AbstractKeycloakTest { } } - @Test - public void legacyCookiesTest() { - ContainerAssume.assumeAuthServerSSL(); - - loginPage.open(); - loginPage.assertCurrent(); - - loginPage.login("test-user@localhost", "password"); - appPage.assertCurrent(); - - driver.navigate().to(oauth.AUTH_SERVER_ROOT + "/realms/test/login-actions/authenticate/"); - - 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); - Cookie sameSiteAuthSessionIdCookie = driver.manage().getCookieNamed(AUTH_SESSION_ID); - Cookie legacyAuthSessionIdCookie = driver.manage().getCookieNamed(AUTH_SESSION_ID + LEGACY_COOKIE); - - assertSameSiteCookies(sameSiteIdentityCookie, legacyIdentityCookie); - assertSameSiteCookies(sameSiteSessionCookie, legacySessionCookie); - assertSameSiteCookies(sameSiteAuthSessionIdCookie, legacyAuthSessionIdCookie); - } - @Test public void testNoDuplicationsWhenExpiringCookies() throws IOException { ContainerAssume.assumeAuthServerSSL(); @@ -215,7 +181,7 @@ public class CookieTest extends AbstractKeycloakTest { driver.navigate().to(oauth.AUTH_SERVER_ROOT + "/realms/test/login-actions/authenticate/"); - Cookie invalidIdentityCookie = driver.manage().getCookieNamed(KEYCLOAK_IDENTITY_COOKIE); + Cookie invalidIdentityCookie = driver.manage().getCookieNamed(CookieType.IDENTITY.getName()); CookieStore cookieStore = new BasicCookieStore(); BasicClientCookie invalidClientIdentityCookie = new BasicClientCookie(invalidIdentityCookie.getName(), invalidIdentityCookie.getValue()); @@ -243,18 +209,4 @@ public class CookieTest extends AbstractKeycloakTest { } } - 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 - } - } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/CookiesPathTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/CookiesPathTest.java deleted file mode 100644 index 09e5a6c9c9..0000000000 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/CookiesPathTest.java +++ /dev/null @@ -1,223 +0,0 @@ -package org.keycloak.testsuite.cookies; - -import org.apache.commons.io.IOUtils; -import org.apache.http.NameValuePair; -import org.apache.http.client.CookieStore; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpRequestBase; -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.impl.client.LaxRedirectStrategy; -import org.apache.http.impl.cookie.BasicClientCookie; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.protocol.HttpCoreContext; -import org.hamcrest.Matchers; -import org.jboss.arquillian.graphene.page.Page; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.services.managers.AuthenticationSessionManager; -import org.keycloak.testsuite.AbstractKeycloakTest; -import org.keycloak.testsuite.ActionURIUtils; -import org.keycloak.testsuite.pages.LoginPage; -import org.keycloak.testsuite.util.RealmBuilder; -import org.keycloak.testsuite.util.UserBuilder; -import org.openqa.selenium.Cookie; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Calendar; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.is; -import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_HOST; - - -/** - * @author Martin Kanis - */ -public class CookiesPathTest extends AbstractKeycloakTest { - @Page - protected LoginPage loginPage; - - public static final String KC_RESTART = "KC_RESTART"; - - private CloseableHttpClient httpClient = null; - - private static final List KEYCLOAK_COOKIE_NAMES = Arrays.asList("KC_RESTART", "AUTH_SESSION_ID", "KEYCLOAK_IDENTITY", "KEYCLOAK_SESSION"); - - @Before - public void beforeCookiesPathTest() { - createAppClientInRealm("foo"); - createAppClientInRealm("foobar"); - } - - @After - public void afterCookiesPathTest() throws IOException { - if (httpClient != null) httpClient.close(); - - // Setting back default oauth values - oauth.realm("test"); - oauth.redirectUri(oauth.APP_AUTH_ROOT); - } - - @Test - public void testCookiesPath() { - // navigate to "/realms/foo/account" and them remove cookies in the browser for the current path - // first access to the path means there are no cookies being sent - // we are redirected to login page and Keycloak sets cookie's path to "/auth/realms/foo/" - navigateToLoginPage("foo"); - driver.manage().deleteAllCookies(); - - Assert.assertTrue("There shouldn't be any cookies sent!", driver.manage().getCookies().isEmpty()); - - // refresh the page and cookies are sent within the request - driver.navigate().refresh(); - - Set cookies = driver.manage().getCookies(); - Assert.assertTrue("There should be cookies sent!", cookies.size() > 0); - // check cookie's path, for some reason IE adds extra slash to the beginning of the path - cookies.stream() - .filter(cookie -> KEYCLOAK_COOKIE_NAMES.contains(cookie.getName())) - .forEach(cookie -> assertThat(cookie.getPath(), Matchers.endsWith("/auth/realms/foo/"))); - - // now navigate to realm which name overlaps the first realm and delete cookies for that realm (foobar) - navigateToLoginPage("foobar"); - driver.manage().deleteAllCookies(); - - // cookies shouldn't be sent for the first access to /realms/foobar/account - // At this moment IE would sent cookies for /auth/realms/foo without the fix - cookies = driver.manage().getCookies(); - Assert.assertTrue("There shouldn't be any cookies sent!", cookies.isEmpty()); - - // navigate to account and check if correct cookies were sent - driver.navigate().to(oauth.getLoginFormUrl()); - cookies = driver.manage().getCookies(); - - Assert.assertTrue("There should be cookies sent!", cookies.size() > 0); - // check cookie's path, for some reason IE adds extra slash to the beginning of the path - cookies.stream() - .filter(cookie -> KEYCLOAK_COOKIE_NAMES.contains(cookie.getName())) - .forEach(cookie -> assertThat(cookie.getPath(), Matchers.endsWith("/auth/realms/foobar/"))); - - // lets back to "/realms/foo/account" to test the cookies for "foo" realm are still there and haven't been (correctly) sent to "foobar" - oauth.realm("foo"); - driver.navigate().to(oauth.getLoginFormUrl()); - - cookies = driver.manage().getCookies(); - Assert.assertTrue("There should be cookies sent!", cookies.size() > 0); - cookies.stream() - .filter(cookie -> KEYCLOAK_COOKIE_NAMES.contains(cookie.getName())) - .forEach(cookie -> assertThat(cookie.getPath(), Matchers.endsWith("/auth/realms/foo/"))); - } - - /** - * Add two realms which names are overlapping i.e foo and foobar - * @param testRealms - */ - @Override - public void addTestRealms(List testRealms) { - RealmBuilder foo = RealmBuilder.create().name("foo"); - foo.user(UserBuilder.create().username("foo").password("password")); - testRealms.add(foo.build()); - - RealmBuilder foobar = RealmBuilder.create().name("foobar"); - foo.user(UserBuilder.create().username("foobar").password("password")); - testRealms.add(foobar.build()); - } - - // if the client is closed before the response is read, it throws - // org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body - // that's why the this.httpClient is introduced, the client is closed either here or after test method - private CloseableHttpResponse sendRequest(HttpRequestBase request, CookieStore cookieStore, HttpCoreContext localContext) throws IOException { - if (httpClient != null) httpClient.close(); - httpClient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).setRedirectStrategy(new LaxRedirectStrategy()).build(); - return httpClient.execute(request, localContext); - } - - private CookieStore getCorrectCookies(String uri) throws IOException { - CookieStore cookieStore = new BasicCookieStore(); - - HttpGet request = new HttpGet(uri); - try (CloseableHttpResponse response = sendRequest(request, new BasicCookieStore(), new HttpCoreContext())) { - for (org.apache.http.Header h: response.getHeaders("Set-Cookie")) { - if (h.getValue().contains(AuthenticationSessionManager.AUTH_SESSION_ID)) { - cookieStore.addCookie(parseCookie(h.getValue(), AuthenticationSessionManager.AUTH_SESSION_ID)); - } else if (h.getValue().contains(KC_RESTART)) { - cookieStore.addCookie(parseCookie(h.getValue(), KC_RESTART)); - } - } - } - - return cookieStore; - } - - private BasicClientCookie parseCookie(String line, String name) { - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.DAY_OF_YEAR, 1); - - String path = ""; - String value = ""; - - for (String s: line.split(";")) { - if (s.contains(name)) { - String[] split = s.split("="); - value = split[1]; - } else if (s.contains("Path")) { - String[] split = s.split("="); - path = split[1]; - } - } - - BasicClientCookie c = new BasicClientCookie(name, value); - c.setExpiryDate(calendar.getTime()); - c.setDomain(AUTH_SERVER_HOST); - c.setPath(path); - - return c; - } - - private void login(String requestURI, CookieStore cookieStore) throws IOException { - HttpCoreContext httpContext = new HttpCoreContext(); - HttpGet request = new HttpGet(requestURI); - - // send an initial request, we are redirected to login page - String entityContent; - try (CloseableHttpResponse response = sendRequest(request, cookieStore, httpContext)) { - entityContent = IOUtils.toString(response.getEntity().getContent(), "UTF-8"); - } - - // send credentials to login form - HttpPost post = new HttpPost(ActionURIUtils.getActionURIFromPageSource(entityContent)); - List params = new LinkedList<>(); - params.add(new BasicNameValuePair("username", "foo")); - params.add(new BasicNameValuePair("password", "password")); - - post.setHeader("Content-Type", "application/x-www-form-urlencoded"); - post.setEntity(new UrlEncodedFormEntity(params)); - - try (CloseableHttpResponse response = sendRequest(post, cookieStore, httpContext)) { - assertThat("Expected successful login.", response.getStatusLine().getStatusCode(), is(equalTo(200))); - } - } - - private void navigateToLoginPage(String realm) { - setOAuthUri(realm); - driver.navigate().to(oauth.getLoginFormUrl()); - } - - private void setOAuthUri(String realm) { - oauth.realm(realm); - oauth.redirectUri(oauth.AUTH_SERVER_ROOT + "/realms/" + realm + "/app/auth"); - } -} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/DefaultCookieProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/DefaultCookieProviderTest.java new file mode 100644 index 0000000000..238b269f81 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/cookies/DefaultCookieProviderTest.java @@ -0,0 +1,172 @@ +package org.keycloak.testsuite.cookies; + +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.core.NewCookie; +import jakarta.ws.rs.core.Response; +import org.jboss.resteasy.client.jaxrs.ResteasyClient; +import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.keycloak.cookie.CookieProvider; +import org.keycloak.cookie.CookieType; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.AbstractKeycloakTest; +import org.keycloak.testsuite.client.KeycloakTestingClient; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class DefaultCookieProviderTest extends AbstractKeycloakTest { + + private KeycloakTestingClient testing; + private SetHeaderFilter filter; + + @Before + public void before() { + filter = new SetHeaderFilter(); + String serverUrl = suiteContext.getAuthServerInfo().getContextRoot().toString() + "/auth"; + testing = createTestingClient(serverUrl); + } + + @After + public void after() { + testing.close(); + } + + @Test + public void testCookieDefaults() { + Response response = testing.server("master").runWithResponse(session -> { + CookieProvider cookies = session.getProvider(CookieProvider.class); + cookies.set(CookieType.AUTH_SESSION_ID, "my-auth-session-id"); + cookies.set(CookieType.AUTH_STATE, "my-auth-state", 111); + cookies.set(CookieType.AUTH_RESTART, "my-auth-restart"); + cookies.set(CookieType.AUTH_DETACHED, "my-auth-detached", 222); + cookies.set(CookieType.IDENTITY, "my-identity", 333); + cookies.set(CookieType.LOCALE, "my-locale"); + cookies.set(CookieType.LOGIN_HINT, "my-username"); + cookies.set(CookieType.SESSION, "my-session", 444); + cookies.set(CookieType.WELCOME_CSRF, "my-welcome-csrf"); + }); + Assert.assertEquals(12, response.getCookies().size()); + assertCookie(response, "AUTH_SESSION_ID", "my-auth-session-id", "/auth/realms/master/", -1, true, true, "None", true); + assertCookie(response, "KC_AUTH_STATE", "my-auth-state", "/auth/realms/master/", 111, true, false, null, false); + assertCookie(response, "KC_RESTART", "my-auth-restart", "/auth/realms/master/", -1, true, true, null, false); + assertCookie(response, "KC_STATE_CHECKER", "my-auth-detached", "/auth/realms/master/", 222, true, true, null, false); + assertCookie(response, "KEYCLOAK_IDENTITY", "my-identity", "/auth/realms/master/", 333, true, true, "None", true); + assertCookie(response, "KEYCLOAK_LOCALE", "my-locale", "/auth/realms/master/", -1, true, true, null, false); + assertCookie(response, "KEYCLOAK_REMEMBER_ME", "my-username", "/auth/realms/master/", 31536000, true, true, null, false); + assertCookie(response, "KEYCLOAK_SESSION", "my-session", "/auth/realms/master/", 444, true, false, "None", true); + assertCookie(response, "WELCOME_STATE_CHECKER", "my-welcome-csrf", "/auth/realms/master/testing/run-on-server", 300, true, true, "Strict", false); + } + + @Test + public void testExpire() { + filter.setHeader("Cookie", "AUTH_SESSION_ID=new;KC_RESTART=new;"); + + Response response = testing.server().runWithResponse(session -> { + session.getProvider(CookieProvider.class).expire(CookieType.AUTH_SESSION_ID); + session.getProvider(CookieProvider.class).expire(CookieType.LOCALE); + }); + + Map cookies = response.getCookies(); + Assert.assertEquals(1, cookies.size()); + assertCookie(response, "AUTH_SESSION_ID", "", "/auth/realms/master/", 0, false, false, null, false); + } + + @Test + public void testCookieHeaderWithSpaces() { + filter.setHeader("Cookie", "terms_user=; KC_RESTART=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhZDUyMjdhMy1iY2ZkLTRjZjAtYTdiNi0zOTk4MzVhMDg1NjYifQ.eyJjaWQiOiJodHRwczovL3Nzby5qYm9zcy5vcmciLCJwdHkiOiJzYW1sIiwicnVyaSI6Imh0dHBzOi8vc3NvLmpib3NzLm9yZy9sb2dpbj9wcm92aWRlcj1SZWRIYXRFeHRlcm5hbFByb3ZpZGVyIiwiYWN0IjoiQVVUSEVOVElDQVRFIiwibm90ZXMiOnsiU0FNTF9SRVFVRVNUX0lEIjoibXBmbXBhYWxkampqa2ZmcG5oYmJoYWdmZmJwam1rbGFqbWVlb2lsaiIsInNhbWxfYmluZGluZyI6InBvc3QifX0.d0QJSOQ6pJGzqcjqDTRwkRpU6fwYeICedL6R9Gqs8CQ; AUTH_SESSION_ID=451ec4be-a0c8-430e-b489-6580f195ccf0; AUTH_SESSION_ID=55000981-8b5e-4c8d-853f-ee4c582c1d0d;AUTH_SESSION_ID=451ec4be-a0c8-430e-b489-6580f195ccf0; AUTH_SESSION_ID=55000981-8b5e-4c8d-853f-ee4c582c1d0d;AUTH_SESSION_ID=451ec4be-a0c8-430e-b489-6580f195ccf0; AUTH_SESSION_ID=55000981-8b5e-4c8d-853f-ee4c582c1d0d4;"); + + testing.server().run(session -> { + String authSessionId = session.getProvider(CookieProvider.class).get(CookieType.AUTH_SESSION_ID); + Assert.assertEquals("55000981-8b5e-4c8d-853f-ee4c582c1d0d4", authSessionId); + }); + } + + @Test + public void testSameSiteLegacyGet() { + filter.setHeader("Cookie", "AUTH_SESSION_ID=new;AUTH_SESSION_ID_LEGACY=legacy;KC_RESTART_LEGACY=ignore"); + + testing.server().run(session -> { + Assert.assertEquals("new", session.getProvider(CookieProvider.class).get(CookieType.AUTH_SESSION_ID)); + Assert.assertEquals(null, session.getProvider(CookieProvider.class).get(CookieType.AUTH_RESTART)); + }); + + filter.setHeader("Cookie", "AUTH_SESSION_ID_LEGACY=legacy"); + + testing.server().run(session -> { + Assert.assertEquals("legacy", session.getProvider(CookieProvider.class).get(CookieType.AUTH_SESSION_ID)); + }); + } + + @Test + public void testSameSiteLegacyExpire() { + filter.setHeader("Cookie", "AUTH_SESSION_ID=new;AUTH_SESSION_ID_LEGACY=legacy;KC_RESTART_LEGACY=ignore;KEYCLOAK_LOCALE=foobar"); + + Response response = testing.server().runWithResponse(session -> { + session.getProvider(CookieProvider.class).expire(CookieType.AUTH_SESSION_ID); + session.getProvider(CookieProvider.class).expire(CookieType.AUTH_RESTART); + }); + + Map cookies = response.getCookies(); + Assert.assertEquals(2, cookies.size()); + assertCookie(response, "AUTH_SESSION_ID", "", "/auth/realms/master/", 0, false, false, null, true); + } + + private void assertCookie(Response response, String name, String value, String path, int maxAge, boolean secure, boolean httpOnly, String sameSite, boolean hasLegacy) { + Map cookies = response.getCookies(); + NewCookie cookie = cookies.get(name); + Assert.assertNotNull(cookie); + Assert.assertEquals(value, cookie.getValue()); + Assert.assertEquals(path, cookie.getPath()); + Assert.assertEquals(maxAge, cookie.getMaxAge()); + Assert.assertEquals(secure, cookie.isSecure()); + Assert.assertEquals(httpOnly, cookie.isHttpOnly()); + + String setHeader = (String) response.getHeaders().get("Set-Cookie").stream().filter(v -> ((String) v).startsWith(name)).findFirst().get(); + if (sameSite == null) { + Assert.assertFalse(setHeader.contains("SameSite")); + } else { + Assert.assertTrue(setHeader.contains("SameSite=" + sameSite)); + } + + if (hasLegacy) { + assertCookie(response, name + "_LEGACY", value, path, maxAge, secure, httpOnly, null, false); + } + } + + private KeycloakTestingClient createTestingClient(String serverUrl) { + ResteasyClientBuilder restEasyClientBuilder = KeycloakTestingClient.getRestEasyClientBuilder(serverUrl); + ResteasyClient resteasyClient = restEasyClientBuilder.build(); + resteasyClient.register(filter); + return KeycloakTestingClient.getInstance(serverUrl, resteasyClient); + } + + @Override + public void addTestRealms(List testRealms) { + } + + public static class SetHeaderFilter implements ClientRequestFilter { + + private String key; + private String value; + + public void setHeader(String key, String value) { + this.key = key; + this.value = value; + } + + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + if (key != null && value != null) { + requestContext.getHeaders().add(key, value); + } + } + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java index c2bef3ba2f..9257f57b65 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java @@ -16,6 +16,7 @@ import org.keycloak.admin.client.resource.UserResource; import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.common.util.ObjectUtil; import org.keycloak.common.util.reflections.Types; +import org.keycloak.cookie.CookieType; import org.keycloak.credential.CredentialAuthentication; import org.keycloak.credential.CredentialModel; import org.keycloak.credential.CredentialProvider; @@ -86,8 +87,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.keycloak.models.UserModel.RequiredAction.UPDATE_PROFILE; -import static org.keycloak.services.managers.AuthenticationManager.KEYCLOAK_SESSION_COOKIE; -import static org.keycloak.services.util.CookieHelper.LEGACY_COOKIE; import static org.keycloak.storage.UserStorageProviderModel.CACHE_POLICY; import static org.keycloak.storage.UserStorageProviderModel.EVICTION_DAY; import static org.keycloak.storage.UserStorageProviderModel.EVICTION_HOUR; @@ -260,8 +259,8 @@ public class UserStorageTest extends AbstractAuthTest { appPage.assertCurrent(); driver.navigate().to(oauth.AUTH_SERVER_ROOT + "/realms/" + testRealmResource().toRepresentation().getRealm() + "/login-actions/authenticate/" ); - Cookie sameSiteSessionCookie = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE); - Cookie legacySessionCookie = driver.manage().getCookieNamed(KEYCLOAK_SESSION_COOKIE + LEGACY_COOKIE); + Cookie sameSiteSessionCookie = driver.manage().getCookieNamed(CookieType.SESSION.getName()); + Cookie legacySessionCookie = driver.manage().getCookieNamed(CookieType.SESSION.getSameSiteLegacyName()); String cookieValue = sameSiteSessionCookie.getValue(); assertThat(cookieValue.contains("spécial"), is(false)); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTest.java index f67262d79b..610802d6b0 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTest.java @@ -33,6 +33,7 @@ import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.UserResource; import org.keycloak.admin.client.resource.UsersResource; import org.keycloak.common.Profile; +import org.keycloak.cookie.CookieType; import org.keycloak.crypto.Algorithm; import org.keycloak.events.Details; import org.keycloak.events.Errors; @@ -900,7 +901,7 @@ public class LoginTest extends AbstractTestRealmKeycloakTest { driver.navigate().refresh(); // Assert authenticationSession in cache with 2 tabs - String authSessionId = driver.manage().getCookieNamed(AuthenticationSessionManager.AUTH_SESSION_ID).getValue(); + String authSessionId = driver.manage().getCookieNamed(CookieType.AUTH_SESSION_ID.getName()).getValue(); Assert.assertEquals((Integer) 2, getTestingClient().testing().getAuthenticationSessionTabsCount("test", authSessionId)); loginPage.login("test-user@localhost", "password"); @@ -1016,7 +1017,7 @@ public class LoginTest extends AbstractTestRealmKeycloakTest { // make sure the authentication session is no longer available for (Cookie cookie : driver.manage().getCookies()) { - if (cookie.getName().startsWith(AuthenticationSessionManager.AUTH_SESSION_ID)) { + if (cookie.getName().startsWith(CookieType.AUTH_SESSION_ID.getName())) { driver.manage().deleteCookie(cookie); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java index e442106c3e..dab918b7e8 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/i18n/LoginPageTest.java @@ -30,7 +30,6 @@ import org.keycloak.adapters.HttpClientBuilder; import org.keycloak.admin.client.resource.UserResource; import org.keycloak.common.util.KeycloakUriBuilder; import org.keycloak.cookie.CookieType; -import org.keycloak.cookie.DefaultCookieProvider; import org.keycloak.events.Details; import org.keycloak.events.EventType; import org.keycloak.forms.login.freemarker.DetachedInfoStateChecker; @@ -232,7 +231,7 @@ public class LoginPageTest extends AbstractI18NTest { assertEquals("Deutsch", loginPage.getLanguageDropdownText()); - Cookie localeCookie = driver.manage().getCookieNamed(CookieType.KEYCLOAK_LOCALE.name()); + Cookie localeCookie = driver.manage().getCookieNamed(CookieType.LOCALE.getName()); assertEquals("de", localeCookie.getValue()); UserResource user = ApiUtil.findUserByUsernameId(testRealm(), "test-user@localhost"); @@ -277,7 +276,7 @@ public class LoginPageTest extends AbstractI18NTest { loginPage.open(); // Cookie should be removed as last user to login didn't have a locale - localeCookie = driver.manage().getCookieNamed(CookieType.KEYCLOAK_LOCALE.name()); + localeCookie = driver.manage().getCookieNamed(CookieType.LOCALE.getName()); Assert.assertNull(localeCookie); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java index a508c78f3b..699f49e124 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java @@ -33,6 +33,7 @@ import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmsResource; import org.keycloak.admin.client.resource.UserResource; import org.keycloak.common.enums.SslRequired; +import org.keycloak.cookie.CookieType; import org.keycloak.crypto.Algorithm; import org.keycloak.events.EventType; import org.keycloak.events.Details; @@ -52,13 +53,11 @@ import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.representations.AccessToken; import org.keycloak.representations.IDToken; import org.keycloak.representations.RefreshToken; -import org.keycloak.representations.UserInfo; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientScopeRepresentation; import org.keycloak.representations.idm.EventRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserSessionRepresentation; -import org.keycloak.services.managers.AuthenticationSessionManager; import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.admin.ApiUtil; @@ -111,7 +110,6 @@ import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson; import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername; import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_SSL_REQUIRED; import static org.keycloak.testsuite.util.OAuthClient.AUTH_SERVER_ROOT; -import static org.keycloak.testsuite.util.ServerURLs.AUTH_SERVER_SSL_REQUIRED; import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getHttpAuthServerContextRoot; /** @@ -432,7 +430,7 @@ public class RefreshTokenTest extends AbstractKeycloakTest { oauth.openLoginForm(); - Cookie authSessionCookie = driver.manage().getCookieNamed(AuthenticationSessionManager.AUTH_SESSION_ID); + Cookie authSessionCookie = driver.manage().getCookieNamed(CookieType.AUTH_SESSION_ID.getName()); oauth.fillLoginForm("alice", "alice");