hardcoded-ldap-group-mapper
This commit is contained in:
parent
fc3ca33033
commit
d07f13eace
5 changed files with 270 additions and 30 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory
|
org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory
|
||||||
org.keycloak.storage.ldap.mappers.HardcodedLDAPRoleStorageMapperFactory
|
org.keycloak.storage.ldap.mappers.HardcodedLDAPRoleStorageMapperFactory
|
||||||
|
org.keycloak.storage.ldap.mappers.HardcodedLDAPGroupStorageMapperFactory
|
||||||
org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapperFactory
|
org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapperFactory
|
||||||
org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapperFactory
|
org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapperFactory
|
||||||
org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapperFactory
|
org.keycloak.storage.ldap.mappers.membership.role.RoleLDAPStorageMapperFactory
|
||||||
|
|
|
@ -42,14 +42,7 @@ import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.credential.CredentialModel;
|
import org.keycloak.credential.CredentialModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.*;
|
||||||
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.cache.CachedUserModel;
|
import org.keycloak.models.cache.CachedUserModel;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.representations.AccessToken;
|
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.LDAPStorageProvider;
|
||||||
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
||||||
import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
||||||
import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper;
|
import org.keycloak.storage.ldap.mappers.*;
|
||||||
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.testsuite.OAuthClient;
|
import org.keycloak.testsuite.OAuthClient;
|
||||||
import org.keycloak.testsuite.pages.AccountPasswordPage;
|
import org.keycloak.testsuite.pages.AccountPasswordPage;
|
||||||
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
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
|
@Test
|
||||||
public void testImportExistingUserFromLDAP() throws Exception {
|
public void testImportExistingUserFromLDAP() throws Exception {
|
||||||
// Add LDAP user with same email like existing model user
|
// Add LDAP user with same email like existing model user
|
||||||
|
|
|
@ -32,14 +32,7 @@ import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.credential.CredentialModel;
|
import org.keycloak.credential.CredentialModel;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.*;
|
||||||
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.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
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.LDAPStorageProvider;
|
||||||
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
import org.keycloak.storage.ldap.LDAPStorageProviderFactory;
|
||||||
import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
import org.keycloak.storage.ldap.idm.model.LDAPObject;
|
||||||
import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper;
|
import org.keycloak.storage.ldap.mappers.*;
|
||||||
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.testsuite.ApiUtil;
|
import org.keycloak.testsuite.ApiUtil;
|
||||||
import org.keycloak.testsuite.OAuthClient;
|
import org.keycloak.testsuite.OAuthClient;
|
||||||
import org.keycloak.testsuite.federation.storage.ldap.LDAPTestUtils;
|
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
|
@Test
|
||||||
public void testImportExistingUserFromLDAP() throws Exception {
|
public void testImportExistingUserFromLDAP() throws Exception {
|
||||||
// Add LDAP user with same email like existing model user
|
// Add LDAP user with same email like existing model user
|
||||||
|
|
Loading…
Reference in a new issue