Skip to content

Commit

Permalink
feat: add user session removed ext
Browse files Browse the repository at this point in the history
  • Loading branch information
NithinKuruba committed Jun 2, 2024
1 parent a3aca9a commit 990a5a4
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.github.bcgov.keycloak.authenticators;

import org.jboss.logging.Logger;
import org.keycloak.authentication.Authenticator;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.sessions.AuthenticationSessionModel;

import java.util.Map;

public class UserSessionRemover implements Authenticator {

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

@Override
public boolean requiresUser() {
return false;
}

@Override
public void authenticate(AuthenticationFlowContext context) {
AuthenticationSessionModel session = context.getAuthenticationSession();
AuthenticationManager.AuthResult authResult = AuthenticationManager.authenticateIdentityCookie(
context.getSession(),
context.getRealm(),
true
);

// 1. If no Cookie session, proceed to next step
if (authResult == null) {
context.attempted();
return;
}

// Need to use the KeycloakSession context to get the authenticating client ID. Not available on the AuthenticationFlowContext.
KeycloakSession keycloakSession = context.getSession();
String authenticatingClientUUID = keycloakSession.getContext().getClient().getId();

// Get all existing sessions. If any session is associated with a different client, clear all user sessions.
UserSessionProvider userSessionProvider = keycloakSession.sessions();
Map<String, Long> activeClientSessionStats = userSessionProvider.getActiveClientSessionStats(context.getRealm(), false);

for (String activeSessionClientUUID : activeClientSessionStats.keySet()) {
if (!activeSessionClientUUID.equals(authenticatingClientUUID)) {
userSessionProvider.removeUserSession(context.getRealm(), authResult.getSession());
}
}

context.attempted();
}

@Override
public void action(AuthenticationFlowContext context) {
}

@Override
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
return true;
}

@Override
public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {
}

@Override
public void close() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.github.bcgov.keycloak.authenticators;

import java.util.List;
import org.keycloak.Config;
import org.keycloak.authentication.Authenticator;
import org.keycloak.authentication.AuthenticatorFactory;
import org.keycloak.models.AuthenticationExecutionModel.Requirement;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderConfigProperty;

public class UserSessionRemoverFactory implements AuthenticatorFactory {

protected static final Requirement[] REQUIREMENT_CHOICES = {
Requirement.REQUIRED, Requirement.ALTERNATIVE, Requirement.DISABLED
};

private static final Authenticator AUTHENTICATOR_INSTANCE = new UserSessionRemover();

@Override
public String getId() {
return "user-session-remover";
}

@Override
public String getDisplayType() {
return "User Session Remover";
}

@Override
public String getHelpText() {
return "Checks if the user session is realted to any other client, and removes it if so.";
}

@Override
public Authenticator create(KeycloakSession session) {
return AUTHENTICATOR_INSTANCE;
}

@Override
public Requirement[] getRequirementChoices() {
return REQUIREMENT_CHOICES;
}

@Override
public List<ProviderConfigProperty> getConfigProperties() {
return null;
}

@Override
public String getReferenceCategory() {
return null;
}

@Override
public boolean isConfigurable() {
return false;
}

@Override
public boolean isUserSetupAllowed() {
return true;
}

@Override
public void init(Config.Scope config) {
}

@Override
public void postInit(KeycloakSessionFactory factory) {
}

@Override
public void close() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ com.github.bcgov.keycloak.authenticators.IdentityProviderStopAuthenticatorFactor
com.github.bcgov.keycloak.authenticators.CookieStopAuthenticatorFactory
com.github.bcgov.keycloak.authenticators.ClientLoginAuthenticatorFactory
com.github.bcgov.keycloak.authenticators.ClientLoginRoleBindingFactory
com.github.bcgov.keycloak.authenticators.UserSessionRemoverFactory
com.github.bcgov.keycloak.authenticators.UserAttributeAuthenticatorFactory
com.github.bcgov.keycloak.authenticators.broker.IdpDeleteUserIfDuplicateAuthenticatorFactory
com.github.bcgov.keycloak.authenticators.browser.IdentityProviderStopFormFactory

0 comments on commit 990a5a4

Please sign in to comment.