Issue 6916 - slapo-unique returns operations error when assertion control is used
Summary: slapo-unique returns operations error when assertion control is used
Status: VERIFIED FIXED
Alias: None
Product: OpenLDAP
Classification: Unclassified
Component: overlays (show other issues)
Version: 2.4.25
Hardware: All All
: Normal normal
Target Milestone: 2.6.0
Assignee: Howard Chu
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-04-26 17:18 UTC by Michael Ströder
Modified: 2021-10-25 22:07 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Michael Ströder 2011-04-26 17:18:41 UTC
Full_Name: Michael Str��der
Version: 2.4.25
OS: openSUSE Linux
URL: 
Submission from: (NULL) (195.145.144.134)


If an assertion control is sent along with a modify request slapo-unique returns
operation error with diagnostic message "unique_search failed" instead of
returning constraint violation.
Comment 1 Michael Ströder 2011-04-26 18:24:22 UTC
Further observations show that...

1. processing add requests seems to behave like expected.

2. it depends on the assertion filter sent in the control value:

$ ldapmodify -H ldap://localhost -D "uid=Mstroeder,dc=stroeder,dc=de" -W -f
uidnumber_clash.ldif -e 'assert=(cn=*)'
modifying entry "uid=ttester,dc=stroeder,dc=de"
ldap_modify: Operations error (1)
	additional info: unique_search failed

$ ldapmodify -H ldap://localhost -D "uid=Mstroeder,dc=stroeder,dc=de" -W -f
uidnumber_clash.ldif -e 'assert=(objectClass=*)'
modifying entry "uid=ttester,dc=stroeder,dc=de"
ldap_modify: Constraint violation (19)
	additional info: some attributes not unique


Comment 2 Michael Ströder 2011-04-28 16:50:45 UTC
Note that with assertion control always
Operations error: "unique_search failed"
is returned even if the attribute values are unique.

