KEYCLOAK-2053 Memberships based on memberUid like attribute

This commit is contained in:
mposolda 2015-12-14 16:30:23 +01:00
parent 2b409b3462
commit 215d59b1e5
2 changed files with 67 additions and 16 deletions

View file

@ -39,11 +39,14 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
// Name of LDAP attribute, which is used in role objects for name and RDN of role. Usually it will be "cn" // Name of LDAP attribute, which is used in role objects for name and RDN of role. Usually it will be "cn"
public static final String ROLE_NAME_LDAP_ATTRIBUTE = "role.name.ldap.attribute"; public static final String ROLE_NAME_LDAP_ATTRIBUTE = "role.name.ldap.attribute";
// Object classes of the role object.
public static final String ROLE_OBJECT_CLASSES = "role.object.classes";
// Name of LDAP attribute on role, which is used for membership mappings. Usually it will be "member" // Name of LDAP attribute on role, which is used for membership mappings. Usually it will be "member"
public static final String MEMBERSHIP_LDAP_ATTRIBUTE = "membership.ldap.attribute"; public static final String MEMBERSHIP_LDAP_ATTRIBUTE = "membership.ldap.attribute";
// Object classes of the role object. // See docs for MembershipType enum
public static final String ROLE_OBJECT_CLASSES = "role.object.classes"; public static final String MEMBERSHIP_ATTRIBUTE_TYPE = "membership.attribute.type";
// Boolean option. If true, we will map LDAP roles to realm roles. If false, we will map to client roles (client specified by option CLIENT_ID) // Boolean option. If true, we will map LDAP roles to realm roles. If false, we will map to client roles (client specified by option CLIENT_ID)
public static final String USE_REALM_ROLES_MAPPING = "use.realm.roles.mapping"; public static final String USE_REALM_ROLES_MAPPING = "use.realm.roles.mapping";
@ -179,6 +182,15 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
return membershipAttrName!=null ? membershipAttrName : LDAPConstants.MEMBER; return membershipAttrName!=null ? membershipAttrName : LDAPConstants.MEMBER;
} }
protected MembershipType getMembershipTypeLdapAttribute(UserFederationMapperModel mapperModel) {
String membershipType = mapperModel.getConfig().get(MEMBERSHIP_ATTRIBUTE_TYPE);
return membershipType!=null ? Enum.valueOf(MembershipType.class, membershipType) : MembershipType.DN;
}
private String getMembershipFromUser(LDAPObject ldapUser, MembershipType membershipType) {
return membershipType == MembershipType.DN ? ldapUser.getDn().toString() : ldapUser.getAttributeAsString(ldapUser.getRdnAttributeName());
}
protected Collection<String> getRoleObjectClasses(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider) { protected Collection<String> getRoleObjectClasses(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider) {
String objectClasses = mapperModel.getConfig().get(ROLE_OBJECT_CLASSES); String objectClasses = mapperModel.getConfig().get(ROLE_OBJECT_CLASSES);
if (objectClasses == null) { if (objectClasses == null) {
@ -228,17 +240,23 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
ldapRole = createLDAPRole(mapperModel, roleName, ldapProvider); ldapRole = createLDAPRole(mapperModel, roleName, ldapProvider);
} }
MembershipType membershipType = getMembershipTypeLdapAttribute(mapperModel);
Set<String> memberships = getExistingMemberships(mapperModel, ldapRole); Set<String> memberships = getExistingMemberships(mapperModel, ldapRole);
// Remove membership placeholder if present // Remove membership placeholder if present
for (String membership : memberships) { if (membershipType == MembershipType.DN) {
if (LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE.equals(membership)) { for (String membership : memberships) {
memberships.remove(membership); if (LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE.equals(membership)) {
break; memberships.remove(membership);
break;
}
} }
} }
memberships.add(ldapUser.getDn().toString()); String membership = getMembershipFromUser(ldapUser, membershipType);
memberships.add(membership);
ldapRole.setAttribute(getMembershipLdapAttribute(mapperModel), memberships); ldapRole.setAttribute(getMembershipLdapAttribute(mapperModel), memberships);
ldapProvider.getLdapIdentityStore().update(ldapRole); ldapProvider.getLdapIdentityStore().update(ldapRole);
@ -246,10 +264,14 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
public void deleteRoleMappingInLDAP(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, LDAPObject ldapRole) { public void deleteRoleMappingInLDAP(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser, LDAPObject ldapRole) {
Set<String> memberships = getExistingMemberships(mapperModel, ldapRole); Set<String> memberships = getExistingMemberships(mapperModel, ldapRole);
memberships.remove(ldapUser.getDn().toString());
MembershipType membershipType = getMembershipTypeLdapAttribute(mapperModel);
String userMembership = getMembershipFromUser(ldapUser, membershipType);
memberships.remove(userMembership);
// Some membership placeholder needs to be always here as "member" is mandatory attribute on some LDAP servers. But not on active directory! (Placeholder, which not matches any real object is not allowed here) // Some membership placeholder needs to be always here as "member" is mandatory attribute on some LDAP servers. But not on active directory! (Placeholder, which not matches any real object is not allowed here)
if (memberships.size() == 0 && !ldapProvider.getLdapIdentityStore().getConfig().isActiveDirectory()) { if (memberships.size() == 0 && membershipType==MembershipType.DN && !ldapProvider.getLdapIdentityStore().getConfig().isActiveDirectory()) {
memberships.add(LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE); memberships.add(LDAPConstants.EMPTY_MEMBER_ATTRIBUTE_VALUE);
} }
@ -276,7 +298,10 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
protected List<LDAPObject> getLDAPRoleMappings(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser) { protected List<LDAPObject> getLDAPRoleMappings(UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider, LDAPObject ldapUser) {
LDAPQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider); LDAPQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider);
String membershipAttr = getMembershipLdapAttribute(mapperModel); String membershipAttr = getMembershipLdapAttribute(mapperModel);
Condition membershipCondition = new LDAPQueryConditionsBuilder().equal(membershipAttr, ldapUser.getDn().toString());
String userMembership = getMembershipFromUser(ldapUser, getMembershipTypeLdapAttribute(mapperModel));
Condition membershipCondition = new LDAPQueryConditionsBuilder().equal(membershipAttr, userMembership);
ldapQuery.addWhereCondition(membershipCondition); ldapQuery.addWhereCondition(membershipCondition);
return ldapQuery.getResultList(); return ldapQuery.getResultList();
} }
@ -437,7 +462,8 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
LDAPQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider); LDAPQuery ldapQuery = createRoleQuery(mapperModel, ldapProvider);
LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder(); LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
Condition roleNameCondition = conditionsBuilder.equal(getRoleNameLdapAttribute(mapperModel), role.getName()); Condition roleNameCondition = conditionsBuilder.equal(getRoleNameLdapAttribute(mapperModel), role.getName());
Condition membershipCondition = conditionsBuilder.equal(getMembershipLdapAttribute(mapperModel), ldapUser.getDn().toString()); String membershipUserAttr = getMembershipFromUser(ldapUser, getMembershipTypeLdapAttribute(mapperModel));
Condition membershipCondition = conditionsBuilder.equal(getMembershipLdapAttribute(mapperModel), membershipUserAttr);
ldapQuery.addWhereCondition(roleNameCondition).addWhereCondition(membershipCondition); ldapQuery.addWhereCondition(roleNameCondition).addWhereCondition(membershipCondition);
LDAPObject ldapRole = ldapQuery.getFirstResult(); LDAPObject ldapRole = ldapQuery.getFirstResult();
@ -462,6 +488,7 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
} }
} }
public enum Mode { public enum Mode {
/** /**
* All role mappings are retrieved from LDAP and saved into LDAP * All role mappings are retrieved from LDAP and saved into LDAP
@ -484,4 +511,18 @@ public class RoleLDAPFederationMapper extends AbstractLDAPFederationMapper {
*/ */
READ_ONLY READ_ONLY
} }
public enum MembershipType {
/**
* Used if LDAP role has it's members declared in form of their full DN. For example ( "member: uid=john,ou=users,dc=example,dc=com" )
*/
DN,
/**
* Used if LDAP role has it's members declared in form of pure user uids. For example ( "memberUid: john" )
*/
UID
}
} }

