SI-2473-Acknowledge-Client-Roles
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakClientRoles.java b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakClientRoles.java
new file mode 100644
index 0000000..6536a21
--- /dev/null
+++ b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakClientRoles.java
@@ -0,0 +1,45 @@
+/**
+******************************************************************************
+* Copyright © 2017-2018 PTA GmbH.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* 
+*     http://www.eclipse.org/legal/epl-v10.html
+* 
+******************************************************************************
+*/
+package org.eclipse.openk.portal.auth2.model;
+
+import java.util.List;
+
+public class KeyCloakClientRoles {
+
+  private String id;
+  private String client;
+  private List<KeyCloakRole> mappings;
+
+  public String getId() {
+    return id;
+  }
+
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  public String getClient() {
+    return client;
+  }
+
+  public void setClient(String client) {
+    this.client = client;
+  }
+
+  public List<KeyCloakRole> getMappings() {
+    return mappings;
+  }
+
+  public void setMappings(List<KeyCloakRole> mappings) {
+    this.mappings = mappings;
+  }
+}
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakRoles.java b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakRoles.java
new file mode 100644
index 0000000..643b105
--- /dev/null
+++ b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakRoles.java
@@ -0,0 +1,38 @@
+/**
+******************************************************************************
+* Copyright © 2017-2018 PTA GmbH.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* 
+*     http://www.eclipse.org/legal/epl-v10.html
+* 
+******************************************************************************
+*/
+package org.eclipse.openk.portal.auth2.model;
+
+import java.util.List;
+import java.util.Map;
+
+public class KeyCloakRoles {
+
+  List<KeyCloakRole> realmMappings;
+
+  private Map<String, KeyCloakClientRoles> clientMappings;
+
+  public List<KeyCloakRole> getRealmMappings() {
+    return realmMappings;
+  }
+
+  public void setRealmMappings(List<KeyCloakRole> realmMappings) {
+    this.realmMappings = realmMappings;
+  }
+
+  public Map<String, KeyCloakClientRoles> getClientMappings() {
+    return clientMappings;
+  }
+
+  public void setClientMappings(Map<String, KeyCloakClientRoles> clientMappings) {
+    this.clientMappings = clientMappings;
+  }
+}
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakUser.java b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakUser.java
index 67bc1ce..58aeb90 100644
--- a/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakUser.java
+++ b/src/main/java/org/eclipse/openk/portal/auth2/model/KeyCloakUser.java
@@ -24,6 +24,7 @@
     private String firstName;
     private String lastName;
     private String name;
+    private List<String> allRoles;
     private List<String> realmRoles;
     private Map<String, List<String>> clientRoles;
 
@@ -75,6 +76,14 @@
         return emailVerified;
     }
 
+    public List<String> getAllRoles() {
+        return allRoles;
+    }
+
+    public void setAllRoles(List<String> allRoles) {
+        this.allRoles = allRoles;
+    }
+
     public List<String> getRealmRoles() {
         return realmRoles;
     }
diff --git a/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java b/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java
index c830013..afd04df 100644
--- a/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java
+++ b/src/main/java/org/eclipse/openk/portal/auth2/util/JwtHelper.java
@@ -18,7 +18,9 @@
 import org.eclipse.openk.portal.auth2.model.JwtHeader;
 import org.eclipse.openk.portal.auth2.model.JwtPayload;
 import org.eclipse.openk.portal.auth2.model.JwtToken;
+import org.eclipse.openk.portal.auth2.model.KeyCloakClientRoles;
 import org.eclipse.openk.portal.auth2.model.KeyCloakRole;
+import org.eclipse.openk.portal.auth2.model.KeyCloakRoles;
 import org.eclipse.openk.portal.auth2.model.KeyCloakUser;
 import com.google.gson.JsonSyntaxException;
 import com.google.gson.reflect.TypeToken;
@@ -26,13 +28,18 @@
 import java.lang.reflect.Type;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+
 import org.apache.log4j.Logger;
 import org.eclipse.openk.portal.common.BackendConfig;
 import org.eclipse.openk.portal.common.JsonGeneratorBase;
 import org.eclipse.openk.portal.exceptions.PortalInternalServerError;
 import org.keycloak.common.util.Base64Url;
 
