2014-03-13 16:07:36 +01:00
|
|
|
##@file
|
|
|
|
# Auth-basic authentication with Lemonldap::NG rights management
|
|
|
|
|
|
|
|
##@class
|
|
|
|
# Auth-basic authentication with Lemonldap::NG rights management
|
2014-03-20 19:40:26 +01:00
|
|
|
|
|
|
|
# This specific handler is intended to be called directly by Apache
|
|
|
|
|
2014-05-23 12:23:51 +02:00
|
|
|
package Lemonldap::NG::Handler::Specific::AuthBasic;
|
2014-03-13 16:07:36 +01:00
|
|
|
|
2014-05-21 19:44:24 +02:00
|
|
|
use Lemonldap::NG::Handler::SharedConf qw(:all);
|
2014-06-16 11:44:39 +02:00
|
|
|
use Lemonldap::NG::Handler::API qw(:httpCodes);
|
2014-06-25 12:01:17 +02:00
|
|
|
use Digest::MD5;
|
2014-03-13 16:07:36 +01:00
|
|
|
use MIME::Base64;
|
|
|
|
use HTTP::Headers;
|
|
|
|
use SOAP::Lite; # link protected portalRequest
|
2014-04-11 16:58:30 +02:00
|
|
|
use Lemonldap::NG::Common::Session;
|
2014-03-13 16:07:36 +01:00
|
|
|
|
2014-05-21 19:44:24 +02:00
|
|
|
use base qw(Lemonldap::NG::Handler::SharedConf);
|
2014-03-13 16:07:36 +01:00
|
|
|
|
2014-04-11 16:58:30 +02:00
|
|
|
our $VERSION = '1.4.0';
|
2014-03-13 16:07:36 +01:00
|
|
|
|
2014-07-01 14:58:04 +02:00
|
|
|
## @rmethod protected $ fetchId
|
2014-06-25 12:01:17 +02:00
|
|
|
# Get user session id from Authorization header
|
|
|
|
# Unlike usual processing, session id is computed from user creds,
|
|
|
|
# so that it remains secret but handler can easily get it.
|
|
|
|
# It is still changed from time to time - once a day - to prevent from
|
|
|
|
# using indefinitely a session id disclosed accidentally or maliciously.
|
|
|
|
# @return session id
|
|
|
|
sub fetchId {
|
2014-07-01 14:58:04 +02:00
|
|
|
my $class = shift;
|
|
|
|
if ( my $creds = Lemonldap::NG::Handler::API->header_in('Authorization') ) {
|
2014-06-25 12:01:17 +02:00
|
|
|
$creds =~ s/^Basic\s+//;
|
|
|
|
my @date = localtime;
|
2014-07-24 17:48:32 +02:00
|
|
|
my $day = $date[5] * 366 + $date[7];
|
|
|
|
return Digest::MD5::md5_hex( $creds . $day );
|
|
|
|
}
|
|
|
|
else {
|
2014-06-25 12:01:17 +02:00
|
|
|
return 0;
|
2014-03-13 16:07:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 12:01:17 +02:00
|
|
|
## @rmethod protected boolean retrieveSession(id)
|
|
|
|
# Tries to retrieve the session whose index is id,
|
|
|
|
# and if needed, ask portal to create it through a SOAP request
|
|
|
|
# @return true if the session was found, false else
|
|
|
|
sub retrieveSession {
|
2014-07-01 14:58:04 +02:00
|
|
|
my ( $class, $id ) = @_;
|
2014-06-25 12:01:17 +02:00
|
|
|
|
|
|
|
# First check if session already exists
|
2014-07-01 14:58:04 +02:00
|
|
|
return 1 if ( $class->SUPER::retrieveSession($id) );
|
2014-06-25 12:01:17 +02:00
|
|
|
|
|
|
|
# Then ask portal to create it
|
2014-07-01 14:58:04 +02:00
|
|
|
if ( $class->createSession($id) ) {
|
|
|
|
return $class->SUPER::retrieveSession($id);
|
2014-07-24 17:48:32 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-06-25 12:01:17 +02:00
|
|
|
return 0;
|
2014-03-13 16:07:36 +01:00
|
|
|
}
|
2014-06-25 12:01:17 +02:00
|
|
|
}
|
2014-03-13 16:07:36 +01:00
|
|
|
|
2014-06-25 12:01:17 +02:00
|
|
|
## @rmethod protected boolean retrieveSession(id)
|
|
|
|
# Ask portal to create it through a SOAP request
|
|
|
|
# @return true if the session is created, else false
|
|
|
|
sub createSession {
|
2014-07-01 14:58:04 +02:00
|
|
|
my ( $class, $id ) = @_;
|
2014-06-25 12:01:17 +02:00
|
|
|
|
|
|
|
# Add client IP as X-Forwarded-For IP in SOAP request
|
2014-07-01 14:58:04 +02:00
|
|
|
my $xheader = Lemonldap::NG::Handler::API->header_in('X-Forwarded-For');
|
2014-06-25 12:01:17 +02:00
|
|
|
$xheader .= ", " if ($xheader);
|
2014-07-01 14:58:04 +02:00
|
|
|
$xheader .= Lemonldap::NG::Handler::API->remote_ip;
|
2014-06-25 12:01:17 +02:00
|
|
|
my $soapHeaders = HTTP::Headers->new( "X-Forwarded-For" => $xheader );
|
|
|
|
|
2014-07-24 17:48:32 +02:00
|
|
|
my $soapClient =
|
|
|
|
SOAP::Lite->proxy( $class->portal(), default_headers => $soapHeaders )
|
|
|
|
->uri('urn:Lemonldap::NG::Common::CGI::SOAPService');
|
2014-06-25 12:01:17 +02:00
|
|
|
|
2014-07-01 14:58:04 +02:00
|
|
|
my $creds = Lemonldap::NG::Handler::API->header_in('Authorization');
|
2014-06-25 12:01:17 +02:00
|
|
|
$creds =~ s/^Basic\s+//;
|
|
|
|
my ( $user, $pwd ) = ( decode_base64($creds) =~ /^(.*?):(.*)$/ );
|
|
|
|
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
2014-07-01 14:58:04 +02:00
|
|
|
"AuthBasic authentication for user: $user", 'debug' );
|
2014-06-25 12:01:17 +02:00
|
|
|
my $soapRequest = $soapClient->getCookies( $user, $pwd, $id );
|
|
|
|
|
|
|
|
# Catch SOAP errors
|
|
|
|
if ( $soapRequest->fault ) {
|
2014-07-24 17:48:32 +02:00
|
|
|
$class->abort( "SOAP request to the portal failed: "
|
2014-06-25 12:01:17 +02:00
|
|
|
. $soapRequest->fault->{faultstring} );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
my $res = $soapRequest->result();
|
2014-07-24 17:48:32 +02:00
|
|
|
|
2014-06-25 12:01:17 +02:00
|
|
|
# If authentication failed, display error
|
|
|
|
if ( $res->{errorCode} ) {
|
2014-04-11 16:58:30 +02:00
|
|
|
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
2014-06-25 12:01:17 +02:00
|
|
|
"Authentication failed for $user: "
|
|
|
|
. $soapClient->error( $res->{errorCode}, 'en' )->result(),
|
|
|
|
'notice'
|
|
|
|
);
|
|
|
|
return 0;
|
2014-07-24 17:48:32 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-06-25 12:01:17 +02:00
|
|
|
return 1;
|
2014-03-13 16:07:36 +01:00
|
|
|
}
|
|
|
|
}
|
2014-06-25 12:01:17 +02:00
|
|
|
}
|
2014-03-13 16:07:36 +01:00
|
|
|
|
2014-06-25 12:01:17 +02:00
|
|
|
## @rmethod protected void hideCookie()
|
|
|
|
# Hide user credentials to the protected application
|
|
|
|
sub hideCookie {
|
2014-07-01 14:58:04 +02:00
|
|
|
my $class = shift;
|
2014-07-24 17:48:32 +02:00
|
|
|
Lemonldap::NG::Handler::Main::Logger->lmLog(
|
|
|
|
"removing Authorization header", 'debug' );
|
2014-07-01 14:58:04 +02:00
|
|
|
Lemonldap::NG::Handler::API->unset_header_in('Authorization');
|
2014-06-25 12:01:17 +02:00
|
|
|
}
|
2014-04-11 16:58:30 +02:00
|
|
|
|
2014-06-25 12:01:17 +02:00
|
|
|
## @rmethod protected int goToPortal(string url, string arg)
|
|
|
|
# If user is asked to authenticate, return AUTH_REQUIRED,
|
|
|
|
# else redirect him to the portal to display some message defined by $arg
|
|
|
|
# @param $url Url requested
|
|
|
|
# @param $arg optionnal GET parameters
|
|
|
|
# @return Apache2::Const::REDIRECT or Apache2::Const::AUTH_REQUIRED
|
|
|
|
sub goToPortal {
|
2014-07-01 14:58:04 +02:00
|
|
|
my ( $class, $url, $arg ) = @_;
|
2014-06-25 12:01:17 +02:00
|
|
|
if ($arg) {
|
2014-07-01 14:58:04 +02:00
|
|
|
return $class->SUPER::goToPortal( $url, $arg );
|
2014-07-24 17:48:32 +02:00
|
|
|
}
|
|
|
|
else {
|
2014-07-07 10:08:39 +02:00
|
|
|
Lemonldap::NG::Handler::API->set_header_out(
|
2014-06-25 12:01:17 +02:00
|
|
|
'WWW-Authenticate' => 'Basic realm="LemonLDAP::NG"' );
|
|
|
|
return AUTH_REQUIRED;
|
|
|
|
}
|
2014-03-13 16:07:36 +01:00
|
|
|
}
|
|
|
|
|
2014-06-25 12:01:17 +02:00
|
|
|
__PACKAGE__->init();
|
2014-03-13 16:07:36 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2016-01-21 22:15:19 +01:00
|
|
|
=item Copyright (C) 2008-2010 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
|
2014-03-13 16:07:36 +01:00
|
|
|
|
2016-01-21 22:15:19 +01:00
|
|
|
=item Copyright (C) 2012-2013 by François-Xavier Deltombe, E<lt>fxdeltombe@gmail.com.E<gt>
|
2014-03-13 16:07:36 +01:00
|
|
|
|
2016-01-21 22:15:19 +01:00
|
|
|
=item Copyright (C) 2010-2012 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
|
2014-03-13 16:07:36 +01:00
|
|
|
|
|
|
|
=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
|