From 62dd6fbc6bd0246da5860429ab2a24cae432a570 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Wed, 9 Jul 2014 11:31:30 +0100 Subject: [PATCH] Revert JPA model provider --- export-import/export-import-impl/pom.xml | 13 + .../JPAToMongoExportImportTest.java | 4 - .../MongoToJPAExportImportTest.java | 4 - model/jpa/pom.xml | 139 ++ .../models/jpa/ApplicationAdapter.java | 268 ++++ .../keycloak/models/jpa/ClientAdapter.java | 268 ++++ .../models/jpa/JpaKeycloakTransaction.java | 53 + .../keycloak/models/jpa/JpaModelProvider.java | 400 ++++++ .../models/jpa/JpaModelProviderFactory.java | 40 + .../models/jpa/OAuthClientAdapter.java | 56 + .../jpa/PersistenceExceptionConverter.java | 49 + .../org/keycloak/models/jpa/RealmAdapter.java | 1142 +++++++++++++++++ .../org/keycloak/models/jpa/RoleAdapter.java | 135 ++ .../org/keycloak/models/jpa/UserAdapter.java | 384 ++++++ .../models/jpa/UserSessionAdapter.java | 130 ++ .../jpa/UsernameLoginFailureAdapter.java | 70 + .../entities/AbstractRoleMappingEntity.java | 52 + .../jpa/entities/ApplicationEntity.java | 90 ++ .../entities/AuthenticationLinkEntity.java | 50 + .../AuthenticationProviderEntity.java | 80 ++ .../models/jpa/entities/ClientEntity.java | 131 ++ .../ClientUserSessionAssociationEntity.java | 84 ++ .../models/jpa/entities/CredentialEntity.java | 91 ++ .../jpa/entities/OAuthClientEntity.java | 27 + .../models/jpa/entities/RealmEntity.java | 479 +++++++ .../entities/RequiredCredentialEntity.java | 64 + .../models/jpa/entities/RoleEntity.java | 157 +++ .../jpa/entities/ScopeMappingEntity.java | 60 + .../models/jpa/entities/SocialLinkEntity.java | 86 ++ .../models/jpa/entities/UserEntity.java | 196 +++ .../jpa/entities/UserRoleMappingEntity.java | 19 + .../jpa/entities/UserSessionEntity.java | 107 ++ .../entities/UsernameLoginFailureEntity.java | 88 ++ .../models/jpa/utils/JpaIdGenerator.java | 19 + .../org.keycloak.models.ModelProviderFactory | 1 + .../test/resources/META-INF/persistence.xml | 70 + server/pom.xml | 22 +- .../resources/META-INF/keycloak-server.json | 14 +- .../main/resources/META-INF/persistence.xml | 35 +- testsuite/integration/pom.xml | 22 +- .../resources/META-INF/keycloak-server.json | 14 +- .../main/resources/META-INF/persistence.xml | 65 +- testsuite/performance/pom.xml | 25 - testsuite/tools/pom.xml | 20 - 44 files changed, 5168 insertions(+), 155 deletions(-) create mode 100755 model/jpa/pom.xml create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProviderFactory.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java create mode 100644 model/jpa/src/main/java/org/keycloak/models/jpa/PersistenceExceptionConverter.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/UserSessionAdapter.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/UsernameLoginFailureAdapter.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/AbstractRoleMappingEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java create mode 100644 model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationLinkEntity.java create mode 100644 model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationProviderEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientUserSessionAssociationEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/CredentialEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredCredentialEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/ScopeMappingEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/SocialLinkEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserRoleMappingEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserSessionEntity.java create mode 100755 model/jpa/src/main/java/org/keycloak/models/jpa/entities/UsernameLoginFailureEntity.java create mode 100644 model/jpa/src/main/java/org/keycloak/models/jpa/utils/JpaIdGenerator.java create mode 100644 model/jpa/src/main/resources/META-INF/services/org.keycloak.models.ModelProviderFactory create mode 100755 model/jpa/src/test/resources/META-INF/persistence.xml diff --git a/export-import/export-import-impl/pom.xml b/export-import/export-import-impl/pom.xml index 683cfe91ca..9b10c8a026 100755 --- a/export-import/export-import-impl/pom.xml +++ b/export-import/export-import-impl/pom.xml @@ -101,6 +101,19 @@ ${project.version} test + + org.keycloak + keycloak-model-jpa + ${project.version} + test + + + org.keycloak + keycloak-model-jpa + ${project.version} + tests + test + org.keycloak keycloak-model-mongo diff --git a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java index c1491d9f96..8cc6a176b7 100644 --- a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java +++ b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/JPAToMongoExportImportTest.java @@ -1,6 +1,5 @@ package org.keycloak.exportimport; -import org.junit.Ignore; import org.keycloak.exportimport.io.directory.TmpDirExportImportIOProvider; import org.keycloak.models.KeycloakSessionFactory; @@ -8,10 +7,7 @@ import org.keycloak.models.KeycloakSessionFactory; * Test for full export of data from JPA and import them to Mongo. Using "directory" provider * * @author Marek Posolda - * - * TODO Update to work with hybrid model provider */ -@Ignore public class JPAToMongoExportImportTest extends ExportImportTestBase { @Override diff --git a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java index 0de953e452..5fe08f76e8 100644 --- a/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java +++ b/export-import/export-import-impl/src/test/java/org/keycloak/exportimport/MongoToJPAExportImportTest.java @@ -1,7 +1,6 @@ package org.keycloak.exportimport; import org.junit.Assert; -import org.junit.Ignore; import org.keycloak.exportimport.io.zip.EncryptedZIPIOProvider; import org.keycloak.models.KeycloakSessionFactory; @@ -11,10 +10,7 @@ import java.io.File; * Test for full export of data from Mongo and import them to JPA. Using export into encrypted ZIP and import from it * * @author Marek Posolda - * - * TODO Update to work with hybrid model provider */ -@Ignore public class MongoToJPAExportImportTest extends ExportImportTestBase { private static final String zipFile = "keycloak-export.zip"; diff --git a/model/jpa/pom.xml b/model/jpa/pom.xml new file mode 100755 index 0000000000..987abd23b1 --- /dev/null +++ b/model/jpa/pom.xml @@ -0,0 +1,139 @@ + + + + keycloak-parent + org.keycloak + 1.0-beta-4-SNAPSHOT + ../../pom.xml + + 4.0.0 + + keycloak-model-jpa + Keycloak Model JPA + + + + + org.bouncycastle + bcprov-jdk16 + provided + + + net.iharder + base64 + provided + + + org.keycloak + keycloak-core + ${project.version} + provided + + + org.keycloak + keycloak-model-api + ${project.version} + + + org.keycloak + keycloak-invalidation-cache-model + ${project.version} + test + + + org.hibernate.javax.persistence + hibernate-jpa-2.0-api + provided + + + org.hibernate + hibernate-entitymanager + ${hibernate.entitymanager.version} + provided + + + org.jboss.resteasy + resteasy-jaxrs + provided + + + log4j + log4j + + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-simple + + + + + + org.keycloak + keycloak-model-tests + ${project.version} + test + + + org.keycloak + keycloak-model-tests + ${project.version} + tests + test + + + com.h2database + h2 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + package-tests-jar + package + + test-jar + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + default-test + + + org.keycloak:keycloak-model-tests + + + + + + + + + + diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java new file mode 100755 index 0000000000..0ebe0170be --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java @@ -0,0 +1,268 @@ +package org.keycloak.models.jpa; + +import org.keycloak.models.ApplicationModel; +import org.keycloak.models.ClientModel; +import org.keycloak.models.ModelDuplicateException; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RoleContainerModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.jpa.entities.*; +import org.keycloak.models.utils.KeycloakModelUtils; + +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class ApplicationAdapter extends ClientAdapter implements ApplicationModel { + + protected EntityManager em; + protected ApplicationEntity applicationEntity; + + public ApplicationAdapter(RealmModel realm, EntityManager em, ApplicationEntity applicationEntity) { + super(realm, applicationEntity, em); + this.realm = realm; + this.em = em; + this.applicationEntity = applicationEntity; + } + + @Override + public void updateApplication() { + em.flush(); + } + + @Override + public String getName() { + return entity.getName(); + } + + @Override + public void setName(String name) { + entity.setName(name); + } + + @Override + public boolean isSurrogateAuthRequired() { + return applicationEntity.isSurrogateAuthRequired(); + } + + @Override + public void setSurrogateAuthRequired(boolean surrogateAuthRequired) { + applicationEntity.setSurrogateAuthRequired(surrogateAuthRequired); + } + + @Override + public String getManagementUrl() { + return applicationEntity.getManagementUrl(); + } + + @Override + public void setManagementUrl(String url) { + applicationEntity.setManagementUrl(url); + } + + @Override + public String getBaseUrl() { + return applicationEntity.getBaseUrl(); + } + + @Override + public void setBaseUrl(String url) { + applicationEntity.setBaseUrl(url); + } + + @Override + public boolean isBearerOnly() { + return applicationEntity.isBearerOnly(); + } + + @Override + public void setBearerOnly(boolean only) { + applicationEntity.setBearerOnly(only); + } + + @Override + public boolean isDirectGrantsOnly() { + return false; // applications can't be grant only + } + + @Override + public void setDirectGrantsOnly(boolean flag) { + // applications can't be grant only + } + + @Override + public RoleModel getRole(String name) { + TypedQuery query = em.createNamedQuery("getAppRoleByName", RoleEntity.class); + query.setParameter("name", name); + query.setParameter("application", entity); + List roles = query.getResultList(); + if (roles.size() == 0) return null; + return new RoleAdapter(realm, em, roles.get(0)); + } + + @Override + public RoleModel addRole(String name) { + return this.addRole(KeycloakModelUtils.generateId(), name); + } + + @Override + public RoleModel addRole(String id, String name) { + RoleEntity roleEntity = new RoleEntity(); + roleEntity.setId(id); + roleEntity.setName(name); + roleEntity.setApplication(applicationEntity); + roleEntity.setApplicationRole(true); + roleEntity.setRealmId(realm.getId()); + em.persist(roleEntity); + applicationEntity.getRoles().add(roleEntity); + em.flush(); + return new RoleAdapter(realm, em, roleEntity); + } + + @Override + public boolean removeRole(RoleModel roleModel) { + if (roleModel == null) { + return false; + } + if (!roleModel.getContainer().equals(this)) return false; + + RoleEntity role = RoleAdapter.toRoleEntity(roleModel, em); + if (!role.isApplicationRole()) return false; + + + applicationEntity.getRoles().remove(role); + applicationEntity.getDefaultRoles().remove(role); + em.createNativeQuery("delete from CompositeRole where childRole = :role").setParameter("role", role).executeUpdate(); + em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", role).executeUpdate(); + em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", role).executeUpdate(); + role.setApplication(null); + em.flush(); + em.remove(role); + em.flush(); + + return true; + } + + @Override + public Set getRoles() { + Set list = new HashSet(); + Collection roles = applicationEntity.getRoles(); + if (roles == null) return list; + for (RoleEntity entity : roles) { + list.add(new RoleAdapter(realm, em, entity)); + } + return list; + } + + @Override + public Set getApplicationScopeMappings(ClientModel client) { + Set roleMappings = client.getScopeMappings(); + + Set appRoles = new HashSet(); + for (RoleModel role : roleMappings) { + RoleContainerModel container = role.getContainer(); + if (container instanceof RealmModel) { + } else { + ApplicationModel app = (ApplicationModel)container; + if (app.getId().equals(getId())) { + appRoles.add(role); + } + } + } + + return appRoles; + } + + + + + @Override + public List getDefaultRoles() { + Collection entities = applicationEntity.getDefaultRoles(); + List roles = new ArrayList(); + if (entities == null) return roles; + for (RoleEntity entity : entities) { + roles.add(entity.getName()); + } + return roles; + } + + @Override + public void addDefaultRole(String name) { + RoleModel role = getRole(name); + if (role == null) { + role = addRole(name); + } + Collection entities = applicationEntity.getDefaultRoles(); + for (RoleEntity entity : entities) { + if (entity.getId().equals(role.getId())) { + return; + } + } + RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em); + entities.add(roleEntity); + em.flush(); + } + + public static boolean contains(String str, String[] array) { + for (String s : array) { + if (str.equals(s)) return true; + } + return false; + } + + @Override + public void updateDefaultRoles(String[] defaultRoles) { + Collection entities = applicationEntity.getDefaultRoles(); + Set already = new HashSet(); + List remove = new ArrayList(); + for (RoleEntity rel : entities) { + if (!contains(rel.getName(), defaultRoles)) { + remove.add(rel); + } else { + already.add(rel.getName()); + } + } + for (RoleEntity entity : remove) { + entities.remove(entity); + } + em.flush(); + for (String roleName : defaultRoles) { + if (!already.contains(roleName)) { + addDefaultRole(roleName); + } + } + em.flush(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof ApplicationModel)) return false; + + ApplicationModel that = (ApplicationModel) o; + return that.getId().equals(getId()); + } + + @Override + public int hashCode() { + return getId().hashCode(); + } + + public String toString() { + return getName(); + } + + ApplicationEntity getJpaEntity() { + return applicationEntity; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java new file mode 100755 index 0000000000..2e996580a5 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ClientAdapter.java @@ -0,0 +1,268 @@ +package org.keycloak.models.jpa; + +import org.keycloak.models.ClientModel; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RoleContainerModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.models.jpa.entities.ClientEntity; +import org.keycloak.models.jpa.entities.ClientUserSessionAssociationEntity; +import org.keycloak.models.jpa.entities.RoleEntity; +import org.keycloak.models.jpa.entities.ScopeMappingEntity; + +import javax.persistence.EntityManager; +import javax.persistence.Query; +import javax.persistence.TypedQuery; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public abstract class ClientAdapter implements ClientModel { + protected ClientEntity entity; + protected RealmModel realm; + protected EntityManager em; + + public ClientAdapter(RealmModel realm, ClientEntity entity, EntityManager em) { + this.realm = realm; + this.entity = entity; + this.em = em; + } + + public ClientEntity getEntity() { + return entity; + } + + @Override + public String getId() { + return entity.getId(); + } + + @Override + public RealmModel getRealm() { + return realm; + } + + @Override + public String getClientId() { + return entity.getName(); + } + + @Override + public boolean isEnabled() { + return entity.isEnabled(); + } + + @Override + public void setEnabled(boolean enabled) { + entity.setEnabled(enabled); + } + + @Override + public long getAllowedClaimsMask() { + return entity.getAllowedClaimsMask(); + } + + @Override + public void setAllowedClaimsMask(long mask) { + entity.setAllowedClaimsMask(mask); + } + + @Override + public boolean isPublicClient() { + return entity.isPublicClient(); + } + + @Override + public void setPublicClient(boolean flag) { + entity.setPublicClient(flag); + } + + @Override + public Set getWebOrigins() { + Set result = new HashSet(); + result.addAll(entity.getWebOrigins()); + return result; + } + + + + @Override + public void setWebOrigins(Set webOrigins) { + entity.setWebOrigins(webOrigins); + } + + @Override + public void addWebOrigin(String webOrigin) { + entity.getWebOrigins().add(webOrigin); + } + + @Override + public void removeWebOrigin(String webOrigin) { + entity.getWebOrigins().remove(webOrigin); + } + + @Override + public Set getRedirectUris() { + Set result = new HashSet(); + result.addAll(entity.getRedirectUris()); + return result; + } + + @Override + public void setRedirectUris(Set redirectUris) { + entity.setRedirectUris(redirectUris); + } + + @Override + public void addRedirectUri(String redirectUri) { + entity.getRedirectUris().add(redirectUri); + } + + @Override + public void removeRedirectUri(String redirectUri) { + entity.getRedirectUris().remove(redirectUri); + } + + @Override + public String getSecret() { + return entity.getSecret(); + } + + @Override + public void setSecret(String secret) { + entity.setSecret(secret); + } + + @Override + public boolean validateSecret(String secret) { + return secret.equals(entity.getSecret()); + } + + @Override + public int getNotBefore() { + return entity.getNotBefore(); + } + + @Override + public void setNotBefore(int notBefore) { + entity.setNotBefore(notBefore); + } + + @Override + public int getActiveUserSessions() { + Query query = em.createNamedQuery("getActiveClientSessions"); + query.setParameter("clientId", getId()); + Object count = query.getSingleResult(); + return ((Number)count).intValue(); + } + + @Override + public Set getUserSessions() { + Set list = new HashSet(); + TypedQuery query = em.createNamedQuery("getClientUserSessionByClient", ClientUserSessionAssociationEntity.class); + String id = getId(); + query.setParameter("clientId", id); + List results = query.getResultList(); + for (ClientUserSessionAssociationEntity entity : results) { + list.add(new UserSessionAdapter(em, realm, entity.getSession())); + } + return list; + } + + public void deleteUserSessionAssociation() { + em.createNamedQuery("removeClientUserSessionByClient").setParameter("clientId", getId()).executeUpdate(); + } + + @Override + public Set getRealmScopeMappings() { + Set roleMappings = getScopeMappings(); + + Set appRoles = new HashSet(); + for (RoleModel role : roleMappings) { + RoleContainerModel container = role.getContainer(); + if (container instanceof RealmModel) { + if (((RealmModel) container).getId().equals(realm.getId())) { + appRoles.add(role); + } + } + } + + return appRoles; + } + + + + @Override + public Set getScopeMappings() { + TypedQuery query = em.createNamedQuery("clientScopeMappingIds", String.class); + query.setParameter("client", getEntity()); + List ids = query.getResultList(); + Set roles = new HashSet(); + for (String roleId : ids) { + RoleModel role = realm.getRoleById(roleId); + if (role == null) continue; + roles.add(role); + } + return roles; + } + + @Override + public void addScopeMapping(RoleModel role) { + if (hasScope(role)) return; + ScopeMappingEntity entity = new ScopeMappingEntity(); + entity.setClient(getEntity()); + RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em); + entity.setRole(roleEntity); + em.persist(entity); + em.flush(); + em.detach(entity); + } + + @Override + public void deleteScopeMapping(RoleModel role) { + TypedQuery query = getRealmScopeMappingQuery(role); + List results = query.getResultList(); + if (results.size() == 0) return; + for (ScopeMappingEntity entity : results) { + em.remove(entity); + } + } + + protected TypedQuery getRealmScopeMappingQuery(RoleModel role) { + TypedQuery query = em.createNamedQuery("hasScope", ScopeMappingEntity.class); + query.setParameter("client", getEntity()); + RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em); + query.setParameter("role", roleEntity); + return query; + } + + @Override + public boolean hasScope(RoleModel role) { + Set roles = getScopeMappings(); + if (roles.contains(role)) return true; + + for (RoleModel mapping : roles) { + if (mapping.hasRole(role)) return true; + } + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!this.getClass().equals(o.getClass())) return false; + + ClientAdapter that = (ClientAdapter) o; + return that.getId().equals(getId()); + } + + @Override + public int hashCode() { + return entity.getId().hashCode(); + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java new file mode 100755 index 0000000000..095b3414a1 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakTransaction.java @@ -0,0 +1,53 @@ +package org.keycloak.models.jpa; + +import org.keycloak.models.KeycloakTransaction; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class JpaKeycloakTransaction implements KeycloakTransaction { + + protected EntityManager em; + + public JpaKeycloakTransaction(EntityManager em) { + this.em = em; + } + + @Override + public void begin() { + em.getTransaction().begin(); + } + + @Override + public void commit() { + try { + em.getTransaction().commit(); + } catch (PersistenceException e) { + throw PersistenceExceptionConverter.convert(e.getCause() != null ? e.getCause() : e); + } + } + + @Override + public void rollback() { + em.getTransaction().rollback(); + } + + @Override + public void setRollbackOnly() { + em.getTransaction().setRollbackOnly(); + } + + @Override + public boolean getRollbackOnly() { + return em.getTransaction().getRollbackOnly(); + } + + @Override + public boolean isActive() { + return em.getTransaction().isActive(); + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java new file mode 100755 index 0000000000..940e0671ff --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProvider.java @@ -0,0 +1,400 @@ +package org.keycloak.models.jpa; + +import org.keycloak.models.*; +import org.keycloak.models.jpa.entities.*; +import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.util.Time; + +import javax.persistence.EntityManager; +import javax.persistence.Query; +import javax.persistence.TypedQuery; +import java.lang.reflect.Proxy; +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 Bill Burke + * @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; + this.em = PersistenceExceptionConverter.create(em); + } + + @Override + public KeycloakTransaction getTransaction() { + return new JpaKeycloakTransaction(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 getRealms() { + TypedQuery query = em.createNamedQuery("getAllRealms", RealmEntity.class); + List entities = query.getResultList(); + List realms = new ArrayList(); + for (RealmEntity entity : entities) { + realms.add(new RealmAdapter(session, em, entity)); + } + return realms; + } + + @Override + public RealmModel getRealmByName(String name) { + TypedQuery query = em.createNamedQuery("getRealmByName", RealmEntity.class); + query.setParameter("name", name); + List 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 query = em.createNamedQuery("getRealmUserById", UserEntity.class); + query.setParameter("id", id); + RealmEntity realm = em.getReference(RealmEntity.class, realmModel.getId()); + query.setParameter("realm", realm); + List 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 query = em.createNamedQuery("getRealmUserByUsername", UserEntity.class); + query.setParameter("username", username); + RealmEntity realm = em.getReference(RealmEntity.class, realmModel.getId()); + query.setParameter("realm", realm); + List 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 query = em.createNamedQuery("getRealmUserByEmail", UserEntity.class); + query.setParameter("email", email); + RealmEntity realm = em.getReference(RealmEntity.class, realmModel.getId()); + query.setParameter("realm", realm); + List 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); + adapter.removeUserSessions(); + for (ApplicationEntity a : new LinkedList(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() { + if (em.getTransaction().isActive()) em.getTransaction().rollback(); + if (em.isOpen()) em.close(); + } + + @Override + public void removeAllData() { + // Should be sufficient to delete all realms. Rest data should be removed in cascade + List realms = getRealms(); + for (RealmModel realm : realms) { + removeRealm(realm.getId()); + } + } + + @Override + public UserModel getUserBySocialLink(SocialLinkModel socialLink, RealmModel realm) { + TypedQuery 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 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 getUsers(RealmModel realm) { + TypedQuery 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 results = query.getResultList(); + List users = new ArrayList(); + for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity)); + return users; + } + + @Override + public List searchForUser(String search, RealmModel realm) { + TypedQuery 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 results = query.getResultList(); + List users = new ArrayList(); + for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity)); + return users; + } + + @Override + public List searchForUserByAttributes(Map attributes, RealmModel realm) { + StringBuilder builder = new StringBuilder("select u from UserEntity u"); + boolean first = true; + for (Map.Entry 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 query = em.createQuery(q, UserEntity.class); + RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId()); + query.setParameter("realm", realmEntity); + List results = query.getResultList(); + List users = new ArrayList(); + for (UserEntity entity : results) users.add(new UserAdapter(realm, em, entity)); + return users; + } + + private SocialLinkEntity findSocialLink(UserModel user, String socialProvider) { + TypedQuery query = em.createNamedQuery("findSocialLinkByUserAndProvider", SocialLinkEntity.class); + UserEntity userEntity = em.getReference(UserEntity.class, user.getId()); + query.setParameter("user", userEntity); + query.setParameter("socialProvider", socialProvider); + List results = query.getResultList(); + return results.size() > 0 ? results.get(0) : null; + } + + + @Override + public Set getSocialLinks(UserModel user, RealmModel realm) { + TypedQuery query = em.createNamedQuery("findSocialLinkByUser", SocialLinkEntity.class); + UserEntity userEntity = em.getReference(UserEntity.class, user.getId()); + query.setParameter("user", userEntity); + List results = query.getResultList(); + Set set = new HashSet(); + 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); + } + + @Override + public UsernameLoginFailureModel getUserLoginFailure(String username, RealmModel realm) { + String id = username + "-" + realm.getId(); + UsernameLoginFailureEntity entity = em.find(UsernameLoginFailureEntity.class, id); + if (entity == null) return null; + return new UsernameLoginFailureAdapter(entity); + } + + @Override + public UsernameLoginFailureModel addUserLoginFailure(String username, RealmModel realm) { + UsernameLoginFailureModel model = getUserLoginFailure(username, realm); + if (model != null) return model; + String id = username + "-" + realm.getId(); + UsernameLoginFailureEntity entity = new UsernameLoginFailureEntity(); + entity.setId(id); + entity.setUsername(username); + RealmEntity realmEntity = em.getReference(RealmEntity.class, realm.getId()); + entity.setRealm(realmEntity); + em.persist(entity); + return new UsernameLoginFailureAdapter(entity); + } + + @Override + public List getAllUserLoginFailures(RealmModel realm) { + TypedQuery query = em.createNamedQuery("getAllFailures", UsernameLoginFailureEntity.class); + List entities = query.getResultList(); + List models = new ArrayList(); + for (UsernameLoginFailureEntity entity : entities) { + models.add(new UsernameLoginFailureAdapter(entity)); + } + return models; + } + + @Override + public UserSessionModel createUserSession(RealmModel realm, UserModel user, String ipAddress) { + UserSessionEntity entity = new UserSessionEntity(); + entity.setRealmId(realm.getId()); + entity.setUserId(user.getId()); + entity.setIpAddress(ipAddress); + + int currentTime = Time.currentTime(); + + entity.setStarted(currentTime); + entity.setLastSessionRefresh(currentTime); + + em.persist(entity); + return new UserSessionAdapter(em, realm, entity); + } + + @Override + public UserSessionModel getUserSession(String id, RealmModel realm) { + UserSessionEntity entity = em.find(UserSessionEntity.class, id); + return entity != null ? new UserSessionAdapter(em, realm, entity) : null; + } + + @Override + public List getUserSessions(UserModel user, RealmModel realm) { + List sessions = new LinkedList(); + for (UserSessionEntity e : em.createNamedQuery("getUserSessionByUser", UserSessionEntity.class) + .setParameter("userId", user.getId()).getResultList()) { + sessions.add(new UserSessionAdapter(em, realm, e)); + } + return sessions; + } + + @Override + public Set getUserSessions(RealmModel realm, ClientModel client) { + Set list = new HashSet(); + TypedQuery query = em.createNamedQuery("getClientUserSessionByClient", ClientUserSessionAssociationEntity.class); + String id = client.getId(); + query.setParameter("clientId", id); + List results = query.getResultList(); + for (ClientUserSessionAssociationEntity entity : results) { + list.add(new UserSessionAdapter(em, realm, entity.getSession())); + } + return list; + } + + @Override + public int getActiveUserSessions(RealmModel realm, ClientModel client) { + Query query = em.createNamedQuery("getActiveClientSessions"); + query.setParameter("clientId", client.getId()); + Object count = query.getSingleResult(); + return ((Number)count).intValue(); + } + + @Override + public void removeUserSession(UserSessionModel session) { + em.remove(((UserSessionAdapter) session).getEntity()); + } + + @Override + public void removeUserSessions(RealmModel realm, UserModel user) { + em.createNamedQuery("removeClientUserSessionByUser").setParameter("userId", user.getId()).executeUpdate(); + em.createNamedQuery("removeUserSessionByUser").setParameter("userId", user.getId()).executeUpdate(); + } + + @Override + public void removeExpiredUserSessions(RealmModel realm) { + TypedQuery query = em.createNamedQuery("getUserSessionExpired", UserSessionEntity.class) + .setParameter("maxTime", Time.currentTime() - realm.getSsoSessionMaxLifespan()) + .setParameter("idleTime", Time.currentTime() - realm.getSsoSessionIdleTimeout()); + List results = query.getResultList(); + for (UserSessionEntity entity : results) { + em.remove(entity); + } + } + + @Override + public void removeUserSessions(RealmModel realm) { + em.createNamedQuery("removeClientUserSessionByRealm").setParameter("realmId", realm.getId()).executeUpdate(); + em.createNamedQuery("removeRealmUserSessions").setParameter("realmId", realm.getId()).executeUpdate(); + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProviderFactory.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProviderFactory.java new file mode 100755 index 0000000000..ad4e6dce46 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaModelProviderFactory.java @@ -0,0 +1,40 @@ +package org.keycloak.models.jpa; + +import org.keycloak.Config; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelProvider; +import org.keycloak.models.ModelProviderFactory; +import org.keycloak.util.JpaUtils; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class JpaModelProviderFactory implements ModelProviderFactory { + + protected EntityManagerFactory emf; + + @Override + public void init(Config.Scope config) { + emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store", JpaUtils.getHibernateProperties()); + } + + @Override + public String getId() { + return "jpa"; + } + + @Override + public ModelProvider create(KeycloakSession session) { + return new JpaModelProvider(session, emf.createEntityManager()); + } + + @Override + public void close() { + emf.close(); + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java new file mode 100755 index 0000000000..c890c9f922 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/OAuthClientAdapter.java @@ -0,0 +1,56 @@ +package org.keycloak.models.jpa; + +import org.keycloak.models.ApplicationModel; +import org.keycloak.models.OAuthClientModel; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.jpa.entities.OAuthClientEntity; + +import javax.persistence.EntityManager; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class OAuthClientAdapter extends ClientAdapter implements OAuthClientModel { + + protected final OAuthClientEntity oAuthClientEntity; + + public OAuthClientAdapter(RealmModel realm, OAuthClientEntity entity, EntityManager em) { + super(realm, entity, em); + oAuthClientEntity = entity; + } + + @Override + public void setClientId(String id) { + entity.setName(id); + + } + + @Override + public boolean isDirectGrantsOnly() { + return oAuthClientEntity.isDirectGrantsOnly(); + } + + @Override + public void setDirectGrantsOnly(boolean flag) { + oAuthClientEntity.setDirectGrantsOnly(flag); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof OAuthClientModel)) return false; + + OAuthClientModel that = (OAuthClientModel) o; + return that.getId().equals(getId()); + } + + @Override + public int hashCode() { + return getId().hashCode(); + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/PersistenceExceptionConverter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/PersistenceExceptionConverter.java new file mode 100644 index 0000000000..dfa5053822 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/PersistenceExceptionConverter.java @@ -0,0 +1,49 @@ +package org.keycloak.models.jpa; + +import org.hibernate.exception.ConstraintViolationException; +import org.keycloak.models.ModelException; +import org.keycloak.models.ModelDuplicateException; + +import javax.persistence.EntityExistsException; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * @author Stian Thorgersen + */ +public class PersistenceExceptionConverter implements InvocationHandler { + + private EntityManager em; + + public static EntityManager create(EntityManager em) { + return (EntityManager) Proxy.newProxyInstance(EntityManager.class.getClassLoader(), new Class[]{EntityManager.class}, new PersistenceExceptionConverter(em)); + } + + private PersistenceExceptionConverter(EntityManager em) { + this.em = em; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + try { + return method.invoke(em, args); + } catch (InvocationTargetException e) { + throw convert(e.getCause()); + } + } + + public static ModelException convert(Throwable t) { + if (t.getCause() != null && t.getCause() instanceof ConstraintViolationException) { + throw new ModelDuplicateException(t); + } if (t instanceof EntityExistsException) { + throw new ModelDuplicateException(t); + } else { + throw new ModelException(t); + } + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java new file mode 100755 index 0000000000..23602ec49c --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java @@ -0,0 +1,1142 @@ +package org.keycloak.models.jpa; + +import org.keycloak.models.AuthenticationLinkModel; +import org.keycloak.models.AuthenticationProviderModel; +import org.keycloak.models.ClientModel; +import org.keycloak.models.CredentialValidation; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelDuplicateException; +import org.keycloak.models.RoleContainerModel; +import org.keycloak.models.UserCredentialValueModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.models.UsernameLoginFailureModel; +import org.keycloak.models.jpa.entities.ApplicationEntity; +import org.keycloak.models.jpa.entities.AuthenticationLinkEntity; +import org.keycloak.models.jpa.entities.AuthenticationProviderEntity; +import org.keycloak.models.jpa.entities.OAuthClientEntity; +import org.keycloak.models.jpa.entities.RealmEntity; +import org.keycloak.models.jpa.entities.RequiredCredentialEntity; +import org.keycloak.models.jpa.entities.RoleEntity; +import org.keycloak.models.jpa.entities.ScopeMappingEntity; +import org.keycloak.models.jpa.entities.SocialLinkEntity; +import org.keycloak.models.jpa.entities.UserEntity; +import org.keycloak.models.jpa.entities.UserSessionEntity; +import org.keycloak.models.jpa.entities.UserRoleMappingEntity; +import org.keycloak.models.jpa.entities.UsernameLoginFailureEntity; +import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.models.utils.Pbkdf2PasswordEncoder; +import org.keycloak.models.ApplicationModel; +import org.keycloak.models.OAuthClientModel; +import org.keycloak.models.PasswordPolicy; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RequiredCredentialModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.SocialLinkModel; +import org.keycloak.models.UserCredentialModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.utils.TimeBasedOTP; +import org.keycloak.util.Time; + +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.*; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class RealmAdapter implements RealmModel { + protected RealmEntity realm; + protected EntityManager em; + protected volatile transient PublicKey publicKey; + protected volatile transient PrivateKey privateKey; + protected KeycloakSession session; + private PasswordPolicy passwordPolicy; + + public RealmAdapter(KeycloakSession session, EntityManager em, RealmEntity realm) { + this.session = session; + this.em = em; + this.realm = realm; + } + + public RealmEntity getEntity() { + return realm; + } + + @Override + public String getId() { + return realm.getId(); + } + + @Override + public String getName() { + return realm.getName(); + } + + @Override + public void setName(String name) { + realm.setName(name); + em.flush(); + } + + @Override + public boolean isEnabled() { + return realm.isEnabled(); + } + + @Override + public void setEnabled(boolean enabled) { + realm.setEnabled(enabled); + em.flush(); + } + + @Override + public boolean isSslNotRequired() { + return realm.isSslNotRequired(); + } + + @Override + public void setSslNotRequired(boolean sslNotRequired) { + realm.setSslNotRequired(sslNotRequired); + em.flush(); + } + + @Override + public boolean isPasswordCredentialGrantAllowed() { + return realm.isPasswordCredentialGrantAllowed(); + } + + @Override + public void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed) { + realm.setPasswordCredentialGrantAllowed(passwordCredentialGrantAllowed); + em.flush(); + } + + @Override + public boolean isRegistrationAllowed() { + return realm.isRegistrationAllowed(); + } + + @Override + public void setRegistrationAllowed(boolean registrationAllowed) { + realm.setRegistrationAllowed(registrationAllowed); + em.flush(); + } + + @Override + public boolean isRememberMe() { + return realm.isRememberMe(); + } + + @Override + public void setRememberMe(boolean rememberMe) { + realm.setRememberMe(rememberMe); + em.flush(); + } + + @Override + public boolean isBruteForceProtected() { + return realm.isBruteForceProtected(); + } + + @Override + public void setBruteForceProtected(boolean value) { + realm.setBruteForceProtected(value); + } + + @Override + public int getMaxFailureWaitSeconds() { + return realm.getMaxFailureWaitSeconds(); + } + + @Override + public void setMaxFailureWaitSeconds(int val) { + realm.setMaxFailureWaitSeconds(val); + } + + @Override + public int getWaitIncrementSeconds() { + return realm.getWaitIncrementSeconds(); + } + + @Override + public void setWaitIncrementSeconds(int val) { + realm.setWaitIncrementSeconds(val); + } + + @Override + public long getQuickLoginCheckMilliSeconds() { + return realm.getQuickLoginCheckMilliSeconds(); + } + + @Override + public void setQuickLoginCheckMilliSeconds(long val) { + realm.setQuickLoginCheckMilliSeconds(val); + } + + @Override + public int getMinimumQuickLoginWaitSeconds() { + return realm.getMinimumQuickLoginWaitSeconds(); + } + + @Override + public void setMinimumQuickLoginWaitSeconds(int val) { + realm.setMinimumQuickLoginWaitSeconds(val); + } + + @Override + public int getMaxDeltaTimeSeconds() { + return realm.getMaxDeltaTimeSeconds(); + } + + @Override + public void setMaxDeltaTimeSeconds(int val) { + realm.setMaxDeltaTimeSeconds(val); + } + + @Override + public int getFailureFactor() { + return realm.getFailureFactor(); + } + + @Override + public void setFailureFactor(int failureFactor) { + realm.setFailureFactor(failureFactor); + } + + @Override + public boolean isVerifyEmail() { + return realm.isVerifyEmail(); + } + + @Override + public void setVerifyEmail(boolean verifyEmail) { + realm.setVerifyEmail(verifyEmail); + em.flush(); + } + + @Override + public boolean isResetPasswordAllowed() { + return realm.isResetPasswordAllowed(); + } + + @Override + public void setResetPasswordAllowed(boolean resetPasswordAllowed) { + realm.setResetPasswordAllowed(resetPasswordAllowed); + em.flush(); + } + + @Override + public int getNotBefore() { + return realm.getNotBefore(); + } + + @Override + public void setNotBefore(int notBefore) { + realm.setNotBefore(notBefore); + } + + @Override + public int getAccessTokenLifespan() { + return realm.getAccessTokenLifespan(); + } + + @Override + public void setAccessTokenLifespan(int tokenLifespan) { + realm.setAccessTokenLifespan(tokenLifespan); + em.flush(); + } + + @Override + public int getSsoSessionIdleTimeout() { + return realm.getSsoSessionIdleTimeout(); + } + + @Override + public void setSsoSessionIdleTimeout(int seconds) { + realm.setSsoSessionIdleTimeout(seconds); + } + + @Override + public int getSsoSessionMaxLifespan() { + return realm.getSsoSessionMaxLifespan(); + } + + @Override + public void setSsoSessionMaxLifespan(int seconds) { + realm.setSsoSessionMaxLifespan(seconds); + } + + @Override + public int getAccessCodeLifespan() { + return realm.getAccessCodeLifespan(); + } + + @Override + public void setAccessCodeLifespan(int accessCodeLifespan) { + realm.setAccessCodeLifespan(accessCodeLifespan); + em.flush(); + } + + @Override + public int getAccessCodeLifespanUserAction() { + return realm.getAccessCodeLifespanUserAction(); + } + + @Override + public void setAccessCodeLifespanUserAction(int accessCodeLifespanUserAction) { + realm.setAccessCodeLifespanUserAction(accessCodeLifespanUserAction); + em.flush(); + } + + @Override + public String getPublicKeyPem() { + return realm.getPublicKeyPem(); + } + + @Override + public void setPublicKeyPem(String publicKeyPem) { + realm.setPublicKeyPem(publicKeyPem); + em.flush(); + } + + @Override + public String getPrivateKeyPem() { + return realm.getPrivateKeyPem(); + } + + @Override + public void setPrivateKeyPem(String privateKeyPem) { + realm.setPrivateKeyPem(privateKeyPem); + em.flush(); + } + + @Override + public PublicKey getPublicKey() { + if (publicKey != null) return publicKey; + publicKey = KeycloakModelUtils.getPublicKey(getPublicKeyPem()); + return publicKey; + } + + @Override + public void setPublicKey(PublicKey publicKey) { + this.publicKey = publicKey; + String publicKeyPem = KeycloakModelUtils.getPemFromKey(publicKey); + setPublicKeyPem(publicKeyPem); + } + + @Override + public PrivateKey getPrivateKey() { + if (privateKey != null) return privateKey; + privateKey = KeycloakModelUtils.getPrivateKey(getPrivateKeyPem()); + return privateKey; + } + + @Override + public void setPrivateKey(PrivateKey privateKey) { + this.privateKey = privateKey; + String privateKeyPem = KeycloakModelUtils.getPemFromKey(privateKey); + setPrivateKeyPem(privateKeyPem); + } + + protected RequiredCredentialModel initRequiredCredentialModel(String type) { + RequiredCredentialModel model = RequiredCredentialModel.BUILT_IN.get(type); + if (model == null) { + throw new RuntimeException("Unknown credential type " + type); + } + return model; + } + + @Override + public void addRequiredCredential(String type) { + RequiredCredentialModel model = initRequiredCredentialModel(type); + addRequiredCredential(model); + em.flush(); + } + + public void addRequiredCredential(RequiredCredentialModel model) { + RequiredCredentialEntity entity = new RequiredCredentialEntity(); + entity.setInput(model.isInput()); + entity.setSecret(model.isSecret()); + entity.setType(model.getType()); + entity.setFormLabel(model.getFormLabel()); + em.persist(entity); + realm.getRequiredCredentials().add(entity); + em.flush(); + } + + @Override + public void updateRequiredCredentials(Set creds) { + Collection relationships = realm.getRequiredCredentials(); + if (relationships == null) relationships = new ArrayList(); + + Set already = new HashSet(); + List remove = new ArrayList(); + for (RequiredCredentialEntity rel : relationships) { + if (!creds.contains(rel.getType())) { + remove.add(rel); + } else { + already.add(rel.getType()); + } + } + for (RequiredCredentialEntity entity : remove) { + relationships.remove(entity); + em.remove(entity); + } + for (String cred : creds) { + if (!already.contains(cred)) { + addRequiredCredential(cred); + } + } + em.flush(); + } + + + @Override + public List getRequiredCredentials() { + List requiredCredentialModels = new ArrayList(); + Collection entities = realm.getRequiredCredentials(); + if (entities == null) return requiredCredentialModels; + for (RequiredCredentialEntity entity : entities) { + RequiredCredentialModel model = new RequiredCredentialModel(); + model.setFormLabel(entity.getFormLabel()); + model.setType(entity.getType()); + model.setSecret(entity.isSecret()); + model.setInput(entity.isInput()); + requiredCredentialModels.add(model); + } + return requiredCredentialModels; //To change body of implemented methods use File | Settings | File Templates. + } + + + @Override + public UserModel getUser(String name) { + return session.getUserByUsername(name, this); + } + + @Override + public UsernameLoginFailureModel getUserLoginFailure(String username) { + return session.getUserLoginFailure(username, this); + } + + @Override + public UsernameLoginFailureModel addUserLoginFailure(String username) { + return session.addUserLoginFailure(username, this); + } + + @Override + public List getAllUserLoginFailures() { + return session.getAllUserLoginFailures(this); + } + + @Override + public UserModel getUserByEmail(String email) { + return session.getUserByEmail(email, this); + } + + @Override + public UserModel getUserById(String id) { + return session.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 query = em.createNamedQuery("getRealmUserByUsername", UserEntity.class); + query.setParameter("username", name); + query.setParameter("realm", realm); + List results = query.getResultList(); + if (results.size() == 0) return false; + removeUser(results.get(0)); + return true; + } + + private void removeUser(UserEntity user) { + em.createNamedQuery("removeClientUserSessionByUser").setParameter("userId", user.getId()).executeUpdate(); + em.createNamedQuery("removeUserSessionByUser").setParameter("userId", user.getId()).executeUpdate(); + + em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where user = :user").setParameter("user", user).executeUpdate(); + em.createQuery("delete from " + SocialLinkEntity.class.getSimpleName() + " where user = :user").setParameter("user", user).executeUpdate(); + if (user.getAuthenticationLink() != null) { + em.remove(user.getAuthenticationLink()); + } + em.remove(user); + } + + @Override + public List getDefaultRoles() { + Collection entities = realm.getDefaultRoles(); + List roles = new ArrayList(); + if (entities == null) return roles; + for (RoleEntity entity : entities) { + roles.add(entity.getName()); + } + return roles; + } + + @Override + public void addDefaultRole(String name) { + RoleModel role = getRole(name); + if (role == null) { + role = addRole(name); + } + Collection entities = realm.getDefaultRoles(); + for (RoleEntity entity : entities) { + if (entity.getId().equals(role.getId())) { + return; + } + } + RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em); + entities.add(roleEntity); + em.flush(); + } + + public static boolean contains(String str, String[] array) { + for (String s : array) { + if (str.equals(s)) return true; + } + return false; + } + + @Override + public void updateDefaultRoles(String[] defaultRoles) { + Collection entities = realm.getDefaultRoles(); + Set already = new HashSet(); + List remove = new ArrayList(); + for (RoleEntity rel : entities) { + if (!contains(rel.getName(), defaultRoles)) { + remove.add(rel); + } else { + already.add(rel.getName()); + } + } + for (RoleEntity entity : remove) { + entities.remove(entity); + } + em.flush(); + for (String roleName : defaultRoles) { + if (!already.contains(roleName)) { + addDefaultRole(roleName); + } + } + em.flush(); + } + + @Override + public ClientModel findClient(String clientId) { + ClientModel model = getApplicationByName(clientId); + if (model != null) return model; + return getOAuthClient(clientId); + } + + @Override + public ClientModel findClientById(String id) { + ClientModel model = getApplicationById(id); + if (model != null) return model; + return getOAuthClientById(id); + } + + @Override + public Map getApplicationNameMap() { + Map map = new HashMap(); + for (ApplicationModel app : getApplications()) { + map.put(app.getName(), app); + } + return map; //To change body of implemented methods use File | Settings | File Templates. + } + + @Override + public List getApplications() { + List list = new ArrayList(); + if (realm.getApplications() == null) return list; + for (ApplicationEntity entity : realm.getApplications()) { + list.add(new ApplicationAdapter(this, em, entity)); + } + return list; + } + + @Override + public ApplicationModel addApplication(String name) { + return this.addApplication(KeycloakModelUtils.generateId(), name); + } + + @Override + public ApplicationModel addApplication(String id, String name) { + ApplicationEntity applicationData = new ApplicationEntity(); + applicationData.setId(id); + applicationData.setName(name); + applicationData.setEnabled(true); + applicationData.setRealm(realm); + realm.getApplications().add(applicationData); + em.persist(applicationData); + em.flush(); + ApplicationModel resource = new ApplicationAdapter(this, em, applicationData); + em.flush(); + return resource; + } + + @Override + public boolean removeApplication(String id) { + if (id == null) return false; + ApplicationModel application = getApplicationById(id); + if (application == null) return false; + + em.createNamedQuery("removeClientUserSessionByClient").setParameter("clientId", application.getId()).executeUpdate(); + + for (RoleModel role : application.getRoles()) { + application.removeRole(role); + } + + ApplicationEntity applicationEntity = null; + Iterator it = realm.getApplications().iterator(); + while (it.hasNext()) { + ApplicationEntity ae = it.next(); + if (ae.getId().equals(id)) { + applicationEntity = ae; + it.remove(); + break; + } + } + for (ApplicationEntity a : realm.getApplications()) { + if (a.getId().equals(id)) { + applicationEntity = a; + } + } + if (application == null) { + return false; + } + em.remove(applicationEntity); + em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where client = :client").setParameter("client", applicationEntity).executeUpdate(); + + return true; + } + + @Override + public ApplicationModel getApplicationById(String id) { + return session.getApplicationById(id, this); + } + + @Override + public ApplicationModel getApplicationByName(String name) { + return getApplicationNameMap().get(name); + } + + @Override + public UserModel getUserBySocialLink(SocialLinkModel socialLink) { + return session.getUserBySocialLink(socialLink, this); + } + + @Override + public Set getSocialLinks(UserModel user) { + return session.getSocialLinks(user, this); + } + + @Override + public SocialLinkModel getSocialLink(UserModel user, String socialProvider) { + return session.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 query = em.createNamedQuery("findSocialLinkByUserAndProvider", SocialLinkEntity.class); + UserEntity userEntity = em.getReference(UserEntity.class, user.getId()); + query.setParameter("user", userEntity); + query.setParameter("socialProvider", socialProvider); + List results = query.getResultList(); + return results.size() > 0 ? results.get(0) : null; + } + + + @Override + public boolean removeSocialLink(UserModel user, String socialProvider) { + SocialLinkEntity entity = findSocialLink(user, socialProvider); + if (entity != null) { + em.remove(entity); + em.flush(); + return true; + } else { + return false; + } + } + + + @Override + public boolean isSocial() { + return realm.isSocial(); + } + + @Override + public void setSocial(boolean social) { + realm.setSocial(social); + em.flush(); + } + + @Override + public boolean isUpdateProfileOnInitialSocialLogin() { + return realm.isUpdateProfileOnInitialSocialLogin(); + } + + @Override + public void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin) { + realm.setUpdateProfileOnInitialSocialLogin(updateProfileOnInitialSocialLogin); + em.flush(); + } + + @Override + public List getUsers() { + return session.getUsers(this); + } + + @Override + public List searchForUser(String search) { + return session.searchForUser(search, this); + } + + @Override + public List searchForUserByAttributes(Map attributes) { + return session.searchForUserByAttributes(attributes, this); + } + + @Override + public OAuthClientModel addOAuthClient(String name) { + return this.addOAuthClient(KeycloakModelUtils.generateId(), name); + } + + @Override + public OAuthClientModel addOAuthClient(String id, String name) { + OAuthClientEntity data = new OAuthClientEntity(); + data.setId(id); + data.setEnabled(true); + data.setName(name); + data.setRealm(realm); + em.persist(data); + em.flush(); + return new OAuthClientAdapter(this, data, em); + } + + @Override + public boolean removeOAuthClient(String id) { + OAuthClientModel oauth = getOAuthClientById(id); + if (oauth == null) return false; + ((OAuthClientAdapter)oauth).deleteUserSessionAssociation(); + OAuthClientEntity client = (OAuthClientEntity) ((OAuthClientAdapter) oauth).getEntity(); + em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where client = :client").setParameter("client", client).executeUpdate(); + em.remove(client); + return true; + } + + + @Override + public OAuthClientModel getOAuthClient(String name) { + TypedQuery query = em.createNamedQuery("findOAuthClientByName", OAuthClientEntity.class); + query.setParameter("name", name); + query.setParameter("realm", realm); + List entities = query.getResultList(); + if (entities.size() == 0) return null; + return new OAuthClientAdapter(this, entities.get(0), em); + } + + @Override + public OAuthClientModel getOAuthClientById(String id) { + return session.getOAuthClientById(id, this); + } + + + @Override + public List getOAuthClients() { + TypedQuery query = em.createNamedQuery("findOAuthClientByRealm", OAuthClientEntity.class); + query.setParameter("realm", realm); + List entities = query.getResultList(); + List list = new ArrayList(); + for (OAuthClientEntity entity : entities) list.add(new OAuthClientAdapter(this, entity, em)); + return list; + } + + @Override + public Map getSmtpConfig() { + return realm.getSmtpConfig(); + } + + @Override + public void setSmtpConfig(Map smtpConfig) { + realm.setSmtpConfig(smtpConfig); + em.flush(); + } + + @Override + public Map getSocialConfig() { + return realm.getSocialConfig(); + } + + @Override + public void setSocialConfig(Map socialConfig) { + realm.setSocialConfig(socialConfig); + em.flush(); + } + + @Override + public Map getLdapServerConfig() { + return realm.getLdapServerConfig(); + } + + @Override + public void setLdapServerConfig(Map ldapServerConfig) { + realm.setLdapServerConfig(ldapServerConfig); + em.flush(); + } + + @Override + public List getAuthenticationProviders() { + List entities = realm.getAuthenticationProviders(); + List copy = new ArrayList(); + for (AuthenticationProviderEntity entity : entities) { + copy.add(entity); + + } + Collections.sort(copy, new Comparator() { + + @Override + public int compare(AuthenticationProviderEntity o1, AuthenticationProviderEntity o2) { + return o1.getPriority() - o2.getPriority(); + } + + }); + List result = new ArrayList(); + for (AuthenticationProviderEntity entity : copy) { + result.add(new AuthenticationProviderModel(entity.getProviderName(), entity.isPasswordUpdateSupported(), entity.getConfig())); + } + + return result; + } + + @Override + public void setAuthenticationProviders(List authenticationProviders) { + List newEntities = new ArrayList(); + int counter = 1; + for (AuthenticationProviderModel model : authenticationProviders) { + AuthenticationProviderEntity entity = new AuthenticationProviderEntity(); + entity.setProviderName(model.getProviderName()); + entity.setPasswordUpdateSupported(model.isPasswordUpdateSupported()); + entity.setConfig(model.getConfig()); + entity.setPriority(counter++); + newEntities.add(entity); + } + + // Remove all existing first + Collection existing = realm.getAuthenticationProviders(); + Collection copy = new ArrayList(existing); + for (AuthenticationProviderEntity apToRemove : copy) { + existing.remove(apToRemove); + em.remove(apToRemove); + } + + // Now create all new providers + for (AuthenticationProviderEntity apToAdd : newEntities) { + existing.add(apToAdd); + em.persist(apToAdd); + } + + em.flush(); + } + + @Override + public RoleModel getRole(String name) { + TypedQuery query = em.createNamedQuery("getRealmRoleByName", RoleEntity.class); + query.setParameter("name", name); + query.setParameter("realm", realm); + List roles = query.getResultList(); + if (roles.size() == 0) return null; + return new RoleAdapter(this, em, roles.get(0)); + } + + @Override + public RoleModel addRole(String name) { + return this.addRole(KeycloakModelUtils.generateId(), name); + } + + @Override + public RoleModel addRole(String id, String name) { + RoleEntity entity = new RoleEntity(); + entity.setId(id); + entity.setName(name); + entity.setRealm(realm); + entity.setRealmId(realm.getId()); + realm.getRoles().add(entity); + em.persist(entity); + em.flush(); + return new RoleAdapter(this, em, entity); + } + + @Override + public boolean removeRole(RoleModel role) { + if (role == null) { + return false; + } + if (!role.getContainer().equals(this)) return false; + + RoleEntity roleEntity = RoleAdapter.toRoleEntity(role, em); + realm.getRoles().remove(role); + realm.getDefaultRoles().remove(role); + + em.createNativeQuery("delete from CompositeRole where childRole = :role").setParameter("role", roleEntity).executeUpdate(); + em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate(); + em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate(); + + em.remove(roleEntity); + + return true; + } + + @Override + public Set getRoles() { + Set list = new HashSet(); + Collection roles = realm.getRoles(); + if (roles == null) return list; + for (RoleEntity entity : roles) { + list.add(new RoleAdapter(this, em, entity)); + } + return list; + } + + @Override + public RoleModel getRoleById(String id) { + return session.getRoleById(id, this); + } + + @Override + public boolean removeRoleById(String id) { + RoleModel role = getRoleById(id); + if (role == null) return false; + return role.getContainer().removeRole(role); + } + + @Override + public boolean validatePassword(UserModel user, String password) { + return CredentialValidation.validatePassword(this, user, password); + } + + @Override + public boolean validateTOTP(UserModel user, String password, String token) { + if (!validatePassword(user, password)) return false; + for (UserCredentialValueModel cred : user.getCredentialsDirectly()) { + if (cred.getType().equals(UserCredentialModel.TOTP)) { + return new TimeBasedOTP().validate(token, cred.getValue().getBytes()); + } + } + return false; + } + + @Override + public PasswordPolicy getPasswordPolicy() { + if (passwordPolicy == null) { + passwordPolicy = new PasswordPolicy(realm.getPasswordPolicy()); + } + return passwordPolicy; + } + + @Override + public void setPasswordPolicy(PasswordPolicy policy) { + this.passwordPolicy = policy; + realm.setPasswordPolicy(policy.toString()); + em.flush(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof RealmModel)) return false; + + RealmModel that = (RealmModel) o; + return that.getId().equals(getId()); + } + + @Override + public int hashCode() { + return getId().hashCode(); + } + + @Override + public String getLoginTheme() { + return realm.getLoginTheme(); + } + + @Override + public void setLoginTheme(String name) { + realm.setLoginTheme(name); + em.flush(); + } + + @Override + public String getAccountTheme() { + return realm.getAccountTheme(); + } + + @Override + public void setAccountTheme(String name) { + realm.setAccountTheme(name); + em.flush(); + } + + @Override + public String getAdminTheme() { + return realm.getAdminTheme(); + } + + @Override + public void setAdminTheme(String name) { + realm.setAdminTheme(name); + em.flush(); + } + + @Override + public String getEmailTheme() { + return realm.getEmailTheme(); + } + + @Override + public void setEmailTheme(String name) { + realm.setEmailTheme(name); + em.flush(); + } + + @Override + public boolean isAuditEnabled() { + return realm.isAuditEnabled(); + } + + @Override + public void setAuditEnabled(boolean enabled) { + realm.setAuditEnabled(enabled); + em.flush(); + } + + @Override + public long getAuditExpiration() { + return realm.getAuditExpiration(); + } + + @Override + public void setAuditExpiration(long expiration) { + realm.setAuditExpiration(expiration); + em.flush(); + } + + @Override + public Set getAuditListeners() { + return realm.getAuditListeners(); + } + + @Override + public void setAuditListeners(Set listeners) { + realm.setAuditListeners(listeners); + em.flush(); + } + + @Override + public ApplicationModel getMasterAdminApp() { + return new ApplicationAdapter(this, em, realm.getMasterAdminApp()); + } + + @Override + public void setMasterAdminApp(ApplicationModel app) { + realm.setMasterAdminApp(((ApplicationAdapter) app).getJpaEntity()); + em.flush(); + } + + @Override + public UserSessionModel createUserSession(UserModel user, String ipAddress) { + return session.createUserSession(this, user, ipAddress); + } + + @Override + public UserSessionModel getUserSession(String id) { + return session.getUserSession(id, this); + } + + @Override + public List getUserSessions(UserModel user) { + return session.getUserSessions(user, this); + } + + @Override + public void removeUserSession(UserSessionModel session) { + this.session.removeUserSession(session); + } + + @Override + public void removeUserSessions() { + session.removeUserSessions(this); + + } + + @Override + public void removeUserSessions(UserModel user) { + session.removeUserSessions(this, user); + } + + @Override + public void removeExpiredUserSessions() { + session.removeExpiredUserSessions(this); + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java new file mode 100755 index 0000000000..28a1f47d02 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RoleAdapter.java @@ -0,0 +1,135 @@ +package org.keycloak.models.jpa; + +import org.keycloak.models.RealmModel; +import org.keycloak.models.RoleContainerModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.jpa.entities.RoleEntity; +import org.keycloak.models.utils.KeycloakModelUtils; + +import javax.persistence.EntityManager; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class RoleAdapter implements RoleModel { + protected RoleEntity role; + protected EntityManager em; + protected RealmModel realm; + + public RoleAdapter(RealmModel realm, EntityManager em, RoleEntity role) { + this.em = em; + this.realm = realm; + this.role = role; + } + + public RoleEntity getRole() { + return role; + } + + public void setRole(RoleEntity role) { + this.role = role; + } + + @Override + public String getName() { + return role.getName(); + } + + @Override + public String getDescription() { + return role.getDescription(); + } + + @Override + public void setDescription(String description) { + role.setDescription(description); + } + + @Override + public String getId() { + return role.getId(); + } + + @Override + public void setName(String name) { + role.setName(name); + } + + @Override + public boolean isComposite() { + return getComposites().size() > 0; + } + + @Override + public void addCompositeRole(RoleModel role) { + RoleEntity entity = RoleAdapter.toRoleEntity(role, em); + for (RoleEntity composite : getRole().getCompositeRoles()) { + if (composite.equals(entity)) return; + } + getRole().getCompositeRoles().add(entity); + em.flush(); + } + + @Override + public void removeCompositeRole(RoleModel role) { + RoleEntity entity = RoleAdapter.toRoleEntity(role, em); + Iterator it = getRole().getCompositeRoles().iterator(); + while (it.hasNext()) { + if (it.next().equals(entity)) it.remove(); + } + } + + @Override + public Set getComposites() { + Set set = new HashSet(); + + for (RoleEntity composite : getRole().getCompositeRoles()) { + set.add(new RoleAdapter(realm, em, composite)); + } + return set; + } + + @Override + public boolean hasRole(RoleModel role) { + if (this.equals(role)) return true; + if (!isComposite()) return false; + + Set visited = new HashSet(); + return KeycloakModelUtils.searchFor(role, this, visited); + } + + @Override + public RoleContainerModel getContainer() { + if (role.isApplicationRole()) { + return realm.getApplicationById(role.getApplication().getId()); + + } else { + return realm; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof RoleModel)) return false; + + RoleModel that = (RoleModel) o; + return that.getId().equals(getId()); + } + + @Override + public int hashCode() { + return getId().hashCode(); + } + + public static RoleEntity toRoleEntity(RoleModel model, EntityManager em) { + if (model instanceof RoleAdapter) { + return ((RoleAdapter)model).getRole(); + } + return em.getReference(RoleEntity.class, model.getId()); + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java new file mode 100755 index 0000000000..18219f62d4 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java @@ -0,0 +1,384 @@ +package org.keycloak.models.jpa; + +import org.keycloak.models.ApplicationModel; +import org.keycloak.models.AuthenticationLinkModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.PasswordPolicy; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RoleContainerModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.UserCredentialModel; +import org.keycloak.models.UserCredentialValueModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.jpa.entities.AuthenticationLinkEntity; +import org.keycloak.models.jpa.entities.CredentialEntity; +import org.keycloak.models.jpa.entities.RoleEntity; +import org.keycloak.models.jpa.entities.UserEntity; +import org.keycloak.models.jpa.entities.UserRoleMappingEntity; +import org.keycloak.models.utils.Pbkdf2PasswordEncoder; + +import javax.persistence.EntityManager; +import javax.persistence.TypedQuery; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.keycloak.models.utils.Pbkdf2PasswordEncoder.getSalt; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class UserAdapter implements UserModel { + + protected UserEntity user; + protected EntityManager em; + protected RealmModel realm; + + public UserAdapter(RealmModel realm, EntityManager em, UserEntity user) { + this.em = em; + this.user = user; + this.realm = realm; + } + + public UserEntity getUser() { + return user; + } + + @Override + public String getId() { + return user.getId(); + } + + @Override + public String getUsername() { + return user.getUsername(); + } + + @Override + public void setUsername(String username) { + user.setUsername(username); + } + + @Override + public boolean isEnabled() { + return user.isEnabled(); + } + + @Override + public boolean isTotp() { + return user.isTotp(); + } + + @Override + public void setEnabled(boolean enabled) { + user.setEnabled(enabled); + } + + @Override + public void setAttribute(String name, String value) { + Map attributes = user.getAttributes(); + if (attributes == null) { + attributes = new HashMap(); + } + attributes.put(name, value); + user.setAttributes(attributes); + } + + @Override + public void removeAttribute(String name) { + Map attributes = user.getAttributes(); + if (attributes == null) { + attributes = new HashMap(); + } + attributes.remove(name); + user.setAttributes(attributes); + } + + @Override + public String getAttribute(String name) { + if (user.getAttributes() == null) return null; + return user.getAttributes().get(name); + } + + @Override + public Map getAttributes() { + Map result = new HashMap(); + result.putAll(user.getAttributes()); + return result; + } + + @Override + public Set getRequiredActions() { + Set result = new HashSet(); + result.addAll(user.getRequiredActions()); + return result; + } + + @Override + public void addRequiredAction(RequiredAction action) { + user.getRequiredActions().add(action); + } + + @Override + public void removeRequiredAction(RequiredAction action) { + user.getRequiredActions().remove(action); + } + + + @Override + public String getFirstName() { + return user.getFirstName(); + } + + @Override + public void setFirstName(String firstName) { + user.setFirstName(firstName); + } + + @Override + public String getLastName() { + return user.getLastName(); + } + + @Override + public void setLastName(String lastName) { + user.setLastName(lastName); + } + + @Override + public String getEmail() { + return user.getEmail(); + } + + @Override + public void setEmail(String email) { + user.setEmail(email); + } + + @Override + public boolean isEmailVerified() { + return user.isEmailVerified(); + } + + @Override + public void setEmailVerified(boolean verified) { + user.setEmailVerified(verified); + } + + @Override + public void setTotp(boolean totp) { + user.setTotp(totp); + } + + @Override + public void updateCredential(UserCredentialModel cred) { + CredentialEntity credentialEntity = getCredentialEntity(user, cred.getType()); + + if (credentialEntity == null) { + credentialEntity = new CredentialEntity(); + credentialEntity.setType(cred.getType()); + credentialEntity.setDevice(cred.getDevice()); + credentialEntity.setUser(user); + em.persist(credentialEntity); + user.getCredentials().add(credentialEntity); + } + if (cred.getType().equals(UserCredentialModel.PASSWORD)) { + byte[] salt = getSalt(); + int hashIterations = 1; + PasswordPolicy policy = realm.getPasswordPolicy(); + if (policy != null) { + hashIterations = policy.getHashIterations(); + if (hashIterations == -1) hashIterations = 1; + } + credentialEntity.setValue(new Pbkdf2PasswordEncoder(salt).encode(cred.getValue(), hashIterations)); + credentialEntity.setSalt(salt); + credentialEntity.setHashIterations(hashIterations); + } else { + credentialEntity.setValue(cred.getValue()); + } + credentialEntity.setDevice(cred.getDevice()); + em.flush(); + } + + private CredentialEntity getCredentialEntity(UserEntity userEntity, String credType) { + for (CredentialEntity entity : userEntity.getCredentials()) { + if (entity.getType().equals(credType)) { + return entity; + } + } + + return null; + } + + @Override + public List getCredentialsDirectly() { + List credentials = new ArrayList(user.getCredentials()); + List result = new ArrayList(); + + if (credentials != null) { + for (CredentialEntity credEntity : credentials) { + UserCredentialValueModel credModel = new UserCredentialValueModel(); + credModel.setType(credEntity.getType()); + credModel.setDevice(credEntity.getDevice()); + credModel.setValue(credEntity.getValue()); + credModel.setSalt(credEntity.getSalt()); + credModel.setHashIterations(credEntity.getHashIterations()); + + result.add(credModel); + } + } + + return result; + } + + @Override + public void updateCredentialDirectly(UserCredentialValueModel credModel) { + CredentialEntity credentialEntity = getCredentialEntity(user, credModel.getType()); + + if (credentialEntity == null) { + credentialEntity = new CredentialEntity(); + credentialEntity.setType(credModel.getType()); + credentialEntity.setUser(user); + em.persist(credentialEntity); + user.getCredentials().add(credentialEntity); + } + + credentialEntity.setValue(credModel.getValue()); + credentialEntity.setSalt(credModel.getSalt()); + credentialEntity.setDevice(credModel.getDevice()); + credentialEntity.setHashIterations(credModel.getHashIterations()); + + em.flush(); + } + + @Override + public boolean hasRole(RoleModel role) { + Set roles = getRoleMappings(); + if (roles.contains(role)) return true; + + for (RoleModel mapping : roles) { + if (mapping.hasRole(role)) return true; + } + return false; + } + + protected TypedQuery getUserRoleMappingEntityTypedQuery(RoleModel role) { + TypedQuery query = em.createNamedQuery("userHasRole", UserRoleMappingEntity.class); + query.setParameter("user", getUser()); + RoleEntity roleEntity = em.getReference(RoleEntity.class, role.getId()); + query.setParameter("role", roleEntity); + return query; + } + + @Override + public void grantRole(RoleModel role) { + if (hasRole(role)) return; + UserRoleMappingEntity entity = new UserRoleMappingEntity(); + entity.setUser(getUser()); + RoleEntity roleEntity = em.getReference(RoleEntity.class, role.getId()); + entity.setRole(roleEntity); + em.persist(entity); + em.flush(); + em.detach(entity); + } + + @Override + public Set getRealmRoleMappings() { + Set roleMappings = getRoleMappings(); + + Set realmRoles = new HashSet(); + for (RoleModel role : roleMappings) { + RoleContainerModel container = role.getContainer(); + if (container instanceof RealmModel) { + realmRoles.add(role); + } + } + return realmRoles; + } + + + @Override + public Set getRoleMappings() { + // we query ids only as the role might be cached and following the @ManyToOne will result in a load + // even if we're getting just the id. + TypedQuery query = em.createNamedQuery("userRoleMappingIds", String.class); + query.setParameter("user", getUser()); + List ids = query.getResultList(); + Set roles = new HashSet(); + for (String roleId : ids) { + RoleModel roleById = realm.getRoleById(roleId); + if (roleById == null) continue; + roles.add(roleById); + } + return roles; + } + + @Override + public void deleteRoleMapping(RoleModel role) { + if (user == null || role == null) return; + + TypedQuery query = getUserRoleMappingEntityTypedQuery(role); + List results = query.getResultList(); + if (results.size() == 0) return; + for (UserRoleMappingEntity entity : results) { + em.remove(entity); + } + em.flush(); + } + + @Override + public Set getApplicationRoleMappings(ApplicationModel app) { + Set roleMappings = getRoleMappings(); + + Set roles = new HashSet(); + for (RoleModel role : roleMappings) { + RoleContainerModel container = role.getContainer(); + if (container instanceof ApplicationModel) { + ApplicationModel appModel = (ApplicationModel)container; + if (appModel.getId().equals(app.getId())) { + roles.add(role); + } + } + } + return roles; + } + + @Override + public AuthenticationLinkModel getAuthenticationLink() { + AuthenticationLinkEntity authLinkEntity = user.getAuthenticationLink(); + return authLinkEntity == null ? null : new AuthenticationLinkModel(authLinkEntity.getAuthProvider(), authLinkEntity.getAuthUserId()); + } + + @Override + public void setAuthenticationLink(AuthenticationLinkModel authenticationLink) { + AuthenticationLinkEntity entity = new AuthenticationLinkEntity(); + entity.setAuthProvider(authenticationLink.getAuthProvider()); + entity.setAuthUserId(authenticationLink.getAuthUserId()); + + user.setAuthenticationLink(entity); + em.persist(entity); + em.persist(user); + em.flush(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof UserModel)) return false; + + UserModel that = (UserModel) o; + return that.getId().equals(getId()); + } + + @Override + public int hashCode() { + return getId().hashCode(); + } + + + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserSessionAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserSessionAdapter.java new file mode 100755 index 0000000000..333f7d19f4 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserSessionAdapter.java @@ -0,0 +1,130 @@ +package org.keycloak.models.jpa; + +import org.keycloak.models.ClientModel; +import org.keycloak.models.ModelException; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.jpa.entities.ClientUserSessionAssociationEntity; +import org.keycloak.models.jpa.entities.UserSessionEntity; + +import javax.persistence.EntityManager; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Stian Thorgersen + */ +public class UserSessionAdapter implements UserSessionModel { + + private RealmModel realm; + private UserSessionEntity entity; + private EntityManager em; + + public UserSessionAdapter(EntityManager em, RealmModel realm, UserSessionEntity entity) { + this.entity = entity; + this.em = em; + this.realm = realm; + } + + public UserSessionEntity getEntity() { + return entity; + } + + @Override + public String getId() { + return entity.getId(); + } + + @Override + public void setId(String id) { + entity.setId(id); + } + + @Override + public UserModel getUser() { + return realm.getUserById(entity.getUserId()); + } + + @Override + public void setUser(UserModel user) { + entity.setUserId(user.getId()); + } + + @Override + public String getIpAddress() { + return entity.getIpAddress(); + } + + @Override + public void setIpAddress(String ipAddress) { + entity.setIpAddress(ipAddress); + } + + @Override + public int getStarted() { + return entity.getStarted(); + } + + @Override + public void setStarted(int started) { + entity.setStarted(started); + } + + @Override + public int getLastSessionRefresh() { + return entity.getLastSessionRefresh(); + } + + @Override + public void setLastSessionRefresh(int seconds) { + entity.setLastSessionRefresh(seconds); + } + + @Override + public void associateClient(ClientModel client) { + for (ClientUserSessionAssociationEntity ass : entity.getClients()) { + if (ass.getClientId().equals(client.getId())) return; + } + ClientUserSessionAssociationEntity association = new ClientUserSessionAssociationEntity(); + association.setClientId(client.getId()); + association.setSession(entity); + association.setUserId(entity.getUserId()); + association.setRealmId(realm.getId()); + em.persist(association); + entity.getClients().add(association); + } + + @Override + public void removeAssociatedClient(ClientModel client) { + em.createNamedQuery("removeClientUserSessionByClient").setParameter("clientId", client.getId()).executeUpdate(); + + } + + @Override + public List getClientAssociations() { + List clients = new ArrayList(); + for (ClientUserSessionAssociationEntity association : entity.getClients()) { + ClientModel client = realm.findClientById(association.getClientId()); + if (client == null) { + throw new ModelException("couldnt find client"); + } + clients.add(client); + } + return clients; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof UserSessionModel)) return false; + + UserSessionModel that = (UserSessionModel) o; + return that.getId().equals(getId()); + } + + @Override + public int hashCode() { + return getId().hashCode(); + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UsernameLoginFailureAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UsernameLoginFailureAdapter.java new file mode 100755 index 0000000000..ba43c82388 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UsernameLoginFailureAdapter.java @@ -0,0 +1,70 @@ +package org.keycloak.models.jpa; + +import org.keycloak.models.UsernameLoginFailureModel; +import org.keycloak.models.jpa.entities.UsernameLoginFailureEntity; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class UsernameLoginFailureAdapter implements UsernameLoginFailureModel +{ + protected UsernameLoginFailureEntity user; + + public UsernameLoginFailureAdapter(UsernameLoginFailureEntity user) + { + this.user = user; + } + + @Override + public String getUsername() + { + return user.getUsername(); + } + + @Override + public int getFailedLoginNotBefore() { + return user.getFailedLoginNotBefore(); + } + + @Override + public void setFailedLoginNotBefore(int notBefore) { + user.setFailedLoginNotBefore(notBefore); + } + + @Override + public int getNumFailures() { + return user.getNumFailures(); + } + + @Override + public void incrementFailures() { + user.setNumFailures(getNumFailures() + 1); + } + + @Override + public void clearFailures() { + user.setNumFailures(0); + } + + @Override + public long getLastFailure() { + return user.getLastFailure(); + } + + @Override + public void setLastFailure(long lastFailure) { + user.setLastFailure(lastFailure); + } + + @Override + public String getLastIPFailure() { + return user.getLastIPFailure(); + } + + @Override + public void setLastIPFailure(String ip) { + user.setLastIPFailure(ip); + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AbstractRoleMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AbstractRoleMappingEntity.java new file mode 100755 index 0000000000..2ab0d00cc7 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AbstractRoleMappingEntity.java @@ -0,0 +1,52 @@ +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 Bill Burke + * @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; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java new file mode 100755 index 0000000000..8327bd0e04 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java @@ -0,0 +1,90 @@ +package org.keycloak.models.jpa.entities; + +import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.hibernate.annotations.GenericGenerator; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@Entity +public class ApplicationEntity extends ClientEntity { + + private boolean surrogateAuthRequired; + private String baseUrl; + private String managementUrl; + private boolean bearerOnly; + + @OneToMany(fetch = FetchType.EAGER, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "application") + Collection roles = new ArrayList(); + + @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true) + @JoinTable(name="ApplicationDefaultRoles") + Collection defaultRoles = new ArrayList(); + + public boolean isSurrogateAuthRequired() { + return surrogateAuthRequired; + } + + public void setSurrogateAuthRequired(boolean surrogateAuthRequired) { + this.surrogateAuthRequired = surrogateAuthRequired; + } + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getManagementUrl() { + return managementUrl; + } + + public void setManagementUrl(String managementUrl) { + this.managementUrl = managementUrl; + } + + public Collection getRoles() { + return roles; + } + + public void setRoles(Collection roles) { + this.roles = roles; + } + + public Collection getDefaultRoles() { + return defaultRoles; + } + + public void setDefaultRoles(Collection defaultRoles) { + this.defaultRoles = defaultRoles; + } + + public boolean isBearerOnly() { + return bearerOnly; + } + + public void setBearerOnly(boolean bearerOnly) { + this.bearerOnly = bearerOnly; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationLinkEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationLinkEntity.java new file mode 100644 index 0000000000..e6ae8d421c --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationLinkEntity.java @@ -0,0 +1,50 @@ +package org.keycloak.models.jpa.entities; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToOne; + +import org.hibernate.annotations.GenericGenerator; + +/** + * @author Marek Posolda + */ +@Entity +public class AuthenticationLinkEntity { + + @Id + @GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator") + @GeneratedValue(generator = "keycloak_generator") + private String id; + + protected String authProvider; + protected String authUserId; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAuthProvider() { + return authProvider; + } + + public void setAuthProvider(String authProvider) { + this.authProvider = authProvider; + } + + public String getAuthUserId() { + return authUserId; + } + + public void setAuthUserId(String authUserId) { + this.authUserId = authUserId; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationProviderEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationProviderEntity.java new file mode 100644 index 0000000000..2ce4c127a5 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/AuthenticationProviderEntity.java @@ -0,0 +1,80 @@ +package org.keycloak.models.jpa.entities; + +import java.util.Map; + +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.MapKeyColumn; +import javax.persistence.Table; + +import org.hibernate.annotations.GenericGenerator; + +/** + * @author Marek Posolda + */ +@Entity +@Table(name="AuthProviderEntity") +public class AuthenticationProviderEntity { + + @Id + @GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator") + @GeneratedValue(generator = "keycloak_generator") + protected String id; + + private String providerName; + private boolean passwordUpdateSupported; + private int priority; + + @ElementCollection + @MapKeyColumn(name="name") + @Column(name="value") + @CollectionTable(name="AuthProviderEntity_cfg", joinColumns = { + @JoinColumn(name = "AuthProviderEntity_id") + }) + private Map config; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getProviderName() { + return providerName; + } + + public void setProviderName(String providerName) { + this.providerName = providerName; + } + + public boolean isPasswordUpdateSupported() { + return passwordUpdateSupported; + } + + public void setPasswordUpdateSupported(boolean passwordUpdateSupported) { + this.passwordUpdateSupported = passwordUpdateSupported; + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + public Map getConfig() { + return config; + } + + public void setConfig(Map config) { + this.config = config; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java new file mode 100755 index 0000000000..9367d251d7 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientEntity.java @@ -0,0 +1,131 @@ +package org.keycloak.models.jpa.entities; + +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +import java.util.HashSet; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"realm", "name"})}) +public abstract class ClientEntity { + @Id + private String id; + @Column(name = "name") + private String name; + private boolean enabled; + private String secret; + private long allowedClaimsMask; + private int notBefore; + private boolean publicClient; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "realm") + protected RealmEntity realm; + + @ElementCollection + @CollectionTable + protected Set webOrigins = new HashSet(); + @ElementCollection + @CollectionTable + protected Set redirectUris = new HashSet(); + + public RealmEntity getRealm() { + return realm; + } + + public void setRealm(RealmEntity realm) { + this.realm = realm; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public long getAllowedClaimsMask() { + return allowedClaimsMask; + } + + public void setAllowedClaimsMask(long allowedClaimsMask) { + this.allowedClaimsMask = allowedClaimsMask; + } + + public Set getWebOrigins() { + return webOrigins; + } + + public void setWebOrigins(Set webOrigins) { + this.webOrigins = webOrigins; + } + + public Set getRedirectUris() { + return redirectUris; + } + + public void setRedirectUris(Set redirectUris) { + this.redirectUris = redirectUris; + } + + public String getSecret() { + return secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + + public int getNotBefore() { + return notBefore; + } + + public void setNotBefore(int notBefore) { + this.notBefore = notBefore; + } + + public boolean isPublicClient() { + return publicClient; + } + + public void setPublicClient(boolean publicClient) { + this.publicClient = publicClient; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientUserSessionAssociationEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientUserSessionAssociationEntity.java new file mode 100755 index 0000000000..490e75d7c2 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ClientUserSessionAssociationEntity.java @@ -0,0 +1,84 @@ +package org.keycloak.models.jpa.entities; + +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@Entity +@Table(name = "ClientUserSessionAscEntity") +@NamedQueries({ + @NamedQuery(name = "getAllClientUserSessions", query = "select s from ClientUserSessionAssociationEntity s"), + @NamedQuery(name = "getClientUserSessionBySession", query = "select s from ClientUserSessionAssociationEntity s where s.session = :session"), + @NamedQuery(name = "getClientUserSessionByClient", query = "select s from ClientUserSessionAssociationEntity s where s.clientId = :clientId"), + @NamedQuery(name = "getActiveClientSessions", query = "select COUNT(s) from ClientUserSessionAssociationEntity s where s.clientId = :clientId"), + @NamedQuery(name = "removeClientUserSessionByClient", query = "delete from ClientUserSessionAssociationEntity s where s.clientId = :clientId"), + @NamedQuery(name = "removeClientUserSessionByUser", query = "delete from ClientUserSessionAssociationEntity s where s.userId = :userId"), + @NamedQuery(name = "removeClientUserSessionByRealm", query = "delete from ClientUserSessionAssociationEntity s where s.realmId = :realmId")}) +public class ClientUserSessionAssociationEntity { + @Id + @GenericGenerator(name="uuid_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator") + @GeneratedValue(generator = "uuid_generator") + private String id; + + // we use ids to avoid select for update contention + private String userId; + private String realmId; + + @ManyToOne(fetch= FetchType.LAZY) + private UserSessionEntity session; + + + + private String clientId; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public UserSessionEntity getSession() { + return session; + } + + public void setSession(UserSessionEntity session) { + this.session = session; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getRealmId() { + return realmId; + } + + public void setRealmId(String realmId) { + this.realmId = realmId; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/CredentialEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/CredentialEntity.java new file mode 100755 index 0000000000..6d792f887c --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/CredentialEntity.java @@ -0,0 +1,91 @@ +package org.keycloak.models.jpa.entities; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; + +import org.hibernate.annotations.GenericGenerator; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@NamedQueries({ + @NamedQuery(name="credentialByUserAndType", query="select cred from CredentialEntity cred where cred.user = :user and cred.type = :type") +}) +@Entity +public class CredentialEntity { + @Id + @GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator") + @GeneratedValue(generator = "keycloak_generator") + protected String id; + + protected String type; + protected String value; + protected String device; + protected byte[] salt; + protected int hashIterations; + + @ManyToOne(fetch = FetchType.LAZY) + protected UserEntity user; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDevice() { + return device; + } + + public void setDevice(String device) { + this.device = device; + } + + public UserEntity getUser() { + return user; + } + + public void setUser(UserEntity user) { + this.user = user; + } + + public byte[] getSalt() { + return salt; + } + + public void setSalt(byte[] salt) { + this.salt = salt; + } + + public int getHashIterations() { + return hashIterations; + } + + public void setHashIterations(int hashIterations) { + this.hashIterations = hashIterations; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java new file mode 100755 index 0000000000..dbdf080272 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/OAuthClientEntity.java @@ -0,0 +1,27 @@ +package org.keycloak.models.jpa.entities; + +import javax.persistence.Entity; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@NamedQueries({ + @NamedQuery(name="findOAuthClientByName", query="select o from OAuthClientEntity o where o.name=:name and o.realm = :realm"), + @NamedQuery(name="findOAuthClientByRealm", query="select o from OAuthClientEntity o where o.realm = :realm") + +}) +@Entity +public class OAuthClientEntity extends ClientEntity { + protected boolean directGrantsOnly; + + public boolean isDirectGrantsOnly() { + return directGrantsOnly; + } + + public void setDirectGrantsOnly(boolean directGrantsOnly) { + this.directGrantsOnly = directGrantsOnly; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java new file mode 100755 index 0000000000..8fd8a5660a --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java @@ -0,0 +1,479 @@ +package org.keycloak.models.jpa.entities; + + +import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinTable; +import javax.persistence.MapKeyColumn; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@Entity +@NamedQueries({ + @NamedQuery(name="getAllRealms", query="select realm from RealmEntity realm"), + @NamedQuery(name="getRealmByName", query="select realm from RealmEntity realm where realm.name = :name"), +}) +public class RealmEntity { + @Id + protected String id; + + @Column(unique = true) + protected String name; + + protected boolean enabled; + protected boolean sslNotRequired; + protected boolean registrationAllowed; + protected boolean passwordCredentialGrantAllowed; + protected boolean verifyEmail; + protected boolean resetPasswordAllowed; + protected boolean social; + protected boolean rememberMe; + //--- brute force settings + protected boolean bruteForceProtected; + protected int maxFailureWaitSeconds; + protected int minimumQuickLoginWaitSeconds; + protected int waitIncrementSeconds; + protected long quickLoginCheckMilliSeconds; + protected int maxDeltaTimeSeconds; + protected int failureFactor; + //--- end brute force settings + + + @Column(name="updateProfileOnInitSocLogin") + protected boolean updateProfileOnInitialSocialLogin; + protected String passwordPolicy; + + private int ssoSessionIdleTimeout; + private int ssoSessionMaxLifespan; + protected int accessTokenLifespan; + protected int accessCodeLifespan; + protected int accessCodeLifespanUserAction; + protected int notBefore; + + @Column(length = 2048) + protected String publicKeyPem; + @Column(length = 2048) + protected String privateKeyPem; + + protected String loginTheme; + protected String accountTheme; + protected String adminTheme; + protected String emailTheme; + + @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true) + @JoinTable(name="User_RequiredCreds") + Collection requiredCredentials = new ArrayList(); + + + @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true) + @JoinTable(name="AuthProviders") + List authenticationProviders = new ArrayList(); + + @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true) + Collection applications = new ArrayList(); + + @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm") + Collection roles = new ArrayList(); + + @ElementCollection + @MapKeyColumn(name="name") + @Column(name="value") + @CollectionTable + protected Map smtpConfig = new HashMap(); + + @ElementCollection + @MapKeyColumn(name="name") + @Column(name="value") + @CollectionTable + protected Map socialConfig = new HashMap(); + + @ElementCollection + @MapKeyColumn(name="name") + @Column(name="value") + @CollectionTable + protected Map ldapServerConfig = new HashMap(); + + @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true) + @JoinTable(name="RealmDefaultRoles") + protected Collection defaultRoles = new ArrayList(); + + protected boolean auditEnabled; + protected long auditExpiration; + + @ElementCollection + protected Set auditListeners= new HashSet(); + + @OneToOne + protected ApplicationEntity masterAdminApp; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isSslNotRequired() { + return sslNotRequired; + } + + public void setSslNotRequired(boolean sslNotRequired) { + this.sslNotRequired = sslNotRequired; + } + + public boolean isPasswordCredentialGrantAllowed() { + return passwordCredentialGrantAllowed; + } + + public void setPasswordCredentialGrantAllowed(boolean passwordCredentialGrantAllowed) { + this.passwordCredentialGrantAllowed = passwordCredentialGrantAllowed; + } + + public boolean isRegistrationAllowed() { + return registrationAllowed; + } + + public void setRegistrationAllowed(boolean registrationAllowed) { + this.registrationAllowed = registrationAllowed; + } + + public boolean isRememberMe() { + return rememberMe; + } + + public void setRememberMe(boolean rememberMe) { + this.rememberMe = rememberMe; + } + + public boolean isVerifyEmail() { + return verifyEmail; + } + + public void setVerifyEmail(boolean verifyEmail) { + this.verifyEmail = verifyEmail; + } + + public boolean isResetPasswordAllowed() { + return resetPasswordAllowed; + } + + public void setResetPasswordAllowed(boolean resetPasswordAllowed) { + this.resetPasswordAllowed = resetPasswordAllowed; + } + + public boolean isSocial() { + return social; + } + + public void setSocial(boolean social) { + this.social = social; + } + + public boolean isUpdateProfileOnInitialSocialLogin() { + return updateProfileOnInitialSocialLogin; + } + + public void setUpdateProfileOnInitialSocialLogin(boolean updateProfileOnInitialSocialLogin) { + this.updateProfileOnInitialSocialLogin = updateProfileOnInitialSocialLogin; + } + + public int getSsoSessionIdleTimeout() { + return ssoSessionIdleTimeout; + } + + public void setSsoSessionIdleTimeout(int ssoSessionIdleTimeout) { + this.ssoSessionIdleTimeout = ssoSessionIdleTimeout; + } + + public int getSsoSessionMaxLifespan() { + return ssoSessionMaxLifespan; + } + + public void setSsoSessionMaxLifespan(int ssoSessionMaxLifespan) { + this.ssoSessionMaxLifespan = ssoSessionMaxLifespan; + } + + public int getAccessTokenLifespan() { + return accessTokenLifespan; + } + + public void setAccessTokenLifespan(int accessTokenLifespan) { + this.accessTokenLifespan = accessTokenLifespan; + } + + public int getAccessCodeLifespan() { + return accessCodeLifespan; + } + + public void setAccessCodeLifespan(int accessCodeLifespan) { + this.accessCodeLifespan = accessCodeLifespan; + } + + public int getAccessCodeLifespanUserAction() { + return accessCodeLifespanUserAction; + } + + public void setAccessCodeLifespanUserAction(int accessCodeLifespanUserAction) { + this.accessCodeLifespanUserAction = accessCodeLifespanUserAction; + } + + public String getPublicKeyPem() { + return publicKeyPem; + } + + public void setPublicKeyPem(String publicKeyPem) { + this.publicKeyPem = publicKeyPem; + } + + public String getPrivateKeyPem() { + return privateKeyPem; + } + + public void setPrivateKeyPem(String privateKeyPem) { + this.privateKeyPem = privateKeyPem; + } + + public Collection getRequiredCredentials() { + return requiredCredentials; + } + + public void setRequiredCredentials(Collection requiredCredentials) { + this.requiredCredentials = requiredCredentials; + } + + public List getAuthenticationProviders() { + return authenticationProviders; + } + + public void setAuthenticationProviders(List authenticationProviders) { + this.authenticationProviders = authenticationProviders; + } + + public Collection getApplications() { + return applications; + } + + public void setApplications(Collection applications) { + this.applications = applications; + } + + public Collection getRoles() { + return roles; + } + + public void setRoles(Collection roles) { + this.roles = roles; + } + + public void addRole(RoleEntity role) { + if (roles == null) { + roles = new ArrayList(); + } + roles.add(role); + } + + public Map getSmtpConfig() { + return smtpConfig; + } + + public void setSmtpConfig(Map smtpConfig) { + this.smtpConfig = smtpConfig; + } + + public Map getSocialConfig() { + return socialConfig; + } + + public void setSocialConfig(Map socialConfig) { + this.socialConfig = socialConfig; + } + + public Map getLdapServerConfig() { + return ldapServerConfig; + } + + public void setLdapServerConfig(Map ldapServerConfig) { + this.ldapServerConfig = ldapServerConfig; + } + + public Collection getDefaultRoles() { + return defaultRoles; + } + + public void setDefaultRoles(Collection defaultRoles) { + this.defaultRoles = defaultRoles; + } + + public String getPasswordPolicy() { + return passwordPolicy; + } + + public void setPasswordPolicy(String passwordPolicy) { + this.passwordPolicy = passwordPolicy; + } + + public String getLoginTheme() { + return loginTheme; + } + + public void setLoginTheme(String theme) { + this.loginTheme = theme; + } + + public String getAccountTheme() { + return accountTheme; + } + + public void setAccountTheme(String theme) { + this.accountTheme = theme; + } + + public String getAdminTheme() { + return adminTheme; + } + + public void setAdminTheme(String adminTheme) { + this.adminTheme = adminTheme; + } + + public String getEmailTheme() { + return emailTheme; + } + + public void setEmailTheme(String emailTheme) { + this.emailTheme = emailTheme; + } + + public int getNotBefore() { + return notBefore; + } + + public void setNotBefore(int notBefore) { + this.notBefore = notBefore; + } + + public boolean isBruteForceProtected() { + return bruteForceProtected; + } + + public void setBruteForceProtected(boolean bruteForceProtected) { + this.bruteForceProtected = bruteForceProtected; + } + + public int getMaxFailureWaitSeconds() { + return maxFailureWaitSeconds; + } + + public void setMaxFailureWaitSeconds(int maxFailureWaitSeconds) { + this.maxFailureWaitSeconds = maxFailureWaitSeconds; + } + + public int getMinimumQuickLoginWaitSeconds() { + return minimumQuickLoginWaitSeconds; + } + + public void setMinimumQuickLoginWaitSeconds(int minimumQuickLoginWaitSeconds) { + this.minimumQuickLoginWaitSeconds = minimumQuickLoginWaitSeconds; + } + + public int getWaitIncrementSeconds() { + return waitIncrementSeconds; + } + + public void setWaitIncrementSeconds(int waitIncrementSeconds) { + this.waitIncrementSeconds = waitIncrementSeconds; + } + + public long getQuickLoginCheckMilliSeconds() { + return quickLoginCheckMilliSeconds; + } + + public void setQuickLoginCheckMilliSeconds(long quickLoginCheckMilliSeconds) { + this.quickLoginCheckMilliSeconds = quickLoginCheckMilliSeconds; + } + + public int getMaxDeltaTimeSeconds() { + return maxDeltaTimeSeconds; + } + + public void setMaxDeltaTimeSeconds(int maxDeltaTimeSeconds) { + this.maxDeltaTimeSeconds = maxDeltaTimeSeconds; + } + + public int getFailureFactor() { + return failureFactor; + } + + public void setFailureFactor(int failureFactor) { + this.failureFactor = failureFactor; + } + + public boolean isAuditEnabled() { + return auditEnabled; + } + + public void setAuditEnabled(boolean auditEnabled) { + this.auditEnabled = auditEnabled; + } + + public long getAuditExpiration() { + return auditExpiration; + } + + public void setAuditExpiration(long auditExpiration) { + this.auditExpiration = auditExpiration; + } + + public Set getAuditListeners() { + return auditListeners; + } + + public void setAuditListeners(Set auditListeners) { + this.auditListeners = auditListeners; + } + + public ApplicationEntity getMasterAdminApp() { + return masterAdminApp; + } + + public void setMasterAdminApp(ApplicationEntity masterAdminApp) { + this.masterAdminApp = masterAdminApp; + } + +} + diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredCredentialEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredCredentialEntity.java new file mode 100755 index 0000000000..94870224a5 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RequiredCredentialEntity.java @@ -0,0 +1,64 @@ +package org.keycloak.models.jpa.entities; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import org.hibernate.annotations.GenericGenerator; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@Entity +public class RequiredCredentialEntity { + @Id + @GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator") + @GeneratedValue(generator = "keycloak_generator") + protected String id; + + protected String type; + protected boolean input; + protected boolean secret; + protected String formLabel; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public boolean isInput() { + return input; + } + + public void setInput(boolean input) { + this.input = input; + } + + public boolean isSecret() { + return secret; + } + + public void setSecret(boolean secret) { + this.secret = secret; + } + + public String getFormLabel() { + return formLabel; + } + + public void setFormLabel(String formLabel) { + this.formLabel = formLabel; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java new file mode 100755 index 0000000000..d3fc6dfb8c --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RoleEntity.java @@ -0,0 +1,157 @@ +package org.keycloak.models.jpa.entities; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +import java.util.ArrayList; +import java.util.Collection; + +import org.hibernate.annotations.GenericGenerator; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@Entity +@Table(uniqueConstraints = { + @UniqueConstraint(columnNames = { "name", "appRealmConstraint" }) +}) +@NamedQueries({ + @NamedQuery(name="getAppRoleByName", query="select role from RoleEntity role where role.name = :name and role.application = :application"), + @NamedQuery(name="getRealmRoleByName", query="select role from RoleEntity role where role.applicationRole = false and role.name = :name and role.realm = :realm") +}) + +public class RoleEntity { + @Id + @Column(name="id") + private String id; + + private String name; + private String description; + + // hax! couldn't get constraint to work properly + private String realmId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "realm") + private RealmEntity realm; + + @Column(name="applicationRole") + private boolean applicationRole; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "application") + private ApplicationEntity application; + + // Hack to ensure that either name+application or name+realm are unique. Needed due to MS-SQL as it don't allow multiple NULL values in the column, which is part of constraint + private String appRealmConstraint; + + @ManyToMany(fetch = FetchType.LAZY, cascade = {}) + @JoinTable(name = "CompositeRole", joinColumns = @JoinColumn(name = "composite"), inverseJoinColumns = @JoinColumn(name = "childRole")) + private Collection compositeRoles = new ArrayList(); + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getRealmId() { + return realmId; + } + + public void setRealmId(String realmId) { + this.realmId = realmId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Collection getCompositeRoles() { + return compositeRoles; + } + + public void setCompositeRoles(Collection compositeRoles) { + this.compositeRoles = compositeRoles; + } + + public boolean isApplicationRole() { + return applicationRole; + } + + public void setApplicationRole(boolean applicationRole) { + this.applicationRole = applicationRole; + } + + public RealmEntity getRealm() { + return realm; + } + + public void setRealm(RealmEntity realm) { + this.realm = realm; + this.appRealmConstraint = realm.getId(); + } + + public ApplicationEntity getApplication() { + return application; + } + + public void setApplication(ApplicationEntity application) { + this.application = application; + if (application != null) { + this.appRealmConstraint = application.getId(); + } + } + + public String getAppRealmConstraint() { + return appRealmConstraint; + } + + public void setAppRealmConstraint(String appRealmConstraint) { + this.appRealmConstraint = appRealmConstraint; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + RoleEntity that = (RoleEntity) o; + + if (!id.equals(that.id)) return false; + + return true; + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ScopeMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ScopeMappingEntity.java new file mode 100755 index 0000000000..b45b69b8e4 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ScopeMappingEntity.java @@ -0,0 +1,60 @@ +package org.keycloak.models.jpa.entities; + +import org.hibernate.annotations.GenericGenerator; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@NamedQueries({ + @NamedQuery(name="hasScope", query="select m from ScopeMappingEntity m where m.client = :client and m.role = :role"), + @NamedQuery(name="clientScopeMappings", query="select m from ScopeMappingEntity m where m.client = :client"), + @NamedQuery(name="clientScopeMappingIds", query="select m.role.id from ScopeMappingEntity m where m.client = :client") +}) +@Entity +public class ScopeMappingEntity { + @Id + @GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator") + @GeneratedValue(generator = "keycloak_generator") + protected String id; + @ManyToOne(fetch= FetchType.LAZY) + protected ClientEntity client; + + @ManyToOne(fetch= FetchType.LAZY) + @JoinColumn(name="roleId") + protected RoleEntity role; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public ClientEntity getClient() { + return client; + } + + public void setClient(ClientEntity client) { + this.client = client; + } + + public RoleEntity getRole() { + return role; + } + + public void setRole(RoleEntity role) { + this.role = role; + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/SocialLinkEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/SocialLinkEntity.java new file mode 100755 index 0000000000..a1de3af283 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/SocialLinkEntity.java @@ -0,0 +1,86 @@ +package org.keycloak.models.jpa.entities; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; + +import org.hibernate.annotations.GenericGenerator; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@NamedQueries({ + @NamedQuery(name="findSocialLinkByUser", query="select link from SocialLinkEntity link where link.user = :user"), + @NamedQuery(name="findSocialLinkByUserAndProvider", query="select link from SocialLinkEntity link where link.user = :user and link.socialProvider = :socialProvider"), + @NamedQuery(name="findUserByLinkAndRealm", query="select link.user from SocialLinkEntity link where link.realm = :realm and link.socialProvider = :socialProvider and link.socialUserId = :socialUserId") +}) +@Entity +public class SocialLinkEntity { + @Id + @GenericGenerator(name="keycloak_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator") + @GeneratedValue(generator = "keycloak_generator") + private String id; + + @ManyToOne(fetch = FetchType.LAZY) + private UserEntity user; + + @ManyToOne(fetch = FetchType.LAZY) + protected RealmEntity realm; + + protected String socialProvider; + protected String socialUserId; + protected String socialUsername; + + 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 String getSocialProvider() { + return socialProvider; + } + + public void setSocialProvider(String socialProvider) { + this.socialProvider = socialProvider; + } + + public String getSocialUserId() { + return socialUserId; + } + + public void setSocialUserId(String socialUserId) { + this.socialUserId = socialUserId; + } + + public String getSocialUsername() { + return socialUsername; + } + + public void setSocialUsername(String socialUsername) { + this.socialUsername = socialUsername; + } + + public RealmEntity getRealm() { + return realm; + } + + public void setRealm(RealmEntity realm) { + this.realm = realm; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java new file mode 100755 index 0000000000..75389c94df --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserEntity.java @@ -0,0 +1,196 @@ +package org.keycloak.models.jpa.entities; + +import org.hibernate.annotations.GenericGenerator; +import org.keycloak.models.UserModel; +import org.keycloak.models.utils.KeycloakModelUtils; + +import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MapKeyColumn; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@NamedQueries({ + @NamedQuery(name="getRealmUserById", query="select u from UserEntity u where u.id = :id and u.realm = :realm"), + @NamedQuery(name="getRealmUserByUsername", query="select u from UserEntity u where u.username = :username and u.realm = :realm"), + @NamedQuery(name="getRealmUserByEmail", query="select u from UserEntity u where u.email = :email and u.realm = :realm"), + @NamedQuery(name="getRealmUserByLastName", query="select u from UserEntity u where u.lastName = :lastName and u.realm = :realm"), + @NamedQuery(name="getRealmUserByFirstLastName", query="select u from UserEntity u where u.firstName = :first and u.lastName = :last and u.realm = :realm") +}) +@Entity +@Table(uniqueConstraints = { + @UniqueConstraint(columnNames = { "realm", "username" }), + @UniqueConstraint(columnNames = { "realm", "emailConstraint" }) +}) +public class UserEntity { + @Id + protected String id; + + protected String username; + protected String firstName; + protected String lastName; + protected String email; + protected boolean enabled; + protected boolean totp; + protected boolean emailVerified; + + // Hack just to workaround the fact that on MS-SQL you can't have unique constraint with multiple NULL values TODO: Find better solution (like unique index with 'where' but that's proprietary) + protected String emailConstraint = KeycloakModelUtils.generateId(); + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "realm") + protected RealmEntity realm; + + @ElementCollection + @MapKeyColumn(name="name") + @Column(name="value") + @CollectionTable + protected Map attributes = new HashMap(); + + @ElementCollection + @CollectionTable + protected Set requiredActions = new HashSet(); + + @OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true) + protected Collection credentials = new ArrayList(); + + @OneToOne(cascade = CascadeType.REMOVE, orphanRemoval = true) + protected AuthenticationLinkEntity authenticationLink; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + this.emailConstraint = email != null ? email : KeycloakModelUtils.generateId(); + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getEmailConstraint() { + return emailConstraint; + } + + public void setEmailConstraint(String emailConstraint) { + this.emailConstraint = emailConstraint; + } + + public boolean isTotp() { + return totp; + } + + public void setTotp(boolean totp) { + this.totp = totp; + } + + public boolean isEmailVerified() { + return emailVerified; + } + + public void setEmailVerified(boolean emailVerified) { + this.emailVerified = emailVerified; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + public Set getRequiredActions() { + return requiredActions; + } + + public void setRequiredActions(Set requiredActions) { + this.requiredActions = requiredActions; + } + + public RealmEntity getRealm() { + return realm; + } + + public void setRealm(RealmEntity realm) { + this.realm = realm; + } + + public Collection getCredentials() { + return credentials; + } + + public void setCredentials(Collection credentials) { + this.credentials = credentials; + } + + public AuthenticationLinkEntity getAuthenticationLink() { + return authenticationLink; + } + + public void setAuthenticationLink(AuthenticationLinkEntity authenticationLink) { + this.authenticationLink = authenticationLink; + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserRoleMappingEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserRoleMappingEntity.java new file mode 100755 index 0000000000..647acea93b --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserRoleMappingEntity.java @@ -0,0 +1,19 @@ +package org.keycloak.models.jpa.entities; + +import javax.persistence.Entity; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@NamedQueries({ + @NamedQuery(name="userHasRole", query="select m from UserRoleMappingEntity m where m.user = :user and m.role = :role"), + @NamedQuery(name="userRoleMappings", query="select m from UserRoleMappingEntity m where m.user = :user"), + @NamedQuery(name="userRoleMappingIds", query="select m.role.id from UserRoleMappingEntity m where m.user = :user") +}) +@Entity +public class UserRoleMappingEntity extends AbstractRoleMappingEntity { + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserSessionEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserSessionEntity.java new file mode 100755 index 0000000000..4be28530e4 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserSessionEntity.java @@ -0,0 +1,107 @@ +package org.keycloak.models.jpa.entities; + +import org.hibernate.annotations.GenericGenerator; +import org.keycloak.models.UserModel; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import java.util.ArrayList; +import java.util.Collection; + +/** + * @author Stian Thorgersen + */ +@Entity +@NamedQueries({ + @NamedQuery(name = "getUserSessionByUser", query = "select s from UserSessionEntity s where s.userId = :userId"), + @NamedQuery(name = "removeRealmUserSessions", query = "delete from UserSessionEntity s where s.realmId = :realmId"), + @NamedQuery(name = "removeUserSessionByUser", query = "delete from UserSessionEntity s where s.userId = :userId"), + @NamedQuery(name = "getUserSessionExpired", query = "select s from UserSessionEntity s where s.started < :maxTime or s.lastSessionRefresh < :idleTime"), + @NamedQuery(name = "removeUserSessionExpired", query = "delete from UserSessionEntity s where s.started < :maxTime or s.lastSessionRefresh < :idleTime") +}) +public class UserSessionEntity { + + @Id + @GenericGenerator(name="uuid_generator", strategy="org.keycloak.models.jpa.utils.JpaIdGenerator") + @GeneratedValue(generator = "uuid_generator") + private String id; + + // we use ids to avoid select for update contention + private String userId; + private String realmId; + + private String ipAddress; + + private int started; + + private int lastSessionRefresh; + + @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy="session") + private Collection clients = new ArrayList(); + + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getRealmId() { + return realmId; + } + + public void setRealmId(String realmId) { + this.realmId = realmId; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public int getStarted() { + return started; + } + + public void setStarted(int started) { + this.started = started; + } + + public int getLastSessionRefresh() { + return lastSessionRefresh; + } + + public void setLastSessionRefresh(int lastSessionRefresh) { + this.lastSessionRefresh = lastSessionRefresh; + } + + public Collection getClients() { + return clients; + } + + public void setClients(Collection clients) { + this.clients = clients; + } + +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UsernameLoginFailureEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UsernameLoginFailureEntity.java new file mode 100755 index 0000000000..f3cffb4d27 --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UsernameLoginFailureEntity.java @@ -0,0 +1,88 @@ +package org.keycloak.models.jpa.entities; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +@Entity +@NamedQueries({ + @NamedQuery(name="getAllFailures", query="select failure from UsernameLoginFailureEntity failure"), +}) +public class UsernameLoginFailureEntity { + // we manually set the id to be username-realmid + // we may have a concurrent creation of the same login failure entry that we want to avoid + @Id + protected String id; + protected String username; + protected int failedLoginNotBefore; + protected int numFailures; + protected long lastFailure; + protected String lastIPFailure; + + + @ManyToOne(fetch = FetchType.LAZY) + protected RealmEntity realm; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public int getFailedLoginNotBefore() { + return failedLoginNotBefore; + } + + public void setFailedLoginNotBefore(int failedLoginNotBefore) { + this.failedLoginNotBefore = failedLoginNotBefore; + } + + public int getNumFailures() { + return numFailures; + } + + public void setNumFailures(int numFailures) { + this.numFailures = numFailures; + } + + public long getLastFailure() { + return lastFailure; + } + + public void setLastFailure(long lastFailure) { + this.lastFailure = lastFailure; + } + + public String getLastIPFailure() { + return lastIPFailure; + } + + public void setLastIPFailure(String lastIPFailure) { + this.lastIPFailure = lastIPFailure; + } + + public RealmEntity getRealm() { + return realm; + } + + public void setRealm(RealmEntity realm) { + this.realm = realm; + } +} diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/utils/JpaIdGenerator.java b/model/jpa/src/main/java/org/keycloak/models/jpa/utils/JpaIdGenerator.java new file mode 100644 index 0000000000..6fc10e854b --- /dev/null +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/utils/JpaIdGenerator.java @@ -0,0 +1,19 @@ +package org.keycloak.models.jpa.utils; + +import java.io.Serializable; + +import org.hibernate.HibernateException; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.id.IdentifierGenerator; +import org.keycloak.models.utils.KeycloakModelUtils; + +/** + * @author Marek Posolda + */ +public class JpaIdGenerator implements IdentifierGenerator { + + @Override + public Serializable generate(SessionImplementor session, Object object) throws HibernateException { + return KeycloakModelUtils.generateId(); + } +} diff --git a/model/jpa/src/main/resources/META-INF/services/org.keycloak.models.ModelProviderFactory b/model/jpa/src/main/resources/META-INF/services/org.keycloak.models.ModelProviderFactory new file mode 100644 index 0000000000..d981d8c615 --- /dev/null +++ b/model/jpa/src/main/resources/META-INF/services/org.keycloak.models.ModelProviderFactory @@ -0,0 +1 @@ +org.keycloak.models.jpa.JpaModelProviderFactory \ No newline at end of file diff --git a/model/jpa/src/test/resources/META-INF/persistence.xml b/model/jpa/src/test/resources/META-INF/persistence.xml new file mode 100755 index 0000000000..a150d05038 --- /dev/null +++ b/model/jpa/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,70 @@ + + + org.hibernate.ejb.HibernatePersistence + + org.keycloak.models.jpa.entities.ApplicationEntity + org.keycloak.models.jpa.entities.CredentialEntity + org.keycloak.models.jpa.entities.OAuthClientEntity + org.keycloak.models.jpa.entities.RealmEntity + org.keycloak.models.jpa.entities.RequiredCredentialEntity + org.keycloak.models.jpa.entities.AuthenticationProviderEntity + org.keycloak.models.jpa.entities.RoleEntity + org.keycloak.models.jpa.entities.SocialLinkEntity + org.keycloak.models.jpa.entities.AuthenticationLinkEntity + org.keycloak.models.jpa.entities.UserEntity + org.keycloak.models.jpa.entities.UserSessionEntity + org.keycloak.models.jpa.entities.ClientUserSessionAssociationEntity + org.keycloak.models.jpa.entities.UserRoleMappingEntity + org.keycloak.models.jpa.entities.UsernameLoginFailureEntity + org.keycloak.models.jpa.entities.ScopeMappingEntity + + true + + + + + + + + + + + + + + diff --git a/server/pom.xml b/server/pom.xml index d0318f4d45..2d8e61d684 100755 --- a/server/pom.xml +++ b/server/pom.xml @@ -49,27 +49,7 @@ org.keycloak - keycloak-model-hybrid - ${project.version} - - - org.keycloak - keycloak-model-realms-jpa - ${project.version} - - - org.keycloak - keycloak-model-users-jpa - ${project.version} - - - org.keycloak - keycloak-model-sessions-mem - ${project.version} - - - org.keycloak - keycloak-model-sessions-jpa + keycloak-model-jpa ${project.version} diff --git a/server/src/main/resources/META-INF/keycloak-server.json b/server/src/main/resources/META-INF/keycloak-server.json index 6133aa4876..7e3f2465b8 100755 --- a/server/src/main/resources/META-INF/keycloak-server.json +++ b/server/src/main/resources/META-INF/keycloak-server.json @@ -11,25 +11,13 @@ }, "model": { - "provider": "hybrid" + "provider": "jpa" }, "modelCache": { "provider": "${keycloak.model.cache.provider:}" }, - "modelRealms": { - "provider": "jpa" - }, - - "modelUsers": { - "provider": "jpa" - }, - - "modelSessions": { - "provider": "mem" - }, - "timer": { "provider": "basic" }, diff --git a/server/src/main/resources/META-INF/persistence.xml b/server/src/main/resources/META-INF/persistence.xml index bba0831dc6..a7040140f5 100755 --- a/server/src/main/resources/META-INF/persistence.xml +++ b/server/src/main/resources/META-INF/persistence.xml @@ -4,23 +4,21 @@ version="1.0"> java:jboss/datasources/ExampleDS - - org.keycloak.models.realms.jpa.entities.ApplicationEntity - org.keycloak.models.realms.jpa.entities.OAuthClientEntity - org.keycloak.models.realms.jpa.entities.RealmEntity - org.keycloak.models.realms.jpa.entities.RequiredCredentialEntity - org.keycloak.models.realms.jpa.entities.AuthenticationProviderEntity - org.keycloak.models.realms.jpa.entities.RoleEntity - org.keycloak.models.realms.jpa.entities.ScopeMappingEntity - - org.keycloak.models.users.jpa.entities.UserAttributeEntity - org.keycloak.models.users.jpa.entities.UserCredentialEntity - org.keycloak.models.users.jpa.entities.UserRoleMappingEntity - org.keycloak.models.users.jpa.entities.UserEntity - - org.keycloak.models.sessions.jpa.entities.ClientUserSessionAssociationEntity - org.keycloak.models.sessions.jpa.entities.UsernameLoginFailureEntity - org.keycloak.models.sessions.jpa.entities.UserSessionEntity + org.keycloak.models.jpa.entities.ApplicationEntity + org.keycloak.models.jpa.entities.CredentialEntity + org.keycloak.models.jpa.entities.OAuthClientEntity + org.keycloak.models.jpa.entities.RealmEntity + org.keycloak.models.jpa.entities.RequiredCredentialEntity + org.keycloak.models.jpa.entities.AuthenticationProviderEntity + org.keycloak.models.jpa.entities.RoleEntity + org.keycloak.models.jpa.entities.SocialLinkEntity + org.keycloak.models.jpa.entities.AuthenticationLinkEntity + org.keycloak.models.jpa.entities.UserEntity + org.keycloak.models.jpa.entities.UserSessionEntity + org.keycloak.models.jpa.entities.ClientUserSessionAssociationEntity + org.keycloak.models.jpa.entities.UsernameLoginFailureEntity + org.keycloak.models.jpa.entities.UserRoleMappingEntity + org.keycloak.models.jpa.entities.ScopeMappingEntity true @@ -28,7 +26,7 @@ - + java:jboss/datasources/ExampleDS org.keycloak.audit.jpa.EventEntity @@ -39,4 +37,5 @@ + diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml index 50466c81b6..052f6b1945 100755 --- a/testsuite/integration/pom.xml +++ b/testsuite/integration/pom.xml @@ -122,27 +122,7 @@ org.keycloak - keycloak-model-hybrid - ${project.version} - - - org.keycloak - keycloak-model-realms-jpa - ${project.version} - - - org.keycloak - keycloak-model-users-jpa - ${project.version} - - - org.keycloak - keycloak-model-sessions-mem - ${project.version} - - - org.keycloak - keycloak-model-sessions-jpa + keycloak-model-jpa ${project.version} diff --git a/testsuite/integration/src/main/resources/META-INF/keycloak-server.json b/testsuite/integration/src/main/resources/META-INF/keycloak-server.json index c39a794003..326c697f1e 100755 --- a/testsuite/integration/src/main/resources/META-INF/keycloak-server.json +++ b/testsuite/integration/src/main/resources/META-INF/keycloak-server.json @@ -14,7 +14,7 @@ }, "model": { - "provider": "${keycloak.model.provider:hybrid}", + "provider": "${keycloak.model.provider:jpa}", "mongo": { "host": "${keycloak.model.mongo.host:127.0.0.1}", "port": "${keycloak.model.mongo.port:27017}", @@ -27,18 +27,6 @@ "provider": "${keycloak.model.cache.provider:simple}" }, - "modelRealms": { - "provider": "jpa" - }, - - "modelUsers": { - "provider": "jpa" - }, - - "modelSessions": { - "provider": "mem" - }, - "timer": { "provider": "basic" }, diff --git a/testsuite/integration/src/main/resources/META-INF/persistence.xml b/testsuite/integration/src/main/resources/META-INF/persistence.xml index 5a261d7237..39dd390bc9 100755 --- a/testsuite/integration/src/main/resources/META-INF/persistence.xml +++ b/testsuite/integration/src/main/resources/META-INF/persistence.xml @@ -5,22 +5,21 @@ org.hibernate.ejb.HibernatePersistence - org.keycloak.models.realms.jpa.entities.ApplicationEntity - org.keycloak.models.realms.jpa.entities.OAuthClientEntity - org.keycloak.models.realms.jpa.entities.RealmEntity - org.keycloak.models.realms.jpa.entities.RequiredCredentialEntity - org.keycloak.models.realms.jpa.entities.AuthenticationProviderEntity - org.keycloak.models.realms.jpa.entities.RoleEntity - org.keycloak.models.realms.jpa.entities.ScopeMappingEntity - - org.keycloak.models.users.jpa.entities.UserAttributeEntity - org.keycloak.models.users.jpa.entities.UserCredentialEntity - org.keycloak.models.users.jpa.entities.UserRoleMappingEntity - org.keycloak.models.users.jpa.entities.UserEntity - - org.keycloak.models.sessions.jpa.entities.ClientUserSessionAssociationEntity - org.keycloak.models.sessions.jpa.entities.UsernameLoginFailureEntity - org.keycloak.models.sessions.jpa.entities.UserSessionEntity + org.keycloak.models.jpa.entities.ApplicationEntity + org.keycloak.models.jpa.entities.CredentialEntity + org.keycloak.models.jpa.entities.OAuthClientEntity + org.keycloak.models.jpa.entities.RealmEntity + org.keycloak.models.jpa.entities.RequiredCredentialEntity + org.keycloak.models.jpa.entities.AuthenticationProviderEntity + org.keycloak.models.jpa.entities.RoleEntity + org.keycloak.models.jpa.entities.SocialLinkEntity + org.keycloak.models.jpa.entities.AuthenticationLinkEntity + org.keycloak.models.jpa.entities.UserEntity + org.keycloak.models.jpa.entities.ClientUserSessionAssociationEntity + org.keycloak.models.jpa.entities.UserSessionEntity + org.keycloak.models.jpa.entities.UsernameLoginFailureEntity + org.keycloak.models.jpa.entities.UserRoleMappingEntity + org.keycloak.models.jpa.entities.ScopeMappingEntity true @@ -52,4 +51,38 @@ + + diff --git a/testsuite/performance/pom.xml b/testsuite/performance/pom.xml index 201abf381a..1ba9c0fc8c 100755 --- a/testsuite/performance/pom.xml +++ b/testsuite/performance/pom.xml @@ -40,31 +40,6 @@ keycloak-model-jpa ${project.version} - - org.keycloak - keycloak-model-hybrid - ${project.version} - - - org.keycloak - keycloak-model-realms-jpa - ${project.version} - - - org.keycloak - keycloak-model-users-jpa - ${project.version} - - - org.keycloak - keycloak-model-sessions-mem - ${project.version} - - - org.keycloak - keycloak-model-sessions-jpa - ${project.version} - org.keycloak keycloak-model-mongo diff --git a/testsuite/tools/pom.xml b/testsuite/tools/pom.xml index 31d14921ef..c630624317 100755 --- a/testsuite/tools/pom.xml +++ b/testsuite/tools/pom.xml @@ -66,26 +66,6 @@ keycloak-model-jpa ${project.version} - - org.keycloak - keycloak-model-hybrid - ${project.version} - - - org.keycloak - keycloak-model-realms-jpa - ${project.version} - - - org.keycloak - keycloak-model-users-jpa - ${project.version} - - - org.keycloak - keycloak-model-sessions-mem - ${project.version} - org.keycloak keycloak-audit-api