Table of Contents
The SQL server as storage backend is provided by org.nuxeo.ecm.directory.sql.* component.
<component name="org.nuxeo.ecm.directory.sql.storage"> <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="userDirectory"> <schema>user</schema> <dataSource>java:/nxsqldirectory</dataSource> <table>users</table> <idField>username</idField> <passwordField>password</passwordField> <autoincrementIdField>false</autoincrementIdField> <dataFile>users.csv</dataFile> <createTablePolicy>on_missing_columns</createTablePolicy> <querySizeLimit>15</querySizeLimit> </directory> </extension> </component>
This code declares a directories node which defines a directory of users or of groups. The following information are given to describe the directory:
name
: name of the server which will be used
in the declaration of the directories
schema
: namee of the schema describing the
user attributes in the directory
dataSource
: type of storage for the
directory. In this example, the HSQLDB is used. Other RDBMS like
PostgreSQL can be used to store the datas by changing the local
datasource.
table
: name of the table in which the data
will be stored
idField
: the id field designs the primary key
in the table, used for retrieving entries by id
password
: field from the table which contain
the passwords, relative to the identfiant
autoincrementIdField: boolean value which tells if the idField is automatically incremented - this value is most of the time at false, because the identifiant is a string.
dataFile
: file from which data are getting to
populate the table. Be careful to follow the structure of the schema
given above.
createTablePolicy
: indicates how the dataFile
will be used to populate the table. Three values are allowed:
never: the dataFile is never used
on_missing_columns: the dataFile is used to create missing columns, it means at creation of the table or each time a new column is added, to follow the schema for example. Colums cannot be deleted.
always: the dataFile is used to create the table as each restart of the application server
querySizeLimit
: the maximum number of results
that the queries on this directory should return; if there are more
results than this, an exception will be raised
The LDAP server as storage backend is provided by the org.nuxeo.ecm.directory.ldap.* component
First of all, LDAP servers have to be defined by adding a contribution to the servers extension point. The syntax is:
<extension target="org.nuxeo.ecm.directory.ldap.LDAPDirectoryFactory" point="servers"> <server name="default"> <ldapUrl>ldap://localhost:389</ldapUrl> <bindDn>cn=nuxeo5,ou=applications,dc=example,dc=com</bindDn> <bindPassword>changeme</bindPassword> </server> </extension>
These information need to be provided to use an LDAP connection:
name
:name of the server which will be used
in the declaration of the directories
ldapUrl
:address of the LDAP server. A
single server declaration can point to a cluster of replicated
servers. To leverage such a cluster and improve availibility, please
provide one <ldapUrl/> tag for each replica of the cluster.
ldaps is the convention to use TLS/SSL connection.
bindDn
: the Distinguished Name used to bind
to the LDAP server
bindPassword
: corresponding password
relative to the Distinguished Name for binding
These credentials are used by Nuxeo5 to browse directory and create/modify entries.
Once you have declared the server, you can define new LDAP directories, using the following syntax for its declaration:
<extension target="org.nuxeo.ecm.directory.ldap.LDAPDirectoryFactory" point="directories"> <directory name="userDirectory"> <server>default</server> <schema>user</schema> <idField>username</idField> <passwordField>password</passwordField> <searchBaseDn>ou=people,dc=example,dc=com</searchBaseDn> <searchClass>person</searchClass> <searchFilter>(&(sn=toto*)(myCustomAttribute=somevalue))</searchFilter> <searchScope>onelevel</searchScope> <substringMatchType>subany</substringMatchType> <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> </directory> </extension>
The attributes are:
name, schema, idField and passwordField are the same as for SQL directories
searchBaseDn
: entry point into the server's
LDAP tree structure. Searches are only made below this root
node
searchClass
: restricts the type of entries
to return as result
searchFilter
:additional filter to restrict
the search results
searchScope
: the scope of the search. It
can take two values:
onelevel:search only under the current node.
subtree: search in the whole subtree. Use this parameter when the [people] branch is nested.
substringMatchType
: defines who the query
is built using wildcard characters. Three different values can be
provided:
subany: wildcards are added around the string to match (as *foo*)
subinitial: wildcard is added before the string (*bar)
subfinal: wildcard is added after the string (baz*). This is the default behaviour.
readOnly
: boolean value. This parameter
allows to create new entries or modify existing ones in the LDAP
server
cacheTimeout
: cache timeout in
seconds
cacheMaxSize
: maximum number of cached
entries before global invalidation
To disable the cache, comment <cache* /> tags
creationBaseDn
: entry point in the server's
LDAP tree structure where new entries will be created. This is
useless to provided if readOnly attribute is set to false.
creationClass
: use as many tag as needed to
specify which class are used to defined new people entries in LDAP
server.
Directory references leverage two common ways of string relationship in LDAP directories
The static reference strategy is to apply when a multi-valued attribute stores the exhaustive list of distinguished names of reference entries, for example the uniqueMember of the groupOfUniqueNames object.
<ldapReference field="members" directory="userDirectory" staticAttributeId="uniqueMember" />
The staticAttributeId attribute contains directly the value which can be read and manipulated.
The dynamic attribute strategy is used when a potentially multi-value attribute stores a LDAP URL intensively, for example the memberURL's attribute of the groupOfURL object class.
<ldapReference field="members" directory="userDirectory" forceDnConsistencyCheck="false" dynamicAttributeId="memberURL" />
The value contained in dynamicAttributeId
looks
like ldap:///ou=groups,dc=example,dc=com??subtree?(cn=sub*) and will be
resolved by dynamical queries to get all values. The
forceDnConsistencyCheck
attribute will check that the
value got through the dynamic resolution correspond to the attended
format. otherwise, the value will be ignored. Use this check when you
are not sure of the validity of the distinguished name
The LDAP tree reference can be used to resolve children in the LDAP tree hierarchy.
<ldapTreeReference field="children" directory="groupDirectory" scope="subtree" />
The field has to be a list of strings. It will resolve children of entries in the current directory, and look them up in the directory specified in the reference.The scope attribute. Available scopes are "onelevel" (default), "subtree". Children with same id than parent will be filtered. An inverse reference can be used to retrieve the parent form the children entries. It will be stored in a list, even if there can be only 0 or 1 parent.
WARNING: Edit is NOT IMPLEMENTED: modifications to this field will be ignored when saving the entry.
Inverse references are defined with the following declarations:
<references> <inverseReference field="groups" directory="groupDirectory" dualReferenceField="members" /> </references>
This syntax should be understood as "the member groups value is an inverse reference on groupDirectory directory using members reference". It is the group directory that stores all members for a given group. So the groups of a member are retrieved by querying in which groups a member belongs to.
Multi directories are used to combine values coming from different directories.
For example, it is useful to combine entries from LDAP directory with a standard directory provided by Nuxeo5.
<component name="org.nuxeo.ecm.directory.multi.config"> <extension target="org.nuxeo.ecm.directory.multi.MultiDirectoryFactory" point="directories"> <directory name="multi"> <schema>schema</schema> <idField>uid</idField> <passwordField>password</passwordField> <source name="sourceA" creation="true"> ... </source> <source name="sourceB"> .... </source> </directory> </extension> </component>
This component provides tools to dialog with directories, make queries and get informations. Three classes are a
Directories are also useful to build and store values that will be used in option lists. We usually call "vocabulary" that kind of directories as they follow a simple schema.
<component name="org.nuxeo.ecm.directories"> <extension target="org.nuxeo.ecm.directory.sql.SQLDirectoryFactory" point="directories"> <directory name="country"> <schema>xvocabulary</schema> <parentDirectory>continent</parentDirectory> <dataSource>java:/nxsqldirectory</dataSource> <cacheTimeout>3600</cacheTimeout> <cacheMaxSize>1000</cacheMaxSize> <table>country</table> <idField>id</idField> <autoincrementIdField>false</autoincrementIdField> <dataFile>directories/country.csv</dataFile> <createTablePolicy>on_missing_columns</createTablePolicy> </directory> <directory name="continent"> <schema>vocabulary</schema> <dataSource>java:/nxsqldirectory</dataSource> <cacheTimeout>3600</cacheTimeout> <cacheMaxSize>1000</cacheMaxSize> <table>continent</table> <idField>id</idField> <autoincrementIdField>false</autoincrementIdField> <dataFile>directories/continent.csv</dataFile> <createTablePolicy>on_missing_columns</createTablePolicy> </directory> </extension> </component>
Example 19.1. Sample declaration of vocabularies.
The different attributes have the same behaviour as other directories.
Let's have a look at the schema attribute which can take two different values:
vocabulary
: this schema is provided to make
default vocabulary. It defines the following fields: id, label,
order and obsolete.
xvocabulary
: this schema is used to define
linked vocabularies. It defines the following fields: id, label,
order, obsolete and parent. When using
xvocabulary
schema, an other attribute should be
defined: parentDirectory
points the parent
directory name to which the current one is relative.
When these vocabularies are set up, the following JSF methods can be used to render them in forms:
<div xmlns:h="http://java.sun.com/jsf/html" xmlns:nxdir="http://nuxeo.org/nxdirectory"> <nxdir:selectOneListbox value="#{mydoc.myschema.myfield}" directoryName="continent" id="continentSelect" localize="true" /> <h:message for="continentSelect" class="errorMessage" /> </div>
Example 19.2. Sample declaration of vocabularies.
In this example, a simple vocabulary selection list is displayed. The equivalent tag for multi selection, nxdir:selectManyListbox is also available.
<div xmlns:h="http://java.sun.com/jsf/html" xmlns:nxdir="http://nuxeo.org/nxdirectory"> <h:selectOneListbox value="#{mydoc.myschema.myfield}" id="continentSelect"> <nxdir:selectItems directoryName="continent" var="item" itemValue="#{item.vocabulary.id}" itemLabel="#{item.vocabulary.label}" displayAll="true" /> </h:selectOneListbox> <h:message for="continentSelect" class="errorMessage" /> </div>
Example 19.3. Sample declaration of vocabularies.
This is the same example, but using standard JSF selection components, and another JSF method to display select items. This is more configurable, and can be helpful when using another schema than the default "vocabulary" and "xvocabulary" ones.
<div xmlns:h="http://java.sun.com/jsf/html" xmlns:a4j="https://ajax4jsf.dev.java.net/ajax" xmlns:nxdir="http://nuxeo.org/nxdirectory"> <a4j:region id="countrySelectRegion"> <nxdir:chainSelect size="2" value="#{mydoc.myschema.myfield}" id="#{continentCountryChainSelect}"> <nxdir:chainSelectListbox index="0" size="0" directoryName="continent" localize="true" id="selectContinent"> <a4j:support event="onchange" reRender="selectCountry" /> </nxdir:chainSelectListbox> <nxdir:chainSelectListbox size="0" index="1" directoryName="country" localize="true" id="selectCountry" /> </nxdir:chainSelect> </a4j:region> <h:message styleClass="errorMessage" for="continentCountryChainSelect" /> </div>
Example 19.4. Sample declaration of vocabularies.
This is an example of a chained list box.
For more information about available tags, please check the documentation at http://doc.nuxeo.org/current/tlddoc/. Note that this kind of rendering can be achieved using layout configuration too.
Some pages are available to be able to delete/add/edit entries in these directories. In the default application, it is presented clicking on the "Manage vocabularies" link that is displayed on top of every page if logged in as an administrator.
The list of directories that can be managed will be displayed. Since Nuxeo 5.2.1, this is managed through another extension point, dedicated to the User Interface part, and uses layouts configuration.
<component name="org.nuxeo.ecm.webapp.directory.directoryUI"> <extension target="org.nuxeo.ecm.directory.ui.DirectoryUIManager" point="directories"> <directory name="continent" layout="vocabulary" sortField="label"> <deleteConstraint class="org.nuxeo.ecm.directory.api.ui.HierarchicalDirectoryUIDeleteConstraint"> <property name="targetDirectory">country</property> <property name="targetDirectoryField">parent</property> </deleteConstraint> </directory> <directory name="country" layout="country_vocabulary" sortField="parent" /> </extension> <extension target="org.nuxeo.ecm.platform.forms.layout.WebLayoutManager" point="layouts"> <layout name="vocabulary"> <templates> <template mode="any"> /directory/directory_layout_template.xhtml </template> </templates> <rows> <row> <widget>vocabulary_id</widget> </row> <row> <widget>vocabulary_label</widget> </row> <row> <widget>vocabulary_obsolete</widget> </row> <row> <widget>vocabulary_order</widget> </row> </rows> </layout> <layout name="country_vocabulary"> <templates> <template mode="any"> /directory/directory_layout_template.xhtml </template> </templates> <rows> <row> <widget>parent</widget> </row> <row> <widget>xvocabulary_id</widget> </row> <row> <widget>xvocabulary_label</widget> </row> <row> <widget>xvocabulary_obsolete</widget> </row> <row> <widget>xvocabulary_order</widget> </row> </rows> <widget name="parent" type="selectOneDirectory"> <labels> <label mode="any">label.vocabulary.entry.parent</label> </labels> <translated>true</translated> <fields> <field>xvocabulary:parent</field> </fields> <properties mode="any"> <property name="directoryName">continent</property> <property name="localize">true</property> </properties> <properties widgetMode="edit"> <property name="required">true</property> </properties> </widget> </layout> </extension> </component>
Example 19.5. Sample declaration of directory to display.
This files is declaring the directories to display, and the layouts to use when displaying them. The layouts configuration is standard, please refer to the chapter Chapter 8, Layouts for more information.
Note that the Directory UI declaration can state a delete constraint to be used when trying to delete an item. The class checking the deletion can be contributed and has to follow the org.nuxeo.ecm.directory.api.ui.DirectoryUIDeleteConstraint interface. The class in the example takes as parameters some information about the directory where to check constraints on. It is designed to refuse deletion of a parent vocabulary item, if there is still a reference to it in the child vocabulary.