- deleting specific handlers defined in two places.
- deleting old MyHandler*, because they are not used anymore. (Specific handlers are called directly) - renaming SpecificHandlers into Specific - documentation updated accordingly in: 1.4/upgrades, 1.4/applications/zimbra, 1.4/applications/sympa, 1.4/securetoken (references #630)
This commit is contained in:
parent
233026eb6f
commit
ca6227f469
|
@ -1,42 +0,0 @@
|
|||
package My::Package;
|
||||
use Lemonldap::NG::Handler::DefaultHandler;
|
||||
@ISA = qw(Lemonldap::NG::Handler::DefaultHandler);
|
||||
|
||||
__PACKAGE__->init(
|
||||
{
|
||||
|
||||
# WARNING:
|
||||
# all args inserted here must be the same for all handlers launched on
|
||||
# the same Apache server even if they inherits from different classes
|
||||
# (SympaAutoLogin,...)
|
||||
|
||||
# ACCESS TO CONFIGURATION
|
||||
|
||||
# By default, Lemonldap::NG uses the default lemonldap-ng.ini file to
|
||||
# know where to find is configuration
|
||||
# (generaly /etc/lemonldap-ng/lemonldap-ng.ini)
|
||||
# You can specify by yourself this file :
|
||||
#configStorage => { confFile => '/path/to/my/file' },
|
||||
# You can also specify directly the configuration
|
||||
# (see Lemonldap::NG::Handler::DefaultHandler(3))
|
||||
#configStorage => {
|
||||
# type => 'File',
|
||||
# dirName => '/usr/local/lemonldap-ng/data/conf/'
|
||||
#},
|
||||
|
||||
# OTHERS
|
||||
# You can also overload any parameter issued from manager
|
||||
# configuration. Example:
|
||||
#globalStorage => 'Lemonldap::NG::Common::Apache::Session::SOAP',
|
||||
#globalStorageOptions => {
|
||||
# proxy => 'http://auth.example.com/index.pl/sessions',
|
||||
# proxyOptions => {
|
||||
# timeout => 5,
|
||||
# },
|
||||
# # If soapserver is protected by HTTP Basic:
|
||||
# User => 'http-user',
|
||||
# Password => 'pass',
|
||||
#},
|
||||
}
|
||||
);
|
||||
1;
|
|
@ -1,16 +0,0 @@
|
|||
# Handler for Auth Basic
|
||||
|
||||
package My::AuthBasic;
|
||||
|
||||
# Load Auth Basic Handler
|
||||
use Lemonldap::NG::Handler::SpecificHandlers::AuthBasic;
|
||||
@ISA = qw(Lemonldap::NG::Handler::SpecificHandlers::AuthBasic);
|
||||
|
||||
__PACKAGE__->init(
|
||||
{
|
||||
|
||||
# See Lemonldap::NG::Handler
|
||||
}
|
||||
);
|
||||
|
||||
1;
|
|
@ -1,16 +0,0 @@
|
|||
# Handler for Secure Token
|
||||
|
||||
package My::SecureToken;
|
||||
|
||||
# Load Secure Token Handler
|
||||
use Lemonldap::NG::Handler::SpecificHandlers::SecureToken;
|
||||
@ISA = qw(Lemonldap::NG::Handler::SpecificHandlers::SecureToken);
|
||||
|
||||
__PACKAGE__->init(
|
||||
{
|
||||
|
||||
# See Lemonldap::NG::Handler
|
||||
}
|
||||
);
|
||||
|
||||
1;
|
|
@ -1,16 +0,0 @@
|
|||
# Handler for Sympa autologin
|
||||
|
||||
package My::Sympa;
|
||||
|
||||
# Load Sympa Handler
|
||||
use Lemonldap::NG::Handler::SpecificHandlers::SympaAutoLogin;
|
||||
@ISA = qw(Lemonldap::NG::Handler::SpecificHandlers::SympaAutoLogin);
|
||||
|
||||
__PACKAGE__->init(
|
||||
{
|
||||
|
||||
# See Lemonldap::NG::Handler
|
||||
}
|
||||
);
|
||||
|
||||
1;
|
|
@ -1,16 +0,0 @@
|
|||
# Handler for Zimbra preauthentication
|
||||
|
||||
package My::Zimbra;
|
||||
|
||||
# Load Zimbra Handler
|
||||
use Lemonldap::NG::Handler::SpecificHandlers::ZimbraPreAuth;
|
||||
@ISA = qw(Lemonldap::NG::Handler::SpecificHandlers::ZimbraPreAuth);
|
||||
|
||||
__PACKAGE__->init(
|
||||
{
|
||||
|
||||
# See Lemonldap::NG::Handler
|
||||
}
|
||||
);
|
||||
|
||||
1;
|
|
@ -1,14 +0,0 @@
|
|||
# Handler to manage update cookie
|
||||
package My::Package::UpdateCookie;
|
||||
|
||||
use Lemonldap::NG::Handler::SpecificHandlers::UpdateCookie;
|
||||
@ISA = qw(Lemonldap::NG::Handler::SpecificHandlers::UpdateCookie);
|
||||
|
||||
__PACKAGE__->init(
|
||||
{
|
||||
|
||||
# See Lemonldap::NG::Handler
|
||||
}
|
||||
);
|
||||
|
||||
1;
|
|
@ -1,292 +0,0 @@
|
|||
##@file
|
||||
# Auth-basic authentication with Lemonldap::NG rights management
|
||||
|
||||
##@class
|
||||
# Auth-basic authentication with Lemonldap::NG rights management
|
||||
|
||||
# This specific handler is intended to be called by a handler caller
|
||||
# old working, kept for compatibility with previous 1.4.0 versions
|
||||
|
||||
package Lemonldap::NG::Handler::AuthBasic;
|
||||
|
||||
use strict;
|
||||
|
||||
use Lemonldap::NG::Handler::DefaultHandler qw(:all);
|
||||
use Digest::MD5 qw(md5_base64);
|
||||
use MIME::Base64;
|
||||
use HTTP::Headers;
|
||||
use SOAP::Lite; # link protected portalRequest
|
||||
use Lemonldap::NG::Handler::Main::Headers;
|
||||
use Lemonldap::NG::Handler::Main::Logger;
|
||||
use Lemonldap::NG::Common::Session;
|
||||
|
||||
use base qw(Lemonldap::NG::Handler::DefaultHandler);
|
||||
use utf8;
|
||||
no utf8;
|
||||
|
||||
our $VERSION = '1.4.0';
|
||||
|
||||
# We need just this constant, that's why Portal is 'required' but not 'used'
|
||||
*PE_OK = *Lemonldap::NG::Portal::SharedConf::PE_OK;
|
||||
|
||||
# Apache constants
|
||||
BEGIN {
|
||||
if ( MP() == 2 ) {
|
||||
*AUTH_REQUIRED = \&Apache2::Const::AUTH_REQUIRED;
|
||||
require Apache2::Access;
|
||||
}
|
||||
elsif ( MP() == 0 ) {
|
||||
eval 'sub AUTH_REQUIRED {1}';
|
||||
}
|
||||
}
|
||||
|
||||
## @rmethod int run(Apache2::RequestRec apacheRequest)
|
||||
# overload run subroutine to implement Auth-Basic mechanism.
|
||||
# @param $apacheRequest current request
|
||||
# @return Apache constant
|
||||
sub run ($$) {
|
||||
my $class;
|
||||
( $class, $apacheRequest ) = splice @_;
|
||||
if ( time() - $lastReload > $reloadTime ) {
|
||||
unless ( my $tmp = $class->testConf(1) == OK ) {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"$class: No configuration found", 'error' );
|
||||
return $tmp;
|
||||
}
|
||||
}
|
||||
return DECLINED unless ( $apacheRequest->is_initial_req );
|
||||
my $uri = $apacheRequest->uri
|
||||
. ( $apacheRequest->args ? "?" . $apacheRequest->args : "" );
|
||||
|
||||
# AUTHENTICATION
|
||||
# I - recover the WWW-Authentication header
|
||||
my ( $id, $user, $pass );
|
||||
unless (
|
||||
$user = Lemonldap::NG::Handler::Main::Headers->lmHeaderIn(
|
||||
$apacheRequest, 'Authorization'
|
||||
)
|
||||
)
|
||||
{
|
||||
Lemonldap::NG::Handler::Main::Headers->lmSetErrHeaderOut(
|
||||
$apacheRequest,
|
||||
'WWW-Authenticate' => 'Basic realm="LemonLDAP::NG"' );
|
||||
return AUTH_REQUIRED;
|
||||
}
|
||||
$user =~ s/^Basic\s*//;
|
||||
|
||||
# ID for local cache
|
||||
$id = md5_base64($user);
|
||||
|
||||
# II - recover the user datas
|
||||
# 2.1 search if the user was the same as previous (very efficient in
|
||||
# persistent connection).
|
||||
unless ( $id eq $datas->{_cache_id} ) {
|
||||
|
||||
# 2.2 search in the local cache if exists
|
||||
my $session_id;
|
||||
unless ($tsv->{refLocalStorage}
|
||||
and $session_id = $tsv->{refLocalStorage}->get($id) )
|
||||
{
|
||||
|
||||
# 2.3 Authentication by Lemonldap::NG::Portal using SOAP request
|
||||
|
||||
# Add client IP as X-Forwarded-For IP in SOAP request
|
||||
my $xheader =
|
||||
Lemonldap::NG::Handler::Main::Headers->lmHeaderIn( $apacheRequest,
|
||||
'X-Forwarded-For' );
|
||||
$xheader .= ", " if ($xheader);
|
||||
$xheader .= $class->ip();
|
||||
my $soapHeaders =
|
||||
HTTP::Headers->new( "X-Forwarded-For" => $xheader );
|
||||
|
||||
my $soap =
|
||||
SOAP::Lite->proxy( $class->portal(),
|
||||
default_headers => $soapHeaders )
|
||||
->uri('urn:Lemonldap::NG::Common::CGI::SOAPService');
|
||||
$user = decode_base64($user);
|
||||
( $user, $pass ) = ( $user =~ /^(.*?):(.*)$/ );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"AuthBasic authentication for user: $user", 'debug' );
|
||||
my $r = $soap->getCookies( $user, $pass );
|
||||
|
||||
# Catch SOAP errors
|
||||
if ( $r->fault ) {
|
||||
return $class->abort( "SOAP request to the portal failed: "
|
||||
. $r->fault->{faultstring} );
|
||||
}
|
||||
else {
|
||||
my $res = $r->result();
|
||||
|
||||
# If authentication failed, display error
|
||||
if ( $res->{errorCode} ) {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Authentication failed for $user: "
|
||||
. $soap->error( $res->{errorCode}, 'en' )->result(),
|
||||
'notice'
|
||||
);
|
||||
Lemonldap::NG::Handler::Main::Headers->lmSetErrHeaderOut(
|
||||
$apacheRequest,
|
||||
'WWW-Authenticate' => 'Basic realm="LemonLDAP::NG"' );
|
||||
return AUTH_REQUIRED;
|
||||
}
|
||||
$session_id = $res->{cookies}->{ $tsv->{cookieName} };
|
||||
}
|
||||
}
|
||||
|
||||
# Get the session
|
||||
my $apacheSession = Lemonldap::NG::Common::Session->new(
|
||||
{
|
||||
storageModule => $tsv->{globalStorage},
|
||||
storageModuleOptions => $tsv->{globalStorageOptions},
|
||||
cacheModule => $tsv->{localSessionStorage},
|
||||
cacheModuleOptions => $tsv->{localSessionStorageOptions},
|
||||
id => $session_id,
|
||||
kind => "SSO",
|
||||
}
|
||||
);
|
||||
|
||||
unless ( $apacheSession->data ) {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"The cookie $session_id isn't yet available", 'info' );
|
||||
$class->updateStatus( $class->ip(), $apacheRequest->uri,
|
||||
'EXPIRED' );
|
||||
return $class->goToPortal($uri);
|
||||
}
|
||||
|
||||
$datas->{$_} = $apacheSession->data->{$_}
|
||||
foreach ( keys %{ $apacheSession->data } );
|
||||
$datas->{_cache_id} = $id;
|
||||
|
||||
# Store now the user in the local storage
|
||||
if ( $tsv->{refLocalStorage} ) {
|
||||
$tsv->{refLocalStorage}
|
||||
->set( $id, $datas->{_session_id}, "20 minutes" );
|
||||
}
|
||||
}
|
||||
|
||||
# ACCOUNTING
|
||||
# 1 - Inform Apache
|
||||
$class->lmSetApacheUser( $apacheRequest, $datas->{ $tsv->{whatToTrace} } );
|
||||
|
||||
# AUTHORIZATION
|
||||
return $class->forbidden($uri) unless ( $class->grant($uri) );
|
||||
$class->updateStatus( $datas->{ $tsv->{whatToTrace} },
|
||||
$apacheRequest->uri, 'OK' );
|
||||
$class->logGranted( $uri, $datas );
|
||||
|
||||
# SECURITY
|
||||
# Hide Lemonldap::NG cookie
|
||||
$class->hideCookie;
|
||||
|
||||
# Hide user password
|
||||
Lemonldap::NG::Handler::Main::Headers->lmUnsetHeaderIn( $apacheRequest,
|
||||
"Authorization" );
|
||||
|
||||
# ACCOUNTING
|
||||
# 2 - Inform remote application
|
||||
Lemonldap::NG::Handler::Main::Headers->sendHeaders( $apacheRequest,
|
||||
$tsv->{forgeHeaders} );
|
||||
|
||||
OK;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
=encoding utf8
|
||||
|
||||
Lemonldap::NG::Handler::AuthBasic - Perl extension to be able to authenticate
|
||||
users by basic web system but to use Lemonldap::NG to control authorizations.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
Create your own package:
|
||||
|
||||
package My::Package;
|
||||
use Lemonldap::NG::Handler::AuthBasic;
|
||||
|
||||
# IMPORTANT ORDER
|
||||
our @ISA = qw (Lemonldap::NG::Handler::AuthBasic);
|
||||
|
||||
__PACKAGE__->init ( {
|
||||
# Local storage used for sessions and configuration
|
||||
localStorage => "Cache::DBFile",
|
||||
localStorageOptions => {...},
|
||||
# How to get my configuration
|
||||
configStorage => {
|
||||
type => "DBI",
|
||||
dbiChain => "DBI:mysql:database=lemondb;host=$hostname",
|
||||
dbiUser => "lemonldap",
|
||||
dbiPassword => "password",
|
||||
}
|
||||
# Uncomment this to activate status module
|
||||
# status => 1,
|
||||
} );
|
||||
|
||||
Call your package in <apache-directory>/conf/httpd.conf
|
||||
|
||||
PerlRequire MyFile
|
||||
PerlHeaderParserHandler My::Package
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This library provides a way to use Lemonldap::NG to manage authorizations
|
||||
without using Lemonldap::NG for authentications. This can be used in conjunction
|
||||
with a normal Lemonldap::NG installation but to manage non-browser clients.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Lemonldap::NG::Handler(3)>,
|
||||
L<http://lemonldap-ng.org/>
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
=over
|
||||
|
||||
=item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=item François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt>
|
||||
|
||||
=item Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUG REPORT
|
||||
|
||||
Use OW2 system to report bug or ask for features:
|
||||
L<http://jira.ow2.org>
|
||||
|
||||
=head1 DOWNLOAD
|
||||
|
||||
Lemonldap::NG is available at
|
||||
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
=over
|
||||
|
||||
=item Copyright (C) 2008, 2009, 2010 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
||||
|
||||
=item Copyright (C) 2012, 2013 by François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt>
|
||||
|
||||
=item Copyright (C) 2010, 2011, 2012 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=back
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see L<http://www.gnu.org/licenses/>.
|
||||
|
||||
=cut
|
|
@ -1,383 +0,0 @@
|
|||
##@file
|
||||
# Secure Token
|
||||
|
||||
##@class
|
||||
# Secure Token
|
||||
#
|
||||
# Create a secure token used to resolve user identity by a protected application
|
||||
|
||||
# This specific handler is intended to be called by a handler caller
|
||||
# old working, kept for compatibility with previous 1.4.0 versions
|
||||
|
||||
package Lemonldap::NG::Handler::SecureToken;
|
||||
|
||||
use strict;
|
||||
use Lemonldap::NG::Handler::DefaultHandler qw(:all);
|
||||
use base qw(Lemonldap::NG::Handler::DefaultHandler);
|
||||
use Cache::Memcached;
|
||||
use Apache::Session::Generate::MD5;
|
||||
use Lemonldap::NG::Handler::Main::Headers;
|
||||
use Lemonldap::NG::Handler::Main::Logger;
|
||||
|
||||
our $VERSION = '1.1.2';
|
||||
|
||||
# Shared variables
|
||||
our (
|
||||
$secureTokenMemcachedServers, $secureTokenExpiration,
|
||||
$secureTokenAttribute, $secureTokenUrls,
|
||||
$secureTokenHeader, $datas,
|
||||
$secureTokenMemcachedConnection, $secureTokenAllowOnError,
|
||||
);
|
||||
|
||||
BEGIN {
|
||||
eval {
|
||||
require threads::shared;
|
||||
threads::share($secureTokenMemcachedConnection);
|
||||
};
|
||||
}
|
||||
|
||||
## @imethod protected void globalInit(hashRef args)
|
||||
# Overload globalInit to launch this class defaultValuesInit
|
||||
# @param $args reference to the configuration hash
|
||||
sub globalInit {
|
||||
my $class = shift;
|
||||
__PACKAGE__->defaultValuesInit(@_);
|
||||
$class->SUPER::globalInit(@_);
|
||||
}
|
||||
|
||||
## @imethod protected void defaultValuesInit(hashRef args)
|
||||
# Overload defaultValuesInit
|
||||
# @param $args reference to the configuration hash
|
||||
sub defaultValuesInit {
|
||||
my ( $class, $args ) = splice @_;
|
||||
|
||||
# Catch Secure Token parameters
|
||||
$secureTokenMemcachedServers =
|
||||
$args->{'secureTokenMemcachedServers'}
|
||||
|| $secureTokenMemcachedServers
|
||||
|| ['127.0.0.1:11211'];
|
||||
$secureTokenExpiration =
|
||||
$args->{'secureTokenExpiration'}
|
||||
|| $secureTokenExpiration
|
||||
|| '60';
|
||||
$secureTokenAttribute =
|
||||
$args->{'secureTokenAttribute'}
|
||||
|| $secureTokenAttribute
|
||||
|| 'uid';
|
||||
$secureTokenUrls = $args->{'secureTokenUrls'} || $secureTokenUrls || ['.*'];
|
||||
$secureTokenHeader =
|
||||
$args->{'secureTokenHeader'}
|
||||
|| $secureTokenHeader
|
||||
|| 'Auth-Token';
|
||||
$args->{'secureTokenAllowOnError'} = 1
|
||||
unless defined $args->{'secureTokenAllowOnError'};
|
||||
$secureTokenAllowOnError =
|
||||
defined $secureTokenAllowOnError
|
||||
? $secureTokenAllowOnError
|
||||
: $args->{'secureTokenAllowOnError'};
|
||||
|
||||
# Force some parameters to be array references
|
||||
foreach (qw/secureTokenMemcachedServers secureTokenUrls/) {
|
||||
no strict 'refs';
|
||||
unless ( ref ${$_} eq "ARRAY" ) {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Transform $_ value into an array reference", 'debug' );
|
||||
my @array = split( /\s+/, ${$_} );
|
||||
${$_} = \@array;
|
||||
}
|
||||
}
|
||||
|
||||
# Display found values in debug mode
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"secureTokenMemcachedServers: @$secureTokenMemcachedServers", 'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"secureTokenExpiration: $secureTokenExpiration", 'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"secureTokenAttribute: $secureTokenAttribute", 'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"secureTokenUrls: @$secureTokenUrls", 'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"secureTokenHeader: $secureTokenHeader", 'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"secureTokenAllowOnError: $secureTokenAllowOnError", 'debug' );
|
||||
|
||||
# Delete Secure Token parameters
|
||||
delete $args->{'secureTokenMemcachedServers'};
|
||||
delete $args->{'secureTokenExpiration'};
|
||||
delete $args->{'secureTokenAttribute'};
|
||||
delete $args->{'secureTokenUrls'};
|
||||
delete $args->{'secureTokenHeader'};
|
||||
delete $args->{'secureTokenAllowOnError'};
|
||||
|
||||
# Call main subroutine
|
||||
return $class->SUPER::defaultValuesInit($args);
|
||||
}
|
||||
|
||||
## @rmethod Apache2::Const run(Apache2::RequestRec r)
|
||||
# Overload main run method
|
||||
# @param r Current request
|
||||
# @return Apache2::Const value (OK, FORBIDDEN, REDIRECT or SERVER_ERROR)
|
||||
sub run {
|
||||
my $class = shift;
|
||||
my $r = $_[0];
|
||||
my $ret = $class->SUPER::run(@_);
|
||||
|
||||
# Continue only if user is authorized
|
||||
return $ret unless ( $ret == OK );
|
||||
|
||||
# Get current URI
|
||||
my $args = $r->args;
|
||||
my $uri = $r->uri . ( $args ? "?$args" : "" );
|
||||
|
||||
# Return if we are not on a secure token URL
|
||||
my $checkurl = 0;
|
||||
foreach (@$secureTokenUrls) {
|
||||
if ( $uri =~ m#$_# ) {
|
||||
$checkurl = 1;
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"URL $uri detected as an Secure Token URL (rule $_)", 'debug' );
|
||||
last;
|
||||
}
|
||||
}
|
||||
return OK unless ($checkurl);
|
||||
|
||||
# Test Memcached connection
|
||||
unless ( $class->_isAlive() ) {
|
||||
$secureTokenMemcachedConnection = $class->_createMemcachedConnection();
|
||||
}
|
||||
|
||||
# Exit if no connection
|
||||
return $class->_returnError() unless $class->_isAlive();
|
||||
|
||||
# Value to store
|
||||
my $value = $datas->{$secureTokenAttribute};
|
||||
|
||||
# Set token
|
||||
my $key = $class->_setToken($value);
|
||||
return $class->_returnError() unless $key;
|
||||
|
||||
# Header location
|
||||
Lemonldap::NG::Handler::Main::Headers->lmSetHeaderIn( $r,
|
||||
$secureTokenHeader => $key );
|
||||
|
||||
# Remove token
|
||||
eval 'use Apache2::Filter' unless ( $INC{"Apache2/Filter.pm"} );
|
||||
|
||||
$r->add_output_filter(
|
||||
sub {
|
||||
my $f = shift;
|
||||
while ( $f->read( my $buffer, 1024 ) ) {
|
||||
$f->print($buffer);
|
||||
}
|
||||
if ( $f->seen_eos ) {
|
||||
$class->_deleteToken($key);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
);
|
||||
|
||||
# Return OK
|
||||
return OK;
|
||||
}
|
||||
|
||||
## @method private Cache::Memcached _createMemcachedConnection
|
||||
# Create Memcached connexion
|
||||
# @return Cache::Memcached object
|
||||
sub _createMemcachedConnection {
|
||||
my ($class) = splice @_;
|
||||
|
||||
# Open memcached connexion
|
||||
my $memd = new Cache::Memcached {
|
||||
'servers' => $secureTokenMemcachedServers,
|
||||
'debug' => 0,
|
||||
};
|
||||
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "Memcached connection created",
|
||||
'debug' );
|
||||
|
||||
return $memd;
|
||||
}
|
||||
|
||||
## @method private string _setToken(string value)
|
||||
# Set token value
|
||||
# @param value Value
|
||||
# @return Token key
|
||||
sub _setToken {
|
||||
my ( $class, $value ) = splice @_;
|
||||
|
||||
my $key = Apache::Session::Generate::MD5::generate();
|
||||
|
||||
my $res =
|
||||
$secureTokenMemcachedConnection->set( $key, $value,
|
||||
$secureTokenExpiration );
|
||||
|
||||
unless ($res) {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Unable to store secure token $key", 'error' );
|
||||
return;
|
||||
}
|
||||
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "Set $value in token $key",
|
||||
'info' );
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
## @method private boolean _deleteToken(string key)
|
||||
# Delete token
|
||||
# @param key Key
|
||||
# @return result
|
||||
sub _deleteToken {
|
||||
my ( $class, $key ) = splice @_;
|
||||
|
||||
my $res = $secureTokenMemcachedConnection->delete($key);
|
||||
|
||||
unless ($res) {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Unable to delete secure token $key", 'error' );
|
||||
}
|
||||
else {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "Token $key deleted",
|
||||
'info' );
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
## @method private boolean _isAlive()
|
||||
# Run a STATS command to see if Memcached connection is alive
|
||||
# @param connection Cache::Memcached object
|
||||
# @return result
|
||||
sub _isAlive {
|
||||
my ($class) = splice @_;
|
||||
|
||||
return 0 unless defined $secureTokenMemcachedConnection;
|
||||
|
||||
my $stats = $secureTokenMemcachedConnection->stats();
|
||||
|
||||
if ( $stats and defined $stats->{'total'} ) {
|
||||
my $total_c = $stats->{'total'}->{'connection_structures'};
|
||||
my $total_i = $stats->{'total'}->{'total_items'};
|
||||
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Memcached connection is alive ($total_c connections / $total_i items)",
|
||||
'debug'
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Memcached connection is not alive", 'error' );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
## @method private int _returnError()
|
||||
# Give hand back to Apache
|
||||
# @return Apache2::Const value
|
||||
sub _returnError {
|
||||
my ($class) = splice @_;
|
||||
|
||||
if ($secureTokenAllowOnError) {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Allow request without secure token", 'debug' );
|
||||
return OK;
|
||||
}
|
||||
|
||||
# Redirect or Forbidden?
|
||||
if ( $tsv->{useRedirectOnError} ) {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "Use redirect for error",
|
||||
'debug' );
|
||||
return $class->goToPortal( '/', 'lmError=500' );
|
||||
}
|
||||
|
||||
else {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "Return error", 'debug' );
|
||||
return SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
=encoding utf8
|
||||
|
||||
Lemonldap::NG::Handler::SecureToken - Perl extension to generate a secure token
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package My::SecureToken;
|
||||
use Lemonldap::NG::Handler::SecureToken;
|
||||
@ISA = qw(Lemonldap::NG::Handler::SecureToken);
|
||||
|
||||
__PACKAGE__->init ( {
|
||||
|
||||
# See Lemonldap::NG::Handler for more
|
||||
|
||||
} );
|
||||
1;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Edit your vhost configuration like this:
|
||||
|
||||
<VirtualHost *>
|
||||
ServerName secure.example.com
|
||||
|
||||
# Load Secure Token Handler
|
||||
PerlRequire __HANDLERDIR__/MyHandlerSecureToken.pm
|
||||
PerlHeaderParserHandler My::SecureToken
|
||||
|
||||
</VirtualHost>
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
See L<Lemonldap::NG::Handler>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Lemonldap::NG::Handler>
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
=over
|
||||
|
||||
=item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUG REPORT
|
||||
|
||||
Use OW2 system to report bug or ask for features:
|
||||
L<http://jira.ow2.org>
|
||||
|
||||
=head1 DOWNLOAD
|
||||
|
||||
Lemonldap::NG is available at
|
||||
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
=over
|
||||
|
||||
=item Copyright (C) 2011, 2012 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=back
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see L<http://www.gnu.org/licenses/>.
|
||||
|
|
@ -1,205 +0,0 @@
|
|||
##@file
|
||||
# Sympa autologin
|
||||
|
||||
##@class
|
||||
# Sympa autologin
|
||||
#
|
||||
# Build Sympa cookie and send it to Sympa
|
||||
|
||||
# This specific handler is intended to be called by a handler caller
|
||||
# old working, kept for compatibility with previous 1.4.0 versions
|
||||
|
||||
package Lemonldap::NG::Handler::SympaAutoLogin;
|
||||
|
||||
use strict;
|
||||
use Lemonldap::NG::Handler::DefaultHandler qw(:all);
|
||||
use base qw(Lemonldap::NG::Handler::DefaultHandler);
|
||||
use Digest::MD5;
|
||||
use Lemonldap::NG::Handler::Main::Headers;
|
||||
use Lemonldap::NG::Handler::Main::Logger;
|
||||
|
||||
our $VERSION = '1.1.2';
|
||||
|
||||
# Shared variables
|
||||
our ( $sympaSecret, $sympaMailKey );
|
||||
|
||||
## @imethod protected void globalInit(hashRef args)
|
||||
# Overload globalInit to launch this class defaultValuesInit
|
||||
# @param $args reference to the configuration hash
|
||||
sub globalInit {
|
||||
my $class = shift;
|
||||
__PACKAGE__->defaultValuesInit(@_);
|
||||
$class->SUPER::globalInit(@_);
|
||||
}
|
||||
|
||||
## @imethod protected void defaultValuesInit(hashRef args)
|
||||
# Overload defaultValuesInit
|
||||
# @param $args reference to the configuration hash
|
||||
sub defaultValuesInit {
|
||||
my ( $class, $args ) = splice @_;
|
||||
|
||||
# Sympa secret should be in configuration
|
||||
$sympaSecret = $args->{'sympaSecret'} || $sympaSecret;
|
||||
|
||||
# If not, try to read it from /etc/lemonldap-ng/sympa.secret
|
||||
if ( !$sympaSecret and -r '/etc/lemonldap-ng/sympa.secret' ) {
|
||||
open S, '/etc/lemonldap-ng/sympa.secret'
|
||||
or die("Unable to open /etc/lemonldap-ng/sympa.secret");
|
||||
$sympaSecret = join( '', <S> );
|
||||
close S;
|
||||
$sympaSecret =~ s/[\r\n]//g;
|
||||
}
|
||||
|
||||
# Sympa mail key
|
||||
$sympaMailKey = $args->{'sympaMailKey'} || $sympaMailKey || "mail";
|
||||
|
||||
# Display found values in debug mode
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "sympaSecret: $sympaSecret",
|
||||
'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "sympaMailKey: $sympaMailKey",
|
||||
'debug' );
|
||||
|
||||
# Delete Sympa parameters
|
||||
delete $args->{'sympaSecret'};
|
||||
delete $args->{'sympaMailKey'};
|
||||
|
||||
# Call main subroutine
|
||||
return $class->SUPER::defaultValuesInit($args);
|
||||
}
|
||||
|
||||
## @rmethod Apache2::Const run(Apache2::RequestRec r)
|
||||
# Overload main run method
|
||||
# @param r Current request
|
||||
# @return Apache2::Const value (OK, FORBIDDEN, REDIRECT or SERVER_ERROR)
|
||||
sub run {
|
||||
my $class = shift;
|
||||
my $r = $_[0];
|
||||
my $ret = $class->SUPER::run(@_);
|
||||
|
||||
# Continue only if user is authorized
|
||||
return $ret unless ( $ret == OK );
|
||||
|
||||
# Fail if no sympaSecret
|
||||
return $class->abort("No Sympa secret configured")
|
||||
unless ($sympaSecret);
|
||||
|
||||
# Mail value
|
||||
my $mail = $datas->{$sympaMailKey};
|
||||
|
||||
# Building Sympa cookie
|
||||
my $tmp = new Digest::MD5;
|
||||
$tmp->reset;
|
||||
$tmp->add( $mail . $sympaSecret );
|
||||
my $str = "sympauser=$mail:" . substr( unpack( "H*", $tmp->digest ), -8 );
|
||||
|
||||
# Get cookie header, removing Sympa cookie if exists (avoid security
|
||||
# problems) and set the new value
|
||||
$tmp = Lemonldap::NG::Handler::Main::Headers->lmHeaderIn( $r, 'Cookie' );
|
||||
$tmp =~ s/\bsympauser=[^,;]*[,;]?//;
|
||||
$tmp .= $tmp ? ";$str" : $str;
|
||||
Lemonldap::NG::Handler::Main::Headers->lmSetHeaderIn( $r,
|
||||
'Cookie' => $tmp );
|
||||
|
||||
# Return SUPER::run() result
|
||||
return $ret;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
=encoding utf8
|
||||
|
||||
Lemonldap::NG::Handler::SympaAutoLogin - Perl extension to generate Sympa cookie
|
||||
for users authenticated by LemonLDAP::NG
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package My::Sympa;
|
||||
use Lemonldap::NG::Handler::SympaAutoLogin;
|
||||
@ISA = qw(Lemonldap::NG::Handler::SympaAutoLogin);
|
||||
|
||||
__PACKAGE__->init ( {
|
||||
|
||||
# Sympa parameters
|
||||
sympaSecret => 'XXXX',
|
||||
sympaMailKey => 'mail',
|
||||
|
||||
# See Lemonldap::NG::Handler for more
|
||||
} );
|
||||
1;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Lemonldap::NG::Handler::SympaAutoLogin is a special Lemonldap::NG handler that
|
||||
generates Sympa cookie for authenticated users. Use it instead of classic
|
||||
Lemonldap::NG::Handler to protect your Sympa web server. You have to set the
|
||||
configuration key containing user email (parameter sympaMailKey) and to
|
||||
store Sympa secret (cookie parameter on Sympa configuration file) in the
|
||||
corresponding configuration parameter (sympaSecret)
|
||||
|
||||
Edit you Sympa vhost configuration like this:
|
||||
|
||||
<VirtualHost *>
|
||||
ServerName sympa.example.com
|
||||
|
||||
# Load Sympa Handler
|
||||
PerlRequire __HANDLERDIR__/MyHandlerSympa.pm
|
||||
PerlHeaderParserHandler My::Sympa
|
||||
|
||||
</VirtualHost>
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
See L<Lemonldap::NG::Handler>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Lemonldap::NG::Handler>
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
=over
|
||||
|
||||
=item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=item Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUG REPORT
|
||||
|
||||
Use OW2 system to report bug or ask for features:
|
||||
L<http://jira.ow2.org>
|
||||
|
||||
=head1 DOWNLOAD
|
||||
|
||||
Lemonldap::NG is available at
|
||||
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
=over
|
||||
|
||||
=item Copyright (C) 2009, 2010 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
||||
|
||||
=item Copyright (C) 2010, 2011, 2012 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=back
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see L<http://www.gnu.org/licenses/>.
|
||||
|
||||
=cut
|
|
@ -1,181 +0,0 @@
|
|||
## @file
|
||||
# Lemonldap::NG special handler
|
||||
|
||||
## @class
|
||||
# Lemonldap::NG special handler
|
||||
|
||||
# This specific handler is intended to be called by a handler caller
|
||||
# old working, kept for compatibility with previous 1.4.0 versions
|
||||
|
||||
package Lemonldap::NG::Handler::UpdateCookie;
|
||||
|
||||
use strict;
|
||||
use Lemonldap::NG::Handler::DefaultHandler qw(:all);
|
||||
use base qw(Lemonldap::NG::Handler::DefaultHandler);
|
||||
use Lemonldap::NG::Handler::Main::Headers;
|
||||
use Lemonldap::NG::Handler::Main::Logger;
|
||||
use Lemonldap::NG::Common::Session;
|
||||
|
||||
our $VERSION = '1.4.0';
|
||||
|
||||
## @rmethod int run(Apache2::RequestRec apacheRequest)
|
||||
# Main method used to control access.
|
||||
# Calls :
|
||||
# - fetchId()
|
||||
# - fetchUTime()
|
||||
# - SUPER::run()
|
||||
# @param $apacheRequest Current request
|
||||
# @return Apache2::Const value (OK, FORBIDDEN, REDIRECT or SERVER_ERROR)
|
||||
sub run {
|
||||
my $class = shift;
|
||||
$apacheRequest = $_[0];
|
||||
|
||||
# I - Recover the main cookie.
|
||||
# If not present, then call parent.
|
||||
my $id;
|
||||
if ( $id = $class->SUPER::fetchId ) {
|
||||
|
||||
# II - Found update cookie.
|
||||
# If found, remove session from local cache when utime is recent.
|
||||
my $utime;
|
||||
if ( $utime = $class->fetchUTime ) {
|
||||
my $clear = 0;
|
||||
|
||||
my $apacheSession = Lemonldap::NG::Common::Session->new(
|
||||
{
|
||||
storageModule => $tsv->{globalStorage},
|
||||
storageModuleOptions => $tsv->{globalStorageOptions},
|
||||
cacheModule => $tsv->{localSessionStorage},
|
||||
cacheModuleOptions => $tsv->{localSessionStorageOptions},
|
||||
id => $id,
|
||||
kind => "SSO",
|
||||
}
|
||||
);
|
||||
|
||||
# Check process data
|
||||
if ( $id eq $datas->{_session_id} and $datas->{_utime} lt $utime ) {
|
||||
$datas->{_session_id} = 0;
|
||||
$clear = 1;
|
||||
}
|
||||
|
||||
# Get session
|
||||
else {
|
||||
unless ( $apacheSession->data ) {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Session $id can't be retrieved", 'info' );
|
||||
}
|
||||
else {
|
||||
$clear = 1 if ( $apacheSession->data->{_utime} lt $utime );
|
||||
}
|
||||
}
|
||||
|
||||
# Clear cache if needed
|
||||
if ($clear) {
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"$class: remove $id from local cache", 'debug' );
|
||||
$apacheSession->cacheUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# III - Call parent process.
|
||||
$class->SUPER::run(@_);
|
||||
}
|
||||
|
||||
## @rmethod protected $ fetchUTime()
|
||||
# Get user cookies and search for Lemonldap::NG update cookie.
|
||||
# @return Value of the cookie if found, 0 else
|
||||
sub fetchUTime {
|
||||
my $t = Lemonldap::NG::Handler::Main::Headers->lmHeaderIn( $apacheRequest,
|
||||
'Cookie' );
|
||||
my $c = $tsv->{cookieName} . 'update';
|
||||
return ( $t =~ /$c=([^,; ]+)/o ) ? $1 : 0;
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
=encoding utf8
|
||||
|
||||
Lemonldap::NG::Handler::UpdateCookie - Perl extension to manage update
|
||||
cookie sent by client, to reload session in local cache.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package My::Package;
|
||||
use Lemonldap::NG::Handler::UpdateCookie;
|
||||
@ISA = qw(Lemonldap::NG::Handler::DefaultHandler);
|
||||
|
||||
__PACKAGE__->init ( {
|
||||
# See Lemonldap::NG::Handler for more
|
||||
# Local storage used for sessions and configuration
|
||||
} );
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Lemonldap::NG::Handler::UpdateCookie is a special Lemonldap::NG:: handler that
|
||||
allow a session to be removed from local cache of the current handler, if a
|
||||
update cookie is sent by the user.
|
||||
|
||||
The update cookie should be name "lemonldapupdate" and only contains a simple
|
||||
timestamp.
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
See L<Lemonldap::NG::Handler>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Lemonldap::NG::Handler>
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
=over
|
||||
|
||||
=item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=item Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
||||
|
||||
=item Thomas Chemineau, E<lt>thomas.chemineau@gmail.comE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUG REPORT
|
||||
|
||||
Use OW2 system to report bug or ask for features:
|
||||
L<http://jira.ow2.org>
|
||||
|
||||
=head1 DOWNLOAD
|
||||
|
||||
Lemonldap::NG is available at
|
||||
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
=over
|
||||
|
||||
=item Copyright (C) 2010 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
||||
|
||||
=item Copyright (C) 2010, 2012 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=item Copyright (C) 2010 by Thomas Chemineau, E<lt>thomas.chemineau@gmail.comE<gt>
|
||||
|
||||
=back
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see L<http://www.gnu.org/licenses/>.
|
||||
|
||||
=cut
|
|
@ -1,248 +0,0 @@
|
|||
##@file
|
||||
# Zimbra preauthentication
|
||||
|
||||
##@class
|
||||
# Zimbra preauthentication
|
||||
#
|
||||
# It will build Zimbra preauth URL
|
||||
|
||||
# This specific handler is intended to be called by a handler caller
|
||||
# old working, kept for compatibility with previous 1.4.0 versions
|
||||
|
||||
package Lemonldap::NG::Handler::ZimbraPreAuth;
|
||||
|
||||
use strict;
|
||||
use Lemonldap::NG::Handler::DefaultHandler qw(:all);
|
||||
use base qw(Lemonldap::NG::Handler::DefaultHandler);
|
||||
use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
|
||||
use Lemonldap::NG::Handler::Main::Headers;
|
||||
use Lemonldap::NG::Handler::Main::Logger;
|
||||
|
||||
our $VERSION = '1.0.0';
|
||||
|
||||
# Shared variables
|
||||
our ( $zimbraPreAuthKey, $zimbraAccountKey, $zimbraBy, $zimbraUrl,
|
||||
$zimbraSsoUrl, $timeout );
|
||||
|
||||
## @imethod protected void globalInit(hashRef args)
|
||||
# Overload globalInit to launch this class defaultValuesInit
|
||||
# @param $args reference to the configuration hash
|
||||
sub globalInit {
|
||||
my $class = shift;
|
||||
__PACKAGE__->defaultValuesInit(@_);
|
||||
$class->SUPER::globalInit(@_);
|
||||
}
|
||||
|
||||
## @imethod protected void defaultValuesInit(hashRef args)
|
||||
# Overload defaultValuesInit
|
||||
# @param $args reference to the configuration hash
|
||||
sub defaultValuesInit {
|
||||
my ( $class, $args ) = splice @_;
|
||||
|
||||
# Catch Zimbra parameters
|
||||
$zimbraPreAuthKey = $args->{'zimbraPreAuthKey'} || $zimbraPreAuthKey;
|
||||
$zimbraAccountKey =
|
||||
$args->{'zimbraAccountKey'}
|
||||
|| $zimbraAccountKey
|
||||
|| 'uid';
|
||||
$zimbraBy = $args->{'zimbraBy'} || $zimbraBy || 'id';
|
||||
$zimbraUrl = $args->{'zimbraUrl'} || $zimbraUrl || '/service/preauth';
|
||||
$zimbraSsoUrl = $args->{'zimbraSsoUrl'} || $zimbraSsoUrl || '^/zimbrasso$';
|
||||
$timeout = $args->{'timeout'} || $timeout || '0';
|
||||
|
||||
# Display found values in debug mode
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"zimbraPreAuthKey: $zimbraPreAuthKey", 'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"zimbraAccountKey: $zimbraAccountKey", 'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "zimbraBy: $zimbraBy",
|
||||
'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "zimbraUrl: $zimbraUrl",
|
||||
'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "zimbraSsoUrl: $zimbraSsoUrl",
|
||||
'debug' );
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog( "timeout: $timeout", 'debug' );
|
||||
|
||||
# Delete Zimbra parameters
|
||||
delete $args->{'zimbraPreAuthKey'};
|
||||
delete $args->{'zimbraAccountKey'};
|
||||
delete $args->{'zimbraBy'};
|
||||
delete $args->{'zimbraUrl'};
|
||||
delete $args->{'zimbraSsoUrl'};
|
||||
delete $args->{'timeout'};
|
||||
|
||||
# Call main subroutine
|
||||
return $class->SUPER::defaultValuesInit($args);
|
||||
}
|
||||
|
||||
## @rmethod Apache2::Const run(Apache2::RequestRec r)
|
||||
# Overload main run method
|
||||
# @param r Current request
|
||||
# @return Apache2::Const value (OK, FORBIDDEN, REDIRECT or SERVER_ERROR)
|
||||
sub run {
|
||||
my $class = shift;
|
||||
my $r = $_[0];
|
||||
my $ret = $class->SUPER::run(@_);
|
||||
|
||||
# Continue only if user is authorized
|
||||
return $ret unless ( $ret == OK );
|
||||
|
||||
# Get current URI
|
||||
my $args = $r->args;
|
||||
my $uri = $r->uri . ( $args ? "?$args" : "" );
|
||||
|
||||
# Return if we are not on a Zimbra SSO URI
|
||||
return OK unless ( $uri =~ $zimbraSsoUrl );
|
||||
|
||||
# Check mandatory parameters
|
||||
return $class->abort("No Zimbra preauth key configured")
|
||||
unless ($zimbraPreAuthKey);
|
||||
|
||||
# Build URL
|
||||
my $zimbra_url = $class->_buildZimbraPreAuthUrl(
|
||||
$zimbraPreAuthKey, $zimbraUrl,
|
||||
$datas->{$zimbraAccountKey}, $zimbraBy
|
||||
);
|
||||
|
||||
# Header location
|
||||
Lemonldap::NG::Handler::Main::Headers->lmSetHeaderOut( $r,
|
||||
'Location' => $zimbra_url );
|
||||
|
||||
# Return REDIRECT
|
||||
return REDIRECT;
|
||||
}
|
||||
|
||||
## @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 ( $class, $key, $url, $account, $by ) = splice @_;
|
||||
|
||||
# Expiration time is calculated with _utime and timeout
|
||||
my $expires = $timeout ? ( $datas->{_utime} + $timeout ) * 1000 : $timeout;
|
||||
|
||||
# Timestamp
|
||||
my $timestamp = time() * 1000;
|
||||
|
||||
# Compute preauth value
|
||||
my $computed_value =
|
||||
hmac_sha1_hex( "$account|$by|$expires|$timestamp", $key );
|
||||
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Compute value $account|$by|$expires|$timestamp into $computed_value",
|
||||
'debug' );
|
||||
|
||||
# Build PreAuth URL
|
||||
my $zimbra_url =
|
||||
"$url?account=$account&by=$by×tamp=$timestamp&expires=$expires&preauth=$computed_value";
|
||||
|
||||
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
||||
"Build Zimbra URL: $zimbra_url", 'debug' );
|
||||
|
||||
return $zimbra_url;
|
||||
}
|
||||
|
||||
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 ( {
|
||||
|
||||
# Zimbra parameters
|
||||
zimbraPreAuthKey => 'XXXX',
|
||||
zimbraAccountKey => 'uid',
|
||||
zimbraBy => 'id',
|
||||
zimbraUrl => '/service/preauth',
|
||||
zimbraSsoUrl => '^/zimbrasso$',
|
||||
|
||||
# Common parameters
|
||||
timeout => '72000',
|
||||
|
||||
# See Lemonldap::NG::Handler for more
|
||||
|
||||
} );
|
||||
1;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Edit you Zimbra vhost configuration like this:
|
||||
|
||||
<VirtualHost *>
|
||||
ServerName zimbra.example.com
|
||||
|
||||
# Load Zimbra Handler
|
||||
PerlRequire __HANDLERDIR__/MyHandlerZimbra.pm
|
||||
PerlHeaderParserHandler My::Zimbra
|
||||
|
||||
</VirtualHost>
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
See L<Lemonldap::NG::Handler>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<http://wiki.zimbra.com/wiki/Preauth>
|
||||
L<Lemonldap::NG::Handler>
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
=over
|
||||
|
||||
=item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=item Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
||||
|
||||
=back
|
||||
|
||||
=head1 BUG REPORT
|
||||
|
||||
Use OW2 system to report bug or ask for features:
|
||||
L<http://jira.ow2.org>
|
||||
|
||||
=head1 DOWNLOAD
|
||||
|
||||
Lemonldap::NG is available at
|
||||
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
=over
|
||||
|
||||
=item Copyright (C) 2010 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
||||
|
||||
=item Copyright (C) 2010, 2012 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
||||
|
||||
=back
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see L<http://www.gnu.org/licenses/>.
|
||||
|
||||
=cut
|
Loading…
Reference in New Issue
Block a user