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 94aa83df73b2..5de0f2752d8f 100755 --- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java +++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java @@ -733,10 +733,18 @@ public static Response browserLogout(KeycloakSession session, String brokerId = userSession.getNote(Details.IDENTITY_PROVIDER); String initiatingIdp = logoutAuthSession.getAuthNote(AuthenticationManager.LOGOUT_INITIATING_IDP); if (brokerId != null && !brokerId.equals(initiatingIdp)) { - UserAuthenticationIdentityProvider identityProvider = IdentityBrokerService.getIdentityProvider(session, brokerId); - Response response = identityProvider.keycloakInitiatedBrowserLogout(session, userSession, uriInfo, realm); - if (response != null) { - return response; + UserAuthenticationIdentityProvider identityProvider = null; + try { + identityProvider = IdentityBrokerService.getIdentityProvider(session, brokerId); + } catch (IdentityBrokerException e) { + logger.warnf("Identity provider [%s] is no longer available, skipping Keycloak-initiated broker logout for user session [%s]", brokerId, userSession.getId()); + } + + if (identityProvider != null) { + Response response = identityProvider.keycloakInitiatedBrowserLogout(session, userSession, uriInfo, realm); + if (response != null) { + return response; + } } } 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 7e9236bccf67..ce446da71f6f 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 @@ -289,4 +289,70 @@ public void testFrontChannelLogoutRequestsSendingOnlyClientIdWithFrontChannelLog identityProviderResource.update(representation); } } + + @Test + public void logoutSucceedsWhenIdpIsDisabled() { + logInAsUserInIDPForFirstTime(); + Assertions.assertTrue(oauth.parseLoginResponse().isSuccess()); + + // Disable the identity provider while the user session is still active + RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); + IdentityProviderResource idpResource = consumerRealm.identityProviders().get(bc.getIDPAlias()); + IdentityProviderRepresentation idpRep = idpResource.toRepresentation(); + idpRep.setEnabled(false); + idpResource.update(idpRep); + + try { + // Browser logout should complete gracefully even though the IdP is disabled + logoutFromRealm( + getConsumerRoot(), + bc.consumerRealmName(), + null, + null, + null, + null + ); + + // Verify user is actually logged out + oauth.client("broker-app"); + oauth.realm(bc.consumerRealmName()); + oauth.openLoginForm(); + waitForPage(driver, "sign in to", true); + } finally { + idpRep.setEnabled(true); + idpResource.update(idpRep); + } + } + + @Test + public void logoutSucceedsWhenIdpIsRemoved() { + logInAsUserInIDPForFirstTime(); + Assertions.assertTrue(oauth.parseLoginResponse().isSuccess()); + + // Remove the identity provider entirely while the user session is still active + RealmResource consumerRealm = adminClient.realm(bc.consumerRealmName()); + IdentityProviderResource idpResource = consumerRealm.identityProviders().get(bc.getIDPAlias()); + IdentityProviderRepresentation idpRep = idpResource.toRepresentation(); + idpResource.remove(); + + try { + // Browser logout should complete gracefully even though the IdP no longer exists + logoutFromRealm( + getConsumerRoot(), + bc.consumerRealmName(), + null, + null, + null, + null + ); + + // Verify user is actually logged out + oauth.client("broker-app"); + oauth.realm(bc.consumerRealmName()); + oauth.openLoginForm(); + waitForPage(driver, "sign in to", true); + } finally { + consumerRealm.identityProviders().create(idpRep).close(); + } + } }