How Shibboleth is used to authenticate PPKE users
Zimbra has a mechanism called preauth which makes it possible to interface with other authentication systems.
The big picture
A Shibboleth SP with apache is needed. This authenticates the user with shibboleth and relays it to Zimbra.
In our case shibboleth attribute eduPersonPrincipalName is the same as the email address in Zimbra. The identity provider releases this attribute to the service provider. There a Perl CGI script accesses this as an environment variable. After a valid shibboleth session is established with the SP the user is redirected to a Zimbra URL with a GET variable encoding a signed cookie which identifies the user to Zimbra. This cookie is validated and user access is granted if found valid.
Shibboleth SP setup
From the apache side this is the main part of the configuration.
This is needed for the directory containing our custom cgi script.
(shibboleth2.xml
is needed as usual)
<Directory /where-your-cgi-is>
AuthType shibboleth
require shibboleth
ShibRequireSession On
</Directory>
The cgi script
First the shared secret must be obtained with zmprov
:
prov> gdpak example.org
This value is required for the script.
#!/usr/bin/perl
use strict;
use warnings;
use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
use Data::Dump qw(pp);
use CGI;
my $cgi = new CGI->new;
my %k;
#prov> gdpak example.org
#preAuthKey: aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbccccccccccccccccc
$k{"example.org"}="aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbccccccccccccccccc";
my $zmda = $ENV{"eduPersonPrincipalName"};
my $urlbase = "mail.example.org";
unless($k{$domain}) {
print $cgi->header(-status=>'500 Service Unavailable');
print "unknown domain, are you authorized for zimbra?";
die;
}
my $redir = buildZimbraPreAuthUrl($k{$domain},
"https://$urlbase/service/preauth",
$zmda,
"name");
print $cgi->redirect( -uri => $redir );
## @method private string buildZimbraPreAuthUrl(string key, string url, string account, string by)
# Build Zimbra PreAuth URL
# @param key PreAuthKey
# @param url URL
# @param account User account
# @param by Account type
# @return Zimbra PreAuth URL
sub buildZimbraPreAuthUrl {
my ( $key, $url, $account, $by ) = splice @_;
# Expiration time
my $expires = 0;
# Timestamp
my $timestamp = time() * 1000;
# Compute preauth value
my $computed_value =
hmac_sha1_hex( "$account|$by|$expires|$timestamp", $key );
# Build PreAuth URL
my $zimbra_url;
$zimbra_url .= $url;
$zimbra_url .= '?account=' . $account;
$zimbra_url .= '&by=' . $by;
$zimbra_url .= '×tamp=' . $timestamp;
$zimbra_url .= '&expires=' . $expires;
$zimbra_url .= '&preauth=' . $computed_value;
return $zimbra_url;
}
Zimbra can redirect unauthenticated users to our cgi
We can achive that with changing the domain attribute zimbraWebClientLoginURL
.