Skip to main content
Version: 2.25.x.x Java 8 ELS

LDAPDataSink

The LDAPDataSink supports create, update, delete methods described in Data sink implementations, thus allowing to keep an LDAP directory in sync with some arbitrary data source (e.g., a database). An LdapContextProvider is needed to access the LDAP directory.

The update mode determines how attributes are removed in the case of null values. Cross references can be used to ensure referential integrity across the current and referenced LDAP objects.

To support integration scenarios where the LDAP directory is not solely modified by nevisDataPorter but also by other entities or systems, attribute value management can be configured. By using this configuration parameter, nevisDataPorter is assigned its dedicated competence over a restricted set of values. In other words: nevisDataPorter will only consider LDAP attribute values that are actually declared to be within competence and leave all others untouched. Allowing the filtering mechanism to be configured directly on the sink reduces complexity and redundancy of the logic preceding the sink.

Configuration

NameType, usage constraints, defaultsDescription
basednrequired: paraVal
default: none
type: DN string
The base DN used to construct the DN of the object to be exported.Example: "ou=people,dc=example,dc=com"
rdnoptional: paraVal
default: none
type: DN string
The RDN used to construct the DN of the object to be exported. If the RDN is omitted, the filter is used as RDN. The RDN defines the naming attribute of the LDAP object. Its value depends on the underlying object class. Example: "cn=Hans Muster"
filteroptional: paraVal
default: none
type: LDAP filter string
The naming attribute used to construct the RDN is generally not a unique, invariant identifier and is subject to changes. The filter can be used to identify an object based on a different attribute than the naming attribute. Using a unique identifier attribute as a filter it is possible to change the value of the naming attribute. If the filter is omitted, the RDN is used for object identification.
searchScopeoptional: paraVal
default: onelevel
type: LDAP search scope string
Defines the scope of the search when used to update a directory object: object: Only search the object specified by the DN.; onelevel: Search one level in the LDAP hierarchy.; subtree: Search the full subtree with the DN object as root.
operationoptional: paraVal
default: createOrUpdate
type: export operation
Defines the operation used to export the object. The following operations are supported: create, update, delete, and createOrUpdate. See the table DataSink operations for a more detailed description of the supported operations.
ldapContextrequired: paraVal
default: none
type: ch.adnovum.dataporter.
dataobject.LdapContextProvider
A reference to an LdapContextProvider object. It refers either to an LDAPConnectionPool defined in some initialization section of the configuration file or it refers to an LdapContextProvider provided programmatically by the client application that is put into the configuration repository.
updateModeoptional: paraVal
default: full
type: update mode
The mode of an update operation: partial: Only add and update specified attributes. Do not remove them if null.; full: Add and update specified attributes. Remove specified attributes which are null.
crossReferencesoptional: paraMap
default: none
type: map of cross-references
Determines whether an attribute is referencing another object and whether this reference should be established through the other object or both objects.
managedAttributeValuesoptional: paraMap
default: none
type: map of maps per attribute
Determines whether a value shall be blocked or passed to the LDAP directory attribute. If the value is not contained in the list of values, the value is blocked and not written to the attribute

The LDAPDataSink requires for an operation either an RDN or a filter or both.

  • If only an RDN is given, the RDN is used to identify the LDAP object.
  • If only a filter is given, the filter is used as the RDN to create/update the object.
  • If both are given, the RDN is only used for object creation or renaming and the filter is used for object identification.

Moving an object in the directory is internally executed in two steps. First, the object is searched in the directory. Second, the object is moved. To be able to successfully complete both steps the starting point, i.e., the basedn, has to be chosen carefully in the directory tree to reach both locations, the old and the future one. Refer to the examples below for further information.

Moving an object in the directory changes its DN. To avoid issues with cross references, we strongly suggest not to combine a move of an object together with updates of other attributes containing DNs. Move the object first, then do a separate update of attributes like cross references; this guarantees cross references to contain proper, up-to-date DNs.

Cross-references are used to establish referential integrity. Specifically when putting the DN of the referenced object in the attribute value is not enough. The DN of the current value is also put in an attribute of the referenced object (operate on “both“) or only there (operate on “other“). E.g., in MS ActiveDirectory the attribute memberOf of a user object contains the DN of the group the user has a membership relation with. On the other side the referenced group stores DNs of all the users being a member of this group in the attribute member. Updating user membership is executed not on the memberOf attribute of the user but on the member attribute of the referenced group. Thus in this case, the operateOn parameter should be set to other.

As mentioned above, filtering of attribute values can be used to avoid collisions with other entities or systems that are operating on the same LDAP directory. Example: nevisDataPorter is only responsible for provisioning group membership for certain groups identified by corresponding group-DN. Modification operations on directory objects shall only consider configured group-DNs and leave other DNs untouched. Another system or a LDAP administrator can operate on the same LDAP directory without interference from nevisDataPorter and vice versa (provided that all entities stick to their assigned competences regarding group-DNs).

Example

Identification based on the naming attribute "cn":

<dataSink type="LDAPDataSink">
<dp:paraVal name="ldapContext" value="${inst.ldapConnection}"/>
<dp:paraVal name="operation" value="update"/>
<dp:paraVal name="basedn" value="ou=people,dc=example,dc=com"/>
<dp:paraVal name="rdn" value="cn=#{out.person.cn}"/>
</dataSink>

