From f2a59aefa69562493c1f1dd2cfd524cf18a47c1b Mon Sep 17 00:00:00 2001
From: Hugo Renard <hugo.renard@protonmail.com>
Date: Tue, 22 Mar 2022 18:32:30 +0100
Subject: [PATCH] (feat) roles support

---
 .../java/sh/libre/scim/core/UserAdapter.java  | 28 +++++++++++++++++++
 .../scim/event/ScimEventListenerProvider.java | 18 ++++++------
 2 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/src/main/java/sh/libre/scim/core/UserAdapter.java b/src/main/java/sh/libre/scim/core/UserAdapter.java
index 4d7b21d..bc233cb 100644
--- a/src/main/java/sh/libre/scim/core/UserAdapter.java
+++ b/src/main/java/sh/libre/scim/core/UserAdapter.java
@@ -3,10 +3,13 @@ package sh.libre.scim.core;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
 import java.util.stream.Stream;
 
 import com.unboundid.scim2.common.types.Email;
 import com.unboundid.scim2.common.types.Meta;
+import com.unboundid.scim2.common.types.Role;
 import com.unboundid.scim2.common.types.UserResource;
 
 import org.jboss.logging.Logger;
@@ -21,6 +24,7 @@ public class UserAdapter extends Adapter<UserModel, UserResource> {
     private String displayName;
     private String email;
     private Boolean active;
+    private String[] roles;
 
     public UserAdapter(KeycloakSession session, String componentId) {
         super(session, componentId, "User", Logger.getLogger(UserAdapter.class));
@@ -66,6 +70,14 @@ public class UserAdapter extends Adapter<UserModel, UserResource> {
         }
     }
 
+    public String[] getRoles() {
+        return roles;
+    }
+
+    public void setRoles(String[] roles) {
+        this.roles = roles;
+    }
+
     @Override
     public Class<UserResource> getResourceClass() {
         return UserResource.class;
@@ -84,6 +96,15 @@ public class UserAdapter extends Adapter<UserModel, UserResource> {
         }
         setEmail(user.getEmail());
         setActive(user.isEnabled());
+        var rolesSet = new HashSet<String>();
+        user.getGroupsStream().flatMap(g -> g.getRoleMappingsStream())
+                .filter((r) -> r.getFirstAttribute("scim").equals("true")).map((r) -> r.getName())
+                .forEach(r -> rolesSet.add(r));
+        user.getRoleMappingsStream().filter((r) -> r.getFirstAttribute("scim").equals("true"))
+                .map((r) -> r.getName()).forEach(r -> rolesSet.add(r));
+        var roles = new String[rolesSet.size()];
+        rolesSet.toArray(roles);
+        setRoles(roles);
     }
 
     @Override
@@ -120,6 +141,13 @@ public class UserAdapter extends Adapter<UserModel, UserResource> {
             }
             user.setMeta(meta);
         }
+        List<Role> roles = new ArrayList<Role>();
+        for (var r : this.roles) {
+            var role = new Role();
+            role.setValue(r);
+            roles.add(role);
+        }
+        user.setRoles(roles);
         return user;
     }
 
diff --git a/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java b/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java
index 13ccbad..2a48ec6 100644
--- a/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java
+++ b/src/main/java/sh/libre/scim/event/ScimEventListenerProvider.java
@@ -1,7 +1,6 @@
 package sh.libre.scim.event;
 
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.regex.*;
 
 import org.jboss.logging.Logger;
 import org.keycloak.events.Event;
@@ -13,7 +12,6 @@ import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.GroupModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.UserModel;
-import org.keycloak.representations.idm.GroupRepresentation;
 
 import sh.libre.scim.core.GroupAdapter;
 import sh.libre.scim.core.ScimDispatcher;
@@ -81,12 +79,16 @@ public class ScimEventListenerProvider implements EventListenerProvider {
             }
         }
         if (event.getResourceType() == ResourceType.GROUP_MEMBERSHIP) {
-            ObjectMapper obj = new ObjectMapper();
-            try {
-                var groupRepresentation = obj.readValue(event.getRepresentation(), GroupRepresentation.class);
-                var group = getGroup(groupRepresentation.getId());
+            Pattern pattern = Pattern.compile("users/(.+)/groups/(.+)");
+            Matcher matcher = pattern.matcher(event.getResourcePath());
+            if (matcher.find()) {
+                var userId = matcher.group(1);
+                var groupId = matcher.group(2);
+                LOGGER.infof("%s %s from %s", event.getOperationType(), userId, groupId);
+                var group = getGroup(groupId);
                 dispatcher.run((client) -> client.replace(GroupAdapter.class, group));
-            } catch (JsonProcessingException e) {
+                var user = getUser(userId);
+                dispatcher.run((client) -> client.replace(UserAdapter.class, user));
             }
         }
     }
-- 
GitLab