lemonldap-ng/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/AuthBasic.pm

130 lines
4.0 KiB
Perl
Raw Normal View History

2016-09-30 07:15:17 +02:00
package Lemonldap::NG::Handler::Lib::AuthBasic;
use strict;
use Exporter;
use Digest::MD5;
use MIME::Base64;
use HTTP::Headers;
use SOAP::Lite; # link protected portalRequest
use Lemonldap::NG::Common::Session;
our $VERSION = '2.0.0';
our @ISA = ('Exporter');
our @EXPORT = qw(fetchId retrieveSession createSession hideCookie goToPortal);
our @EXPORT_OK = @EXPORT;
## @rmethod protected fetchId
# 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 {
my $class = shift;
if ( my $creds = $class->header_in('Authorization') ) {
$creds =~ s/^Basic\s+//;
my @date = localtime;
my $day = $date[5] * 366 + $date[7];
return Digest::MD5::md5_hex( $creds . $day );
}
else {
return 0;
}
}
## @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 {
my ( $class, $id ) = @_;
# First check if session already exists
2016-12-26 10:23:35 +01:00
return 1
if ( $class->Lemonldap::NG::Handler::Main::Run::retrieveSession($id) );
2016-09-30 07:15:17 +02:00
# Then ask portal to create it
if ( $class->createSession($id) ) {
2016-10-13 21:42:34 +02:00
return $class->Lemonldap::NG::Handler::Main::Run::retrieveSession($id);
2016-09-30 07:15:17 +02:00
}
else {
return 0;
}
}
## @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 {
my ( $class, $id ) = @_;
# Add client IP as X-Forwarded-For IP in SOAP request
my $xheader = $class->header_in('X-Forwarded-For');
$xheader .= ", " if ($xheader);
$xheader .= $class->remote_ip;
my $soapHeaders = HTTP::Headers->new( "X-Forwarded-For" => $xheader );
2016-10-04 21:45:58 +02:00
my $soapClient = SOAP::Lite->proxy( $class->tsv->{portal}->(),
default_headers => $soapHeaders )
2016-09-30 07:15:17 +02:00
->uri('urn:Lemonldap::NG::Common::CGI::SOAPService');
my $creds = $class->header_in('Authorization');
$creds =~ s/^Basic\s+//;
my ( $user, $pwd ) = ( decode_base64($creds) =~ /^(.*?):(.*)$/ );
$class->lmLog( "AuthBasic authentication for user: $user", 'debug' );
2016-10-13 21:42:34 +02:00
die 'Replace this by REST call';
2016-09-30 07:15:17 +02:00
my $soapRequest = $soapClient->getCookies( $user, $pwd, $id );
# Catch SOAP errors
if ( $soapRequest->fault ) {
$class->abort( "SOAP request to the portal failed: "
. $soapRequest->fault->{faultstring} );
}
else {
my $res = $soapRequest->result();
# If authentication failed, display error
if ( $res->{errorCode} ) {
$class->lmLog(
"Authentication failed for $user: "
. $soapClient->error( $res->{errorCode}, 'en' )->result(),
'notice'
);
return 0;
}
else {
return 1;
}
}
}
## @rmethod protected void hideCookie()
# Hide user credentials to the protected application
sub hideCookie {
my $class = shift;
$class->lmLog( "removing Authorization header", 'debug' );
$class->unset_header_in('Authorization');
}
## @rmethod protected int goToPortal(string url, string arg)
# If user is asked to authenticate, return $class->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 {
my ( $class, $url, $arg ) = @_;
if ($arg) {
2016-12-26 10:23:35 +01:00
return $class->Lemonldap::NG::Handler::Main::Run::goToPortal( $url,
$arg );
2016-09-30 07:15:17 +02:00
}
else {
$class->set_header_out(
'WWW-Authenticate' => 'Basic realm="LemonLDAP::NG"' );
return $class->AUTH_REQUIRED;
}
}
1;