#3218 [RFE] ad_access_filter should ignore what happens after the first open paren
Closed: Fixed None Opened 7 years ago by mikeely.

In their documentation, Microsoft supports nested group query via LDAP using particular OIDs:
https://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx

However, when attempting to use this format in ad_access_filter, the parser fails and the filter is skipped:

From sssd.conf:
ad_access_filter = (&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org)(unixHomeDirectory=*))

From log at debug_level = 8:
Keyword in filter [(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org)(unixHomeDirectory=))] did not match expected format
(Wed Oct 12 11:01:29 2016) [sssd[be[ad.example.org]]] [ad_parse_access_filter] (0x0080): Access filter [(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org)(unixHomeDirectory=
))] could not be parsed, skipping

This RFE requests that the use of OID :1.2.840.113556.1.4.1941: be supported for AD nested group lookups using ad_access_filter. This will avoid the need to use simple for such cases.


Yes, looks like a bug in parsing the filter. But what sssd does in this case is actually very simple -- it just runs this search against the user entry. Did you try from the command line if using this filter anded with samaccount name of the user would match?

Also, what is the reason to use the AD provider and either not the simple access provider or GPOs?

what is the reason to use the AD provider and either not the simple access provider or GPOs?
Better flexibility, mostly. Rather than put the work on our AD folks to make the domain fit the needs of the LDAP search, it'd be preferable to do the work on the search query end.

Did you try from the command line if using this filter anded with samaccount name of the user would match?
Yes, I tested using ldapsearch and the filter works as expected (and omitting the OID produces a "no match" also as expected).

_comment0: > what is the reason to use the AD provider and either not the simple access provider or GPOs?
Better flexibility, mostly. Rather than put the work on our AD folks to make the domain fit the needs of the search engine, it'd be preferable to do the work on the search query end.

Did you try from the command line if using this filter anded with samaccount name of the user would match?
Yes, I tested using ldapsearch and the filter works as expected (and omitting the filter produces a "no match" also as expected). => 1476303317626525
_comment1: > what is the reason to use the AD provider and either not the simple access provider or GPOs?
Better flexibility, mostly. Rather than put the work on our AD folks to make the domain fit the needs of the LDAP search, it'd be preferable to do the work on the search query end.

Did you try from the command line if using this filter anded with samaccount name of the user would match?
Yes, I tested using ldapsearch and the filter works as expected (and omitting the filter produces a "no match" also as expected). => 1476303390085001

As a workaround you can try to specific the domain or forest where this filter should be valid, e.g.

DOM:ad.example.org:(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org)(unixHomeDirectory=*))

HTH

bye,
Sumit

Sumit also suggested to only parse the sssd-specific filter prefix taking opening braces into account.

milestone: NEEDS_TRIAGE => SSSD Patches welcome

Fields changed

cc: => sbose

I tried with the DOM:ad.example.org: format but the error was now "Malformed search filter." The parser really doesn't like the OID.

Will start digging through sssd code to find the parser.

_comment0: I tried with the DOM=ad.example.org: format but the error was identical. The parser really doesn't like the OID.

Will start digging through sssd code to find the parser. => 1476386423345429

Found the root cause, I think.

src/providers/ad/ad_access.c:112:
kwdelim = strchr(full_filter, ':');

Then at 140:
"Keyword in filter [%s] did not match expected format\n",

This is setting up the delimiter for the special dom: and DOM:dom: etc prefixes to the search filter. So basically the format of the OID surrounded as it is by colons is confusing the parser.

The solution would seem to be to test to see if the delimiter text (a colon) is within or without parentheses and ignore when the delimiter is inside parens:

text:(blahblah) <- colon is parsed as a delimiter

(blah:blah:blah) <- colon is ignored by the parser

text:text:(blah:blah) <- only the colons outside the parens are parsed

I'd happily propose a patch but my C is not usable.

_comment0: Found the root cause, I think.

src/providers/ad/ad_access.c:112:
kwdelim = strchr(full_filter, ':');

Then at 140:
"Keyword in filter [%s] did not match expected format\n",

