The problem, briefly: Apache configured to authenticate via LDAP and authorize access only to members of a certain group, would not authorize a new user account that was clearly a member of that group.
The solution, briefly: The new user account had its primary group
identifier (GID) set to the authorized group, while all other users
were auxiliary members. The new user account had to be given an
memberUid entry within the group’s LDAP definition.
I and the rest of our team use our regular accounts for both normal
and administrative work on our Unix machines, resorting to separate
admin accounts on Windows only. In the Unix environment, we’re
members of the group
admins, that grants us the rights to log
into infrastructure machines and invoke
sudo when necessary.
Our documentation wiki contains some sensitive information, so we
require that wiki visitors also be a member of the
We use Apache’s mod_authnz_ldap:
<Directory /> # everyone authenticates AuthName "Documentation" AuthType Basic AuthBasicProvider ldap AuthLDAPUrl "ldap://directory.work.com:389/ou=users,dc=work,dc=com?uid?sub" AuthLDAPGroupAttribute memberUid AuthLDAPGroupAttributeIsDN off Require ldap-group cn=admins,ou=groups,dc=work,dc=com </Directory>
A colleague within our system administration group—let’s call him
“Skip”—wanted to create a new, separate user account for himself.
He planned to use his regular account for non-administrative functions
only, switching to the new account only when he wanted to invoke
sudo or do other administrator-level work.
Skip didn’t want his regular account listed in that administrative group, which meant that he’d have to use his new administrative account to access our wiki.
He created the account:
skipadm. He tested login access to machines
that require users to be part of the
admins group. He encountered
no troubles. Unix tools like
id reported that the
was part of the
admins group using
Despite success with system-level access, Apache wouldn’t authorize
him. We increased Apache’s
LogLevel setting up to
watched the error log. We could see that the password was accepted
just fine, but Apache couldn’t map the account to the
[Thu Mar 17 10:01:33.809963 2016] [authnz_ldap:debug] [pid 18098] mod_authnz_ldap.c(593): [client 10.11.12.13:46107] AH01697: auth_ldap authenticate: accepting skipadm [Thu Mar 17 10:01:33.809969 2016] [authnz_ldap:debug] [pid 18098] mod_authnz_ldap.c(879): [client 10.11.12.13:46107] AH01714: auth_ldap authorize: require group: testing for memberUid: skipadm (cn=admins,ou=groups,dc=work,dc=com) [Thu Mar 17 10:01:33.810001 2016] [authnz_ldap:debug] [pid 18098] mod_authnz_ldap.c(945): [client 10.11.12.13:46107] AH01720: auth_ldap authorize group: authorization denied for user skipadm to /wiki/
Various troubleshooting steps followed, to no avail.
Then Skip sent this to me via chat:
actually, maybe I have a theory I think I set it as my primary GID
And that freed up the brain cells for me to get to the heart of the problem.
Here’s our normal procedure for creating new user accounts:
allusersthe primary group
For example, for Skip’s normal account we
skipand added user
When Skip created his admin account, however, he followed a different procedure:
skipadmand added user
Most user accounts for system administrators have
admins added as an
auxiliary group, but for this account it was the primary group.
That difference showed up in our LDAP directory in an unexpected way.
In a normal case, the user’s directory entry has the accounts user ID (UID) listed via uidNumber and the group ID via gidNumber. Auxiliary group membership isn’t listed in the user’s entry but by querying memberUid in a group entry.
In our directory scheme, however, the default group doesn’t get memberUid entry, just the aforementioned gidNumber in the user’s entry.
It can show up via
getent. If we assume that the
allusers group (our default group) has GID 1234, we can see a huge difference in the number of group members seen via
getent group allusers as opposed to via
getent passwd and looking for GID 1234:
[~]$ getent group allusers | cut -d: -f4 | sed 's/,/ /g' | wc 1 61 484 [~]$ getent passwd | grep :1234: | wc 916 917 50790
The group map reports 61 members, while the passwd map reports 916.
When queried on a per-user basis, the system has one view of group membership. That’s what PAM does, and that’s why Skip was able to use his new account to log into systems.
When viewed on a per-group basis, there’s a different view. That’s what Apache does, and that’s why it didn’t view Skip’s admin account as a group member.
Short of asking Apache to test group membership via PAM by way of
a mechanism like the
id utility, I’m not sure there’s an easy
long-term solution to this problem when the user and group databases
are stored in LDAP.
The fix was easy, if not really scalable: I manually edited the LDAP
directory, adding a memberUid for
skipadm in the
entry. Once that was in place, Apache was fine.
Still, it was a weird problem.