Commit d9958cbd authored by Howard Chu's avatar Howard Chu
Browse files

Enhanced unique configuration

parent 0752716d
......@@ -9,9 +9,9 @@ ETCDIR/slapd.conf
.SH DESCRIPTION
The Attribute Uniqueness overlay can be used with a backend database such as
.BR slapd-bdb (5)
to enforce the uniqueness of some or all attributes within a subtree. This
subtree defaults to the base DN of the database for which the Uniqueness
overlay is configured.
to enforce the uniqueness of some or all attributes within a
scope. This subtree defaults to all objects within the subtree of the
database for which the Uniqueness overlay is configured.
.LP
Uniqueness is enforced by searching the subtree to ensure that the values of
all attributes presented with an
......@@ -19,7 +19,7 @@ all attributes presented with an
.B modify
or
.B modrdn
operation are unique within the subtree.
operation are unique within the scope.
For example, if uniqueness were enforced for the
.B uid
attribute, the subtree would be searched for any other records which also
......@@ -35,18 +35,59 @@ They should appear after the
.B overlay
directive.
.TP
.B unique_base <basedn>
Configure the subtree against which uniqueness searches will be invoked.
.B unique_uri <[strict ][ignore ]URI[URI...]...>
Configure the base, attributes, scope, and filter for uniqueness
checking. Multiple URIs may be specified within a domain, allowing complex selections of objects. Multiple
.B unique_uri
statements or
.B olcUniqueURI
attributes will create independent domains, each with their own independent lists of URIs and ignore/strict settings.
The LDAP URI syntax is a subset of
.B RFC-4516,
and takes the form:
ldap:///[base dn]?[attributes...]?scope[?filter]
The
.B basedn
defaults to the base DN of the database for which uniqueness is configured.
.TP
.B unique_ignore <attribute...>
Configure one or more attributes for which uniqueness will not be enforced.
.B base dn
defaults to that of the back-end database. Specified base dns must be within the subtree of the back-end database.
If no
.B attributes
are specified, the URI applies to all non-operational attributes.
The
.B scope
component is effectively mandatory, because LDAP URIs default to
.B base
scope, which is not valid for uniqueness, because groups of one object
are always unique. Scopes of
.B sub
(for subtree) and
.B one
for one-level are valid.
The
.B filter
component causes the domain to apply uniqueness constraints only to
matching objects. e.g.
.B ldap:///?cn?sub?(sn=e*)
would require unique
.B cn
attributes for all objects in the subtree of the back-end database whose
.B sn
starts with an e.
It is possible to assert uniqueness upon all non-operational
attributes except those listed by prepending the keyword
.B ignore
If not configured, all non-operational (eg, system) attributes must be
unique. Note that the
.B unique_ignore
list should generally contain the
.B attributes
list of an
.B ignore
URI should generally contain the
.BR objectClass ,
.BR dc ,
.B ou
......@@ -54,42 +95,55 @@ and
.B o
attributes, as these will generally not be unique, nor are they operational
attributes.
It is possible to set strict checking for the uniqueness domain by
prepending the keyword
.B strict.
By default, uniqueness is not enforced
for null values. Enabling
.B strict
mode extends the concept of uniqueness to include null values, such
that only one attribute within a subtree will be allowed to have a
null value. Strictness applies to all URIs within a uniqueness
domain, but some domains may be strict while others are not.
.LP
It is not possible to set both URIs and legacy slapo-unique configuration parameters simultaneously. In general, the legacy configuration options control pieces of a single unfiltered subtree domain.
.TP
.B unique_base <basedn>
This legacy configuration parameter should be converted to the
.B base dn
component of the above
.B unique_uri
style of parameter.
.TP
.B unique_ignore <attribute...>
This legacy configuration parameter should be converted to a
.B unique_uri
parameter with
.B ignore
keyword as described above.
.TP
.B unique_attributes <attribute...>
Specify one or more attributes for which uniqueness will be enforced.
If not specified, all attributes which are not operational (eg, system
attributes such as
.B entryUUID )
or specified via the
.B unique_ignore
directive above must be unique within the subtree.
This legacy configuration parameter should be converted to a
.B unique_uri
parameter, as described above.
.TP
.B unique_strict
By default, uniqueness is not enforced for null values. Enabling
.B unique_strict
mode extends the concept of uniqueness to include null values, such that
only one attribute within a subtree will be allowed to have a null value.
This legacy configuration parameter should be converted to a
.B strict
keyword prepended to a
.B unique_uri
parameter, as described above.
.SH CAVEATS
.LP
The search key is generated with attributes that are non-operational, not
on the
.B unique_ignore
list, and included in the
.B unique_attributes
list, in that order. This makes it possible to create interesting and
unusable configurations. Usually only one of
.B unique_ignore
or
.B unique_attributes
should be configured; use
.B unique_ignore
if the majority of attributes should be unique, and use
.B unique_attributes
if only a small set of attributes should be unique.
.B unique_uri
cannot be used with the old-style of configuration, and vice versa.
.B unique_uri
can implement everything the older system can do, however.
.LP
Typical attributes for the
.B unique_ignore
directive are intentionally not hardcoded into the overlay to allow for
.B ignore ldap:///...
URIs are intentionally not hardcoded into the overlay to allow for
maximum flexibility in meeting site-specific requirements.
.SH FILES
.TP
......
This diff is collapsed.
......@@ -47,7 +47,14 @@ rootpw secret
#ldbm#index cn,sn,uid pres,eq,sub
overlay unique
unique_ignore o cn sn ou objectClass
unique_attributes employeeNumber displayName
unique_base o=unique
#unique_uri ldap:///?description?one
#unique_uri ldap:///?employeeNumber,displayName?sub
#monitor#database monitor
database config
include @TESTDIR@/configpw.conf
......@@ -16,16 +16,19 @@
echo "running defines.sh"
. $SRCDIR/scripts/defines.sh
if test $UNIQUE = uniqueno; then
if test $UNIQUE = uniqueno; then
echo "Attribute Uniqueness overlay not available, test skipped"
exit 0
fi
fi
mkdir -p $TESTDIR $DBDIR1
$SLAPPASSWD -g -n >$CONFIGPWF
echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf
echo "Running slapadd to build slapd database..."
. $CONFFILTER $BACKEND $MONITORDB < $UNIQUECONF > $CONF1
$SLAPADD -f $CONF1 -l $LDIFUNIQUE
$SLAPADD -f $CONF1 -l $LDIFUNIQUE -d7
RC=$?
if test $RC != 0 ; then
echo "slapadd failed ($RC)!"
......@@ -33,7 +36,8 @@ if test $RC != 0 ; then
fi
echo "Starting slapd on TCP/IP port $PORT1..."
$SLAPD -f $CONF1 -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
mkdir testrun/confdir
$SLAPD -f $CONF1 -F testrun/confdir -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
PID=$!
if test $WAIT != 0 ; then
echo PID $PID
......@@ -62,9 +66,6 @@ if test $RC != 0 ; then
fi
echo "Adding a unique record..."
#$LDAPADD -D "$UNIQUEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD > \
# $TESTOUT 2>&1 << EOTUNIQ1
$LDAPADD -D "$UNIQUEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \
> /dev/null << EOTUNIQ1
dn: uid=dave,ou=users,o=unique
......@@ -82,7 +83,6 @@ employeeNumber: 69
employeeType: contractor
givenName: Dave
EOTUNIQ1
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed ($RC)!"
......@@ -90,11 +90,180 @@ if test $RC != 0 ; then
exit $RC
fi
#echo ----------------------
#$LDAPSEARCH -S "" -b "o=unique" -h $LOCALHOST -p $PORT1
echo "Adding a non-unique record..."
$LDAPADD -D "$UNIQUEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD > \
$TESTOUT 2>&1 << EOTUNIQ2
dn: uid=bill,ou=users,o=unique
objectClass: inetOrgPerson
uid: bill
sn: johnson
cn: bill
businessCategory: rtest
carLicense: ABC123
departmentNumber: 42
displayName: Bill
employeeNumber: 5150
employeeType: contractor
givenName: Bill
EOTUNIQ2
RC=$?
if test $RC != 19 ; then
echo "unique check failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Dynamically retrieving initial configuration...
$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -h $LOCALHOST -p $PORT1 -LLL | tr -d \\r >testrun/initial-config.ldif
cat <<EOF >testrun/initial-reference.ldif
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
objectClass: olcOverlayConfig
objectClass: olcUniqueConfig
olcOverlay: {0}unique
olcUniqueBase: o=unique
olcUniqueAttribute: employeeNumber
olcUniqueAttribute: displayName
EOF
diff testrun/initial-config.ldif testrun/initial-reference.ldif > /dev/null 2>&1
RC=$?
if test $RC != 0 ; then
echo "Initial configuration is not reported correctly."
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Dynamically trying to add a URI with legacy attrs present...
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
add: olcUniqueURI
olcUniqueURI: ldap:///?employeeNumber,displayName?sub
EOF
RC=$?
if test $RC != 80 ; then
echo "legacy and unique_uri allowed together"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Dynamically trying to add legacy ignored attrs with legacy attrs present...
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
add: olcUniqueIgnore
olcUniqueIgnore: objectClass
EOF
RC=$?
if test $RC != 80 ; then
echo "legacy attrs and legacy ignore attrs allowed together"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Verifying initial configuration intact...
$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -h $LOCALHOST -p $PORT1 -LLL | tr -d \\r >testrun/initial-config-recheck.ldif
diff testrun/initial-config-recheck.ldif testrun/initial-reference.ldif > /dev/null 2>&1
RC=$?
if test $RC != 0 ; then
echo "Initial configuration damaged by unsuccessful modifies."
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Dynamically removing legacy base...
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
delete: olcUniqueBase
EOF
RC=$?
if test $RC != 0 ; then
echo "base removal failed"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Verifying base removal...
$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -h $LOCALHOST -p $PORT1 -LLL | tr -d \\r >testrun/baseremoval-config.ldif
cat >testrun/baseremoval-reference.ldif <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
objectClass: olcOverlayConfig
objectClass: olcUniqueConfig
olcOverlay: {0}unique
olcUniqueAttribute: employeeNumber
olcUniqueAttribute: displayName
EOF
diff testrun/baseremoval-config.ldif testrun/baseremoval-reference.ldif > /dev/null 2>&1
RC=$?
if test $RC != 0 ; then
echo "Configuration damaged by base removal"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo "Adding a non-unique record..."
$LDAPADD -D "$UNIQUEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD > \
$TESTOUT 2>&1 << EOTUNIQ2
dn: uid=bill,ou=users,o=unique
objectClass: inetOrgPerson
uid: bill
sn: johnson
cn: bill
businessCategory: rtest
carLicense: ABC123
departmentNumber: 42
displayName: Bill
employeeNumber: 5150
employeeType: contractor
givenName: Bill
EOTUNIQ2
RC=$?
if test $RC != 19 ; then
echo "unique check failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Trying a legacy base outside of the backend...
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
add: olcUniqueBase
olcUniqueBase: cn=config
EOF
RC=$?
if test $RC != 80 ; then
echo "out of backend scope base allowed"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo "Adding and removing attrs..."
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
add: olcUniqueAttribute
olcUniqueAttribute: description
olcUniqueAttribute: telephoneNumber
-
delete: olcUniqueAttribute
olcUniqueAttribute: displayName
EOF
RC=$?
if test $RC != 0 ; then
echo "Unable to remove an attribute"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo "Verifying we removed the right attr..."
$LDAPADD -D "$UNIQUEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD > \
$TESTOUT 2>&1 << EOTUNIQ2
dn: uid=bill,ou=users,o=unique
......@@ -110,7 +279,66 @@ employeeNumber: 5150
employeeType: contractor
givenName: Bill
EOTUNIQ2
RC=$?
if test $RC != 19 ; then
echo "olcUniqueAttribtue single deletion hit the wrong value"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Removing legacy config and adding URIs...
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
delete: olcUniqueAttribute
-
add: olcUniqueURI
olcUniqueURI: ldap:///?employeeNumber,displayName?sub
olcUniqueURI: ldap:///?description?one
EOF
RC=$?
if test $RC != 0 ; then
echo "Reconfiguration to URIs failed"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Dynamically retrieving second configuration...
$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -h $LOCALHOST -p $PORT1 -LLL | tr -d \\r >testrun/second-config.ldif
cat >testrun/second-reference.ldif <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
objectClass: olcOverlayConfig
objectClass: olcUniqueConfig
olcOverlay: {0}unique
olcUniqueURI: ldap:///?employeeNumber,displayName?sub
olcUniqueURI: ldap:///?description?one
EOF
diff testrun/second-config.ldif testrun/second-reference.ldif > /dev/null 2>&1
RC=$?
if test $RC != 0 ; then
echo "Second configuration is not reported correctly."
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo "Adding a non-unique record..."
$LDAPADD -D "$UNIQUEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD > \
$TESTOUT 2>&1 << EOTUNIQ2
dn: uid=bill,ou=users,o=unique
objectClass: inetOrgPerson
uid: bill
sn: johnson
cn: bill
businessCategory: rtest
carLicense: ABC123
departmentNumber: 42
displayName: Bill
employeeNumber: 5150
employeeType: contractor
givenName: Bill
EOTUNIQ2
RC=$?
if test $RC != 19 ; then
echo "unique check failed ($RC)!"
......@@ -118,11 +346,222 @@ if test $RC != 19 ; then
exit -1
fi
echo Dynamically trying to add legacy base
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
add: olcUniqueBase
olcUniqueBase: o=unique
EOF
RC=$?
if test $RC != 80 ; then
echo "legacy base allowed with URIs"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Dynamically trying to add legacy attrs
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
add: olcUniqueAttribute
olcUniqueAttribute: description
EOF
RC=$?
if test $RC != 80 ; then
echo "legacy attributes allowed with URIs"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Dynamically trying to add legacy strictness
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
add: olcUniqueStrict
olcUniqueStrict: TRUE
EOF
RC=$?
if test $RC != 80 ; then
echo "legacy strictness allowed with URIs"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
#echo ----------------------
echo Dynamically trying a bad filter...
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
replace: olcUniqueURI
olcUniqueURI: ldap:///?sn?sub?((cn=e*))
EOF
RC=$?
if test $RC != 80 ; then
echo "bad filter allowed"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Verifying second configuration intact...
$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -h $LOCALHOST -p $PORT1 -LLL | tr -d \\r >testrun/second-config-recheck.ldif
diff testrun/second-config-recheck.ldif testrun/second-reference.ldif > /dev/null 2>&1
RC=$?
if test $RC != 0 ; then
echo "Second configuration damaged by rejected modifies."
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
#echo ----------------------
echo Dynamically reconfiguring to use different URIs...
$LDAPMODIFY -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF \
> $TESTOUT 2>&1 <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
changetype: modify
add: olcUniqueURI
olcUniqueURI: ldap:///?sn?sub?(cn=e*)
-
delete: olcUniqueURI
olcUniqueURI: ldap:///?description?one
EOF
RC=$?
if test $RC != 0 ; then
echo "unable to reconfigure"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo Dynamically retrieving third configuration...
$LDAPSEARCH -S "" -b olcOverlay='{0}'unique,olcDatabase='{1}'$BACKEND,cn=config -D cn=config -y $CONFIGPWF -h $LOCALHOST -p $PORT1 -LLL | tr -d \\r >testrun/third-config.ldif
cat >testrun/third-reference.ldif <<EOF
dn: olcOverlay={0}unique,olcDatabase={1}$BACKEND,cn=config
objectClass: olcOverlayConfig
objectClass: olcUniqueConfig
olcOverlay: {0}unique
olcUniqueURI: ldap:///?employeeNumber,displayName?sub
olcUniqueURI: ldap:///?sn?sub?(cn=e*)
EOF
diff testrun/third-config.ldif testrun/third-reference.ldif > /dev/null 2>&1
RC=$?
if test $RC != 0 ; then
echo "Third configuration is not reported correctly."
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo "Adding a record unique in both domains if filtered..."
$LDAPADD -D "$UNIQUEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD > \
$TESTOUT 2>&1 << EOF
dn: uid=edgar,ou=users,o=unique
objectClass: inetOrgPerson
uid: edgar
sn: johnson
cn: edgar
EOF
RC=$?
if test $RC != 0 ; then
echo "unique check failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit -1
fi
echo "Adding a record unique in one domain, non-unique in the filtered domain..."
$LDAPADD -D "$UNIQUEDN" -h $LOCALHOST -p $PORT1 -w $PASSWD > \
$TESTOUT 2>&1 << EOF
dn: uid=elvis,ou=users,o=unique
objectClass: inetOrgPerson
uid: elvis
sn: johnson
cn: elvis
EOF
RC=$?