This is setting up the delimiter for the special dom: and DOM:dom: etc prefixes to the search filter. So basically the format of the OID surrounded as it is by colons is confusing the parser.

The solution would seem to be to test to see if the delimiter text (a colon) is within or without parentheses and ignore when the delimiter is inside parens:

text:(blahblah) <- colon is parsed as a delimiter
(blah:blah:blah) <- colon is ignored by the parser
text:text:(blah:blah) <- only the colons outside the parens are parsed

I'd happily propose a patch but my C is not usable. => 1476386889511302

Replying to [comment:6 mikeely]:

I tried with the DOM:ad.example.org: format but the error was now "Malformed search filter." The parser really doesn't like the OID.

This error is generated by the ldap_search_ext() call. Can you check in the logs how does the search filter looks at this point?

Sure.

First, here's the filter in question:

ad_access_filter = DOM:ad.example.org:(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org)

[[BR]]

Here's an example log output from a failed auth using that filter:

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_get_generic_ext_step] (0x0400): calling ldap_search_ext with [(&(sAMAccountName=ad.user)(objectclass=user)(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org))][CN=Example User,OU=Local Users,DC=ad,DC=example,DC=org].

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_get_generic_ext_step] (0x0080): ldap_search_ext failed: Bad search filter

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [generic_ext_search_handler] (0x0040): sdap_get_generic_ext_recv failed [1432158239]: Malformed search filter

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_access_filter_done] (0x0020): Malformed access control filter [(&(sAMAccountName=ad.user)(objectclass=user)(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org))]

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_access_done] (0x0400): Access was denied

(Sorry for edit. Trac smooshes things together in unexpected and annoying ways)

_comment0: Sure.

First, here's the filter in question:

ad_access_filter = DOM:ad.example.org:(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org)

Here's an example log output from a failed auth using that filter:

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_get_generic_ext_step] (0x0400): calling ldap_search_ext with [(&(sAMAccountName=ad.user)(objectclass=user)(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org))][CN=Example User,OU=Local Users,DC=ad,DC=example,DC=org].
(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_get_generic_ext_step] (0x0080): ldap_search_ext failed: Bad search filter
(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [generic_ext_search_handler] (0x0040): sdap_get_generic_ext_recv failed [1432158239]: Malformed search filter
(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_access_filter_done] (0x0020): Malformed access control filter [(&(sAMAccountName=ad.user)(objectclass=user)(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org))]
(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_access_done] (0x0400): Access was denied => 1476463821196569

Replying to [comment:9 mikeely]:

Sure.

First, here's the filter in question:

ad_access_filter = DOM:ad.example.org:(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org)

Your original filter was

(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org)(unixHomeDirectory=*))

any chance the unixHomeDirectory part got lost?

Here's an example log output from a failed auth using that filter:

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_get_generic_ext_step] (0x0400): calling ldap_search_ext with [(&(sAMAccountName=ad.user)(objectclass=user)(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org))][CN=Example User,OU=Local Users,DC=ad,DC=example,DC=org].

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_get_generic_ext_step] (0x0080): ldap_search_ext failed: Bad search filter

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [generic_ext_search_handler] (0x0040): sdap_get_generic_ext_recv failed [1432158239]: Malformed search filter

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_access_filter_done] (0x0020): Malformed access control filter [(&(sAMAccountName=ad.user)(objectclass=user)(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org))]

(Thu Oct 13 12:06:36 2016) [sssd[be[ad.example.org]]] [sdap_access_done] (0x0400): Access was denied

(Sorry for edit. Trac smooshes things together in unexpected and annoying ways)

You can use the markup for code-block which start with three opening curly braces and ends with three closing curly braces.

Good point regarding unixHomeDirectory (why is this needed, by the way?). Changes the error back to no match but does not solve the problem:

(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_access_filter_send] (0x0400): Checking filter against LDAP
(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_print_server] (0x2000): Searching 1.2.3.4
(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_get_generic_ext_step] (0x0400): calling ldap_search_ext with [(&(sAMAccountName=ad.user)(objectclass=user)(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org)(unixHomeDirectory=*)))][CN=Example User,OU=Local Users,DC=ad,DC=example,DC=org].
(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_get_generic_ext_step] (0x2000): ldap_search_ext called, msgid = 28
(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_op_add] (0x2000): New operation 28 timeout 6
(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_process_result] (0x2000): Trace: sh[0x7f83678a28b0], connected[1], ops[0x7f83678a48b0], ldap[0x7f83678bb770]
(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_get_generic_op_finished] (0x0400): Search result: Success(0), no errmsg set
(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_op_destructor] (0x2000): Operation 28 finished
(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_access_filter_done] (0x0100): User [ad.user] was not found with the specified filter. Denying access.
(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_access_filter_done] (0x0400): Access denied by online lookup
(Fri Oct 14 13:27:11 2016) [sssd[be[ad.example.org]]] [sdap_access_done] (0x0400): Access was denied.

Huh. Better, but it'd be nice if it wrapped rather than expanded.

Anyhow, I tried ldapsearch with the filter as it was (but without unixHomeDirectory) and verified that all the users are there, nested out of two subgroups:

# ldapsearch -H ldap://dc.ad.example.org -Y GSSAPI -N -b "dc=ad,dc=example,dc=org" "(&(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org))" | grep numEntries
SASL/GSSAPI authentication started
SASL username: ad.user@AD.EXAMPLE.ORG
...
# numEntries: 58

unixHomeDirectory is not needed at all, it just was in your original description so I thought it might be important for your setup. If it is not needed it might be the reason why SSSD didn't found the user because the search will only look for object which have the unixHomeDirectory attribute set.

So you can try just

(memberOf:1.2.840.113556.1.4.1941:=CN=Special AD Group,OU=Local Groups,DC=ad,DC=example,DC=org)

with only a brace at the start and the end no '&' or extra braces.

That works, which means we can say ad_access_provider can be made to work with nested groups!

Maybe change this to a doc fix?

Fields changed

summary: [RFE] Use OID syntax to support nested groups with ad_access_filter => [RFE/DOC] Use OID syntax to support nested groups with ad_access_filter
type: enhancement => documentation

Thank you for the feedback.

I think it is both DOC and RFE. I would keep it as a RFE as well because we should add code so that SSSD ignores what happens after the first '('.

Do you have any suggestions how to improve to man page entry starting at https://github.com/SSSD/sssd/blob/master/src/man/sssd-ad.5.xml#L207 ?

Suggested change to document searching for nested group membership
document_nested_groups.patch

Thanks for your help. Doc patch uploaded.

Fields changed

summary: [RFE/DOC] Use OID syntax to support nested groups with ad_access_filter => [RFE] ad_access_filter should ignore what happens after the first open paren

Fields changed

type: documentation => enhancement

Thank you for the patch (I think there is a ':' missing in the example).

We recently moved to github pull-requests for patches (https://fedorahosted.org/sssd/wiki/GithubWorkflow). Can you prepare a pull-request for your patch? If you prefer to avoid the hassle with github please let me know, then I can prepare one for you.

Nice catch on the missing char. I've added the pull request:

https://github.com/SSSD/sssd/pull/60

OK, I've now officially bolluxed the doc change. Sbose, is it too late to take you up on your offer?

I'm sorry causing you so much github troubles. Unfortunately it looks like I cannot push into your pull-request.

Please find attached a cleaned-up patch. If you check out a clean SSSD master branch without any patches you should be able to apply the patch locally and then a 'git push your_github_repo_name --force' should update the pull request with the patch. If this does not work for you please close the pull-request and I will open a new one.

Got it figured out. Thanks!

milestone: SSSD Patches welcome => SSSD 1.14.3

resolution: => fixed
status: new => closed

Fields changed

rhbz: => 0

Metadata Update from @mikeely:
- Issue set to the milestone: SSSD 1.14.3

7 years ago

SSSD is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in SSSD's github repository.

This issue has been cloned to Github and is available here:
- https://github.com/SSSD/sssd/issues/4251

If you want to receive further updates on the issue, please navigate to the github issue
and click on subscribe button.

Thank you for understanding. We apologize for all inconvenience.

Login to comment on this ticket.

Metadata