Platform Explorer / server 10.10

Extension point directories

The directories extension point is used to register LDAP filtering parameters to identify which part of the LDAP branches are actually used by Nuxeo EP to fetch its entries.

Examples:

    <directory name="userDirectory">
        <server>default</server>
        <schema>user</schema>
        <types>
            <type>system</type>
        </types>
        <idField>username</idField>
        <idCase>unchanged</idCase>
        <passwordField>password</passwordField>
        <passwordHashAlgorithm>SSHA</passwordHashAlgorithm>
        <searchBaseDn>ou=people,dc=example,dc=com</searchBaseDn>
        <searchClass>person</searchClass>
        <searchFilter>(&amp;(sn=toto*)(myCustomAttribute=somevalue))</searchFilter>
        <searchScope>onelevel</searchScope>
        <readOnly>false</readOnly>
        <cacheTimeout>3600</cacheTimeout>
        <cacheMaxSize>1000</cacheMaxSize>
        <creationBaseDn>ou=people,dc=example,dc=com</creationBaseDn>
        <creationClass>top</creationClass>
        <creationClass>person</creationClass>
        <creationClass>organizationalPerson</creationClass>
        <creationClass>inetOrgPerson</creationClass>
        <rdnAttribute>uid</rdnAttribute>
        <querySizeLimit>200</querySizeLimit>
        <queryTimeLimit>0</queryTimeLimit>
        <fieldMapping name="username">uid</fieldMapping>
        <fieldMapping name="password">userPassword</fieldMapping>
        <fieldMapping name="firstName">givenName</fieldMapping>
        <fieldMapping name="lastName">sn</fieldMapping>
        <fieldMapping name="company">o</fieldMapping>
        <fieldMapping name="email">mail</fieldMapping>
        <references>
            <inverseReference directory="groupDirectory"
                dualReferenceField="members" field="groups"/>
        </references>
    </directory>
    <directory name="groupDirectory">
        <server>default</server>
        <schema>group</schema>
        <idField>groupname</idField>
        <searchBaseDn>ou=groups,dc=example,dc=com</searchBaseDn>
        <searchFilter>(|(objectClass=groupOfUniqueNames)(objectClass=groupOfURLs))</searchFilter>
        <searchScope>subtree</searchScope>
        <!-- Special entry adaptor that makes entries in the ou=editable branch editable
          other entries have the readonly flag. This require adding a "dn" xs:string field
          to the group schema.
          -->
        <entryAdaptor class="org.nuxeo.ecm.directory.impl.WritePolicyEntryAdaptor">
            <parameter name="fieldName">dn</parameter>
            <parameter name="regexp">.*,ou=editable,ou=groups,dc=example,dc=com</parameter>
        </entryAdaptor>
        <readOnly>false</readOnly>
        <cacheTimeout>3600</cacheTimeout>
        <cacheMaxSize>1000</cacheMaxSize>
        <creationBaseDn>ou=editable,ou=groups,dc=example,dc=com</creationBaseDn>
        <creationClass>top</creationClass>
        <creationClass>groupOfUniqueNames</creationClass>
        <rdnAttribute>cn</rdnAttribute>
        <querySizeLimit>200</querySizeLimit>
        <queryTimeLimit>0</queryTimeLimit>
        <fieldMapping name="groupname">cn</fieldMapping>
        <references>
            <!-- LDAP reference resolve DNs embedded in uniqueMember attributes

              If the target directory has no specific filtering policy, it is most
              of the time not necessary to enable the 'forceDnConsistencyCheck' policy.

              Enabling this option will fetch each reference entry to ensure its
              existence in the target directory.
            -->
            <ldapReference directory="userDirectory"
                dynamicAttributeId="memberURL" field="members"
                forceDnConsistencyCheck="false"
                staticAttributeId="uniqueMember" staticAttributeIdIsDn="true"/>
            <ldapReference directory="groupDirectory"
                dynamicAttributeId="memberURL" field="subGroups"
                forceDnConsistencyCheck="false" staticAttributeId="uniqueMember"/>
            <inverseReference directory="groupDirectory"
                dualReferenceField="subGroups" field="parentGroups"/>
            <ldapTreeReference directory="groupDirectory"
                field="children" scope="onelevel"/>
            <inverseReference directory="groupDirectory"
                dualReferenceField="children" field="parents"/>
        </references>
    </directory>

In the previous examples we configured two directories one for the users and one for the groups of users. Each directory uses a single schema which is to be registered as any core document schema and that will be used to build a DocumentModel for each matching entry of the directory.

Nuxeo EP provides group resolution for statically dn-referenced entries (in read and write mode) and for dynamically ldapUrl matched entries (readonly). You may also need to statically reference entries without a dn using the 'staticAttributeIdIsDn' attribute.

