Merge pull request #524 from patriot1burke/master

user provider split
This commit is contained in:
Bill Burke 2014-07-15 15:45:30 -04:00
commit e4b3007ce2
213 changed files with 2101 additions and 2043 deletions

View file

@ -7,7 +7,7 @@ import org.keycloak.audit.EventType;
import org.keycloak.email.EmailException;
import org.keycloak.email.EmailProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
@ -21,13 +21,13 @@ public class EmailAuditListener implements AuditListener {
private static final Logger log = Logger.getLogger(EmailAuditListener.class);
private KeycloakSession session;
private ModelProvider model;
private RealmProvider model;
private EmailProvider emailProvider;
private Set<EventType> includedEvents;
public EmailAuditListener(KeycloakSession session, EmailProvider emailProvider, Set<EventType> includedEvents) {
this.session = session;
this.model = session.model();
this.model = session.realms();
this.emailProvider = emailProvider;
this.includedEvents = includedEvents;
}
@ -37,7 +37,7 @@ public class EmailAuditListener implements AuditListener {
if (includedEvents.contains(event.getEvent())) {
if (event.getRealmId() != null && event.getUserId() != null) {
RealmModel realm = model.getRealm(event.getRealmId());
UserModel user = realm.getUserById(event.getUserId());
UserModel user = session.users().getUserById(event.getUserId(), realm);
if (user != null && user.getEmail() != null && user.isEmailVerified()) {
try {
emailProvider.setRealm(realm).setUser(user).sendEvent(event);

View file

@ -3,6 +3,7 @@ package org.keycloak.authentication.model;
import java.util.Map;
import org.jboss.logging.Logger;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
@ -22,17 +23,23 @@ public abstract class AbstractModelAuthenticationProvider implements Authenticat
private static final Logger logger = Logger.getLogger(AbstractModelAuthenticationProvider.class);
protected KeycloakSession keycloakSession;
protected AbstractModelAuthenticationProvider(KeycloakSession keycloakSession) {
this.keycloakSession = keycloakSession;
}
@Override
public AuthUser getUser(RealmModel currentRealm, Map<String, String> config, String username) throws AuthenticationProviderException {
RealmModel realm = getRealm(currentRealm, config);
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(realm, username);
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(keycloakSession, realm, username);
return user == null ? null : createAuthenticatedUserInstance(user);
}
@Override
public String registerUser(RealmModel currentRealm, Map<String, String> config, UserModel user) throws AuthenticationProviderException {
RealmModel realm = getRealm(currentRealm, config);
UserModel newUser = realm.addUser(user.getUsername());
UserModel newUser = keycloakSession.users().addUser(realm, user.getUsername());
newUser.setFirstName(user.getFirstName());
newUser.setLastName(user.getLastName());
newUser.setEmail(user.getEmail());
@ -43,7 +50,7 @@ public abstract class AbstractModelAuthenticationProvider implements Authenticat
@Override
public AuthProviderStatus validatePassword(RealmModel currentRealm, Map<String, String> config, String username, String password) throws AuthenticationProviderException {
RealmModel realm = getRealm(currentRealm, config);
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(realm, username);
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(keycloakSession, realm, username);
boolean result = realm.validatePassword(user, password);
return result ? AuthProviderStatus.SUCCESS : AuthProviderStatus.INVALID_CREDENTIALS;
@ -59,7 +66,7 @@ public abstract class AbstractModelAuthenticationProvider implements Authenticat
throw new AuthenticationProviderException(error);
}
UserModel user = realm.getUser(username);
UserModel user = keycloakSession.users().getUserByUsername(username, realm);
if (user == null) {
logger.warnf("User '%s' doesn't exists. Skip password update", username);
return false;

View file

@ -3,7 +3,6 @@ package org.keycloak.authentication.model;
import org.keycloak.authentication.AuthProviderConstants;
import org.keycloak.authentication.AuthenticationProviderException;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.RealmModel;
import java.util.Arrays;
@ -17,10 +16,9 @@ import java.util.Map;
*/
public class ExternalModelAuthenticationProvider extends AbstractModelAuthenticationProvider {
private ModelProvider model;
public ExternalModelAuthenticationProvider(KeycloakSession session) {
this.model = session.model();
super(session);
}
@Override
@ -40,7 +38,7 @@ public class ExternalModelAuthenticationProvider extends AbstractModelAuthentica
throw new AuthenticationProviderException("Option '" + AuthProviderConstants.EXTERNAL_REALM_ID + "' not specified in configuration");
}
RealmModel realm = model.getRealm(realmId);
RealmModel realm = keycloakSession.realms().getRealm(realmId);
if (realm == null) {
throw new AuthenticationProviderException("Realm with id '" + realmId + "' doesn't exists");
}

View file

@ -4,6 +4,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.authentication.AuthProviderConstants;
@ -14,6 +15,10 @@ import org.keycloak.authentication.AuthProviderConstants;
*/
public class ModelAuthenticationProvider extends AbstractModelAuthenticationProvider {
public ModelAuthenticationProvider(KeycloakSession keycloakSession) {
super(keycloakSession);
}
@Override
public String getName() {
return AuthProviderConstants.PROVIDER_NAME_MODEL;

View file

@ -13,7 +13,7 @@ public class ModelAuthenticationProviderFactory implements AuthenticationProvide
@Override
public AuthenticationProvider create(KeycloakSession session) {
return new ModelAuthenticationProvider();
return new ModelAuthenticationProvider(session);
}
@Override

View file

@ -22,6 +22,7 @@ import org.keycloak.exportimport.Strategy;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.AuthenticationLinkModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
@ -47,7 +48,7 @@ import org.keycloak.representations.idm.UserRepresentation;
*/
public class ExportUtils {
public static RealmRepresentation exportRealm(RealmModel realm, boolean includeUsers) {
public static RealmRepresentation exportRealm(KeycloakSession session, RealmModel realm, boolean includeUsers) {
RealmRepresentation rep = ModelToRepresentation.toRepresentation(realm);
// Audit
@ -147,10 +148,10 @@ public class ExportUtils {
// Finally users if needed
if (includeUsers) {
List<UserModel> allUsers = realm.getUsers();
List<UserModel> allUsers = session.users().getUsers(realm);
List<UserRepresentation> users = new ArrayList<UserRepresentation>();
for (UserModel user : allUsers) {
UserRepresentation userRep = exportUser(realm, user);
UserRepresentation userRep = exportUser(session, realm, user);
users.add(userRep);
}
@ -251,7 +252,7 @@ public class ExportUtils {
* @param user
* @return fully exported user representation
*/
public static UserRepresentation exportUser(RealmModel realm, UserModel user) {
public static UserRepresentation exportUser(KeycloakSession session, RealmModel realm, UserModel user) {
UserRepresentation userRep = ModelToRepresentation.toRepresentation(user);
// AuthenticationLink
@ -262,7 +263,7 @@ public class ExportUtils {
}
// Social links
Set<SocialLinkModel> socialLinks = realm.getSocialLinks(user);
Set<SocialLinkModel> socialLinks = session.users().getSocialLinks(user, realm);
List<SocialLinkRepresentation> socialLinkReps = new ArrayList<SocialLinkRepresentation>();
for (SocialLinkModel socialLink : socialLinks) {
SocialLinkRepresentation socialLinkRep = exportSocialLink(socialLink);
@ -338,7 +339,7 @@ public class ExportUtils {
// Streaming API
public static void exportUsersToStream(RealmModel realm, List<UserModel> usersToExport, ObjectMapper mapper, OutputStream os) throws IOException {
public static void exportUsersToStream(KeycloakSession session, RealmModel realm, List<UserModel> usersToExport, ObjectMapper mapper, OutputStream os) throws IOException {
JsonFactory factory = mapper.getJsonFactory();
JsonGenerator generator = factory.createJsonGenerator(os, JsonEncoding.UTF8);
try {
@ -352,7 +353,7 @@ public class ExportUtils {
generator.writeStartArray();
for (UserModel user : usersToExport) {
UserRepresentation userRep = ExportUtils.exportUser(realm, user);
UserRepresentation userRep = ExportUtils.exportUser(session, realm, user);
generator.writeObject(userRep);
}

View file

@ -2,17 +2,13 @@ package org.keycloak.exportimport.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.io.SerializedString;
import org.codehaus.jackson.map.ObjectMapper;
import org.jboss.logging.Logger;
import org.keycloak.Config;
@ -20,10 +16,9 @@ import org.keycloak.exportimport.Strategy;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.RealmRepresentation;
@ -46,7 +41,7 @@ public class ImportUtils {
*/
public static RealmModel importRealm(KeycloakSession session, RealmRepresentation rep, Strategy strategy) {
String realmName = rep.getRealm();
ModelProvider model = session.model();
RealmProvider model = session.realms();
RealmModel realm = model.getRealmByName(realmName);
if (realm != null) {
@ -64,7 +59,7 @@ public class ImportUtils {
realm = rep.getId() != null ? model.createRealm(rep.getId(), realmName) : model.createRealm(realmName);
RepresentationToModel.importRealm(rep, realm);
RepresentationToModel.importRealm(session, rep, realm);
refreshMasterAdminApps(model, realm);
@ -72,7 +67,7 @@ public class ImportUtils {
return realm;
}
private static void refreshMasterAdminApps(ModelProvider model, RealmModel realm) {
private static void refreshMasterAdminApps(RealmProvider model, RealmModel realm) {
String adminRealmId = Config.getAdminRealm();
if (adminRealmId.equals(realm.getId())) {
// We just imported master realm. All 'masterAdminApps' need to be refreshed
@ -98,7 +93,7 @@ public class ImportUtils {
}
// TODO: We need method here, so we are able to refresh masterAdmin applications after import. Should be RealmManager moved to model/api instead?
public static void setupMasterAdminManagement(ModelProvider model, RealmModel realm) {
public static void setupMasterAdminManagement(RealmProvider model, RealmModel realm) {
RealmModel adminRealm;
RoleModel adminRole;
@ -160,7 +155,7 @@ public class ImportUtils {
// Assuming that it's invoked inside transaction
public static void importUsersFromStream(KeycloakSession session, String realmName, ObjectMapper mapper, InputStream is) throws IOException {
ModelProvider model = session.model();
RealmProvider model = session.realms();
JsonFactory factory = mapper.getJsonFactory();
JsonParser parser = factory.createJsonParser(is);
try {
@ -188,7 +183,7 @@ public class ImportUtils {
parser.nextToken();
}
importUsers(model, realmName, userReps);
importUsers(session, model, realmName, userReps);
if (parser.getCurrentToken() == JsonToken.END_ARRAY) {
parser.nextToken();
@ -200,11 +195,11 @@ public class ImportUtils {
}
}
private static void importUsers(ModelProvider model, String realmName, List<UserRepresentation> userReps) {
private static void importUsers(KeycloakSession session, RealmProvider model, String realmName, List<UserRepresentation> userReps) {
RealmModel realm = model.getRealmByName(realmName);
Map<String, ApplicationModel> apps = realm.getApplicationNameMap();
for (UserRepresentation user : userReps) {
RepresentationToModel.createUser(realm, user, apps);
RepresentationToModel.createUser(session, realm, user, apps);
}
}

View file

@ -28,7 +28,7 @@ public abstract class MultipleStepsExportProvider implements ExportProvider {
@Override
public void run(KeycloakSession session) {
List<RealmModel> realms = session.model().getRealms();
List<RealmModel> realms = session.realms().getRealms();
holder.realms = realms;
}
@ -49,15 +49,15 @@ public abstract class MultipleStepsExportProvider implements ExportProvider {
@Override
public void run(KeycloakSession session) throws IOException {
RealmModel realm = session.model().getRealmByName(realmName);
RealmRepresentation rep = ExportUtils.exportRealm(realm, exportUsersIntoSameFile);
RealmModel realm = session.realms().getRealmByName(realmName);
RealmRepresentation rep = ExportUtils.exportRealm(session, realm, exportUsersIntoSameFile);
writeRealm(realmName + "-realm.json", rep);
logger.info("Realm '" + realmName + "' - data exported");
// Count total number of users
if (!exportUsersIntoSameFile) {
// TODO: getUsersCount method on model
usersHolder.totalCount = realm.getUsers().size();
usersHolder.totalCount = session.users().getUsers(realm).size();
}
}
@ -81,12 +81,12 @@ public abstract class MultipleStepsExportProvider implements ExportProvider {
@Override
public void run(KeycloakSession session) throws IOException {
RealmModel realm = session.model().getRealmByName(realmName);
RealmModel realm = session.realms().getRealmByName(realmName);
// TODO: pagination
List<UserModel> users = realm.getUsers();
List<UserModel> users = session.users().getUsers(realm);
usersHolder.users = users.subList(usersHolder.currentPageStart, usersHolder.currentPageEnd);
writeUsers(realmName + "-users-" + (usersHolder.currentPageStart / countPerPage) + ".json", realm, usersHolder.users);
writeUsers(realmName + "-users-" + (usersHolder.currentPageStart / countPerPage) + ".json", session, realm, usersHolder.users);
logger.info("Users " + usersHolder.currentPageStart + "-" + usersHolder.currentPageEnd + " exported");
}
@ -100,7 +100,7 @@ public abstract class MultipleStepsExportProvider implements ExportProvider {
protected abstract void writeRealm(String fileName, RealmRepresentation rep) throws IOException;
protected abstract void writeUsers(String fileName, RealmModel realm, List<UserModel> users) throws IOException;
protected abstract void writeUsers(String fileName, KeycloakSession session, RealmModel realm, List<UserModel> users) throws IOException;
public static class RealmsHolder {
List<RealmModel> realms;

View file

@ -7,6 +7,7 @@ import java.util.List;
import org.keycloak.exportimport.util.ExportUtils;
import org.keycloak.exportimport.util.MultipleStepsExportProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.RealmRepresentation;
@ -61,10 +62,10 @@ public class DirExportProvider extends MultipleStepsExportProvider {
}
@Override
protected void writeUsers(String fileName, RealmModel realm, List<UserModel> users) throws IOException {
protected void writeUsers(String fileName, KeycloakSession session, RealmModel realm, List<UserModel> users) throws IOException {
File file = new File(this.rootDirectory, fileName);
FileOutputStream os = new FileOutputStream(file);
ExportUtils.exportUsersToStream(realm, users, JsonSerialization.prettyMapper, os);
ExportUtils.exportUsersToStream(session, realm, users, JsonSerialization.prettyMapper, os);
}
@Override

View file

@ -42,10 +42,10 @@ public class SingleFileExportProvider implements ExportProvider {
@Override
public void run(KeycloakSession session) throws IOException {
List<RealmModel> realms = session.model().getRealms();
List<RealmModel> realms = session.realms().getRealms();
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
for (RealmModel realm : realms) {
reps.add(ExportUtils.exportRealm(realm, true));
reps.add(ExportUtils.exportRealm(session, realm, true));
}
writeToFile(reps);
@ -62,8 +62,8 @@ public class SingleFileExportProvider implements ExportProvider {
@Override
public void run(KeycloakSession session) throws IOException {
RealmModel realm = session.model().getRealmByName(realmName);
RealmRepresentation realmRep = ExportUtils.exportRealm(realm, true);
RealmModel realm = session.realms().getRealmByName(realmName);
RealmRepresentation realmRep = ExportUtils.exportRealm(session, realm, true);
writeToFile(realmRep);
}

View file

@ -12,6 +12,7 @@ import de.idyl.winzipaes.impl.AESEncrypterBC;
import org.jboss.logging.Logger;
import org.keycloak.exportimport.util.ExportUtils;
import org.keycloak.exportimport.util.MultipleStepsExportProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.RealmRepresentation;
@ -53,9 +54,9 @@ public class ZipExportProvider extends MultipleStepsExportProvider {
}
@Override
protected void writeUsers(String fileName, RealmModel realm, List<UserModel> users) throws IOException {
protected void writeUsers(String fileName, KeycloakSession session, RealmModel realm, List<UserModel> users) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ExportUtils.exportUsersToStream(realm, users, JsonSerialization.mapper, stream);
ExportUtils.exportUsersToStream(session, realm, users, JsonSerialization.mapper, stream);
byte[] byteArray = stream.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(byteArray);

View file

@ -124,7 +124,7 @@ public class FreeMarkerAccountProvider implements AccountProvider {
attributes.put("totp", new TotpBean(user, baseUri));
break;
case SOCIAL:
attributes.put("social", new AccountSocialBean(realm, user, uriInfo.getBaseUri()));
attributes.put("social", new AccountSocialBean(session, realm, user, uriInfo.getBaseUri()));
break;
case LOG:
attributes.put("log", new LogBean(events));

View file

@ -8,6 +8,7 @@ import java.util.Set;
import javax.ws.rs.core.UriBuilder;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel;
@ -22,13 +23,15 @@ public class AccountSocialBean {
private final List<SocialLinkEntry> socialLinks;
private final boolean removeLinkPossible;
private final KeycloakSession session;
public AccountSocialBean(RealmModel realm, UserModel user, URI baseUri) {
public AccountSocialBean(KeycloakSession session, RealmModel realm, UserModel user, URI baseUri) {
this.session = session;
URI accountSocialUpdateUri = Urls.accountSocialUpdate(baseUri, realm.getName());
this.socialLinks = new LinkedList<SocialLinkEntry>();
Map<String, String> socialConfig = realm.getSocialConfig();
Set<SocialLinkModel> userSocialLinks = realm.getSocialLinks(user);
Set<SocialLinkModel> userSocialLinks = session.users().getSocialLinks(user, realm);
int availableLinks = 0;
if (socialConfig != null && !socialConfig.isEmpty()) {

View file

@ -1,6 +1,5 @@
package org.keycloak.models;
import java.util.List;
import java.util.Set;
/**

View file

@ -2,8 +2,6 @@ package org.keycloak.models;
import org.keycloak.provider.Provider;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@ -29,7 +27,7 @@ public interface KeycloakSession {
* @return
* @throws IllegalStateException if transaction is not active
*/
ModelProvider model();
RealmProvider realms();
/**
* Returns a managed provider instance. Will start a provider transaction. This transaction is managed by the KeycloakSession
@ -42,4 +40,5 @@ public interface KeycloakSession {
void close();
UserProvider users();
}

View file

@ -1,39 +0,0 @@
package org.keycloak.models;
import org.keycloak.provider.Provider;
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 interface ModelProvider extends Provider {
// Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
RealmModel createRealm(String name);
RealmModel createRealm(String id, String name);
RealmModel getRealm(String id);
RealmModel getRealmByName(String name);
UserModel getUserById(String id, RealmModel realm);
UserModel getUserByUsername(String username, RealmModel realm);
UserModel getUserByEmail(String email, RealmModel realm);
UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm);
List<UserModel> getUsers(RealmModel realm);
List<UserModel> searchForUser(String search, RealmModel realm);
List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm);
Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm);
SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm);
RoleModel getRoleById(String id, RealmModel realm);
ApplicationModel getApplicationById(String id, RealmModel realm);
OAuthClientModel getOAuthClientById(String id, RealmModel realm);
List<RealmModel> getRealms();
boolean removeRealm(String id);
void close();
}

View file

@ -110,18 +110,6 @@ public interface RealmModel extends RoleContainerModel {
boolean validateTOTP(UserModel user, String password, String token);
UserModel getUser(String name);
UserModel getUserByEmail(String email);
UserModel getUserById(String name);
UserModel addUser(String id, String username, boolean addDefaultRoles);
UserModel addUser(String username);
boolean removeUser(String name);
RoleModel getRoleById(String id);
List<String> getDefaultRoles();
@ -147,16 +135,6 @@ public interface RealmModel extends RoleContainerModel {
void updateRequiredCredentials(Set<String> creds);
UserModel getUserBySocialLink(SocialLinkModel socialLink);
Set<SocialLinkModel> getSocialLinks(UserModel user);
SocialLinkModel getSocialLink(UserModel user, String socialProvider);
void addSocialLink(UserModel user, SocialLinkModel socialLink);
boolean removeSocialLink(UserModel user, String socialProvider);
boolean isSocial();
void setSocial(boolean social);
@ -165,12 +143,6 @@ public interface RealmModel extends RoleContainerModel {
void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin);
List<UserModel> getUsers();
List<UserModel> searchForUser(String search);
List<UserModel> searchForUserByAttributes(Map<String, String> attributes);
OAuthClientModel addOAuthClient(String name);
OAuthClientModel addOAuthClient(String id, String name);

View file

@ -0,0 +1,26 @@
package org.keycloak.models;
import org.keycloak.provider.Provider;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface RealmProvider extends Provider {
// Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
RealmModel createRealm(String name);
RealmModel createRealm(String id, String name);
RealmModel getRealm(String id);
RealmModel getRealmByName(String name);
RoleModel getRoleById(String id, RealmModel realm);
ApplicationModel getApplicationById(String id, RealmModel realm);
OAuthClientModel getOAuthClientById(String id, RealmModel realm);
List<RealmModel> getRealms();
boolean removeRealm(String id);
void close();
}

View file

@ -6,5 +6,5 @@ import org.keycloak.provider.ProviderFactory;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface ModelProviderFactory extends ProviderFactory<ModelProvider> {
public interface RealmProviderFactory extends ProviderFactory<RealmProvider> {
}

View file

@ -7,21 +7,21 @@ import org.keycloak.provider.Spi;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class ModelSpi implements Spi {
public class RealmSpi implements Spi {
@Override
public String getName() {
return "model";
return "realm";
}
@Override
public Class<? extends Provider> getProviderClass() {
return ModelProvider.class;
return RealmProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return ModelProviderFactory.class;
return RealmProviderFactory.class;
}
}

View file

@ -1,6 +1,5 @@
package org.keycloak.models;
import java.util.List;
import java.util.Set;
/**

View file

@ -1,8 +1,5 @@
package org.keycloak.models;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $

View file

@ -13,12 +13,13 @@ import java.util.Set;
public interface UserProvider extends Provider {
// Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
KeycloakTransaction getTransaction();
UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles);
UserModel addUser(RealmModel realm, String username);
boolean removeUser(RealmModel realm, String name);
public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink);
public boolean removeSocialLink(RealmModel realm, UserModel user, String socialProvider);
UserModel getUserById(String id, RealmModel realm);
UserModel getUserByUsername(String username, RealmModel realm);
UserModel getUserByEmail(String email, RealmModel realm);

View file

@ -1,7 +1,6 @@
package org.keycloak.models;
import java.util.List;
import java.util.Set;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>

View file

@ -3,8 +3,6 @@ package org.keycloak.models;
import org.keycloak.provider.Provider;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>

View file

@ -0,0 +1,27 @@
package org.keycloak.models;
import org.keycloak.provider.Provider;
import org.keycloak.provider.ProviderFactory;
import org.keycloak.provider.Spi;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class UserSpi implements Spi {
@Override
public String getName() {
return "user";
}
@Override
public Class<? extends Provider> getProviderClass() {
return UserProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return UserProviderFactory.class;
}
}

View file

@ -1,11 +1,11 @@
package org.keycloak.models.entities;
import org.keycloak.models.UserModel;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.keycloak.models.UserModel;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/

View file

@ -1,5 +1,15 @@
package org.keycloak.models.utils;
import org.bouncycastle.openssl.PEMWriter;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.util.PemUtils;
import java.io.IOException;
import java.io.StringWriter;
import java.security.Key;
@ -10,16 +20,6 @@ import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import org.bouncycastle.openssl.PEMWriter;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel;
import org.keycloak.util.PemUtils;
/**
* Set of helper methods, which are useful in various model implementations.
@ -122,10 +122,10 @@ public final class KeycloakModelUtils {
* @param username username or email of user
* @return found user
*/
public static UserModel findUserByNameOrEmail(RealmModel realm, String username) {
UserModel user = realm.getUser(username);
public static UserModel findUserByNameOrEmail(KeycloakSession session, RealmModel realm, String username) {
UserModel user = session.users().getUserByUsername(username, realm);
if (user == null && username.contains("@")) {
user = realm.getUserByEmail(username);
user = session.users().getUserByEmail(username, realm);
}
return user;
}

View file

@ -1,15 +1,5 @@
package org.keycloak.models.utils;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.iharder.Base64;
import org.jboss.logging.Logger;
import org.keycloak.models.ApplicationModel;
@ -17,6 +7,7 @@ import org.keycloak.models.AuthenticationLinkModel;
import org.keycloak.models.AuthenticationProviderModel;
import org.keycloak.models.ClaimMask;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
@ -37,11 +28,21 @@ import org.keycloak.representations.idm.ScopeMappingRepresentation;
import org.keycloak.representations.idm.SocialLinkRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class RepresentationToModel {
private static Logger logger = Logger.getLogger(RepresentationToModel.class);
public static void importRealm(RealmRepresentation rep, RealmModel newRealm) {
public static void importRealm(KeycloakSession session, RealmRepresentation rep, RealmModel newRealm) {
newRealm.setName(rep.getRealm());
if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial());
@ -210,7 +211,7 @@ public class RepresentationToModel {
if (rep.getUsers() != null) {
for (UserRepresentation userRep : rep.getUsers()) {
UserModel user = createUser(newRealm, userRep, appMap);
UserModel user = createUser(session, newRealm, userRep, appMap);
}
}
}
@ -571,8 +572,8 @@ public class RepresentationToModel {
// Users
public static UserModel createUser(RealmModel newRealm, UserRepresentation userRep, Map<String, ApplicationModel> appMap) {
UserModel user = newRealm.addUser(userRep.getId(), userRep.getUsername(), false);
public static UserModel createUser(KeycloakSession session, RealmModel newRealm, UserRepresentation userRep, Map<String, ApplicationModel> appMap) {
UserModel user = session.users().addUser(newRealm, userRep.getId(), userRep.getUsername(), false);
user.setEnabled(userRep.isEnabled());
user.setEmail(userRep.getEmail());
user.setFirstName(userRep.getFirstName());
@ -600,7 +601,7 @@ public class RepresentationToModel {
if (userRep.getSocialLinks() != null) {
for (SocialLinkRepresentation socialLink : userRep.getSocialLinks()) {
SocialLinkModel mappingModel = new SocialLinkModel(socialLink.getSocialProvider(), socialLink.getSocialUserId(), socialLink.getSocialUsername());
newRealm.addSocialLink(user, mappingModel);
session.users().addSocialLink(newRealm, user, mappingModel);
}
}
if (userRep.getRealmRoles() != null) {

View file

@ -1,7 +1,5 @@
package org.keycloak.models.utils.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
/**

View file

@ -1,6 +1,5 @@
package org.keycloak.models.utils.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**

View file

@ -1,2 +1,3 @@
org.keycloak.models.ModelSpi
org.keycloak.models.RealmSpi
org.keycloak.models.UserSessionSpi
org.keycloak.models.UserSpi

View file

@ -1,15 +1,12 @@
package org.keycloak.models.hybrid;
import org.keycloak.models.realms.Application;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.realms.Application;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**

View file

@ -3,7 +3,6 @@ package org.keycloak.models.hybrid;
import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.realms.Client;
import java.util.Set;

View file

@ -1,7 +1,6 @@
package org.keycloak.models.hybrid;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.ModelProvider;
@ -10,13 +9,11 @@ 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.realms.RealmProvider;
import org.keycloak.models.sessions.SessionProvider;
import org.keycloak.models.users.UserProvider;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.util.Time;
import java.util.HashSet;
import java.util.List;

View file

@ -1,12 +1,9 @@
package org.keycloak.models.hybrid;
import org.keycloak.Config;
import org.keycloak.models.realms.RealmProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.ModelProviderFactory;
import org.keycloak.models.sessions.SessionProvider;
import org.keycloak.models.users.UserProvider;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>

View file

@ -1,11 +1,5 @@
package org.keycloak.models.hybrid;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.realms.Application;
import org.keycloak.models.realms.Client;
import org.keycloak.models.realms.OAuthClient;
import org.keycloak.models.realms.Realm;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.AuthenticationProviderModel;
import org.keycloak.models.ClientModel;
@ -15,9 +9,14 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.realms.Application;
import org.keycloak.models.realms.Client;
import org.keycloak.models.realms.OAuthClient;
import org.keycloak.models.realms.Realm;
import org.keycloak.models.users.Credentials;
import org.keycloak.models.users.Feature;
import org.keycloak.models.users.User;

View file

@ -1,10 +1,10 @@
package org.keycloak.models.hybrid;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.realms.Application;
import org.keycloak.models.realms.Realm;
import org.keycloak.models.realms.Role;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.HashSet;

View file

@ -3,9 +3,6 @@ package org.keycloak.models.hybrid;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.sessions.LoginFailure;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/

View file

@ -19,7 +19,7 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
protected ApplicationModel updated;
protected CachedApplication cached;
public ApplicationAdapter(RealmModel cachedRealm, CachedApplication cached, CacheModelProvider cacheSession, KeycloakCache cache) {
public ApplicationAdapter(RealmModel cachedRealm, CachedApplication cached, CacheRealmProvider cacheSession, RealmCache cache) {
super(cachedRealm, cached, cache, cacheSession);
this.cached = cached;
}

View file

@ -1,13 +1,13 @@
package org.keycloak.models.cache;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.RealmProvider;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface CacheModelProvider extends ModelProvider {
ModelProvider getDelegate();
public interface CacheRealmProvider extends RealmProvider {
RealmProvider getDelegate();
void registerRealmInvalidation(String id);

View file

@ -6,6 +6,6 @@ import org.keycloak.provider.ProviderFactory;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface CacheModelProviderFactory extends ProviderFactory<CacheModelProvider> {
public interface CacheRealmProviderFactory extends ProviderFactory<CacheRealmProvider> {
}

View file

@ -8,20 +8,20 @@ import org.keycloak.provider.Spi;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CacheModelProviderSpi implements Spi {
public class CacheRealmProviderSpi implements Spi {
@Override
public String getName() {
return "modelCache";
return "realmCache";
}
@Override
public Class<? extends Provider> getProviderClass() {
return CacheModelProvider.class;
return CacheRealmProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return CacheModelProviderFactory.class;
return CacheRealmProviderFactory.class;
}
}

View file

@ -0,0 +1,14 @@
package org.keycloak.models.cache;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserProvider;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface CacheUserProvider extends UserProvider {
UserProvider getDelegate();
void registerUserInvalidation(RealmModel realm, String id);
}

View file

@ -0,0 +1,11 @@
package org.keycloak.models.cache;
import org.keycloak.provider.ProviderFactory;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface CacheUserProviderFactory extends ProviderFactory<CacheUserProvider> {
}

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 CacheUserProviderSpi implements Spi {
@Override
public String getName() {
return "userCache";
}
@Override
public Class<? extends Provider> getProviderClass() {
return CacheUserProvider.class;
}
@Override
public Class<? extends ProviderFactory> getProviderFactoryClass() {
return CacheUserProviderFactory.class;
}
}

View file

@ -4,7 +4,6 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.cache.entities.CachedClient;
import java.util.HashSet;
@ -16,12 +15,12 @@ import java.util.Set;
*/
public abstract class ClientAdapter implements ClientModel {
protected CachedClient cachedClient;
protected CacheModelProvider cacheSession;
protected CacheRealmProvider cacheSession;
protected ClientModel updatedClient;
protected RealmModel cachedRealm;
protected KeycloakCache cache;
protected RealmCache cache;
public ClientAdapter(RealmModel cachedRealm, CachedClient cached, KeycloakCache cache, CacheModelProvider cacheSession) {
public ClientAdapter(RealmModel cachedRealm, CachedClient cached, RealmCache cache, CacheRealmProvider cacheSession) {
this.cachedRealm = cachedRealm;
this.cache = cache;
this.cacheSession = cacheSession;

View file

@ -1,24 +1,19 @@
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.ModelProvider;
import org.keycloak.models.RealmProvider;
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.models.cache.entities.CachedUser;
import java.util.HashMap;
import java.util.HashSet;
@ -30,10 +25,10 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class DefaultCacheModelProvider implements CacheModelProvider {
protected KeycloakCache cache;
public class DefaultCacheRealmProvider implements CacheRealmProvider {
protected RealmCache cache;
protected KeycloakSession session;
protected ModelProvider delegate;
protected RealmProvider delegate;
protected boolean transactionActive;
protected boolean setRollbackOnly;
@ -50,7 +45,7 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
protected boolean clearAll;
public DefaultCacheModelProvider(KeycloakCache cache, KeycloakSession session) {
public DefaultCacheRealmProvider(RealmCache cache, KeycloakSession session) {
this.cache = cache;
this.session = session;
@ -58,10 +53,10 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
}
@Override
public ModelProvider getDelegate() {
public RealmProvider getDelegate() {
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
if (delegate != null) return delegate;
delegate = session.getProvider(ModelProvider.class);
delegate = session.getProvider(RealmProvider.class);
return delegate;
}
@ -103,10 +98,6 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
for (String id : clientInvalidations) {
cache.invalidateCachedOAuthClientById(id);
}
for (String id : userInvalidations) {
cache.invalidateCachedUserById(id);
}
}
private KeycloakTransaction getTransaction() {
@ -200,63 +191,6 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
return adapter;
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
CachedUser cached = cache.getCachedUser(id);
if (cached == null) {
UserModel model = getDelegate().getUserById(id, realm);
if (model == null) return null;
if (userInvalidations.contains(id)) return model;
cached = new CachedUser(realm, model);
cache.addCachedUser(cached);
} else if (userInvalidations.contains(id)) {
return getDelegate().getUserById(id, realm);
} else if (managedUsers.containsKey(id)) {
return managedUsers.get(id);
}
UserAdapter adapter = new UserAdapter(cached, cache, this, realm);
managedUsers.put(id, adapter);
return adapter;
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
CachedUser cached = cache.getCachedUserByUsername(username, realm);
if (cached == null) {
UserModel model = getDelegate().getUserByUsername(username, realm);
if (model == null) return null;
if (userInvalidations.contains(model.getId())) return model;
cached = new CachedUser(realm, model);
cache.addCachedUser(cached);
} else if (userInvalidations.contains(cached.getId())) {
return getDelegate().getUserById(cached.getId(), realm);
} else if (managedUsers.containsKey(cached.getId())) {
return managedUsers.get(cached.getId());
}
UserAdapter adapter = new UserAdapter(cached, cache, this, realm);
managedUsers.put(cached.getId(), adapter);
return adapter;
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
CachedUser cached = cache.getCachedUserByEmail(email, realm);
if (cached == null) {
UserModel model = getDelegate().getUserByEmail(email, realm);
if (model == null) return null;
if (userInvalidations.contains(model.getId())) return model;
cached = new CachedUser(realm, model);
cache.addCachedUser(cached);
} else if (userInvalidations.contains(cached.getId())) {
return getDelegate().getUserByEmail(email, realm);
} else if (managedUsers.containsKey(cached.getId())) {
return managedUsers.get(cached.getId());
}
UserAdapter adapter = new UserAdapter(cached, cache, this, realm);
managedUsers.put(cached.getId(), adapter);
return adapter;
}
@Override
public List<RealmModel> getRealms() {
// we don't cache this for now
@ -291,36 +225,6 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
if (delegate != null) delegate.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);

View file

@ -0,0 +1,244 @@
package org.keycloak.models.cache;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.cache.entities.CachedUser;
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 DefaultCacheUserProvider implements CacheUserProvider {
protected UserCache cache;
protected KeycloakSession session;
protected UserProvider delegate;
protected boolean transactionActive;
protected boolean setRollbackOnly;
protected Map<String, String> userInvalidations = new HashMap<String, String>();
protected Set<String> realmInvalidations = new HashSet<String>();
protected Map<String, UserModel> managedUsers = new HashMap<String, UserModel>();
protected boolean clearAll;
public DefaultCacheUserProvider(UserCache cache, KeycloakSession session) {
this.cache = cache;
this.session = session;
session.getTransaction().enlistAfterCompletion(getTransaction());
}
@Override
public UserProvider getDelegate() {
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
if (delegate != null) return delegate;
delegate = session.getProvider(UserProvider.class);
return delegate;
}
@Override
public void registerUserInvalidation(RealmModel realm, String id) {
userInvalidations.put(id, realm.getId());
}
protected void runInvalidations() {
for (Map.Entry<String, String> invalidation : userInvalidations.entrySet()) {
cache.invalidateCachedUserById(invalidation.getValue(), invalidation.getKey());
}
for (String realmId : realmInvalidations) {
cache.invalidateRealmUsers(realmId);
}
}
private KeycloakTransaction getTransaction() {
return new KeycloakTransaction() {
@Override
public void begin() {
transactionActive = true;
}
@Override
public void commit() {
if (delegate == null) return;
if (clearAll) {
cache.clear();
}
runInvalidations();
}
@Override
public void rollback() {
setRollbackOnly = true;
runInvalidations();
}
@Override
public void setRollbackOnly() {
setRollbackOnly = true;
}
@Override
public boolean getRollbackOnly() {
return setRollbackOnly;
}
@Override
public boolean isActive() {
return transactionActive;
}
};
}
@Override
public UserModel getUserById(String id, RealmModel realm) {
if (realmInvalidations.contains(realm.getId())) {
return getDelegate().getUserById(id, realm);
}
if (userInvalidations.containsKey(id)) {
return getDelegate().getUserById(id, realm);
}
CachedUser cached = cache.getCachedUser(realm.getId(), id);
if (cached == null) {
UserModel model = getDelegate().getUserById(id, realm);
if (model == null) return null;
if (userInvalidations.containsKey(id)) return model;
cached = new CachedUser(realm, model);
cache.addCachedUser(realm.getId(), cached);
} else if (managedUsers.containsKey(id)) {
return managedUsers.get(id);
}
UserAdapter adapter = new UserAdapter(cached, this, session, realm);
managedUsers.put(id, adapter);
return adapter;
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
if (realmInvalidations.contains(realm.getId())) {
return getDelegate().getUserByUsername(username, realm);
}
CachedUser cached = cache.getCachedUserByUsername(realm.getId(), username);
if (cached == null) {
UserModel model = getDelegate().getUserByUsername(username, realm);
if (model == null) return null;
if (userInvalidations.containsKey(model.getId())) return model;
cached = new CachedUser(realm, model);
cache.addCachedUser(realm.getId(), cached);
} else if (userInvalidations.containsKey(cached.getId())) {
return getDelegate().getUserById(cached.getId(), realm);
} else if (managedUsers.containsKey(cached.getId())) {
return managedUsers.get(cached.getId());
}
UserAdapter adapter = new UserAdapter(cached, this, session, realm);
managedUsers.put(cached.getId(), adapter);
return adapter;
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
if (realmInvalidations.contains(realm.getId())) {
return getDelegate().getUserByEmail(email, realm);
}
CachedUser cached = cache.getCachedUserByEmail(realm.getId(), email);
if (cached == null) {
UserModel model = getDelegate().getUserByEmail(email, realm);
if (model == null) return null;
if (userInvalidations.containsKey(model.getId())) return model;
cached = new CachedUser(realm, model);
cache.addCachedUser(realm.getId(), cached);
} else if (userInvalidations.containsKey(cached.getId())) {
return getDelegate().getUserByEmail(email, realm);
} else if (managedUsers.containsKey(cached.getId())) {
return managedUsers.get(cached.getId());
}
UserAdapter adapter = new UserAdapter(cached, this, session, realm);
managedUsers.put(cached.getId(), adapter);
return adapter;
}
@Override
public void close() {
if (delegate != null) delegate.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 UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles) {
return getDelegate().addUser(realm, id, username, addDefaultRoles);
}
@Override
public UserModel addUser(RealmModel realm, String username) {
return getDelegate().addUser(realm, username);
}
@Override
public boolean removeUser(RealmModel realm, String name) {
UserModel user = getUserByUsername(name, realm);
if (user == null) return false;
registerUserInvalidation(realm, user.getId());
return getDelegate().removeUser(realm, name);
}
@Override
public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink) {
getDelegate().addSocialLink(realm, user, socialLink);
}
@Override
public boolean removeSocialLink(RealmModel realm, UserModel user, String socialProvider) {
return getDelegate().removeSocialLink(realm, user, socialProvider);
}
@Override
public void preRemove(RealmModel realm) {
realmInvalidations.add(realm.getId());
getDelegate().preRemove(realm);
}
@Override
public void preRemove(RoleModel role) {
getDelegate().preRemove(role);
}
}

View file

@ -7,12 +7,12 @@ import org.keycloak.models.KeycloakSession;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class SimpleCacheModelProviderFactory implements CacheModelProviderFactory {
protected KeycloakCache cache = new SimpleCache();
public class MemoryCacheRealmProviderFactory implements CacheRealmProviderFactory {
protected RealmCache cache = new MemoryRealmCache();
@Override
public CacheModelProvider create(KeycloakSession session) {
return new DefaultCacheModelProvider(cache, session);
public CacheRealmProvider create(KeycloakSession session) {
return new DefaultCacheRealmProvider(cache, session);
}
@Override
@ -28,6 +28,6 @@ public class SimpleCacheModelProviderFactory implements CacheModelProviderFactor
@Override
public String getId() {
return "simple";
return "mem";
}
}

View file

@ -0,0 +1,33 @@
package org.keycloak.models.cache;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MemoryCacheUserProviderFactory implements CacheUserProviderFactory {
protected UserCache cache = new MemoryUserCache();
@Override
public CacheUserProvider create(KeycloakSession session) {
return new DefaultCacheUserProvider(cache, session);
}
@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 "mem";
}
}

View file

@ -0,0 +1,125 @@
package org.keycloak.models.cache;
import org.keycloak.models.cache.entities.CachedApplication;
import org.keycloak.models.cache.entities.CachedOAuthClient;
import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRole;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MemoryRealmCache implements RealmCache {
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
public CachedRealm getCachedRealm(String id) {
return realmCache.get(id);
}
@Override
public void invalidateCachedRealm(CachedRealm realm) {
realmCache.remove(realm.getId());
realmCacheByName.remove(realm.getName());
}
@Override
public void invalidateCachedRealmById(String id) {
CachedRealm cached = realmCache.remove(id);
if (cached != null) realmCacheByName.remove(cached.getName());
}
@Override
public void addCachedRealm(CachedRealm realm) {
realmCache.put(realm.getId(), realm);
realmCacheByName.put(realm.getName(), realm);
}
@Override
public CachedRealm getCachedRealmByName(String name) {
return realmCacheByName.get(name);
}
@Override
public CachedApplication getApplication(String id) {
return applicationCache.get(id);
}
@Override
public void invalidateApplication(CachedApplication app) {
applicationCache.remove(app.getId());
}
@Override
public void addCachedApplication(CachedApplication app) {
applicationCache.put(app.getId(), app);
}
@Override
public void invalidateCachedApplicationById(String id) {
applicationCache.remove(id);
}
@Override
public CachedOAuthClient getOAuthClient(String id) {
return clientCache.get(id);
}
@Override
public void invalidateOAuthClient(CachedOAuthClient client) {
clientCache.remove(client.getId());
}
@Override
public void addCachedOAuthClient(CachedOAuthClient client) {
clientCache.put(client.getId(), client);
}
@Override
public void invalidateCachedOAuthClientById(String id) {
clientCache.remove(id);
}
@Override
public CachedRole getRole(String id) {
return roleCache.get(id);
}
@Override
public void invalidateRole(CachedRole role) {
roleCache.remove(role);
}
@Override
public void invalidateRoleById(String id) {
roleCache.remove(id);
}
@Override
public void addCachedRole(CachedRole role) {
roleCache.put(role.getId(), role);
}
@Override
public void invalidateCachedRoleById(String id) {
roleCache.remove(id);
}
}

View file

@ -0,0 +1,143 @@
package org.keycloak.models.cache;
import org.keycloak.models.cache.entities.CachedUser;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class MemoryUserCache implements UserCache {
protected int maxUserCacheSize = 10000;
protected class RealmUsers {
protected class LRUCache extends LinkedHashMap<String, CachedUser> {
public LRUCache() {
super(1000, 1.1F, true);
}
@Override
public CachedUser put(String key, CachedUser value) {
usersByUsername.put(value.getUsername(), value);
if (value.getEmail() != null) {
usersByEmail.put(value.getEmail(), value);
}
return super.put(key, value);
}
@Override
public CachedUser remove(Object key) {
CachedUser user = super.remove(key);
if (user == null) return null;
removeUser(user);
return user;
}
@Override
public void clear() {
super.clear();
usersByUsername.clear();
usersByEmail.clear();
}
@Override
protected boolean removeEldestEntry(Map.Entry<String, CachedUser> eldest) {
boolean evict = size() > maxUserCacheSize;
if (evict) {
removeUser(eldest.getValue());
}
return evict;
}
private void removeUser(CachedUser value) {
usersByUsername.remove(value.getUsername());
if (value.getEmail() != null) usersByEmail.remove(value.getEmail());
}
}
protected Map<String, CachedUser> usersById = Collections.synchronizedMap(new LRUCache());
protected Map<String, CachedUser> usersByUsername = new ConcurrentHashMap<String, CachedUser>();
protected Map<String, CachedUser> usersByEmail = new ConcurrentHashMap<String, CachedUser>();
}
protected ConcurrentHashMap<String, RealmUsers> realmUsers = new ConcurrentHashMap<String, RealmUsers>();
public int getMaxUserCacheSize() {
return maxUserCacheSize;
}
public void setMaxUserCacheSize(int maxUserCacheSize) {
this.maxUserCacheSize = maxUserCacheSize;
}
@Override
public CachedUser getCachedUser(String realmId, String id) {
if (realmId == null || id == null) return null;
RealmUsers users = realmUsers.get(realmId);
if (users == null) return null;
return users.usersById.get(id);
}
@Override
public void invalidateCachedUser(String realmId, CachedUser user) {
RealmUsers users = realmUsers.get(realmId);
if (users == null) return;
users.usersById.remove(user.getId());
}
@Override
public void invalidateCachedUserById(String realmId, String id) {
RealmUsers users = realmUsers.get(realmId);
if (users == null) return;
users.usersById.remove(id);
}
@Override
public void addCachedUser(String realmId, CachedUser user) {
RealmUsers users = realmUsers.get(realmId);
if (users == null) {
users = new RealmUsers();
realmUsers.put(realmId, users);
}
users.usersById.put(user.getId(), user);
}
@Override
public CachedUser getCachedUserByUsername(String realmId, String name) {
if (realmId == null || name == null) return null;
RealmUsers users = realmUsers.get(realmId);
if (users == null) return null;
CachedUser user = users.usersByUsername.get(name);
if (user == null) return null;
users.usersById.get(user.getId()); // refresh cache entry age
return user;
}
@Override
public CachedUser getCachedUserByEmail(String realmId, String email) {
if (realmId == null || email == null) return null;
RealmUsers users = realmUsers.get(realmId);
if (users == null) return null;
CachedUser user = users.usersByEmail.get(email);
if (user == null) return null;
users.usersById.get(user.getId()); // refresh cache entry age
return user;
}
@Override
public void invalidateRealmUsers(String realmId) {
realmUsers.remove(realmId);
}
@Override
public void clear() {
realmUsers.clear();
}
}

View file

@ -1,42 +1,34 @@
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.ModelProvider;
import org.keycloak.models.RealmProvider;
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 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 NoCacheModelProvider implements CacheModelProvider {
public class NoCacheRealmProvider implements CacheRealmProvider {
protected KeycloakSession session;
protected ModelProvider delegate;
protected RealmProvider delegate;
// protected KeycloakTransaction transactionDelegate;
// protected boolean transactionActive;
// protected boolean setRollbackOnly;
public NoCacheModelProvider(KeycloakSession session) {
public NoCacheRealmProvider(KeycloakSession session) {
this.session = session;
}
@Override
public ModelProvider getDelegate() {
public RealmProvider getDelegate() {
// if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
if (delegate != null) return delegate;
delegate = session.getProvider(ModelProvider.class);
delegate = session.getProvider(RealmProvider.class);
// transactionDelegate = delegate.getTransaction();
// if (!transactionDelegate.isActive()) {
// transactionDelegate.begin();
@ -83,21 +75,6 @@ public class NoCacheModelProvider implements CacheModelProvider {
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
@ -114,36 +91,6 @@ public class NoCacheModelProvider implements CacheModelProvider {
if (delegate != null) delegate.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);

View file

@ -7,10 +7,10 @@ import org.keycloak.models.KeycloakSession;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class NoCacheModelProviderFactory implements CacheModelProviderFactory {
public class NoCacheRealmProviderFactory implements CacheRealmProviderFactory {
@Override
public CacheModelProvider create(KeycloakSession session) {
return new NoCacheModelProvider(session);
public CacheRealmProvider create(KeycloakSession session) {
return new NoCacheRealmProvider(session);
}
@Override

View file

@ -0,0 +1,126 @@
package org.keycloak.models.cache;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
import org.keycloak.models.cache.entities.CachedUser;
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 NoCacheUserProvider implements CacheUserProvider {
protected KeycloakSession session;
protected UserProvider delegate;
public NoCacheUserProvider(KeycloakSession session) {
this.session = session;
}
@Override
public UserProvider getDelegate() {
if (delegate != null) return delegate;
delegate = session.getProvider(UserProvider.class);
return delegate;
}
@Override
public void registerUserInvalidation(RealmModel realm, String id) {
//To change body of implemented methods use File | Settings | File Templates.
}
@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 void close() {
if (delegate != null) delegate.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 UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles) {
return getDelegate().addUser(realm, id, username, addDefaultRoles);
}
@Override
public UserModel addUser(RealmModel realm, String username) {
return getDelegate().addUser(realm, username);
}
@Override
public boolean removeUser(RealmModel realm, String name) {
return getDelegate().removeUser(realm, name);
}
@Override
public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink) {
getDelegate().addSocialLink(realm, user, socialLink);
}
@Override
public boolean removeSocialLink(RealmModel realm, UserModel user, String socialProvider) {
return getDelegate().removeSocialLink(realm, user, socialProvider);
}
@Override
public void preRemove(RealmModel realm) {
getDelegate().preRemove(realm);
}
@Override
public void preRemove(RoleModel role) {
getDelegate().preRemove(role);
}
}

View file

@ -0,0 +1,30 @@
package org.keycloak.models.cache;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class NoCacheUserProviderFactory implements CacheUserProviderFactory {
@Override
public CacheUserProvider create(KeycloakSession session) {
return new NoCacheUserProvider(session);
}
@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

@ -12,7 +12,7 @@ public class OAuthClientAdapter extends ClientAdapter implements OAuthClientMode
protected OAuthClientModel updated;
protected CachedOAuthClient cached;
public OAuthClientAdapter(RealmModel cachedRealm, CachedOAuthClient cached, CacheModelProvider cacheSession, KeycloakCache cache) {
public OAuthClientAdapter(RealmModel cachedRealm, CachedOAuthClient cached, CacheRealmProvider cacheSession, RealmCache cache) {
super(cachedRealm, cached, cache, cacheSession);
this.cached = cached;
}

View file

@ -9,15 +9,11 @@ import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
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.utils.KeycloakModelUtils;
import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
import org.keycloak.models.utils.TimeBasedOTP;
import java.security.PrivateKey;
@ -35,13 +31,13 @@ import java.util.Set;
*/
public class RealmAdapter implements RealmModel {
protected CachedRealm cached;
protected CacheModelProvider cacheSession;
protected CacheRealmProvider cacheSession;
protected RealmModel updated;
protected KeycloakCache cache;
protected RealmCache cache;
protected volatile transient PublicKey publicKey;
protected volatile transient PrivateKey privateKey;
public RealmAdapter(CachedRealm cached, CacheModelProvider cacheSession) {
public RealmAdapter(CachedRealm cached, CacheRealmProvider cacheSession) {
this.cached = cached;
this.cacheSession = cacheSession;
}
@ -395,39 +391,6 @@ public class RealmAdapter implements RealmModel {
return false;
}
@Override
public UserModel getUser(String name) {
return cacheSession.getUserByUsername(name, this);
}
@Override
public UserModel getUserByEmail(String email) {
return cacheSession.getUserByEmail(email, this);
}
@Override
public UserModel getUserById(String id) {
return cacheSession.getUserById(id, this);
}
@Override
public UserModel addUser(String id, String username, boolean addDefaultRoles) {
getDelegateForUpdate();
return updated.addUser(id, username, addDefaultRoles);
}
@Override
public UserModel addUser(String username) {
getDelegateForUpdate();
return updated.addUser(username);
}
@Override
public boolean removeUser(String name) {
getDelegateForUpdate();
return updated.removeUser(name);
}
@Override
public RoleModel getRoleById(String id) {
if (updated != null) return updated.getRoleById(id);
@ -538,36 +501,6 @@ public class RealmAdapter implements RealmModel {
updated.updateRequiredCredentials(creds);
}
@Override
public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
if (updated != null) return updated.getUserBySocialLink(socialLink);
return cacheSession.getUserBySocialLink(socialLink, this);
}
@Override
public Set<SocialLinkModel> getSocialLinks(UserModel user) {
if (updated != null) return updated.getSocialLinks(user);
return cacheSession.getSocialLinks(user, this);
}
@Override
public SocialLinkModel getSocialLink(UserModel user, String socialProvider) {
if (updated != null) return updated.getSocialLink(user, socialProvider);
return cacheSession.getSocialLink(user, socialProvider, this);
}
@Override
public void addSocialLink(UserModel user, SocialLinkModel socialLink) {
getDelegateForUpdate();
updated.addSocialLink(user, socialLink);
}
@Override
public boolean removeSocialLink(UserModel user, String socialProvider) {
getDelegateForUpdate();
return updated.removeSocialLink(user, socialProvider);
}
@Override
public boolean isSocial() {
if (updated != null) return updated.isSocial();
@ -592,24 +525,6 @@ public class RealmAdapter implements RealmModel {
updated.setUpdateProfileOnInitialSocialLogin(updateProfileOnInitialSocialLogin);
}
@Override
public List<UserModel> getUsers() {
if (updated != null) return updated.getUsers();
return cacheSession.getUsers(this);
}
@Override
public List<UserModel> searchForUser(String search) {
if (updated != null) return updated.searchForUser(search);
return cacheSession.searchForUser(search, this);
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes) {
if (updated != null) return updated.searchForUserByAttributes(attributes);
return cacheSession.searchForUserByAttributes(attributes, this);
}
@Override
public OAuthClientModel addOAuthClient(String name) {
getDelegateForUpdate();

View file

@ -1,17 +1,15 @@
package org.keycloak.models.cache;
import org.keycloak.models.RealmModel;
import org.keycloak.models.cache.entities.CachedApplication;
import org.keycloak.models.cache.entities.CachedOAuthClient;
import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRole;
import org.keycloak.models.cache.entities.CachedUser;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface KeycloakCache {
public interface RealmCache {
void clear();
CachedRealm getCachedRealm(String id);
@ -51,16 +49,4 @@ public interface KeycloakCache {
void invalidateRoleById(String id);
CachedUser getCachedUser(String id);
void invalidateCachedUser(CachedUser user);
void addCachedUser(CachedUser user);
CachedUser getCachedUserByUsername(String name, RealmModel realm);
CachedUser getCachedUserByEmail(String name, RealmModel realm);
void invalidedCachedUserById(String id);
void invalidateCachedUserById(String id);
}

View file

@ -19,11 +19,11 @@ public class RoleAdapter implements RoleModel {
protected RoleModel updated;
protected CachedRole cached;
protected KeycloakCache cache;
protected CacheModelProvider cacheSession;
protected RealmCache cache;
protected CacheRealmProvider cacheSession;
protected RealmModel realm;
public RoleAdapter(CachedRole cached, KeycloakCache cache, CacheModelProvider session, RealmModel realm) {
public RoleAdapter(CachedRole cached, RealmCache cache, CacheRealmProvider session, RealmModel realm) {
this.cached = cached;
this.cache = cache;
this.cacheSession = session;

View file

@ -1,246 +0,0 @@
package org.keycloak.models.cache;
import org.keycloak.models.RealmModel;
import org.keycloak.models.cache.entities.CachedApplication;
import org.keycloak.models.cache.entities.CachedOAuthClient;
import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRole;
import org.keycloak.models.cache.entities.CachedUser;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
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>();
protected int maxUserCacheSize = 10000;
protected boolean userCacheEnabled = true;
protected Map<String, CachedUser> usersById = Collections.synchronizedMap(new LRUCache());
protected Map<String, CachedUser> usersByUsername = new ConcurrentHashMap<String, CachedUser>();
protected Map<String, CachedUser> usersByEmail = new ConcurrentHashMap<String, CachedUser>();
protected class LRUCache extends LinkedHashMap<String, CachedUser> {
public LRUCache() {
super(1000, 1.1F, true);
}
@Override
public CachedUser put(String key, CachedUser value) {
usersByUsername.put(value.getUsernameKey(), value);
if (value.getEmail() != null) {
usersByEmail.put(value.getEmailKey(), value);
}
return super.put(key, value);
}
@Override
public CachedUser remove(Object key) {
CachedUser user = super.remove(key);
if (user == null) return null;
removeUser(user);
return user;
}
@Override
public void clear() {
super.clear();
usersByUsername.clear();
usersByEmail.clear();
}
@Override
protected boolean removeEldestEntry(Map.Entry<String, CachedUser> eldest) {
boolean evict = size() > maxUserCacheSize;
if (evict) {
removeUser(eldest.getValue());
}
return evict;
}
private void removeUser(CachedUser value) {
usersByUsername.remove(value.getUsernameKey());
if (value.getEmail() != null) usersByEmail.remove(value.getEmailKey());
}
}
public int getMaxUserCacheSize() {
return maxUserCacheSize;
}
public void setMaxUserCacheSize(int maxUserCacheSize) {
this.maxUserCacheSize = maxUserCacheSize;
}
public boolean isUserCacheEnabled() {
return userCacheEnabled;
}
public void setUserCacheEnabled(boolean userCacheEnabled) {
this.userCacheEnabled = userCacheEnabled;
}
@Override
public CachedUser getCachedUser(String id) {
if (!userCacheEnabled) return null;
return usersById.get(id);
}
@Override
public void invalidateCachedUser(CachedUser user) {
if (!userCacheEnabled) return;
usersById.remove(user.getId());
}
@Override
public void invalidateCachedUserById(String id) {
if (!userCacheEnabled) return;
usersById.remove(id);
}
@Override
public void addCachedUser(CachedUser user) {
if (!userCacheEnabled) return;
usersById.put(user.getId(), user);
}
@Override
public CachedUser getCachedUserByUsername(String name, RealmModel realm) {
if (!userCacheEnabled) return null;
CachedUser user = usersByUsername.get(realm.getId() + "." +name);
if (user == null) return null;
usersById.get(user.getId()); // refresh cache entry age
return user;
}
@Override
public CachedUser getCachedUserByEmail(String name, RealmModel realm) {
if (!userCacheEnabled) return null;
CachedUser user = usersByEmail.get(realm.getId() + "." +name);
if (user == null) return null;
usersById.get(user.getId()); // refresh cache entry age
return user;
}
@Override
public void invalidedCachedUserById(String id) {
if (!userCacheEnabled) return;
usersById.remove(id);
}
@Override
public void clear() {
realmCache.clear();
realmCacheByName.clear();
applicationCache.clear();
clientCache.clear();
roleCache.clear();
usersById.clear();
}
@Override
public CachedRealm getCachedRealm(String id) {
return realmCache.get(id);
}
@Override
public void invalidateCachedRealm(CachedRealm realm) {
realmCache.remove(realm.getId());
realmCacheByName.remove(realm.getName());
}
@Override
public void invalidateCachedRealmById(String id) {
CachedRealm cached = realmCache.remove(id);
if (cached != null) realmCacheByName.remove(cached.getName());
}
@Override
public void addCachedRealm(CachedRealm realm) {
realmCache.put(realm.getId(), realm);
realmCacheByName.put(realm.getName(), realm);
}
@Override
public CachedRealm getCachedRealmByName(String name) {
return realmCacheByName.get(name);
}
@Override
public CachedApplication getApplication(String id) {
return applicationCache.get(id);
}
@Override
public void invalidateApplication(CachedApplication app) {
applicationCache.remove(app.getId());
}
@Override
public void addCachedApplication(CachedApplication app) {
applicationCache.put(app.getId(), app);
}
@Override
public void invalidateCachedApplicationById(String id) {
applicationCache.remove(id);
}
@Override
public CachedOAuthClient getOAuthClient(String id) {
return clientCache.get(id);
}
@Override
public void invalidateOAuthClient(CachedOAuthClient client) {
clientCache.remove(client.getId());
}
@Override
public void addCachedOAuthClient(CachedOAuthClient client) {
clientCache.put(client.getId(), client);
}
@Override
public void invalidateCachedOAuthClientById(String id) {
clientCache.remove(id);
}
@Override
public CachedRole getRole(String id) {
return roleCache.get(id);
}
@Override
public void invalidateRole(CachedRole role) {
roleCache.remove(role.getId());
}
@Override
public void invalidateRoleById(String id) {
roleCache.remove(id);
}
@Override
public void addCachedRole(CachedRole role) {
roleCache.put(role.getId(), role);
}
@Override
public void invalidateCachedRoleById(String id) {
roleCache.remove(id);
}
}

View file

@ -2,6 +2,7 @@ package org.keycloak.models.cache;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.AuthenticationLinkModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
@ -22,21 +23,21 @@ import java.util.Set;
public class UserAdapter implements UserModel {
protected UserModel updated;
protected CachedUser cached;
protected KeycloakCache cache;
protected CacheModelProvider cacheSession;
protected CacheUserProvider userProviderCache;
protected KeycloakSession keycloakSession;
protected RealmModel realm;
public UserAdapter(CachedUser cached, KeycloakCache cache, CacheModelProvider session, RealmModel realm) {
public UserAdapter(CachedUser cached, CacheUserProvider userProvider, KeycloakSession keycloakSession, RealmModel realm) {
this.cached = cached;
this.cache = cache;
this.cacheSession = session;
this.userProviderCache = userProvider;
this.keycloakSession = keycloakSession;
this.realm = realm;
}
protected void getDelegateForUpdate() {
if (updated == null) {
cacheSession.registerUserInvalidation(getId());
updated = cacheSession.getDelegate().getUserById(getId(), realm);
userProviderCache.registerUserInvalidation(realm, getId());
updated = userProviderCache.getDelegate().getUserById(getId(), realm);
if (updated == null) throw new IllegalStateException("Not found in database");
}
}
@ -257,7 +258,13 @@ public class UserAdapter implements UserModel {
if (updated != null) return updated.getRoleMappings();
Set<RoleModel> roles = new HashSet<RoleModel>();
for (String id : cached.getRoleMappings()) {
roles.add(cacheSession.getRoleById(id, realm));
RoleModel roleById = keycloakSession.realms().getRoleById(id, realm);
if (roleById == null) {
// chance that role was removed, so just delete to persistence and get user invalidated
getDelegateForUpdate();
return updated.getRoleMappings();
}
roles.add(roleById);
}
return roles;

View file

@ -0,0 +1,25 @@
package org.keycloak.models.cache;
import org.keycloak.models.cache.entities.CachedUser;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public interface UserCache {
void clear();
CachedUser getCachedUser(String realmId, String id);
void invalidateCachedUser(String realmId, CachedUser user);
void addCachedUser(String realmId, CachedUser user);
CachedUser getCachedUserByUsername(String realmId, String name);
CachedUser getCachedUserByEmail(String realmId, String name);
void invalidateCachedUserById(String realmId, String id);
void invalidateRealmUsers(String realmId);
}

View file

@ -1,21 +1,15 @@
package org.keycloak.models.cache.entities;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.cache.KeycloakCache;
import org.keycloak.models.cache.RealmCache;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -29,7 +23,7 @@ public class CachedApplication extends CachedClient {
private boolean bearerOnly;
private Map<String, String> roles = new HashMap<String, String>();
public CachedApplication(KeycloakCache cache, ModelProvider delegate, RealmModel realm, ApplicationModel model) {
public CachedApplication(RealmCache cache, RealmProvider delegate, RealmModel realm, ApplicationModel model) {
super(cache, delegate, realm, model);
surrogateAuthRequired = model.isSurrogateAuthRequired();
managementUrl = model.getManagementUrl();

View file

@ -1,12 +1,10 @@
package org.keycloak.models.cache.entities;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.cache.KeycloakCache;
import org.keycloak.models.cache.RealmCache;
import java.util.HashSet;
import java.util.Set;
@ -28,7 +26,7 @@ public class CachedClient {
protected Set<String> scope = new HashSet<String>();
protected Set<String> webOrigins = new HashSet<String>();
public CachedClient(KeycloakCache cache, ModelProvider delegate, RealmModel realm, ClientModel model) {
public CachedClient(RealmCache cache, RealmProvider delegate, RealmModel realm, ClientModel model) {
id = model.getId();
secret = model.getSecret();
name = model.getClientId();

View file

@ -1,17 +1,16 @@
package org.keycloak.models.cache.entities;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.cache.KeycloakCache;
import org.keycloak.models.cache.RealmCache;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class CachedOAuthClient extends CachedClient {
public CachedOAuthClient(KeycloakCache cache, ModelProvider delegate, RealmModel realm, OAuthClientModel model) {
public CachedOAuthClient(RealmCache cache, RealmProvider delegate, RealmModel realm, OAuthClientModel model) {
super(cache, delegate, realm, model);
}

View file

@ -2,14 +2,13 @@ package org.keycloak.models.cache.entities;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.AuthenticationProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.cache.KeycloakCache;
import org.keycloak.models.cache.RealmCache;
import java.util.ArrayList;
import java.util.HashMap;
@ -81,7 +80,7 @@ public class CachedRealm {
public CachedRealm() {
}
public CachedRealm(KeycloakCache cache, ModelProvider delegate, RealmModel model) {
public CachedRealm(RealmCache cache, RealmProvider delegate, RealmModel model) {
id = model.getId();
name = model.getName();
enabled = model.isEnabled();

View file

@ -2,9 +2,6 @@ package org.keycloak.models.cache.entities;
import org.keycloak.models.RoleModel;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $

View file

@ -20,11 +20,9 @@ import java.util.Set;
public class CachedUser {
private String id;
private String username;
private String usernameKey;
private String firstName;
private String lastName;
private String email;
private String emailKey;
private boolean emailVerified;
private List<UserCredentialValueModel> credentials = new LinkedList<UserCredentialValueModel>();
private boolean enabled;
@ -38,14 +36,10 @@ public class CachedUser {
public CachedUser(RealmModel realm, UserModel user) {
this.id = user.getId();
this.username = user.getUsername();
this.usernameKey = realm.getId() + "." + this.username;
this.firstName = user.getFirstName();
this.lastName = user.getLastName();
this.attributes.putAll(user.getAttributes());
this.email = user.getEmail();
if (this.email != null) {
this.emailKey = realm.getId() + "." + this.email;
}
this.emailVerified = user.isEmailVerified();
this.credentials.addAll(user.getCredentialsDirectly());
this.enabled = user.isEnabled();
@ -65,14 +59,6 @@ public class CachedUser {
return username;
}
public String getUsernameKey() {
return usernameKey;
}
public String getEmailKey() {
return emailKey;
}
public String getFirstName() {
return firstName;
}

View file

@ -1,2 +0,0 @@
org.keycloak.models.cache.SimpleCacheModelProviderFactory
org.keycloak.models.cache.NoCacheModelProviderFactory

View file

@ -0,0 +1,2 @@
org.keycloak.models.cache.MemoryCacheRealmProviderFactory
org.keycloak.models.cache.NoCacheRealmProviderFactory

View file

@ -0,0 +1,2 @@
org.keycloak.models.cache.MemoryCacheUserProviderFactory
org.keycloak.models.cache.NoCacheUserProviderFactory

View file

@ -1 +1,2 @@
org.keycloak.models.cache.CacheModelProviderSpi
org.keycloak.models.cache.CacheRealmProviderSpi
org.keycloak.models.cache.CacheUserProviderSpi

View file

@ -2,12 +2,13 @@ package org.keycloak.models.jpa;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.jpa.entities.*;
import org.keycloak.models.jpa.entities.ApplicationEntity;
import org.keycloak.models.jpa.entities.RoleEntity;
import org.keycloak.models.jpa.entities.ScopeMappingEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager;
@ -25,10 +26,12 @@ import java.util.Set;
public class ApplicationAdapter extends ClientAdapter implements ApplicationModel {
protected EntityManager em;
protected KeycloakSession session;
protected ApplicationEntity applicationEntity;
public ApplicationAdapter(RealmModel realm, EntityManager em, ApplicationEntity applicationEntity) {
public ApplicationAdapter(RealmModel realm, EntityManager em, KeycloakSession session, ApplicationEntity applicationEntity) {
super(realm, applicationEntity, em);
this.session = session;
this.realm = realm;
this.em = em;
this.applicationEntity = applicationEntity;
@ -135,6 +138,7 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
}
if (!roleModel.getContainer().equals(this)) return false;
session.users().preRemove(roleModel);
RoleEntity role = RoleAdapter.toRoleEntity(roleModel, em);
if (!role.isApplicationRole()) return false;
@ -143,7 +147,6 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
applicationEntity.getDefaultRoles().remove(role);
em.createNativeQuery("delete from CompositeRole where childRole = :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);

View file

@ -1,278 +0,0 @@
package org.keycloak.models.jpa;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.ModelProvider;
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.jpa.entities.ApplicationEntity;
import org.keycloak.models.jpa.entities.OAuthClientEntity;
import org.keycloak.models.jpa.entities.RealmEntity;
import org.keycloak.models.jpa.entities.RoleEntity;
import org.keycloak.models.jpa.entities.SocialLinkEntity;
import org.keycloak.models.jpa.entities.UserEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
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 JpaModelProvider implements ModelProvider {
private final KeycloakSession session;
protected EntityManager em;
public JpaModelProvider(KeycloakSession session, EntityManager em) {
this.session = session;
this.em = em;
}
@Override
public RealmModel createRealm(String name) {
return createRealm(KeycloakModelUtils.generateId(), name);
}
@Override
public RealmModel createRealm(String id, String name) {
RealmEntity realm = new RealmEntity();
realm.setName(name);
realm.setId(id);
em.persist(realm);
em.flush();
return new RealmAdapter(session, em, realm);
}
@Override
public RealmModel getRealm(String id) {
RealmEntity realm = em.find(RealmEntity.class, id);
if (realm == null) return null;
return new RealmAdapter(session, em, realm);
}
@Override
public List<RealmModel> getRealms() {
TypedQuery<RealmEntity> query = em.createNamedQuery("getAllRealms", RealmEntity.class);
List<RealmEntity> entities = query.getResultList();
List<RealmModel> realms = new ArrayList<RealmModel>();
for (RealmEntity entity : entities) {
realms.add(new RealmAdapter(session, em, entity));
}
return realms;
}
@Override
public RealmModel getRealmByName(String name) {
TypedQuery<RealmEntity> query = em.createNamedQuery("getRealmByName", RealmEntity.class);
query.setParameter("name", name);
List<RealmEntity> entities = query.getResultList();
if (entities.size() == 0) return null;
if (entities.size() > 1) throw new IllegalStateException("Should not be more than one realm with same name");
RealmEntity realm = query.getResultList().get(0);
if (realm == null) return null;
return new RealmAdapter(session, em, realm);
}
@Override
public UserModel getUserById(String id, RealmModel realmModel) {
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserById", UserEntity.class);
query.setParameter("id", id);
RealmEntity realm = em.getReference(RealmEntity.class, realmModel.getId());
query.setParameter("realm", realm);
List<UserEntity> entities = query.getResultList();
if (entities.size() == 0) return null;
return new UserAdapter(realmModel, em, entities.get(0));
}
@Override
public UserModel getUserByUsername(String username, RealmModel realmModel) {
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByUsername", UserEntity.class);
query.setParameter("username", username);
RealmEntity realm = em.getReference(RealmEntity.class, realmModel.getId());
query.setParameter("realm", realm);
List<UserEntity> results = query.getResultList();
if (results.size() == 0) return null;
return new UserAdapter(realmModel, em, results.get(0));
}
@Override
public UserModel getUserByEmail(String email, RealmModel realmModel) {
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByEmail", UserEntity.class);
query.setParameter("email", email);
RealmEntity realm = em.getReference(RealmEntity.class, realmModel.getId());
query.setParameter("realm", realm);
List<UserEntity> results = query.getResultList();
return results.isEmpty() ? null : new UserAdapter(realmModel, em, results.get(0));
}
@Override
public boolean removeRealm(String id) {
RealmEntity realm = em.find(RealmEntity.class, id);
if (realm == null) {
return false;
}
RealmAdapter adapter = new RealmAdapter(session, em, realm);
for (ApplicationEntity a : new LinkedList<ApplicationEntity>(realm.getApplications())) {
adapter.removeApplication(a.getId());
}
for (OAuthClientModel oauth : adapter.getOAuthClients()) {
adapter.removeOAuthClient(oauth.getId());
}
for (UserEntity u : em.createQuery("from UserEntity u where u.realm = :realm", UserEntity.class).setParameter("realm", realm).getResultList()) {
adapter.removeUser(u.getUsername());
}
em.remove(realm);
return true;
}
@Override
public void close() {
}
@Override
public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) {
TypedQuery<UserEntity> query = em.createNamedQuery("findUserByLinkAndRealm", UserEntity.class);
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
query.setParameter("realm", realmEntity);
query.setParameter("socialProvider", socialLink.getSocialProvider());
query.setParameter("socialUserId", socialLink.getSocialUserId());
List<UserEntity> results = query.getResultList();
if (results.isEmpty()) {
return null;
} else if (results.size() > 1) {
throw new IllegalStateException("More results found for socialProvider=" + socialLink.getSocialProvider() +
", socialUserId=" + socialLink.getSocialUserId() + ", results=" + results);
} else {
UserEntity user = results.get(0);
return new UserAdapter(realm, em, user);
}
}
@Override
public List<UserModel> getUsers(RealmModel realm) {
TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm", UserEntity.class);
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
query.setParameter("realm", realmEntity);
List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity));
return users;
}
@Override
public List<UserModel> searchForUser(String search, RealmModel realm) {
TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm and ( lower(u.username) like :search or lower(concat(u.firstName, ' ', u.lastName)) like :search or u.email like :search )", UserEntity.class);
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
query.setParameter("realm", realmEntity);
query.setParameter("search", "%" + search.toLowerCase() + "%");
List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity));
return users;
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
StringBuilder builder = new StringBuilder("select u from UserEntity u");
boolean first = true;
for (Map.Entry<String, String> entry : attributes.entrySet()) {
String attribute = null;
if (entry.getKey().equals(UserModel.LOGIN_NAME)) {
attribute = "lower(username)";
} else if (entry.getKey().equalsIgnoreCase(UserModel.FIRST_NAME)) {
attribute = "lower(firstName)";
} else if (entry.getKey().equalsIgnoreCase(UserModel.LAST_NAME)) {
attribute = "lower(lastName)";
} else if (entry.getKey().equalsIgnoreCase(UserModel.EMAIL)) {
attribute = "lower(email)";
}
if (attribute == null) continue;
if (first) {
first = false;
builder.append(" where realm = :realm");
} else {
builder.append(" and ");
}
builder.append(attribute).append(" like '%").append(entry.getValue().toLowerCase()).append("%'");
}
String q = builder.toString();
TypedQuery<UserEntity> query = em.createQuery(q, UserEntity.class);
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
query.setParameter("realm", realmEntity);
List<UserEntity> results = query.getResultList();
List<UserModel> users = new ArrayList<UserModel>();
for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity));
return users;
}
private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
TypedQuery<SocialLinkEntity> query = em.createNamedQuery("findSocialLinkByUserAndProvider", SocialLinkEntity.class);
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
query.setParameter("user", userEntity);
query.setParameter("socialProvider", socialProvider);
List<SocialLinkEntity> results = query.getResultList();
return results.size() > 0 ? results.get(0) : null;
}
@Override
public Set<SocialLinkModel> getSocialLinks(UserModel user, RealmModel realm) {
TypedQuery<SocialLinkEntity> query = em.createNamedQuery("findSocialLinkByUser", SocialLinkEntity.class);
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
query.setParameter("user", userEntity);
List<SocialLinkEntity> results = query.getResultList();
Set<SocialLinkModel> set = new HashSet<SocialLinkModel>();
for (SocialLinkEntity entity : results) {
set.add(new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()));
}
return set;
}
@Override
public SocialLinkModel getSocialLink(UserModel user, String socialProvider, RealmModel realm) {
SocialLinkEntity entity = findSocialLink(user, socialProvider);
return (entity != null) ? new SocialLinkModel(entity.getSocialProvider(), entity.getSocialUserId(), entity.getSocialUsername()) : null;
}
@Override
public RoleModel getRoleById(String id, RealmModel realm) {
RoleEntity entity = em.find(RoleEntity.class, id);
if (entity == null) return null;
if (!realm.getId().equals(entity.getRealmId())) return null;
return new RoleAdapter(realm, em, entity);
}
@Override
public ApplicationModel getApplicationById(String id, RealmModel realm) {
ApplicationEntity app = em.find(ApplicationEntity.class, id);
// Check if application belongs to this realm
if (app == null || !realm.getId().equals(app.getRealm().getId())) return null;
return new ApplicationAdapter(realm, em, app);
}
@Override
public OAuthClientModel getOAuthClientById(String id, RealmModel realm) {
OAuthClientEntity client = em.find(OAuthClientEntity.class, id);
// Check if client belongs to this realm
if (client == null || !realm.getId().equals(client.getRealm().getId())) return null;
return new OAuthClientAdapter(realm, client, em);
}
}

View file

@ -0,0 +1,130 @@
package org.keycloak.models.jpa;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.jpa.entities.ApplicationEntity;
import org.keycloak.models.jpa.entities.OAuthClientEntity;
import org.keycloak.models.jpa.entities.RealmEntity;
import org.keycloak.models.jpa.entities.RoleEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JpaRealmProvider implements RealmProvider {
private final KeycloakSession session;
protected EntityManager em;
public JpaRealmProvider(KeycloakSession session, EntityManager em) {
this.session = session;
this.em = em;
}
@Override
public RealmModel createRealm(String name) {
return createRealm(KeycloakModelUtils.generateId(), name);
}
@Override
public RealmModel createRealm(String id, String name) {
RealmEntity realm = new RealmEntity();
realm.setName(name);
realm.setId(id);
em.persist(realm);
em.flush();
return new RealmAdapter(session, em, realm);
}
@Override
public RealmModel getRealm(String id) {
RealmEntity realm = em.find(RealmEntity.class, id);
if (realm == null) return null;
return new RealmAdapter(session, em, realm);
}
@Override
public List<RealmModel> getRealms() {
TypedQuery<RealmEntity> query = em.createNamedQuery("getAllRealms", RealmEntity.class);
List<RealmEntity> entities = query.getResultList();
List<RealmModel> realms = new ArrayList<RealmModel>();
for (RealmEntity entity : entities) {
realms.add(new RealmAdapter(session, em, entity));
}
return realms;
}
@Override
public RealmModel getRealmByName(String name) {
TypedQuery<RealmEntity> query = em.createNamedQuery("getRealmByName", RealmEntity.class);
query.setParameter("name", name);
List<RealmEntity> entities = query.getResultList();
if (entities.size() == 0) return null;
if (entities.size() > 1) throw new IllegalStateException("Should not be more than one realm with same name");
RealmEntity realm = query.getResultList().get(0);
if (realm == null) return null;
return new RealmAdapter(session, em, realm);
}
@Override
public boolean removeRealm(String id) {
RealmEntity realm = em.find(RealmEntity.class, id);
if (realm == null) {
return false;
}
RealmAdapter adapter = new RealmAdapter(session, em, realm);
session.users().preRemove(adapter);
for (ApplicationEntity a : new LinkedList<ApplicationEntity>(realm.getApplications())) {
adapter.removeApplication(a.getId());
}
for (OAuthClientModel oauth : adapter.getOAuthClients()) {
adapter.removeOAuthClient(oauth.getId());
}
em.remove(realm);
return true;
}
@Override
public void close() {
}
@Override
public RoleModel getRoleById(String id, RealmModel realm) {
RoleEntity entity = em.find(RoleEntity.class, id);
if (entity == null) return null;
if (!realm.getId().equals(entity.getRealmId())) return null;
return new RoleAdapter(realm, em, entity);
}
@Override
public ApplicationModel getApplicationById(String id, RealmModel realm) {
ApplicationEntity app = em.find(ApplicationEntity.class, id);
// Check if application belongs to this realm
if (app == null || !realm.getId().equals(app.getRealm().getId())) return null;
return new ApplicationAdapter(realm, em, session, app);
}
@Override
public OAuthClientModel getOAuthClientById(String id, RealmModel realm) {
OAuthClientEntity client = em.find(OAuthClientEntity.class, id);
// Check if client belongs to this realm
if (client == null || !realm.getId().equals(client.getRealm().getId())) return null;
return new OAuthClientAdapter(realm, client, em);
}
}

View file

@ -3,8 +3,8 @@ package org.keycloak.models.jpa;
import org.keycloak.Config;
import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.ModelProviderFactory;
import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmProviderFactory;
import javax.persistence.EntityManager;
@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JpaModelProviderFactory implements ModelProviderFactory {
public class JpaRealmProviderFactory implements RealmProviderFactory {
@Override
public void init(Config.Scope config) {
@ -24,9 +24,9 @@ public class JpaModelProviderFactory implements ModelProviderFactory {
}
@Override
public ModelProvider create(KeycloakSession session) {
public RealmProvider create(KeycloakSession session) {
EntityManager em = session.getProvider(JpaConnectionProvider.class).getEntityManager();
return new JpaModelProvider(session, em);
return new JpaRealmProvider(session, em);
}
@Override

View file

@ -2,16 +2,11 @@ package org.keycloak.models.jpa;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.ModelProvider;
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.UserProvider;
import org.keycloak.models.jpa.entities.ApplicationEntity;
import org.keycloak.models.jpa.entities.OAuthClientEntity;
import org.keycloak.models.jpa.entities.RealmEntity;
import org.keycloak.models.jpa.entities.RoleEntity;
import org.keycloak.models.jpa.entities.SocialLinkEntity;
@ -23,7 +18,6 @@ import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -39,7 +33,6 @@ public class JpaUserProvider implements UserProvider {
public JpaUserProvider(KeycloakSession session, EntityManager em) {
this.session = session;
this.em = em;
this.em = PersistenceExceptionConverter.create(em);
}
@Override
@ -99,12 +92,38 @@ public class JpaUserProvider implements UserProvider {
}
@Override
public void preRemove(RealmModel realm) {
TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm", UserEntity.class);
public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink) {
SocialLinkEntity entity = new SocialLinkEntity();
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
query.setParameter("realm", realmEntity);
for (UserEntity u : query.getResultList()) {
em.remove(u);
entity.setRealm(realmEntity);
entity.setSocialProvider(socialLink.getSocialProvider());
entity.setSocialUserId(socialLink.getSocialUserId());
entity.setSocialUsername(socialLink.getSocialUsername());
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
entity.setUser(userEntity);
em.persist(entity);
em.flush();
}
@Override
public boolean removeSocialLink(RealmModel realm, UserModel user, String socialProvider) {
SocialLinkEntity entity = findSocialLink(user, socialProvider);
if (entity != null) {
em.remove(entity);
em.flush();
return true;
} else {
return false;
}
}
@Override
public void preRemove(RealmModel realm) {
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
for (UserEntity u : em.createQuery("from UserEntity u where u.realm = :realm", UserEntity.class).setParameter("realm", realmEntity).getResultList()) {
removeUser(realm, u.getUsername());
}
}
@ -114,12 +133,6 @@ public class JpaUserProvider implements UserProvider {
em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate();
}
@Override
public KeycloakTransaction getTransaction() {
return new JpaKeycloakTransaction(em);
}
@Override
public UserModel getUserById(String id, RealmModel realmModel) {
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserById", UserEntity.class);
@ -154,8 +167,6 @@ public class JpaUserProvider implements UserProvider {
@Override
public void close() {
if (em.getTransaction().isActive()) em.getTransaction().rollback();
if (em.isOpen()) em.close();
}
@Override

View file

@ -0,0 +1,36 @@
package org.keycloak.models.jpa;
import org.keycloak.Config;
import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.UserProvider;
import org.keycloak.models.UserProviderFactory;
import javax.persistence.EntityManager;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class JpaUserProviderFactory implements UserProviderFactory {
@Override
public void init(Config.Scope config) {
}
@Override
public String getId() {
return "jpa";
}
@Override
public UserProvider create(KeycloakSession session) {
EntityManager em = session.getProvider(JpaConnectionProvider.class).getEntityManager();
return new JpaUserProvider(session, em);
}
@Override
public void close() {
}
}

View file

@ -1,14 +1,10 @@
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;
import org.keycloak.models.jpa.entities.OAuthClientEntity;
import javax.persistence.EntityManager;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>

View file

@ -1,12 +1,11 @@
package org.keycloak.models.jpa;
import org.hibernate.exception.ConstraintViolationException;
import org.keycloak.models.ModelException;
import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

View file

@ -10,11 +10,9 @@ import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.jpa.entities.ApplicationEntity;
import org.keycloak.models.jpa.entities.AuthenticationProviderEntity;
import org.keycloak.models.jpa.entities.OAuthClientEntity;
@ -22,9 +20,6 @@ import org.keycloak.models.jpa.entities.RealmEntity;
import org.keycloak.models.jpa.entities.RequiredCredentialEntity;
import org.keycloak.models.jpa.entities.RoleEntity;
import org.keycloak.models.jpa.entities.ScopeMappingEntity;
import org.keycloak.models.jpa.entities.SocialLinkEntity;
import org.keycloak.models.jpa.entities.UserEntity;
import org.keycloak.models.jpa.entities.UserRoleMappingEntity;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.TimeBasedOTP;
@ -411,75 +406,6 @@ public class RealmAdapter implements RealmModel {
}
@Override
public UserModel getUser(String name) {
return session.model().getUserByUsername(name, this);
}
@Override
public UserModel getUserByEmail(String email) {
return session.model().getUserByEmail(email, this);
}
@Override
public UserModel getUserById(String id) {
return session.model().getUserById(id, this);
}
@Override
public UserModel addUser(String username) {
return this.addUser(KeycloakModelUtils.generateId(), username, true);
}
@Override
public UserModel addUser(String id, String username, boolean addDefaultRoles) {
if (id == null) {
id = KeycloakModelUtils.generateId();
}
UserEntity entity = new UserEntity();
entity.setId(id);
entity.setUsername(username);
entity.setRealm(realm);
em.persist(entity);
em.flush();
UserModel userModel = new UserAdapter(this, em, entity);
if (addDefaultRoles) {
for (String r : getDefaultRoles()) {
userModel.grantRole(getRole(r));
}
for (ApplicationModel application : getApplications()) {
for (String r : application.getDefaultRoles()) {
userModel.grantRole(application.getRole(r));
}
}
}
return userModel;
}
@Override
public boolean removeUser(String name) {
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByUsername", UserEntity.class);
query.setParameter("username", name);
query.setParameter("realm", realm);
List<UserEntity> results = query.getResultList();
if (results.size() == 0) return false;
removeUser(results.get(0));
return true;
}
private void removeUser(UserEntity user) {
em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where user = :user").setParameter("user", user).executeUpdate();
em.createQuery("delete from " + SocialLinkEntity.class.getSimpleName() + " where user = :user").setParameter("user", user).executeUpdate();
if (user.getAuthenticationLink() != null) {
em.remove(user.getAuthenticationLink());
}
em.remove(user);
}
@Override
public List<String> getDefaultRoles() {
Collection<RoleEntity> entities = realm.getDefaultRoles();
@ -567,7 +493,7 @@ public class RealmAdapter implements RealmModel {
List<ApplicationModel> list = new ArrayList<ApplicationModel>();
if (realm.getApplications() == null) return list;
for (ApplicationEntity entity : realm.getApplications()) {
list.add(new ApplicationAdapter(this, em, entity));
list.add(new ApplicationAdapter(this, em, session, entity));
}
return list;
}
@ -587,7 +513,7 @@ public class RealmAdapter implements RealmModel {
realm.getApplications().add(applicationData);
em.persist(applicationData);
em.flush();
ApplicationModel resource = new ApplicationAdapter(this, em, applicationData);
ApplicationModel resource = new ApplicationAdapter(this, em, session, applicationData);
em.flush();
return resource;
}
@ -628,7 +554,7 @@ public class RealmAdapter implements RealmModel {
@Override
public ApplicationModel getApplicationById(String id) {
return session.model().getApplicationById(id, this);
return session.realms().getApplicationById(id, this);
}
@Override
@ -636,57 +562,6 @@ public class RealmAdapter implements RealmModel {
return getApplicationNameMap().get(name);
}
@Override
public UserModel getUserBySocialLink(SocialLinkModel socialLink) {
return session.model().getUserBySocialLink(socialLink, this);
}
@Override
public Set<SocialLinkModel> getSocialLinks(UserModel user) {
return session.model().getSocialLinks(user, this);
}
@Override
public SocialLinkModel getSocialLink(UserModel user, String socialProvider) {
return session.model().getSocialLink(user, socialProvider, this);
}
@Override
public void addSocialLink(UserModel user, SocialLinkModel socialLink) {
SocialLinkEntity entity = new SocialLinkEntity();
entity.setRealm(realm);
entity.setSocialProvider(socialLink.getSocialProvider());
entity.setSocialUserId(socialLink.getSocialUserId());
entity.setSocialUsername(socialLink.getSocialUsername());
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
entity.setUser(userEntity);
em.persist(entity);
em.flush();
}
private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) {
TypedQuery<SocialLinkEntity> query = em.createNamedQuery("findSocialLinkByUserAndProvider", SocialLinkEntity.class);
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
query.setParameter("user", userEntity);
query.setParameter("socialProvider", socialProvider);
List<SocialLinkEntity> results = query.getResultList();
return results.size() > 0 ? results.get(0) : null;
}
@Override
public boolean removeSocialLink(UserModel user, String socialProvider) {
SocialLinkEntity entity = findSocialLink(user, socialProvider);
if (entity != null) {
em.remove(entity);
em.flush();
return true;
} else {
return false;
}
}
@Override
public boolean isSocial() {
return realm.isSocial();
@ -709,21 +584,6 @@ public class RealmAdapter implements RealmModel {
em.flush();
}
@Override
public List<UserModel> getUsers() {
return session.model().getUsers(this);
}
@Override
public List<UserModel> searchForUser(String search) {
return session.model().searchForUser(search, this);
}
@Override
public List<UserModel> searchForUserByAttributes(Map<String, String> attributes) {
return session.model().searchForUserByAttributes(attributes, this);
}
@Override
public OAuthClientModel addOAuthClient(String name) {
return this.addOAuthClient(KeycloakModelUtils.generateId(), name);
@ -764,7 +624,7 @@ public class RealmAdapter implements RealmModel {
@Override
public OAuthClientModel getOAuthClientById(String id) {
return session.model().getOAuthClientById(id, this);
return session.realms().getOAuthClientById(id, this);
}
@ -899,13 +759,12 @@ public class RealmAdapter implements RealmModel {
return false;
}
if (!role.getContainer().equals(this)) return false;
session.users().preRemove(role);
RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em);
realm.getRoles().remove(role);
realm.getDefaultRoles().remove(role);
em.createNativeQuery("delete from CompositeRole where childRole = :role").setParameter("role", roleEntity).executeUpdate();
em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate();
em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate();
em.remove(roleEntity);
@ -926,7 +785,7 @@ public class RealmAdapter implements RealmModel {
@Override
public RoleModel getRoleById(String id) {
return session.model().getRoleById(id, this);
return session.realms().getRoleById(id, this);
}
@Override
@ -1060,7 +919,7 @@ public class RealmAdapter implements RealmModel {
@Override
public ApplicationModel getMasterAdminApp() {
return new ApplicationAdapter(this, em, realm.getMasterAdminApp());
return new ApplicationAdapter(this, em, session, realm.getMasterAdminApp());
}
@Override

View file

@ -2,7 +2,6 @@ package org.keycloak.models.jpa;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.AuthenticationLinkModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel;

View file

@ -1,52 +0,0 @@
package org.keycloak.models.jpa.entities;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import org.hibernate.annotations.GenericGenerator;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@MappedSuperclass
public class AbstractRoleMappingEntity {
@Id
@GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator")
@GeneratedValue(generator = "keycloak_generator")
protected String id;
@ManyToOne(fetch= FetchType.LAZY)
protected UserEntity user;
@ManyToOne(fetch= FetchType.LAZY)
@JoinColumn(name="roleId")
protected RoleEntity role;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
public RoleEntity getRole() {
return role;
}
public void setRole(RoleEntity role) {
this.role = role;
}
}

View file

@ -1,25 +1,12 @@
package org.keycloak.models.jpa.entities;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.annotations.GenericGenerator;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>

View file

@ -1,14 +1,10 @@
package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import org.hibernate.annotations.GenericGenerator;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>

View file

@ -1,6 +1,6 @@
package org.keycloak.models.jpa.entities;
import java.util.Map;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
@ -11,8 +11,7 @@ import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKeyColumn;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import java.util.Map;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>

View file

@ -1,20 +1,15 @@
package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.CascadeType;
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.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.HashSet;

View file

@ -1,5 +1,7 @@
package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
@ -8,8 +10,6 @@ import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import org.hibernate.annotations.GenericGenerator;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
@ -33,6 +33,9 @@ public class CredentialEntity {
@ManyToOne(fetch = FetchType.LAZY)
protected UserEntity user;
@ManyToOne(fetch = FetchType.LAZY)
protected RealmEntity realm;
public String getValue() {
return value;
}

View file

@ -1,11 +1,11 @@
package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $

View file

@ -3,10 +3,7 @@ package org.keycloak.models.jpa.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
@ -18,8 +15,6 @@ import javax.persistence.UniqueConstraint;
import java.util.ArrayList;
import java.util.Collection;
import org.hibernate.annotations.GenericGenerator;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $

View file

@ -1,5 +1,7 @@
package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
@ -8,8 +10,6 @@ import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import org.hibernate.annotations.GenericGenerator;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $

View file

@ -1,6 +1,5 @@
package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
@ -10,7 +9,6 @@ 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;
import javax.persistence.ManyToOne;
@ -21,7 +19,6 @@ import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

View file

@ -1,6 +1,13 @@
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.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
@ -14,6 +21,40 @@ import javax.persistence.NamedQuery;
@NamedQuery(name="userRoleMappingIds", query="select m.role.id from UserRoleMappingEntity m where m.user = :user")
})
@Entity
public class UserRoleMappingEntity extends AbstractRoleMappingEntity {
public class UserRoleMappingEntity {
@Id
@GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator")
@GeneratedValue(generator = "keycloak_generator")
protected String id;
@ManyToOne(fetch= FetchType.LAZY)
protected UserEntity user;
@ManyToOne(fetch= FetchType.LAZY)
@JoinColumn(name="roleId")
protected RoleEntity role;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
public RoleEntity getRole() {
return role;
}
public void setRole(RoleEntity role) {
this.role = role;
}
}

View file

@ -1,12 +1,12 @@
package org.keycloak.models.jpa.utils;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.io.Serializable;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/

View file

@ -1 +0,0 @@
org.keycloak.models.jpa.JpaModelProviderFactory

View file

@ -0,0 +1 @@
org.keycloak.models.jpa.JpaRealmProviderFactory

View file

@ -0,0 +1 @@
org.keycloak.models.jpa.JpaUserProviderFactory

View file

@ -2,12 +2,12 @@ package org.keycloak.models.mongo.keycloak.adapters;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
import org.keycloak.models.mongo.utils.MongoModelUtils;
@ -141,6 +141,7 @@ public class ApplicationAdapter extends ClientAdapter<MongoApplicationEntity> im
@Override
public boolean removeRole(RoleModel role) {
session.users().preRemove(role);
return getMongoStore().removeEntity(MongoRoleEntity.class, role.getId(), invocationContext);
}

Some files were not shown because too many files have changed in this diff Show more