Skip to content

Commit

Permalink
UserSessionProvider.removeUserSessions now removes all user sessions …
Browse files Browse the repository at this point in the history
…(both regular and offline)

Closes keycloak#31359

Signed-off-by: Stefan Guilhen <[email protected]>
  • Loading branch information
sguilhen authored and pedroigor committed Nov 29, 2024
1 parent 3c2e531 commit 9861acc
Show file tree
Hide file tree
Showing 10 changed files with 50 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,9 @@ expect the database schema being updated to add a new column `DETAILS_JSON` to t
The key providers that allow to import externally generated keys (`rsa` and `java-keystore` factories) now check the validity of the associated certificate if present. Therefore a key with a certificate that is expired cannot be imported in {project_name} anymore. If the certificate expires at runtime, the key is converted into a passive key (enabled but not active). A passive key is not used for new tokens, but it is still valid for validating previous issued tokens.

The default `generated` key providers generate a certificate valid for 10 years (the types that have or can have an associated certificate). Because of the long validity and the recommendation to rotate keys frequently, the generated providers do not perform this check.

= Sign out all active sessions in admin console now effectively removes all sessions

In previous versions, clicking on `Sign out all active sessions` in the admin console resulted in the removal of regular sessions only. Offline sessions would still be displayed despite being effectively invalidated.

This has been changed and now all sessions, regular and offline, are removed when signing out of all active sessions.
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ public void removeUserSessions(RealmModel realm) {

protected void onRemoveUserSessionsEvent(String realmId) {
removeLocalUserSessions(realmId, false);
removeLocalUserSessions(realmId, true);
}

// public for usage in the testsuite
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ public void removeUserSessions(RealmModel realm) {
RemoveUserSessionsEvent.createEvent(RemoveUserSessionsEvent.class, InfinispanUserSessionProviderFactory.REMOVE_USER_SESSIONS_EVENT, session, realm.getId(), true),
ClusterProvider.DCNotify.ALL_DCS);

session.getProvider(UserSessionPersisterProvider.class).removeUserSessions(realm, false);
session.getProvider(UserSessionPersisterProvider.class).removeUserSessions(realm);
}

protected void onRemoveUserSessionsEvent(String realmId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public void removeExpired(RealmModel realm) {

@Override
public void removeUserSessions(RealmModel realm) {
transaction.removeOnlineSessionsByRealmId(realm.getId());
transaction.removeAllSessionsByRealmId(realm.getId());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,7 @@ private List<PersistentClientSessionEntity> getClientSessionsByUserSession(Strin

@Override
public void onRealmRemoved(RealmModel realm) {
em.createNamedQuery("deleteClientSessionsByRealm")
.setParameter("realmId", realm.getId())
.executeUpdate();

em.createNamedQuery("deleteUserSessionsByRealm")
.setParameter("realmId", realm.getId())
.executeUpdate();
this.removeUserSessions(realm);
}

@Override
Expand Down Expand Up @@ -760,6 +754,15 @@ public void removeUserSessions(RealmModel realm, boolean offline) {
.executeUpdate();
}

@Override
public void removeUserSessions(RealmModel realm) {
em.createNamedQuery("deleteClientSessionsByRealm")
.setParameter("realmId", realm.getId())
.executeUpdate();
em.createNamedQuery("deleteUserSessionsByRealm")
.setParameter("realmId", realm.getId())
.executeUpdate();
}

@Override
public void close() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,12 @@ default void removeUserSessions(RealmModel realm, boolean offline) {
// TODO: remove default implementation
}

/**
* Removes all user sessions from the specified realm.
*/
default void removeUserSessions(RealmModel realm) {
removeUserSessions(realm, true);
removeUserSessions(realm, false);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,28 @@ UserSessionModel createUserSession(String id, RealmModel realm, UserModel user,
*/
void removeExpired(RealmModel realm);

/**
* Removes all user sessions (regular and offline) from the specified realm.
*
* @param realm the realm whose sessions are to be removed.
*/
void removeUserSessions(RealmModel realm);

/**
* Callback method invoked when a realm is removed. Implementations should clear any sessions associated with the removed
* realm.
*
* @param realm a reference to the realm being removed.
*/
void onRealmRemoved(RealmModel realm);

/**
* Callback method invoked when a client is removed. Implementations should clear any sessions associated with the
* removed client.
*
* @param realm a reference to the realm.
* @param client a reference to the client being removed.
*/
void onClientRemoved(RealmModel realm, ClientModel client);

/** Newly created userSession won't contain attached AuthenticatedClientSessions **/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ public void offlineTokenAdminRESTAccess() throws Exception {
setTimeOffset(86400);

// Remove expired sessions. This will remove "normal" userSession
testingClient.testing().removeUserSessions("test");
testingClient.testing().removeExpired("test");

// Refresh with the offline token
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "secret1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ public void testSessionExpiredOfflineAccess() throws Exception {
try {
AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client, true, true);

testingClient.testing().removeUserSessions("test");
testingClient.testing().removeExpired("test");

Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessTokenResponse.getToken());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.keycloak.models.session.UserSessionPersisterProvider;
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.model.HotRodServerRule;
import org.keycloak.testsuite.model.KeycloakModelTest;
import org.keycloak.testsuite.model.RequireProvider;
Expand Down Expand Up @@ -93,10 +94,7 @@ public void cleanEnvironment(KeycloakSession s) {
InfinispanTestUtil.revertTimeService(s);
RealmModel realm = s.realms().getRealm(realmId);
s.getContext().setRealm(realm);
UserModel user1 = s.users().getUserByUsername(realm, "user1");
s.sessions().removeUserSessions(realm);
s.sessions().getOfflineUserSessionsStream(realm, user1).forEach(us -> s.sessions().removeOfflineUserSession(realm, us));
s.realms().removeRealm(realmId);
new RealmManager(s).removeRealm(realm);

super.cleanEnvironment(s);
}
Expand Down

0 comments on commit 9861acc

Please sign in to comment.