hardcoded-ldap-group-mapper

This commit is contained in:
Jean-Loup Maillet 2018-05-30 15:36:01 +02:00 committed by Marek Posolda
parent fc3ca33033
commit d07f13eace
5 changed files with 270 additions and 30 deletions

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -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;
@ -870,6 +856,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

View file

@ -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;
@ -712,6 +700,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