mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-03-31 14:50:34 +08:00
ITS#10160 - Add "neguri" and "negset" constraint types to slapo-constraint
This commit is contained in:
parent
429556c5f6
commit
068881efb4
@ -35,14 +35,16 @@ directive.
|
||||
.B constraint_attribute <attribute_name>[,...] <type> <value> [<extra> [...]]
|
||||
Specifies the constraint which should apply to the comma-separated
|
||||
attribute list named as the first parameter.
|
||||
Six types of constraint are currently supported -
|
||||
Eight types of constraint are currently supported -
|
||||
.BR regex ,
|
||||
.BR negregex ,
|
||||
.BR size ,
|
||||
.BR count ,
|
||||
.BR uri ,
|
||||
.BR neguri ,
|
||||
.BR set ,
|
||||
and
|
||||
.BR set .
|
||||
.BR negset .
|
||||
|
||||
The parameter following the
|
||||
.B regex
|
||||
@ -52,12 +54,16 @@ type is a Unix style regular expression (See
|
||||
.BR regex (7)
|
||||
). The parameter following the
|
||||
.B uri
|
||||
or
|
||||
.B neguri
|
||||
type is an LDAP URI. The URI will be evaluated using an internal search.
|
||||
It must not include a hostname, and it must include a list of attributes
|
||||
to evaluate.
|
||||
|
||||
The parameter following the
|
||||
.B set
|
||||
or
|
||||
.B negset
|
||||
type is a string that is interpreted according to the syntax in use
|
||||
for ACL sets. This allows one to construct constraints based on the contents
|
||||
of the entry.
|
||||
@ -110,6 +116,8 @@ constraint_attribute mail regex ^[[:alnum:]]+@mydomain.com$
|
||||
constraint_attribute mail negregex ^[[:alnum:]]+@notallowed.com$
|
||||
constraint_attribute title uri
|
||||
ldap:///dc=catalog,dc=example,dc=com?title?sub?(objectClass=titleCatalog)
|
||||
constraint_attribute cn neguri
|
||||
ldap:///ou=People,dc=example,dc=com?cn,sn?sub?(objectClass=inetOrgPerson)
|
||||
constraint_attribute cn,sn,givenName set
|
||||
"(this/givenName + [ ] + this/sn) & this/cn"
|
||||
restrict="ldap:///ou=People,dc=example,dc=com??sub?(objectClass=inetOrgPerson)"
|
||||
@ -133,6 +141,22 @@ entries in the given scope. (Note that the
|
||||
in a separate database, otherwise the initial set of
|
||||
titleCatalog entries could not be populated while the
|
||||
constraint is in effect.)
|
||||
With the type "neguri" (negated "uri"), it would
|
||||
ensure uniqueness of one (or more) attributes against one (or
|
||||
more) other attributes. A specification like the above
|
||||
would reject any
|
||||
.B cn
|
||||
attributes whose
|
||||
.B any
|
||||
values
|
||||
.B was already listed
|
||||
in another
|
||||
.B cn
|
||||
or
|
||||
.B sn
|
||||
attributes of any
|
||||
.B inetOrgPerson
|
||||
entries in the given scope.
|
||||
Finally, it requires the values of the attribute
|
||||
.B cn
|
||||
to be constructed by pairing values of the attributes
|
||||
@ -141,6 +165,8 @@ and
|
||||
.BR givenName ,
|
||||
separated by a space, but only for entries derived from the objectClass
|
||||
.BR inetOrgPerson .
|
||||
Should the type "negset" have been used instead of "set", the
|
||||
condition would have been reversed.
|
||||
.RE
|
||||
.SH FILES
|
||||
.TP
|
||||
|
@ -42,7 +42,9 @@
|
||||
#define REGEX_STR "regex"
|
||||
#define NEG_REGEX_STR "negregex"
|
||||
#define URI_STR "uri"
|
||||
#define NEG_URI_STR "neguri"
|
||||
#define SET_STR "set"
|
||||
#define NEG_SET_STR "negset"
|
||||
#define SIZE_STR "size"
|
||||
#define COUNT_STR "count"
|
||||
|
||||
@ -82,13 +84,15 @@ enum {
|
||||
CONSTRAINT_REGEX,
|
||||
CONSTRAINT_NEG_REGEX,
|
||||
CONSTRAINT_SET,
|
||||
CONSTRAINT_NEG_SET,
|
||||
CONSTRAINT_URI,
|
||||
CONSTRAINT_NEG_URI,
|
||||
};
|
||||
|
||||
static ConfigDriver constraint_cf_gen;
|
||||
|
||||
static ConfigTable constraintcfg[] = {
|
||||
{ "constraint_attribute", "attribute[list]> (regex|negregex|uri|set|size|count) <value> [<restrict URI>]",
|
||||
{ "constraint_attribute", "attribute[list]> (regex|negregex|uri|neguri|set|negset|size|count) <value> [<restrict URI>]",
|
||||
4, 0, 0, ARG_MAGIC | CONSTRAINT_ATTRIBUTE, constraint_cf_gen,
|
||||
"( OLcfgOvAt:13.1 NAME 'olcConstraintAttribute' "
|
||||
"DESC 'constraint for list of attributes' "
|
||||
@ -187,10 +191,18 @@ constraint_cf_gen( ConfigArgs *c )
|
||||
tstr = SET_STR;
|
||||
quotes = 1;
|
||||
break;
|
||||
case CONSTRAINT_NEG_SET:
|
||||
tstr = NEG_SET_STR;
|
||||
quotes = 1;
|
||||
break;
|
||||
case CONSTRAINT_URI:
|
||||
tstr = URI_STR;
|
||||
quotes = 1;
|
||||
break;
|
||||
case CONSTRAINT_NEG_URI:
|
||||
tstr = NEG_URI_STR;
|
||||
quotes = 1;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@ -339,10 +351,10 @@ constraint_cf_gen( ConfigArgs *c )
|
||||
ap.count = strtoull(c->argv[3], &endptr, 10);
|
||||
if ( *endptr )
|
||||
rc = ARG_BAD_CONF;
|
||||
} else if ( strcasecmp( c->argv[2], URI_STR ) == 0 ) {
|
||||
} else if ( strcasecmp( c->argv[2], URI_STR ) == 0 || strcasecmp( c->argv[2], NEG_URI_STR ) == 0 ) {
|
||||
int err;
|
||||
|
||||
ap.type = CONSTRAINT_URI;
|
||||
ap.type = strcasecmp( c->argv[2], URI_STR ) == 0 ? CONSTRAINT_URI : CONSTRAINT_NEG_URI;
|
||||
err = ldap_url_parse(c->argv[3], &ap.lud);
|
||||
if ( err != LDAP_URL_SUCCESS ) {
|
||||
snprintf( c->cr_msg, sizeof( c->cr_msg ),
|
||||
@ -421,6 +433,11 @@ constraint_cf_gen( ConfigArgs *c )
|
||||
ber_str2bv( c->argv[3], 0, 1, &ap.val );
|
||||
ap.type = CONSTRAINT_SET;
|
||||
|
||||
} else if ( strcasecmp( c->argv[2], NEG_SET_STR ) == 0 ) {
|
||||
ap.set = 1;
|
||||
ber_str2bv( c->argv[3], 0, 1, &ap.val );
|
||||
ap.type = CONSTRAINT_NEG_SET;
|
||||
|
||||
} else {
|
||||
snprintf( c->cr_msg, sizeof( c->cr_msg ),
|
||||
"%s %s: Unknown constraint type: %s",
|
||||
@ -616,7 +633,9 @@ constraint_violation( constraint *c, struct berval *bv, Operation *op )
|
||||
if (regexec(c->re, bv->bv_val, 0, NULL, 0) != REG_NOMATCH)
|
||||
return LDAP_CONSTRAINT_VIOLATION; /* regular expression violation */
|
||||
break;
|
||||
case CONSTRAINT_URI: {
|
||||
case CONSTRAINT_URI: /* fallthrough */
|
||||
case CONSTRAINT_NEG_URI:
|
||||
{
|
||||
Operation nop = *op;
|
||||
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
|
||||
slap_callback cb = { 0 };
|
||||
@ -719,7 +738,7 @@ constraint_violation( constraint *c, struct berval *bv, Operation *op )
|
||||
return rc; /* unexpected error */
|
||||
}
|
||||
|
||||
if (!found)
|
||||
if (found ^ c->type == CONSTRAINT_URI)
|
||||
return LDAP_CONSTRAINT_VIOLATION; /* constraint violation */
|
||||
break;
|
||||
}
|
||||
@ -858,6 +877,10 @@ constraint_add( Operation *op, SlapReply *rs )
|
||||
if (acl_match_set(&cp->val, op, op->ora_e, NULL) == 0)
|
||||
rc = LDAP_CONSTRAINT_VIOLATION;
|
||||
break;
|
||||
case CONSTRAINT_NEG_SET:
|
||||
if (acl_match_set(&cp->val, op, op->ora_e, NULL) != 0)
|
||||
rc = LDAP_CONSTRAINT_VIOLATION;
|
||||
break;
|
||||
default:
|
||||
for ( i = 0; b[i].bv_val; i++ ) {
|
||||
rc = constraint_violation( cp, &b[i], op );
|
||||
@ -1051,7 +1074,7 @@ constraint_update( Operation *op, SlapReply *rs )
|
||||
}
|
||||
}
|
||||
|
||||
if (cp->type == CONSTRAINT_SET && target_entry) {
|
||||
if ((cp->type == CONSTRAINT_SET || cp->type == CONSTRAINT_NEG_SET) && target_entry) {
|
||||
if (target_entry_copy == NULL) {
|
||||
Modifications *ml;
|
||||
|
||||
@ -1145,7 +1168,7 @@ constraint_update( Operation *op, SlapReply *rs )
|
||||
}
|
||||
}
|
||||
|
||||
if ( acl_match_set(&cp->val, op, target_entry_copy, NULL) == 0) {
|
||||
if ((acl_match_set(&cp->val, op, target_entry_copy, NULL) == 1) ^ (cp->type == CONSTRAINT_SET)) {
|
||||
rc = LDAP_CONSTRAINT_VIOLATION;
|
||||
goto mod_violation;
|
||||
}
|
||||
|
@ -29,3 +29,7 @@ FAIL
|
||||
FAIL
|
||||
FAIL
|
||||
FAIL
|
||||
OK
|
||||
FAIL
|
||||
FAIL
|
||||
FAIL
|
||||
|
@ -8,6 +8,10 @@ dn: ou=users,dc=example,dc=com
|
||||
ou: users
|
||||
objectclass: organizationalUnit
|
||||
|
||||
dn: ou=users2,dc=example,dc=com
|
||||
ou: users2
|
||||
objectclass: organizationalUnit
|
||||
|
||||
dn: ou=groups,dc=example,dc=com
|
||||
ou: groups
|
||||
objectclass: organizationalUnit
|
||||
|
4
tests/data/constraint/tn_fail_01.ldif
Normal file
4
tests/data/constraint/tn_fail_01.ldif
Normal file
@ -0,0 +1,4 @@
|
||||
dn: givenName=John,ou=users2,dc=example,dc=com
|
||||
changetype: modify
|
||||
replace: cn
|
||||
cn: John Rouge
|
4
tests/data/constraint/tn_fail_02.ldif
Normal file
4
tests/data/constraint/tn_fail_02.ldif
Normal file
@ -0,0 +1,4 @@
|
||||
dn: givenName=John,ou=users2,dc=example,dc=com
|
||||
changetype: modify
|
||||
replace: sn
|
||||
sn: le Rouge
|
4
tests/data/constraint/tn_fail_03.ldif
Normal file
4
tests/data/constraint/tn_fail_03.ldif
Normal file
@ -0,0 +1,4 @@
|
||||
dn: givenName=John,ou=users2,dc=example,dc=com
|
||||
changetype: modify
|
||||
replace: uid
|
||||
uid: 1
|
4
tests/data/constraint/tn_ok_01.ldif
Normal file
4
tests/data/constraint/tn_ok_01.ldif
Normal file
@ -0,0 +1,4 @@
|
||||
dn: givenName=John,ou=users2,dc=example,dc=com
|
||||
changetype: modify
|
||||
replace: uid
|
||||
uid: 4
|
10
tests/data/constraint/user2.ldif
Normal file
10
tests/data/constraint/user2.ldif
Normal file
@ -0,0 +1,10 @@
|
||||
dn: givenName=John,ou=users2,dc=example,dc=com
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: organizationalPerson
|
||||
cn: John le Rouge
|
||||
givenname: John
|
||||
sn: Rouge
|
||||
mail: original@example.com
|
||||
description: desc1
|
||||
description: desc2
|
||||
uid: 3
|
@ -24,9 +24,11 @@ fi
|
||||
CONSTRAINTDIR="$DATADIR/constraint"
|
||||
ROOTLDIF="$CONSTRAINTDIR/root.ldif"
|
||||
USERLDIF="$CONSTRAINTDIR/user.ldif"
|
||||
USER2LDIF="$CONSTRAINTDIR/user2.ldif"
|
||||
RESULTOUT="$CONSTRAINTDIR/constraint.out"
|
||||
SCRIPTOUT="$TESTDIR/constraint.out"
|
||||
USERDN="cn=John Doe,ou=users,$BASEDN"
|
||||
USER2DN="givenName=John,ou=users2,$BASEDN"
|
||||
|
||||
CONFDIR=$TESTDIR/slapd.d
|
||||
mkdir -p $TESTDIR $CONFDIR $DBDIR1
|
||||
@ -117,6 +119,12 @@ olcConstraintAttribute: cn,sn,givenName
|
||||
olcConstraintAttribute: uid
|
||||
uri "ldap:///ou=groups,$BASEDN?uid?one?(objectClass=inetOrgPerson)"
|
||||
restrict="ldap:///ou=users,$BASEDN??one"
|
||||
olcConstraintAttribute: cn,sn,givenName
|
||||
negset "(this/givenName + [ ] + this/sn) & this/cn"
|
||||
restrict="ldap:///$USER2DN??sub?(objectClass=inetOrgPerson)"
|
||||
olcConstraintAttribute: uid
|
||||
neguri "ldap:///ou=groups,$BASEDN?uid?one?(objectClass=inetOrgPerson)"
|
||||
restrict="ldap:///ou=users2,$BASEDN??one"
|
||||
EOF
|
||||
|
||||
$SLAPADD -F $CONFDIR -n 0 -l $TESTDIR/config.ldif
|
||||
@ -168,9 +176,16 @@ if test $RC != 0 ; then
|
||||
test $KILLSERVERS != no && kill -HUP $PID
|
||||
exit $RC
|
||||
fi
|
||||
$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $USER2LDIF >/dev/null 2>&1
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapadd failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $PID
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
echo "Running constraint tests..."
|
||||
for ldif in $CONSTRAINTDIR/*ok*.ldif $CONSTRAINTDIR/*fail*.ldif; do
|
||||
for ldif in $CONSTRAINTDIR/t_ok*.ldif $CONSTRAINTDIR/t_fail*.ldif; do
|
||||
### reload
|
||||
$LDAPDELETE -D "$MANAGERDN" -H $URI1 -w $PASSWD "$USERDN" >/dev/null 2>&1
|
||||
RC=$?
|
||||
@ -202,6 +217,39 @@ for ldif in $CONSTRAINTDIR/*ok*.ldif $CONSTRAINTDIR/*fail*.ldif; do
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Running *neg* constraint tests..."
|
||||
for ldif in $CONSTRAINTDIR/tn_ok*.ldif $CONSTRAINTDIR/tn_fail*.ldif; do
|
||||
### reload
|
||||
$LDAPDELETE -D "$MANAGERDN" -H $URI1 -w $PASSWD "$USER2DN" >/dev/null 2>&1
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapdelete failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $PID
|
||||
exit $RC
|
||||
fi
|
||||
$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $USER2LDIF >/dev/null 2>&1
|
||||
RC=$?
|
||||
if test $RC != 0 ; then
|
||||
echo "ldapadd failed ($RC)!"
|
||||
test $KILLSERVERS != no && kill -HUP $PID
|
||||
exit $RC
|
||||
fi
|
||||
|
||||
### info
|
||||
echo -n " [$ldif]: "
|
||||
|
||||
### modify
|
||||
$LDAPMODIFY -H $URI1 -x -D "$MANAGERDN" -f $ldif -w $PASSWD >/dev/null 2>&1
|
||||
RC=$?
|
||||
if test $RC = 0 ; then
|
||||
echo "OK" | tee -a $SCRIPTOUT
|
||||
elif test $RC = 19 ; then
|
||||
echo "FAIL" | tee -a $SCRIPTOUT
|
||||
else
|
||||
echo "UNEXPECTED ($RC)"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Comparing output..."
|
||||
$DIFF $SCRIPTOUT $RESULTOUT > $CMPOUT
|
||||
RC=$?
|
||||
|
Loading…
x
Reference in New Issue
Block a user