+import static org.eclipse.openk.portal.common.JsonGeneratorBase.getGson;
+
 public class JwtHelper {
 
   private static final Logger logger = Logger.getLogger(JwtHelper.class.getName());
@@ -69,7 +76,7 @@
   }
 
   public static List<KeyCloakRole> getRolesForUser(JwtToken jwtToken, String id) throws PortalInternalServerError {
-    String roles = sendGet(BackendConfig.getInstance().getAuthServerUrl() + "auth/admin/realms/" + BackendConfig.getInstance().getKeycloakRealm() + "/users/" + id + "/role-mappings/realm",
+    String roles = sendGet(BackendConfig.getInstance().getAuthServerUrl() + "auth/admin/realms/" + BackendConfig.getInstance().getKeycloakRealm() + "/users/" + id + "/role-mappings/",
         MediaType.APPLICATION_JSON, jwtToken.getAccessToken());
     return getRolesListFromJson(roles);
   }
@@ -99,9 +106,24 @@
 
   public static List<KeyCloakRole> getRolesListFromJson(String json) throws PortalInternalServerError {
     try {
-      Type listType = new TypeToken<List<KeyCloakRole>>() {
-      }.getType();
-      return JsonGeneratorBase.getGson().fromJson(json, listType);
+      List<KeyCloakRole> allRoles = new ArrayList<>();
+      KeyCloakRoles keyCloakRoles = getGson().fromJson(json, KeyCloakRoles.class);
+      List<KeyCloakRole> realmRoles = keyCloakRoles.getRealmMappings();
+
+      if (realmRoles != null) {
+        allRoles.addAll(realmRoles);
+      }
+
+      Map<String, KeyCloakClientRoles> clientMappings = keyCloakRoles.getClientMappings();
+      if (clientMappings != null) {
+        KeyCloakClientRoles keyCloakClientRoles = clientMappings.get(BackendConfig.getInstance().getKeycloakClient());
+        if (keyCloakClientRoles != null){
+          List<KeyCloakRole> clientRoles = keyCloakClientRoles.getMappings();
+          allRoles.addAll(clientRoles);
+        }
+      }
+
+      return allRoles;
     } catch (JsonSyntaxException ex) {
       logger.error("Error in getRolesListFromJson", ex);
       throw new PortalInternalServerError("JsonSyntaxException");
diff --git a/src/main/java/org/eclipse/openk/portal/common/UserCacheTimerTask.java b/src/main/java/org/eclipse/openk/portal/common/UserCacheTimerTask.java
index e4d572c..3a192f1 100644
--- a/src/main/java/org/eclipse/openk/portal/common/UserCacheTimerTask.java
+++ b/src/main/java/org/eclipse/openk/portal/common/UserCacheTimerTask.java
@@ -63,7 +63,7 @@
       for (KeyCloakRole keyCloakRole : rolesForUser) {
         rolesList.add(keyCloakRole.getName());
       }
-      user.setRealmRoles(rolesList);
+      user.setAllRoles(rolesList);
       allUsersWithRoles.add(user);
     }
     return allUsersWithRoles;
diff --git a/src/main/java/org/eclipse/openk/portal/controller/BackendController.java b/src/main/java/org/eclipse/openk/portal/controller/BackendController.java
index caf8388..495bd77 100644
--- a/src/main/java/org/eclipse/openk/portal/controller/BackendController.java
+++ b/src/main/java/org/eclipse/openk/portal/controller/BackendController.java
@@ -36,13 +36,13 @@
         List<KeyCloakUser> keyCloakUsers = UserCache.getInstance().getKeyCloakUsers();
 
         for (KeyCloakUser user : keyCloakUsers) {
-            List<String> realmRoles = user.getRealmRoles();
-            if (realmRoles ==  null) {
+            List<String> allRoles = user.getAllRoles();
+            if (allRoles ==  null) {
                 continue;
             }
 
-            for (String realmRole : realmRoles) {
-                if(realmRole.equals(roleToCheck)){
+            for (String role : allRoles) {
+                if(role.equals(roleToCheck)){
                     usersWithRole.add(user);
                     break;
                 }
diff --git a/src/main/resources/backendConfigDevLocal.json b/src/main/resources/backendConfigDevLocal.json
index 430658e..38dd236 100644
--- a/src/main/resources/backendConfigDevLocal.json
+++ b/src/main/resources/backendConfigDevLocal.json
@@ -1,8 +1,8 @@
 {
   "internalSessionLengthMillis": 3600000,
   "reloadUsersInSec": 300,
-  "authServerUrl": "http://entjava002:8080/",
-  "keycloakRealm": "elogbook",
+  "authServerUrl": "http://entopkon:8080/",
+  "keycloakRealm": "Elogbook",
   "keycloakClient": "elogbook-backend",
   "keycloakAdmin": "admin",
   "keycloakPW": "admin",
diff --git a/src/main/resources/moduleConfigDevLocal.json b/src/main/resources/moduleConfigDevLocal.json
index da34f80..3010aeb 100644
--- a/src/main/resources/moduleConfigDevLocal.json
+++ b/src/main/resources/moduleConfigDevLocal.json
@@ -35,5 +35,23 @@
     "link": "http://localhost:4220/",
     "pictureLink": "https://www.openkonsequenz.de//components/com_flexicontent/librairies/phpthumb/phpThumb.php?src=/medien/cache/main_image/l_ok_module5.jpg",
     "requiredRole": "planned-policies-access"
+  },
+  {
+    "name": "Kontaktstammdaten",
+    "cols": 1,
+    "rows": 1,
+    "color": "#ffffff",
+    "link": "http://entdockergss:4222",
+    "pictureLink": "assets/img/kontaktstammdaten_kachel.jpg",
+    "requiredRole": "kon-access"
+  },
+  {
+    "name": "Kontaktstammdaten Local",
+    "cols": 1,
+    "rows": 1,
+    "color": "#ffffff",
+    "link": "http://localhost:4200",
+    "pictureLink": "assets/img/kontaktstammdaten_kachel.jpg",
+    "requiredRole": "kon-access"
   }
 ]
diff --git a/src/test/java/org/eclipse/openk/portal/common/UserCacheTimerTaskTest.java b/src/test/java/org/eclipse/openk/portal/common/UserCacheTimerTaskTest.java
index 1c3e49a..cf4f250 100644
--- a/src/test/java/org/eclipse/openk/portal/common/UserCacheTimerTaskTest.java
+++ b/src/test/java/org/eclipse/openk/portal/common/UserCacheTimerTaskTest.java
@@ -23,9 +23,11 @@
 import java.util.List;
 import org.eclipse.openk.portal.auth2.model.JwtToken;
 import org.eclipse.openk.portal.auth2.model.KeyCloakRole;
+import org.eclipse.openk.portal.auth2.model.KeyCloakRoles;
 import org.eclipse.openk.portal.auth2.model.KeyCloakUser;
 import org.eclipse.openk.portal.auth2.util.JwtHelper;
 import org.eclipse.openk.portal.common.util.ResourceLoaderBase;
+import org.eclipse.openk.portal.exceptions.PortalInternalServerError;
 import org.eclipse.openk.portal.viewmodel.UserCache;
 import org.junit.Before;
 import org.junit.Test;
@@ -43,7 +45,6 @@
     @Before
     public void prepareTests() {
         task = new UserCacheTimerTask();
-        PowerMock.mockStatic(JwtHelper.class);
     }
 
     @Test
@@ -53,14 +54,14 @@
 
         String jsonKeyCloakUser = super.loadStringFromResource("testKeyCloakUsers.json");
         Type listTypeKeyCloakUser = new TypeToken<List<KeyCloakUser>>(){}.getType();
-        List<KeyCloakUser> keyCloakUsersList = JsonGeneratorBase.getGson().fromJson(jsonKeyCloakUser, listTypeKeyCloakUser);
+        List<KeyCloakUser> keyCloakUsersList = getGson().fromJson(jsonKeyCloakUser, listTypeKeyCloakUser);
         keyCloakUsersList.remove(1);
         keyCloakUsersList.remove(1);
 
-        String jsonKeyCloakRoles = super.loadStringFromResource("testKeyCloakRoles.json");
-        Type listTypeKeyCloakRole = new TypeToken<List<KeyCloakRole>>(){}.getType();
-        List<KeyCloakRole> keyCloakRolesList = JsonGeneratorBase.getGson().fromJson(jsonKeyCloakRoles, listTypeKeyCloakRole);
+        String jsonKeyCloakRoles = super.loadStringFromResource("testKeyCloakClientAndRealmRoles.json");
+        List<KeyCloakRole> keyCloakRolesList = JwtHelper.getRolesListFromJson(jsonKeyCloakRoles);
 
+        PowerMock.mockStatic(JwtHelper.class);
         expect(JwtHelper.login(BackendConfig.getInstance().getKeycloakAdmin(), BackendConfig.getInstance().getKeycloakPW())).andReturn(jwt);
         expect(JwtHelper.getUsers(jwt, BackendConfig.getInstance().getMaxLoadUsers())).andReturn(keyCloakUsersList);
         expect(JwtHelper.getRolesForUser(jwt, keyCloakUsersList.get(0).getId())).andReturn(keyCloakRolesList);
@@ -71,14 +72,15 @@
 
         List<KeyCloakUser> keyCloakUsersResult = UserCache.getInstance().getKeyCloakUsers();
 
-        assertTrue(keyCloakUsersResult.size() == 1);
-        assertTrue(keyCloakUsersResult.get(0).getRealmRoles().size() == 8);
-        assertTrue(keyCloakUsersResult.get(0).getRealmRoles().get(0).equals("elogbook-superuser"));
-        assertTrue(keyCloakUsersResult.get(0).getRealmRoles().get(6).equals("elogbook-access"));
+        assertEquals(1, keyCloakUsersResult.size());
+        assertEquals(18, keyCloakUsersResult.get(0).getAllRoles().size());
+        assertEquals("feedin-management-access", keyCloakUsersResult.get(0).getAllRoles().get(0));
+        assertEquals("testclientrole", keyCloakUsersResult.get(0).getAllRoles().get(17));
     }
 
     @Test
     public void testGetKeyCloakUsers_EmptyToken() throws Exception {
+        PowerMock.mockStatic(JwtHelper.class);
         List<KeyCloakUser> compList = new ArrayList<>();
         UserCache.getInstance().setKeyCloakUsers(compList);
 
@@ -97,6 +99,7 @@
 
     @Test
     public void testGetKeyCloakUsers_null() throws Exception {
+        PowerMock.mockStatic(JwtHelper.class);
         List<KeyCloakUser> compList = new ArrayList<>();
         UserCache.getInstance().setKeyCloakUsers(compList);
 
@@ -116,6 +119,7 @@
 
     @Test
     public void testGetKeyCloakUsersFromToken_ListEmpty() throws Exception {
+        PowerMock.mockStatic(JwtHelper.class);
         String jsonKeyCloakUser = super.loadStringFromResource("testKeyCloakUsers.json");
         Type listTypeKeyCloakUser = new TypeToken<List<KeyCloakUser>>(){}.getType();
         List<KeyCloakUser> keyCloakUsersListOrg = JsonGeneratorBase.getGson().fromJson(jsonKeyCloakUser, listTypeKeyCloakUser);
diff --git a/src/test/java/org/eclipse/openk/portal/util/JwtHelperTest.java b/src/test/java/org/eclipse/openk/portal/util/JwtHelperTest.java
index 0b47db0..f04b751 100644
--- a/src/test/java/org/eclipse/openk/portal/util/JwtHelperTest.java
+++ b/src/test/java/org/eclipse/openk/portal/util/JwtHelperTest.java
@@ -13,12 +13,19 @@
 
 import org.eclipse.openk.portal.auth2.model.JwtPayload;
 import org.eclipse.openk.portal.auth2.model.JwtToken;
+import org.eclipse.openk.portal.auth2.model.KeyCloakRole;
 import org.eclipse.openk.portal.auth2.util.JwtHelper;
+import org.eclipse.openk.portal.common.util.ResourceLoaderBase;
+import org.eclipse.openk.portal.exceptions.PortalInternalServerError;
 import org.junit.Test;
 
+import java.util.List;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
 import static org.junit.Assert.assertNotNull;
 
-public class JwtHelperTest {
+public class JwtHelperTest extends ResourceLoaderBase {
 
     @Test
     public void testGetJwtPayload_Base64URL() {
@@ -59,4 +66,42 @@
         assertNotNull( pl );
 
     }
+
+    @Test
+    public void testGetRolesListFromJson_testKeyCloakRoles_noClientRoleAtAll() throws PortalInternalServerError {
+        String jsonKeyCloakRoles = super.loadStringFromResource("testKeyCloakRoles_noClientRoleAtAll.json");
+        List<KeyCloakRole> keyCloakRolesList = JwtHelper.getRolesListFromJson(jsonKeyCloakRoles);
+
+        assertEquals("elogbook-access", keyCloakRolesList.get(0).getName());
+        assertEquals(2, keyCloakRolesList.size());
+    }
+
+    @Test
+    public void testGetRolesListFromJson_testKeyCloakRoles_noClientRoleForClient() throws PortalInternalServerError {
+        String jsonKeyCloakRoles = super.loadStringFromResource("testKeyCloakRoles_noClientRoleForClient.json");
+        List<KeyCloakRole> keyCloakRolesList = JwtHelper.getRolesListFromJson(jsonKeyCloakRoles);
+
+        assertEquals("elogbook-access", keyCloakRolesList.get(0).getName());
+        assertEquals(2, keyCloakRolesList.size());
+    }
+
+    @Test
+    public void testGetRolesListFromJson_testKeyCloakRoles_noRealmRole() throws PortalInternalServerError {
+        String jsonKeyCloakRoles = super.loadStringFromResource("testKeyCloakRoles_noRealmRole.json");
+        List<KeyCloakRole> keyCloakRolesList = JwtHelper.getRolesListFromJson(jsonKeyCloakRoles);
+
+        assertTrue(keyCloakRolesList.isEmpty());
+    }
+
+    @Test
+    public void testGetRolesListFromJson_testKeyCloakRoles_onlyRealmRole() throws PortalInternalServerError {
+        String jsonKeyCloakRoles = super.loadStringFromResource("testKeyCloakRoles_onlyRealmRole.json");
+        List<KeyCloakRole> keyCloakRolesList = JwtHelper.getRolesListFromJson(jsonKeyCloakRoles);
+
+        assertEquals("view-profile", keyCloakRolesList.get(0).getName());
+        assertTrue(keyCloakRolesList.get(0).getClientRole());
+        assertEquals(2, keyCloakRolesList.size());
+    }
+
+
 }
diff --git a/src/test/resources/testKeyCloakClientAndRealmRoles.json b/src/test/resources/testKeyCloakClientAndRealmRoles.json
new file mode 100644
index 0000000..a39cb11
--- /dev/null
+++ b/src/test/resources/testKeyCloakClientAndRealmRoles.json
@@ -0,0 +1,159 @@
+{
+  "realmMappings": [
+    {
+      "id": "7a145be5-20ba-4992-ad54-17c28d0bc0f9",
+      "name": "feedin-management-access",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "37d42cc3-0157-4ab6-b9fe-8be50de37da8",
+      "name": "planned-policies-executor",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "b1cf034b-bce3-4d29-9e9d-692bf420ce83",
+      "name": "planned-policies-access",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "baf44fc2-7888-4888-beaa-79288e9268a0",
+      "name": "planning-access",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "a1760267-b72d-4cef-bb2a-91c0d4a24cd7",
+      "name": "planned-policies-measureplanner",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "f41f6144-f788-434d-be7a-ee3190099f5d",
+      "name": "planned-policies-superuser",
+      "scopeParamRequired": false,
+      "composite": true,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "f8fa3a84-b7d8-4ad7-98c5-3c77ca6c1a33",
+      "name": "kon_admin",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "1e41d089-72ea-4b22-a88c-56037b9680d8",
+      "name": "planned-policies-measureapplicant",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "e423626e-4616-45b7-9c3d-10a7f0acab8c",
+      "name": "elogbook-superuser",
+      "description": "",
+      "scopeParamRequired": false,
+      "composite": true,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "69cd9f7d-bd7b-473d-9ae2-8ca8665fa9bf",
+      "name": "planned-policies-requester",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "7533b166-79da-44f6-bb84-fe6a3916c9cd",
+      "name": "planned-policies-measureapprover",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "dc84c3f4-2509-4894-9b91-772b67d1d470",
+      "name": "planned-policies-completion",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "061827bc-771d-4ce1-9123-3d211686c078",
+      "name": "planned-policies-normaluser",
+      "description": "Darf vieles, aber nicht alles",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "27b9578f-416b-4f67-8259-60464636f457",
+      "name": "planned-policies-clearance",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "7b977153-1107-4a7d-b2b3-dc6daa461c15",
+      "name": "kon-access",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "384e7a68-8e70-41aa-bbbd-1a0ffb293335",
+      "name": "elogbook-access",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "6b8d2da8-220c-4f83-8e15-889004e66359",
+      "name": "elogbook-normaluser",
+      "description": "Darf vieles, aber nicht alles",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    }
+  ],
+  "clientMappings": {
+    "elogbook-backend": {
+      "id": "e9904530-1ced-4d6b-96dc-fd1f3ce6420c",
+      "client": "elogbook-backend",
+      "mappings": [
+        {
+          "id": "f9971606-b587-41d0-a903-4e97b103e3b2",
+          "name": "testclientrole",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "e9904530-1ced-4d6b-96dc-fd1f3ce6420c"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/testKeyCloakRoles_noClientRoleAtAll.json b/src/test/resources/testKeyCloakRoles_noClientRoleAtAll.json
new file mode 100644
index 0000000..760a6a1
--- /dev/null
+++ b/src/test/resources/testKeyCloakRoles_noClientRoleAtAll.json
@@ -0,0 +1,21 @@
+{
+  "realmMappings": [
+    {
+      "id": "384e7a68-8e70-41aa-bbbd-1a0ffb293335",
+      "name": "elogbook-access",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "6b8d2da8-220c-4f83-8e15-889004e66359",
+      "name": "elogbook-normaluser",
+      "description": "Darf vieles, aber nicht alles",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/src/test/resources/testKeyCloakRoles_noClientRoleForClient.json b/src/test/resources/testKeyCloakRoles_noClientRoleForClient.json
new file mode 100644
index 0000000..d11bef0
--- /dev/null
+++ b/src/test/resources/testKeyCloakRoles_noClientRoleForClient.json
@@ -0,0 +1,47 @@
+{
+  "realmMappings": [
+    {
+      "id": "384e7a68-8e70-41aa-bbbd-1a0ffb293335",
+      "name": "elogbook-access",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    },
+    {
+      "id": "6b8d2da8-220c-4f83-8e15-889004e66359",
+      "name": "elogbook-normaluser",
+      "description": "Darf vieles, aber nicht alles",
+      "scopeParamRequired": false,
+      "composite": false,
+      "clientRole": false,
+      "containerId": "elogbook"
+    }
+  ],
+  "clientMappings": {
+    "account": {
+      "id": "ab5b5dd0-e943-4cef-bb86-5f17031ca6ed",
+      "client": "account",
+      "mappings": [
+        {
+          "id": "bfcf9034-7921-4200-ad2a-bf3f9c0d3f38",
+          "name": "view-profile",
+          "description": "${role_view-profile}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ab5b5dd0-e943-4cef-bb86-5f17031ca6ed"
+        },
+        {
+          "id": "0706bea7-d53b-4075-a4ab-d0b175cd660f",
+          "name": "manage-account",
+          "description": "${role_manage-account}",
+          "scopeParamRequired": false,
+          "composite": true,
+          "clientRole": true,
+          "containerId": "ab5b5dd0-e943-4cef-bb86-5f17031ca6ed"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/testKeyCloakRoles_noRealmRole.json b/src/test/resources/testKeyCloakRoles_noRealmRole.json
new file mode 100644
index 0000000..66470b2
--- /dev/null
+++ b/src/test/resources/testKeyCloakRoles_noRealmRole.json
@@ -0,0 +1,28 @@
+{
+  "clientMappings": {
+    "account": {
+      "id": "ab5b5dd0-e943-4cef-bb86-5f17031ca6ed",
+      "client": "account",
+      "mappings": [
+        {
+          "id": "bfcf9034-7921-4200-ad2a-bf3f9c0d3f38",
+          "name": "view-profile",
+          "description": "${role_view-profile}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ab5b5dd0-e943-4cef-bb86-5f17031ca6ed"
+        },
+        {
+          "id": "0706bea7-d53b-4075-a4ab-d0b175cd660f",
+          "name": "manage-account",
+          "description": "${role_manage-account}",
+          "scopeParamRequired": false,
+          "composite": true,
+          "clientRole": true,
+          "containerId": "ab5b5dd0-e943-4cef-bb86-5f17031ca6ed"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/test/resources/testKeyCloakRoles_onlyRealmRole.json b/src/test/resources/testKeyCloakRoles_onlyRealmRole.json
new file mode 100644
index 0000000..24aff34
--- /dev/null
+++ b/src/test/resources/testKeyCloakRoles_onlyRealmRole.json
@@ -0,0 +1,28 @@
+{
+  "clientMappings": {
+    "elogbook-backend": {
+      "id": "ab5b5dd0-e943-4cef-bb86-5f17031ca6ed",
+      "client": "elogbook-backend",
+      "mappings": [
+        {
+          "id": "bfcf9034-7921-4200-ad2a-bf3f9c0d3f38",
+          "name": "view-profile",
+          "description": "${role_view-profile}",
+          "scopeParamRequired": false,
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ab5b5dd0-e943-4cef-bb86-5f17031ca6ed"
+        },
+        {
+          "id": "0706bea7-d53b-4075-a4ab-d0b175cd660f",
+          "name": "manage-account",
+          "description": "${role_manage-account}",
+          "scopeParamRequired": false,
+          "composite": true,
+          "clientRole": true,
+          "containerId": "ab5b5dd0-e943-4cef-bb86-5f17031ca6ed"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file