Commit 6a7ac2bf authored by Clément OUDOT's avatar Clément OUDOT

First version of Secure Token Handler (#288)

parent 56f1213c
......@@ -353,6 +353,7 @@ install_handler_site: install_conf_dir
@cp --remove-destination ${SRCHANDLERDIR}/example/MyHandler.pm ${RHANDLERDIR}
@cp --remove-destination ${SRCHANDLERDIR}/example/MyHandlerZimbra.pm ${RHANDLERDIR}
@cp --remove-destination ${SRCHANDLERDIR}/example/MyHandlerSympa.pm ${RHANDLERDIR}
@cp --remove-destination ${SRCHANDLERDIR}/example/MyHandlerSecureToken.pm ${RHANDLERDIR}
@cp --remove-destination ${SRCHANDLERDIR}/example/MyUpdateCookieHandler.pm ${RHANDLERDIR}
@cp --remove-destination lemonldap-ng-handler/example/scripts/purgeLocalCache.cron.d $(RCRONDIR)/lemonldap-ng-handler
@if [ ! "$(APACHEUSER)" ]; then \
......@@ -610,6 +611,8 @@ default-diff:
@$(DIFF) lemonldap-ng-handler/example/MyHandler.pm $(LMPREFIX)/handler/MyHandler.pm ||true
@$(DIFF) lemonldap-ng-handler/example/MyHandlerZimbra.pm $(LMPREFIX)/handler/MyHandlerZimbra.pm ||true
@$(DIFF) lemonldap-ng-handler/example/MyHandlerSympa.pm $(LMPREFIX)/handler/MyHandlerSympa.pm ||true
@$(DIFF) lemonldap-ng-handler/example/MyHandlerSecureToken.pm $(LMPREFIX)/handler/MyHandlerSecureToken.pm ||true
@$(DIFF) lemonldap-ng-handler/example/MyUpdateCookieHandler.pm $(LMPREFIX)/handler/MyUpdateCookieHandler.pm ||true
@$(DIFF) lemonldap-ng-handler/example/scripts/purgeLocalCache $(LMPREFIX)/bin/purgeLocalCache ||true
@# Common
@$(DIFF) lemonldap-ng-common/lib/Lemonldap/NG/Common /usr/local/share/perl/5.10.0/Lemonldap/NG/Common ||true
......
......@@ -3,6 +3,7 @@ example/autoProtectedCGI.pl
example/menu.pl
example/MyHandler.pm
example/MyHandlerLog4Perl.pm
example/MyHandlerSecureToken.pm
example/MyHandlerSympa.pm
example/MyHandlerZimbra.pm
example/MyUpdateCookieHandler.pm
......@@ -13,6 +14,7 @@ lib/Lemonldap/NG/Handler/AuthBasic.pm
lib/Lemonldap/NG/Handler/CDA.pm
lib/Lemonldap/NG/Handler/CGI.pm
lib/Lemonldap/NG/Handler/Proxy.pm
lib/Lemonldap/NG/Handler/SecureToken.pm
lib/Lemonldap/NG/Handler/SharedConf.pm
lib/Lemonldap/NG/Handler/Simple.pm
lib/Lemonldap/NG/Handler/Status.pm
......@@ -32,4 +34,5 @@ t/11-Lemonldap-NG-Handler-Status.t
t/20-Lemonldap-NG-Handler-CDA.t
t/30-Lemonldap-NG-Handler-CGI.t
t/40-Lemonldap-NG-Handler-Proxy.t
t/50-Lemonldap-NG-Handler-SecureToken.t
t/99-pod.t
# Handler for Secure Token
package My::SecureToken;
# Load Secure Token Handler
use Lemonldap::NG::Handler::SecureToken;
@ISA = qw(Lemonldap::NG::Handler::SecureToken);
__PACKAGE__->init(
{
# See Lemonldap::NG::Handler
}
);
1;
##@file
# Secure Token
##@class
# Secure Token
#
# Create a secure token used to resolve user identity by a protected application
package Lemonldap::NG::Handler::SecureToken;
use strict;
use Lemonldap::NG::Handler::SharedConf qw(:all);
use base qw(Lemonldap::NG::Handler::SharedConf);
use Cache::Memcached;
use Apache::Session::Generate::MD5;
our $VERSION = '1.1.0';
# Shared variables
our (
$secureTokenMemcachedServers, $secureTokenExpiration,
$secureTokenAttribute, $secureTokenUrls,
$secureTokenHeader, $datas,
$secureTokenMemcachedConnection
);
BEGIN {
eval {
require threads::shared;
threads::share($secureTokenMemcachedConnection);
};
}
## @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';
# 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' );
# Delete Secure Token parameters
delete $args->{'secureTokenMemcachedServers'};
delete $args->{'secureTokenExpiration'};
delete $args->{'secureTokenAttribute'};
delete $args->{'secureTokenUrls'};
delete $args->{'secureTokenHeader'};
# 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;
$class->lmLog( "URL $uri detected as an Secure Token URL (rule $_)",
'debug' );
last;
}
}
return OK unless ($checkurl);
# Memcached connection
unless ($secureTokenMemcachedConnection) {
$secureTokenMemcachedConnection = $class->_createMemcachedConnection();
}
# Value to store
my $value = $datas->{$secureTokenAttribute};
# Set token
my $key = $class->_setToken($value);
# Header location
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,
};
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) {
$class->lmLog( "Unable to store secure token $key", 'error' );
return;
}
$class->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) {
$class->lmLog( "Unable to delete secure token $key", 'error' );
}
else {
$class->lmLog( "Token $key deleted", 'info' );
}
return $res;
}
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
Clement Oudot, E<lt>coudot@linagora.comE<gt>
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2011 by Clement Oudot
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.10.0 or,
at your option, any later version of Perl 5 you may have available.
=cut
# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl Lemonldap-NG-Handler-Proxy.t'
#########################
# change 'tests => 1' to 'tests => last_test_to_print';
use Test::More tests => 1;
#########################
# Insert your test code below, the Test::More module is use()ed here so read
# its man page ( perldoc Test::More ) for help writing this test script.
SKIP: {
eval { require Cache::Memcached };
skip
"Cache::Memcached is not installed, so Lemonldap::NG::Handler::SecureToken will not be useable",
1
if ($@);
use_ok('Lemonldap::NG::Handler::SecureToken');
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment