Merge pull request #472 from mposolda/db-fixes

KEYCLOAK-534 Fix MS-SQL, Oracle and Sybase
This commit is contained in:
Stian Thorgersen 2014-06-18 13:32:57 +01:00
commit d1c890db18
14 changed files with 72 additions and 52 deletions

View file

@ -5,6 +5,7 @@ import org.keycloak.audit.AuditProvider;
import org.keycloak.audit.AuditProviderFactory; import org.keycloak.audit.AuditProviderFactory;
import org.keycloak.audit.EventType; import org.keycloak.audit.EventType;
import org.keycloak.provider.ProviderSession; import org.keycloak.provider.ProviderSession;
import org.keycloak.util.JpaUtils;
import javax.persistence.EntityManagerFactory; import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence; import javax.persistence.Persistence;
@ -28,7 +29,7 @@ public class JpaAuditProviderFactory implements AuditProviderFactory {
@Override @Override
public void init(Config.Scope config) { public void init(Config.Scope config) {
emf = Persistence.createEntityManagerFactory("jpa-keycloak-audit-store"); emf = Persistence.createEntityManagerFactory("jpa-keycloak-audit-store", JpaUtils.getHibernateProperties());
String[] include = config.getArray("include-events"); String[] include = config.getArray("include-events");
if (include != null) { if (include != null) {

View file

@ -0,0 +1,22 @@
package org.keycloak.util;
import java.util.Properties;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class JpaUtils {
// Allows to override some properties in persistence.xml by system properties
public static Properties getHibernateProperties() {
Properties result = new Properties();
for (Object property : System.getProperties().keySet()) {
if (property.toString().startsWith("hibernate.")) {
String propValue = System.getProperty(property.toString());
result.put(property, propValue);
}
}
return result;
}
}

View file

@ -23,11 +23,6 @@
</repositories> </repositories>
<dependencies> <dependencies>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.jboss.spec.javax.servlet</groupId> <groupId>org.jboss.spec.javax.servlet</groupId>
<artifactId>jboss-servlet-api_3.0_spec</artifactId> <artifactId>jboss-servlet-api_3.0_spec</artifactId>

View file

@ -142,7 +142,7 @@ public class ApplicationAdapter extends ClientAdapter implements ApplicationMode
applicationEntity.getRoles().remove(role); applicationEntity.getRoles().remove(role);
applicationEntity.getDefaultRoles().remove(role); applicationEntity.getDefaultRoles().remove(role);
em.createNativeQuery("delete from CompositeRole where role = :role").setParameter("role", role).executeUpdate(); em.createNativeQuery("delete from CompositeRole where childRole = :role").setParameter("role", role).executeUpdate();
em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", role).executeUpdate(); em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", role).executeUpdate();
em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", role).executeUpdate(); em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", role).executeUpdate();
role.setApplication(null); role.setApplication(null);

View file

@ -4,6 +4,7 @@ import org.keycloak.Config;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderSession; import org.keycloak.provider.ProviderSession;
import org.keycloak.util.JpaUtils;
import javax.persistence.EntityManagerFactory; import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence; import javax.persistence.Persistence;
@ -19,7 +20,7 @@ public class JpaKeycloakSessionFactory implements KeycloakSessionFactory {
@Override @Override
public void init(Config.Scope config) { public void init(Config.Scope config) {
emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store", getHibernateProperties()); emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store", JpaUtils.getHibernateProperties());
} }
@Override @Override
@ -36,18 +37,4 @@ public class JpaKeycloakSessionFactory implements KeycloakSessionFactory {
public void close() { public void close() {
emf.close(); emf.close();
} }
// Allows to override some properties in persistence.xml by system properties
protected Properties getHibernateProperties() {
Properties result = new Properties();
for (Object property : System.getProperties().keySet()) {
if (property.toString().startsWith("hibernate.")) {
String propValue = System.getProperty(property.toString());
result.put(property, propValue);
}
}
return result;
}
} }

View file

@ -928,7 +928,7 @@ public class RealmAdapter implements RealmModel {
realm.getRoles().remove(role); realm.getRoles().remove(role);
realm.getDefaultRoles().remove(role); realm.getDefaultRoles().remove(role);
em.createNativeQuery("delete from CompositeRole where role = :role").setParameter("role", roleEntity).executeUpdate(); em.createNativeQuery("delete from CompositeRole where childRole = :role").setParameter("role", roleEntity).executeUpdate();
em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate(); em.createQuery("delete from " + UserRoleMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate();
em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate(); em.createQuery("delete from " + ScopeMappingEntity.class.getSimpleName() + " where role = :role").setParameter("role", roleEntity).executeUpdate();

View file

@ -3,6 +3,7 @@ package org.keycloak.models.jpa.entities;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
@ -20,7 +21,9 @@ public class AbstractRoleMappingEntity {
protected String id; protected String id;
@ManyToOne(fetch= FetchType.LAZY) @ManyToOne(fetch= FetchType.LAZY)
protected UserEntity user; protected UserEntity user;
@ManyToOne(fetch= FetchType.LAZY) @ManyToOne(fetch= FetchType.LAZY)
@JoinColumn(name="roleId")
protected RoleEntity role; protected RoleEntity role;
public String getId() { public String getId() {

View file

@ -8,7 +8,9 @@ import javax.persistence.ElementCollection;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKeyColumn; import javax.persistence.MapKeyColumn;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
@ -16,6 +18,7 @@ import org.hibernate.annotations.GenericGenerator;
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@Entity @Entity
@Table(name="AuthProviderEntity")
public class AuthenticationProviderEntity { public class AuthenticationProviderEntity {
@Id @Id
@ -30,7 +33,9 @@ public class AuthenticationProviderEntity {
@ElementCollection @ElementCollection
@MapKeyColumn(name="name") @MapKeyColumn(name="name")
@Column(name="value") @Column(name="value")
@CollectionTable @CollectionTable(name="AuthProviderEntity_cfg", joinColumns = {
@JoinColumn(name = "AuthProviderEntity_id")
})
private Map<String, String> config; private Map<String, String> config;
public String getId() { public String getId() {

View file

@ -9,12 +9,14 @@ import javax.persistence.Id;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries; import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery; import javax.persistence.NamedQuery;
import javax.persistence.Table;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@Entity @Entity
@Table(name = "ClientUserSessionAscEntity")
@NamedQueries({ @NamedQueries({
@NamedQuery(name = "getAllClientUserSessions", query = "select s from ClientUserSessionAssociationEntity s"), @NamedQuery(name = "getAllClientUserSessions", query = "select s from ClientUserSessionAssociationEntity s"),
@NamedQuery(name = "getClientUserSessionBySession", query = "select s from ClientUserSessionAssociationEntity s where s.session = :session"), @NamedQuery(name = "getClientUserSessionBySession", query = "select s from ClientUserSessionAssociationEntity s where s.session = :session"),

View file

@ -26,9 +26,7 @@ import org.hibernate.annotations.GenericGenerator;
*/ */
@Entity @Entity
@Table(uniqueConstraints = { @Table(uniqueConstraints = {
@UniqueConstraint(columnNames = { "name", "application"}), @UniqueConstraint(columnNames = { "name", "appRealmConstraint" })
@UniqueConstraint(columnNames = { "name", "realm" })
}) })
@NamedQueries({ @NamedQueries({
@NamedQuery(name="getAppRoleByName", query="select role from RoleEntity role where role.name = :name and role.application = :application"), @NamedQuery(name="getAppRoleByName", query="select role from RoleEntity role where role.name = :name and role.application = :application"),
@ -57,8 +55,11 @@ public class RoleEntity {
@JoinColumn(name = "application") @JoinColumn(name = "application")
private ApplicationEntity 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 = {}) @ManyToMany(fetch = FetchType.LAZY, cascade = {})
@JoinTable(name = "CompositeRole", joinColumns = @JoinColumn(name = "composite"), inverseJoinColumns = @JoinColumn(name = "role")) @JoinTable(name = "CompositeRole", joinColumns = @JoinColumn(name = "composite"), inverseJoinColumns = @JoinColumn(name = "childRole"))
private Collection<RoleEntity> compositeRoles = new ArrayList<RoleEntity>(); private Collection<RoleEntity> compositeRoles = new ArrayList<RoleEntity>();
public String getId() { public String getId() {
@ -115,6 +116,7 @@ public class RoleEntity {
public void setRealm(RealmEntity realm) { public void setRealm(RealmEntity realm) {
this.realm = realm; this.realm = realm;
this.appRealmConstraint = realm.getId();
} }
public ApplicationEntity getApplication() { public ApplicationEntity getApplication() {
@ -123,6 +125,17 @@ public class RoleEntity {
public void setApplication(ApplicationEntity application) { public void setApplication(ApplicationEntity application) {
this.application = 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 @Override

View file

@ -6,6 +6,7 @@ import javax.persistence.Entity;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries; import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery; import javax.persistence.NamedQuery;
@ -27,7 +28,9 @@ public class ScopeMappingEntity {
protected String id; protected String id;
@ManyToOne(fetch= FetchType.LAZY) @ManyToOne(fetch= FetchType.LAZY)
protected ClientEntity client; protected ClientEntity client;
@ManyToOne(fetch= FetchType.LAZY) @ManyToOne(fetch= FetchType.LAZY)
@JoinColumn(name="roleId")
protected RoleEntity role; protected RoleEntity role;
public String getId() { public String getId() {

View file

@ -2,6 +2,7 @@ package org.keycloak.models.jpa.entities;
import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.GenericGenerator;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import javax.persistence.CascadeType; import javax.persistence.CascadeType;
import javax.persistence.CollectionTable; import javax.persistence.CollectionTable;
@ -42,7 +43,7 @@ import java.util.Set;
@Entity @Entity
@Table(uniqueConstraints = { @Table(uniqueConstraints = {
@UniqueConstraint(columnNames = { "realm", "loginName" }), @UniqueConstraint(columnNames = { "realm", "loginName" }),
@UniqueConstraint(columnNames = { "realm", "email" }) @UniqueConstraint(columnNames = { "realm", "emailConstraint" })
}) })
public class UserEntity { public class UserEntity {
@Id @Id
@ -57,6 +58,8 @@ public class UserEntity {
protected boolean emailVerified; protected boolean emailVerified;
protected int notBefore; protected int notBefore;
// 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) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "realm") @JoinColumn(name = "realm")
@ -116,6 +119,7 @@ public class UserEntity {
public void setEmail(String email) { public void setEmail(String email) {
this.email = email; this.email = email;
this.emailConstraint = email != null ? email : KeycloakModelUtils.generateId();
} }
public boolean isEnabled() { public boolean isEnabled() {
@ -126,6 +130,14 @@ public class UserEntity {
this.enabled = enabled; this.enabled = enabled;
} }
public String getEmailConstraint() {
return emailConstraint;
}
public void setEmailConstraint(String emailConstraint) {
this.emailConstraint = emailConstraint;
}
public boolean isTotp() { public boolean isTotp() {
return totp; return totp;
} }

View file

@ -260,23 +260,6 @@
<groupId>org.mongodb</groupId> <groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId> <artifactId>mongo-java-driver</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-common</artifactId>
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-api</artifactId>
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-impl</artifactId>
</dependency>
<dependency>
<groupId>org.picketlink</groupId>
<artifactId>picketlink-idm-simple-schema</artifactId>
</dependency>
<!-- export/import --> <!-- export/import -->
<dependency> <dependency>

View file

@ -97,12 +97,6 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-authentication-api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-export-import-api</artifactId> <artifactId>keycloak-export-import-api</artifactId>