Details
diff --git a/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java b/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java
index 58ff08e..546b5e9 100644
--- a/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java
+++ b/audit/jpa/src/main/java/org/keycloak/audit/jpa/JpaAuditProviderFactory.java
@@ -5,6 +5,7 @@ import org.keycloak.audit.AuditProvider;
import org.keycloak.audit.AuditProviderFactory;
import org.keycloak.audit.EventType;
import org.keycloak.provider.ProviderSession;
+import org.keycloak.util.JpaUtils;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
@@ -28,7 +29,7 @@ public class JpaAuditProviderFactory implements AuditProviderFactory {
@Override
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");
if (include != null) {
diff --git a/core/src/main/java/org/keycloak/util/JpaUtils.java b/core/src/main/java/org/keycloak/util/JpaUtils.java
new file mode 100644
index 0000000..abb4efe
--- /dev/null
+++ b/core/src/main/java/org/keycloak/util/JpaUtils.java
@@ -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;
+ }
+}
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
index c6f3eb1..5be5fed 100755
--- 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
@@ -26,9 +26,7 @@ import org.hibernate.annotations.GenericGenerator;
*/
@Entity
@Table(uniqueConstraints = {
- @UniqueConstraint(columnNames = { "name", "application"}),
- @UniqueConstraint(columnNames = { "name", "realm" })
-
+ @UniqueConstraint(columnNames = { "name", "appRealmConstraint" })
})
@NamedQueries({
@NamedQuery(name="getAppRoleByName", query="select role from RoleEntity role where role.name = :name and role.application = :application"),
@@ -57,6 +55,9 @@ public class RoleEntity {
@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 = "role"))
private Collection<RoleEntity> compositeRoles = new ArrayList<RoleEntity>();
@@ -115,6 +116,7 @@ public class RoleEntity {
public void setRealm(RealmEntity realm) {
this.realm = realm;
+ this.appRealmConstraint = realm.getId();
}
public ApplicationEntity getApplication() {
@@ -123,6 +125,17 @@ public class RoleEntity {
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
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
index d873901..3b765b4 100755
--- 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
@@ -2,6 +2,7 @@ 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;
@@ -42,7 +43,7 @@ import java.util.Set;
@Entity
@Table(uniqueConstraints = {
@UniqueConstraint(columnNames = { "realm", "loginName" }),
- @UniqueConstraint(columnNames = { "realm", "email" })
+ @UniqueConstraint(columnNames = { "realm", "emailConstraint" })
})
public class UserEntity {
@Id
@@ -57,6 +58,8 @@ public class UserEntity {
protected boolean emailVerified;
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)
@JoinColumn(name = "realm")
@@ -116,6 +119,7 @@ public class UserEntity {
public void setEmail(String email) {
this.email = email;
+ this.emailConstraint = email != null ? email : KeycloakModelUtils.generateId();
}
public boolean isEnabled() {
@@ -126,6 +130,14 @@ public class UserEntity {
this.enabled = enabled;
}
+ public String getEmailConstraint() {
+ return emailConstraint;
+ }
+
+ public void setEmailConstraint(String emailConstraint) {
+ this.emailConstraint = emailConstraint;
+ }
+
public boolean isTotp() {
return totp;
}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java
index 6efe710..2865957 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaKeycloakSessionFactory.java
@@ -4,6 +4,7 @@ import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderSession;
+import org.keycloak.util.JpaUtils;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
@@ -19,7 +20,7 @@ public class JpaKeycloakSessionFactory implements KeycloakSessionFactory {
@Override
public void init(Config.Scope config) {
- emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store", getHibernateProperties());
+ emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store", JpaUtils.getHibernateProperties());
}
@Override
@@ -36,18 +37,4 @@ public class JpaKeycloakSessionFactory implements KeycloakSessionFactory {
public void 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;
- }
-
}