Merge pull request #1578 from stianst/master

KEYCLOAK-1791 Exception on logout on EAP 6.4 overlay
This commit is contained in:
Stian Thorgersen 2015-09-02 15:25:45 +02:00
commit 38a721425d
10 changed files with 1293 additions and 4 deletions

View file

@ -1,27 +1,54 @@
package org.keycloak.models.sessions.infinispan; package org.keycloak.models.sessions.infinispan;
import org.infinispan.Cache; import org.infinispan.Cache;
import org.infinispan.Version;
import org.jboss.logging.Logger;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.UserSessionProvider; import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.UserSessionProviderFactory; import org.keycloak.models.UserSessionProviderFactory;
import org.keycloak.models.sessions.infinispan.compat.MemUserSessionProviderFactory;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity; import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey; import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
import org.keycloak.models.sessions.infinispan.entities.SessionEntity; import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
/** /**
* Uses Infinispan to store user sessions. On EAP 6.4 (Infinispan 5.2) map reduce is not supported for local caches as a work around
* the old memory user session provider is used in this case. This can be removed once we drop support for EAP 6.4.
*
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
public class InfinispanUserSessionProviderFactory implements UserSessionProviderFactory { public class InfinispanUserSessionProviderFactory implements UserSessionProviderFactory {
private static final Logger log = Logger.getLogger(InfinispanUserSessionProviderFactory.class);
private Boolean compatMode;
private MemUserSessionProviderFactory compatProviderFactory;
@Override @Override
public UserSessionProvider create(KeycloakSession session) { public UserSessionProvider create(KeycloakSession session) {
if (compatMode == null) {
synchronized (this) {
if (compatMode == null) {
compatMode = isCompatMode(session);
if (compatMode) {
compatProviderFactory = new MemUserSessionProviderFactory();
log.info("Infinispan version doesn't support map reduce for local cache. Falling back to deprecated mem user session provider.");
}
}
}
}
if (!compatMode) {
InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class); InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class);
Cache<String, SessionEntity> cache = connections.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME); Cache<String, SessionEntity> cache = connections.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME);
Cache<LoginFailureKey, LoginFailureEntity> loginFailures = connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME); Cache<LoginFailureKey, LoginFailureEntity> loginFailures = connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
return new InfinispanUserSessionProvider(session, cache, loginFailures); return new InfinispanUserSessionProvider(session, cache, loginFailures);
} else {
return compatProviderFactory.create(session);
}
} }
@Override @Override
@ -35,6 +62,9 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
@Override @Override
public void close() { public void close() {
if (compatProviderFactory != null) {
compatProviderFactory.close();
}
} }
@Override @Override
@ -42,5 +72,16 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
return "infinispan"; return "infinispan";
} }
private static boolean isCompatMode(KeycloakSession session) {
if (Version.getVersionShort() < Version.getVersionShort("5.3.0.Final")) {
InfinispanConnectionProvider connections = session.getProvider(InfinispanConnectionProvider.class);
Cache<String, SessionEntity> cache = connections.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME);
if (cache.getAdvancedCache().getRpcManager() == null) {
return true;
}
}
return false;
}
} }

View file

@ -0,0 +1,200 @@
package org.keycloak.models.sessions.infinispan.compat;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.sessions.infinispan.compat.entities.ClientSessionEntity;
import org.keycloak.models.sessions.infinispan.compat.entities.UserSessionEntity;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class ClientSessionAdapter implements ClientSessionModel {
private KeycloakSession session;
private MemUserSessionProvider provider;
private RealmModel realm;
private ClientSessionEntity entity;
public ClientSessionAdapter(KeycloakSession session, MemUserSessionProvider provider, RealmModel realm, ClientSessionEntity entity) {
this.session = session;
this.provider = provider;
this.realm = realm;
this.entity = entity;
}
@Override
public String getId() {
return entity.getId();
}
@Override
public RealmModel getRealm() {
return session.realms().getRealm(entity.getRealmId());
}
public ClientSessionEntity getEntity() {
return entity;
}
@Override
public ClientModel getClient() {
return realm.getClientById(entity.getClientId());
}
@Override
public UserSessionModel getUserSession() {
if (entity.getSession() == null) return null;
return new UserSessionAdapter(session, provider, realm, entity.getSession());
}
@Override
public void setUserSession(UserSessionModel userSession) {
if (userSession == null) {
if (entity.getSession() != null) {
entity.getSession().getClientSessions().remove(entity);
}
entity.setSession(null);
} else {
UserSessionAdapter adapter = (UserSessionAdapter) userSession;
UserSessionEntity userSessionEntity = adapter.getEntity();
entity.setSession(userSessionEntity);
userSessionEntity.getClientSessions().add(entity);
}
}
@Override
public void setRedirectUri(String uri) {
entity.setRedirectUri(uri);
}
@Override
public void setRoles(Set<String> roles) {
entity.setRoles(roles);
}
@Override
public String getRedirectUri() {
return entity.getRedirectUri();
}
@Override
public int getTimestamp() {
return entity.getTimestamp();
}
@Override
public void setTimestamp(int timestamp) {
entity.setTimestamp(timestamp);
}
@Override
public String getAction() {
return entity.getAction();
}
@Override
public void setAction(String action) {
entity.setAction(action);
}
@Override
public Set<String> getRoles() {
return entity.getRoles();
}
@Override
public Set<String> getProtocolMappers() {
return entity.getProtocolMappers();
}
@Override
public void setProtocolMappers(Set<String> protocolMappers) {
entity.setProtocolMappers(protocolMappers);
}
@Override
public String getNote(String name) {
return entity.getNotes().get(name);
}
@Override
public void setNote(String name, String value) {
entity.getNotes().put(name, value);
}
@Override
public void removeNote(String name) {
entity.getNotes().remove(name);
}
@Override
public Map<String, String> getNotes() {
if (entity.getNotes() == null || entity.getNotes().isEmpty()) return Collections.emptyMap();
Map<String, String> copy = new HashMap<>();
copy.putAll(entity.getNotes());
return copy;
}
@Override
public void setUserSessionNote(String name, String value) {
entity.getUserSessionNotes().put(name, value);
}
@Override
public Map<String, String> getUserSessionNotes() {
return entity.getUserSessionNotes();
}
@Override
public String getAuthMethod() {
return entity.getAuthMethod();
}
@Override
public void setAuthMethod(String method) {
entity.setAuthMethod(method);
}
@Override
public Map<String, ExecutionStatus> getExecutionStatus() {
return entity.getAuthenticatorStatus();
}
@Override
public void setExecutionStatus(String authenticator, ExecutionStatus status) {
entity.getAuthenticatorStatus().put(authenticator, status);
}
@Override
public void clearExecutionStatus() {
entity.getAuthenticatorStatus().clear();
}
@Override
public void clearUserSessionNotes() {
entity.getUserSessionNotes().clear();
}
@Override
public UserModel getAuthenticatedUser() {
return entity.getAuthUserId() == null ? null : session.users().getUserById(entity.getAuthUserId(), realm); }
@Override
public void setAuthenticatedUser(UserModel user) {
if (user == null) entity.setAuthUserId(null);
else entity.setAuthUserId(user.getId());
}
}

View file

@ -0,0 +1,382 @@
package org.keycloak.models.sessions.infinispan.compat;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.sessions.infinispan.compat.entities.ClientSessionEntity;
import org.keycloak.models.sessions.infinispan.compat.entities.UserSessionEntity;
import org.keycloak.models.sessions.infinispan.compat.entities.UsernameLoginFailureEntity;
import org.keycloak.models.sessions.infinispan.compat.entities.UsernameLoginFailureKey;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RealmInfoUtil;
import org.keycloak.util.Time;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class MemUserSessionProvider implements UserSessionProvider {
private final KeycloakSession session;
private final ConcurrentHashMap<String, UserSessionEntity> userSessions;
private final ConcurrentHashMap<String, String> userSessionsByBrokerSessionId;
private final ConcurrentHashMap<String, Set<String>> userSessionsByBrokerUserId;
private final ConcurrentHashMap<String, ClientSessionEntity> clientSessions;
private final ConcurrentHashMap<UsernameLoginFailureKey, UsernameLoginFailureEntity> loginFailures;
public MemUserSessionProvider(KeycloakSession session, ConcurrentHashMap<String, UserSessionEntity> userSessions, ConcurrentHashMap<String, String> userSessionsByBrokerSessionId, ConcurrentHashMap<String, Set<String>> userSessionsByBrokerUserId, ConcurrentHashMap<String, ClientSessionEntity> clientSessions, ConcurrentHashMap<UsernameLoginFailureKey, UsernameLoginFailureEntity> loginFailures) {
this.session = session;
this.userSessions = userSessions;
this.clientSessions = clientSessions;
this.loginFailures = loginFailures;
this.userSessionsByBrokerSessionId = userSessionsByBrokerSessionId;
this.userSessionsByBrokerUserId = userSessionsByBrokerUserId;
}
@Override
public ClientSessionModel createClientSession(RealmModel realm, ClientModel client) {
ClientSessionEntity entity = new ClientSessionEntity();
entity.setId(KeycloakModelUtils.generateId());
entity.setTimestamp(Time.currentTime());
entity.setClientId(client.getId());
entity.setRealmId(realm.getId());
clientSessions.put(entity.getId(), entity);
return new ClientSessionAdapter(session, this, realm, entity);
}
@Override
public void removeClientSession(RealmModel realm, ClientSessionModel clientSession) {
ClientSessionEntity entity = ((ClientSessionAdapter)clientSession).getEntity();
UserSessionModel userSession = clientSession.getUserSession();
if (userSession != null) {
UserSessionEntity userSessionEntity = ((UserSessionAdapter)userSession).getEntity();
userSessionEntity.getClientSessions().remove(entity);
}
clientSessions.remove(clientSession.getId());
}
@Override
public ClientSessionModel getClientSession(RealmModel realm, String id) {
ClientSessionEntity entity = clientSessions.get(id);
return entity != null ? new ClientSessionAdapter(session, this, realm, entity) : null;
}
@Override
public ClientSessionModel getClientSession(String id) {
ClientSessionEntity entity = clientSessions.get(id);
if (entity != null) {
RealmModel realm = session.realms().getRealm(entity.getRealmId());
return new ClientSessionAdapter(session, this, realm, entity);
}
return null;
}
@Override
public UserSessionModel createUserSession(RealmModel realm, UserModel user, String loginUsername, String ipAddress, String authMethod, boolean rememberMe, String brokerSessionId, String brokerUserId) {
String id = KeycloakModelUtils.generateId();
UserSessionEntity entity = new UserSessionEntity();
entity.setId(id);
entity.setRealm(realm.getId());
entity.setUser(user.getId());
entity.setLoginUsername(loginUsername);
entity.setIpAddress(ipAddress);
entity.setAuthMethod(authMethod);
entity.setRememberMe(rememberMe);
int currentTime = Time.currentTime();
entity.setStarted(currentTime);
entity.setLastSessionRefresh(currentTime);
entity.setBrokerSessionId(brokerSessionId);
entity.setBrokerUserId(brokerUserId);
userSessions.put(id, entity);
if (brokerSessionId != null) {
userSessionsByBrokerSessionId.put(brokerSessionId, id);
}
if (brokerUserId != null) {
while (true) { // while loop gets around a race condition when a user session is removed
Set<String> set = userSessionsByBrokerUserId.get(brokerUserId);
if (set == null) {
Set<String> value = new HashSet<>();
set = userSessionsByBrokerUserId.putIfAbsent(brokerUserId, value);
if (set == null) {
set = value;
}
}
synchronized (set) {
set.add(id);
}
if (userSessionsByBrokerUserId.get(brokerUserId) == set) {
// we are ensured set isn't deleted before the new id is added
break;
}
}
}
return new UserSessionAdapter(session, this, realm, entity);
}
@Override
public List<UserSessionModel> getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId) {
Set<String> sessions = userSessionsByBrokerUserId.get(brokerUserId);
if (sessions == null) return Collections.emptyList();
List<UserSessionModel> userSessions = new LinkedList<UserSessionModel>();
for (String id : sessions) {
UserSessionModel userSession = getUserSession(realm, id);
if (userSession != null) userSessions.add(userSession);
}
return userSessions;
}
@Override
public UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId) {
String id = userSessionsByBrokerSessionId.get(brokerSessionId);
if (id == null) return null;
return getUserSession(realm, id);
}
@Override
public UserSessionModel getUserSession(RealmModel realm, String id) {
UserSessionEntity entity = getUserSessionEntity(realm, id);
return entity != null ? new UserSessionAdapter(session, this, realm, entity) : null;
}
UserSessionEntity getUserSessionEntity(RealmModel realm, String id) {
UserSessionEntity entity = userSessions.get(id);
if (entity != null && entity.getRealm().equals(realm.getId())) {
return entity;
}
return null;
}
@Override
public List<UserSessionModel> getUserSessions(RealmModel realm, UserModel user) {
List<UserSessionModel> userSessions = new LinkedList<UserSessionModel>();
for (UserSessionEntity s : this.userSessions.values()) {
if (s.getRealm().equals(realm.getId()) && s.getUser().equals(user.getId())) {
userSessions.add(new UserSessionAdapter(session, this, realm, s));
}
}
return userSessions;
}
@Override
public List<UserSessionModel> getUserSessionsByNote(RealmModel realm, String noteName, String noteValue) {
List<UserSessionModel> userSessions = new LinkedList<UserSessionModel>();
for (UserSessionEntity s : this.userSessions.values()) {
if (s.getRealm().equals(realm.getId()) && noteValue.equals(s.getNotes().get(noteName))) {
userSessions.add(new UserSessionAdapter(session, this, realm, s));
}
}
return userSessions;
}
@Override
public List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
List<UserSessionEntity> userSessionEntities = new LinkedList<UserSessionEntity>();
for (ClientSessionEntity s : clientSessions.values()) {
String realmId = realm.getId();
String clientId = client.getId();
if (s.getSession() != null && s.getSession().getRealm().equals(realmId) && s.getClientId().equals(clientId)) {
if (!userSessionEntities.contains(s.getSession())) {
userSessionEntities.add(s.getSession());
}
}
}
List<UserSessionModel> userSessions = new LinkedList<UserSessionModel>();
for (UserSessionEntity e : userSessionEntities) {
userSessions.add(new UserSessionAdapter(session, this, realm, e));
}
Collections.sort(userSessions, new UserSessionSort());
return userSessions;
}
@Override
public List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client, int firstResult, int maxResults) {
List<UserSessionModel> userSessions = getUserSessions(realm, client);
if (firstResult > userSessions.size()) {
return Collections.emptyList();
}
int toIndex = (firstResult + maxResults) < userSessions.size() ? firstResult + maxResults : userSessions.size();
return userSessions.subList(firstResult, toIndex);
}
@Override
public int getActiveUserSessions(RealmModel realm, ClientModel client) {
return getUserSessions(realm, client).size();
}
@Override
public void removeUserSession(RealmModel realm, UserSessionModel session) {
UserSessionEntity entity = getUserSessionEntity(realm, session.getId());
if (entity != null) {
userSessions.remove(entity.getId());
remove(entity);
}
}
@Override
public void removeUserSessions(RealmModel realm, UserModel user) {
Iterator<UserSessionEntity> itr = userSessions.values().iterator();
while (itr.hasNext()) {
UserSessionEntity s = itr.next();
if (s.getRealm().equals(realm.getId()) && s.getUser().equals(user.getId())) {
itr.remove();
remove(s);
}
}
}
protected void remove(UserSessionEntity s) {
if (s.getBrokerSessionId() != null) {
userSessionsByBrokerSessionId.remove(s.getBrokerSessionId());
}
if (s.getBrokerUserId() != null) {
Set<String> set = userSessionsByBrokerUserId.get(s.getBrokerUserId());
if (set != null) {
synchronized (set) {
set.remove(s.getId());
// this is a race condition :(
// Since it will be very rare for a user to have concurrent sessions, I'm hoping we never hit this
if (set.isEmpty()) userSessionsByBrokerUserId.remove(s.getBrokerUserId());
}
}
}
for (ClientSessionEntity clientSession : s.getClientSessions()) {
clientSessions.remove(clientSession.getId());
}
}
@Override
public void removeExpiredUserSessions(RealmModel realm) {
Iterator<UserSessionEntity> itr = userSessions.values().iterator();
while (itr.hasNext()) {
UserSessionEntity s = itr.next();
if (s.getRealm().equals(realm.getId()) && (s.getLastSessionRefresh() < Time.currentTime() - realm.getSsoSessionIdleTimeout() || s.getStarted() < Time.currentTime() - realm.getSsoSessionMaxLifespan())) {
itr.remove();
remove(s);
}
}
int expired = Time.currentTime() - RealmInfoUtil.getDettachedClientSessionLifespan(realm);
Iterator<ClientSessionEntity> citr = clientSessions.values().iterator();
while (citr.hasNext()) {
ClientSessionEntity c = citr.next();
if (c.getSession() == null && c.getRealmId().equals(realm.getId()) && c.getTimestamp() < expired) {
citr.remove();
}
}
}
@Override
public void removeUserSessions(RealmModel realm) {
Iterator<UserSessionEntity> itr = userSessions.values().iterator();
while (itr.hasNext()) {
UserSessionEntity s = itr.next();
if (s.getRealm().equals(realm.getId())) {
itr.remove();
remove(s);
}
}
Iterator<ClientSessionEntity> citr = clientSessions.values().iterator();
while (citr.hasNext()) {
ClientSessionEntity c = citr.next();
if (c.getSession() == null && c.getRealmId().equals(realm.getId())) {
citr.remove();
}
}
}
@Override
public UsernameLoginFailureModel getUserLoginFailure(RealmModel realm, String username) {
UsernameLoginFailureEntity entity = loginFailures.get(new UsernameLoginFailureKey(realm.getId(), username));
return entity != null ? new UsernameLoginFailureAdapter(entity) : null;
}
@Override
public UsernameLoginFailureModel addUserLoginFailure(RealmModel realm, String username) {
UsernameLoginFailureKey key = new UsernameLoginFailureKey(realm.getId(), username);
UsernameLoginFailureEntity entity = new UsernameLoginFailureEntity(username, realm.getId());
if (loginFailures.putIfAbsent(key, entity) != null) {
throw new ModelDuplicateException();
}
return new UsernameLoginFailureAdapter(entity);
}
@Override
public void removeUserLoginFailure(RealmModel realm, String username) {
loginFailures.remove(new UsernameLoginFailureKey(realm.getId(), username));
}
@Override
public void removeAllUserLoginFailures(RealmModel realm) {
Iterator<UsernameLoginFailureEntity> itr = loginFailures.values().iterator();
while (itr.hasNext()) {
if (itr.next().getRealm().equals(realm.getId())) {
itr.remove();
}
}
}
@Override
public void onRealmRemoved(RealmModel realm) {
removeUserSessions(realm);
removeAllUserLoginFailures(realm);
}
@Override
public void onClientRemoved(RealmModel realm, ClientModel client) {
for (ClientSessionEntity e : clientSessions.values()) {
if (e.getRealmId().equals(realm.getId()) && e.getClientId().equals(client.getId())) {
clientSessions.remove(e.getId());
e.getSession().removeClientSession(e);
}
}
}
@Override
public void onUserRemoved(RealmModel realm, UserModel user) {
removeUserSessions(realm, user);
loginFailures.remove(new UsernameLoginFailureKey(realm.getId(), user.getUsername()));
loginFailures.remove(new UsernameLoginFailureKey(realm.getId(), user.getEmail()));
}
@Override
public void close() {
}
private class UserSessionSort implements Comparator<UserSessionModel> {
@Override
public int compare(UserSessionModel o1, UserSessionModel o2) {
int r = o1.getStarted() - o2.getStarted();
if (r == 0) {
return o1.getId().compareTo(o2.getId());
} else {
return r;
}
}
}
}

View file

@ -0,0 +1,40 @@
package org.keycloak.models.sessions.infinispan.compat;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.UserSessionProvider;
import org.keycloak.models.UserSessionProviderFactory;
import org.keycloak.models.sessions.infinispan.compat.entities.ClientSessionEntity;
import org.keycloak.models.sessions.infinispan.compat.entities.UserSessionEntity;
import org.keycloak.models.sessions.infinispan.compat.entities.UsernameLoginFailureEntity;
import org.keycloak.models.sessions.infinispan.compat.entities.UsernameLoginFailureKey;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class MemUserSessionProviderFactory {
private ConcurrentHashMap<String, UserSessionEntity> userSessions = new ConcurrentHashMap<String, UserSessionEntity>();
private ConcurrentHashMap<String, ClientSessionEntity> clientSessions = new ConcurrentHashMap<String, ClientSessionEntity>();
private ConcurrentHashMap<UsernameLoginFailureKey, UsernameLoginFailureEntity> loginFailures = new ConcurrentHashMap<UsernameLoginFailureKey, UsernameLoginFailureEntity>();
private final ConcurrentHashMap<String, String> userSessionsByBrokerSessionId = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Set<String>> userSessionsByBrokerUserId = new ConcurrentHashMap<>();
public UserSessionProvider create(KeycloakSession session) {
return new MemUserSessionProvider(session, userSessions, userSessionsByBrokerSessionId, userSessionsByBrokerUserId, clientSessions, loginFailures);
}
public void close() {
userSessions.clear();
loginFailures.clear();
userSessionsByBrokerSessionId.clear();
userSessionsByBrokerUserId.clear();
}
}

View file

@ -0,0 +1,148 @@
package org.keycloak.models.sessions.infinispan.compat;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.sessions.infinispan.compat.entities.ClientSessionEntity;
import org.keycloak.models.sessions.infinispan.compat.entities.UserSessionEntity;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class UserSessionAdapter implements UserSessionModel {
private final KeycloakSession session;
private MemUserSessionProvider provider;
private final RealmModel realm;
private final UserSessionEntity entity;
public UserSessionAdapter(KeycloakSession session, MemUserSessionProvider provider, RealmModel realm, UserSessionEntity entity) {
this.session = session;
this.provider = provider;
this.realm = realm;
this.entity = entity;
}
public UserSessionEntity getEntity() {
return entity;
}
public String getId() {
return entity.getId();
}
@Override
public String getBrokerSessionId() {
return entity.getBrokerSessionId();
}
@Override
public String getBrokerUserId() {
return entity.getBrokerUserId();
}
public void setId(String id) {
entity.setId(id);
}
public UserModel getUser() {
return session.users().getUserById(entity.getUser(), realm);
}
public void setUser(UserModel user) {
entity.setUser(user.getId());
}
@Override
public String getLoginUsername() {
return entity.getLoginUsername();
}
public String getIpAddress() {
return entity.getIpAddress();
}
@Override
public String getAuthMethod() {
return entity.getAuthMethod();
}
@Override
public boolean isRememberMe() {
return entity.isRememberMe();
}
public int getStarted() {
return entity.getStarted();
}
public int getLastSessionRefresh() {
return entity.getLastSessionRefresh();
}
public void setLastSessionRefresh(int lastSessionRefresh) {
entity.setLastSessionRefresh(lastSessionRefresh);
}
@Override
public State getState() {
return entity.getState();
}
@Override
public void setState(State state) {
entity.setState(state);
}
@Override
public List<ClientSessionModel> getClientSessions() {
List<ClientSessionModel> clientSessionModels = new LinkedList<ClientSessionModel>();
if (entity.getClientSessions() != null) {
for (ClientSessionEntity e : entity.getClientSessions()) {
clientSessionModels.add(new ClientSessionAdapter(session, provider, realm, e));
}
}
return clientSessionModels;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof UserSessionModel)) return false;
UserSessionModel that = (UserSessionModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
@Override
public String getNote(String name) {
return entity.getNotes().get(name);
}
@Override
public void setNote(String name, String value) {
entity.getNotes().put(name, value);
}
@Override
public void removeNote(String name) {
entity.getNotes().remove(name);
}
}

View file

@ -0,0 +1,71 @@
package org.keycloak.models.sessions.infinispan.compat;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.sessions.infinispan.compat.entities.UsernameLoginFailureEntity;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class UsernameLoginFailureAdapter implements UsernameLoginFailureModel {
private final UsernameLoginFailureEntity entity;
public UsernameLoginFailureAdapter(UsernameLoginFailureEntity entity) {
this.entity = entity;
}
@Override
public String getUsername() {
return entity.getUsername();
}
public String getRealm() {
return entity.getRealm();
}
@Override
public int getFailedLoginNotBefore() {
return entity.getFailedLoginNotBefore().get();
}
@Override
public void setFailedLoginNotBefore(int notBefore) {
entity.getFailedLoginNotBefore().set(notBefore);
}
@Override
public int getNumFailures() {
return entity.getNumFailures().get();
}
@Override
public void incrementFailures() {
entity.getNumFailures().incrementAndGet();
}
@Override
public void clearFailures() {
entity.clearFailures();
}
@Override
public long getLastFailure() {
return entity.getLastFailure().get();
}
@Override
public void setLastFailure(long lastFailure) {
entity.getLastFailure().set(lastFailure);
}
@Override
public String getLastIPFailure() {
return entity.getLastIpFailure().get();
}
@Override
public void setLastIPFailure(String ip) {
entity.getLastIpFailure().set(ip);
}
}

View file

@ -0,0 +1,152 @@
package org.keycloak.models.sessions.infinispan.compat.entities;
import org.keycloak.models.ClientSessionModel;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class ClientSessionEntity {
private String id;
private String clientId;
private String realmId;
private Map<String, ClientSessionModel.ExecutionStatus> authenticatorStatus = new HashMap<>();
private String authUserId;
private UserSessionEntity session;
private String redirectUri;
private String authMethod;
private int timestamp;
private String action;
private Set<String> roles;
private Set<String> protocolMappers;
private Map<String, String> notes = new HashMap<>();
private Map<String, String> userSessionNotes = new HashMap<>();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getRealmId() {
return realmId;
}
public void setRealmId(String realmId) {
this.realmId = realmId;
}
public UserSessionEntity getSession() {
return session;
}
public void setSession(UserSessionEntity session) {
this.session = session;
}
public String getRedirectUri() {
return redirectUri;
}
public void setRedirectUri(String redirectUri) {
this.redirectUri = redirectUri;
}
public int getTimestamp() {
return timestamp;
}
public void setTimestamp(int timestamp) {
this.timestamp = timestamp;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
public Set<String> getRoles() {
return roles;
}
public void setRoles(Set<String> roles) {
this.roles = roles;
}
public Set<String> getProtocolMappers() {
return protocolMappers;
}
public void setProtocolMappers(Set<String> protocolMappers) {
this.protocolMappers = protocolMappers;
}
public Map<String, String> getNotes() {
return notes;
}
public String getAuthMethod() {
return authMethod;
}
public void setAuthMethod(String authMethod) {
this.authMethod = authMethod;
}
public String getAuthUserId() {
return authUserId;
}
public void setAuthUserId(String authUserId) {
this.authUserId = authUserId;
}
public Map<String, ClientSessionModel.ExecutionStatus> getAuthenticatorStatus() {
return authenticatorStatus;
}
public void setAuthenticatorStatus(Map<String, ClientSessionModel.ExecutionStatus> authenticatorStatus) {
this.authenticatorStatus = authenticatorStatus;
}
public Map<String, String> getUserSessionNotes() {
return userSessionNotes;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ClientSessionEntity)) return false;
ClientSessionEntity that = (ClientSessionEntity) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
return true;
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}

View file

@ -0,0 +1,147 @@
package org.keycloak.models.sessions.infinispan.compat.entities;
import org.keycloak.models.UserSessionModel;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class UserSessionEntity {
private String id;
private String brokerSessionId;
private String brokerUserId;
private String realm;
private String user;
private String loginUsername;
private String ipAddress;
private String authMethod;
private boolean rememberMe;
private int started;
private int lastSessionRefresh;
private UserSessionModel.State state;
private Map<String, String> notes = new HashMap<String, String>();
private List<ClientSessionEntity> clientSessions = Collections.synchronizedList(new LinkedList<ClientSessionEntity>());
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getRealm() {
return realm;
}
public void setRealm(String realm) {
this.realm = realm;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getLoginUsername() {
return loginUsername;
}
public void setLoginUsername(String loginUsername) {
this.loginUsername = loginUsername;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public String getAuthMethod() {
return authMethod;
}
public void setAuthMethod(String authMethod) {
this.authMethod = authMethod;
}
public boolean isRememberMe() {
return rememberMe;
}
public void setRememberMe(boolean rememberMe) {
this.rememberMe = rememberMe;
}
public int getStarted() {
return started;
}
public void setStarted(int started) {
this.started = started;
}
public int getLastSessionRefresh() {
return lastSessionRefresh;
}
public void setLastSessionRefresh(int lastSessionRefresh) {
this.lastSessionRefresh = lastSessionRefresh;
}
public void addClientSession(ClientSessionEntity clientSession) {
if (clientSessions == null) {
clientSessions = new LinkedList<ClientSessionEntity>();
}
clientSessions.add(clientSession);
}
public void removeClientSession(ClientSessionEntity clientSession) {
if (clientSessions != null) {
clientSessions.remove(clientSession);
}
}
public List<ClientSessionEntity> getClientSessions() {
return clientSessions;
}
public Map<String, String> getNotes() {
return notes;
}
public UserSessionModel.State getState() {
return state;
}
public void setState(UserSessionModel.State state) {
this.state = state;
}
public String getBrokerSessionId() {
return brokerSessionId;
}
public void setBrokerSessionId(String brokerSessionId) {
this.brokerSessionId = brokerSessionId;
}
public String getBrokerUserId() {
return brokerUserId;
}
public void setBrokerUserId(String brokerUserId) {
this.brokerUserId = brokerUserId;
}
}

View file

@ -0,0 +1,72 @@
package org.keycloak.models.sessions.infinispan.compat.entities;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class UsernameLoginFailureEntity {
private String username;
private String realm;
private AtomicInteger failedLoginNotBefore = new AtomicInteger();
private AtomicInteger numFailures = new AtomicInteger();
private AtomicLong lastFailure = new AtomicLong();
private AtomicReference<String> lastIpFailure = new AtomicReference<String>();
public UsernameLoginFailureEntity(String username, String realm) {
this.username = username;
this.realm = realm;
}
public String getUsername() {
return username;
}
public String getRealm() {
return realm;
}
public AtomicInteger getFailedLoginNotBefore() {
return failedLoginNotBefore;
}
public void setFailedLoginNotBefore(AtomicInteger failedLoginNotBefore) {
this.failedLoginNotBefore = failedLoginNotBefore;
}
public AtomicInteger getNumFailures() {
return numFailures;
}
public void setNumFailures(AtomicInteger numFailures) {
this.numFailures = numFailures;
}
public AtomicLong getLastFailure() {
return lastFailure;
}
public void setLastFailure(AtomicLong lastFailure) {
this.lastFailure = lastFailure;
}
public AtomicReference<String> getLastIpFailure() {
return lastIpFailure;
}
public void setLastIpFailure(AtomicReference<String> lastIpFailure) {
this.lastIpFailure = lastIpFailure;
}
public void clearFailures() {
this.failedLoginNotBefore = new AtomicInteger();
this.lastFailure = new AtomicLong();
this.lastIpFailure = new AtomicReference<String>();
this.numFailures = new AtomicInteger();
}
}

View file

@ -0,0 +1,36 @@
package org.keycloak.models.sessions.infinispan.compat.entities;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class UsernameLoginFailureKey {
private final String realm;
private final String username;
public UsernameLoginFailureKey(String realm, String username) {
this.realm = realm;
this.username = username;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UsernameLoginFailureKey key = (UsernameLoginFailureKey) o;
if (realm != null ? !realm.equals(key.realm) : key.realm != null) return false;
if (username != null ? !username.equals(key.username) : key.username != null) return false;
return true;
}
@Override
public int hashCode() {
int result = realm != null ? realm.hashCode() : 0;
result = 31 * result + (username != null ? username.hashCode() : 0);
return result;
}
}