package org.ovirt.engine.core.sso.utils;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.api.extensions.Base;
import org.ovirt.engine.api.extensions.ExtMap;
import org.ovirt.engine.api.extensions.aaa.Authn;
import org.ovirt.engine.core.extensions.mgr.ExtensionProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TokenCleanupUtility {
private static long lastCleanup = 0;
private static Logger log = LoggerFactory.getLogger(TokenCleanupUtility.class);
public static synchronized void cleanupExpiredTokens(ServletContext ctx) {
SsoContext ssoContext = SsoUtils.getSsoContext(ctx);
long currentTime = System.nanoTime();
if (currentTime - lastCleanup < (ssoContext.getSsoLocalConfig().getLong("SSO_HOUSE_KEEPING_INTERVAL") * 1000000000)) {
log.debug("Not cleaning up expired tokens");
return;
}
lastCleanup = currentTime;
log.debug("Cleaning up expired tokens");
long tokenTimeout = ssoContext.getSsoLocalConfig().getLong("SSO_TOKEN_TIMEOUT") * 1000000000;
for (Map.Entry<String, SsoSession> entry : ssoContext.getSsoSessions().entrySet()) {
if ((currentTime - entry.getValue().getTokenLastAccess()) > tokenTimeout) {
try {
cleanupSsoSession(ssoContext, entry.getValue(), entry.getValue().getAssociatedClientIds());
} catch (Exception ex) {
log.error("Unable to cleanup expired session for token {} : {}", entry.getKey(), ex.getMessage());
log.debug("Exception", ex);
}
}
}
log.debug("Done cleaning up expired tokens");
}
public static void cleanupSsoSession(
SsoContext ssoContext,
SsoSession ssoSession,
Set<String> associateClientIds) {
try {
ssoContext.removeSsoSession(ssoSession.getAccessToken());
HttpSession existingSession = ssoSession.getHttpSession();
if (existingSession == null) {
log.debug("No existing Session found for token: {}, cannot invalidate session", ssoSession.getAccessToken());
} else {
log.debug("Existing Session found for token: {}, invalidating session", ssoSession.getAccessToken());
existingSession.invalidate();
}
invokeAuthnLogout(ssoContext, ssoSession);
SsoUtils.notifyClientsOfLogoutEvent(ssoContext,
associateClientIds,
ssoSession.getAccessToken());
} catch (Exception ex) {
log.error("Unable to cleanup SsoSession: {}", ex.getMessage());
log.debug("Exception", ex);
}
}
private static void invokeAuthnLogout(SsoContext ssoContext, SsoSession ssoSession) throws Exception {
String profileName = ssoSession.getProfile();
String principalName = ssoSession.getUserId();
ExtMap authRecord = null;
ExtensionProxy authn = null;
try {
authRecord = ssoSession.getAuthRecord();
if (StringUtils.isNotEmpty(profileName) && StringUtils.isNotEmpty(principalName)) {
for (ExtensionProxy authnExtension :
ssoContext.getSsoExtensionsManager().getExtensionsByService(Authn.class.getName())) {
Properties config = authnExtension.getContext().get(Base.ContextKeys.CONFIGURATION);
if (profileName.equals(config.getProperty(Authn.ConfigKeys.PROFILE_NAME))) {
authn = authnExtension;
break;
}
}
}
} catch (Exception ex) {
throw new RuntimeException(String.format("Unable to invalidate sessions for token: %s", ex.getMessage()));
} finally {
if (authn != null && authRecord != null &&
(authn.getContext().<Long>get(Authn.ContextKeys.CAPABILITIES) & Authn.Capabilities.LOGOUT) != 0) {
authn.invoke(new ExtMap().mput(
Base.InvokeKeys.COMMAND,
Authn.InvokeCommands.LOGOUT
).mput(
Authn.InvokeKeys.AUTH_RECORD,
authRecord
));
}
}
}
}