For some time now, HTTP access to the ADMIRAL file store has been restricted because we were unable to use a combination of Apache
Require valid user,
Require user and
Require ldap-attribute directives to combine by-username and by-group access. For example, we have been unable to realize access control for this scenario:
/data/private all registered users have read-only access
/data/private/UserA read/write access for
UserA,
read-only access for research group leaders,
all others denied
/data/private/UserB read/write access for UserB,
read-only access for research group leaders,
all others denied
We had been finding that any attempt to put an access control statement on the
/data/private directory resulted in the access control statements for the user private directories being ignored. Also, we were finding that we could not allow
UserA to have read/write access to their personal area, while allowing read access to any user designated as a research group leader.
The Apache configuration we had been trying to use looked something like this:
# Default read access to all areas for registered users
<Directory /home/data>
Require valid user
</Directory>
# Define access to area for user $username
<Location /data/private/$username>
Order Deny,Allow
Allow from all
<LimitExcept REPORT GET OPTIONS PROPFIND>
Require ldap-user $username
</LimitExcept>
<Limit PROPFIND OPTIONS GET REPORT>
Require user $username
Require ldap-attribute gidNumber=$RGLeaderGID
</Limit>
</Location>
As this would not work as required, we ended up disabling access to the /data area, leaving users unable to use HTTP to browse between the different user areas, and configuring the research group leader's read-only access using a configured username, making the configuration very much more fragile than needed:
# Define access to area for user $username
<Location /data/private/$username>
Order Deny,Allow
Allow from all
<LimitExcept REPORT GET OPTIONS PROPFIND>
Require user $username
</LimitExcept>
<Limit PROPFIND OPTIONS GET REPORT>
Require user $username $RGLeaderName
</Limit>
</Location>
We recently realized that Apache recognizes different access control providers, and that access to a given area cannot be controlled by a combination of providers. There is a default provider, invoked by
Require user ... and
Require valid user, and there is an LDAP provider. Thus, the presence of a matching
Require ldap-attribute directive meant that any matching
Require user directives were being ignored.
"When no LDAP-specific Require directives are used, authorization is allowed to fall back to other modules as if AuthzLDAPAuthoritative was set to off"
- http://httpd.apache.org/docs/2.2/mod/mod_authnz_ldap.html
The overlooked implication here was that if any LDAP authorization directive is matched, the non-LDAP directives are ignored, even when applied to a more specific directory. The picture is further muddied by the fact that the non-LDAP authorization handlers have limited access to LDAP values (via an LDAP PAM module?), so that
Require user would still respond to LDAP user entries.
Having identified the problem, the fix is easy. Use
Require ldap-user instead of
Require user:
# Default access to all areas
<Directory /home/data>
Require ldap-attribute gidnumber=600
Require ldap-attribute gidnumber=601
Require ldap-attribute gidnumber=602
</Directory>
<Location /data/shared/$username>
Order Deny,Allow
Allow from all
<LimitExcept REPORT GET OPTIONS PROPFIND>
Require ldap-user $username
</LimitExcept>
<Limit PROPFIND OPTIONS GET REPORT>
Require ldap-attribute gidNumber=$RGLeaderGID
Require ldap-attribute gidNumber=$RGMemberGID
</Limit>
</Location>
There is a lingering issue of the mixed
<Directory> and
<Location> directives: using
<Location> for the
/data URI path is not working, and right now we are not sure exactly why, but it seems to be related to either file system symlinks to the data directories, or Apache Alias directives controlling the mapping to same.