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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,17 +2,13 @@ package org.keycloak.exportimport.util;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonParser; import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken; import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.io.SerializedString;
import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectMapper;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.Config; import org.keycloak.Config;
@ -20,10 +16,9 @@ import org.keycloak.exportimport.Strategy;
import org.keycloak.models.AdminRoles; import org.keycloak.models.AdminRoles;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider; import org.keycloak.models.RealmProvider;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
@ -46,7 +41,7 @@ public class ImportUtils {
*/ */
public static RealmModel importRealm(KeycloakSession session, RealmRepresentation rep, Strategy strategy) { public static RealmModel importRealm(KeycloakSession session, RealmRepresentation rep, Strategy strategy) {
String realmName = rep.getRealm(); String realmName = rep.getRealm();
ModelProvider model = session.model(); RealmProvider model = session.realms();
RealmModel realm = model.getRealmByName(realmName); RealmModel realm = model.getRealmByName(realmName);
if (realm != null) { if (realm != null) {
@ -64,7 +59,7 @@ public class ImportUtils {
realm = rep.getId() != null ? model.createRealm(rep.getId(), realmName) : model.createRealm(realmName); realm = rep.getId() != null ? model.createRealm(rep.getId(), realmName) : model.createRealm(realmName);
RepresentationToModel.importRealm(rep, realm); RepresentationToModel.importRealm(session, rep, realm);
refreshMasterAdminApps(model, realm); refreshMasterAdminApps(model, realm);
@ -72,7 +67,7 @@ public class ImportUtils {
return realm; return realm;
} }
private static void refreshMasterAdminApps(ModelProvider model, RealmModel realm) { private static void refreshMasterAdminApps(RealmProvider model, RealmModel realm) {
String adminRealmId = Config.getAdminRealm(); String adminRealmId = Config.getAdminRealm();
if (adminRealmId.equals(realm.getId())) { if (adminRealmId.equals(realm.getId())) {
// We just imported master realm. All 'masterAdminApps' need to be refreshed // 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? // 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; RealmModel adminRealm;
RoleModel adminRole; RoleModel adminRole;
@ -160,7 +155,7 @@ public class ImportUtils {
// Assuming that it's invoked inside transaction // Assuming that it's invoked inside transaction
public static void importUsersFromStream(KeycloakSession session, String realmName, ObjectMapper mapper, InputStream is) throws IOException { 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(); JsonFactory factory = mapper.getJsonFactory();
JsonParser parser = factory.createJsonParser(is); JsonParser parser = factory.createJsonParser(is);
try { try {
@ -188,7 +183,7 @@ public class ImportUtils {
parser.nextToken(); parser.nextToken();
} }
importUsers(model, realmName, userReps); importUsers(session, model, realmName, userReps);
if (parser.getCurrentToken() == JsonToken.END_ARRAY) { if (parser.getCurrentToken() == JsonToken.END_ARRAY) {
parser.nextToken(); 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); RealmModel realm = model.getRealmByName(realmName);
Map<String, ApplicationModel> apps = realm.getApplicationNameMap(); Map<String, ApplicationModel> apps = realm.getApplicationNameMap();
for (UserRepresentation user : userReps) { 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 @Override
public void run(KeycloakSession session) { public void run(KeycloakSession session) {
List<RealmModel> realms = session.model().getRealms(); List<RealmModel> realms = session.realms().getRealms();
holder.realms = realms; holder.realms = realms;
} }
@ -49,15 +49,15 @@ public abstract class MultipleStepsExportProvider implements ExportProvider {
@Override @Override
public void run(KeycloakSession session) throws IOException { public void run(KeycloakSession session) throws IOException {
RealmModel realm = session.model().getRealmByName(realmName); RealmModel realm = session.realms().getRealmByName(realmName);
RealmRepresentation rep = ExportUtils.exportRealm(realm, exportUsersIntoSameFile); RealmRepresentation rep = ExportUtils.exportRealm(session, realm, exportUsersIntoSameFile);
writeRealm(realmName + "-realm.json", rep); writeRealm(realmName + "-realm.json", rep);
logger.info("Realm '" + realmName + "' - data exported"); logger.info("Realm '" + realmName + "' - data exported");
// Count total number of users // Count total number of users
if (!exportUsersIntoSameFile) { if (!exportUsersIntoSameFile) {
// TODO: getUsersCount method on model // 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 @Override
public void run(KeycloakSession session) throws IOException { public void run(KeycloakSession session) throws IOException {
RealmModel realm = session.model().getRealmByName(realmName); RealmModel realm = session.realms().getRealmByName(realmName);
// TODO: pagination // TODO: pagination
List<UserModel> users = realm.getUsers(); List<UserModel> users = session.users().getUsers(realm);
usersHolder.users = users.subList(usersHolder.currentPageStart, usersHolder.currentPageEnd); 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"); 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 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 { public static class RealmsHolder {
List<RealmModel> realms; List<RealmModel> realms;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,8 +2,6 @@ package org.keycloak.models;
import org.keycloak.provider.Provider; import org.keycloak.provider.Provider;
import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
@ -29,7 +27,7 @@ public interface KeycloakSession {
* @return * @return
* @throws IllegalStateException if transaction is not active * @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 * 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(); 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); 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); RoleModel getRoleById(String id);
List<String> getDefaultRoles(); List<String> getDefaultRoles();
@ -147,16 +135,6 @@ public interface RealmModel extends RoleContainerModel {
void updateRequiredCredentials(Set<String> creds); 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(); boolean isSocial();
void setSocial(boolean social); void setSocial(boolean social);
@ -165,12 +143,6 @@ public interface RealmModel extends RoleContainerModel {
void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin); 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 name);
OAuthClientModel addOAuthClient(String id, 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> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @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> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
public class ModelSpi implements Spi { public class RealmSpi implements Spi {
@Override @Override
public String getName() { public String getName() {
return "model"; return "realm";
} }
@Override @Override
public Class<? extends Provider> getProviderClass() { public Class<? extends Provider> getProviderClass() {
return ModelProvider.class; return RealmProvider.class;
} }
@Override @Override
public Class<? extends ProviderFactory> getProviderFactoryClass() { public Class<? extends ProviderFactory> getProviderFactoryClass() {
return ModelProviderFactory.class; return RealmProviderFactory.class;
} }
} }

View file

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

View file

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

View file

@ -13,12 +13,13 @@ import java.util.Set;
public interface UserProvider extends Provider { 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 // 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 id, String username, boolean addDefaultRoles);
UserModel addUser(RealmModel realm, String username); UserModel addUser(RealmModel realm, String username);
boolean removeUser(RealmModel realm, String name); 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 getUserById(String id, RealmModel realm);
UserModel getUserByUsername(String username, RealmModel realm); UserModel getUserByUsername(String username, RealmModel realm);
UserModel getUserByEmail(String email, RealmModel realm); UserModel getUserByEmail(String email, RealmModel realm);

View file

@ -1,7 +1,6 @@
package org.keycloak.models; package org.keycloak.models;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @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 org.keycloak.provider.Provider;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @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; package org.keycloak.models.entities;
import org.keycloak.models.UserModel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.keycloak.models.UserModel;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */

View file

@ -1,5 +1,15 @@
package org.keycloak.models.utils; 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.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.security.Key; import java.security.Key;
@ -10,16 +20,6 @@ import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.Set; import java.util.Set;
import java.util.UUID; 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. * 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 * @param username username or email of user
* @return found user * @return found user
*/ */
public static UserModel findUserByNameOrEmail(RealmModel realm, String username) { public static UserModel findUserByNameOrEmail(KeycloakSession session, RealmModel realm, String username) {
UserModel user = realm.getUser(username); UserModel user = session.users().getUserByUsername(username, realm);
if (user == null && username.contains("@")) { if (user == null && username.contains("@")) {
user = realm.getUserByEmail(username); user = session.users().getUserByEmail(username, realm);
} }
return user; return user;
} }

View file

@ -1,15 +1,5 @@
package org.keycloak.models.utils; 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 net.iharder.Base64;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
@ -17,6 +7,7 @@ import org.keycloak.models.AuthenticationLinkModel;
import org.keycloak.models.AuthenticationProviderModel; import org.keycloak.models.AuthenticationProviderModel;
import org.keycloak.models.ClaimMask; import org.keycloak.models.ClaimMask;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.OAuthClientModel; import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy; import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel; 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.SocialLinkRepresentation;
import org.keycloak.representations.idm.UserRepresentation; 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 { public class RepresentationToModel {
private static Logger logger = Logger.getLogger(RepresentationToModel.class); 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()); newRealm.setName(rep.getRealm());
if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled()); if (rep.isEnabled() != null) newRealm.setEnabled(rep.isEnabled());
if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial()); if (rep.isSocial() != null) newRealm.setSocial(rep.isSocial());
@ -210,7 +211,7 @@ public class RepresentationToModel {
if (rep.getUsers() != null) { if (rep.getUsers() != null) {
for (UserRepresentation userRep : rep.getUsers()) { 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 // Users
public static UserModel createUser(RealmModel newRealm, UserRepresentation userRep, Map<String, ApplicationModel> appMap) { public static UserModel createUser(KeycloakSession session, RealmModel newRealm, UserRepresentation userRep, Map<String, ApplicationModel> appMap) {
UserModel user = newRealm.addUser(userRep.getId(), userRep.getUsername(), false); UserModel user = session.users().addUser(newRealm, userRep.getId(), userRep.getUsername(), false);
user.setEnabled(userRep.isEnabled()); user.setEnabled(userRep.isEnabled());
user.setEmail(userRep.getEmail()); user.setEmail(userRep.getEmail());
user.setFirstName(userRep.getFirstName()); user.setFirstName(userRep.getFirstName());
@ -600,7 +601,7 @@ public class RepresentationToModel {
if (userRep.getSocialLinks() != null) { if (userRep.getSocialLinks() != null) {
for (SocialLinkRepresentation socialLink : userRep.getSocialLinks()) { for (SocialLinkRepresentation socialLink : userRep.getSocialLinks()) {
SocialLinkModel mappingModel = new SocialLinkModel(socialLink.getSocialProvider(), socialLink.getSocialUserId(), socialLink.getSocialUsername()); SocialLinkModel mappingModel = new SocialLinkModel(socialLink.getSocialProvider(), socialLink.getSocialUserId(), socialLink.getSocialUsername());
newRealm.addSocialLink(user, mappingModel); session.users().addSocialLink(newRealm, user, mappingModel);
} }
} }
if (userRep.getRealmRoles() != null) { if (userRep.getRealmRoles() != null) {

View file

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

View file

@ -1,6 +1,5 @@
package org.keycloak.models.utils.reflection; package org.keycloak.models.utils.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.Method; 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.UserSessionSpi
org.keycloak.models.UserSpi

View file

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

View file

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

View file

@ -1,7 +1,6 @@
package org.keycloak.models.hybrid; package org.keycloak.models.hybrid;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction; import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.ModelProvider; import org.keycloak.models.ModelProvider;
@ -10,13 +9,11 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel; import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UsernameLoginFailureModel; import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.realms.RealmProvider; import org.keycloak.models.realms.RealmProvider;
import org.keycloak.models.sessions.SessionProvider; import org.keycloak.models.sessions.SessionProvider;
import org.keycloak.models.users.UserProvider; import org.keycloak.models.users.UserProvider;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.util.Time;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;

View file

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

View file

@ -1,11 +1,5 @@
package org.keycloak.models.hybrid; 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.ApplicationModel;
import org.keycloak.models.AuthenticationProviderModel; import org.keycloak.models.AuthenticationProviderModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
@ -15,9 +9,14 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel; import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UsernameLoginFailureModel; 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.Credentials;
import org.keycloak.models.users.Feature; import org.keycloak.models.users.Feature;
import org.keycloak.models.users.User; import org.keycloak.models.users.User;

View file

@ -1,10 +1,10 @@
package org.keycloak.models.hybrid; 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.Application;
import org.keycloak.models.realms.Realm; import org.keycloak.models.realms.Realm;
import org.keycloak.models.realms.Role; import org.keycloak.models.realms.Role;
import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import java.util.HashSet; import java.util.HashSet;

View file

@ -3,9 +3,6 @@ package org.keycloak.models.hybrid;
import org.keycloak.models.UsernameLoginFailureModel; import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.sessions.LoginFailure; import org.keycloak.models.sessions.LoginFailure;
import java.util.LinkedList;
import java.util.List;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @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 ApplicationModel updated;
protected CachedApplication cached; 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); super(cachedRealm, cached, cache, cacheSession);
this.cached = cached; this.cached = cached;
} }

View file

@ -1,13 +1,13 @@
package org.keycloak.models.cache; 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> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public interface CacheModelProvider extends ModelProvider { public interface CacheRealmProvider extends RealmProvider {
ModelProvider getDelegate(); RealmProvider getDelegate();
void registerRealmInvalidation(String id); 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> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @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> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class CacheModelProviderSpi implements Spi { public class CacheRealmProviderSpi implements Spi {
@Override @Override
public String getName() { public String getName() {
return "modelCache"; return "realmCache";
} }
@Override @Override
public Class<? extends Provider> getProviderClass() { public Class<? extends Provider> getProviderClass() {
return CacheModelProvider.class; return CacheRealmProvider.class;
} }
@Override @Override
public Class<? extends ProviderFactory> getProviderFactoryClass() { 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.RealmModel;
import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.cache.entities.CachedClient; import org.keycloak.models.cache.entities.CachedClient;
import java.util.HashSet; import java.util.HashSet;
@ -16,12 +15,12 @@ import java.util.Set;
*/ */
public abstract class ClientAdapter implements ClientModel { public abstract class ClientAdapter implements ClientModel {
protected CachedClient cachedClient; protected CachedClient cachedClient;
protected CacheModelProvider cacheSession; protected CacheRealmProvider cacheSession;
protected ClientModel updatedClient; protected ClientModel updatedClient;
protected RealmModel cachedRealm; 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.cachedRealm = cachedRealm;
this.cache = cache; this.cache = cache;
this.cacheSession = cacheSession; this.cacheSession = cacheSession;

View file

@ -1,24 +1,19 @@
package org.keycloak.models.cache; package org.keycloak.models.cache;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction; import org.keycloak.models.KeycloakTransaction;
import org.keycloak.models.ModelProvider; import org.keycloak.models.RealmProvider;
import org.keycloak.models.OAuthClientModel; import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel; 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.CachedApplication;
import org.keycloak.models.cache.entities.CachedApplicationRole; import org.keycloak.models.cache.entities.CachedApplicationRole;
import org.keycloak.models.cache.entities.CachedOAuthClient; import org.keycloak.models.cache.entities.CachedOAuthClient;
import org.keycloak.models.cache.entities.CachedRealm; import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRealmRole; import org.keycloak.models.cache.entities.CachedRealmRole;
import org.keycloak.models.cache.entities.CachedRole; import org.keycloak.models.cache.entities.CachedRole;
import org.keycloak.models.cache.entities.CachedUser;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -30,10 +25,10 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class DefaultCacheModelProvider implements CacheModelProvider { public class DefaultCacheRealmProvider implements CacheRealmProvider {
protected KeycloakCache cache; protected RealmCache cache;
protected KeycloakSession session; protected KeycloakSession session;
protected ModelProvider delegate; protected RealmProvider delegate;
protected boolean transactionActive; protected boolean transactionActive;
protected boolean setRollbackOnly; protected boolean setRollbackOnly;
@ -50,7 +45,7 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
protected boolean clearAll; protected boolean clearAll;
public DefaultCacheModelProvider(KeycloakCache cache, KeycloakSession session) { public DefaultCacheRealmProvider(RealmCache cache, KeycloakSession session) {
this.cache = cache; this.cache = cache;
this.session = session; this.session = session;
@ -58,10 +53,10 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
} }
@Override @Override
public ModelProvider getDelegate() { public RealmProvider getDelegate() {
if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction"); if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
if (delegate != null) return delegate; if (delegate != null) return delegate;
delegate = session.getProvider(ModelProvider.class); delegate = session.getProvider(RealmProvider.class);
return delegate; return delegate;
} }
@ -103,10 +98,6 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
for (String id : clientInvalidations) { for (String id : clientInvalidations) {
cache.invalidateCachedOAuthClientById(id); cache.invalidateCachedOAuthClientById(id);
} }
for (String id : userInvalidations) {
cache.invalidateCachedUserById(id);
}
} }
private KeycloakTransaction getTransaction() { private KeycloakTransaction getTransaction() {
@ -200,63 +191,6 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
return adapter; 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 @Override
public List<RealmModel> getRealms() { public List<RealmModel> getRealms() {
// we don't cache this for now // we don't cache this for now
@ -291,36 +225,6 @@ public class DefaultCacheModelProvider implements CacheModelProvider {
if (delegate != null) delegate.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 @Override
public RoleModel getRoleById(String id, RealmModel realm) { public RoleModel getRoleById(String id, RealmModel realm) {
CachedRole cached = cache.getRole(id); 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> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SimpleCacheModelProviderFactory implements CacheModelProviderFactory { public class MemoryCacheRealmProviderFactory implements CacheRealmProviderFactory {
protected KeycloakCache cache = new SimpleCache(); protected RealmCache cache = new MemoryRealmCache();
@Override @Override
public CacheModelProvider create(KeycloakSession session) { public CacheRealmProvider create(KeycloakSession session) {
return new DefaultCacheModelProvider(cache, session); return new DefaultCacheRealmProvider(cache, session);
} }
@Override @Override
@ -28,6 +28,6 @@ public class SimpleCacheModelProviderFactory implements CacheModelProviderFactor
@Override @Override
public String getId() { 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; package org.keycloak.models.cache;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakTransaction; import org.keycloak.models.RealmProvider;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.OAuthClientModel; import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; 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.List;
import java.util.Map;
import java.util.Set;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class NoCacheModelProvider implements CacheModelProvider { public class NoCacheRealmProvider implements CacheRealmProvider {
protected KeycloakSession session; protected KeycloakSession session;
protected ModelProvider delegate; protected RealmProvider delegate;
// protected KeycloakTransaction transactionDelegate; // protected KeycloakTransaction transactionDelegate;
// protected boolean transactionActive; // protected boolean transactionActive;
// protected boolean setRollbackOnly; // protected boolean setRollbackOnly;
public NoCacheModelProvider(KeycloakSession session) { public NoCacheRealmProvider(KeycloakSession session) {
this.session = session; this.session = session;
} }
@Override @Override
public ModelProvider getDelegate() { public RealmProvider getDelegate() {
// if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction"); // if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
if (delegate != null) return delegate; if (delegate != null) return delegate;
delegate = session.getProvider(ModelProvider.class); delegate = session.getProvider(RealmProvider.class);
// transactionDelegate = delegate.getTransaction(); // transactionDelegate = delegate.getTransaction();
// if (!transactionDelegate.isActive()) { // if (!transactionDelegate.isActive()) {
// transactionDelegate.begin(); // transactionDelegate.begin();
@ -83,21 +75,6 @@ public class NoCacheModelProvider implements CacheModelProvider {
return getDelegate().getRealmByName(name); return getDelegate().getRealmByName(name);
} }
@Override
public UserModel getUserById(String id, RealmModel realm) {
return getDelegate().getUserById(id, realm);
}
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
return getDelegate().getUserByUsername(username, realm);
}
@Override
public UserModel getUserByEmail(String email, RealmModel realm) {
return getDelegate().getUserByEmail(email, realm);
}
@Override @Override
public List<RealmModel> getRealms() { public List<RealmModel> getRealms() {
// we don't cache this for now // we don't cache this for now
@ -114,36 +91,6 @@ public class NoCacheModelProvider implements CacheModelProvider {
if (delegate != null) delegate.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 @Override
public RoleModel getRoleById(String id, RealmModel realm) { public RoleModel getRoleById(String id, RealmModel realm) {
return getDelegate().getRoleById(id, 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> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class NoCacheModelProviderFactory implements CacheModelProviderFactory { public class NoCacheRealmProviderFactory implements CacheRealmProviderFactory {
@Override @Override
public CacheModelProvider create(KeycloakSession session) { public CacheRealmProvider create(KeycloakSession session) {
return new NoCacheModelProvider(session); return new NoCacheRealmProvider(session);
} }
@Override @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 OAuthClientModel updated;
protected CachedOAuthClient cached; 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); super(cachedRealm, cached, cache, cacheSession);
this.cached = cached; this.cached = cached;
} }

View file

@ -9,15 +9,11 @@ import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel; import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.cache.entities.CachedRealm; import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.Pbkdf2PasswordEncoder;
import org.keycloak.models.utils.TimeBasedOTP; import org.keycloak.models.utils.TimeBasedOTP;
import java.security.PrivateKey; import java.security.PrivateKey;
@ -35,13 +31,13 @@ import java.util.Set;
*/ */
public class RealmAdapter implements RealmModel { public class RealmAdapter implements RealmModel {
protected CachedRealm cached; protected CachedRealm cached;
protected CacheModelProvider cacheSession; protected CacheRealmProvider cacheSession;
protected RealmModel updated; protected RealmModel updated;
protected KeycloakCache cache; protected RealmCache cache;
protected volatile transient PublicKey publicKey; protected volatile transient PublicKey publicKey;
protected volatile transient PrivateKey privateKey; protected volatile transient PrivateKey privateKey;
public RealmAdapter(CachedRealm cached, CacheModelProvider cacheSession) { public RealmAdapter(CachedRealm cached, CacheRealmProvider cacheSession) {
this.cached = cached; this.cached = cached;
this.cacheSession = cacheSession; this.cacheSession = cacheSession;
} }
@ -395,39 +391,6 @@ public class RealmAdapter implements RealmModel {
return false; 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 @Override
public RoleModel getRoleById(String id) { public RoleModel getRoleById(String id) {
if (updated != null) return updated.getRoleById(id); if (updated != null) return updated.getRoleById(id);
@ -538,36 +501,6 @@ public class RealmAdapter implements RealmModel {
updated.updateRequiredCredentials(creds); 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 @Override
public boolean isSocial() { public boolean isSocial() {
if (updated != null) return updated.isSocial(); if (updated != null) return updated.isSocial();
@ -592,24 +525,6 @@ public class RealmAdapter implements RealmModel {
updated.setUpdateProfileOnInitialSocialLogin(updateProfileOnInitialSocialLogin); 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 @Override
public OAuthClientModel addOAuthClient(String name) { public OAuthClientModel addOAuthClient(String name) {
getDelegateForUpdate(); getDelegateForUpdate();

View file

@ -1,17 +1,15 @@
package org.keycloak.models.cache; package org.keycloak.models.cache;
import org.keycloak.models.RealmModel;
import org.keycloak.models.cache.entities.CachedApplication; import org.keycloak.models.cache.entities.CachedApplication;
import org.keycloak.models.cache.entities.CachedOAuthClient; import org.keycloak.models.cache.entities.CachedOAuthClient;
import org.keycloak.models.cache.entities.CachedRealm; import org.keycloak.models.cache.entities.CachedRealm;
import org.keycloak.models.cache.entities.CachedRole; import org.keycloak.models.cache.entities.CachedRole;
import org.keycloak.models.cache.entities.CachedUser;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public interface KeycloakCache { public interface RealmCache {
void clear(); void clear();
CachedRealm getCachedRealm(String id); CachedRealm getCachedRealm(String id);
@ -51,16 +49,4 @@ public interface KeycloakCache {
void invalidateRoleById(String id); 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 RoleModel updated;
protected CachedRole cached; protected CachedRole cached;
protected KeycloakCache cache; protected RealmCache cache;
protected CacheModelProvider cacheSession; protected CacheRealmProvider cacheSession;
protected RealmModel realm; 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.cached = cached;
this.cache = cache; this.cache = cache;
this.cacheSession = session; 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.ApplicationModel;
import org.keycloak.models.AuthenticationLinkModel; import org.keycloak.models.AuthenticationLinkModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
@ -22,21 +23,21 @@ import java.util.Set;
public class UserAdapter implements UserModel { public class UserAdapter implements UserModel {
protected UserModel updated; protected UserModel updated;
protected CachedUser cached; protected CachedUser cached;
protected KeycloakCache cache; protected CacheUserProvider userProviderCache;
protected CacheModelProvider cacheSession; protected KeycloakSession keycloakSession;
protected RealmModel realm; 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.cached = cached;
this.cache = cache; this.userProviderCache = userProvider;
this.cacheSession = session; this.keycloakSession = keycloakSession;
this.realm = realm; this.realm = realm;
} }
protected void getDelegateForUpdate() { protected void getDelegateForUpdate() {
if (updated == null) { if (updated == null) {
cacheSession.registerUserInvalidation(getId()); userProviderCache.registerUserInvalidation(realm, getId());
updated = cacheSession.getDelegate().getUserById(getId(), realm); updated = userProviderCache.getDelegate().getUserById(getId(), realm);
if (updated == null) throw new IllegalStateException("Not found in database"); 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(); if (updated != null) return updated.getRoleMappings();
Set<RoleModel> roles = new HashSet<RoleModel>(); Set<RoleModel> roles = new HashSet<RoleModel>();
for (String id : cached.getRoleMappings()) { 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; 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; package org.keycloak.models.cache.entities;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.RealmProvider;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.cache.RealmCache;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.cache.KeycloakCache;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@ -29,7 +23,7 @@ public class CachedApplication extends CachedClient {
private boolean bearerOnly; private boolean bearerOnly;
private Map<String, String> roles = new HashMap<String, String>(); 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); super(cache, delegate, realm, model);
surrogateAuthRequired = model.isSurrogateAuthRequired(); surrogateAuthRequired = model.isSurrogateAuthRequired();
managementUrl = model.getManagementUrl(); managementUrl = model.getManagementUrl();

View file

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

View file

@ -1,17 +1,16 @@
package org.keycloak.models.cache.entities; package org.keycloak.models.cache.entities;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmProvider;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.OAuthClientModel; import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel; 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> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class CachedOAuthClient extends CachedClient { 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); 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.ApplicationModel;
import org.keycloak.models.AuthenticationProviderModel; import org.keycloak.models.AuthenticationProviderModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmProvider;
import org.keycloak.models.ModelProvider;
import org.keycloak.models.OAuthClientModel; import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.PasswordPolicy; import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.cache.KeycloakCache; import org.keycloak.models.cache.RealmCache;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -81,7 +80,7 @@ public class CachedRealm {
public CachedRealm() { public CachedRealm() {
} }
public CachedRealm(KeycloakCache cache, ModelProvider delegate, RealmModel model) { public CachedRealm(RealmCache cache, RealmProvider delegate, RealmModel model) {
id = model.getId(); id = model.getId();
name = model.getName(); name = model.getName();
enabled = model.isEnabled(); enabled = model.isEnabled();

View file

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

View file

@ -20,11 +20,9 @@ import java.util.Set;
public class CachedUser { public class CachedUser {
private String id; private String id;
private String username; private String username;
private String usernameKey;
private String firstName; private String firstName;
private String lastName; private String lastName;
private String email; private String email;
private String emailKey;
private boolean emailVerified; private boolean emailVerified;
private List<UserCredentialValueModel> credentials = new LinkedList<UserCredentialValueModel>(); private List<UserCredentialValueModel> credentials = new LinkedList<UserCredentialValueModel>();
private boolean enabled; private boolean enabled;
@ -38,14 +36,10 @@ public class CachedUser {
public CachedUser(RealmModel realm, UserModel user) { public CachedUser(RealmModel realm, UserModel user) {
this.id = user.getId(); this.id = user.getId();
this.username = user.getUsername(); this.username = user.getUsername();
this.usernameKey = realm.getId() + "." + this.username;
this.firstName = user.getFirstName(); this.firstName = user.getFirstName();
this.lastName = user.getLastName(); this.lastName = user.getLastName();
this.attributes.putAll(user.getAttributes()); this.attributes.putAll(user.getAttributes());
this.email = user.getEmail(); this.email = user.getEmail();
if (this.email != null) {
this.emailKey = realm.getId() + "." + this.email;
}
this.emailVerified = user.isEmailVerified(); this.emailVerified = user.isEmailVerified();
this.credentials.addAll(user.getCredentialsDirectly()); this.credentials.addAll(user.getCredentialsDirectly());
this.enabled = user.isEnabled(); this.enabled = user.isEnabled();
@ -65,14 +59,6 @@ public class CachedUser {
return username; return username;
} }
public String getUsernameKey() {
return usernameKey;
}
public String getEmailKey() {
return emailKey;
}
public String getFirstName() { public String getFirstName() {
return firstName; 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.ApplicationModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel; import org.keycloak.models.RoleContainerModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.jpa.entities.ApplicationEntity;
import org.keycloak.models.jpa.entities.*; import org.keycloak.models.jpa.entities.RoleEntity;
import org.keycloak.models.jpa.entities.ScopeMappingEntity;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
@ -25,10 +26,12 @@ import java.util.Set;
public class ApplicationAdapter extends ClientAdapter implements ApplicationModel { public class ApplicationAdapter extends ClientAdapter implements ApplicationModel {
protected EntityManager em; protected EntityManager em;
protected KeycloakSession session;
protected ApplicationEntity applicationEntity; 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); super(realm, applicationEntity, em);
this.session = session;
this.realm = realm; this.realm = realm;
this.em = em; this.em = em;
this.applicationEntity = applicationEntity; this.applicationEntity = applicationEntity;
@ -135,6 +138,7 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
} }
if (!roleModel.getContainer().equals(this)) return false; if (!roleModel.getContainer().equals(this)) return false;
session.users().preRemove(roleModel);
RoleEntity role = RoleAdapter.toRoleEntity(roleModel, em); RoleEntity role = RoleAdapter.toRoleEntity(roleModel, em);
if (!role.isApplicationRole()) return false; if (!role.isApplicationRole()) return false;
@ -143,7 +147,6 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
applicationEntity.getDefaultRoles().remove(role); applicationEntity.getDefaultRoles().remove(role);
em.createNativeQuery("delete from CompositeRole where childRole = :role").setParameter("role", role).executeUpdate(); 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 " + 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); role.setApplication(null);
em.flush(); em.flush();
em.remove(role); 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.Config;
import org.keycloak.connections.jpa.JpaConnectionProvider; import org.keycloak.connections.jpa.JpaConnectionProvider;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelProvider; import org.keycloak.models.RealmProvider;
import org.keycloak.models.ModelProviderFactory; import org.keycloak.models.RealmProviderFactory;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class JpaModelProviderFactory implements ModelProviderFactory { public class JpaRealmProviderFactory implements RealmProviderFactory {
@Override @Override
public void init(Config.Scope config) { public void init(Config.Scope config) {
@ -24,9 +24,9 @@ public class JpaModelProviderFactory implements ModelProviderFactory {
} }
@Override @Override
public ModelProvider create(KeycloakSession session) { public RealmProvider create(KeycloakSession session) {
EntityManager em = session.getProvider(JpaConnectionProvider.class).getEntityManager(); EntityManager em = session.getProvider(JpaConnectionProvider.class).getEntityManager();
return new JpaModelProvider(session, em); return new JpaRealmProvider(session, em);
} }
@Override @Override

View file

@ -2,16 +2,11 @@ package org.keycloak.models.jpa;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.KeycloakSession; 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.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel; import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider; 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.RealmEntity;
import org.keycloak.models.jpa.entities.RoleEntity; import org.keycloak.models.jpa.entities.RoleEntity;
import org.keycloak.models.jpa.entities.SocialLinkEntity; import org.keycloak.models.jpa.entities.SocialLinkEntity;
@ -23,7 +18,6 @@ import javax.persistence.EntityManager;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -39,7 +33,6 @@ public class JpaUserProvider implements UserProvider {
public JpaUserProvider(KeycloakSession session, EntityManager em) { public JpaUserProvider(KeycloakSession session, EntityManager em) {
this.session = session; this.session = session;
this.em = em; this.em = em;
this.em = PersistenceExceptionConverter.create(em);
} }
@Override @Override
@ -99,12 +92,38 @@ public class JpaUserProvider implements UserProvider {
} }
@Override @Override
public void preRemove(RealmModel realm) { public void addSocialLink(RealmModel realm, UserModel user, SocialLinkModel socialLink) {
TypedQuery<UserEntity> query = em.createQuery("select u from UserEntity u where u.realm = :realm", UserEntity.class); SocialLinkEntity entity = new SocialLinkEntity();
RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId()); RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId());
query.setParameter("realm", realmEntity); entity.setRealm(realmEntity);
for (UserEntity u : query.getResultList()) { entity.setSocialProvider(socialLink.getSocialProvider());
em.remove(u); 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(); em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate();
} }
@Override
public KeycloakTransaction getTransaction() {
return new JpaKeycloakTransaction(em);
}
@Override @Override
public UserModel getUserById(String id, RealmModel realmModel) { public UserModel getUserById(String id, RealmModel realmModel) {
TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserById", UserEntity.class); TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserById", UserEntity.class);
@ -154,8 +167,6 @@ public class JpaUserProvider implements UserProvider {
@Override @Override
public void close() { public void close() {
if (em.getTransaction().isActive()) em.getTransaction().rollback();
if (em.isOpen()) em.close();
} }
@Override @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; package org.keycloak.models.jpa;
import org.keycloak.models.ApplicationModel;
import org.keycloak.models.OAuthClientModel; import org.keycloak.models.OAuthClientModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.jpa.entities.OAuthClientEntity; import org.keycloak.models.jpa.entities.OAuthClientEntity;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import java.util.HashSet;
import java.util.Set;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>

View file

@ -1,12 +1,11 @@
package org.keycloak.models.jpa; package org.keycloak.models.jpa;
import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.ConstraintViolationException;
import org.keycloak.models.ModelException;
import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.ModelException;
import javax.persistence.EntityExistsException; import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; 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.RealmModel;
import org.keycloak.models.RequiredCredentialModel; import org.keycloak.models.RequiredCredentialModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.SocialLinkModel;
import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserCredentialValueModel; import org.keycloak.models.UserCredentialValueModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UsernameLoginFailureModel;
import org.keycloak.models.jpa.entities.ApplicationEntity; import org.keycloak.models.jpa.entities.ApplicationEntity;
import org.keycloak.models.jpa.entities.AuthenticationProviderEntity; import org.keycloak.models.jpa.entities.AuthenticationProviderEntity;
import org.keycloak.models.jpa.entities.OAuthClientEntity; 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.RequiredCredentialEntity;
import org.keycloak.models.jpa.entities.RoleEntity; import org.keycloak.models.jpa.entities.RoleEntity;
import org.keycloak.models.jpa.entities.ScopeMappingEntity; 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.KeycloakModelUtils;
import org.keycloak.models.utils.TimeBasedOTP; 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 @Override
public List<String> getDefaultRoles() { public List<String> getDefaultRoles() {
Collection<RoleEntity> entities = realm.getDefaultRoles(); Collection<RoleEntity> entities = realm.getDefaultRoles();
@ -567,7 +493,7 @@ public class RealmAdapter implements RealmModel {
List<ApplicationModel> list = new ArrayList<ApplicationModel>(); List<ApplicationModel> list = new ArrayList<ApplicationModel>();
if (realm.getApplications() == null) return list; if (realm.getApplications() == null) return list;
for (ApplicationEntity entity : realm.getApplications()) { for (ApplicationEntity entity : realm.getApplications()) {
list.add(new ApplicationAdapter(this, em, entity)); list.add(new ApplicationAdapter(this, em, session, entity));
} }
return list; return list;
} }
@ -587,7 +513,7 @@ public class RealmAdapter implements RealmModel {
realm.getApplications().add(applicationData); realm.getApplications().add(applicationData);
em.persist(applicationData); em.persist(applicationData);
em.flush(); em.flush();
ApplicationModel resource = new ApplicationAdapter(this, em, applicationData); ApplicationModel resource = new ApplicationAdapter(this, em, session, applicationData);
em.flush(); em.flush();
return resource; return resource;
} }
@ -628,7 +554,7 @@ public class RealmAdapter implements RealmModel {
@Override @Override
public ApplicationModel getApplicationById(String id) { public ApplicationModel getApplicationById(String id) {
return session.model().getApplicationById(id, this); return session.realms().getApplicationById(id, this);
} }
@Override @Override
@ -636,57 +562,6 @@ public class RealmAdapter implements RealmModel {
return getApplicationNameMap().get(name); 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 @Override
public boolean isSocial() { public boolean isSocial() {
return realm.isSocial(); return realm.isSocial();
@ -709,21 +584,6 @@ public class RealmAdapter implements RealmModel {
em.flush(); 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 @Override
public OAuthClientModel addOAuthClient(String name) { public OAuthClientModel addOAuthClient(String name) {
return this.addOAuthClient(KeycloakModelUtils.generateId(), name); return this.addOAuthClient(KeycloakModelUtils.generateId(), name);
@ -764,7 +624,7 @@ public class RealmAdapter implements RealmModel {
@Override @Override
public OAuthClientModel getOAuthClientById(String id) { 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; return false;
} }
if (!role.getContainer().equals(this)) return false; if (!role.getContainer().equals(this)) return false;
session.users().preRemove(role);
RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em); RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em);
realm.getRoles().remove(role); realm.getRoles().remove(role);
realm.getDefaultRoles().remove(role); realm.getDefaultRoles().remove(role);
em.createNativeQuery("delete from CompositeRole where childRole = :role").setParameter("role", roleEntity).executeUpdate(); 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.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate();
em.remove(roleEntity); em.remove(roleEntity);
@ -926,7 +785,7 @@ public class RealmAdapter implements RealmModel {
@Override @Override
public RoleModel getRoleById(String id) { public RoleModel getRoleById(String id) {
return session.model().getRoleById(id, this); return session.realms().getRoleById(id, this);
} }
@Override @Override
@ -1060,7 +919,7 @@ public class RealmAdapter implements RealmModel {
@Override @Override
public ApplicationModel getMasterAdminApp() { public ApplicationModel getMasterAdminApp() {
return new ApplicationAdapter(this, em, realm.getMasterAdminApp()); return new ApplicationAdapter(this, em, session, realm.getMasterAdminApp());
} }
@Override @Override

View file

@ -2,7 +2,6 @@ package org.keycloak.models.jpa;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.AuthenticationLinkModel; import org.keycloak.models.AuthenticationLinkModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.PasswordPolicy; import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleContainerModel; 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; package org.keycloak.models.jpa.entities;
import javax.persistence.CascadeType; import javax.persistence.CascadeType;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; 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> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>

View file

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

View file

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

View file

@ -1,20 +1,15 @@
package org.keycloak.models.jpa.entities; package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.CascadeType;
import javax.persistence.CollectionTable; import javax.persistence.CollectionTable;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.ElementCollection; import javax.persistence.ElementCollection;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Inheritance; import javax.persistence.Inheritance;
import javax.persistence.InheritanceType; import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import java.util.HashSet; import java.util.HashSet;

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,5 @@
package org.keycloak.models.jpa.entities; package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
@ -10,7 +9,6 @@ import javax.persistence.Column;
import javax.persistence.ElementCollection; import javax.persistence.ElementCollection;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
@ -21,7 +19,6 @@ import javax.persistence.OneToMany;
import javax.persistence.OneToOne; import javax.persistence.OneToOne;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;

View file

@ -1,6 +1,13 @@
package org.keycloak.models.jpa.entities; package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Entity; 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.NamedQueries;
import javax.persistence.NamedQuery; 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") @NamedQuery(name="userRoleMappingIds", query="select m.role.id from UserRoleMappingEntity m where m.user = :user")
}) })
@Entity @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; package org.keycloak.models.jpa.utils;
import java.io.Serializable;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGenerator;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import java.io.Serializable;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @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.DBObject;
import com.mongodb.QueryBuilder; import com.mongodb.QueryBuilder;
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; 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.MongoApplicationEntity;
import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity; import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
import org.keycloak.models.mongo.utils.MongoModelUtils; import org.keycloak.models.mongo.utils.MongoModelUtils;
@ -141,6 +141,7 @@ public class ApplicationAdapter extends ClientAdapter<MongoApplicationEntity> im
@Override @Override
public boolean removeRole(RoleModel role) { public boolean removeRole(RoleModel role) {
session.users().preRemove(role);
return getMongoStore().removeEntity(MongoRoleEntity.class, role.getId(), invocationContext); return getMongoStore().removeEntity(MongoRoleEntity.class, role.getId(), invocationContext);
} }

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