From 95c6c5588f81989cce5e7b70f3f1499419298109 Mon Sep 17 00:00:00 2001
From: Hugo Renard <hugo.renard@protonmail.com>
Date: Wed, 16 Feb 2022 17:07:19 +0100
Subject: [PATCH] cascade delete scim resource

---
 .../java/sh/libre/scim/core/ScimClient.java   | 31 +++++++-----
 .../java/sh/libre/scim/jpa/ScimResource.java  | 49 +++++++++----------
 .../sh/libre/scim/jpa/ScimResourceId.java     | 20 ++++----
 .../META-INF/scim-resource-changelog.xml      |  2 +
 4 files changed, 53 insertions(+), 49 deletions(-)

diff --git a/src/main/java/sh/libre/scim/core/ScimClient.java b/src/main/java/sh/libre/scim/core/ScimClient.java
index da34206..7258127 100644
--- a/src/main/java/sh/libre/scim/core/ScimClient.java
+++ b/src/main/java/sh/libre/scim/core/ScimClient.java
@@ -23,6 +23,9 @@ import org.keycloak.component.ComponentModel;
 import org.keycloak.connections.jpa.JpaConnectionProvider;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.jpa.entities.ComponentEntity;
+import org.keycloak.models.jpa.entities.RealmEntity;
+
 import sh.libre.scim.jpa.ScimResource;
 
 public class ScimClient {
@@ -31,22 +34,18 @@ public class ScimClient {
     final private Client client = ResteasyClientBuilder.newClient();
     final private ScimService scimService;
     final private RetryRegistry registry;
-    final private String name;
     final private KeycloakSession session;
     final private String contentType;
-    final private String authMode;
-    final private String bearerToken;
+    final private ComponentModel model;
 
     public ScimClient(ComponentModel model, KeycloakSession session) {
-        this.name = model.getName();
+        this.model = model;
         this.contentType = model.get("content-type");
-        this.authMode = model.get("auth-mode");
-        this.bearerToken = model.get("auth-bearer-token");
 
         this.session = session;
         var target = client.target(model.get("endpoint"));
-        if (this.authMode.equals("BEARER")) {
-            target = target.register(new BearerAuthentication(this.bearerToken));
+        if (model.get("auth-mode").equals("BEARER")) {
+            target = target.register(new BearerAuthentication(model.get("auth-bearer-token")));
         }
 
         scimService = new ScimService(target);
@@ -66,6 +65,14 @@ public class ScimClient {
         return session.getContext().getRealm().getId();
     }
 
+    private RealmEntity getRealmEntity() {
+        return getEM().getReference(RealmEntity.class, getRealmId());
+    }
+
+    private ComponentEntity getSPEntity() {
+        return getEM().getReference(ComponentEntity.class, this.model.getId());
+    }
+
     public void createUser(UserModel kcUser) {
         LOGGER.info("Create User");
         var user = toUser(kcUser);
@@ -129,9 +136,9 @@ public class ScimClient {
     private TypedQuery<ScimResource> queryUser(String query) {
         return getEM()
                 .createNamedQuery(query, ScimResource.class)
-                .setParameter("realmId", getRealmId())
+                .setParameter("realm", getRealmEntity())
                 .setParameter("type", "Users")
-                .setParameter("serviceProvider", name);
+                .setParameter("serviceProvider", getSPEntity());
     }
 
     private ScimResource querUserById(String id) {
@@ -141,8 +148,8 @@ public class ScimClient {
     private ScimResource scimUser() {
         var resource = new ScimResource();
         resource.setType("Users");
-        resource.setRealmId(getRealmId());
-        resource.setServiceProvider(name);
+        resource.setRealm(getRealmEntity());
+        resource.setServiceProvider(getSPEntity());
         return resource;
     }
 
diff --git a/src/main/java/sh/libre/scim/jpa/ScimResource.java b/src/main/java/sh/libre/scim/jpa/ScimResource.java
index a0e9922..94d041e 100644
--- a/src/main/java/sh/libre/scim/jpa/ScimResource.java
+++ b/src/main/java/sh/libre/scim/jpa/ScimResource.java
@@ -4,61 +4,56 @@ import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.IdClass;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
 import javax.persistence.NamedQuery;
 import javax.persistence.NamedQueries;
 import javax.persistence.Table;
 
+import org.keycloak.models.jpa.entities.ComponentEntity;
+import org.keycloak.models.jpa.entities.RealmEntity;
+
 @Entity
 @IdClass(ScimResourceId.class)
 @Table(name = "SCIM_RESOURCE")
 @NamedQueries({
-                @NamedQuery(name = "findByLocalId", query = "from ScimResource where realmId = :realmId and type = :type and serviceProvider = :serviceProvider and localId = :id"),
-                @NamedQuery(name = "findByRemoteId", query = "from ScimResource where realmId = :realmId and type = :type and serviceProvider = :serviceProvider and remoteId = :id") })
+                @NamedQuery(name = "findByLocalId", query = "from ScimResource where realm = :realm and type = :type and serviceProvider = :serviceProvider and localId = :id"),
+                @NamedQuery(name = "findByRemoteId", query = "from ScimResource where realm = :realm and type = :type and serviceProvider = :serviceProvider and remoteId = :id") })
 public class ScimResource {
-
         @Id
-        @Column(name = "REALM_ID", nullable = false)
-        private String realmId;
+        @ManyToOne
+        @JoinColumn(name = "REALM_ID", referencedColumnName = "ID")
+        private RealmEntity realm;
 
         @Id
-        @Column(name = "SERVICE_PROVIDER", nullable = false)
-        private String serviceProvider;
-
+        @ManyToOne
+        @JoinColumn(name = "SERVICE_PROVIDER", referencedColumnName = "ID")
+        private ComponentEntity serviceProvider;
+        
         @Id
         @Column(name = "TYPE", nullable = false)
         private String type;
 
         @Id
-        @Column(name = "REMOTE_ID", nullable = false)
-        private String remoteId;
-
         @Column(name = "LOCAL_ID", nullable = false)
         private String localId;
 
-        // public ScimResource() {
-        // }
-
-        // public ScimResource(String realmId, String serviceProvider, String type, String remoteId, String localId) {
-        //         this.realmId = realmId;
-        //         this.serviceProvider = serviceProvider;
-        //         this.type = type;
-        //         this.remoteId = remoteId;
-        //         this.localId = localId;
-        // }
+        @Column(name = "REMOTE_ID", nullable = false)
+        private String remoteId;
 
-        public String getRealmId() {
-                return realmId;
+        public RealmEntity getRealm() {
+                return realm;
         }
 
-        public void setRealmId(String realmId) {
-                this.realmId = realmId;
+        public void setRealm(RealmEntity realm) {
+                this.realm = realm;
         }
 
-        public String getServiceProvider() {
+        public ComponentEntity getServiceProvider() {
                 return serviceProvider;
         }
 
-        public void setServiceProvider(String serviceProvider) {
+        public void setServiceProvider(ComponentEntity serviceProvider) {
                 this.serviceProvider = serviceProvider;
         }
 
diff --git a/src/main/java/sh/libre/scim/jpa/ScimResourceId.java b/src/main/java/sh/libre/scim/jpa/ScimResourceId.java
index c97ff53..e4eb1b3 100644
--- a/src/main/java/sh/libre/scim/jpa/ScimResourceId.java
+++ b/src/main/java/sh/libre/scim/jpa/ScimResourceId.java
@@ -4,7 +4,7 @@ import java.io.Serializable;
 import java.util.Objects;
 
 public class ScimResourceId implements Serializable {
-    private String realmId;
+    private String realm;
     private String serviceProvider;
     private String type;
     private String remoteId;
@@ -12,19 +12,19 @@ public class ScimResourceId implements Serializable {
     public ScimResourceId() {
     }
 
-    public ScimResourceId(String realmId, String serviceProvider, String type, String remoteId) {
-        this.realmId = realmId;
+    public ScimResourceId(String realm, String serviceProvider, String type, String remoteId) {
+        this.realm = realm;
         this.serviceProvider = serviceProvider;
         this.type = type;
         this.remoteId = remoteId;
     }
 
-    public String getRealmId() {
-        return realmId;
+    public String getRealm() {
+        return realm;
     }
 
-    public void setRealmId(String realmId) {
-        this.realmId = realmId;
+    public void setRealm(String realm) {
+        this.realm = realm;
     }
 
     public String getServiceProvider() {
@@ -44,7 +44,7 @@ public class ScimResourceId implements Serializable {
     }
 
     public String getRemoteId() {
-        return realmId;
+        return remoteId;
     }
 
     public void setRemoteId(String remoteId) {
@@ -58,7 +58,7 @@ public class ScimResourceId implements Serializable {
         if (!(other instanceof ScimResourceId))
             return false;
         var o = (ScimResourceId) other;
-        return (o.realmId == realmId &&
+        return (o.realm == realm &&
                 o.serviceProvider == serviceProvider &&
                 o.type == type &&
                 o.remoteId == remoteId);
@@ -66,6 +66,6 @@ public class ScimResourceId implements Serializable {
 
     @Override
     public int hashCode() {
-        return Objects.hash(realmId, serviceProvider, type, remoteId);
+        return Objects.hash(realm, serviceProvider, type, remoteId);
     }
 }
diff --git a/src/main/resources/META-INF/scim-resource-changelog.xml b/src/main/resources/META-INF/scim-resource-changelog.xml
index 954a44a..ca0c39e 100644
--- a/src/main/resources/META-INF/scim-resource-changelog.xml
+++ b/src/main/resources/META-INF/scim-resource-changelog.xml
@@ -21,6 +21,8 @@
         </createTable>
 
         <addPrimaryKey constraintName="PK_SCIM_RESOURCE" tableName="SCIM_RESOURCE" columnNames="REALM_ID,SERVICE_PROVIDER,TYPE,REMOTE_ID" />
+        <addForeignKeyConstraint baseTableName="SCIM_RESOURCE" baseColumnNames="REALM_ID" constraintName="FK_SCIM_RESOURCE_REALM" referencedTableName="REALM" referencedColumnNames="ID" onDelete="CASCADE" onUpdate="CASCADE" />
+        <addForeignKeyConstraint baseTableName="SCIM_RESOURCE" baseColumnNames="SERVICE_PROVIDER" constraintName="FK_SCIM_RESOURCE_COMPONENT" referencedTableName="COMPONENT" referencedColumnNames="ID" onDelete="CASCADE" onUpdate="CASCADE" />
 
     </changeSet>
 
-- 
GitLab