Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/UAA-APIs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1390,7 +1390,8 @@ Fields *Available Fields* ::
skipSSLVerification boolean Optional Set to true if you wish to skip SSL certificate verification
emailDomain List<String> Optional List of email domains associated with the LDAP provider for the purpose of associating users to the correct origin upon invitation. If null or empty list, no invitations are accepted. Wildcards supported.
attributeMappings Map<String, Object> Optional List of UAA attributes mapped to attributes from LDAP. Currently we support mapping given_name, family_name, email, phone_number and external_groups.
externalGroupsWhitelist List<String> Optional List of external groups (`DN` distinguished names`) that can be included in the ID Token if the `roles` scope is requested. See `UAA-LDAP.md UAA-LDAP.md`_ for more information
externalGroupsWhitelist List<String> Optional List of external groups that can be included in the ID Token if the `roles` scope is requested. By default matched against the bare `cn` of each LDAP group; set `includeExternalGroupDn` to `true` to also allow matching on the group's full `DN`. See `UAA-LDAP.md UAA-LDAP.md`_ for more information
includeExternalGroupDn boolean Optional Defaults to false. When true, the full `DN` of each LDAP group is added as an additional candidate value (alongside the existing `cn` value) for `externalGroupsWhitelist` matching and the `/userinfo` `roles` field. See `UAA-LDAP.md UAA-LDAP.md`_ for more information
providerDescription String Optional Human readable name/description of this provider

Curl Example POST (Creating a SAML provider)::
Expand Down
48 changes: 48 additions & 0 deletions docs/UAA-Configuration-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ or `$CLOUDFOUNDRY_CONFIG_PATH/uaa.yml`.
| <a href="#ldapgroupsgroupsearchfilter"><img src="images/click-me.png" width="14" height="14"/></a> `ldap.groups.groupSearchFilter` | —| Group membership filter|
| <a href="#ldapgroupsmaxsearchdepth"><img src="images/click-me.png" width="14" height="14"/></a> `ldap.groups.maxSearchDepth` | `10`| Max nested group depth|
| <a href="#ldapgroupsautoadd"><img src="images/click-me.png" width="14" height="14"/></a> `ldap.groups.autoAdd` | —| Auto-add LDAP groups|
| <a href="#ldapgroupsgrouproleattribute"><img src="images/click-me.png" width="14" height="14"/></a> `ldap.groups.groupRoleAttribute` | `description`| Attribute holding the scope name(s) for `groups-as-scopes`|
| <a href="#ldapexternalgroupswhitelist"><img src="images/click-me.png" width="14" height="14"/></a> `ldap.externalGroupsWhitelist` | —| External group names/patterns allowed into the `roles` field|
| <a href="#ldapincludeexternalgroupdn"><img src="images/click-me.png" width="14" height="14"/></a> `ldap.includeExternalGroupDn` | `false`| Also match external groups by full DN|

### Encryption

Expand Down Expand Up @@ -2686,6 +2689,51 @@ When `true`, LDAP groups are automatically created as UAA groups if they don't e

---

### `ldap.groups.groupRoleAttribute`

**Default:** `description`
**Source:** YAML config
**Type:** `String`

Used with `groups-as-scopes` (`ldap.groups.file: ldap/ldap-groups-as-scopes.xml`), defines the
LDAP attribute that holds the scope name(s) for a group. Ignored by `groups-map-to-scopes`, where
the group's DN is used instead.

[Back to table](#ldap)

---

### `ldap.externalGroupsWhitelist`

**Default:** — (not set, meaning all external groups are allowed)
**Source:** YAML config
**Type:** `List<String>`

Allowlist of external group names/patterns (wildcards supported) that may be reported as the
user's external groups — used to populate the `/userinfo` endpoint's `roles` field. By default,
each LDAP group the user belongs to is matched by its bare `cn` (e.g. `cf_admin`), not its full
`DN`. Set `ldap.includeExternalGroupDn` to `true` to also allow matching on the group's full `DN`.

[Back to table](#ldap)

---

### `ldap.includeExternalGroupDn`

**Default:** `false`
**Source:** YAML config
**Type:** `boolean`

When `true`, the full `DN` of each LDAP group the user belongs to is added as an additional
candidate value (alongside the existing `cn` value) when matching against
`ldap.externalGroupsWhitelist` and when populating the `/userinfo` endpoint's `roles` field. This
does not replace the `cn`-based value, so existing `cn`-based whitelist entries keep working when
this is enabled.

[Back to table](#ldap)

---

### `encryption.active_key_label`

**Default:** — (required)
Expand Down
15 changes: 13 additions & 2 deletions docs/UAA-LDAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -684,8 +684,19 @@ In the above example, the user `marissa`'s UAA email always become `generated-m
* <a name="ldap.externalGroupsWhitelist">`ldap.externalGroupsWhitelist`</a>
List<String> value,
Optional List of external groups that will be included in the ID Token if the `roles` scope is requested.
The list should contain `DN` values for the groups that are associated with the user.
The display name of the group in the ID token will be the taken from the `ldap.groups.groupRoleAttribute` attribute
By default, the list is matched against the bare `cn` of each LDAP group the user belongs to (e.g. `cf_admin`),
not the group's full `DN`. Set `ldap.includeExternalGroupDn` to `true` to also allow matching on the full `DN`
(e.g. `cn=cf_admin,ou=dev,dc=example,dc=com`).


* <a name="ldap.includeExternalGroupDn">`ldap.includeExternalGroupDn`</a>
boolean value, defaults to `false`.
When `true`, the full `DN` of each LDAP group the user belongs to is added as an additional candidate value
(alongside the existing bare `cn` value) when matching against `ldap.externalGroupsWhitelist` and when
populating the external groups reported via the `/userinfo` endpoint's `roles` field. This does not replace
the `cn`-based value, so existing `cn`-based whitelist entries keep working when this is enabled.
Useful when an external system (for example, a role-to-external-group mapping configured with a group's
full `DN`) needs to match against the `DN` rather than the bare `cn`.


* <a name="ldap.attributeMappings">`ldap.attributeMappings`</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class LdapIdentityProviderDefinition extends ExternalIdentityProviderDefi
public static final String LDAP_EMAIL_DOMAIN = LDAP_PREFIX + EMAIL_DOMAIN_ATTR;
public static final String LDAP_STORE_CUSTOM_ATTRIBUTES = LDAP_PREFIX + STORE_CUSTOM_ATTRIBUTES_NAME;
public static final String LDAP_EXTERNAL_GROUPS_WHITELIST = LDAP_PREFIX + "externalGroupsWhitelist";
public static final String LDAP_INCLUDE_EXTERNAL_GROUP_DN = LDAP_PREFIX + "includeExternalGroupDn";
public static final String LDAP_GROUP_FILE_GROUPS_AS_SCOPES = "ldap/ldap-groups-as-scopes.xml";
public static final String LDAP_GROUP_FILE_GROUPS_MAP_TO_SCOPES = "ldap/ldap-groups-map-to-scopes.xml";
public static final String LDAP_GROUP_FILE_GROUPS_NULL_XML = "ldap/ldap-groups-null.xml";
Expand All @@ -75,7 +76,7 @@ public class LdapIdentityProviderDefinition extends ExternalIdentityProviderDefi
List.of("ldap/ldap-groups-as-scopes.xml", "ldap/ldap-groups-map-to-scopes.xml", "ldap/ldap-groups-null.xml", "ldap/ldap-groups-populator.xml");


public static final List<String> LDAP_PROPERTY_NAMES = List.of(LDAP_ATTRIBUTE_MAPPINGS, LDAP_BASE_LOCAL_PASSWORD_COMPARE, LDAP_BASE_MAIL_ATTRIBUTE_NAME, LDAP_BASE_MAIL_SUBSTITUTE, LDAP_BASE_MAIL_SUBSTITUTE_OVERRIDES_LDAP, LDAP_BASE_PASSWORD, LDAP_BASE_PASSWORD_ATTRIBUTE_NAME, LDAP_BASE_PASSWORD_ENCODER, LDAP_BASE_REFERRAL, LDAP_BASE_SEARCH_BASE, LDAP_BASE_SEARCH_FILTER, LDAP_BASE_URL, LDAP_BASE_USER_DN, LDAP_BASE_USER_DN_PATTERN, LDAP_BASE_USER_DN_PATTERN_DELIMITER, LDAP_EMAIL_DOMAIN, LDAP_EXTERNAL_GROUPS_WHITELIST, LDAP_GROUPS_AUTO_ADD, LDAP_GROUPS_FILE, LDAP_GROUPS_GROUP_ROLE_ATTRIBUTE, LDAP_GROUPS_GROUP_SEARCH_FILTER, LDAP_GROUPS_IGNORE_PARTIAL_RESULT_EXCEPTION, LDAP_GROUPS_MAX_SEARCH_DEPTH, LDAP_GROUPS_SEARCH_BASE, LDAP_GROUPS_SEARCH_SUBTREE, LDAP_PROFILE_FILE, LDAP_SSL_SKIPVERIFICATION, LDAP_SSL_TLS);
public static final List<String> LDAP_PROPERTY_NAMES = List.of(LDAP_ATTRIBUTE_MAPPINGS, LDAP_BASE_LOCAL_PASSWORD_COMPARE, LDAP_BASE_MAIL_ATTRIBUTE_NAME, LDAP_BASE_MAIL_SUBSTITUTE, LDAP_BASE_MAIL_SUBSTITUTE_OVERRIDES_LDAP, LDAP_BASE_PASSWORD, LDAP_BASE_PASSWORD_ATTRIBUTE_NAME, LDAP_BASE_PASSWORD_ENCODER, LDAP_BASE_REFERRAL, LDAP_BASE_SEARCH_BASE, LDAP_BASE_SEARCH_FILTER, LDAP_BASE_URL, LDAP_BASE_USER_DN, LDAP_BASE_USER_DN_PATTERN, LDAP_BASE_USER_DN_PATTERN_DELIMITER, LDAP_EMAIL_DOMAIN, LDAP_EXTERNAL_GROUPS_WHITELIST, LDAP_INCLUDE_EXTERNAL_GROUP_DN, LDAP_GROUPS_AUTO_ADD, LDAP_GROUPS_FILE, LDAP_GROUPS_GROUP_ROLE_ATTRIBUTE, LDAP_GROUPS_GROUP_SEARCH_FILTER, LDAP_GROUPS_IGNORE_PARTIAL_RESULT_EXCEPTION, LDAP_GROUPS_MAX_SEARCH_DEPTH, LDAP_GROUPS_SEARCH_BASE, LDAP_GROUPS_SEARCH_SUBTREE, LDAP_PROFILE_FILE, LDAP_SSL_SKIPVERIFICATION, LDAP_SSL_TLS);

public static final Map<String, Class<?>> LDAP_PROPERTY_TYPES = new HashMap<>();

Expand All @@ -97,6 +98,7 @@ public class LdapIdentityProviderDefinition extends ExternalIdentityProviderDefi
LDAP_PROPERTY_TYPES.put(LDAP_BASE_USER_DN_PATTERN_DELIMITER, String.class);
LDAP_PROPERTY_TYPES.put(LDAP_EMAIL_DOMAIN, List.class);
LDAP_PROPERTY_TYPES.put(LDAP_EXTERNAL_GROUPS_WHITELIST, List.class);
LDAP_PROPERTY_TYPES.put(LDAP_INCLUDE_EXTERNAL_GROUP_DN, Boolean.class);
LDAP_PROPERTY_TYPES.put(LDAP_GROUPS_AUTO_ADD, Boolean.class);
LDAP_PROPERTY_TYPES.put(LDAP_GROUPS_FILE, String.class);
LDAP_PROPERTY_TYPES.put(LDAP_GROUPS_GROUP_ROLE_ATTRIBUTE, String.class);
Expand Down Expand Up @@ -138,6 +140,7 @@ public class LdapIdentityProviderDefinition extends ExternalIdentityProviderDefi
private Boolean groupSearchSubTree = true;
private int maxGroupSearchDepth = 10;
private String groupRoleAttribute;
private Boolean includeExternalGroupDn = false;

private String tlsConfiguration = LDAP_TLS_NONE;

Expand Down Expand Up @@ -356,6 +359,14 @@ public void setGroupRoleAttribute(String groupRoleAttribute) {
this.groupRoleAttribute = groupRoleAttribute;
}

public Boolean isIncludeExternalGroupDn() {
return includeExternalGroupDn;
}

public void setIncludeExternalGroupDn(Boolean includeExternalGroupDn) {
this.includeExternalGroupDn = includeExternalGroupDn;
}

@JsonIgnore
public Boolean isConfigured() {
return StringUtils.hasText(getBaseUrl());
Expand Down Expand Up @@ -485,6 +496,9 @@ public boolean equals(Object o) {
if (!Objects.equals(groupSearchSubTree, that.groupSearchSubTree)) {
return false;
}
if (!Objects.equals(includeExternalGroupDn, that.includeExternalGroupDn)) {
return false;
}
return Objects.equals(groupRoleAttribute, that.groupRoleAttribute);

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.cloudfoundry.identity.uaa.provider.LdapIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.ldap.ExtendedLdapUserDetails;
import org.cloudfoundry.identity.uaa.provider.ldap.extension.LdapAuthority;
import org.cloudfoundry.identity.uaa.provider.ldap.extension.SpringSecurityLdapTemplate;
import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.cloudfoundry.identity.uaa.util.ObjectUtils;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
Expand Down Expand Up @@ -97,12 +98,13 @@ protected List<String> getExternalUserAuthorities(UserDetails request, ExternalA
IdentityProvider provider = getProviderProvisioning().retrieveByOrigin(authenticationData.getOrigin(), IdentityZoneHolder.get().getId());
LdapIdentityProviderDefinition ldapIdentityProviderDefinition = ObjectUtils.castInstance(provider.getConfig(), LdapIdentityProviderDefinition.class);
List<String> externalWhiteList = ldapIdentityProviderDefinition.getExternalGroupsWhitelist();
result = new ArrayList<>(retainAllMatches(getAuthoritiesAsNames(request.getAuthorities()), externalWhiteList));
boolean includeDn = Boolean.TRUE.equals(ldapIdentityProviderDefinition.isIncludeExternalGroupDn());
result = new ArrayList<>(retainAllMatches(getAuthoritiesAsNames(request.getAuthorities(), includeDn), externalWhiteList));
}
return result;
}

protected Set<String> getAuthoritiesAsNames(Collection<? extends GrantedAuthority> authorities) {
protected Set<String> getAuthoritiesAsNames(Collection<? extends GrantedAuthority> authorities, boolean includeDn) {
Set<String> result = new HashSet<>();
authorities = new LinkedList<>(authorities != null ? authorities : emptyList());
for (GrantedAuthority a : authorities) {
Expand All @@ -111,6 +113,12 @@ protected Set<String> getAuthoritiesAsNames(Collection<? extends GrantedAuthorit
if (groupNames != null) {
result.addAll(Arrays.asList(groupNames));
}
if (includeDn) {
String[] dnValues = la.getAttributeValues(SpringSecurityLdapTemplate.DN_KEY);
if (dnValues != null) {
result.addAll(Arrays.asList(dnValues));
}
}
}
}
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public static ConfigurableEnvironment getLdapConfigurationEnvironment(LdapIdenti
setIfNotNull(LdapIdentityProviderDefinition.LDAP_BASE_USER_DN_PATTERN_DELIMITER, definition.getUserDNPatternDelimiter(), properties);
setIfNotNull(LdapIdentityProviderDefinition.LDAP_EMAIL_DOMAIN, definition.getEmailDomain(), properties);
setIfNotNull(LdapIdentityProviderDefinition.LDAP_EXTERNAL_GROUPS_WHITELIST, definition.getExternalGroupsWhitelist(), properties);
setIfNotNull(LdapIdentityProviderDefinition.LDAP_INCLUDE_EXTERNAL_GROUP_DN, definition.isIncludeExternalGroupDn(), properties);
setIfNotNull(LdapIdentityProviderDefinition.LDAP_GROUPS_AUTO_ADD, definition.isAutoAddGroups(), properties);
setIfNotNull(LdapIdentityProviderDefinition.LDAP_GROUPS_FILE, definition.getLdapGroupFile(), properties);
setIfNotNull(LdapIdentityProviderDefinition.LDAP_GROUPS_GROUP_ROLE_ATTRIBUTE, definition.getGroupRoleAttribute(), properties);
Expand Down Expand Up @@ -101,6 +102,10 @@ public static LdapIdentityProviderDefinition fromConfig(Map<String, Object> ldap
definition.setExternalGroupsWhitelist((List<String>) ldapConfig.get(LdapIdentityProviderDefinition.LDAP_EXTERNAL_GROUPS_WHITELIST));
}

if (ldapConfig.get(LdapIdentityProviderDefinition.LDAP_INCLUDE_EXTERNAL_GROUP_DN) != null) {
definition.setIncludeExternalGroupDn((Boolean) ldapConfig.get(LdapIdentityProviderDefinition.LDAP_INCLUDE_EXTERNAL_GROUP_DN));
}

if (ldapConfig.get(LdapIdentityProviderDefinition.LDAP_ATTRIBUTE_MAPPINGS) != null) {
definition.setAttributeMappings((Map<String, Object>) ldapConfig.get(LdapIdentityProviderDefinition.LDAP_ATTRIBUTE_MAPPINGS));
}
Expand Down
Loading
Loading