keycloak-uncached

hardcoded-ldap-group-mapper

5/30/2018 10:36:01 AM

Details

diff --git a/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/HardcodedLDAPGroupStorageMapper.java b/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/HardcodedLDAPGroupStorageMapper.java
new file mode 100644
index 0000000..0768a19
--- /dev/null
+++ b/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/HardcodedLDAPGroupStorageMapper.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.ldap.mappers;
+
+import org.jboss.logging.Logger;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.*;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.UserModelDelegate;
+import org.keycloak.storage.ldap.LDAPStorageProvider;
+import org.keycloak.storage.ldap.idm.model.LDAPObject;
+import org.keycloak.storage.ldap.idm.query.internal.LDAPQuery;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:jean-loup.maillet@yesitis.fr">Jean-Loup Maillet</a>
+ */
+public class HardcodedLDAPGroupStorageMapper extends AbstractLDAPStorageMapper {
+
+    private static final Logger logger = Logger.getLogger(HardcodedLDAPGroupStorageMapper.class);
+
+    public static final String GROUP = "group";
+
+    public HardcodedLDAPGroupStorageMapper(ComponentModel mapperModel, LDAPStorageProvider ldapProvider) {
+        super(mapperModel, ldapProvider);
+    }
+
+    @Override
+    public void beforeLDAPQuery(LDAPQuery query) {
+    }
+
+    @Override
+    public UserModel proxy(LDAPObject ldapUser, UserModel delegate, RealmModel realm) {
+        return new UserModelDelegate(delegate) {
+
+            @Override
+            public Set<GroupModel> getGroups() {
+                Set<GroupModel> groups = super.getGroups();
+
+                GroupModel group = getGroup(realm);
+                if (group != null) {
+                    groups.add(group);
+                }
+
+                return groups;
+            }
+
+            @Override
+            public boolean isMemberOf(GroupModel group) {
+                return super.isMemberOf(group) || group.equals(getGroup(realm));
+            }
+
+            @Override
+            public void leaveGroup(GroupModel group) {
+                if (group.equals(getGroup(realm))) {
+                    throw new ModelException("Not possible to delete group. It's hardcoded by LDAP mapper");
+                } else {
+                    super.leaveGroup(group);
+                }
+            }
+        };
+    }
+
+    @Override
+    public void onRegisterUserToLDAP(LDAPObject ldapUser, UserModel localUser, RealmModel realm) {
+
+    }
+
+    @Override
+    public void onImportUserFromLDAP(LDAPObject ldapUser, UserModel user, RealmModel realm, boolean isCreate) {
+
+    }
+
+    private GroupModel getGroup(RealmModel realm) {
+        String groupName = mapperModel.getConfig().getFirst(HardcodedLDAPGroupStorageMapper.GROUP);
+        GroupModel group = KeycloakModelUtils.findGroupByPath(realm, groupName);
+        if (group == null) {
+            logger.warnf("Hardcoded group '%s' configured in mapper '%s' is not available anymore");
+        }
+        return group;
+    }
+}
diff --git a/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/HardcodedLDAPGroupStorageMapperFactory.java b/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/HardcodedLDAPGroupStorageMapperFactory.java
new file mode 100644
index 0000000..4abb27d
--- /dev/null
+++ b/federation/ldap/src/main/java/org/keycloak/storage/ldap/mappers/HardcodedLDAPGroupStorageMapperFactory.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.ldap.mappers;
+
+import org.keycloak.component.ComponentModel;
+import org.keycloak.component.ComponentValidationException;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.storage.ldap.LDAPStorageProvider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:jean-loup.maillet@yesitis.fr">Jean-Loup Maillet</a>
+ */
+public class HardcodedLDAPGroupStorageMapperFactory extends AbstractLDAPStorageMapperFactory {
+
+    public static final String PROVIDER_ID = "hardcoded-ldap-group-mapper";
+    protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
+
+    static {
+        ProviderConfigProperty groupAttr = createConfigProperty(HardcodedLDAPGroupStorageMapper.GROUP, "Group",
+                "Group to add the user in.  Click 'Select Group' button to browse groups, or just type it in the textbox.",
+                ProviderConfigProperty.STRING_TYPE, null);
+
+        configProperties.add(groupAttr);
+    }
+
+    @Override
+    public String getHelpText() {
+        return "When user is imported from LDAP, he will be automatically added into this configured group.";
+    }
+
+    @Override
+    public List<ProviderConfigProperty> getConfigProperties() {
+        return configProperties;
+    }
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel config) throws ComponentValidationException {
+        String groupName = config.getConfig().getFirst(HardcodedLDAPGroupStorageMapper.GROUP);
+        if (groupName == null) {
+            throw new ComponentValidationException("Group can't be null");
+        }
+        GroupModel group = KeycloakModelUtils.findGroupByPath(realm, groupName);
+        if (group == null) {
+            throw new ComponentValidationException("There is no group corresponding to configured value");
+        }
+    }
+
+    @Override
+    protected AbstractLDAPStorageMapper createMapper(ComponentModel mapperModel, LDAPStorageProvider federationProvider) {
+        return new HardcodedLDAPGroupStorageMapper(mapperModel, federationProvider);
+    }
+}
diff --git a/federation/ldap/src/main/resources/META-INF/services/org.keycloak.storage.ldap.mappers.LDAPStorageMapperFactory b/federation/ldap/src/main/resources/META-INF/services/org.keycloak.storage.ldap.mappers.LDAPStorageMapperFactory
index e43fdbe..12fd30b 100644
--- a/federation/ldap/src/main/resources/META-INF/services/org.keycloak.storage.ldap.mappers.LDAPStorageMapperFactory
+++ b/federation/ldap/src/main/resources/META-INF/services/org.keycloak.storage.ldap.mappers.LDAPStorageMapperFactory
@@ -17,6 +17,7 @@
 
 org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory
 org.keycloak.storage.ldap.mappers.HardcodedLDAPRoleStorageMapperFactory