I'd really like to get this solved. web2ldap makes use of the assertion
control to ensure that an entry has not been changed since being edited by the
user. Otherwise I have to implement another vendor-specific hack switching off
this feature when OpenLDAP is used as server. :-(

Ciao, Michael.

michael@stroeder.com wrote:
> Further observations show that...
> 
> 1. processing add requests seems to behave like expected.
> 
> 2. it depends on the assertion filter sent in the control value:
> 
> $ ldapmodify -H ldap://localhost -D "uid=Mstroeder,dc=stroeder,dc=de" -W -f
> uidnumber_clash.ldif -e 'assert=(cn=*)'
> modifying entry "uid=ttester,dc=stroeder,dc=de"
> ldap_modify: Operations error (1)
> 	additional info: unique_search failed
> 
> $ ldapmodify -H ldap://localhost -D "uid=Mstroeder,dc=stroeder,dc=de" -W -f
> uidnumber_clash.ldif -e 'assert=(objectClass=*)'
> modifying entry "uid=ttester,dc=stroeder,dc=de"
> ldap_modify: Constraint violation (19)
> 	additional info: some attributes not unique

Comment 3 Howard Chu 2011-04-28 22:21:43 UTC
michael@stroeder.com wrote:
> Note that with assertion control always
> Operations error: "unique_search failed"
> is returned even if the attribute values are unique.
>
> I'd really like to get this solved. web2ldap makes use of the assertion
> control to ensure that an entry has not been changed since being edited by the
> user. Otherwise I have to implement another vendor-specific hack switching off
> this feature when OpenLDAP is used as server. :-(

First step toward a solution would be providing slapd -d output for the 
problem. Probably a sample config would help too.

> Ciao, Michael.
>
> michael@stroeder.com wrote:
>> Further observations show that...
>>
>> 1. processing add requests seems to behave like expected.
>>
>> 2. it depends on the assertion filter sent in the control value:
>>
>> $ ldapmodify -H ldap://localhost -D "uid=Mstroeder,dc=stroeder,dc=de" -W -f
>> uidnumber_clash.ldif -e 'assert=(cn=*)'
>> modifying entry "uid=ttester,dc=stroeder,dc=de"
>> ldap_modify: Operations error (1)
>> 	additional info: unique_search failed
>>
>> $ ldapmodify -H ldap://localhost -D "uid=Mstroeder,dc=stroeder,dc=de" -W -f
>> uidnumber_clash.ldif -e 'assert=(objectClass=*)'
>> modifying entry "uid=ttester,dc=stroeder,dc=de"
>> ldap_modify: Constraint violation (19)
>> 	additional info: some attributes not unique
>
>
>


-- 
   -- Howard Chu
   CTO, Symas Corp.           http://www.symas.com
   Director, Highland Sun     http://highlandsun.com/hyc/
   Chief Architect, OpenLDAP  http://www.openldap.org/project/

Comment 4 Michael Ströder 2011-04-29 09:45:28 UTC
Howard Chu wrote:
> michael@stroeder.com wrote:
>> Note that with assertion control always
>> Operations error: "unique_search failed"
>> is returned even if the attribute values are unique.
>>
>> I'd really like to get this solved. web2ldap makes use of the assertion
>> control to ensure that an entry has not been changed since being
>> edited by the
>> user. Otherwise I have to implement another vendor-specific hack
>> switching off
>> this feature when OpenLDAP is used as server. :-(
> 
> First step toward a solution would be providing slapd -d output for the
> problem. Probably a sample config would help too.

(Sigh! Did anybody actually read through my report?)

Take any slapd.conf with database hdb and add these lines (no other overlays
configured):

overlay unique
unique_attributes uid uidNumber employeeNumber

Or any other LDAP-URL-based unique constraint...

Then apply a LDIF change record (example below) which contains any of the
attributes defined as unique (no matter whether unique constraint is violated
or not).

------------------------------- snip -------------------------------
dn: cn=Anna Blume,ou=Users,ou=schulung,dc=stroeder,dc=local
changetype: modify
replace: employeeNumber
employeeNumber: 456
-

------------------------------- snip -------------------------------

Try these commands (bind-DN is the rootdn here):

Without assertion control it works:
$ ldapmodify -H ldap://localhost:2071 -D
"uid=diradm,ou=schulung,dc=stroeder,dc=local" -w testsecret -f unique.ldif
modifying entry "cn=Anna Blume,ou=Users,ou=schulung,dc=stroeder,dc=local"

Assertion control just contains objectClass filter:
$ ldapmodify -H ldap://localhost:2071 -D
"uid=diradm,ou=schulung,dc=stroeder,dc=local" -w testsecret -f unique.ldif -e
'assert=(objectClass=*)'
modifying entry "cn=Anna Blume,ou=Users,ou=schulung,dc=stroeder,dc=local"

This fails:
$ ldapmodify -H ldap://localhost:2071 -D
"uid=diradm,ou=schulung,dc=stroeder,dc=local" -w testsecret -f unique.ldif -e
'assert=(cn=*)'modifying entry "cn=Anna
Blume,ou=Users,ou=schulung,dc=stroeder,dc=local"
ldap_modify: Operations error (1)
	additional info: unique_search failed


Output of slapd -d config,stats,stats2,acl,args,trace,sync:

------------------------------- snip -------------------------------
[..]
conn=1000 op=1 modifications:
	replace: employeeNumber
		one value, length 3
conn=1000 op=1 MOD dn="cn=Anna Blume,ou=Users,ou=schulung,dc=stroeder,dc=local"
conn=1000 op=1 MOD attr=employeeNumber
bdb_dn2entry("cn=anna blume,ou=users,ou=schulung,dc=stroeder,dc=local")
=> hdb_dn2id("ou=users,ou=schulung,dc=stroeder,dc=local")
<= hdb_dn2id: got id=0x6
=> hdb_dn2id("cn=anna blume,ou=users,ou=schulung,dc=stroeder,dc=local")
<= hdb_dn2id: got id=0xd
entry_decode: ""
<= entry_decode()
==> unique_modify <cn=Anna Blume,ou=Users,ou=schulung,dc=stroeder,dc=local>
==> unique_search (|(employeeNumber=456))
put_filter: "(|(employeeNumber=456))"
put_filter: OR
put_filter_list "(employeeNumber=456)"
put_filter: "(employeeNumber=456)"
put_filter: simple
put_simple_filter: "employeeNumber=456"
ber_scanf fmt ({mm}) ber:
=> hdb_search
bdb_dn2entry("ou=schulung,dc=stroeder,dc=local")
=> access_allowed: search access to "ou=schulung,dc=stroeder,dc=local" "entry"
requested
<= root access granted
=> access_allowed: search access granted by manage(=mwrscxd)
=> access_allowed: search access to "ou=schulung,dc=stroeder,dc=local" "cn"
requested
<= root access granted
=> access_allowed: search access granted by manage(=mwrscxd)
send_ldap_result: conn=1000 op=1 p=3
send_ldap_result: err=122 matched="" text=""
send_ldap_result: conn=1000 op=1 p=3
send_ldap_result: err=1 matched="" text="unique_search failed"
send_ldap_response: msgid=2 tag=103 err=1
ber_flush2: 34 bytes to sd 16
conn=1000 op=1 RESULT tag=103 err=1 text=unique_search failed
connection_get(16)
connection_get(16): got connid=1000
connection_read(16): checking for input on id=1000
ber_get_next
ber_get_next: tag 0x30 len 5 contents:
op tag 0x42, time 1304069972
ber_get_next
ber_get_next on fd 16 failed errno=0 (Success)
conn=1000 op=2 do_unbind
conn=1000 op=2 UNBIND
connection_close: conn=1000 sd=16
conn=1000 fd=16 closed
------------------------------- snip -------------------------------

Comment 5 Michael Ströder 2011-06-05 14:27:21 UTC
Sad enough I had to turn off using the assertion control in upcoming web2ldap 
release as yet another vendor-specific workaround - this time for OpenLDAP...

It works with OpenDS and OpenDJ and web2ldap uses it with these servers.

Comment 6 ando@openldap.org 2011-06-07 22:24:19 UTC
The problem seems to be that unique_modify() calls unique_search() passing
it an Operation that contains the assertion, which fails within the
search.  The failure is propagated back to the modification.  The
assertion control should not apply to internal operations performed by the
unique overlay.  The solution to me is not straightforward, apart from
explicitly removing the assert control when calling unique_search().  I
understand this solution is by no means general; similar problems may
surface in other overlays and with other controls.

p.

Comment 7 ando@openldap.org 2011-06-07 22:26:35 UTC
changed notes
moved from Incoming to Software Bugs
Comment 8 OpenLDAP project 2014-08-01 21:04:36 UTC
internal ops should not use assertion control
Comment 9 Johannes Kanefendt 2016-01-12 16:00:33 UTC
A workaround is to extend the assertion filter to match all other entries 
except the one to be modified:

(|(cn=*)(!(entryDN=cn=Anna 
Blume,ou=Users,ou=schulung,dc=stroeder,dc=local)))
--
Mit freundlichem Gruß
Im Auftrag

Johannes Kanefendt

Kommunales Rechenzentrum Niederrhein
Der Verbandsvorsteher
Abteilung 2.3.2 - Schulen Online
Friedrich-Heinrich-Allee 130
47475 Kamp-Lintfort -Germany-

Telefon: +49 (0)2842 90 70 125
Web: www.krzn.de
Email: Johannes.Kanefendt@krzn.de
Comment 10 Michael Ströder 2016-01-12 19:13:15 UTC
Johannes.Kanefendt@krzn.de wrote:
> A workaround is to extend the assertion filter to match all other entries
> except the one to be modified:
> 
> (|(cn=*)(!(entryDN=cn=Anna\20Blume,ou=Users,ou=schulung,dc=stroeder,dc=local)))

The whole purpose of using the Assertion Control is that it should match the
modified entry. When I construct a filter deliberately not matching the entry I
can simply omit the Assertion Control completely.

Maybe I didn't get your idea though.

The use-case: My web2ldap sends Assertion Control along with a modify request
with a filter constructed from all attributes considered to be not modified by
another user:

(&(entryCSN=20160112183104\2e449732Z\23000000\23000\23000000)(creatorsName=cn=michael\20str\c3\b6der\2bmail=michael@stroeder\2ecom\2cou=private\2cdc=stroeder\2cdc=de)(entryUUID=1c66859e\2d3441\2d1034\2d93db\2d751297a711ee)(modifiersName=cn=michael\20str\c3\b6der\2bmail=michael@stroeder\2ecom\2cou=private\2cdc=stroeder\2cdc=de)(createTimestamp=20150119160811Z)(entryDN=ou=test\2cou=Testing\2cdc=stroeder\2cdc=de)(modifyTimestamp=20160112183104Z))

This is done to really ensure that the entry was *not* changed after being read
into the input form the user edits.

Ciao, Michael.

Comment 11 Johannes Kanefendt 2016-01-13 08:02:31 UTC
Michael Ströder <michael@stroeder.com> schrieb am 12.01.2016 20:13:15:

> The whole purpose of using the Assertion Control is that it should match 
the
> modified entry. When I construct a filter deliberately not matching 
> the entry I
> can simply omit the Assertion Control completely.

The logical outcome of the assertion doesn't change as the actual 
assertion filter is or-ed with a rule that will never match the targeted 
entry. However, when (wrongly) passed to unique_search, it will prevent a 
failure as all other entries than the target match.

> 
> Maybe I didn't get your idea though.
> 
> The use-case: My web2ldap sends Assertion Control along with a modify 
request
> with a filter constructed from all attributes considered to be not 
modified by
> another user:
> 
> (&(entryCSN=20160112183104\2e449732Z\23000000\23000\23000000)
> (creatorsName=cn=michael\20str\c3\b6der\2bmail=michael@stroeder
> \2ecom\2cou=private\2cdc=stroeder\2cdc=de)(entryUUID=1c66859e\2d3441
> \2d1034\2d93db\2d751297a711ee)(modifiersName=cn=michael\20str\c3
> \b6der\2bmail=michael@stroeder\2ecom\2cou=private\2cdc=stroeder
> \2cdc=de)(createTimestamp=20150119160811Z)(entryDN=ou=test
> \2cou=Testing\2cdc=stroeder\2cdc=de)(modifyTimestamp=20160112183104Z))
> 

Try to enclose the assertion by 
(|(...)(!(entryDN=ou=test,ou=Testing,dc=stroeder,dc=de))) or 
(|(...)(!(entryUUID=1c66859e-34411034-93db-751297a711ee)))
Comment 12 Howard Chu 2021-07-20 16:55:08 UTC
fixed in master
Comment 13 Quanah Gibson-Mount 2021-07-22 16:29:57 UTC
Commits: 
  • 4bd6a6d4 
by Howard Chu at 2021-07-20T17:54:26+01:00 
ITS#6916 unique: internal ops shouldn't have user's controls