Nuxeo Server

How to Configure a Multidirectory for Users and Groups

Updated: December 26, 2016 Page Information Edit on GitHub

This page provides a turnkey solution to configure a multidirectory which responds to the following needs:

  • Local and LDAP users,
  • Local and LDAP groups,
  • Local user creation,
  • Local group creation,
  • Local groups can contain local and LDAP groups as subgroups,
  • Local groups can reference local and LDAP users as members.

This configuration is ready to use, so it is based on a public LDAP server whose main properties are:

  • URL: ldap://ldap.testathon.net:389/
  • Bind user and password: stuart / stuart
  • Search base DNs for users and groups are entries of DC=testathon,DC=net

Moreover a virtual administrator is added to let you log in even if the LDAP configuration is not perfectly working. It lets you browse the users and groups from Admin Center > Users & Groups.

To enable this configuration:

  1. Copy the XML below in a default-multi-directories-config.xml file.
  2. Put the file in $NUXEO/nxserver/config.
  3. Start your server.
  4. Check this multidirectory configuration is working on your Nuxeo Platform instance. For instance:

    • Log in with stuart / stuart.
    • Log in with MyAdministrator / secret
    • With any of these two accounts, go to the Admin > Users & Groups menu to see new users or groups from the LDAP (use * to search all users/groups).
  5. Stop the server and edit the XML file to change the parameters and the field mappings with your specific ones.

default-multi-directories-config.xml

<?xml version="1.0"?>
<component name="org.nuxeo.ecm.directory.multi.storage.users">
  <implementation class="org.nuxeo.ecm.directory.ldap.LDAPDirectoryDescriptor" />
  <implementation class="org.nuxeo.ecm.directory.ldap.LDAPServerDescriptor" />
  <require>org.nuxeo.ecm.directory.ldap.LDAPDirectoryFactory</require>
  <!-- the groups SQL directories are required to make this bundle work -->
  <require>org.nuxeo.ecm.directory.sql.storage</require>
  <require>org.nuxeo.ecm.platform.usermanager.UserManagerImpl</require>

  <extension target="org.nuxeo.ecm.directory.ldap.LDAPDirectoryFactory"
    point="servers">
    <server name="default">
      <ldapUrl>ldap://ldap.testathon.net:389/</ldapUrl>
      <bindDn>CN=stuart,OU=users,DC=testathon,DC=net</bindDn>
      <bindPassword>stuart</bindPassword>
      <!-- Attempts to get a result when LDAP is temporary unavailable -->
      <retries>5</retries>
    </server>
  </extension>

  <extension target="org.nuxeo.ecm.directory.ldap.LDAPDirectoryFactory"
    point="directories">
    <directory name="ldapUserDirectory">
      <server>default</server>
      <schema>user</schema>
      <idField>username</idField>
      <passwordField>password</passwordField>
      <searchBaseDn>DC=testathon,DC=net</searchBaseDn>
      <searchClass>person</searchClass>
      <!-- use subtree if the people branch is nested -->
      <searchScope>subtree</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>
      <!--
           If the id field is not returned by the search, we set it with the searched entry, probably the login.
           Before setting it, you can change its case. Accepted values are 'lower' and 'upper',
           anything else will not change the case.
      -->
      <missingIdFieldCase>lower</missingIdFieldCase>
      <!-- Maximum number of entries returned by the search -->
      <querySizeLimit>200</querySizeLimit>
      <!-- Time to wait for a search to finish. 0 to wait indefinitely -->
      <queryTimeLimit>0</queryTimeLimit>

      <rdnAttribute>cn</rdnAttribute>
      <fieldMapping name="username">cn</fieldMapping>
      <fieldMapping name="password">userPassword</fieldMapping>
      <fieldMapping name="firstName">givenName</fieldMapping>
      <fieldMapping name="lastName">sn</fieldMapping>
      <fieldMapping name="company">telephoneNumber</fieldMapping>
      <fieldMapping name="email">mail</fieldMapping>
      <references>
        <inverseReference field="groups" directory="multiGroupDirectory"
          dualReferenceField="members" />
      </references>
    </directory>
    <directory name="ldapGroupDirectory">
      <!-- Reuse the default server configuration defined for ldapUserDirectory -->
      <server>default</server>
      <schema>group</schema>
      <idField>groupname</idField>
      <searchBaseDn>OU=groups,DC=testathon,DC=net</searchBaseDn>
      <searchFilter>
        (|(objectClass=groupOfNames)(objectClass=groupOfURLs))
      </searchFilter>
      <searchScope>subtree</searchScope>
      <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>

      <!-- Maximum number of entries returned by the search -->
      <querySizeLimit>200</querySizeLimit>
      <!-- Time to wait for a search to finish. 0 to wait indefinitely -->
      <queryTimeLimit>0</queryTimeLimit>
      <rdnAttribute>cn</rdnAttribute>
      <fieldMapping name="groupname">cn</fieldMapping>
      <!-- Add another field to map reel group label -->
      <fieldMapping name="grouplabel">description</fieldMapping>
      <references>
        <ldapReference field="members" directory="ldapUserDirectory"
          forceDnConsistencyCheck="false" staticAttributeId="member"
          dynamicAttributeId="memberURL" />
        <ldapReference field="subGroups" directory="ldapGroupDirectory"
          forceDnConsistencyCheck="false"  staticAttributeId="member"
          dynamicAttributeId="memberURL" />
        <inverseReference field="parentGroups" directory="multiGroupDirectory"
          dualReferenceField="subGroups" />
      </references>
    </directory>
  </extension>

  <implementation class="org.nuxeo.ecm.directory.sql.SQLDirectoryDescriptor" />
  <require>org.nuxeo.ecm.directory.sql.SQLDirectoryFactory</require>
  <extension target="org.nuxeo.ecm.directory.sql.SQLDirectoryFactory"
    point="directories">
    <directory name="sqlUserDirectory">
      <schema>user</schema>
      <dataSource>jdbc/nxsqldirectory</dataSource>