+org.keycloak.storage.ldap.mappers.HardcodedLDAPGroupStorageMapperFactory
 org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapperFactory
 org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapperFactory
 org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapperFactory
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPProvidersIntegrationTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPProvidersIntegrationTest.java
index 80a3d3f..075b9d2 100755
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPProvidersIntegrationTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPProvidersIntegrationTest.java
@@ -42,14 +42,7 @@ import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.common.util.Time;
 import org.keycloak.component.ComponentModel;
 import org.keycloak.credential.CredentialModel;
-import org.keycloak.models.Constants;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.LDAPConstants;
-import org.keycloak.models.ModelException;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
-import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserModel;
+import org.keycloak.models.*;
 import org.keycloak.models.cache.CachedUserModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.representations.AccessToken;
@@ -61,14 +54,7 @@ import org.keycloak.storage.ldap.LDAPConfig;
 import org.keycloak.storage.ldap.LDAPStorageProvider;
 import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
 import org.keycloak.storage.ldap.idm.model.LDAPObject;
-import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper;
-import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory;
-import org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapper;
-import org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapperFactory;
-import org.keycloak.storage.ldap.mappers.HardcodedLDAPRoleStorageMapper;
-import org.keycloak.storage.ldap.mappers.HardcodedLDAPRoleStorageMapperFactory;
-import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
-import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper;
+import org.keycloak.storage.ldap.mappers.*;
 import org.keycloak.testsuite.OAuthClient;
 import org.keycloak.testsuite.pages.AccountPasswordPage;
 import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
@@ -871,6 +857,50 @@ public class LDAPProvidersIntegrationTest {
     }
 
     @Test