View file

@ -42,15 +42,25 @@ public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMappe
ProviderConfigProperty.STRING_TYPE, LDAPConstants.CN); ProviderConfigProperty.STRING_TYPE, LDAPConstants.CN);
configProperties.add(roleNameLDAPAttribute); configProperties.add(roleNameLDAPAttribute);
ProviderConfigProperty roleObjectClasses = createConfigProperty(RoleLDAPFederationMapper.ROLE_OBJECT_CLASSES, "Role Object Classes",
"Object class (or classes) of the role object. It's divided by comma if more classes needed. In typical LDAP deployment it could be 'groupOfNames' . In Active Directory it's usually 'group' ",
ProviderConfigProperty.STRING_TYPE, null);
configProperties.add(roleObjectClasses);
ProviderConfigProperty membershipLDAPAttribute = createConfigProperty(RoleLDAPFederationMapper.MEMBERSHIP_LDAP_ATTRIBUTE, "Membership LDAP Attribute", ProviderConfigProperty membershipLDAPAttribute = createConfigProperty(RoleLDAPFederationMapper.MEMBERSHIP_LDAP_ATTRIBUTE, "Membership LDAP Attribute",
"Name of LDAP attribute on role, which is used for membership mappings. Usually it will be 'member' ", "Name of LDAP attribute on role, which is used for membership mappings. Usually it will be 'member' ",
ProviderConfigProperty.STRING_TYPE, LDAPConstants.MEMBER); ProviderConfigProperty.STRING_TYPE, LDAPConstants.MEMBER);
configProperties.add(membershipLDAPAttribute); configProperties.add(membershipLDAPAttribute);
ProviderConfigProperty roleObjectClasses = createConfigProperty(RoleLDAPFederationMapper.ROLE_OBJECT_CLASSES, "Role Object Classes", List<String> membershipTypes = new LinkedList<>();
"Object class (or classes) of the role object. It's divided by comma if more classes needed. In typical LDAP deployment it could be 'groupOfNames' . In Active Directory it's usually 'group' ", for (RoleLDAPFederationMapper.MembershipType membershipType : RoleLDAPFederationMapper.MembershipType.values()) {
ProviderConfigProperty.STRING_TYPE, null); membershipTypes.add(membershipType.toString());
configProperties.add(roleObjectClasses); }
ProviderConfigProperty membershipType = createConfigProperty(RoleLDAPFederationMapper.MEMBERSHIP_ATTRIBUTE_TYPE, "Membership Attribute Type",
"DN means that LDAP role has it's members declared in form of their full DN. For example ( 'member: uid=john,ou=users,dc=example,dc=com' . " +
"UID means that LDAP role has it's members declared in form of pure user uids. For example ( 'memberuid: john' ))",
ProviderConfigProperty.LIST_TYPE, membershipTypes);
configProperties.add(membershipType);
ProviderConfigProperty ldapFilter = createConfigProperty(RoleLDAPFederationMapper.ROLES_LDAP_FILTER, ProviderConfigProperty ldapFilter = createConfigProperty(RoleLDAPFederationMapper.ROLES_LDAP_FILTER,
"LDAP Filter", "LDAP Filter",
@ -58,7 +68,7 @@ public class RoleLDAPFederationMapperFactory extends AbstractLDAPFederationMappe
ProviderConfigProperty.STRING_TYPE, null); ProviderConfigProperty.STRING_TYPE, null);
configProperties.add(ldapFilter); configProperties.add(ldapFilter);
List<String> modes = new LinkedList<String>(); List<String> modes = new LinkedList<>();
for (RoleLDAPFederationMapper.Mode mode : RoleLDAPFederationMapper.Mode.values()) { for (RoleLDAPFederationMapper.Mode mode : RoleLDAPFederationMapper.Mode.values()) {
modes.add(mode.toString()); modes.add(mode.toString());
} }