<table>users</table>
      <idField>username</idField>
      <passwordField>password</passwordField>
      <passwordHashAlgorithm>SSHA</passwordHashAlgorithm>
      <autoincrementIdField>false</autoincrementIdField>
      <computeMultiTenantId>false</computeMultiTenantId>
      <dataFile>users.csv</dataFile>
      <createTablePolicy>on_missing_columns</createTablePolicy>
      <querySizeLimit>50</querySizeLimit>
      <references>
        <inverseReference field="groups" directory="sqlGroupDirectory"
          dualReferenceField="members" />
      </references>
    </directory>
    <directory name="sqlGroupDirectory">
      <schema>group</schema>
      <dataSource>jdbc/nxsqldirectory</dataSource>

<table>groups</table>
      <idField>groupname</idField>
      <dataFile>groups.csv</dataFile>
      <createTablePolicy>on_missing_columns</createTablePolicy>
      <autoincrementIdField>false</autoincrementIdField>
      <!-- Add 10 min cache to avoid refetching the groups during login -->
      <cacheTimeout>360</cacheTimeout>
      <cacheMaxSize>1000</cacheMaxSize>
      <references>
        <tableReference field="members" directory="multiUserDirectory"
          table="user2group" sourceColumn="groupId" targetColumn="userId" schema="user2group"
          dataFile="user2group.csv" />
        <tableReference field="subGroups" directory="sqlGroupDirectory"
          table="group2group" sourceColumn="parentGroupId"
          targetColumn="childGroupId" schema="group2group" />
        <inverseReference field="parentGroups" directory="sqlGroupDirectory"
          dualReferenceField="subGroups" />
      </references>
    </directory>
  </extension>

  <extension
    target="org.nuxeo.ecm.directory.multi.MultiDirectoryFactory"
    point="directories">
    <directory name="multiUserDirectory">
      <schema>user</schema>
      <idField>username</idField>
      <passwordField>password</passwordField>
      <source name="userSQLsource" creation="true">
        <subDirectory name="sqlUserDirectory" />
      </source>
      <source name="userLDAPsource">
        <subDirectory name="ldapUserDirectory" />
      </source>
    </directory>
    <directory name="multiGroupDirectory">
      <schema>group</schema>
      <idField>groupname</idField>
      <source name="groupSQLsource" creation="true">
        <subDirectory name="sqlGroupDirectory" />
      </source>
      <source name="groupLDAPsource">
        <subDirectory name="ldapGroupDirectory" />
      </source>
    </directory>
  </extension>

  <extension target="org.nuxeo.ecm.platform.usermanager.UserService" point="userManager">
    <userManager>
      <defaultAdministratorId>stuart</defaultAdministratorId>
      <defaultGroup>members</defaultGroup>
      <users>
        <directory>multiUserDirectory</directory>
        <virtualUser id="MyAdministrator" searchable="false">
          <password>secret</password>
          <property name="firstName">Super</property>
          <property name="lastName">Admin</property>
          <group>administrators</group>
        </virtualUser>
      </users>
      <groups>
        <directory>multiGroupDirectory</directory>
      </groups>
    </userManager>
  </extension>
</component>


4 months ago Solen Guitter review for docday dmetzler
4 months ago Solen Guitter Fix links, formatting issues, add related pages, rename pages
4 months ago Solen Guitter reorganize authentication page
5 months ago Andrew Goodricke Add content-review-lts2016 to labels
5 months ago manonlumeau Fix related pages panel
6 months ago Kevin Leturc NXP-19481: Update MarkLogic page to detail how to configure range element indexes
a year ago Solen Guitter 11
a year ago Solen Guitter 10
2 years ago Solen Guitter 9
2 years ago Thierry Martins 8
2 years ago Solen Guitter 7 | fix xml and add details in steps
2 years ago Solen Guitter 6
3 years ago Manon Lumeau 5
3 years ago Solen Guitter 4
3 years ago Solen Guitter 3
3 years ago Thierry Martins 2
3 years ago Thierry Martins 1
History: Created by Thierry Martins