Support for query-based groups

Now that we have LDAP support, I would love to be able to create dynamic groups based on an LDAP query.

For example, all of my user accounts in AD are in an container named after the department. It would be nice to have a group named “Dept123” that is populated based on the query “cn=Dept123.”

Others might find it useful to create groups based on company, country, city, state, office, security group membership, etc.

I could imagine that this feature would be very useful to administrators with a large user base.

JL,

This is a good idea. I’'ve added it as a feature request: JM-129.

Thanks,

Matt

I like the idea of dynamic query-based groups but I don’‘t know how I like the extra maintenance factor involved. Typically, you’‘re already going to have groups set up at the OS level for different things and I’'m wondering if we could just hook into that so administrators are using tools that they are familiar with. Also, it would reduce the need for a seperate web interface to accomplish this.

To clarify, what I’'m thinking is:

I have a group called “XMPP - Manufacturing” and I put all my users who I want to show up in that group in JM. The options to JM would realistically just be the DN of group object in LDAP and maybe a display name for the group. Once all my groups are set up, then I use my standard LDAP tools to update the group memberships and those people will automatically be added to JM.

Now the tricky part is getting it done correctly so it works cross-platform on Win32 AD as well as Unix LDAP. I’‘m not entirely familiar with the Unix LDAP but I’‘m guess it’‘s based on POSIX groups and should be analogous to AD groups. In AD, the group object will have a multi-string value called “Members” (or something similiar) that you can query and get the DN’‘s of the group’'s members. Even if you just get the UID in the Unix implementation, that should be enough to search and lookup the DNs of the user objects.

darcher,

I think what you are proposing is exactly what we’‘re already talking about, but I’'ll leave that alone.

You do raise a good point about having to support different LDAP schemas – I hadn’'t really looked at it until now. In Active Directory, group objects have multiple member attributes that contain a single object reference for each member of the group, like this:

member: CN=John Doe,OU=Users,DC=example,DC=com

member: CN=Jane Doe,OU=Users,DC=example,DC=com

But in a posixGroup object, the group has multiple memberUid attributes that hold each user’‘s uid, which may or may not be the usernameField setup in the JM config. Here’'s an example:

memberUid: johndoe

memberUid: janedoe

So, at least for these two scenarios, JM would need to be able to do a secondary query for each member attribute defined in the group object in order to get the attribute defined in the JM LDAP usernameField. So, I’'m thinking we need three things: (1) a group query filter, (2) an attribute to select from the group query, and (3) an optional user query filter. An AD example:

  1. (&(objectCategory=Group)(cn=MyGroup))

  2. member

  3. (&(objectCategory=Person)(distinguishedName=))

I’‘m assuming that whatever is returned from #3, JM will select whatever attributed is defined as the usernameField from the conf file. In this example, it’'s generally sAMAccountName.

Since parameter 3 is optional, we can setup a posix example like this:

  1. (&(objectClass=posixGroup)(cn=MyGroup))

  2. memberUid

This, of course, assumes that the usernameField is the uid.

How does all that sound?

The only wrinkle that I can think of is whether or not the primary group of a given posixAccount has that user in it’‘s member list. Did that make sense? Let me explain. On a posix system (without LDAP), the passwd file has a user’‘s primary group, but the group file doesn’‘t explicitly list that user in it’'s user list. I just wonder is the LDAP implementation is the same way because that would obviously complicate things a little.

hrothgar,

Looking at the original post again, it does look like we were talking about the same thing. My mind must have slipped or something.

