Commit bec0831f authored by Clément OUDOT's avatar Clément OUDOT

Zimbra preAuth is now an independent Handler (#12)

parent cdad662b
......@@ -359,6 +359,7 @@ install_handler_site: install_conf_dir
# Handler install
@install -v -d ${RHANDLERDIR}
@cp --remove-destination ${SRCHANDLERDIR}/example/MyHandler.pm ${RHANDLERDIR}
@cp --remove-destination ${SRCHANDLERDIR}/example/MyHandlerZimbra.pm ${RHANDLERDIR}
@rm -rf $$(find $(RHANDLERDIR) -type d -name .svn)
install_test_site:
......@@ -605,6 +606,7 @@ default-diff:
@# Handler
@$(DIFF) lemonldap-ng-handler/lib/Lemonldap/NG/Handler /usr/local/share/perl/5.10.0/Lemonldap/NG/Handler ||true
@$(DIFF) lemonldap-ng-handler/example/MyHandler.pm $(LMPREFIX)/handler/MyHandler.pm ||true
@$(DIFF) lemonldap-ng-handler/example/MyHandlerZimbra.pm $(LMPREFIX)/handler/MyHandlerZimbra.pm ||true
@# Common
@$(DIFF) lemonldap-ng-common/lib/Lemonldap/NG/Common /usr/local/share/perl/5.10.0/Lemonldap/NG/Common ||true
@$(DIFF) lemonldap-ng-common/lib/Lemonldap/NG/Common.pm /usr/local/share/perl/5.10.0/Lemonldap/NG/Common.pm ||true
......
# Handler for Zimbra preauthentication
package My::Zimbra;
# Load Zimbra Handler
use Lemonldap::NG::Handler::ZimbraPreAuth;
@ISA = qw(Lemonldap::NG::Handler::ZimbraPreAuth);
__PACKAGE__->init(
{
# See Lemonldap::NG::Handler
}
);
1;
......@@ -22,7 +22,6 @@ use Lemonldap::NG::Common::Safelib; #link protected safe Safe object
require Data::Dumper;
require POSIX;
use CGI::Util 'expires';
use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex); # Zimbra preauth
#inherits Cache::Cache
#inherits Apache::Session
......@@ -600,44 +599,12 @@ sub conditionSub {
);
}
}
# Replace some strings in condition
$cond =~ s/\$date/&POSIX::strftime("%Y%m%d%H%M%S",localtime())/e;
$cond =~ s/\$(\w+)/\$datas->{$1}/g;
$cond =~ s/\$datas->{vhost}/\$apacheRequest->hostname/g;
# Zimbra preauth trigger
if ( $cond =~ /^zimbra_preauth(?:\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+))?$/i ) {
# Get preauth parameters
my ( $ZimbraPreAuthKey, $ZimbraAccount, $ZimbraBy, $ZimbraUri ) =
( $1, $2, $3, $4 );
my $ZimbraExpires = 0;
my $ZimbraTimestamp = gmtime() * 1000;
# Compute preauth value
my $ZimbraComputedValue = hmac_sha1_hex(
"$ZimbraAccount|$ZimbraBy|$ZimbraExpires|$ZimbraTimestamp",
$ZimbraPreAuthKey );
# Redirect user
return (
$class->safe->reval(
"sub {
\$datas->{_redirect} = 'http';
\$datas->{_redirect} .= ( \$https ? 's' : '' ) . '://' ;
\$datas->{_redirect} .= \$apacheRequest->get_server_name;
\$datas->{_redirect} .= ':' . ( \$port ? \$port : \$apacheRequest->get_server_port );
\$datas->{_redirect} .= '$ZimbraUri';
\$datas->{_redirect} .= '?account='.$ZimbraAccount;
\$datas->{_redirect} .= '&by=$ZimbraBy';
\$datas->{_redirect} .= '&expires=$ZimbraExpires';
\$datas->{_redirect} .= '&preauth=$ZimbraComputedValue';
return 0; }"
),
1
);
}
# Eval sub
my $sub = $class->safe->reval("sub {return ( $cond )}");
......@@ -870,15 +837,6 @@ sub forbidden {
$class->localUnlog;
return $class->goToPortal( $u, 'logout=1' );
}
elsif ( $datas->{_redirect} ) {
$class->updateStatus( $datas->{$whatToTrace}, $_[0], 'REDIRECT' );
my $u = $datas->{_redirect};
$class->lmLog(
"Redirect " . $apacheRequest->connection->remote_ip . " to $u",
'debug' );
lmSetHeaderOut( $apacheRequest, 'Location' => $u );
return REDIRECT;
}
$class->updateStatus( $datas->{$whatToTrace}, $_[0], 'REJECT' );
$apacheRequest->push_handlers(
PerlLogHandler => sub { $class->logForbidden( $uri, $datas ); DECLINED }
......
##@file
# Zimbra preauthentication
##@class
# Zimbra preauthentication
#
# It will build Zimbra preauth URL
package Lemonldap::NG::Handler::ZimbraPreAuth;
use strict;
use Lemonldap::NG::Handler::SharedConf qw(:all);
our @ISA = qw(Lemonldap::NG::Handler::SharedConf);
use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
our $VERSION = '0.1';
# @method run()
# Overload main run method
# return Apache error code
sub run {
my $class = shift;
my $r = $_[0];
my $ret = $class->SUPER::run(@_);
# Continue only if user is authorized
return $ret unless $ret eq OK;
# Get configuration parameters
my $ZimbraPreAuthKey = $r->dir_config('ZimbraPreAuthKey');
my $ZimbraAccountKey = $r->dir_config('ZimbraAccountKey') || "uid";
my $ZimbraBy = $r->dir_config('ZimbraBy') || "id";
my $ZimbraUrl = $r->dir_config('ZimbraUrl');
unless ( $ZimbraPreAuthKey and $ZimbraUrl ) {
$class->lmLog( "No preauth key or URL configured", 'error' );
return SERVER_ERROR;
}
# Other values
my $ZimbraAccount = $datas->{$ZimbraAccountKey};
my $ZimbraExpires = 0;
my $ZimbraTimestamp = gmtime() * 1000;
# Compute preauth value
my $ZimbraComputedValue =
hmac_sha1_hex( "$ZimbraAccount|$ZimbraBy|$ZimbraExpires|$ZimbraTimestamp",
$ZimbraPreAuthKey );
# Build PreAuth URL
my $zimbra_url;
$zimbra_url .= $ZimbraUrl;
$zimbra_url .= '?account=' . $ZimbraAccount;
$zimbra_url .= '&by=' . $ZimbraBy;
$zimbra_url .= '&expires=' . $ZimbraExpires;
$zimbra_url .= '&preauth=' . $ZimbraComputedValue;
$class->lmLog( "Build Zimbra URL $zimbra_url", 'debug' );
# Header location
lmSetHeaderOut( $r, 'Location' => $zimbra_url );
# Return REDIRECT
return REDIRECT;
}
1;
__END__
=head1 NAME
=encoding utf8
Lemonldap::NG::Handler::ZimbraPreAuth - Perl extension to generate Zimbra preauth URL
for users authenticated by Lemonldap::NG
=head1 SYNOPSIS
package My::Zimbra;
use Lemonldap::NG::Handler::ZimbraPreAuth;
@ISA = qw(Lemonldap::NG::Handler::ZimbraPreAuth);
__PACKAGE__->init ( {
# See Lemonldap::NG::Handler for more
} );
1;
=head1 DESCRIPTION
Edit you Zimbra vhost configuration like this to catch a specific SSO URL
<VirtualHost *>
ServerName zimbra.example.com
# Default Handler
PerlRequire __HANDLERDIR__/MyHandler.pm
PerlHeaderParserHandler My::Zimbra
# Load Zimbra Handler
PerlRequire __HANDLERDIR__/MyHandlerZimbra.pm
# Zimbra SSO URL
<Location /zimbrasso>
PerlSetVar ZimbraPreAuthKey XXXX
PerlSetVar ZimbraAccountKey uid
PerlSetVar ZimbraBy id
PerlSetVar ZimbraUrl /service/preauth
PerlHeaderParserHandler My::Zimbra
</Location>
</VirtualHost>
=head2 EXPORT
See L<Lemonldap::NG::Handler>
=head1 SEE ALSO
L<Lemonldap::NG::Handler>
=head1 AUTHOR
Clement Oudot, E<lt>clement@oodo.netE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 201O by Clement Oudot
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.
=cut
......@@ -559,7 +559,7 @@ sub _compileRules {
sub _conditionSub {
my ( $self, $cond ) = splice @_;
return sub { 1 }
if ( $cond =~ /^(?:accept$|unprotect$|zimbra_preauth)/i );
if ( $cond =~ /^(?:accept|unprotect)$/i );
return sub { 0 }
if ( $cond =~ /^(?:deny$|logout)/i );
$cond =~ s/\$date/&POSIX::strftime("%Y%m%d%H%M%S",localtime())/e;
......
......@@ -362,7 +362,7 @@ sub _conditionSub {
my ( $self, $id, $cond ) = splice @_;
my $h = $self->getApacheSession( $id, 1 );
return sub { 1 }
if ( $cond =~ /^(?:accept$|unprotect$|zimbra_preauth)/i );
if ( $cond =~ /^(?:accept|unprotect)$/i );
return sub { 0 }
if ( !$h or $cond =~ /^(?:deny$|logout)/i );
$cond =~ s/\$date/&POSIX::strftime("%Y%m%d%H%M%S",localtime())/e;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment