KEYCLOAK-15327 backchannel logout invalidate offline session even if there is no corresponding active session found
This commit is contained in:
parent
4e9bdd44f3
commit
b2934e8dd0
4 changed files with 77 additions and 7 deletions
|
@ -831,6 +831,17 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
|
|||
return getUserSession(realm, userSessionId, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserSessionModel getOfflineUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId) {
|
||||
List<UserSessionModel> userSessions = getUserSessions(realm, UserSessionPredicate.create(realm.getId()).brokerSessionId(brokerSessionId), true);
|
||||
return userSessions.isEmpty() ? null : userSessions.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserSessionModel> getOfflineUserSessionByBrokerUserId(RealmModel realm, String brokerUserId) {
|
||||
return getUserSessions(realm, UserSessionPredicate.create(realm.getId()).brokerUserId(brokerUserId), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOfflineUserSession(RealmModel realm, UserSessionModel userSession) {
|
||||
UserSessionEntity userSessionEntity = getUserSessionEntity(realm, userSession, true);
|
||||
|
|
|
@ -86,6 +86,8 @@ public interface UserSessionProvider extends Provider {
|
|||
/** Will automatically attach newly created offline client session to the offlineUserSession **/
|
||||
AuthenticatedClientSessionModel createOfflineClientSession(AuthenticatedClientSessionModel clientSession, UserSessionModel offlineUserSession);
|
||||
List<UserSessionModel> getOfflineUserSessions(RealmModel realm, UserModel user);
|
||||
UserSessionModel getOfflineUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId);
|
||||
List<UserSessionModel> getOfflineUserSessionByBrokerUserId(RealmModel realm, String brokerUserId);
|
||||
|
||||
long getOfflineSessionsCount(RealmModel realm, ClientModel client);
|
||||
List<UserSessionModel> getOfflineUserSessions(RealmModel realm, ClientModel client, int first, int max);
|
||||
|
@ -95,4 +97,5 @@ public interface UserSessionProvider extends Provider {
|
|||
|
||||
void close();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -320,14 +320,26 @@ public class LogoutEndpoint {
|
|||
UserSessionModel userSession = session.sessions().getUserSessionByBrokerSessionId(realm,
|
||||
identityProviderAlias + "." + sessionId);
|
||||
|
||||
if (logoutOfflineSessions) {
|
||||
logoutOfflineUserSession(identityProviderAlias + "." + sessionId);
|
||||
}
|
||||
|
||||
if (userSession != null) {
|
||||
backchannelLogoutResponse = logoutUserSession(userSession, logoutOfflineSessions);
|
||||
backchannelLogoutResponse = logoutUserSession(userSession);
|
||||
}
|
||||
}
|
||||
|
||||
return backchannelLogoutResponse;
|
||||
}
|
||||
|
||||
private void logoutOfflineUserSession(String brokerSessionId) {
|
||||
UserSessionModel offlineUserSession =
|
||||
session.sessions().getOfflineUserSessionByBrokerSessionId(realm, brokerSessionId);
|
||||
if (offlineUserSession != null) {
|
||||
new UserSessionManager(session).revokeOfflineUserSession(offlineUserSession);
|
||||
}
|
||||
}
|
||||
|
||||
private BackchannelLogoutResponse backchannelLogoutFederatedUserId(String federatedUserId,
|
||||
List<String> identityProviderAliases, boolean logoutOfflineSessions) {
|
||||
BackchannelLogoutResponse backchannelLogoutResponse = new BackchannelLogoutResponse();
|
||||
|
@ -336,9 +348,13 @@ public class LogoutEndpoint {
|
|||
List<UserSessionModel> userSessions = session.sessions().getUserSessionByBrokerUserId(realm,
|
||||
identityProviderAlias + "." + federatedUserId);
|
||||
|
||||
if (logoutOfflineSessions) {
|
||||
logoutOfflineUserSessions(identityProviderAlias + "." + federatedUserId);
|
||||
}
|
||||
|
||||
for (UserSessionModel userSession : userSessions) {
|
||||
BackchannelLogoutResponse userBackchannelLogoutResponse;
|
||||
userBackchannelLogoutResponse = logoutUserSession(userSession, logoutOfflineSessions);
|
||||
userBackchannelLogoutResponse = logoutUserSession(userSession);
|
||||
backchannelLogoutResponse.setLocalLogoutSucceeded(backchannelLogoutResponse.getLocalLogoutSucceeded()
|
||||
&& userBackchannelLogoutResponse.getLocalLogoutSucceeded());
|
||||
userBackchannelLogoutResponse.getClientResponses()
|
||||
|
@ -349,11 +365,19 @@ public class LogoutEndpoint {
|
|||
return backchannelLogoutResponse;
|
||||
}
|
||||
|
||||
private BackchannelLogoutResponse logoutUserSession(UserSessionModel userSession, boolean logoutOfflineSessions) {
|
||||
BackchannelLogoutResponse backchannelLogoutResponse =
|
||||
AuthenticationManager.backchannelLogout(session, realm, userSession,
|
||||
session.getContext().getUri(),
|
||||
clientConnection, headers, false, logoutOfflineSessions);
|
||||
private void logoutOfflineUserSessions(String brokerUserId) {
|
||||
List<UserSessionModel> offlineUserSessions =
|
||||
session.sessions().getOfflineUserSessionByBrokerUserId(realm, brokerUserId);
|
||||
|
||||
UserSessionManager userSessionManager = new UserSessionManager(session);
|
||||
for (UserSessionModel offlineUserSession : offlineUserSessions) {
|
||||
userSessionManager.revokeOfflineUserSession(offlineUserSession);
|
||||
}
|
||||
}
|
||||
|
||||
private BackchannelLogoutResponse logoutUserSession(UserSessionModel userSession) {
|
||||
BackchannelLogoutResponse backchannelLogoutResponse = AuthenticationManager.backchannelLogout(session, realm,
|
||||
userSession, session.getContext().getUri(), clientConnection, headers, false);
|
||||
|
||||
if (backchannelLogoutResponse.getLocalLogoutSucceeded()) {
|
||||
event.user(userSession.getUser())
|
||||
|
|
|
@ -578,6 +578,38 @@ public class BackchannelLogoutTest extends AbstractNestedBrokerTest {
|
|||
sessionIdProviderRealm);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postBackchannelLogoutNestedBrokeringRevokeOfflineSessionsWithoutActiveUserSession() throws Exception {
|
||||
String consumerClientId =
|
||||
getClientId(nbc.consumerRealmName(), OidcBackchannelLogoutBrokerConfiguration.CONSUMER_CLIENT_ID);
|
||||
subConsumerIdpRequestsOfflineSessions();
|
||||
|
||||
logInAsUserInNestedIDPForFirstTime();
|
||||
String userIdConsumerRealm = getUserIdConsumerRealm();
|
||||
String sessionIdProviderRealm = assertProviderLoginEventIdpClient(userIdProviderRealm);
|
||||
|
||||
String sessionIdConsumerRealm = assertConsumerLoginEvent(userIdConsumerRealm,
|
||||
OidcBackchannelLogoutBrokerConfiguration.CONSUMER_CLIENT_ID);
|
||||
assertActiveSessionInClient(nbc.consumerRealmName(), consumerClientId, userIdConsumerRealm,
|
||||
sessionIdConsumerRealm);
|
||||
|
||||
logoutFromRealm(getConsumerRoot(), nbc.consumerRealmName());
|
||||
assertNoSessionsInClient(nbc.consumerRealmName(), consumerClientId, userIdConsumerRealm,
|
||||
sessionIdConsumerRealm);
|
||||
assertActiveOfflineSessionInClient(nbc.consumerRealmName(), consumerClientId, userIdConsumerRealm,
|
||||
sessionIdConsumerRealm);
|
||||
|
||||
String logoutTokenEncoded = getLogoutTokenEncodedAndSigned(userIdProviderRealm, sessionIdProviderRealm, true);
|
||||
|
||||
oauth.realm(nbc.consumerRealmName());
|
||||
try (CloseableHttpResponse response = oauth.doBackchannelLogout(logoutTokenEncoded)) {
|
||||
assertThat(response, Matchers.statusCodeIsHC(Response.Status.OK));
|
||||
}
|
||||
|
||||
assertNoOfflineSessionsInClient(nbc.consumerRealmName(), consumerClientId, userIdConsumerRealm,
|
||||
sessionIdConsumerRealm);
|
||||
}
|
||||
|
||||
private void subConsumerIdpRequestsOfflineSessions() {
|
||||
IdentityProviderResource subConsumerIDPResource = adminClient.realm(nbc.subConsumerRealmName())
|
||||
.identityProviders().get(nbc.getSubConsumerIDPDisplayName());
|
||||
|
|
Loading…
Reference in a new issue