##@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 directly by Apache package Lemonldap::NG::Handler::Specific::AuthBasic; use Lemonldap::NG::Handler::ApacheMP2; use Digest::MD5; use MIME::Base64; use HTTP::Headers; use SOAP::Lite; # link protected portalRequest use Lemonldap::NG::Common::Session; use base qw(Lemonldap::NG::Handler::ApacheMP2); our $VERSION = '2.0.0'; ## @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 return 1 if ( $class->SUPER::retrieveSession($id) ); # Then ask portal to create it if ( $class->createSession($id) ) { return $class->SUPER::retrieveSession($id); } 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 ); my $soapClient = SOAP::Lite->proxy( $tsv->{portal}->(), default_headers => $soapHeaders ) ->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' ); 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) { return $class->SUPER::goToPortal( $url, $arg ); } else { $class->set_header_out( 'WWW-Authenticate' => 'Basic realm="LemonLDAP::NG"' ); return $class->AUTH_REQUIRED; } } __PACKAGE__->init(); 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 /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, L =head1 AUTHOR =over =item Clement Oudot, Eclem.oudot@gmail.comE =item François-Xavier Deltombe, Efxdeltombe@gmail.com.E =item Xavier Guimard, Ex.guimard@free.frE =back =head1 BUG REPORT Use OW2 system to report bug or ask for features: L =head1 DOWNLOAD Lemonldap::NG is available at L =head1 COPYRIGHT AND LICENSE =over =item Copyright (C) 2008-2010 by Xavier Guimard, Ex.guimard@free.frE =item Copyright (C) 2012-2013 by François-Xavier Deltombe, Efxdeltombe@gmail.com.E =item Copyright (C) 2010-2012 by Clement Oudot, Eclem.oudot@gmail.comE =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. =cut