The references tags are used to dynamically build nxs:stringList fields of that schema that are to compute membership relationships between users and groups or between parent groups and sub groups. It can also resole children and parents following the ldap tree structure.

You have two ways for declaring a dynamic reference in a 'references' tag. You can use 'dynamicAttributeId' to point to an ldap attribute that contains an ldap url.

    <ldapReference directory="userDirectory"
        dynamicAttributeId="memberURL" field="members"/>

Or, you can use a subtag 'dynamicReference' to declare attributes that contain a DN, a filter and a type. This values will be used to selected the references.

    <ldapReference directory="userDirectory" field="members"/>
    <dynamicReference baseDN="ldapAttribute" filter="ldapAttribute" type="subtree/onelevel"/>
    <ldapReference/>

When using dynamic references, caching is advised since dynamic group resolution can be expensive.

The element "idCase" makes it possible to control the case of the identifier on Nuxeo side. It accepts values "upper", "lower" or "unchanged". It is useful when changing case on the LDAP without affecting Nuxeo (for rights management for instance which is case sensitive for instance).

Dependening on your LDAP Backend implementation, if you have some specific restriction (for example on password, or logins ...), you may want Nuxeo to handle the validation errors of your server on the Nuxeo side.

Since there error code and message may vary depending on the LDAP server provider, you may need to provide a custom class that knows how to handle the Exceptions returned by it.

For this you can specify a class that will be in charge of this task.

    <ldapExceptionHandler>org.nuxeo.ecm.directory.ldap.DefaultLdapExceptionProcessor</ldapExceptionHandler>

This class should implement org.nuxeo.ecm.directory.ldap.LdapExceptionProcessor and return a RecoverableClientException for any exception that should be displayed to the user.

By default, referrals will be automatically resolved, if you don't want that behavior (since 5.9.4) you can use the followReferrals tag

    <directory name="groupDirectory">
           ....
           <followReferrals>false</followReferrals>
           ...
        </directory>

Contribution Descriptor

Existing Contributions

  • nuxeo-runtime-10.10.jar /opt/apidoc/nuxeo-server-10.10-tomcat/nxserver/config/default-ldap-users-directory-bundle.xml
    <extension point="directories" target="org.nuxeo.ecm.directory.ldap.LDAPDirectoryFactory">
    
        <directory name="userLDAPDirectory">
          <server>default</server>
          <schema>user</schema>
          <idField>username</idField>
          <passwordField>password</passwordField>
    
          <searchBaseDn>ou=People,dc=nuxeo,dc=com</searchBaseDn>
          <searchClass>person</searchClass>
          <!-- To additionally restricte entries you can add an
            arbitrary search filter such as the following:
    
            <searchFilter>(&amp;(sn=toto*)(myCustomAttribute=somevalue))</searchFilter>
    
            Beware that "&" writes "&amp;" in XML.
          -->
    
          <!-- use subtree if the people branch is nested -->
          <searchScope>onelevel</searchScope>
    
          <!-- using 'subany', search will match *toto*. use 'subfinal' to
            match *toto and 'subinitial' to match toto*. subinitial is the
            default  behaviour-->
          <substringMatchType>subany</substringMatchType>
    
          <readOnly>true</readOnly>
    
          <!-- comment <cache* /> tags to disable the cache -->
          <!-- cache timeout in seconds -->
          <cacheTimeout>3600</cacheTimeout>
    
          <!-- maximum number of cached entries before global invalidation -->
          <cacheMaxSize>1000</cacheMaxSize>
    
          <cacheEntryName>ldap-user-entry-cache</cacheEntryName>
          <cacheEntryWithoutReferencesName>ldap-user-entry-cache-without-references</cacheEntryWithoutReferencesName>
    
          <creationBaseDn>ou=people,dc=example,dc=com</creationBaseDn>
          <creationClass>top</creationClass>
          <creationClass>person</creationClass>
          <creationClass>organizationalPerson</creationClass>
          <creationClass>inetOrgPerson</creationClass>
    
          <rdnAttribute>uid</rdnAttribute>
          <fieldMapping name="username">uid</fieldMapping>
          <fieldMapping name="password">********</fieldMapping>
          <fieldMapping name="firstName">givenName</fieldMapping>
          <fieldMapping name="lastName">sn</fieldMapping>
          <fieldMapping name="company">o</fieldMapping>
          <fieldMapping name="email">mail</fieldMapping>
    
          <references>
    
            <inverseReference directory="groupDirectory" dualReferenceField="members" field="groups"/>
    
          </references>
    
        </directory>
    
      </extension>