LDAP Authentication
Digital.ai Release has a role-based security system with two types of users:
- Internal users that are managed by Digital.ai Release
- External users that are maintained in an LDAP repository such as Active Directory
This topic describes how to configure Release to use an LDAP repository to authenticate users and retrieve role, group, membership. In Digital.ai Release, LDAP users and groups become principals that you can assign to roles. Global permissions are assigned at the role level. For more information, see configure permissions.
Role memberships and permissions that are assigned to roles are stored in the database. Release treats the LDAP repository as read-only, which means that it will use information from the LDAP repository, but that it cannot make changes to that information.
Release cookies store security information that is provided by the Spring Security framework. Release does not store any additional information in cookies.
Configure Release to use an LDAP repository
To configure Release to use an LDAP repository, you must modify the xl-release-security.xml
security configuration file. The following is an example of an xl-release-security.xml
file that uses LDAP. Values that you must provide are highlighted.
Do not copy the entire sample. We recommend that you add the following items only: LDAP_SERVER_URL
, MANAGER_DN
, MANAGER_PASSWORD
, GROUP_SEARCH_BASE
, GROUP_SEARCH_FILTER
, USER_SEARCH_BASE
, USER_SEARCH_FILTER
, GROUP_EMAIL_SEARCH_BASE
, GROUP_EMAIL_SEARCH_FILTER
, GROUP_EMAIL_SEARCH_TIME_LIMIT_IN_MS
, GROUP_EMAIL_ATTRIBUTE_NAME
, and EXTERNAL_ID_ATTRIBUTE_NAME
. This sample may differ from your xl-release-security.xml
file, depending on your version of Release and any other customizations that you have made.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<bean id="ldapServer" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="LDAP_SERVER_URL"/>
<property name="userDn" value="MANAGER_DN"/>
<property name="password" value="MANAGER_PASSWORD"/>
<property name="baseEnvironmentProperties">
<map>
<entry key="java.naming.referral">
<value>ignore</value>
</entry>
</map>
</property>
</bean>
<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value="USER_SEARCH_BASE"/>
<constructor-arg index="1" value="USER_SEARCH_FILTER"/>
<constructor-arg index="2" ref="ldapServer"/>
</bean>
<bean id="bindAuthenticator" class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="ldapServer"/>
<property name="userSearch" ref="userSearch"/>
</bean>
<bean id="authoritiesPopulator" class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="ldapServer"/>
<constructor-arg value="GROUP_SEARCH_BASE"/>
<property name="groupSearchFilter" value="GROUP_SEARCH_FILTER"/>
<property name="rolePrefix" value=""/>
<property name="searchSubtree" value="true"/>
<property name="convertToUpperCase" value="false"/>
</bean>
<bean id="ldapGroupEmailProvider" class="com.xebialabs.xlrelease.principaldata.LdapGroupEmailProvider">
<constructor-arg index="0" value="GROUP_EMAIL_SEARCH_BASE"/>
<constructor-arg index="1" value="GROUP_EMAIL_SEARCH_FILTER"/>
<constructor-arg index="2" ref="ldapServer"/>
<property name="searchSubtree" value="true"/>
<property name="searchTimeLimit" value="GROUP_EMAIL_SEARCH_TIME_LIMIT_IN_MS"/>
<property name="groupEmailAttribute" value="GROUP_EMAIL_ATTRIBUTE_NAME"/>
</bean>
<bean id="ldapProvider" class="com.xebialabs.xlrelease.security.authentication.LdapAuthenticationProvider">
<constructor-arg ref="bindAuthenticator"/>
<constructor-arg ref="authoritiesPopulator"/>
<constructor-arg ref="ldapGroupEmailProvider"/>
<!-- Set optional external id attribute if required -->
<property name="externalIdAttribute" value="EXTERNAL_ID_ATTRIBUTE_NAME"/>
</bean>
<bean id="userDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService">
<constructor-arg index="0" ref="userSearch"/>
<constructor-arg index="1" ref="authoritiesPopulator"/>
</bean>
<bean id="rememberMeAuthenticationProvider" class="com.xebialabs.deployit.security.authentication.RememberMeAuthenticationProvider"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="rememberMeAuthenticationProvider"/>
<security:authentication-provider ref="xlAuthenticationProvider"/>
<security:authentication-provider ref="ldapProvider"/>
</security:authentication-manager>
</beans>
Update the security XML file
- Update
xl-release-security.xml
with information about your LDAP setup:
Placeholder | Description | Example |
---|---|---|
LDAP_SERVER_URL | LDAP URL to connect to. | ldap://localhost:389/ |
MANAGER_DN | Principal to perform the initial bind to the LDAP server. | cn=admin,dc=example,dc=com |
MANAGER_PASSWORD | Credentials to perform the initial bind to the LDAP server. For more information, see configure custom passwords. | secret |
USER_SEARCH_FILTER | LDAP filter to determine the LDAP dn for the user who is logging in; {0} will be replaced with the user name. | (&(uid={0})(objectClass=inetOrgPerson)) |
USER_SEARCH_BASE | LDAP filter to use as a basis for searching for users. | dc=example,dc=com |
GROUP_SEARCH_FILTER | LDAP filter to determine the group memberships of the user; {0} will be replaced with the dn of the user. | (member={0}) |
GROUP_SEARCH_BASE | LDAP filter to use as a basis for searching for groups. | ou=groups,dc=example,dc=com |
GROUP_EMAIL_SEARCH_BASE | LDAP filter to use as a basis for searching for mailing groups. | ou=groups,dc=example,dc=com |
GROUP_EMAIL_SEARCH_FILTER | LDAP filter to determine the mailing group; {0} will be replaced with the dn of the group. | (cn={0}) |
GROUP_EMAIL_SEARCH_TIME_LIMIT_IN_MS | LDAP request time limit in milliseconds. | 1000 |
GROUP_EMAIL_ATTRIBUTE_NAME | LDAP attribute to determine a mailing group mail. | mail |
EXTERNAL_ID_ATTRIBUTE_NAME | LDAP attribute to determine an external id. | employeeId |
- After you provide values, restart the Release server.
- Add the group as principals in the Release interface and assign the permission to group to log in.
- Use an LDAP browser such as JXplorer to verify that the credentials are correct.
Allow users of a certain group to login only
The following sample grants access to users of a certain group only.
Important: Do not copy the entire sample. We recommend that you add the following items only: ldap://192.168.0.1:389
, cn=admin,dc=test,dc=com
, myPassword
, and (&(objectclass=posixAccount)(entryDN=cn={0},cn=MY_AD_GROUP,ou=Security,ou=Groups,ou=France,ou=Regions,dc=test,dc=com)
only. This sample may differ from your xl-release-security.xml
file, depending on your version of Release and any other customizations that you have made.
Note: This is based on an openldap implementation. Filter queries may differ based on your LDAP setup and vendor.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
">
<bean id="ldapServer" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://192.168.0.1:389"/>
<property name="userDn" value="cn=admin,dc=test,dc=com"/>
<property name="password" value="myPassword"/>
<property name="baseEnvironmentProperties">
<map>
<entry key="java.naming.referral" value="ignore"/>
</map>
</property>
</bean>
<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value="dc=test,dc=com"/>
<!-- Use this LDAP filter query to allow only users from a specific Organisational Unit -->
<constructor-arg index="1"
value="(&(objectclass=posixAccount)(entryDN=cn={0},cn=MY_AD_GROUP,ou=Security,ou=Groups,ou=France,ou=Regions,dc=test,dc=com)"/>
<constructor-arg index="2" ref="ldapServer"/>
</bean>
<bean id="bindAuthenticator" class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="ldapServer"/>
<property name="userSearch" ref="userSearch"/>
</bean>
<bean id="authoritiesPopulator" class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="ldapServer"/>
<constructor-arg value="ou=users,o=mycorp"/>
<property name="groupSearchFilter" value="(&(objectclass=group)(member={0}))"/>
<property name="rolePrefix" value=""/>
<property name="searchSubtree" value="true"/>
<property name="convertToUpperCase" value="false"/>
</bean>
<bean id="ldapProvider" class="com.xebialabs.xlrelease.security.authentication.LdapAuthenticationProvider">
<constructor-arg ref="bindAuthenticator"/>
<constructor-arg ref="authoritiesPopulator"/>
</bean>
<bean id="userDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService">
<constructor-arg index="0" ref="userSearch"/>
<constructor-arg index="1" ref="authoritiesPopulator"/>
</bean>
<bean id="rememberMeAuthenticationProvider" class="com.xebialabs.deployit.security.authentication.RememberMeAuthenticationProvider"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="rememberMeAuthenticationProvider"/>
<security:authentication-provider ref="xlAuthenticationProvider"/>
<security:authentication-provider ref="ldapProvider"/>
</security:authentication-manager>
</beans>
Escaping special characters
You must escape the following special characters in xl-release-security.xml
:
Character | Escape with |
---|---|
& | & |
" | " |
' | ' |
< | < |
> | > |
Assign a default role to all authenticated users
If you have an LDAP setup and do not have a group that contains all Release users, and want to use such a group in the default xlAuthenticationProvider
, you can configure this in the xl-release-security.xml
file.
The following example creates a group called everyone
that is assigned to each authenticated user. You can then link this group to a Release role and assign a global permission to it. For more information, see configure permissions.
<beans>
...
<bean id="ldapProvider" class="com.xebialabs.xlrelease.security.authentication.LdapAuthenticationProvider">
<constructor-arg>
...
</constructor-arg>
<property name="authoritiesMapper" ref="additionalAuthoritiesMapper" />
</bean>
<bean id="xlAuthenticationProvider" autowire="constructor" class="com.xebialabs.xlrelease.security.authentication.ReleaseAuthenticationProvider">
<property name="authoritiesMapper" ref="additionalAuthoritiesMapper" />
</bean>
<bean id="additionalAuthoritiesMapper" class="com.xebialabs.deployit.security.AdditionalAuthoritiesMapper">
<property name="additionalAuthorities">
<list>
<value>everyone</value>
</list>
</property>
</bean>
</beans>
Setting up team security
To set up team security:
- Set up an LDAP/Active Directory group called
devs
. This group will be used by the members of a team in Release. Note: See your directory services documentation for details on how to configure a group. - Assign the
devs
group to a role in Release calledDevelopers
.- In the top navigation bar, click User management.
- Click Roles.
- Click New role.
- In the Role name field, type
Developers
. - Click Save.
- At the folder or release level, add permissions for a team called
Dev Team
that contains the Release roleDevelopers
. This role contains the created LDAP/Active Directory group calleddevs
.
When you log in as a user to the devs
group using LDAP/Active Directory, you will have the permissions for the Developers
role at the folder or release level.
LDAP data caching
To ensure a high level of performance, Release caches user data for 30 minutes and a group email for 1 minute. This can produce a small delay between updates in your LDAP repository when they appear in Release.
Sample setup and configuration with OpenLDAP
Follow the steps mentioned below to set up LDAP:
- Start Docker on your host.
- Start an OpenLDAP container.
docker run -p 389:389 -p 636:636 --name ldap-service -h ldap-service -e LDAP_ORGANISATION="XL" -e LDAP_DOMAIN="xl.com" -e LDAP_ADMIN_PASSWORD="password" -d osixia/openldap:lates
t Tip: This exposes LDAP over port 389 and LDAPS over port 636. Both ports are configurable. - Start a phpLDAPadmin container to serve the WebUI to the new LDAP.
docker run -p 6443:443 --name phpldapadmin-service -h phpldapadmin-service --link ldap-service:ldap-host -e PHPLDAPADMIN_LDAP_HOSTS=ldap-host --detach osixia/phpldapadmin:latest
Tip: This will run phpLDAPadmin at your host's port 6443 (configurable), which connects to the OpenLDAP service running in the container in step 2. - Access the phpLDAPadmin WebUI at
https://localhost:6443
. - Log in as admin with the right login DN (same as below if your LDAP domain name is xl.com as well).
Login Credential: ID : cn=admin,dc=xl,dc=com Password: password
- Populate the LDAP server with the users and groups by the below steps:
- Select Create new entry here
- Select Generic: Organisational Unit and create OU name = users.
- Click users and click Create a child entry
- Select Default
- Select inetOrgPerson, organizationalPerson, person from the ObjectClasses dropdown and click proceed.
- Change RDN to cn (cn) and fill the rest of the information.
- Click proceed and commit to create users.
- Click admin and then click Create new entry here.
- Select Generic: Organisational Unit and create OU name = group.
- Click groups and then click Create new entry here.
- Click Default
- Select groupOfNames,mailGroup from the ObjectClasses dropdown and click proceed.
- Change RDN to cn (cn) and fill the rest of the information.
- Fill the name of the group in cn, email, add members by searching.
- Click proceed and commit to create a group.
- Configure
conf/xl-release security.xml
file with LDAP connection. Add the below LDAP connection string to yourxl-release security.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
">
<bean id="ldapServer" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://localhost:389/"/>
<property name="userDn" value="cn=admin,dc=xl,dc=com"/>
<property name="password" value="password"/>
<property name="baseEnvironmentProperties">
<map>
<entry key="java.naming.referral">
<value>ignore</value>
</entry>
</map>
</property>
</bean>
<bean id="userSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value="dc=xl,dc=com"/>
<constructor-arg index="1" value="(&(uid={0})(objectClass=inetOrgPerson))"/>
<constructor-arg index="2" ref="ldapServer"/>
</bean>
<bean id="bindAuthenticator" class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="ldapServer" />
<property name="userSearch" ref="userSearch"/>
</bean>
<bean id="authoritiesPopulator" class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
<constructor-arg ref="ldapServer"/>
<constructor-arg value="ou=groups,dc=xl,dc=com"/>
<property name="groupSearchFilter" value="(member={0})"/>
<property name="rolePrefix" value=""/>
<property name="searchSubtree" value="true"/>
<property name="convertToUpperCase" value="false"/>
</bean>
<bean id="ldapGroupEmailProvider" class="com.xebialabs.xlrelease.principaldata.LdapGroupEmailProvider">
<constructor-arg index="0" value="ou=groups,dc=example,dc=org" />
<constructor-arg index="1" value="(cn={0})" />
<constructor-arg index="2" ref="ldapServer" />
<property name="searchSubtree" value="true" />
<property name="searchTimeLimit" value="1000" />
<property name="groupEmailAttribute" value="mail" />
</bean>
<bean id="ldapProvider" class="com.xebialabs.xlrelease.security.authentication.LdapAuthenticationProvider">
<constructor-arg ref="bindAuthenticator"/>
<constructor-arg ref="authoritiesPopulator"/>
<constructor-arg ref="ldapGroupEmailProvider"/>
</bean>
<bean id="userDetailsService" class="org.springframework.security.ldap.userdetails.LdapUserDetailsService">
<constructor-arg index="0" ref="userSearch"/>
<constructor-arg index="1" ref="authoritiesPopulator"/>
</bean>
<bean id="rememberMeAuthenticationProvider" class="com.xebialabs.deployit.security.authentication.RememberMeAuthenticationProvider"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="rememberMeAuthenticationProvider"/>
<security:authentication-provider ref="xlAuthenticationProvider"/>
<security:authentication-provider ref="ldapProvider"/>
</security:authentication-manager>
</beans>