+    public void testHardcodedGroupMapper() {
+        KeycloakSession session = keycloakRule.startSession();
+        ComponentModel firstNameMapper = null;
+
+        try {
+            RealmModel appRealm = new RealmManager(session).getRealmByName("test");
+            GroupModel hardcodedGroup = appRealm.createGroup("hardcoded-group", "hardcoded-group");
+
+            // assert that user "johnkeycloak" doesn't have hardcoded group
+            UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
+            Assert.assertFalse(john.isMemberOf(hardcodedGroup));
+
+            ComponentModel hardcodedMapperModel = KeycloakModelUtils.createComponentModel("hardcoded group", ldapModel.getId(), HardcodedLDAPGroupStorageMapperFactory.PROVIDER_ID, LDAPStorageMapper.class.getName(),
+                    HardcodedLDAPGroupStorageMapper.GROUP, "hardcoded-group");
+            appRealm.addComponentModel(hardcodedMapperModel);
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+
+        session = keycloakRule.startSession();
+        try {
+            RealmModel appRealm = new RealmManager(session).getRealmByName("test");
+            GroupModel hardcodedGroup = appRealm.getGroupById("hardcoded-group");
+
+            // Assert user is successfully imported in Keycloak DB now with correct firstName and lastName
+            UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
+            Assert.assertTrue(john.isMemberOf(hardcodedGroup));
+
+            // Can't remove user from hardcoded role
+            try {
+                john.leaveGroup(hardcodedGroup);
+                Assert.fail("Didn't expected to leave group");
+            } catch (ModelException expected) {
+            }
+
+            // Revert mappers
+            ComponentModel hardcodedMapperModel = LDAPTestUtils.getSubcomponentByName(appRealm, ldapModel, "hardcoded group");
+            appRealm.removeComponent(hardcodedMapperModel);
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+    }
+
+    @Test
     public void testImportExistingUserFromLDAP() throws Exception {
         // Add LDAP user with same email like existing model user
         keycloakRule.update(new KeycloakRule.KeycloakSetup() {
diff --git a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/noimport/LDAPProvidersIntegrationNoImportTest.java b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/noimport/LDAPProvidersIntegrationNoImportTest.java
index 2878c7c..11c205a 100755
--- a/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/noimport/LDAPProvidersIntegrationNoImportTest.java
+++ b/testsuite/integration-deprecated/src/test/java/org/keycloak/testsuite/federation/storage/ldap/noimport/LDAPProvidersIntegrationNoImportTest.java
@@ -32,14 +32,7 @@ import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.component.ComponentModel;
 import org.keycloak.credential.CredentialModel;
-import org.keycloak.models.Constants;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.LDAPConstants;
-import org.keycloak.models.ModelException;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
-import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserModel;
+import org.keycloak.models.*;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.idm.CredentialRepresentation;
@@ -53,12 +46,7 @@ import org.keycloak.storage.ldap.LDAPConfig;
 import org.keycloak.storage.ldap.LDAPStorageProvider;
 import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
 import org.keycloak.storage.ldap.idm.model.LDAPObject;
-import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper;
-import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory;
-import org.keycloak.storage.ldap.mappers.HardcodedLDAPRoleStorageMapper;
-import org.keycloak.storage.ldap.mappers.HardcodedLDAPRoleStorageMapperFactory;
-import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
-import org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper;
+import org.keycloak.storage.ldap.mappers.*;
 import org.keycloak.testsuite.ApiUtil;
 import org.keycloak.testsuite.OAuthClient;
 import org.keycloak.testsuite.federation.storage.ldap.LDAPTestUtils;
@@ -713,6 +701,50 @@ public class LDAPProvidersIntegrationNoImportTest {
     }
 
     @Test
+    public void testHardcodedGroupMapper() {
+        KeycloakSession session = keycloakRule.startSession();
+        ComponentModel firstNameMapper = null;
+
+        try {
+            RealmModel appRealm = new RealmManager(session).getRealmByName("test");
+            GroupModel hardcodedGroup = appRealm.createGroup("hardcoded-group", "hardcoded-group");
+
+            // assert that user "johnkeycloak" doesn't have hardcoded group
+            UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
+            Assert.assertFalse(john.isMemberOf(hardcodedGroup));
+
+            ComponentModel hardcodedMapperModel = KeycloakModelUtils.createComponentModel("hardcoded group", ldapModel.getId(), HardcodedLDAPGroupStorageMapperFactory.PROVIDER_ID, LDAPStorageMapper.class.getName(),
+                    HardcodedLDAPGroupStorageMapper.GROUP, "hardcoded-group");
+            appRealm.addComponentModel(hardcodedMapperModel);
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+
+        session = keycloakRule.startSession();
+        try {
+            RealmModel appRealm = new RealmManager(session).getRealmByName("test");
+            GroupModel hardcodedGroup = appRealm.getGroupById("hardcoded-group");
+
+            // Assert user is successfully imported in Keycloak DB now with correct firstName and lastName
+            UserModel john = session.users().getUserByUsername("johnkeycloak", appRealm);
+            Assert.assertTrue(john.isMemberOf(hardcodedGroup));
+
+            // Can't remove user from hardcoded role
+            try {
+                john.leaveGroup(hardcodedGroup);
+                Assert.fail("Didn't expected to leave group");
+            } catch (ModelException expected) {
+            }
+
+            // Revert mappers
+            ComponentModel hardcodedMapperModel = LDAPTestUtils.getSubcomponentByName(appRealm, ldapModel, "hardcoded group");
+            appRealm.removeComponent(hardcodedMapperModel);
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+    }
+
+    @Test
     public void testImportExistingUserFromLDAP() throws Exception {
         // Add LDAP user with same email like existing model user
         keycloakRule.update(new KeycloakRule.KeycloakSetup() {