Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/documentation/upgrading/topics/changes/changes-26_0_0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,14 @@ Update your custom embedded Infinispan cache configuration file with configurati

For more details proceed to the https://www.keycloak.org/server/caching[Configuring distributed caches] guide.

= Support for legacy `redirect_uri` parameter and SPI options has been removed

Previous versions of {project_name} had supported automatic logout of the user and redirecting to the application by opening logout endpoint URL such as
`http(s)://example-host/auth/realms/my-realm-name/protocol/openid-connect/logout?redirect_uri=encodedRedirectUri`. This functionality was deprecated in {project_name} 18 and has been removed in this version in favor of following the OpenID Connect specification.

As part of this change the following related configuration options for the SPI have been removed:

- `--spi-login-protocol-openid-connect-legacy-logout-redirect-uri`
- `--spi-login-protocol-openid-connect-suppress-logout-confirmation-screen`

If you were still making use these options or the `redirect_uri` parameter for logout you should implement the link:https://openid.net/specs/openid-connect-rpinitiated-1_0.html[OpenID Connect RP-Initiated Logout specification] instead.
Original file line number Diff line number Diff line change
Expand Up @@ -109,21 +109,9 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
public static final String ROLES_SCOPE_CONSENT_TEXT = "${rolesScopeConsentText}";
public static final String ORGANIZATION_SCOPE_CONSENT_TEXT = "${organizationScopeConsentText}";

public static final String CONFIG_LEGACY_LOGOUT_REDIRECT_URI = "legacy-logout-redirect-uri";
public static final String SUPPRESS_LOGOUT_CONFIRMATION_SCREEN = "suppress-logout-confirmation-screen";

private OIDCProviderConfig providerConfig;

@Override
public void init(Config.Scope config) {
initBuiltIns();
this.providerConfig = new OIDCProviderConfig(config);
if (providerConfig.isLegacyLogoutRedirectUri()) {
logger.warnf("Deprecated switch '%s' is enabled. Please try to disable it and update your clients to use OpenID Connect compliant way for RP-initiated logout.", CONFIG_LEGACY_LOGOUT_REDIRECT_URI);
}
if (providerConfig.suppressLogoutConfirmationScreen()) {
logger.warnf("Deprecated switch '%s' is enabled. Please try to disable it and update your clients to use OpenID Connect compliant way for RP-initiated logout.", SUPPRESS_LOGOUT_CONFIRMATION_SCREEN);
}
}