Anyways, it looks like the AD implementation will be less efficient because you have to do multiple queries (one per user) in order to get that actual username versus the POSIX way of listing them in the group object directly. I’‘m not an LDAP wizard by any means but is there a way to pull the sAMAccountName’‘s directly from the group object with a single query (something like a join in relational DB’'s)? If not, then we just have to take the performance hit and hope its not too bad.

As far as the primary groups, yes, in AD, the user object is not explicitly referenced in the group object if it’‘s their primary group. I’‘ve had that bite me a few times in the past while writing some admin scripts. Since it’‘s only used in a windows environment for POSIX applications, we just set everyone to “Domain User” as their primary group. But I guess you can’‘t assume that everyone will be set up that way. So that throws another wrench in the works because we then have to do a subtree search for every user whose primary group is the one we’'re interested in.

I just had an idea: Can’'t we just do an LDAP search using the MemberOf attribute of the users? Are those similiar between POSIX and AD? That would give us all the members of the group in a single query and may be an easier path that doing multiple lookups.

Edit: Nevermind about the MemberOf attribute. Looks like that’'s AD specific (although there is a “member” attribute that can be used for POSIX user objects but there is not a way of keeping it automatically in sync with the groups - http://www.openldap.org/lists/openldap-software/200204/msg00756.html ).

Another thought occurred to me. What about nested groups? How are those handled in POSIX versus AD? I found this code to quickly test membership of a user object in AD against a top-level group and it will also search all nested groups as well.

http://www.khakipants.org/archives/2004/01/a_speedy_algorithm_for_testing_member ship_in_nested_ldap_groups.html

While we don’‘t necessarily need to test membership in a group (unless we want another feature request to replace the admin users hardcoded in the JM config with an LDAP group), we need to get all members in a group and I’'m assuming all nested groups as well. Doing this efficiently is not trivial from what I can tell.

My work on doing nested groups was in Perl and I just kept a cache of the groups as I went as well as some rudimentary recursion checking to make sure we don’'t end up in a loop (nested group having a higher-level group nested in itself causing an infinite loop).

Anyways, it looks like the AD implementation will be

less efficient because you have to do multiple

queries (one per user) in order to get that actual

username versus the POSIX way of listing them in the

group object directly. I’'m not an LDAP wizard by any

means but is there a way to pull the sAMAccountName’'s

directly from the group object with a single query

(something like a join in relational DB’'s)? If not,

then we just have to take the performance hit and

hope its not too bad.

AFAIK, you can not do joins or sub-select type queries in LDAP. You would have to do multiple queries. As for the performance hit, I’‘m expecting JM to only update the group membership every X minutes and cache the results, so JM won’'t be pounding the LDAP server.

As far as the primary groups, yes, in AD, the user

object is not explicitly referenced in the group

object if it’‘s their primary group. I’'ve had that

bite me a few times in the past while writing some

admin scripts. Since it’'s only used in a windows

environment for POSIX applications, we just set

everyone to “Domain User” as their primary group. But

I guess you can’'t assume that everyone will be set up

that way. So that throws another wrench in the

works because we then have to do a subtree search for

every user whose primary group is the one we’'re

interested in.

Great point. I wasn’'t aware of that functionality in AD. So basically to support a Posix-compatible schema, we would need to support a secondary group of queries to search all user objects to see if the group is their primary group. Assuming we could use the same query to find the group object that I posted earlier, how about these parameters: (1) attribute for group ID and (2) query to check for primary group of users. Posix example:

  1. gidNumber

  2. (&(objectClass=Person)(gidNumber=))

How’'s that sound?

Another thought occurred to me. What about nested

groups? How are those handled in POSIX versus AD? I

found this code to quickly test membership of a user

object in AD against a top-level group and it will

also search all nested groups as well.

While we don’'t necessarily need to test membership in

a group (unless we want another feature request to

replace the admin users hardcoded in the JM config

with an LDAP group), we need to get all members in a

group and I’'m assuming all nested groups as well.

Doing this efficiently is not trivial from what I can

tell.

My work on doing nested groups was in Perl and I just

kept a cache of the groups as I went as well as some

rudimentary recursion checking to make sure we don’'t

end up in a loop (nested group having a higher-level

group nested in itself causing an infinite loop).

Hmm…we don’'t use nested groups here. Once basic group support is added, we could wait for someone to complain about nested groups.

Message was edited by:

hrothgar

Fixed an important typo; it’'s in bold.

I posted a bounty for whoever implements JM-129.