Trick789 - Hi ๐ I'm running homeassistant (HA)...
Hi ๐ I'm running homeassistant (HA), lldap and the cisco duo authentication proxy (DUO) on k8s. I can't use the example config as I'm using HA > LDAP > DUO > LDAP > LLDAP. It's working beautifully using a a custom auth provider for HA (python script using ldap3 library: https://gist.github.com/yumenohikari/8440144023cf33ab3ef0d68084a1b42f) , but the only thing I can't get right is the filter so that only members of a group cn=ha_rw,ou=groups,dc=example,dc=com can authenticate.
I've tried a bunch of flavors for the filter, but the lldap log continues to throw [warn]: Ignoring unknown group attribute ""memberof"" in filter messages. I thought memberof was a person attribute so I loaded up an LDAP browser (Apache DS) but can't find the attribute on either groups or people. But it must work because DUO is also pulling a memberof query to allow certain LLDAP users through and that's not generating a log entry on the LLDAP server.
This is the original filter in the script (basically for AD):
FILTER = """ (& (objectClass=person) (| (sAMAccountName={}) (userPrincipalName={}) ) (memberOf=CN=Home Assistant,OU=Security Groups,OU=Accounts,DC=ad,DC=example,DC=com) )"""and that's what I've attempted to change it to..
FILTER = """ (& (objectClass=person) (| (uid={}) (mail={}) ) (memberOf=CN=ha_hw,ou=groups,dc=example,dc=com) )"""Any idea what the filter should look like? (running lldap 0.5.1-alpha). Thank you.
Solution:Jump to solution
@nitnelave - hey, just wanted to let you know that with the right filter in place I got it to work..
filter in ldap-auth.py
safe_username = escape_filter_chars(os.environ['username']) FILTER = f"(&(uid={safe_username})(memberOf=cn=ha_rw,ou=groups,dc=example,dc=com))"...
64 Replies
You're right that memberOf is a person attribute. It's also not technically an attribute, which is why the LDAP browser didn't show it (it's also possible that the browser doesn't work well with LLDAP).
The reverse direction, for groups, is "member".
@nitnelave - thanks for the excellent work. love the project!
Enabled verbosity and am seeing the following entries..
[debug]: | request.base: "DC=example,DC=com" | scope: Global get_user_list [ 607ยตs | 0.03% / 0.34% ] [debug]: | filters: And([And([]), MemberOf("ha_rw")])so I take it the filter is working and I can just ignore those warnings
The warning might be a false alarm: since your query probably has a base DN of just the DC (without the OU), LLDAP searches both groups and users (although it's not going to find any group with the object class condition)
oh right, I could finetune the base DN in the script to avoid that.
If you can configure the base DN of the request, adding "ou=people" at the beginning should make the warnings go away
just noticed, after having added a couple of users to the group, that no matter which user I enter in HA, it's trying to login with the first user (alphabetically) in the group. Bummer but that has nothing to do with LLDAP I suppose ๐
Look at the query sent to LLDAP and make sure it has the login name
(you can see it in the verbose logs)
When I see:
get_user_list [ 607ยตs | 0.03% / 0.34% ] [debug]: | filters: And([And([]), MemberOf("ha_rw")])It seems that there's no login name in there
oh yeh I'm monitoring the logs of all 3 apps while trying to sign in..
HA: authentication failed for user B (the one I'm trying to login with).
DUO: passes user A (first user of group hw_rw) on to LLDAP.
LLDAP: errors out on user A.
I don't see the whole "or" block from your filter
The second "And([])" is just "true", that's the object class= person filter, it's always true for users
I guess the issue is in the duo configuration
This is what I'm seeing when DUO checks if a user is allowed to use the service (DUO)
[debug]: | filters: And([And([Or([MemberOf("duo_access")]), Or([And([Not(And([])), Not(And([]))]), And([]), Not(And([]))])]), UserId(UserId("userB"))])I didn't define the filter, that's all DUO.
It's getting hard to read ๐
can you post the LDAP just above? It has the LDAP filter before processing
[debug]: | filters: And([And([]), MemberOf("ha_rw")]) list_users [ 509ยตs | 0.26% ] filters: Some(And([And([]), MemberOf("ha_rw")])) | _get_groups: false [debug]: | return: [UserAndGroups { user: User { user_id: UserId("userB"), ..
No, I mean a couple of lines above the filter, for the same query, you have the full request
And the filter looks different
gotcha
[debug]: | msg: LdapMsg { msgid: 183, op: SearchRequest(LdapSearchRequest { base: "CN=duo_access,OU=groups,DC=example,DC=com", scope: Base, aliases: Never, sizelimit: 1, timelimit: 0, typesonly: false, filter: Present("objectClass"), attrs: ["objectsid"] }), ctrl: [] }followed by
[debug]: | request.base: "CN=duo_access,OU=groups,DC=example,DC=com" | scope: Group(Equality("cn", "duo_access"))
That's the request for the duo_access group
(no idea about the objectsid attribute though)
(maybe it's important?)