@Override
Expand Down Expand Up @@ -444,7 +432,7 @@ protected void addDefaults(ClientModel client) {

@Override
public Object createProtocolEndpoint(KeycloakSession session, EventBuilder event) {
return new OIDCLoginProtocolService(session, event, providerConfig);
return new OIDCLoginProtocolService(session, event);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ public class OIDCLoginProtocolService {
private final RealmModel realm;
private final TokenManager tokenManager;
private final EventBuilder event;
private final OIDCProviderConfig providerConfig;

private final KeycloakSession session;

Expand All @@ -74,13 +73,12 @@ public class OIDCLoginProtocolService {

private final ClientConnection clientConnection;

public OIDCLoginProtocolService(KeycloakSession session, EventBuilder event, OIDCProviderConfig providerConfig) {
public OIDCLoginProtocolService(KeycloakSession session, EventBuilder event) {
this.session = session;
this.clientConnection = session.getContext().getConnection();
this.realm = session.getContext().getRealm();
this.tokenManager = new TokenManager();
this.event = event;
this.providerConfig = providerConfig;
this.request = session.getContext().getHttpRequest();
this.headers = session.getContext().getRequestHeaders();
}
Expand Down Expand Up @@ -212,11 +210,9 @@ public Object issueUserInfo() {
return new UserInfoEndpoint(session, tokenManager);
}

/* old deprecated logout endpoint needs to be removed in the future
* https://issues.redhat.com/browse/KEYCLOAK-2940 */
@Path("logout")
public Object logout() {
return new LogoutEndpoint(session, tokenManager, event, providerConfig);
return new LogoutEndpoint(session, tokenManager, event);
}

@Path("revoke")
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@
import org.keycloak.protocol.oidc.LogoutTokenValidationCode;
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
import org.keycloak.protocol.oidc.OIDCProviderConfig;
import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
import org.keycloak.protocol.oidc.utils.LogoutUtil;
Expand Down Expand Up @@ -112,17 +110,15 @@ public class LogoutEndpoint {
private final TokenManager tokenManager;
private final RealmModel realm;
private final EventBuilder event;
private final OIDCProviderConfig providerConfig;

private Cors cors;

public LogoutEndpoint(KeycloakSession session, TokenManager tokenManager, EventBuilder event, OIDCProviderConfig providerConfig) {
public LogoutEndpoint(KeycloakSession session, TokenManager tokenManager, EventBuilder event) {
this.session = session;
this.clientConnection = session.getContext().getConnection();
this.tokenManager = tokenManager;
this.realm = session.getContext().getRealm();
this.event = event;
this.providerConfig = providerConfig;
this.request = session.getContext().getHttpRequest();
this.headers = session.getContext().getRequestHeaders();
}
Expand All @@ -143,7 +139,6 @@ public Response issueUserInfoPreflight() {
*
* All parameters are optional. Some combinations of parameters are invalid as described in the specification
*
* @param deprecatedRedirectUri Parameter "redirect_uri" is not supported by the specification. It is here just for the backwards compatibility
* @param encodedIdToken Parameter "id_token_hint" as described in the specification.
* @param clientId Parameter "client_id" as described in the specification.
* @param postLogoutRedirectUri Parameter "post_logout_redirect_uri" as described in the specification with the URL to redirect after logout.
Expand All @@ -154,39 +149,23 @@ public Response issueUserInfoPreflight() {
*/
@GET
@NoCache
public Response logout(@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String deprecatedRedirectUri, // deprecated
@QueryParam(OIDCLoginProtocol.ID_TOKEN_HINT) String encodedIdToken,
public Response logout(@QueryParam(OIDCLoginProtocol.ID_TOKEN_HINT) String encodedIdToken,
@QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId,
@QueryParam(OIDCLoginProtocol.POST_LOGOUT_REDIRECT_URI_PARAM) String postLogoutRedirectUri,
@QueryParam(OIDCLoginProtocol.STATE_PARAM) String state,
@QueryParam(OIDCLoginProtocol.UI_LOCALES_PARAM) String uiLocales,
@QueryParam(AuthenticationManager.INITIATING_IDP_PARAM) String initiatingIdp) {

if (!providerConfig.isLegacyLogoutRedirectUri()) {
if (deprecatedRedirectUri != null) {
event.event(EventType.LOGOUT);
String errorMessage = "Parameter 'redirect_uri' no longer supported.";
event.detail(Details.REASON, errorMessage);
event.error(Errors.INVALID_REQUEST);
logger.warnf("%s Please use 'post_logout_redirect_uri' with 'id_token_hint' for this endpoint. Alternatively you can enable backwards compatibility option '%s' of oidc login protocol in the server configuration.",
errorMessage, OIDCLoginProtocolFactory.CONFIG_LEGACY_LOGOUT_REDIRECT_URI);
return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.INVALID_PARAMETER, OIDCLoginProtocol.REDIRECT_URI_PARAM);
}

if (postLogoutRedirectUri != null && encodedIdToken == null && clientId == null) {
event.event(EventType.LOGOUT);
String errorMessage = "Either the parameter 'client_id' or the parameter 'id_token_hint' is required when 'post_logout_redirect_uri' is used.";
event.detail(Details.REASON, errorMessage);
event.error(Errors.INVALID_REQUEST);
logger.warnf(errorMessage);
return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.MISSING_PARAMETER,
OIDCLoginProtocol.ID_TOKEN_HINT);
}
if (postLogoutRedirectUri != null && encodedIdToken == null && clientId == null) {
event.event(EventType.LOGOUT);
String errorMessage = "Either the parameter 'client_id' or the parameter 'id_token_hint' is required when 'post_logout_redirect_uri' is used.";
event.detail(Details.REASON, errorMessage);
event.error(Errors.INVALID_REQUEST);
logger.warnf(errorMessage);
return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.MISSING_PARAMETER,
OIDCLoginProtocol.ID_TOKEN_HINT);
}

deprecatedRedirectUri = providerConfig.isLegacyLogoutRedirectUri() ? deprecatedRedirectUri : null;
final String redirectUri = postLogoutRedirectUri != null ? postLogoutRedirectUri : deprecatedRedirectUri;

boolean confirmationNeeded = true;
boolean forcedConfirmation = false;
ClientModel client = clientId == null ? null : realm.getClientByClientId(clientId);
Expand Down Expand Up @@ -236,21 +215,16 @@ public Response logout(@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String
}

String validatedRedirectUri = null;
if (redirectUri != null) {
if (postLogoutRedirectUri != null) {
if (client != null) {
OIDCAdvancedConfigWrapper wrapper = OIDCAdvancedConfigWrapper.fromClientModel(client);
Set<String> postLogoutRedirectUris = wrapper.getPostLogoutRedirectUris() != null ? new HashSet(wrapper.getPostLogoutRedirectUris()) : new HashSet<>();
validatedRedirectUri = RedirectUtils.verifyRedirectUri(session, client.getRootUrl(), redirectUri, postLogoutRedirectUris, true);
} else if (clientId == null && providerConfig.isLegacyLogoutRedirectUri()) {
/*
* Only call verifyRealmRedirectUri against all in the realm, in case when "Legacy" switch is enabled and when we don't have a client - usually due both clientId and client are null
*/
validatedRedirectUri = RedirectUtils.verifyRealmRedirectUri(session, redirectUri);
validatedRedirectUri = RedirectUtils.verifyRedirectUri(session, client.getRootUrl(), postLogoutRedirectUri, postLogoutRedirectUris, true);
}

if (validatedRedirectUri == null) {
event.event(EventType.LOGOUT);
event.detail(Details.REDIRECT_URI, redirectUri);
event.detail(Details.REDIRECT_URI, postLogoutRedirectUri);
event.error(Errors.INVALID_REDIRECT_URI);
return ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.INVALID_REDIRECT_URI);
}
Expand Down Expand Up @@ -307,7 +281,7 @@ public Response logout(@QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String
}

// Logout confirmation screen will be displayed to the user in this case
if ((confirmationNeeded || forcedConfirmation) && !providerConfig.suppressLogoutConfirmationScreen()) {
if (confirmationNeeded || forcedConfirmation) {
return displayLogoutConfirmationScreen(loginForm, logoutSession);
} else {
return doBrowserLogout(logoutSession);
Expand Down Expand Up @@ -338,13 +312,14 @@ public Response logout() {
if (form.containsKey(OAuth2Constants.REFRESH_TOKEN)) {
return logoutToken();
} else {
return logout(form.getFirst(OIDCLoginProtocol.REDIRECT_URI_PARAM),
return logout(
form.getFirst(OIDCLoginProtocol.ID_TOKEN_HINT),
form.getFirst(OIDCLoginProtocol.CLIENT_ID_PARAM),
form.getFirst(OIDCLoginProtocol.POST_LOGOUT_REDIRECT_URI_PARAM),
form.getFirst(OIDCLoginProtocol.STATE_PARAM),
form.getFirst(OIDCLoginProtocol.UI_LOCALES_PARAM),
form.getFirst(AuthenticationManager.INITIATING_IDP_PARAM));
form.getFirst(AuthenticationManager.INITIATING_IDP_PARAM)
);
}
}

Expand Down Expand Up @@ -701,7 +676,7 @@ private BackchannelLogoutResponse logoutUserSession(UserSessionModel userSession

return backchannelLogoutResponse;
}

private boolean oneOrMoreDownstreamLogoutsFailed(BackchannelLogoutResponse backchannelLogoutResponse) {
BackchannelLogoutResponse filteredBackchannelLogoutResponse = new BackchannelLogoutResponse();
for (BackchannelLogoutResponse.DownStreamBackchannelLogoutResponse response : backchannelLogoutResponse
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakUriInfo;
import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.services.Urls;
import org.keycloak.services.util.ResolveRelative;

Expand All @@ -33,7 +32,6 @@
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
* @author <a href="mailto:[email protected]">Stian Thorgersen</a>
Expand All @@ -42,17 +40,6 @@ public class RedirectUtils {

private static final Logger logger = Logger.getLogger(RedirectUtils.class);

/**
* This method is deprecated for performance and security reasons and it is available just for the
* backwards compatibility. It is recommended to use some other methods of this class where the client is given as an argument
* to the method, so we know the client, which redirect-uri we are trying to resolve.
*/
@Deprecated
public static String verifyRealmRedirectUri(KeycloakSession session, String redirectUri) {
Set<String> validRedirects = getValidateRedirectUris(session);
return verifyRedirectUri(session, null, redirectUri, validRedirects, true);
}

public static String verifyRedirectUri(KeycloakSession session, String redirectUri, ClientModel client) {
return verifyRedirectUri(session, redirectUri, client, true);
}
Expand All @@ -77,16 +64,6 @@ public static Set<String> resolveValidRedirects(KeycloakSession session, String
return resolveValidRedirects;
}

@Deprecated
private static Set<String> getValidateRedirectUris(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm();
return session.clients().getAllRedirectUrisOfEnabledClients(realm).entrySet().stream()
.filter(me -> me.getKey().isEnabled() && OIDCLoginProtocol.LOGIN_PROTOCOL.equals(me.getKey().getProtocol()) && !me.getKey().isBearerOnly() && (me.getKey().isStandardFlowEnabled() || me.getKey().isImplicitFlowEnabled()))
.map(me -> resolveValidRedirects(session, me.getKey().getRootUrl(), me.getValue()))
.flatMap(Collection::stream)
.collect(Collectors.toSet());
}

public static String verifyRedirectUri(KeycloakSession session, String rootUrl, String redirectUri, Set<String> validRedirects, boolean requireRedirectUri) {
KeycloakUriInfo uriInfo = session.getContext().getUri();
RealmModel realm = session.getContext().getRealm();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,14 +232,6 @@ public LogoutUrlBuilder postLogoutRedirectUri(String redirectUri) {
return this;
}

@Deprecated // Use only in backwards compatibility tests
public LogoutUrlBuilder redirectUri(String redirectUri) {
if (redirectUri != null) {
b.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri);
}
return this;
}

public LogoutUrlBuilder state(String state) {
if (state != null) {
b.queryParam(OIDCLoginProtocol.STATE_PARAM, state);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.keycloak.testsuite.broker;

import org.keycloak.OAuth2Constants;
import org.keycloak.broker.saml.SAMLIdentityProviderConfig;
import org.keycloak.crypto.Algorithm;
import org.keycloak.dom.saml.v2.protocol.AuthnRequestType;
Expand All @@ -21,6 +22,7 @@
import org.keycloak.testsuite.updaters.IdentityProviderAttributeUpdater;
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
import org.keycloak.testsuite.util.KeyUtils;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.SamlClient;
import org.keycloak.testsuite.util.SamlClient.Binding;
import org.keycloak.testsuite.util.SamlClientBuilder;
Expand Down Expand Up @@ -148,8 +150,14 @@ private void testAssertionSignatureRespected() {
loginUser();

// Logout should fail because logout response is not signed.
final String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
final OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password");
final String idTokenString = tokenResponse.getIdToken();
final String redirectUri = getAccountUrl(getProviderRoot(), bc.providerRealmName());
final String logoutUri = oauth.realm(bc.providerRealmName()).getLogoutUrl().redirectUri(redirectUri).build();
final String logoutUri = oauth.realm(bc.providerRealmName()).getLogoutUrl()
.idTokenHint(idTokenString)
.postLogoutRedirectUri(redirectUri).build();

driver.navigate().to(logoutUri);

errorPage.assertCurrent();
Expand Down
Loading