Merge pull request #461 from patriot1burke/master

caching
This commit is contained in:
Bill Burke 2014-06-13 20:09:03 -04:00
commit b649dd39d9
64 changed files with 1271 additions and 471 deletions

View file

@ -95,6 +95,12 @@
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-invalidation-cache-model</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-jpa</artifactId>

View file

@ -1,6 +1,7 @@
package org.keycloak.models;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
@ -12,14 +13,16 @@ public class AuthenticationProviderModel {
private String providerName;
private boolean passwordUpdateSupported = true;
private Map<String, String> config;
private Map<String, String> config = new HashMap<String, String>();
public AuthenticationProviderModel() {};
public AuthenticationProviderModel(String providerName, boolean passwordUpdateSupported, Map<String, String> config) {
this.providerName = providerName;
this.passwordUpdateSupported = passwordUpdateSupported;
this.config = config;
if (config != null) {
this.config.putAll(config);
}
}
public String getProviderName() {

View file

@ -54,7 +54,7 @@ public class RealmEntity extends AbstractIdentifiableEntity {
private Map<String, String> smtpConfig = new HashMap<String, String>();
private Map<String, String> socialConfig = new HashMap<String, String>();
private Map<String, String> ldapServerConfig;
private Map<String, String> ldapServerConfig = new HashMap<String, String>();
private boolean auditEnabled;
private long auditExpiration;

View file

@ -35,17 +35,6 @@
<artifactId>keycloak-model-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.entitymanager.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
@ -83,37 +72,6 @@
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<!-- Test jar used in export-import -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>package-tests-jar</id>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>default-test</id>
<configuration>
<dependenciesToScan>
<dependency>org.keycloak:keycloak-model-tests</dependency>
</dependenciesToScan>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

View file

@ -28,6 +28,7 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
@Override
protected void getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerApplicationInvalidation(getId());
updatedClient = updated = cacheSession.getDelegate().getApplicationById(getId(), cachedRealm);
if (updated == null) throw new IllegalStateException("Not found in database");
}
@ -40,7 +41,8 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
@Override
public String getName() {
return getClientId();
if (updated != null) return updated.getName();
return cached.getName();
}
@Override
@ -150,17 +152,22 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
@Override
public RoleModel addRole(String name) {
getDelegateForUpdate();
return updated.addRole(name);
RoleModel role = updated.addRole(name);
cacheSession.registerRoleInvalidation(role.getId());
return role;
}
@Override
public RoleModel addRole(String id, String name) {
getDelegateForUpdate();
return updated.addRole(id, name);
RoleModel role = updated.addRole(id, name);
cacheSession.registerRoleInvalidation(role.getId());
return role;
}
@Override
public boolean removeRole(RoleModel role) {
cacheSession.registerRoleInvalidation(role.getId());
getDelegateForUpdate();
return updated.removeRole(role);
}
@ -171,8 +178,25 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
Set<RoleModel> roles = new HashSet<RoleModel>();
for (String id : cached.getRoles().values()) {
roles.add(cacheSession.getRoleById(id, cachedRealm));
RoleModel roleById = cacheSession.getRoleById(id, cachedRealm);
if (roleById == null) continue;
roles.add(roleById);
}
return roles;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof ApplicationModel)) return false;
ApplicationModel that = (ApplicationModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -1,291 +1,19 @@
package org.keycloak.models.cache;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.AuthenticationLinkModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRole;
import org.keycloak.provider.ProviderSession;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CacheKeycloakSession implements KeycloakSession {
protected KeycloakCache cache;
protected ProviderSession providerSession;
protected KeycloakSession sessionDelegate;
protected KeycloakTransaction transactionDelegate;
protected boolean transactionActive;
protected boolean setRollbackOnly;
public interface CacheKeycloakSession extends KeycloakSession {
KeycloakSession getDelegate();
protected Set<String> realmInvalidations = new HashSet<String>();
protected boolean clearAll;
void registerRealmInvalidation(String id);
protected KeycloakSession getDelegate() {
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
if (sessionDelegate != null) return sessionDelegate;
sessionDelegate = providerSession.getProvider(KeycloakSession.class);
transactionDelegate = sessionDelegate.getTransaction();
if (!transactionDelegate.isActive()) {
transactionDelegate.begin();
if (setRollbackOnly) {
transactionDelegate.setRollbackOnly();
}
}
return sessionDelegate;
}
void registerApplicationInvalidation(String id);
public void registerInvalidation(RealmAdapter realm) {
realmInvalidations.add(realm.getId());
}
void registerRoleInvalidation(String id);
public void runInvalidations() {
for (String id : realmInvalidations) {
cache.invalidateCachedRealmById(id);
}
}
@Override
public KeycloakTransaction getTransaction() {
return new KeycloakTransaction() {
@Override
public void begin() {
transactionActive = true;
}
@Override
public void commit() {
if (sessionDelegate == null) return;
try {
sessionDelegate.getTransaction().commit();
} finally {
runInvalidations();
}
}
@Override
public void rollback() {
setRollbackOnly = true;
if (sessionDelegate == null) return;
try {
sessionDelegate.getTransaction().commit();
} finally {
runInvalidations();
}
}
@Override
public void setRollbackOnly() {
setRollbackOnly = true;
if (sessionDelegate == null) return;
sessionDelegate.getTransaction().setRollbackOnly();
setRollbackOnly = true;
}
@Override
public boolean getRollbackOnly() {
return setRollbackOnly;
}
@Override
public boolean isActive() {
return transactionActive;
}
};
}
@Override
public RealmModel createRealm(String name) {
return getDelegate().createRealm(name);
}
@Override
public RealmModel createRealm(String id, String name) {
return getDelegate().createRealm(id, name);
}
@Override
public RealmModel getRealm(String id) {
CachedRealm cached = cache.getCachedRealm(id);
if (cached == null) {
RealmModel model = getDelegate().getRealm(id);
if (model == null) return null;
cached = new CachedRealm(cache, this, model);
}
return new RealmAdapter(cached, this);
}
@Override
public RealmModel getRealmByName(String name) {
CachedRealm cached = cache.getCachedRealmByName(name);
if (cached == null) {
RealmModel model = getDelegate().getRealmByName(name);
if (model == null) return null;
cached = new CachedRealm(cache, this, model);
}
return new RealmAdapter(cached, this);
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List<RealmModel> getRealms() {
// we don't cache this for now
return getDelegate().getRealms();
}
@Override
public boolean removeRealm(String id) {
cache.invalidateCachedRealmById(id);
boolean didIt = getDelegate().removeRealm(id);
realmInvalidations.add(id);
return didIt;
}
@Override
public void removeAllData() {
cache.clear();
getDelegate().removeAllData();
clearAll = true;
}
@Override
public void close() {
if (sessionDelegate != null) sessionDelegate.close();
}
@Override
public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List<UserModel> getUsers(RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List<UserModel> searchForUser(String search, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public RoleModel getRoleById(String id, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public ApplicationModel getApplicationById(String id, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public OAuthClientModel getOAuthClientById(String id, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public UsernameLoginFailureModel getUserLoginFailure(String username, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public UsernameLoginFailureModel addUserLoginFailure(String username, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List<UsernameLoginFailureModel> getAllUserLoginFailures(RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public UserSessionModel createUserSession(RealmModel realm, UserModel user, String ipAddress) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public UserSessionModel getUserSession(String id, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public List<UserSessionModel> getUserSessions(UserModel user, RealmModel realm) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public Set<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public int getActiveUserSessions(RealmModel realm, ClientModel client) {
return 0; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void removeUserSession(UserSessionModel session) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void removeUserSessions(RealmModel realm, UserModel user) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void removeExpiredUserSessions(RealmModel realm) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void removeUserSessions(RealmModel realm) {
//To change body of implemented methods use File | Settings | File Templates.
}
void registerOAuthClientInvalidation(String id);
}

View file

@ -0,0 +1,13 @@
package org.keycloak.models.cache;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.ProviderSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface CacheKeycloakSessionFactory extends ProviderFactory<CacheKeycloakSession> {
CacheKeycloakSession create(ProviderSession providerSession);
void close();
}

View file

@ -0,0 +1,27 @@
package org.keycloak.models.cache;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CacheKeycloakSessionSpi implements Spi {
@Override
public String getName() {
return "modelCache";
}
@Override
public Class<? extends Provider> getProviderClass() {
return CacheKeycloakSession.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return CacheKeycloakSessionFactory.class;
}
}

View file

@ -0,0 +1,404 @@
package org.keycloak.models.cache;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.cache.entities.CachedApplication;
import org.keycloak.models.cache.entities.CachedApplicationRole;
import org.keycloak.models.cache.entities.CachedOAuthClient;
import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRealmRole;
import org.keycloak.models.cache.entities.CachedRole;
import org.keycloak.provider.ProviderSession;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class DefaultCacheKeycloakSession implements CacheKeycloakSession {
protected KeycloakCache cache;
protected ProviderSession providerSession;
protected KeycloakSession sessionDelegate;
protected KeycloakTransaction transactionDelegate;
protected boolean transactionActive;
protected boolean setRollbackOnly;
protected Set<String> realmInvalidations = new HashSet<String>();
protected Set<String> appInvalidations = new HashSet<String>();
protected Set<String> roleInvalidations = new HashSet<String>();
protected Set<String> clientInvalidations = new HashSet<String>();
protected Map<String, RealmModel> managedRealms = new HashMap<String, RealmModel>();
protected Map<String, ApplicationModel> managedApplications = new HashMap<String, ApplicationModel>();
protected Map<String, OAuthClientModel> managedClients = new HashMap<String, OAuthClientModel>();
protected Map<String, RoleModel> managedRoles = new HashMap<String, RoleModel>();
protected boolean clearAll;
public DefaultCacheKeycloakSession(KeycloakCache cache, ProviderSession providerSession) {
this.cache = cache;
this.providerSession = providerSession;
}
@Override
public KeycloakSession getDelegate() {
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
if (sessionDelegate != null) return sessionDelegate;
sessionDelegate = providerSession.getProvider(KeycloakSession.class);
transactionDelegate = sessionDelegate.getTransaction();
if (!transactionDelegate.isActive()) {
transactionDelegate.begin();
if (setRollbackOnly) {
transactionDelegate.setRollbackOnly();
}
}
return sessionDelegate;
}
@Override
public void registerRealmInvalidation(String id) {
realmInvalidations.add(id);
}
@Override
public void registerApplicationInvalidation(String id) {
appInvalidations.add(id);
}
@Override
public void registerRoleInvalidation(String id) {
roleInvalidations.add(id);
}
@Override
public void registerOAuthClientInvalidation(String id) {
clientInvalidations.add(id);
}
protected void runInvalidations() {
for (String id : realmInvalidations) {
cache.invalidateCachedRealmById(id);
}
for (String id : roleInvalidations) {
cache.invalidateRoleById(id);
}
for (String id : appInvalidations) {
cache.invalidateCachedApplicationById(id);
}
for (String id : clientInvalidations) {
cache.invalidateCachedOAuthClientById(id);
}
}
@Override
public KeycloakTransaction getTransaction() {
return new KeycloakTransaction() {
@Override
public void begin() {
transactionActive = true;
}
@Override
public void commit() {
if (sessionDelegate == null) return;
try {
sessionDelegate.getTransaction().commit();
if (clearAll) {
cache.clear();
}
} finally {
runInvalidations();
}
}
@Override
public void rollback() {
setRollbackOnly = true;
if (sessionDelegate == null) return;
try {
sessionDelegate.getTransaction().rollback();
} finally {
runInvalidations();
}
}
@Override
public void setRollbackOnly() {
setRollbackOnly = true;
if (sessionDelegate == null) return;
sessionDelegate.getTransaction().setRollbackOnly();
setRollbackOnly = true;
}
@Override
public boolean getRollbackOnly() {
return setRollbackOnly;
}
@Override
public boolean isActive() {
return transactionActive;
}
};
}
@Override
public RealmModel createRealm(String name) {
RealmModel realm = getDelegate().createRealm(name);
registerRealmInvalidation(realm.getId());
return realm;
}
@Override
public RealmModel createRealm(String id, String name) {
RealmModel realm = getDelegate().createRealm(id, name);
registerRealmInvalidation(realm.getId());
return realm;
}
@Override
public RealmModel getRealm(String id) {
CachedRealm cached = cache.getCachedRealm(id);
if (cached == null) {
RealmModel model = getDelegate().getRealm(id);
if (model == null) return null;
if (realmInvalidations.contains(id)) return model;
cached = new CachedRealm(cache, this, model);
cache.addCachedRealm(cached);
} else if (realmInvalidations.contains(id)) {
return getDelegate().getRealm(id);
} else if (managedRealms.containsKey(id)) {
return managedRealms.get(id);
}
RealmAdapter adapter = new RealmAdapter(cached, this);
managedRealms.put(id, adapter);
return adapter;
}
@Override
public RealmModel getRealmByName(String name) {
CachedRealm cached = cache.getCachedRealmByName(name);
if (cached == null) {
RealmModel model = getDelegate().getRealmByName(name);
if (model == null) return null;
if (realmInvalidations.contains(model.getId())) return model;
cached = new CachedRealm(cache, this, model);
cache.addCachedRealm(cached);
} else if (realmInvalidations.contains(cached.getId())) {
return getDelegate().getRealmByName(name);
} else if (managedRealms.containsKey(cached.getId())) {
return managedRealms.get(cached.getId());
}
RealmAdapter adapter = new RealmAdapter(cached, this);
managedRealms.put(cached.getId(), adapter);
return adapter;
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
return getDelegate().getUserById(id, realm);
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
return getDelegate().getUserByUsername(username, realm);
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
return getDelegate().getUserByEmail(email, realm);
}
@Override
public List<RealmModel> getRealms() {
// we don't cache this for now
return getDelegate().getRealms();
}
@Override
public boolean removeRealm(String id) {
cache.invalidateCachedRealmById(id);
boolean didIt = getDelegate().removeRealm(id);
realmInvalidations.add(id);
return didIt;
}
@Override
public void removeAllData() {
cache.clear();
getDelegate().removeAllData();
clearAll = true;
}
@Override
public void close() {
if (sessionDelegate != null) sessionDelegate.close();
}
@Override
public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
return getDelegate().getUserBySocialLink(socialLink, realm);
}
@Override
public List<UserModel> getUsers(RealmModel realm) {
return getDelegate().getUsers(realm);
}
@Override
public List<UserModel> searchForUser(String search, RealmModel realm) {
return getDelegate().searchForUser(search, realm);
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
return getDelegate().searchForUserByAttributes(attributes, realm);
}
@Override
public Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm) {
return getDelegate().getSocialLinks(user, realm);
}
@Override
public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
return getDelegate().getSocialLink(user, socialProvider, realm);
}
@Override
public RoleModel getRoleById(String id, RealmModel realm) {
CachedRole cached = cache.getRole(id);
if (cached == null) {
RoleModel model = getDelegate().getRoleById(id, realm);
if (model == null) return null;
if (roleInvalidations.contains(id)) return model;
if (model.getContainer() instanceof ApplicationModel) {
cached = new CachedApplicationRole(((ApplicationModel) model.getContainer()).getId(), model);
} else {
cached = new CachedRealmRole(model);
}
cache.addCachedRole(cached);
} else if (roleInvalidations.contains(id)) {
return getDelegate().getRoleById(id, realm);
} else if (managedRoles.containsKey(id)) {
return managedRoles.get(id);
}
RoleAdapter adapter = new RoleAdapter(cached, cache, this, realm);
managedRoles.put(id, adapter);
return adapter;
}
@Override
public ApplicationModel getApplicationById(String id, RealmModel realm) {
CachedApplication cached = cache.getApplication(id);
if (cached == null) {
ApplicationModel model = getDelegate().getApplicationById(id, realm);
if (model == null) return null;
if (appInvalidations.contains(id)) return model;
cached = new CachedApplication(cache, getDelegate(), realm, model);
cache.addCachedApplication(cached);
} else if (appInvalidations.contains(id)) {
return getDelegate().getApplicationById(id, realm);
} else if (managedApplications.containsKey(id)) {
return managedApplications.get(id);
}
ApplicationAdapter adapter = new ApplicationAdapter(realm, cached, this, cache);
managedApplications.put(id, adapter);
return adapter;
}
@Override
public OAuthClientModel getOAuthClientById(String id, RealmModel realm) {
CachedOAuthClient cached = cache.getOAuthClient(id);
if (cached == null) {
OAuthClientModel model = getDelegate().getOAuthClientById(id, realm);
if (model == null) return null;
if (clientInvalidations.contains(id)) return model;
cached = new CachedOAuthClient(cache, getDelegate(), realm, model);
cache.addCachedOAuthClient(cached);
} else if (clientInvalidations.contains(id)) {
return getDelegate().getOAuthClientById(id, realm);
} else if (managedClients.containsKey(id)) {
return managedClients.get(id);
}
OAuthClientAdapter adapter = new OAuthClientAdapter(realm, cached, this, cache);
managedClients.put(id, adapter);
return adapter;
}
@Override
public UsernameLoginFailureModel getUserLoginFailure(String username, RealmModel realm) {
return getDelegate().getUserLoginFailure(username, realm);
}
@Override
public UsernameLoginFailureModel addUserLoginFailure(String username, RealmModel realm) {
return getDelegate().addUserLoginFailure(username, realm);
}
@Override
public List<UsernameLoginFailureModel> getAllUserLoginFailures(RealmModel realm) {
return getDelegate().getAllUserLoginFailures(realm);
}
@Override
public UserSessionModel createUserSession(RealmModel realm, UserModel user, String ipAddress) {
return getDelegate().createUserSession(realm, user, ipAddress);
}
@Override
public UserSessionModel getUserSession(String id, RealmModel realm) {
return getDelegate().getUserSession(id, realm);
}
@Override
public List<UserSessionModel> getUserSessions(UserModel user, RealmModel realm) {
return getDelegate().getUserSessions(user, realm);
}
@Override
public Set<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
return getDelegate().getUserSessions(realm, client);
}
@Override
public int getActiveUserSessions(RealmModel realm, ClientModel client) {
return getDelegate().getActiveUserSessions(realm, client);
}
@Override
public void removeUserSession(UserSessionModel session) {
getDelegate().removeUserSession(session);
}
@Override
public void removeUserSessions(RealmModel realm, UserModel user) {
getDelegate().removeUserSessions(realm, user);
}
@Override
public void removeExpiredUserSessions(RealmModel realm) {
getDelegate().removeExpiredUserSessions(realm);
}
@Override
public void removeUserSessions(RealmModel realm) {
getDelegate().removeUserSessions(realm);
}
}

View file

@ -47,4 +47,5 @@ public interface KeycloakCache {
void invalidateCachedRoleById(String id);
void invalidateRoleById(String id);
}

View file

@ -0,0 +1,281 @@
package org.keycloak.models.cache;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.cache.entities.CachedApplication;
import org.keycloak.models.cache.entities.CachedApplicationRole;
import org.keycloak.models.cache.entities.CachedOAuthClient;
import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRealmRole;
import org.keycloak.models.cache.entities.CachedRole;
import org.keycloak.provider.ProviderSession;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class NoCacheKeycloakSession implements CacheKeycloakSession {
protected ProviderSession providerSession;
protected KeycloakSession sessionDelegate;
protected KeycloakTransaction transactionDelegate;
protected boolean transactionActive;
protected boolean setRollbackOnly;
public NoCacheKeycloakSession(ProviderSession providerSession) {
this.providerSession = providerSession;
}
@Override
public KeycloakSession getDelegate() {
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
if (sessionDelegate != null) return sessionDelegate;
sessionDelegate = providerSession.getProvider(KeycloakSession.class);
transactionDelegate = sessionDelegate.getTransaction();
if (!transactionDelegate.isActive()) {
transactionDelegate.begin();
if (setRollbackOnly) {
transactionDelegate.setRollbackOnly();
}
}
return sessionDelegate;
}
@Override
public void registerRealmInvalidation(String id) {
}
@Override
public void registerApplicationInvalidation(String id) {
}
@Override
public void registerRoleInvalidation(String id) {
}
@Override
public void registerOAuthClientInvalidation(String id) {
}
@Override
public KeycloakTransaction getTransaction() {
return new KeycloakTransaction() {
@Override
public void begin() {
transactionActive = true;
}
@Override
public void commit() {
if (sessionDelegate == null) return;
try {
sessionDelegate.getTransaction().commit();
} finally {
}
}
@Override
public void rollback() {
setRollbackOnly = true;
if (sessionDelegate == null) return;
try {
sessionDelegate.getTransaction().rollback();
} finally {
}
}
@Override
public void setRollbackOnly() {
setRollbackOnly = true;
if (sessionDelegate == null) return;
sessionDelegate.getTransaction().setRollbackOnly();
setRollbackOnly = true;
}
@Override
public boolean getRollbackOnly() {
return setRollbackOnly;
}
@Override
public boolean isActive() {
return transactionActive;
}
};
}
@Override
public RealmModel createRealm(String name) {
return getDelegate().createRealm(name);
}
@Override
public RealmModel createRealm(String id, String name) {
return getDelegate().createRealm(id, name);
}
@Override
public RealmModel getRealm(String id) {
return getDelegate().getRealm(id);
}
@Override
public RealmModel getRealmByName(String name) {
return getDelegate().getRealmByName(name);
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
return getDelegate().getUserById(id, realm);
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
return getDelegate().getUserByUsername(username, realm);
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
return getDelegate().getUserByEmail(email, realm);
}
@Override
public List<RealmModel> getRealms() {
// we don't cache this for now
return getDelegate().getRealms();
}
@Override
public boolean removeRealm(String id) {
return getDelegate().removeRealm(id);
}
@Override
public void removeAllData() {
getDelegate().removeAllData();
}
@Override
public void close() {
if (sessionDelegate != null) sessionDelegate.close();
}
@Override
public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
return getDelegate().getUserBySocialLink(socialLink, realm);
}
@Override
public List<UserModel> getUsers(RealmModel realm) {
return getDelegate().getUsers(realm);
}
@Override
public List<UserModel> searchForUser(String search, RealmModel realm) {
return getDelegate().searchForUser(search, realm);
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
return getDelegate().searchForUserByAttributes(attributes, realm);
}
@Override
public Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm) {
return getDelegate().getSocialLinks(user, realm);
}
@Override
public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
return getDelegate().getSocialLink(user, socialProvider, realm);
}
@Override
public RoleModel getRoleById(String id, RealmModel realm) {
return getDelegate().getRoleById(id, realm);
}
@Override
public ApplicationModel getApplicationById(String id, RealmModel realm) {
return getDelegate().getApplicationById(id, realm);
}
@Override
public OAuthClientModel getOAuthClientById(String id, RealmModel realm) {
return getDelegate().getOAuthClientById(id, realm);
}
@Override
public UsernameLoginFailureModel getUserLoginFailure(String username, RealmModel realm) {
return getDelegate().getUserLoginFailure(username, realm);
}
@Override
public UsernameLoginFailureModel addUserLoginFailure(String username, RealmModel realm) {
return getDelegate().addUserLoginFailure(username, realm);
}
@Override
public List<UsernameLoginFailureModel> getAllUserLoginFailures(RealmModel realm) {
return getDelegate().getAllUserLoginFailures(realm);
}
@Override
public UserSessionModel createUserSession(RealmModel realm, UserModel user, String ipAddress) {
return getDelegate().createUserSession(realm, user, ipAddress);
}
@Override
public UserSessionModel getUserSession(String id, RealmModel realm) {
return getDelegate().getUserSession(id, realm);
}
@Override
public List<UserSessionModel> getUserSessions(UserModel user, RealmModel realm) {
return getDelegate().getUserSessions(user, realm);
}
@Override
public Set<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
return getDelegate().getUserSessions(realm, client);
}
@Override
public int getActiveUserSessions(RealmModel realm, ClientModel client) {
return getDelegate().getActiveUserSessions(realm, client);
}
@Override
public void removeUserSession(UserSessionModel session) {
getDelegate().removeUserSession(session);
}
@Override
public void removeUserSessions(RealmModel realm, UserModel user) {
getDelegate().removeUserSessions(realm, user);
}
@Override
public void removeExpiredUserSessions(RealmModel realm) {
getDelegate().removeExpiredUserSessions(realm);
}
@Override
public void removeUserSessions(RealmModel realm) {
getDelegate().removeUserSessions(realm);
}
}

View file

@ -0,0 +1,30 @@
package org.keycloak.models.cache;
import org.keycloak.Config;
import org.keycloak.provider.ProviderSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class NoCacheKeycloakSessionFactory implements CacheKeycloakSessionFactory {
@Override
public CacheKeycloakSession create(ProviderSession providerSession) {
return new NoCacheKeycloakSession(providerSession);
}
@Override
public void close() {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public void init(Config.Scope config) {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public String getId() {
return "none";
}
}

View file

@ -29,6 +29,7 @@ public class OAuthClientAdapter extends ClientAdapter implements OAuthClientMode
@Override
protected void getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerOAuthClientInvalidation(getId());
updatedClient = updated = cacheSession.getDelegate().getOAuthClientById(getId(), cachedRealm);
if (updated == null) throw new IllegalStateException("Not found in database");
}
@ -45,4 +46,19 @@ public class OAuthClientAdapter extends ClientAdapter implements OAuthClientMode
getDelegateForUpdate();
updated.setClientId(id);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof OAuthClientModel)) return false;
OAuthClientModel that = (OAuthClientModel) o;
return that.getId().equals(this.getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -52,6 +52,7 @@ public class RealmAdapter implements RealmModel {
protected void getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerRealmInvalidation(getId());
updated = cacheSession.getDelegate().getRealm(getId());
if (updated == null) throw new IllegalStateException("Not found in database");
}
@ -440,20 +441,8 @@ public class RealmAdapter implements RealmModel {
@Override
public RoleModel getRoleById(String id) {
if (updated != null) return updated.getRoleById(id);
if (!cached.getRolesById().contains(id)) return null;
CachedRole cachedRole = cache.getRole(id);
if (cachedRole == null) {
RoleModel roleModel = cacheSession.getDelegate().getRoleById(id, this);
if (roleModel == null) return null;
if (roleModel.getContainer() instanceof ApplicationModel) {
cachedRole = new CachedApplicationRole(((ApplicationModel) roleModel.getContainer()).getId(), roleModel);
cache.addCachedRole(cachedRole);
} else {
cachedRole = new CachedRealmRole(roleModel);
}
}
return new RoleAdapter(cachedRole, cache, cacheSession, this);
}
return cacheSession.getRoleById(id, this);
}
@Override
public List<String> getDefaultRoles() {
@ -519,17 +508,22 @@ public class RealmAdapter implements RealmModel {
@Override
public ApplicationModel addApplication(String name) {
getDelegateForUpdate();
return updated.addApplication(name);
ApplicationModel app = updated.addApplication(name);
cacheSession.registerApplicationInvalidation(app.getId());
return app;
}
@Override
public ApplicationModel addApplication(String id, String name) {
getDelegateForUpdate();
return updated.addApplication(id, name);
ApplicationModel app = updated.addApplication(id, name);
cacheSession.registerApplicationInvalidation(app.getId());
return app;
}
@Override
public boolean removeApplication(String id) {
cacheSession.registerApplicationInvalidation(id);
getDelegateForUpdate();
return updated.removeApplication(id);
}
@ -629,13 +623,17 @@ public class RealmAdapter implements RealmModel {
@Override
public OAuthClientModel addOAuthClient(String name) {
getDelegateForUpdate();
return updated.addOAuthClient(name);
OAuthClientModel client = updated.addOAuthClient(name);
cacheSession.registerOAuthClientInvalidation(client.getId());
return client;
}
@Override
public OAuthClientModel addOAuthClient(String id, String name) {
getDelegateForUpdate();
return updated.addOAuthClient(id, name);
OAuthClientModel client = updated.addOAuthClient(id, name);
cacheSession.registerOAuthClientInvalidation(client.getId());
return client;
}
@Override
@ -654,6 +652,7 @@ public class RealmAdapter implements RealmModel {
@Override
public boolean removeOAuthClient(String id) {
cacheSession.registerOAuthClientInvalidation(id);
getDelegateForUpdate();
return updated.removeOAuthClient(id);
}
@ -782,6 +781,7 @@ public class RealmAdapter implements RealmModel {
@Override
public boolean removeRoleById(String id) {
cacheSession.registerRoleInvalidation(id);
getDelegateForUpdate();
return updated.removeRoleById(id);
}
@ -845,17 +845,22 @@ public class RealmAdapter implements RealmModel {
@Override
public RoleModel addRole(String name) {
getDelegateForUpdate();
return updated.addRole(name);
RoleModel role = updated.addRole(name);
cacheSession.registerRoleInvalidation(role.getId());
return role;
}
@Override
public RoleModel addRole(String id, String name) {
getDelegateForUpdate();
return updated.addRole(id, name);
RoleModel role = updated.addRole(id, name);
cacheSession.registerRoleInvalidation(role.getId());
return role;
}
@Override
public boolean removeRole(RoleModel role) {
cacheSession.registerRoleInvalidation(role.getId());
getDelegateForUpdate();
return updated.removeRole(role);
}
@ -866,7 +871,9 @@ public class RealmAdapter implements RealmModel {
Set<RoleModel> roles = new HashSet<RoleModel>();
for (String id : cached.getRealmRoles().values()) {
roles.add(cacheSession.getRoleById(id, this));
RoleModel roleById = cacheSession.getRoleById(id, this);
if (roleById == null) continue;
roles.add(roleById);
}
return roles;
}
@ -958,7 +965,7 @@ public class RealmAdapter implements RealmModel {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof RealmModel)) return false;
if (o == null || !(o instanceof RealmModel)) return false;
RealmModel that = (RealmModel) o;
return that.getId().equals(getId());

View file

@ -32,6 +32,7 @@ public class RoleAdapter implements RoleModel {
protected void getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerRoleInvalidation(getId());
updated = cacheSession.getDelegate().getRoleById(getId(), realm);
if (updated == null) throw new IllegalStateException("Not found in database");
}
@ -118,4 +119,19 @@ public class RoleAdapter implements RoleModel {
Set<RoleModel> visited = new HashSet<RoleModel>();
return KeycloakModelUtils.searchFor(role, this, visited);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof RoleModel)) return false;
RoleModel that = (RoleModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -23,11 +23,17 @@ public class SimpleCache implements KeycloakCache {
protected ConcurrentHashMap<String, CachedRealm> realmCache = new ConcurrentHashMap<String, CachedRealm>();
protected ConcurrentHashMap<String, CachedRealm> realmCacheByName = new ConcurrentHashMap<String, CachedRealm>();
protected ConcurrentHashMap<String, CachedApplication> applicationCache = new ConcurrentHashMap<String, CachedApplication>();
protected ConcurrentHashMap<String, CachedOAuthClient> clientCache = new ConcurrentHashMap<String, CachedOAuthClient>();
protected ConcurrentHashMap<String, CachedRole> roleCache = new ConcurrentHashMap<String, CachedRole>();
@Override
public void clear() {
realmCache.clear();
realmCacheByName.clear();
applicationCache.clear();
clientCache.clear();
roleCache.clear();
}
@Override
@ -51,7 +57,7 @@ public class SimpleCache implements KeycloakCache {
@Override
public void addCachedRealm(CachedRealm realm) {
realmCache.put(realm.getId(), realm);
realmCache.put(realm.getName(), realm);
realmCacheByName.put(realm.getName(), realm);
}
@ -62,61 +68,66 @@ public class SimpleCache implements KeycloakCache {
@Override
public CachedApplication getApplication(String id) {
return null; //To change body of implemented methods use File | Settings | File Templates.
return applicationCache.get(id);
}
@Override
public void invalidateApplication(CachedApplication app) {
//To change body of implemented methods use File | Settings | File Templates.
applicationCache.remove(app.getId());
}
@Override
public void addCachedApplication(CachedApplication app) {
//To change body of implemented methods use File | Settings | File Templates.
applicationCache.put(app.getId(), app);
}
@Override
public void invalidateCachedApplicationById(String id) {
//To change body of implemented methods use File | Settings | File Templates.
applicationCache.remove(id);
}
@Override
public CachedOAuthClient getOAuthClient(String id) {
return null; //To change body of implemented methods use File | Settings | File Templates.
return clientCache.get(id);
}
@Override
public void invalidateOAuthClient(CachedOAuthClient client) {
//To change body of implemented methods use File | Settings | File Templates.
clientCache.remove(client.getId());
}
@Override
public void addCachedOAuthClient(CachedOAuthClient client) {
//To change body of implemented methods use File | Settings | File Templates.
clientCache.put(client.getId(), client);
}
@Override
public void invalidateCachedOAuthClientById(String id) {
//To change body of implemented methods use File | Settings | File Templates.
clientCache.remove(id);
}
@Override
public CachedRole getRole(String id) {
return null; //To change body of implemented methods use File | Settings | File Templates.
return roleCache.get(id);
}
@Override
public void invalidateRole(CachedRole role) {
//To change body of implemented methods use File | Settings | File Templates.
roleCache.remove(role);
}
@Override
public void invalidateRoleById(String id) {
roleCache.remove(id);
}
@Override
public void addCachedRole(CachedRole role) {
//To change body of implemented methods use File | Settings | File Templates.
roleCache.put(role.getId(), role);
}
@Override
public void invalidateCachedRoleById(String id) {
//To change body of implemented methods use File | Settings | File Templates.
roleCache.remove(id);
}
}

View file

@ -0,0 +1,33 @@
package org.keycloak.models.cache;
import org.keycloak.Config;
import org.keycloak.provider.ProviderSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SimpleCacheKeycloakSessionFactory implements CacheKeycloakSessionFactory {
protected KeycloakCache cache = new SimpleCache();
@Override
public CacheKeycloakSession create(ProviderSession providerSession) {
return new DefaultCacheKeycloakSession(cache, providerSession);
}
@Override
public void init(Config.Scope config) {
config.get("");
}
@Override
public void close() {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
public String getId() {
return "simple";
}
}

View file

@ -0,0 +1,2 @@
org.keycloak.models.cache.SimpleCacheKeycloakSessionFactory
org.keycloak.models.cache.NoCacheKeycloakSessionFactory

View file

@ -0,0 +1 @@
org.keycloak.models.cache.CacheKeycloakSessionSpi

View file

@ -35,6 +35,12 @@
<artifactId>keycloak-model-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-invalidation-cache-model</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>

View file

@ -131,7 +131,7 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
@Override
public boolean removeRole(RoleModel roleModel) {
RoleAdapter roleAdapter = (RoleAdapter)roleModel;
if (roleAdapter == null) {
if (roleModel == null) {
return false;
}
if (!roleAdapter.getContainer().equals(this)) return false;
@ -142,13 +142,13 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
applicationEntity.getRoles().remove(role);
applicationEntity.getDefaultRoles().remove(role);
em.createNativeQuery("delete from CompositeRole where role = :role").setParameter("role", role).executeUpdate();
em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", role).executeUpdate();
em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", role).executeUpdate();
role.setApplication(null);
em.flush();
em.remove(role);
em.flush();
return true;
}
@ -244,12 +244,18 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
em.flush();
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (o == this) return true;
if (!(o instanceof ApplicationAdapter)) return false;
ApplicationAdapter app = (ApplicationAdapter)o;
return app.getId().equals(getId());
if (this == o) return true;
if (o == null || !(o instanceof ApplicationModel)) return false;
ApplicationModel that = (ApplicationModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
public String toString() {

View file

@ -204,6 +204,7 @@ public abstract class ClientAdapter implements ClientModel {
Set<RoleModel> roles = new HashSet<RoleModel>();
for (ScopeMappingEntity entity : entities) {
roles.add(new RoleAdapter(realm, em, entity.getRole()));
em.detach(entity);
}
return roles;
}
@ -215,6 +216,8 @@ public abstract class ClientAdapter implements ClientModel {
entity.setClient(getEntity());
entity.setRole(((RoleAdapter) role).getRole());
em.persist(entity);
em.flush();
em.detach(entity);
}
@Override

View file

@ -1,5 +1,6 @@
package org.keycloak.models.jpa;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
@ -37,4 +38,19 @@ public class OAuthClientAdapter extends ClientAdapter implements OAuthClientMode
public void setDirectGrantsOnly(boolean flag) {
oAuthClientEntity.setDirectGrantsOnly(flag);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof OAuthClientModel)) return false;
OAuthClientModel that = (OAuthClientModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -1001,11 +1001,18 @@ public class RealmAdapter implements RealmModel {
em.flush();
}
@Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof RealmAdapter)) return false;
RealmAdapter r = (RealmAdapter) o;
return r.getId().equals(getId());
if (this == o) return true;
if (o == null || !(o instanceof RealmModel)) return false;
RealmModel that = (RealmModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
@Override

View file

@ -1,5 +1,6 @@
package org.keycloak.models.jpa;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
@ -115,17 +116,14 @@ public class RoleAdapter implements RoleModel {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (o == null || !(o instanceof RoleModel)) return false;
RoleAdapter that = (RoleAdapter) o;
if (!role.getId().equals(that.role.getId())) return false;
return true;
RoleModel that = (RoleModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return role.getId().hashCode();
return getId().hashCode();
}
}

View file

@ -282,6 +282,7 @@ public class UserAdapter implements UserModel {
entity.setRole(roleEntity);
em.persist(entity);
em.flush();
em.detach(entity);
}
@Override
@ -307,6 +308,7 @@ public class UserAdapter implements UserModel {
Set<RoleModel> roles = new HashSet<RoleModel>();
for (UserRoleMappingEntity entity : entities) {
roles.add(realm.getRoleById(entity.getRole().getId()));
em.detach(entity);
}
return roles;
}
@ -359,5 +361,20 @@ public class UserAdapter implements UserModel {
em.flush();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof UserModel)) return false;
UserModel that = (UserModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -117,10 +117,10 @@ public class UserSessionAdapter implements UserSessionModel {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (o == null || !(o instanceof UserSessionModel)) return false;
UserSessionAdapter that = (UserSessionAdapter) o;
return that.getId().equals(this.getId());
UserSessionModel that = (UserSessionModel) o;
return that.getId().equals(getId());
}
@Override

View file

@ -38,7 +38,7 @@ public abstract class ClientEntity {
private int notBefore;
private boolean publicClient;
@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "realm")
protected RealmEntity realm;

View file

@ -1,6 +1,7 @@
package org.keycloak.models.jpa.entities;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@ -28,7 +29,7 @@ public class CredentialEntity {
protected String device;
protected byte[] salt;
@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
protected UserEntity user;
public String getValue() {

View file

@ -3,6 +3,7 @@ package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@ -23,9 +24,9 @@ public class ScopeMappingEntity {
@GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator")
@GeneratedValue(generator = "keycloak_generator")
protected String id;
@ManyToOne
@ManyToOne(fetch= FetchType.LAZY)
protected ClientEntity client;
@ManyToOne
@ManyToOne(fetch= FetchType.LAZY)
protected RoleEntity role;
public String getId() {

View file

@ -1,6 +1,7 @@
package org.keycloak.models.jpa.entities;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@ -25,10 +26,10 @@ public class SocialLinkEntity {
@GeneratedValue(generator = "keycloak_generator")
private String id;
@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
private UserEntity user;
@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
protected RealmEntity realm;
protected String socialProvider;

View file

@ -8,6 +8,7 @@ import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
@ -57,7 +58,7 @@ public class UserEntity {
protected int notBefore;
@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "realm")
protected RealmEntity realm;

View file

@ -1,6 +1,7 @@
package org.keycloak.models.jpa.entities;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
@ -26,7 +27,7 @@ public class UsernameLoginFailureEntity {
protected String lastIPFailure;
@ManyToOne
@ManyToOne(fetch = FetchType.LAZY)
protected RealmEntity realm;
public String getId() {

View file

@ -37,6 +37,12 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-invalidation-cache-model</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>

View file

@ -8,6 +8,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
@ -204,4 +205,19 @@ public class ApplicationAdapter extends ClientAdapter<MongoApplicationEntity> im
updateMongoEntity();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof ApplicationModel)) return false;
ApplicationModel that = (ApplicationModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -1,5 +1,6 @@
package org.keycloak.models.mongo.keycloak.adapters;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
@ -30,4 +31,19 @@ public class OAuthClientAdapter extends ClientAdapter<MongoOAuthClientEntity> im
public void setDirectGrantsOnly(boolean flag) {
getMongoEntity().setDirectGrantsOnly(flag);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof OAuthClientModel)) return false;
OAuthClientModel that = (OAuthClientModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -1059,4 +1059,19 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
this.session.removeExpiredUserSessions(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof RealmModel)) return false;
RealmModel that = (RealmModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -145,4 +145,19 @@ public class RoleAdapter extends AbstractMongoAdapter<MongoRoleEntity> implement
public MongoRoleEntity getMongoEntity() {
return role;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof RoleModel)) return false;
RoleModel that = (RoleModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -351,14 +351,17 @@ public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implement
getMongoStore().updateEntity(user, invocationContext);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || !(o instanceof UserModel)) return false;
UserModel that = (UserModel) o;
return that.getId().equals(getId());
}
@Override
public int hashCode() {
return getId().hashCode();
}
}

View file

@ -126,4 +126,19 @@ public class UserSessionAdapter extends AbstractMongoAdapter<MongoUserSessionEnt
public void removeAssociatedClient(ClientModel client) {
getMongoStore().pullItemFromList(entity, "associatedClientIds", client.getId(), invocationContext);
}
@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();
}
}

View file

@ -26,10 +26,10 @@
</build>
<modules>
<module>api</module>
<module>invalidation-cache</module>
<!-- <module>picketlink</module> -->
<module>jpa</module>
<module>mongo</module>
<module>invalidation-cache</module>
<module>tests</module>
</modules>
</project>

View file

@ -33,6 +33,12 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-invalidation-cache-model</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authentication-api</artifactId>

View file

@ -14,6 +14,8 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.Config;
import org.keycloak.models.cache.CacheKeycloakSession;
import org.keycloak.models.cache.SimpleCache;
import org.keycloak.provider.ProviderSession;
import org.keycloak.provider.ProviderSessionFactory;
import org.keycloak.representations.idm.RealmRepresentation;
@ -38,7 +40,7 @@ public class AbstractModelTest {
providerSessionFactory = KeycloakApplication.createProviderSessionFactory();
ProviderSession providerSession = providerSessionFactory.createSession();
KeycloakSession identitySession = providerSession.getProvider(KeycloakSession.class);
KeycloakSession identitySession = providerSession.getProvider(CacheKeycloakSession.class, "simple");
try {
identitySession.getTransaction().begin();
new ApplianceBootstrap().bootstrap(identitySession, "/auth");
@ -57,7 +59,7 @@ public class AbstractModelTest {
public void before() throws Exception {
providerSession = providerSessionFactory.createSession();
identitySession = providerSession.getProvider(KeycloakSession.class);
identitySession = providerSession.getProvider(CacheKeycloakSession.class, "simple");
identitySession.getTransaction().begin();
realmManager = new RealmManager(identitySession);
}
@ -68,7 +70,7 @@ public class AbstractModelTest {
providerSession.close();
providerSession = providerSessionFactory.createSession();
identitySession = providerSession.getProvider(KeycloakSession.class);
identitySession = providerSession.getProvider(CacheKeycloakSession.class, "simple");
try {
identitySession.getTransaction().begin();
@ -103,7 +105,7 @@ public class AbstractModelTest {
providerSession.close();
providerSession = providerSessionFactory.createSession();
identitySession = providerSession.getProvider(KeycloakSession.class);
identitySession = providerSession.getProvider(CacheKeycloakSession.class, "simple");
identitySession.getTransaction().begin();
realmManager = new RealmManager(identitySession);
}

View file

@ -51,7 +51,8 @@ public class ApplicationModelTest extends AbstractModelTest {
public void persist() {
RealmModel persisted = realmManager.getRealm(realm.getId());
assertEquals(application, persisted.getApplicationNameMap().get("app-name"));
ApplicationModel actual = persisted.getApplicationNameMap().get("app-name");
assertEquals(application, actual);
}
@Test

View file

@ -40,7 +40,7 @@ public class AuthProvidersExternalModelTest extends AbstractModelTest {
@Before
@Override
public void before() throws Exception {
public void before() throws Exception {
super.before();
// Create 2 realms and user in realm1

View file

@ -47,6 +47,11 @@
<artifactId>keycloak-model-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-invalidation-cache-model</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-jpa</artifactId>

View file

@ -7,6 +7,10 @@
"provider": "jpa"
},
"modelCache": {
"provider": "${keycloak.model.cache.provider:simple}"
},
"timer": {
"provider": "basic"
},

View file

@ -42,6 +42,11 @@
<artifactId>keycloak-model-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-invalidation-cache-model</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-jpa</artifactId>

View file

@ -14,6 +14,10 @@
"provider": "jpa"
},
"modelCache": {
"provider": "${keycloak.model.cache.provider:simple}"
},
"timer": {
"provider": "basic"
},

View file

@ -67,6 +67,18 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-invalidation-cache-model</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authentication-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-social-core</artifactId>

View file

@ -2,8 +2,8 @@ package org.keycloak.services.filters;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.cache.CacheKeycloakSession;
import org.keycloak.provider.ProviderSession;
import org.keycloak.provider.ProviderSessionFactory;
@ -33,7 +33,7 @@ public class KeycloakSessionServletFilter implements Filter {
HttpServletRequest request = (HttpServletRequest)servletRequest;
ResteasyProviderFactory.pushContext(ProviderSession.class, providerSession);
KeycloakSession session = providerSession.getProvider(KeycloakSession.class);
KeycloakSession session = providerSession.getProvider(CacheKeycloakSession.class);
ResteasyProviderFactory.pushContext(KeycloakSession.class, session);
KeycloakTransaction tx = session.getTransaction();
ResteasyProviderFactory.pushContext(KeycloakTransaction.class, tx);

View file

@ -125,6 +125,11 @@
<artifactId>keycloak-model-jpa</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-invalidation-cache-model</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-timer-api</artifactId>

View file

@ -23,6 +23,10 @@
}
},
"modelCache": {
"provider": "${keycloak.model.cache.provider:simple}"
},
"timer": {
"provider": "basic"
},

View file

@ -366,7 +366,7 @@ public class AccountTest {
@Test
public void viewLog() {
keycloakRule.configure(new KeycloakSetup() {
keycloakRule.update(new KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setAuditEnabled(true);
@ -413,7 +413,7 @@ public class AccountTest {
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
keycloakRule.configure(new KeycloakSetup() {
keycloakRule.update(new KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setAuditEnabled(false);

View file

@ -33,6 +33,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.cache.CacheKeycloakSession;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.adapters.action.SessionStats;
@ -186,11 +187,12 @@ public class AdapterTest {
System.out.println(pageSource);
Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
ProviderSession providerSession = keycloakRule.startSession();
RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
KeycloakSession keycloakSession = keycloakRule.startCacheSession();
RealmModel realm = keycloakSession.getRealmByName("demo");
int originalIdle = realm.getSsoSessionIdleTimeout();
realm.setSsoSessionIdleTimeout(1);
keycloakRule.stopSession(providerSession, true);
keycloakSession.getTransaction().commit();
keycloakSession.close();
Thread.sleep(2000);
@ -199,10 +201,11 @@ public class AdapterTest {
driver.navigate().to("http://localhost:8081/product-portal");
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
providerSession = keycloakRule.startSession();
realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
keycloakSession = keycloakRule.startCacheSession();
realm = keycloakSession.getRealmByName("demo");
realm.setSsoSessionIdleTimeout(originalIdle);
keycloakRule.stopSession(providerSession, true);
keycloakSession.getTransaction().commit();
keycloakSession.close();
}
@Test
@ -218,27 +221,30 @@ public class AdapterTest {
System.out.println(pageSource);
Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
ProviderSession providerSession = keycloakRule.startSession();
RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
KeycloakSession keycloakSession = keycloakRule.startCacheSession();
RealmModel realm = keycloakSession.getRealmByName("demo");
int originalIdle = realm.getSsoSessionIdleTimeout();
realm.setSsoSessionIdleTimeout(1);
keycloakRule.stopSession(providerSession, true);
keycloakSession.getTransaction().commit();
keycloakSession.close();
Thread.sleep(2000);
providerSession = keycloakRule.startSession();
realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
keycloakSession = keycloakRule.startCacheSession();
realm = keycloakSession.getRealmByName("demo");
realm.removeExpiredUserSessions();
keycloakRule.stopSession(providerSession, true);
keycloakSession.getTransaction().commit();
keycloakSession.close();
// test SSO
driver.navigate().to("http://localhost:8081/product-portal");
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
providerSession = keycloakRule.startSession();
realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
keycloakSession = keycloakRule.startCacheSession();
realm = keycloakSession.getRealmByName("demo");
realm.setSsoSessionIdleTimeout(originalIdle);
keycloakRule.stopSession(providerSession, true);
keycloakSession.getTransaction().commit();
keycloakSession.close();
}
@Test
@ -254,11 +260,12 @@ public class AdapterTest {
System.out.println(pageSource);
Assert.assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
ProviderSession providerSession = keycloakRule.startSession();
RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
KeycloakSession keycloakSession = keycloakRule.startCacheSession();
RealmModel realm = keycloakSession.getRealmByName("demo");
int original = realm.getSsoSessionMaxLifespan();
realm.setSsoSessionMaxLifespan(1);
keycloakRule.stopSession(providerSession, true);
keycloakSession.getTransaction().commit();
keycloakSession.close();
Thread.sleep(2000);
@ -267,9 +274,10 @@ public class AdapterTest {
driver.navigate().to("http://localhost:8081/product-portal");
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
providerSession = keycloakRule.startSession();
realm = providerSession.getProvider(KeycloakSession.class).getRealmByName("demo");
keycloakSession = keycloakRule.startCacheSession();
realm = keycloakSession.getRealmByName("demo");
realm.setSsoSessionMaxLifespan(original);
keycloakRule.stopSession(providerSession, true);
keycloakSession.getTransaction().commit();
keycloakSession.close();
}
}

View file

@ -150,7 +150,7 @@ public class AuthProvidersIntegrationTest {
@Test
public void passwordChangeExternalModel() {
// Set password-policy for admin realm
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
adminstrationRealm.setPasswordPolicy(new PasswordPolicy("length(6)"));
@ -174,7 +174,7 @@ public class AuthProvidersIntegrationTest {
Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
} finally {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
adminstrationRealm.setPasswordPolicy(new PasswordPolicy(null));

View file

@ -184,7 +184,7 @@ public class ResetPasswordTest {
@Test
public void resetPasswordWithPasswordPolicy() throws IOException, MessagingException {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setPasswordPolicy(new PasswordPolicy("length"));

View file

@ -85,7 +85,7 @@ public class AuthorizationCodeTest {
@Test
public void authorizationRequestInstalledApp() throws IOException {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationNameMap().get("test-app").addRedirectUri(Constants.INSTALLED_APP_URN);
@ -104,7 +104,7 @@ public class AuthorizationCodeTest {
String codeId = events.expectLogin().detail(Details.REDIRECT_URI, Constants.INSTALLED_APP_URN).assertEvent().getDetails().get(Details.CODE_ID);
Assert.assertEquals(codeId, new JWSInput(code).readContentAsString());
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationNameMap().get("test-app").removeRedirectUri(Constants.INSTALLED_APP_URN);
@ -114,7 +114,7 @@ public class AuthorizationCodeTest {
@Test
public void authorizationRequestInstalledAppCancel() throws IOException {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationNameMap().get("test-app").addRedirectUri(Constants.INSTALLED_APP_URN);
@ -133,7 +133,7 @@ public class AuthorizationCodeTest {
events.expectLogin().error("rejected_by_user").user((String) null).session((String) null).removeDetail(Details.USERNAME).removeDetail(Details.CODE_ID).detail(Details.REDIRECT_URI, Constants.INSTALLED_APP_URN).assertEvent().getDetails().get(Details.CODE_ID);
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationNameMap().get("test-app").removeRedirectUri(Constants.INSTALLED_APP_URN);
@ -143,7 +143,7 @@ public class AuthorizationCodeTest {
@Test
public void authorizationValidRedirectUri() throws IOException {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationByName("test-app").addRedirectUri(oauth.getRedirectUri());

View file

@ -90,7 +90,7 @@ public class OAuthRedirectUriTest {
@Test
public void testNoParamMultipleValidUris() throws IOException {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationNameMap().get("test-app").addRedirectUri("http://localhost:8081/app2");
@ -104,7 +104,7 @@ public class OAuthRedirectUriTest {
Assert.assertTrue(errorPage.isCurrent());
Assert.assertEquals("Invalid redirect_uri.", errorPage.getError());
} finally {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationNameMap().get("test-app").removeRedirectUri("http://localhost:8081/app2");
@ -115,7 +115,7 @@ public class OAuthRedirectUriTest {
@Test
public void testNoParamNoValidUris() throws IOException {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationNameMap().get("test-app").removeRedirectUri("http://localhost:8081/app/*");
@ -129,7 +129,7 @@ public class OAuthRedirectUriTest {
Assert.assertTrue(errorPage.isCurrent());
Assert.assertEquals("Invalid redirect_uri.", errorPage.getError());
} finally {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationNameMap().get("test-app").addRedirectUri("http://localhost:8081/app/*");
@ -140,7 +140,7 @@ public class OAuthRedirectUriTest {
@Test
public void testNoValidUris() throws IOException {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationNameMap().get("test-app").removeRedirectUri("http://localhost:8081/app/*");
@ -154,7 +154,7 @@ public class OAuthRedirectUriTest {
Assert.assertTrue(errorPage.isCurrent());
Assert.assertEquals("Invalid redirect_uri.", errorPage.getError());
} finally {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.getApplicationNameMap().get("test-app").addRedirectUri("http://localhost:8081/app/*");

View file

@ -183,11 +183,12 @@ public class RefreshTokenTest {
String refreshId = oauth.verifyRefreshToken(tokenResponse.getRefreshToken()).getId();
ProviderSession session = keycloakRule.startSession();
RealmModel realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
KeycloakSession session = keycloakRule.startCacheSession();
RealmModel realm = session.getRealmByName("test");
UserSessionModel userSession = realm.getUserSession(sessionId);
int last = userSession.getLastSessionRefresh();
keycloakRule.stopSession(session, false);
session.getTransaction().commit();
session.close();
Thread.sleep(2000);
@ -198,40 +199,44 @@ public class RefreshTokenTest {
Assert.assertEquals(200, tokenResponse.getStatusCode());
session = keycloakRule.startSession();
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
session = keycloakRule.startCacheSession();
realm = session.getRealmByName("test");
userSession = realm.getUserSession(sessionId);
int next = userSession.getLastSessionRefresh();
keycloakRule.stopSession(session, false);
session.getTransaction().commit();
session.close();
// should not update last refresh because the access token interval is way less than idle timeout
Assert.assertEquals(last, next);
session = keycloakRule.startSession();
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
session = keycloakRule.startCacheSession();
realm = session.getRealmByName("test");
int lastAccessTokenLifespan = realm.getAccessTokenLifespan();
realm.setAccessTokenLifespan(100000);
keycloakRule.stopSession(session, true);
session.getTransaction().commit();
session.close();
Thread.sleep(2000);
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "password");
session = keycloakRule.startSession();
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
session = keycloakRule.startCacheSession();
realm = session.getRealmByName("test");
userSession = realm.getUserSession(sessionId);
next = userSession.getLastSessionRefresh();
keycloakRule.stopSession(session, false);
session.getTransaction().commit();
session.close();
// lastSEssionRefresh should be updated because access code lifespan is higher than sso idle timeout
Assert.assertThat(next, allOf(greaterThan(last), lessThan(last + 6)));
session = keycloakRule.startSession();
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
session = keycloakRule.startCacheSession();
realm = session.getRealmByName("test");
int originalIdle = realm.getSsoSessionIdleTimeout();
realm.setSsoSessionIdleTimeout(1);
keycloakRule.stopSession(session, true);
session.getTransaction().commit();
session.close();
events.clear();
Thread.sleep(2000);
@ -244,11 +249,12 @@ public class RefreshTokenTest {
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);
session = keycloakRule.startSession();
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
session = keycloakRule.startCacheSession();
realm = session.getRealmByName("test");
realm.setSsoSessionIdleTimeout(originalIdle);
realm.setAccessTokenLifespan(lastAccessTokenLifespan);
keycloakRule.stopSession(session, true);
session.getTransaction().commit();
session.close();
events.clear();
}
@ -268,11 +274,12 @@ public class RefreshTokenTest {
String refreshId = oauth.verifyRefreshToken(tokenResponse.getRefreshToken()).getId();
ProviderSession session = keycloakRule.startSession();
RealmModel realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
KeycloakSession session = keycloakRule.startCacheSession();
RealmModel realm = session.getRealmByName("test");
int maxLifespan = realm.getSsoSessionMaxLifespan();
realm.setSsoSessionMaxLifespan(1);
keycloakRule.stopSession(session, true);
session.getTransaction().commit();
session.close();
Thread.sleep(1000);
@ -282,10 +289,11 @@ public class RefreshTokenTest {
assertNull(tokenResponse.getAccessToken());
assertNull(tokenResponse.getRefreshToken());
session = keycloakRule.startSession();
realm = session.getProvider(KeycloakSession.class).getRealmByName("test");
session = keycloakRule.startCacheSession();
realm = session.getRealmByName("test");
realm.setSsoSessionMaxLifespan(maxLifespan);
keycloakRule.stopSession(session, true);
session.getTransaction().commit();
session.close();
events.expectRefresh(refreshId, sessionId).error(Errors.INVALID_TOKEN);

View file

@ -85,7 +85,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
@Test
public void grantAccessTokenNotEnabled() throws Exception {
try {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setPasswordCredentialGrantAllowed(false);
@ -100,7 +100,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
assertEquals("not_enabled", response.getError());
} finally {
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setPasswordCredentialGrantAllowed(true);

View file

@ -238,6 +238,7 @@ public class AccessTokenPerfTest {
JaxrsClientLogin login = new JaxrsClientLogin();
long start = System.currentTimeMillis();
for (int i = 0; i < ITERATIONS; i++) {
//System.out.println("*************************");
login.run();
}
long end = System.currentTimeMillis() - start;

View file

@ -10,6 +10,7 @@ import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.cache.CacheKeycloakSession;
import org.keycloak.provider.ProviderSession;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
@ -143,6 +144,13 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
return providerSession;
}
public KeycloakSession startCacheSession() {
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
KeycloakSession session = providerSession.getProvider(CacheKeycloakSession.class);
session.getTransaction().begin();
return session;
}
public void stopSession(ProviderSession session, boolean commit) {
if (commit) {
session.getProvider(KeycloakSession.class).getTransaction().commit();

View file

@ -25,6 +25,7 @@ import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.cache.CacheKeycloakSession;
import org.keycloak.provider.ProviderSession;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.ApplicationServlet;
@ -80,6 +81,27 @@ public class KeycloakRule extends AbstractKeycloakRule {
}
}
public void update(KeycloakSetup configurer) {
ProviderSession providerSession = server.getProviderSessionFactory().createSession();
KeycloakSession session = providerSession.getProvider(CacheKeycloakSession.class);
session.getTransaction().begin();
try {
RealmManager manager = new RealmManager(session);
RealmModel adminstrationRealm = manager.getRealm(Config.getAdminRealm());
RealmModel appRealm = manager.getRealm("test");
configurer.providerSession = providerSession;
configurer.config(manager, adminstrationRealm, appRealm);
session.getTransaction().commit();
} finally {
providerSession.close();
}
}
public void removeUserSession(String sessionId) {
ProviderSession providerSession = startSession();
RealmModel realm = providerSession.getProvider(KeycloakSession.class).getRealm("test");