- Merging branch lemonldap-ng-experimental/Handler-Mouse with with trunk

code impacted:
 * lemonldap-ng-handler/*: handler code,
 * lemonldap-ng-handler/example/*.pm: handler aliases to libraries,
 * _example/etc/*.conf: virtual host templates
(references #630, #LEMONLDAP-386)
This commit is contained in:
David COUTADEUR 2014-03-04 16:07:32 +00:00
parent a232f149fa
commit f993e2e6dd
28 changed files with 248 additions and 2820 deletions

View File

@ -6,7 +6,7 @@
#NameVirtualHost __VHOSTLISTEN__
# Load LemonLDAP::NG Handler
PerlRequire __HANDLER__
PerlRequire Lemonldap/NG/Handler/DefaultHandler.pm
# Common error page and security parameters
ErrorDocument 403 http://auth.__DNSDOMAIN__/?lmError=403
@ -23,7 +23,7 @@ ErrorDocument 503 http://auth.__DNSDOMAIN__/?lmError=503
Order deny,allow
Deny from all
Allow from 127.0.0.0/8
PerlHeaderParserHandler My::Package->refresh
PerlHeaderParserHandler Lemonldap::NG::Handler::DefaultHandler->refresh
</Location>
# Uncomment this to activate status module

View File

@ -7,7 +7,7 @@
# Load LemonLDAP::NG Handler
PerlOptions +GlobalRequest
PerlRequire __HANDLER__
PerlRequire Lemonldap/NG/Handler/DefaultHandler.pm
# Common error page and security parameters
ErrorDocument 403 http://auth.__DNSDOMAIN__/?lmError=403
@ -22,7 +22,7 @@ ErrorDocument 503 http://auth.__DNSDOMAIN__/?lmError=503
# configuration change
<Location /reload>
Require all granted
PerlHeaderParserHandler My::Package->refresh
PerlHeaderParserHandler Lemonldap::NG::Handler::DefaultHandler->refresh
</Location>
# Uncomment this to activate status module

View File

@ -7,7 +7,7 @@
# Load LemonLDAP::NG Handler
PerlOptions +GlobalRequest
PerlRequire __HANDLER__
PerlRequire Lemonldap/NG/Handler/DefaultHandler.pm
# Common error page and security parameters
ErrorDocument 403 http://auth.__DNSDOMAIN__/?lmError=403
@ -24,7 +24,7 @@ ErrorDocument 503 http://auth.__DNSDOMAIN__/?lmError=503
Order deny,allow
Deny from all
Allow from 127.0.0.0/8
PerlHeaderParserHandler My::Package->refresh
PerlHeaderParserHandler Lemonldap::NG::Handler::DefaultHandler->refresh
</Location>
# Uncomment this to activate status module

View File

@ -92,8 +92,8 @@
# Uncomment this to increase performance of Portal:
<Perl>
#require Lemonldap::NG::Portal::SharedConf;
#Lemonldap::NG::Portal::SharedConf->compile(
#require Lemonldap::NG::Portal::DefaultHandler;
#Lemonldap::NG::Portal::DefaultHandler->compile(
# qw(delete header cache read_from_client cookie redirect unescapeHTML));
# Uncomment this line if you use Lemonldap::NG menu
#require Lemonldap::NG::Portal::Menu;

View File

@ -97,8 +97,8 @@
# Uncomment this to increase performance of Portal:
<Perl>
#require Lemonldap::NG::Portal::SharedConf;
#Lemonldap::NG::Portal::SharedConf->compile(
#require Lemonldap::NG::Portal::DefaultHandler;
#Lemonldap::NG::Portal::DefaultHandler->compile(
# qw(delete header cache read_from_client cookie redirect unescapeHTML));
# Uncomment this line if you use Lemonldap::NG menu
#require Lemonldap::NG::Portal::Menu;

View File

@ -11,7 +11,7 @@
ServerAlias test2.__DNSDOMAIN__
# SSO protection
PerlHeaderParserHandler My::Package
PerlHeaderParserHandler Lemonldap::NG::Handler::DefaultHandler
# DocumentRoot
DocumentRoot __TESTDIR__

View File

@ -11,7 +11,7 @@
ServerAlias test2.__DNSDOMAIN__
# SSO protection
PerlHeaderParserHandler My::Package
PerlHeaderParserHandler Lemonldap::NG::Handler::DefaultHandler
# DocumentRoot
DocumentRoot __TESTDIR__

View File

@ -1,6 +1,6 @@
package My::Package;
use Lemonldap::NG::Handler::SharedConf;
@ISA = qw(Lemonldap::NG::Handler::SharedConf);
use Lemonldap::NG::Handler::DefaultHandler;
@ISA = qw(Lemonldap::NG::Handler::DefaultHandler);
__PACKAGE__->init(
{
@ -18,7 +18,7 @@ __PACKAGE__->init(
# You can specify by yourself this file :
#configStorage => { confFile => '/path/to/my/file' },
# You can also specify directly the configuration
# (see Lemonldap::NG::Handler::SharedConf(3))
# (see Lemonldap::NG::Handler::DefaultHandler(3))
#configStorage => {
# type => 'File',
# dirName => '/usr/local/lemonldap-ng/data/conf/'

View File

@ -3,8 +3,8 @@
package My::AuthBasic;
# Load Auth Basic Handler
use Lemonldap::NG::Handler::AuthBasic;
@ISA = qw(Lemonldap::NG::Handler::AuthBasic);
use Lemonldap::NG::Handler::SpecificHandlers::AuthBasic;
@ISA = qw(Lemonldap::NG::Handler::SpecificHandlers::AuthBasic);
__PACKAGE__->init(
{

View File

@ -1,6 +1,6 @@
package My::Package;
use Lemonldap::NG::Handler::SharedConf;
@ISA = qw(Lemonldap::NG::Handler::SharedConf);
use Lemonldap::NG::Handler::DefaultHandler;
@ISA = qw(Lemonldap::NG::Handler::DefaultHandler);
use Log::Log4perl;
@ -27,7 +27,7 @@ __PACKAGE__->init(
#configStorage => { confFile => '/path/to/my/file' },
# You can also specify directly the configuration
# (see Lemonldap::NG::Handler::SharedConf(3))
# (see Lemonldap::NG::Handler::DefaultHandler(3))
#configStorage => {
# type => 'File',
# dirName => '/usr/local/lemonldap-ng/data/conf/'

View File

@ -3,8 +3,8 @@
package My::SecureToken;
# Load Secure Token Handler
use Lemonldap::NG::Handler::SecureToken;
@ISA = qw(Lemonldap::NG::Handler::SecureToken);
use Lemonldap::NG::Handler::SpecificHandlers::SecureToken;
@ISA = qw(Lemonldap::NG::Handler::SpecificHandlers::SecureToken);
__PACKAGE__->init(
{

View File

@ -3,8 +3,8 @@
package My::Sympa;
# Load Sympa Handler
use Lemonldap::NG::Handler::SympaAutoLogin;
@ISA = qw(Lemonldap::NG::Handler::SympaAutoLogin);
use Lemonldap::NG::Handler::SpecificHandlers::SympaAutoLogin;
@ISA = qw(Lemonldap::NG::Handler::SpecificHandlers::SympaAutoLogin);
__PACKAGE__->init(
{

View File

@ -3,8 +3,8 @@
package My::Zimbra;
# Load Zimbra Handler
use Lemonldap::NG::Handler::ZimbraPreAuth;
@ISA = qw(Lemonldap::NG::Handler::ZimbraPreAuth);
use Lemonldap::NG::Handler::SpecificHandlers::ZimbraPreAuth;
@ISA = qw(Lemonldap::NG::Handler::SpecificHandlers::ZimbraPreAuth);
__PACKAGE__->init(
{

View File

@ -1,8 +1,8 @@
# Handler to manage update cookie
package My::Package::UpdateCookie;
use Lemonldap::NG::Handler::UpdateCookie;
@ISA = qw(Lemonldap::NG::Handler::UpdateCookie);
use Lemonldap::NG::Handler::SpecificHandlers::UpdateCookie;
@ISA = qw(Lemonldap::NG::Handler::SpecificHandlers::UpdateCookie);
__PACKAGE__->init(
{

View File

@ -7,13 +7,15 @@ package Lemonldap::NG::Handler::AuthBasic;
use strict;
use Lemonldap::NG::Handler::SharedConf qw(:all);
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 base qw(Lemonldap::NG::Handler::SharedConf);
use base qw(Lemonldap::NG::Handler::DefaultHandler);
use utf8;
no utf8;
@ -42,7 +44,8 @@ sub run ($$) {
( $class, $apacheRequest ) = splice @_;
if ( time() - $lastReload > $reloadTime ) {
unless ( my $tmp = $class->testConf(1) == OK ) {
$class->lmLog( "$class: No configuration found", 'error' );
Lemonldap::NG::Handler::Main::Logger->lmLog(
"$class: No configuration found", 'error' );
return $tmp;
}
}
@ -53,8 +56,14 @@ sub run ($$) {
# AUTHENTICATION
# I - recover the WWW-Authentication header
my ( $id, $user, $pass );
unless ( $user = lmHeaderIn( $apacheRequest, 'Authorization' ) ) {
lmSetErrHeaderOut( $apacheRequest,
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;
}
@ -69,12 +78,16 @@ sub run ($$) {
unless ( $id eq $datas->{_cache_id} ) {
# 2.2 search in the local cache if exists
unless ( $refLocalStorage and $datas = $refLocalStorage->get($id) ) {
unless ($tsv->{refLocalStorage}
and $datas = $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 = lmHeaderIn( $apacheRequest, 'X-Forwarded-For' );
my $xheader =
Lemonldap::NG::Handler::Main::Headers->lmHeaderIn( $apacheRequest,
'X-Forwarded-For' );
$xheader .= ", " if ($xheader);
$xheader .= $class->ip();
my $soapHeaders =
@ -86,8 +99,8 @@ sub run ($$) {
->uri('urn:Lemonldap::NG::Common::CGI::SOAPService');
$user = decode_base64($user);
( $user, $pass ) = ( $user =~ /^(.*?):(.*)$/ );
$class->lmLog( "AuthBasic authentication for user: $user",
'debug' );
Lemonldap::NG::Handler::Main::Logger->lmLog(
"AuthBasic authentication for user: $user", 'debug' );
my $r = $soap->getCookies( $user, $pass );
my $cv;
@ -101,26 +114,30 @@ sub run ($$) {
# If authentication failed, display error
if ( $res->{errorCode} ) {
$class->lmLog(
Lemonldap::NG::Handler::Main::Logger->lmLog(
"Authentication failed for $user: "
. $soap->error( $res->{errorCode}, 'en' )->result(),
'notice'
);
lmSetErrHeaderOut( $apacheRequest,
Lemonldap::NG::Handler::Main::Headers->lmSetErrHeaderOut(
$apacheRequest,
'WWW-Authenticate' => 'Basic realm="LemonLDAP::NG"' );
return AUTH_REQUIRED;
}
$cv = $res->{cookies}->{$cookieName};
$cv = $res->{cookies}->{ $tsv->{cookieName} };
}
# Now, normal work to find session
my %h;
eval { tie %h, $globalStorage, $cv, $globalStorageOptions; };
eval {
tie %h, $tsv->{globalStorage}, $cv,
$tsv->{globalStorageOptions};
};
if ($@) {
# The cookie isn't yet available
$class->lmLog( "The cookie $cv isn't yet available: $@",
'info' );
Lemonldap::NG::Handler::Main::Logger->lmLog(
"The cookie $cv isn't yet available: $@", 'info' );
$class->updateStatus( $class->ip(), $apacheRequest->uri,
'EXPIRED' );
return $class->goToPortal($uri);
@ -129,8 +146,8 @@ sub run ($$) {
$datas->{_cache_id} = $id;
# Store now the user in the local storage
if ($refLocalStorage) {
$refLocalStorage->set( $id, $datas, "20 minutes" );
if ( $tsv->{refLocalStorage} ) {
$tsv->{refLocalStorage}->set( $id, $datas, "20 minutes" );
}
untie %h;
}
@ -138,11 +155,12 @@ sub run ($$) {
# ACCOUNTING
# 1 - Inform Apache
$class->lmSetApacheUser( $apacheRequest, $datas->{$whatToTrace} );
$class->lmSetApacheUser( $apacheRequest, $datas->{ $tsv->{whatToTrace} } );
# AUTHORIZATION
return $class->forbidden($uri) unless ( $class->grant($uri) );
$class->updateStatus( $datas->{$whatToTrace}, $apacheRequest->uri, 'OK' );
$class->updateStatus( $datas->{ $tsv->{whatToTrace} },
$apacheRequest->uri, 'OK' );
$class->logGranted( $uri, $datas );
# SECURITY
@ -150,11 +168,12 @@ sub run ($$) {
$class->hideCookie;
# Hide user password
$class->lmUnsetHeaderIn( $apacheRequest, "Authorization" );
Lemonldap::NG::Handler::Main::Headers->lmUnsetHeaderIn( $apacheRequest,
"Authorization" );
# ACCOUNTING
# 2 - Inform remote application
$class->sendHeaders;
Lemonldap::NG::Handler::Main::Headers->sendHeaders;
OK;
}

View File

@ -7,11 +7,11 @@ package Lemonldap::NG::Handler::CDA;
use strict;
use Lemonldap::NG::Handler::SharedConf qw(:all);
use Lemonldap::NG::Handler::DefaultHandler qw(:all);
our $VERSION = '1.2.2';
use base qw(Lemonldap::NG::Handler::SharedConf);
use base qw(Lemonldap::NG::Handler::DefaultHandler);
## @rmethod int run(Apache2::RequestRec apacheRequest)
# overload run subroutine to implement cross-domain mechanism.
@ -20,7 +20,7 @@ use base qw(Lemonldap::NG::Handler::SharedConf);
sub run ($$) {
my $class;
( $class, $apacheRequest ) = splice @_;
$cda = 1;
$ntsv->{cda} = 1;
return $class->SUPER::run($apacheRequest);
}
@ -80,18 +80,18 @@ configuration reload, so you don't need to restart Apache at each change :
=head1 DESCRIPTION
This library inherit from L<Lemonldap::NG::Handler::SharedConf> and add the
This library inherit from L<Lemonldap::NG::Handler::DefaultHandler> and add the
capability to control users that are authenticated with a
L<Lemonldap::NG::Portal::CDA> CGI in another domain.
=head2 EXPORT
Same as L<Lemonldap::NG::Handler::SharedConf>.
Same as L<Lemonldap::NG::Handler::DefaultHandler>.
=head1 SEE ALSO
L<Lemonldap::NG::Manager>, L<Lemonldap::NG::Handler>,
L<Lemonldap::NG::Handler::SharedConf>,
L<Lemonldap::NG::Handler::DefaultHandler>,
L<http://lemonldap-ng.org/>
=head1 AUTHOR

View File

@ -13,7 +13,7 @@ use MIME::Base64;
use base qw(Lemonldap::NG::Common::CGI);
use Lemonldap::NG::Handler::SharedConf qw(:all);
use Lemonldap::NG::Handler::DefaultHandler qw(:all);
#link Lemonldap::NG::Handler::_CGI protected _handler
@ -27,9 +27,10 @@ sub new {
my $class = shift;
my $self = $class->SUPER::new() or $class->abort("Unable to build CGI");
$Lemonldap::NG::Handler::_CGI::_cgi = $self;
unless ($Lemonldap::NG::Handler::_CGI::cookieName) {
unless ( $Lemonldap::NG::Handler::_CGI::tsv->{cookieName} ) {
Lemonldap::NG::Handler::_CGI->init(@_);
Lemonldap::NG::Handler::_CGI->initLocalStorage(@_);
#Lemonldap::NG::Handler::_CGI->initLocalStorage(@_); # already called by _CGI->init()
}
unless ( eval { Lemonldap::NG::Handler::_CGI->testConf() } == OK ) {
if ( $_[0]->{noAbort} ) {
@ -65,8 +66,9 @@ sub new {
$rule =~ s/\$(\w+)/\$datas->{$1}/g;
$rule = 0 if ( $rule eq 'deny' );
my $r;
unless ( $rule eq 'accept'
or Lemonldap::NG::Handler::_CGI->safe->reval($rule) )
or Lemonldap::NG::Handler::_CGI->safe_reval($rule) )
{
$self->abort( 'Forbidden',
"You don't have rights to access this page" );
@ -95,26 +97,33 @@ sub authenticate {
if ( $self->{_noConf} );
my %cookies = fetch CGI::Cookie;
my $id;
unless ( $cookies{$cookieName} and $id = $cookies{$cookieName}->value ) {
unless ($cookies{ $tsv->{cookieName} }
and $id = $cookies{ $tsv->{cookieName} }->value )
{
return $self->goToPortal();
}
unless ( $datas and $id eq $datas->{_session_id} ) {
unless ( $refLocalStorage and $datas = $refLocalStorage->get($id) ) {
unless ($tsv->{refLocalStorage}
and $datas = $tsv->{refLocalStorage}->get($id) )
{
my %h;
eval { tie %h, $globalStorage, $id, $globalStorageOptions; };
eval {
tie %h, $tsv->{globalStorage}, $id,
$tsv->{globalStorageOptions};
};
if ($@) {
return $self->goToPortal();
}
$datas->{$_} = $h{$_} foreach ( keys %h );
if ($refLocalStorage) {
$refLocalStorage->set( $id, $datas, "10 minutes" );
if ( $tsv->{refLocalStorage} ) {
$tsv->{refLocalStorage}->set( $id, $datas, "10 minutes" );
}
}
}
# Accounting : set user in apache logs
$self->setApacheUser( $datas->{$whatToTrace} );
$ENV{REMOTE_USER} = $datas->{$whatToTrace};
$self->setApacheUser( $datas->{ $tsv->{whatToTrace} } );
$ENV{REMOTE_USER} = $datas->{ $tsv->{whatToTrace} };
return 1;
}
@ -176,11 +185,14 @@ sub goToPortal {
sub _uri {
my $vhost = $ENV{SERVER_NAME};
my $portString =
$port->{$vhost}
|| $port->{_}
$tsv->{port}->{$vhost}
|| $tsv->{port}->{_}
|| $ENV{SERVER_PORT};
my $_https =
( defined( $https->{$vhost} ) ? $https->{$vhost} : $https->{_} );
my $_https = (
defined( $tsv->{https}->{$vhost} )
? $tsv->{https}->{$vhost}
: $tsv->{https}->{_}
);
$portString =
( $_https && $portString == 443 ) ? ''
: ( !$_https && $portString == 80 ) ? ''
@ -198,12 +210,29 @@ sub _uri {
package Lemonldap::NG::Handler::_CGI;
use strict;
use Lemonldap::NG::Handler::SharedConf qw(:locationRules :localStorage :traces);
use base qw(Lemonldap::NG::Handler::SharedConf);
#use Lemonldap::NG::Handler::DefaultHandler qw(:locationRules :localStorage :traces);
use Lemonldap::NG::Handler::DefaultHandler qw(:tsv :ntsv :jailSharedVars);
use Lemonldap::NG::Handler::Main::Jail;
use base qw(Lemonldap::NG::Handler::DefaultHandler);
our $_cgi;
sub safe_reval {
my $class = shift;
my $rule = shift;
my $jail = Lemonldap::NG::Handler::Main::Jail->new(
'safe' => $ntsv->{safe},
'useSafeJail' => $tsv->{useSafeJail},
'customFunctions' => $tsv->{customFunctions}
);
$ntsv->{safe} = $jail->build_safe();
return $ntsv->{safe}->reval($rule);
}
## @method boolean childInit()
# Since this is not a real Apache handler, childs have not to be initialized.
# @return true
@ -229,7 +258,7 @@ sub lmLog {
# @return boolean : true if $vhost is available
sub vhostAvailable {
my ( $self, $vhost ) = splice @_;
return defined( $defaultCondition->{$vhost} );
return defined( $tsv->{defaultCondition}->{$vhost} );
}
## @method boolean grant(string uri, string vhost)
@ -246,19 +275,19 @@ sub grant {
args => '',
}
);
for ( my $i = 0 ; $i < $locationCount->{$vhost} ; $i++ ) {
if ( $uri =~ $locationRegexp->{$vhost}->[$i] ) {
return &{ $locationCondition->{$vhost}->[$i] }($datas);
for ( my $i = 0 ; $i < $tsv->{locationCount}->{$vhost} ; $i++ ) {
if ( $uri =~ $tsv->{locationRegexp}->{$vhost}->[$i] ) {
return &{ $tsv->{locationCondition}->{$vhost}->[$i] }($datas);
}
}
unless ( $defaultCondition->{$vhost} ) {
unless ( $tsv->{defaultCondition}->{$vhost} ) {
$self->lmLog(
"User rejected because VirtualHost \"$vhost\" has no configuration",
'warn'
);
return 0;
}
return &{ $defaultCondition->{$vhost} }($datas);
return &{ $tsv->{defaultCondition}->{$vhost} }($datas);
}
package Lemonldap::NG::Apache::Request;

View File

@ -8,8 +8,8 @@
package Lemonldap::NG::Handler::Menu;
use strict;
use Lemonldap::NG::Handler::SharedConf qw(:all);
use base qw(Lemonldap::NG::Handler::SharedConf);
use Lemonldap::NG::Handler::DefaultHandler qw(:all);
use base qw(Lemonldap::NG::Handler::DefaultHandler);
use Apache2::Filter ();
use constant BUFF_LEN => 1024;

View File

@ -7,8 +7,10 @@ package Lemonldap::NG::Handler::Proxy;
use strict;
use Lemonldap::NG::Handler::Simple qw(:apache :headers :traces);
use Lemonldap::NG::Handler::Main qw(:apache :headers :tsv);
use LWP::UserAgent;
use Lemonldap::NG::Handler::Main::Headers;
use Lemonldap::NG::Handler::Main::Logger;
our $VERSION = '1.2.0';
@ -35,7 +37,7 @@ sub handler_mp2 : method {
shift->run(@_);
}
*lmLog = *Lemonldap::NG::Handler::Simple::lmLog;
*lmLog = *Lemonldap::NG::Handler::Main::lmLog;
########
# MAIN #
@ -75,7 +77,7 @@ sub run($$) {
sub {
return 1 if ( $_[1] =~ /^$/ );
$request->header(@_) unless ( $_[0] =~ /^(Host|Referer)$/i );
$class->lmLog(
Lemonldap::NG::Handler::Main::Logger->lmLog(
"$class: header pushed to the server: " . $_[0] . ": " . $_[1],
'debug'
);
@ -148,9 +150,9 @@ sub headers {
and $cookieDomain_new
and $_[0] =~ /Set-Cookie/i );
lmSetErrHeaderOut( $r, @_ );
Lemonldap::NG::Handler::Main::Headers->lmSetErrHeaderOut( $r, @_ );
$class->lmLog(
Lemonldap::NG::Handler::Main::Logger->lmLog(
"$class: header pushed to the client: " . $_[0] . ": " . $_[1],
'debug'
);

View File

@ -8,10 +8,12 @@
package Lemonldap::NG::Handler::SecureToken;
use strict;
use Lemonldap::NG::Handler::SharedConf qw(:all);
use base qw(Lemonldap::NG::Handler::SharedConf);
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';
@ -65,22 +67,26 @@ sub defaultValuesInit {
foreach (qw/secureTokenMemcachedServers secureTokenUrls/) {
no strict 'refs';
unless ( ref ${$_} eq "ARRAY" ) {
$class->lmLog( "Transform $_ value into an array reference",
'debug' );
Lemonldap::NG::Handler::Main::Logger->lmLog(
"Transform $_ value into an array reference", 'debug' );
my @array = split( /\s+/, ${$_} );
${$_} = \@array;
}
}
# Display found values in debug mode
$class->lmLog( "secureTokenMemcachedServers: @$secureTokenMemcachedServers",
'debug' );
$class->lmLog( "secureTokenExpiration: $secureTokenExpiration", 'debug' );
$class->lmLog( "secureTokenAttribute: $secureTokenAttribute", 'debug' );
$class->lmLog( "secureTokenUrls: @$secureTokenUrls", 'debug' );
$class->lmLog( "secureTokenHeader: $secureTokenHeader", 'debug' );
$class->lmLog( "secureTokenAllowOnError: $secureTokenAllowOnError",
'debug' );
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'};
@ -115,8 +121,8 @@ sub run {
foreach (@$secureTokenUrls) {
if ( $uri =~ m#$_# ) {
$checkurl = 1;
$class->lmLog( "URL $uri detected as an Secure Token URL (rule $_)",
'debug' );
Lemonldap::NG::Handler::Main::Logger->lmLog(
"URL $uri detected as an Secure Token URL (rule $_)", 'debug' );
last;
}
}
@ -138,7 +144,8 @@ sub run {
return $class->_returnError() unless $key;
# Header location
$class->lmSetHeaderIn( $r, $secureTokenHeader => $key );
Lemonldap::NG::Handler::Main::Headers->lmSetHeaderIn( $r,
$secureTokenHeader => $key );
# Remove token
eval 'use Apache2::Filter' unless ( $INC{"Apache2/Filter.pm"} );
@ -172,7 +179,8 @@ sub _createMemcachedConnection {
'debug' => 0,
};
$class->lmLog( "Memcached connection created", 'debug' );
Lemonldap::NG::Handler::Main::Logger->lmLog( "Memcached connection created",
'debug' );
return $memd;
}
@ -191,11 +199,13 @@ sub _setToken {
$secureTokenExpiration );
unless ($res) {
$class->lmLog( "Unable to store secure token $key", 'error' );
Lemonldap::NG::Handler::Main::Logger->lmLog(
"Unable to store secure token $key", 'error' );
return;
}
$class->lmLog( "Set $value in token $key", 'info' );
Lemonldap::NG::Handler::Main::Logger->lmLog( "Set $value in token $key",
'info' );
return $key;
}
@ -210,10 +220,12 @@ sub _deleteToken {
my $res = $secureTokenMemcachedConnection->delete($key);
unless ($res) {
$class->lmLog( "Unable to delete secure token $key", 'error' );
Lemonldap::NG::Handler::Main::Logger->lmLog(
"Unable to delete secure token $key", 'error' );
}
else {
$class->lmLog( "Token $key deleted", 'info' );
Lemonldap::NG::Handler::Main::Logger->lmLog( "Token $key deleted",
'info' );
}
return $res;
@ -234,7 +246,7 @@ sub _isAlive {
my $total_c = $stats->{'total'}->{'connection_structures'};
my $total_i = $stats->{'total'}->{'total_items'};
$class->lmLog(
Lemonldap::NG::Handler::Main::Logger->lmLog(
"Memcached connection is alive ($total_c connections / $total_i items)",
'debug'
);
@ -242,7 +254,8 @@ sub _isAlive {
return 1;
}
$class->lmLog( "Memcached connection is not alive", 'error' );
Lemonldap::NG::Handler::Main::Logger->lmLog(
"Memcached connection is not alive", 'error' );
return 0;
}
@ -254,18 +267,20 @@ sub _returnError {
my ($class) = splice @_;
if ($secureTokenAllowOnError) {
$class->lmLog( "Allow request without secure token", 'debug' );
Lemonldap::NG::Handler::Main::Logger->lmLog(
"Allow request without secure token", 'debug' );
return OK;
}
# Redirect or Forbidden?
if ($useRedirectOnError) {
$class->lmLog( "Use redirect for error", 'debug' );
if ( $tsv->{useRedirectOnError} ) {
Lemonldap::NG::Handler::Main::Logger->lmLog( "Use redirect for error",
'debug' );
return $class->goToPortal( '/', 'lmError=500' );
}
else {
$class->lmLog( "Return error", 'debug' );
Lemonldap::NG::Handler::Main::Logger->lmLog( "Return error", 'debug' );
return SERVER_ERROR;
}
}

View File

@ -1,354 +0,0 @@
## @file
# Main handler.
## @class
# Main handler.
# All methods in handler are class methods: in ModPerl environment, handlers
# are always launched without object created.
#
# The main method is run() who is called by Apache for each requests (using
# handler() wrapper).
#
# The initialization process is splitted in two parts :
# - init() is launched as Apache startup
# - globalInit() is launched at each first request received by an Apache child
# and each time a new configuration is detected
package Lemonldap::NG::Handler::SharedConf;
use strict;
use Lemonldap::NG::Handler::Simple qw(:all);
use Lemonldap::NG::Handler::Vhost;
use Lemonldap::NG::Common::Conf; #link protected lmConf
use Lemonldap::NG::Common::Conf::Constants; #inherits
use Cache::Cache qw($EXPIRES_NEVER);
use base qw(Lemonldap::NG::Handler::Vhost Lemonldap::NG::Handler::Simple);
#parameter reloadTime Time in second between 2 configuration check (600)
our $VERSION = '1.1.1';
our $cfgNum = 0;
our $lastReload = 0;
our $reloadTime;
our $lmConf;
our $localConfig;
BEGIN {
if ( MP() == 2 ) {
eval {
require threads::shared;
Apache2::RequestUtil->import();
threads::shared::share($cfgNum);
threads::shared::share($lastReload);
threads::shared::share($reloadTime);
threads::shared::share($lmConf);
threads::shared::share($localConfig);
};
}
*EXPORT_TAGS = *Lemonldap::NG::Handler::Simple::EXPORT_TAGS;
*EXPORT_OK = *Lemonldap::NG::Handler::Simple::EXPORT_OK;
push(
@{ $EXPORT_TAGS{$_} },
qw($cfgNum $lastReload $reloadTime $lmConf $localConfig)
) foreach (qw(variables localStorage));
push @EXPORT_OK, qw($cfgNum $lastReload $reloadTime $lmConf $localConfig);
}
# INIT PROCESS
## @imethod void init(hashRef args)
# Constructor.
# init is overloaded to call only localInit. globalInit is called later.
# @param $args hash containing parameters
sub init($$) {
my ( $class, $args ) = splice @_;
# TODO reloadTime in defaultValuesInit ?
$reloadTime = $args->{reloadTime} || 600;
$class->localInit($args);
}
## @imethod protected void defaultValuesInit(hashRef args)
# Set default values for non-customized variables
# @param $args hash containing parameters
# @return boolean
sub defaultValuesInit {
my ( $class, $args ) = splice @_;
# Local configuration overrides global configuration
my %h = ( %$args, %$localConfig );
return $class->SUPER::defaultValuesInit( \%h );
}
## @imethod void localInit(hashRef args)
# Load parameters and build the Lemonldap::NG::Common::Conf object.
# @return boolean
sub localInit {
my ( $class, $args ) = splice @_;
die(
"$class : unable to build configuration : $Lemonldap::NG::Common::Conf::msg"
)
unless ( $lmConf =
Lemonldap::NG::Common::Conf->new( $args->{configStorage} ) );
# Get local configuration parameters
my $localconf = $lmConf->getLocalConf(HANDLERSECTION);
if ($localconf) {
$args->{$_} ||= $localconf->{$_} foreach ( keys %$localconf );
}
# Store in localConfig global variable
$localConfig = $args;
# localStorage can be declared in configStorage or at the root or both
foreach (qw(localStorage localStorageOptions)) {
$args->{$_} ||= $args->{configStorage}->{$_} || $lmConf->{$_};
$args->{configStorage}->{$_} ||= $args->{$_};
}
$class->defaultValuesInit($args);
$class->SUPER::localInit($args);
}
# MAIN
## @rmethod int run(Apache2::RequestRec r)
# Check configuration and launch Lemonldap::NG::Handler::Simple::run().
# Each $reloadTime, the Apache child verify if its configuration is the same
# as the configuration stored in the local storage.
# @param $r Apache2::RequestRec object
# @return Apache constant
sub run($$) {
my ( $class, $r ) = splice @_;
if ( time() - $lastReload > $reloadTime ) {
die("$class: No configuration found")
unless ( $class->testConf(1) == OK );
}
return $class->SUPER::run($r);
}
# CONFIGURATION UPDATE
## @rmethod protected int testConf(boolean local)
# Test if configuration has changed and launch setConf() if needed.
# If the optional boolean $local is true, remote configuration is not tested:
# only local cached configuration is tested if available. $local is given to
# Lemonldap::NG::Common::getConf()
# @param $local boolean
# @return Apache constant
sub testConf {
my ( $class, $local ) = splice @_;
my $conf = $lmConf->getConf( { local => $local } );
unless ( ref($conf) ) {
$class->lmLog(
"$class: Unable to load configuration: $Lemonldap::NG::Common::Conf::msg",
'error'
);
return $cfgNum ? OK : SERVER_ERROR;
}
if ( !$cfgNum or $cfgNum != $conf->{cfgNum} ) {
$class->lmLog(
"$class: get configuration $conf->{cfgNum} ($Lemonldap::NG::Common::Conf::msg)",
'debug'
);
$lastReload = time();
return $class->setConf($conf);
}
$class->lmLog( "$class: configuration is up to date", 'debug' );
OK;
}
## @rmethod protected int setConf(hashRef conf)
# Launch globalInit().
# Local parameters have best precedence on configuration parameters.
# @return Apache constant
sub setConf {
my ( $class, $conf ) = splice @_;
# Local configuration overrides global configuration
$cfgNum = $conf->{cfgNum};
$conf->{$_} = $localConfig->{$_} foreach ( keys %$localConfig );
$class->globalInit($conf);
OK;
}
# RELOAD SYSTEM
*reload = *refresh;
## @rmethod int refresh(Apache::RequestRec r)
# Launch testConf() with $local=0, so remote configuration is tested.
# Then build a simple HTTP response that just returns "200 OK" or
# "500 Server Error".
# @param $r current request
# @return Apache constant (OK or SERVER_ERROR)
sub refresh($$) {
my ( $class, $r ) = splice @_;
$class->lmLog( "$class: request for configuration reload", 'notice' );
$r->handler("perl-script");
if ( $class->testConf(0) == OK ) {
if ( MP() == 2 ) {
$r->push_handlers( 'PerlResponseHandler' =>
sub { my $r = shift; $r->content_type('text/plain'); OK } );
}
elsif ( MP() == 1 ) {
$r->push_handlers(
'PerlHandler' => sub { my $r = shift; $r->send_http_header; OK }
);
}
else {
return 1;
}
}
else {
if ( MP() == 2 ) {
$r->push_handlers( 'PerlResponseHandler' => sub { SERVER_ERROR } );
}
elsif ( MP() == 1 ) {
$r->push_handlers( 'PerlHandler' => sub { SERVER_ERROR } );
}
else {
return 0;
}
}
return OK;
}
1;
__END__
=head1 NAME
=encoding utf8
Lemonldap::NG::Handler::SharedConf - Perl extension to use dynamic
configuration provide by Lemonldap::NG::Manager.
=head1 SYNOPSIS
package My::Package;
use Lemonldap::NG::Handler::SharedConf;
@ISA = qw(Lemonldap::NG::Handler::SharedConf);
__PACKAGE__->init ( {
localStorage => "Cache::FileCache",
localStorageOptions => {
'namespace' => 'lemonldap-ng',
'default_expires_in' => 600,
},
configStorage => {
type => "DBI"
dbiChain => "DBI:mysql:database=$database;host=$hostname;port=$port",
dbiUser => "lemonldap",
dbiPassword => "password",
},
} );
Call your package in /apache-dir/conf/httpd.conf :
PerlRequire MyFile
# TOTAL PROTECTION
PerlHeaderParserHandler My::Package
# OR SELECTED AREA
<Location /protected-area>
PerlHeaderParserHandler My::Package
</Location>
The configuration is loaded only at Apache start. Create an URI to force
configuration reload, so you don't need to restart Apache at each change :
# /apache-dir/conf/httpd.conf
<Location /location/that/I/ve/choosed>
Order deny,allow
Deny from all
Allow from my.manager.com
PerlHeaderParserHandler My::Package->refresh
</Location>
=head1 DESCRIPTION
This library inherit from L<Lemonldap::NG::Handler::Simple> to build a
complete SSO Handler System: a central database contains the policy of your
domain. People that want to access to a protected applications are redirected
to the portal that run L<Lemonldap::NG::Portal::SharedConf>. After reading
configuration from the database and authenticating the user, it stores a key
word for each application the user is granted to access to.
Then the user is redirected to the application he wanted to access and the
Apache handler build with L<Lemonldap::NG::Handler::SharedConf::DBI> has just
to verify that the keyword corresponding to the protected area is stored in
the database.
=head2 OVERLOADED SUBROUTINES
=head3 init
Like L<Lemonldap::NG::Handler::Simple>::init() but read only localStorage
related options. You may change default time between two configuration checks
with the C<reloadTime> parameter (default 600s).
=head1 OPERATION
Each new Apache child checks if there's a configuration stored in the local
store. If not, it calls getConf to get one and store it in the local store by
calling setconf.
Every 600 seconds, each Apache child checks if the local stored configuration
has changed and reload it if it has.
When refresh subroutine is called (by http for example: see synopsis), getConf
is called to get the new configuration and setconf is called to store it in the
local store.
=head1 SEE ALSO
L<Lemonldap::NG::Handler>, L<Lemonldap::NG::Manager>, L<Lemonldap::NG::Portal>,
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) 2006, 2007, 2008, 2009, 2010, 2013 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
=item Copyright (C) 2012 by François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt>
=item Copyright (C) 2006, 2008, 2009, 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

File diff suppressed because it is too large Load Diff

View File

@ -429,8 +429,8 @@ Lemonldap::NG::Handler::Status - Perl extension to add a mod_status like system
Create your own package (example using a central configuration database):
package My::Package;
use Lemonldap::NG::Handler::SharedConf;
@ISA = qw(Lemonldap::NG::Handler::SharedConf);
use Lemonldap::NG::Handler::DefaultHandler;
@ISA = qw(Lemonldap::NG::Handler::DefaultHandler);
__PACKAGE__->init ( {
# Activate status feature

View File

@ -8,9 +8,11 @@
package Lemonldap::NG::Handler::SympaAutoLogin;
use strict;
use Lemonldap::NG::Handler::SharedConf qw(:all);
use base qw(Lemonldap::NG::Handler::SharedConf);
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';
@ -39,8 +41,10 @@ sub defaultValuesInit {
$sympaMailKey = $args->{'sympaMailKey'} || $sympaMailKey || "mail";
# Display found values in debug mode
$class->lmLog( "sympaSecret: $sympaSecret", 'debug' );
$class->lmLog( "sympaMailKey: $sympaMailKey", 'debug' );
Lemonldap::NG::Handler::Main::Logger->lmLog( "sympaSecret: $sympaSecret",
'debug' );
Lemonldap::NG::Handler::Main::Logger->lmLog( "sympaMailKey: $sympaMailKey",
'debug' );
# Delete Sympa parameters
delete $args->{'sympaSecret'};
@ -77,10 +81,11 @@ sub run {
# Get cookie header, removing Sympa cookie if exists (avoid security
# problems) and set the new value
$tmp = lmHeaderIn( $r, 'Cookie' );
$tmp = Lemonldap::NG::Handler::Main::Headers->lmHeaderIn( $r, 'Cookie' );
$tmp =~ s/\bsympauser=[^,;]*[,;]?//;
$tmp .= $tmp ? ";$str" : $str;
$class->lmSetHeaderIn( $r, 'Cookie' => $tmp );
Lemonldap::NG::Handler::Main::Headers->lmSetHeaderIn( $r,
'Cookie' => $tmp );
# Return SUPER::run() result
return $ret;

View File

@ -6,8 +6,10 @@
package Lemonldap::NG::Handler::UpdateCookie;
use strict;
use Lemonldap::NG::Handler::SharedConf qw(:all);
use base qw(Lemonldap::NG::Handler::SharedConf);
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;
our $VERSION = '1.0.0';
@ -37,16 +39,17 @@ sub run {
$datas->{_session_id} = 0;
$clear = 1;
}
elsif ( $refLocalStorage
and my $ldatas = $refLocalStorage->get($id) )
elsif ( $tsv->{refLocalStorage}
and my $ldatas = $tsv->{refLocalStorage}->get($id) )
{
if ( $ldatas->{_utime} lt $utime ) {
$clear = 1;
}
}
if ($clear) {
$class->lmLog( "$class: remove $id from local cache", 'debug' );
$refLocalStorage->remove($id);
Lemonldap::NG::Handler::Main::Logger->lmLog(
"$class: remove $id from local cache", 'debug' );
$tsv->{refLocalStorage}->remove($id);
}
}
@ -60,8 +63,9 @@ sub run {
# Get user cookies and search for Lemonldap::NG update cookie.
# @return Value of the cookie if found, 0 else
sub fetchUTime {
my $t = lmHeaderIn( $apacheRequest, 'Cookie' );
my $c = $cookieName . 'update';
my $t = Lemonldap::NG::Handler::Main::Headers->lmHeaderIn( $apacheRequest,
'Cookie' );
my $c = $tsv->{cookieName} . 'update';
return ( $t =~ /$c=([^,; ]+)/o ) ? $1 : 0;
}
@ -79,7 +83,7 @@ cookie sent by client, to reload session in local cache.
package My::Package;
use Lemonldap::NG::Handler::UpdateCookie;
@ISA = qw(Lemonldap::NG::Handler::SharedConf);
@ISA = qw(Lemonldap::NG::Handler::DefaultHandler);
__PACKAGE__->init ( {
# See Lemonldap::NG::Handler for more

View File

@ -1,503 +0,0 @@
## @file
# Virtual host support mechanism
## @class
# This class adds virtual host support for Lemonldap::NG handlers.
package Lemonldap::NG::Handler::Vhost;
use strict;
use AutoLoader 'AUTOLOAD';
use Lemonldap::NG::Handler::Simple qw(:locationRules :headers :post :apache)
; #inherits
use MIME::Base64;
use constant SAFEWRAP => ( Safe->can("wrap_code_ref") ? 1 : 0 );
our $VERSION = '1.3.0';
## @imethod protected void defaultValuesInit(hashRef args)
# Set default values for non-customized variables
# @param $args reference to the configuration hash
sub defaultValuesInit {
my ( $class, $args ) = splice @_;
foreach my $t (qw(https port maintenance)) {
# Skip Handler initialization (values not defined)
next unless defined $args->{$t};
# Record default value in key '_'
$args->{$t} = { _ => $args->{$t} } unless ( ref( $args->{$t} ) );
# Override with vhost options
if ( defined $args->{vhostOptions} ) {
my $n = 'vhost' . ucfirst($t);
foreach my $k ( keys %{ $args->{vhostOptions} } ) {
foreach my $alias (
@{ $class->getAliases( $k, $args->{vhostOptions} ) } )
{
my $v = $args->{vhostOptions}->{$k}->{$n};
$class->lmLog( "Options $t for vhost $alias: $v", 'debug' );
$args->{$t}->{$alias} = $v
if ( $v >= 0 ); # Keep default value if $v is negative
}
}
}
}
$class->Lemonldap::NG::Handler::Simple::defaultValuesInit($args);
}
## @imethod void locationRulesInit(hashRef args)
# Compile rules.
# Rules are stored in $args->{locationRules}->{&lt;virtualhost&gt;} that contains
# regexp=>test expressions where :
# - regexp is used to test URIs
# - test contains an expression used to grant the user
#
# This function creates 2 hashRef containing :
# - one list of the compiled regular expressions for each virtual host
# - one list of the compiled functions (compiled with conditionSub()) for each
# virtual host
# @param $args reference to the configuration hash
sub locationRulesInit {
my ( $class, $args ) = splice @_;
foreach my $vhost ( keys %{ $args->{locationRules} } ) {
foreach
my $alias ( @{ $class->getAliases( $vhost, $args->{vhostOptions} ) } )
{
$locationCount->{$alias} = 0;
foreach ( sort keys %{ $args->{locationRules}->{$vhost} } ) {
if ( $_ eq 'default' ) {
(
$defaultCondition->{$alias},
$defaultProtection->{$alias}
)
= $class->conditionSub(
$args->{locationRules}->{$vhost}->{$_} );
}
else {
(
$locationCondition->{$alias}
->[ $locationCount->{$alias} ],
$locationProtection->{$alias}
->[ $locationCount->{$alias} ]
)
= $class->conditionSub(
$args->{locationRules}->{$vhost}->{$_} );
$locationRegexp->{$alias}->[ $locationCount->{$alias} ] =
qr/$_/;
$locationConditionText->{$alias}
->[ $locationCount->{$alias} ] =
/^\(\?#(.*?)\)/ ? $1 : /^(.*?)##(.+)$/ ? $2 : $_;
$locationCount->{$alias}++;
}
}
# Default police
( $defaultCondition->{$alias}, $defaultProtection->{$alias} ) =
$class->conditionSub('accept')
unless ( $defaultCondition->{$alias} );
}
}
1;
}
## @imethod void forgeHeadersInit(hashRef args)
# Create the &$forgeHeaders->{&lt;virtualhost&gt;} subroutines used to insert
# headers into the HTTP request.
# @param $args reference to the configuration hash
sub forgeHeadersInit {
my ( $class, $args ) = splice @_;
# Creation of the subroutine who will generate headers
foreach my $vhost ( keys %{ $args->{exportedHeaders} } ) {
foreach
my $alias ( @{ $class->getAliases( $vhost, $args->{vhostOptions} ) } )
{
my %tmp = %{ $args->{exportedHeaders}->{$vhost} };
foreach ( keys %tmp ) {
$tmp{$_} =~ s/\$(\w+)/\$datas->{$1}/g;
$tmp{$_} = $class->regRemoteIp( $tmp{$_} );
}
my $sub;
foreach ( keys %tmp ) {
$sub .= "'$_' => join('',split(/[\\r\\n]+/,$tmp{$_})),";
}
$forgeHeaders->{$alias} = (
SAFEWRAP
? $class->safe->wrap_code_ref(
$class->safe->reval("sub {$sub}")
)
: $class->safe->reval("sub {return($sub)}")
);
$class->lmLog( "$class: Unable to forge headers: $@: sub {$sub}",
'error' )
if ($@);
}
}
1;
}
## @imethod void headerListInit(hashRef args)
# Lists the exported HTTP headers into $headerList
# @param $args reference to the configuration hash
sub headerListInit {
my ( $class, $args ) = splice @_;
foreach my $vhost ( keys %{ $args->{exportedHeaders} } ) {
foreach
my $alias ( @{ $class->getAliases( $vhost, $args->{vhostOptions} ) } )
{
my @tmp = keys %{ $args->{exportedHeaders}->{$vhost} };
$headerList->{$alias} = \@tmp;
}
}
1;
}
## @rmethod void sendHeaders()
# Launch function compiled by forgeHeadersInit() for the current virtual host
sub sendHeaders {
my $class = shift;
my $vhost = $apacheRequest->hostname;
if ( defined( $forgeHeaders->{$vhost} ) ) {
$class->lmSetHeaderIn( $apacheRequest, &{ $forgeHeaders->{$vhost} } );
}
}
## @rmethod void cleanHeaders()
# Unset HTTP headers for the current virtual host, when sendHeaders is skipped
sub cleanHeaders {
my $class = shift;
my $vhost = $apacheRequest->hostname;
if ( defined( $forgeHeaders->{$vhost} ) ) {
$class->lmUnsetHeaderIn( $apacheRequest, @{ $headerList->{$vhost} } );
}
}
## @rmethod protected int isUnprotected()
# @return 0 if URI is protected,
# UNPROTECT if it is unprotected by "unprotect",
# SKIP if is is unprotected by "skip"
sub isUnprotected {
my ( $class, $uri ) = splice @_;
my $vhost = $apacheRequest->hostname;
for ( my $i = 0 ; $i < $locationCount->{$vhost} ; $i++ ) {
if ( $uri =~ $locationRegexp->{$vhost}->[$i] ) {
return $locationProtection->{$vhost}->[$i];
}
}
return $defaultProtection->{$vhost};
}
## @rmethod boolean grant()
# Grant or refuse client using compiled regexp and functions
# @return True if the user is granted to access to the current URL
sub grant {
my ( $class, $uri ) = splice @_;
my $vhost = $apacheRequest->hostname;
for ( my $i = 0 ; $i < $locationCount->{$vhost} ; $i++ ) {
if ( $uri =~ $locationRegexp->{$vhost}->[$i] ) {
$class->lmLog(
'Regexp "' . $locationConditionText->{$vhost}->[$i] . '" match',
'debug'
);
return &{ $locationCondition->{$vhost}->[$i] }($datas);
}
}
unless ( $defaultCondition->{$vhost} ) {
$class->lmLog(
"User rejected because VirtualHost \"$vhost\" has no configuration",
'warn'
);
return 0;
}
$class->lmLog( "$vhost: Apply default rule", 'debug' );
return &{ $defaultCondition->{$vhost} }($datas);
}
## @rmethod protected $ fetchId()
# Get user cookies and search for Lemonldap::NG cookie.
# @return Value of the cookie if found, 0 else
sub fetchId {
my $t = lmHeaderIn( $apacheRequest, 'Cookie' );
my $vhost = $apacheRequest->hostname;
my $lookForHttpCookie = $securedCookie =~ /^(2|3)$/
&& !(
defined( $https->{$vhost} )
? $https->{$vhost}
: $https->{_}
);
my $value =
$lookForHttpCookie
? ( $t =~ /${cookieName}http=([^,; ]+)/o ? $1 : 0 )
: ( $t =~ /$cookieName=([^,; ]+)/o ? $1 : 0 );
$value = $cipher->decryptHex( $value, "http" )
if ( $value && $lookForHttpCookie && $securedCookie == 3 );
return $value;
}
## @cmethod private string _buildUrl(string s)
# Transform /<s> into http(s?)://<host>:<port>/s
# @param $s path
# @return URL
sub _buildUrl {
my ( $class, $s ) = splice @_;
my $vhost = $apacheRequest->hostname;
my $portString =
$port->{$vhost}
|| $port->{_}
|| $apacheRequest->get_server_port();
my $_https = (
defined( $https->{$vhost} )
? $https->{$vhost}
: $https->{_}
);
$portString =
( $_https && $portString == 443 ) ? ''
: ( !$_https && $portString == 80 ) ? ''
: ':' . $portString;
my $url = "http"
. ( $_https ? "s" : "" ) . "://"
. $apacheRequest->get_server_name()
. $portString
. $s;
$class->lmLog( "Build URL $url", 'debug' );
return $url;
}
## @imethod protected void postUrlInit()
# Prepare methods to post form attributes
sub postUrlInit {
my ( $class, $args ) = splice @_;
# Do nothing if no POST configured
return unless ( $args->{post} );
# Load required modules
eval 'use Apache2::Filter;use URI';
# Prepare transform sub
$transform = {};
# Browse all vhost
foreach my $vhost ( keys %{ $args->{post} } ) {
foreach
my $alias ( @{ $class->getAliases( $vhost, $args->{vhostOptions} ) } )
{
# Browse all POST URI
while ( my ( $url, $d ) = each( %{ $args->{post}->{$vhost} } ) ) {
# Where to POST
$d->{postUrl} ||= $url;
# Register POST form for POST URL
$transform->{$alias}->{$url} =
sub { $class->buildPostForm( $d->{postUrl} ) }
if ( $url ne $d->{postUrl} );
# Get datas to POST
my $expr = $d->{expr};
my %postdata;
# Manage old and new configuration format
# OLD: expr => 'param1 => value1, param2 => value2',
# NEW : expr => { param1 => value1, param2 => value2 },
if ( ref $expr eq 'HASH' ) {
%postdata = %$expr;
}
else {
%postdata = split /(?:\s*=>\s*|\s*,\s*)/, $expr;
}
# Build string for URI::query_form
my $tmp;
foreach ( keys %postdata ) {
$postdata{$_} =~ s/\$(\w+)/\$datas->{$1}/g;
$postdata{$_} = "'$postdata{$_}'"
if ( $postdata{$_} =~ /^\w+$/ );
$tmp .= "'$_'=>$postdata{$_},";
}
$class->lmLog( "Compiling POST request for $url (vhost $alias)",
'debug' );
$transform->{$alias}->{ $d->{postUrl} } = sub {
return $class->buildPostForm( $d->{postUrl} )
if ( $apacheRequest->method ne 'POST' );
$apacheRequest->add_input_filter(
sub {
$class->postFilter( $tmp, @_ );
}
);
OK;
}
}
}
}
}
## @rmethod protected transformUri(string uri)
# Transform URI to replay POST forms
# @param uri URI to catch
# @return Apache2::Const
sub transformUri {
my ( $class, $uri ) = splice @_;
my $vhost = $apacheRequest->hostname;
if ( defined( $transform->{$vhost}->{$uri} ) ) {
return &{ $transform->{$vhost}->{$uri} };
}
OK;
}
## @rmethod protected boolean checkMaintenanceMode
# Check if we are in maintenance mode
# @return true if maintenance mode
sub checkMaintenanceMode {
my ($class) = splice @_;
my $vhost = $apacheRequest->hostname;
my $_maintenance =
( defined $maintenance->{$vhost} )
? $maintenance->{$vhost}
: $maintenance->{_};
if ($_maintenance) {
$class->lmLog( "Maintenance mode activated", 'debug' );
return 1;
}
return 0;
}
## @method arrayref getAliases(scalar vhost, hashref options)
# Check aliases of a vhost
# @param vhost vhost name
# @param options vhostOptions configuration item
# @return arrayref of vhost and aliases
sub getAliases {
my ( $class, $vhost, $options ) = splice @_;
my $aliases = [$vhost];
if ( $options->{$vhost}->{vhostAliases} ) {
foreach ( split /\s+/, $options->{$vhost}->{vhostAliases} ) {
push @$aliases, $_;
$class->lmLog( "$_ is an alias for $vhost", 'debug' );
}
}
return $aliases;
}
1;
__END__
=head1 NAME
=encoding utf8
Lemonldap::NG::Handler::Vhost - Perl extension for building a Lemonldap::NG
compatible handler able to manage Apache virtual hosts.
=head1 SYNOPSIS
Create your own package:
package My::Package;
use Lemonldap::NG::Handler::Vhost;
# IMPORTANT ORDER
our @ISA = qw (Lemonldap::NG::Handler::Vhost Lemonldap::NG::Handler::Simple);
__PACKAGE__->init ( { locationRules => {
'vhost1.dc.com' => {
'default' => '$ou =~ /brh/'
},
'vhost2.dc.com' => {
'^/pj/.*$' => '$qualif="opj"',
'^/rh/.*$' => '$ou=~/brh/',
'^/rh_or_opj.*$' => '$qualif="opj" or $ou=~/brh/',
default => 'accept',
},
# Put here others Lemonldap::NG::Handler::Simple options
}
);
Call your package in <apache-directory>/conf/httpd.conf
PerlRequire MyFile
PerlHeaderParserHandler My::Package
=head1 DESCRIPTION
This library provides a way to protect Apache virtual hosts with Lemonldap::NG.
=head2 INITIALISATION PARAMETERS
Lemonldap::NG::Handler::Vhost splits the locationRules parameter into a hash
reference which contains anonymous hash references as used by
L<Lemonldap::NG::Handler::Simple>.
=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) 2006, 2007, 2008, 2009, 2010 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
=item Copyright (C) 2012 by François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt>
=item Copyright (C) 2006, 2010, 2011, 2012, 2013 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

View File

@ -8,9 +8,11 @@
package Lemonldap::NG::Handler::ZimbraPreAuth;
use strict;
use Lemonldap::NG::Handler::SharedConf qw(:all);
use base qw(Lemonldap::NG::Handler::SharedConf);
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';
@ -36,12 +38,17 @@ sub defaultValuesInit {
$timeout = $args->{'timeout'} || $timeout || '0';
# Display found values in debug mode
$class->lmLog( "zimbraPreAuthKey: $zimbraPreAuthKey", 'debug' );
$class->lmLog( "zimbraAccountKey: $zimbraAccountKey", 'debug' );
$class->lmLog( "zimbraBy: $zimbraBy", 'debug' );
$class->lmLog( "zimbraUrl: $zimbraUrl", 'debug' );
$class->lmLog( "zimbraSsoUrl: $zimbraSsoUrl", 'debug' );
$class->lmLog( "timeout: $timeout", 'debug' );
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'};
@ -85,7 +92,8 @@ sub run {
);
# Header location
lmSetHeaderOut( $r, 'Location' => $zimbra_url );
Lemonldap::NG::Handler::Main::Headers->lmSetHeaderOut( $r,
'Location' => $zimbra_url );
# Return REDIRECT
return REDIRECT;
@ -111,7 +119,7 @@ sub _buildZimbraPreAuthUrl {
my $computed_value =
hmac_sha1_hex( "$account|$by|$expires|$timestamp", $key );
$class->lmLog(
Lemonldap::NG::Handler::Main::Logger->lmLog(
"Compute value $account|$by|$expires|$timestamp into $computed_value",
'debug' );
@ -119,7 +127,8 @@ sub _buildZimbraPreAuthUrl {
my $zimbra_url =
"$url?account=$account&by=$by&timestamp=$timestamp&expires=$expires&preauth=$computed_value";
$class->lmLog( "Build Zimbra URL: $zimbra_url", 'debug' );
Lemonldap::NG::Handler::Main::Logger->lmLog(
"Build Zimbra URL: $zimbra_url", 'debug' );
return $zimbra_url;
}

View File

@ -12,7 +12,7 @@
package Lemonldap::NG::Manager::Sessions;
use strict;
use Lemonldap::NG::Handler::CGI qw(:globalStorage :locationRules);
use Lemonldap::NG::Handler::CGI qw(:tsv);
use Lemonldap::NG::Common::Apache::Session; #inherits
use Lemonldap::NG::Common::Conf; #link protected conf Configuration
use Lemonldap::NG::Common::Conf::Constants; #inherits
@ -21,8 +21,8 @@ use utf8;
#inherits Apache::Session
our $whatToTrace;
*whatToTrace = \$Lemonldap::NG::Handler::_CGI::whatToTrace;
#our $whatToTrace;
#*whatToTrace = \$Lemonldap::NG::Handler::_CGI::whatToTrace;
our $VERSION = '1.3.0';
@ -67,12 +67,12 @@ sub new {
$self->{managerSkin} ||= 'default';
# Now try to load Apache::Session module
unless ( $globalStorage->can('populate') ) {
eval "require $globalStorage";
$class->abort( "Unable to load $globalStorage", $@ ) if ($@);
unless ( $tsv->{globalStorage}->can('populate') ) {
eval "require $tsv->{globalStorage}";
$class->abort( "Unable to load $tsv->{globalStorage}", $@ ) if ($@);
}
%{ $self->{globalStorageOptions} } = %$globalStorageOptions;
$self->{globalStorageOptions}->{backend} = $globalStorage;
%{ $self->{globalStorageOptions} } = %{$tsv->{globalStorageOptions}};
$self->{globalStorageOptions}->{backend} = $tsv->{globalStorage};
# IP field
$self->{ipField} = "ipAddr";
@ -139,10 +139,10 @@ sub list {
# Parse all sessions to store first letter
$res = Lemonldap::NG::Common::Apache::Session->get_key_from_all_sessions(
$self->{globalStorageOptions},
[ '_httpSessionType', $whatToTrace ] );
[ '_httpSessionType', $tsv->{whatToTrace} ] );
while ( my ( $id, $entry ) = each %$res ) {
next if ( $entry->{_httpSessionType} );
next unless $entry->{$whatToTrace} =~ /^(\w)/;
next unless $entry->{$tsv->{whatToTrace}} =~ /^(\w)/;
$byUid->{$1}++;
$count++;
}
@ -189,10 +189,10 @@ sub doubleIp {
# Parse all sessions
$res = Lemonldap::NG::Common::Apache::Session->get_key_from_all_sessions(
$self->{globalStorageOptions},
[ '_httpSessionType', $whatToTrace, $self->{ipField}, 'startTime' ] );
[ '_httpSessionType', $tsv->{whatToTrace}, $self->{ipField}, 'startTime' ] );
while ( my ( $id, $entry ) = each %$res ) {
next if ( $entry->{_httpSessionType} );
push @{ $byUid->{ $entry->{$whatToTrace} }
push @{ $byUid->{ $entry->{$tsv->{whatToTrace}} }
->{ $entry->{ $self->{ipField} } } },
{ id => $id, startTime => $entry->{startTime} };
}
@ -250,12 +250,12 @@ sub fullip {
# Parse sessions and store only if IP match regexp
$res = Lemonldap::NG::Common::Apache::Session->searchOnExpr(
$self->{globalStorageOptions},
$self->{ipField}, $req, $whatToTrace, 'startTime', $self->{ipField},
$self->{ipField}, $req, $tsv->{whatToTrace}, 'startTime', $self->{ipField},
'_httpSessionType' );
while ( my ( $id, $entry ) = each %$res ) {
next if ( $entry->{_httpSessionType} );
push @{ $byUid->{ $entry->{ $self->{ipField} } }
->{ $entry->{$whatToTrace} } },
->{ $entry->{$tsv->{whatToTrace}} } },
{ id => $id, startTime => $entry->{startTime} };
}
$res = '';
@ -293,10 +293,10 @@ sub fulluid {
# Parse sessions to find user that match regexp
$res = Lemonldap::NG::Common::Apache::Session->searchOnExpr(
$self->{globalStorageOptions},
$whatToTrace, $req, $whatToTrace, 'startTime', '_httpSessionType' );
$tsv->{whatToTrace}, $req, $tsv->{whatToTrace}, 'startTime', '_httpSessionType' );
while ( my ( $id, $entry ) = each %$res ) {
next if ( $entry->{_httpSessionType} );
push @{ $byUid->{ $entry->{$whatToTrace} } },
push @{ $byUid->{ $entry->{$tsv->{whatToTrace}} } },
{ id => $id, startTime => $entry->{startTime} };
}
$res = '';
@ -341,7 +341,7 @@ sub delete {
my ( %h, $res );
# Try to read session
eval { tie %h, $globalStorage, $id, $globalStorageOptions; };
eval { tie %h, $tsv->{globalStorage}, $id, $tsv->{globalStorageOptions}; };
if ($@) {
if ( $@ =~ /does not exist in the data store/i ) {
$self->lmLog( "Apache::Session error: $@", 'error' );
@ -360,8 +360,8 @@ sub delete {
if ( $h{_httpSession} ) {
my %h2;
eval {
tie %h2, $globalStorage, $h{_httpSession},
$globalStorageOptions;
tie %h2, $tsv->{globalStorage}, $h{_httpSession},
$tsv->{globalStorageOptions};
tied(%h2)->delete();
};
if ($@) {
@ -395,7 +395,7 @@ sub session {
my ( %h, $res );
# Try to read session
eval { tie %h, $globalStorage, $id, $globalStorageOptions; };
eval { tie %h, $tsv->{globalStorage}, $id, $tsv->{globalStorageOptions}; };
if ($@) {
$self->lmLog( "Apache::Session error: $@", 'error' );
$res .= '<h1 class="ui-widget-header ui-corner-all">'
@ -655,12 +655,12 @@ sub uidByIp {
my ( $byUser, $res );
$res = Lemonldap::NG::Common::Apache::Session->searchOn(
$self->{globalStorageOptions},
$self->{ipField}, $ip, '_httpSessionType', $whatToTrace,
$self->{ipField}, $ip, '_httpSessionType', $tsv->{whatToTrace},
$self->{ipField}, 'startTime' );
while ( my ( $id, $entry ) = each(%$res) ) {
next if ( $entry->{_httpSessionType} );
if ( $entry->{ $self->{ipField} } eq $ip ) {
push @{ $byUser->{ $entry->{$whatToTrace} } },
push @{ $byUser->{ $entry->{$tsv->{whatToTrace}} } },
{ id => $id, startTime => $entry->{startTime} };
}
}
@ -688,11 +688,11 @@ sub uid {
my ( $byIp, $res );
$res = Lemonldap::NG::Common::Apache::Session->searchOn(
$self->{globalStorageOptions},
$whatToTrace, $uid, '_httpSessionType', $whatToTrace, $self->{ipField},
$tsv->{whatToTrace}, $uid, '_httpSessionType', $tsv->{whatToTrace}, $self->{ipField},
'startTime' );
while ( my ( $id, $entry ) = each(%$res) ) {
next if ( $entry->{_httpSessionType} );
if ( $entry->{$whatToTrace} eq $uid ) {
if ( $entry->{$tsv->{whatToTrace}} eq $uid ) {
push @{ $byIp->{ $entry->{ $self->{ipField} } } },
{ id => $id, startTime => $entry->{startTime} };
}
@ -724,10 +724,10 @@ sub letter {
$res = Lemonldap::NG::Common::Apache::Session->searchOnExpr(
$self->{globalStorageOptions},
$whatToTrace, "${letter}*", '_httpSessionType', $whatToTrace );
$tsv->{whatToTrace}, "${letter}*", '_httpSessionType', $tsv->{whatToTrace} );
while ( my ( $id, $entry ) = each %$res ) {
next if ( $entry->{_httpSessionType} );
$byUid->{ $entry->{$whatToTrace} }++;
$byUid->{ $entry->{$tsv->{whatToTrace}} }++;
}
$res = '';
foreach my $uid ( sort keys %$byUid ) {