sabredav-freeipa
FreeIPA integration for sabre/dav
What is this?
This project extends the sabre/dav framework with authentication and principal backends for FreeIPA. You can use this to run your own CalDAV/CardDAV server that retrieves users and groups from the local FreeIPA domain.
Two backends are provided:
\FreeIPA\AuthBackend
: this is an authentication backend that uses theREMOTE_USER
environment variable set by the webserver. You should configure mod_gssapi to handle user authentication. Optionally, you can limit logins to members of certain FreeIPA groups using the$allowedGroups
parameter.
Upon successful login, a default calendar and addressbook will be created for the user if none already exist.
\FreeIPA\PrincipalBackend
: this is a principal backend that retrieves users and groups from FreeIPA. You can (and should) limit the users and groups returned using the$allowedGroups
parameter.
Both backends require php-ldap
compiled with SASL support. Check phpinfo()
to
verify you have a compatible version. In addition, the PHP process needs access
to kerberos credentials in order to perform LDAP queries (see below).
This project has been used successfully in the following environments:
- Rocky Linux 8 with Apache 2.4 and PHP 7.4
- Rocky Linux 9 with Apache 2.4 and PHP 8.0
Limitations
SabreDAV assumes that user and group principals are both stored in the same
principals/
namespace. Practically, this means that you can't have a user
and group in FreeIPA with the same name.
While you can allegedly work around this limitation, it is neither tested nor supported.
In the event a username and groupname clash, the user takes precendence and the group will not be visible to SabreDAV.
Setup
Clone this repostory into your webroot:
webroot=/var/www/html/sabredav
mkdir $webroot
git clone https://github.com/sacredheartsc/sabredav-freeipa $webroot
Install dependences using composer:
cd $webroot
composer install
Rename the sample configuration and modify to suit your needs:
cp server.example.php server.php
Most of this file is boilerplate common to all SabreDAV installations. Note the salient FreeIPA parts:
$ipa = new \FreeIPA\Connection();
$allowedGroups = [
'dav-access'
];
$authBackend = new \FreeIPA\AuthBackend(
$ipa,
$caldavBackend,
$carddavBackend,
$allowedGroups);
$principalBackend = new \FreeIPA\PrincipalBackend(
$ipa,
$allowedGroups);
Note especially the $allowedGroups
array. You should use this parameter to limit
the FreeIPA users and groups visible to SabreDAV. If you leave it empty, then all
users and groups will be visible. This is bad for two reasons:
-
It results in poor client experience by littering the interface with a bunch of groups that no one will ever use.
-
Sabredav makes a lot of group membership queries, seemingly on every request. Querying group memberships across your entire FreeIPA domain on every CalDAV operation is ridiculously expensive.
Consider the example configuration above. Assuming the dav-access
FreeIPA group
looks like this:
$ ipa group-show dav-access
Group name: dav-access
Description: CalDAV/CardDAV access
Member groups: accounting, human-resources
Indirect Member users: benedict, leo, michael
then SabreDAV would only see the following groups:
dav-access
, accounting
, human-resources
And similarly, only the members of those groups would show up as SabreDAV users:
benedict
, leo
, michael
This type of configuration is possible because FreeIPA supports nested groups (a group itself can be a member of another group).
Apache Configuration
The following apache configuration provides Kerberos SSO for SabreDAV, falling back to Basic authentication. In addition, it redirects well-known URLs to aid in client autodiscovery.
Redirect /.well-known/caldav /server.php
Redirect /.well-known/carddav /server.php
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/\.well-known/
RewriteRule .* /server.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
<Location />
AuthType GSSAPI
AuthName "FreeIPA Single Sign-On"
GssapiBasicAuth On
GssapiNegotiateOnce On
Require valid-user
</Location>
Apache needs a keytab for HTTP/dav.example.com
, and PHP needs a kerberos ticket
to perform LDAP queries. The following gssproxy.conf
snippet is sufficient (this
also works for kerberized postgres queries):
[service/sabredav]
mechs = krb5
cred_store = client_keytab:/var/lib/gssproxy/clients/sabredav.keytab
euid = apache
[service/HTTP]
mechs = krb5
cred_store = keytab:/var/lib/gssproxy/clients/httpd.keytab
euid = apache
program = /usr/sbin/httpd
Be sure to export GSS_AUTH_PROXY=yes
for your httpd and php-fpm daemons:
# /etc/systemd/system/httpd.service.d/override.conf
[Service]
Environment=GSS_USE_PROXY=yes
# /etc/php-fpm.d/www.conf
env[GSS_USE_PROXY] = yes
If you're not using gssproxy, you'll need the usual KRB5_KTNAME
and
KRB5_CLIENT_KTNAME
with appropriate permissions.
You'll also need the following if SELinux is enabled:
setsebool -P httpd_can_connect_ldap on