Identification based on the "uid" attribute:

<dataSink type="LDAPDataSink">
<dp:paraVal name="ldapContext" value="${inst.ldapConnection}"/>
<dp:paraVal name="operation" value="update"/>
<dp:paraVal name="basedn" value="ou=people,dc=example,dc=com"/>
<dp:paraVal name="rdn" value="cn=#{out.person.cn}"/>
<dp:paraVal name="filter" value="uid=#{out.person.uid}"/>
</dataSink>

Move of an object in MS ActiveDirectory based on "sAMAccountName" attribute:

<!— example directory tree layout:
user object is below
'ou=people,dc=example,dc=com'
the move destination is an archive at
'ou=archive,dc=example, dc=com'.
The selection of 'basedn' is important here, it has to "cover" the old and the new destination on the same time.
In this example the 'basedn' is set to 'dc=example,dc=com' as this node is an ancestor for both locations.
That is, the 'archive' OU and the 'people' OU are both below the 'basedn'.
The example uses the 'sAMAccountName' as the unique identifying attribute for the object being moved.
The variables used are taken from 'ctl' repository as the modification is purely done on the naming attribute,
without updating other attributes which would be found in 'out' repository.-->

<dataSink type="LDAPDataSink">
<dp:paraVal name="ldapContext" value="${inst.ldapConnection}"/>
<dp:paraVal name="operation" value="update"/>
<dp:paraVal name="basedn" value="dc=example,dc=com"/>
<!-- the new DN is computed as rdn + basedn-->
<dp:paraVal name="rdn" value="cn=#{ctl.person.cn},ou=archive,dc=example,dc=com"/>
<dp:paraVal name="filter" value="sAMAccountName=#{ctl.person.sam}"/>
<!-- basedn to current and to new location are both deeper than one level from the basedn, thus use the subtree scope to reach both locations -->
<dp:paraVal name="searchScope" value="subtree"/>
</dataSink>

Referential integrity through cross-references for directories without reverse group membership overlay:

<dataSink type="LDAPDataSink">
<dp:paraVal name="ldapContext" value="${inst.ldapConnection}"/>
<dp:paraVal name="operation" value="update"/>
<dp:paraVal name="basedn" value="${cfg.ldapBaseUserDn}"/>
<dp:paraVal name="rdn" value="cn=#{out.user.cn}"/>
<dp:paraMap name="crossReferences">
<!-- name of attribute on current object -->
<map name="memberOf">
<!-- name of attribute on referenced (other) object -->
<value name="other" value="member" />
<!-- set the value on the current and other objects' attributes -->
<value name="operateOn" value="both" />
<!-- do not keep the attribute when it's empty (depends on the schema)-->
<value name="keepEmptyAttr" value="false" />
</map>
</dp:paraMap>
</dataSink>

Referential integrity through cross-references for MS Active Directory:

<dataSink type="LDAPDataSink">
<dp:paraVal name="ldapContext" value="${inst.ldapConnection}"/>
<dp:paraVal name="operation" value="update"/>
<dp:paraVal name="basedn" value="${cfg.ldapBaseUserDn}"/>
<dp:paraVal name="rdn" value="cn=#{out.user.cn}"/>
<dp:paraMap name="crossReferences">
<!— usage with MS AD user 'memberof' and group 'member' attribute -->
<map name="memberOf">
<value name="other" value="member" />
<!—update only the group attribute 'member'-->
<value name="operateOn" value="other" />
<!—in MS AD the member of attribute is either filled or not present at all -->
<value name="keepEmptyAttr" value="false" />
</map>
</dp:paraMap>
</dataSink>

Filtering mechanism with help of managed attribute values:

<!—example uses simple values but complete DNs can be used to restrict group membership competence of NevisDataporter to a set of groups -->
<entity name="updateDescription">
<dataFilter type="ELMappingFilter">
<dp:attrVal name="cn" value="newperson" />
<!—try to write all 5 values to the description attribute -->
<dp:attrList name="description">
<value>Zuse Z2 (1939)</value> <!—ignored -->
<value>Zuse Z3 (1941)</value> <!—ignored -->
<value>Zuse Z4 (1942)</value>
<value>Zuse Z11 (1955)</value>
<value>Zuse Z22 (1955)</value> <!—ignored -->
</dp:attrList>
</dataFilter>
<dataSink type="LDAPDataSink">
<dp:paraVal name="ldapContext" value="${inst.ldapConnection}" />
<dp:paraVal name="operation" value="update" />
<dp:paraVal name="basedn" value="${cfg.ldapBaseUserDn}" />
<dp:paraVal name="rdn" value="cn=#{out.updateDescription.cn}" />
<dp:paraVal name="updateMode" value="partial" />
<dp:paraMap name="managedAttributeValues">
<!—restrict the attribute 'description' to the following list of managed values,
change this name to the attribute you want to be filtered -->
<map name="description" >
<!— the list with the constant name 'values' declares all allowed values of attribute 'description',
if a value is not contained in this list it is skipped -->
<list name="values">
<!—this leaves the effective modification with only 'Zuse Z11 (1955)' and 'Zuse Z4 (1942)',
as we restrict attribute values to the follwing list -->
<value>Zuse Z11 (1955)</value>
<value>Zuse Z4 (1942)</value>
<value>another managed value</value>
</list>
</map>
</dp:paraMap>
</dataSink>
</entity>