2016-04-01 07:24:27 +02:00
|
|
|
package Lemonldap::NG::Portal::Main::Process;
|
|
|
|
|
2019-02-12 18:21:38 +01:00
|
|
|
our $VERSION = '2.1.0';
|
2016-04-07 23:31:56 +02:00
|
|
|
|
|
|
|
package Lemonldap::NG::Portal::Main;
|
|
|
|
|
2016-04-01 07:24:27 +02:00
|
|
|
use strict;
|
2016-04-02 22:17:39 +02:00
|
|
|
use MIME::Base64;
|
2016-04-04 07:08:26 +02:00
|
|
|
use POSIX qw(strftime);
|
2019-09-17 20:17:57 +02:00
|
|
|
use Lemonldap::NG::Portal::Main::Constants qw(portalConsts);
|
2016-04-01 07:24:27 +02:00
|
|
|
|
2016-04-03 08:33:50 +02:00
|
|
|
# Main method
|
|
|
|
# -----------
|
|
|
|
# Launch all methods declared in request "steps" array. Methods can be
|
|
|
|
# declared by their name (in Lemonldap::NG::Portal::Main namespace) or point
|
|
|
|
# to a subroutine (see Lemonldap::NG::Portal::Main::Run.pm)
|
|
|
|
|
|
|
|
sub process {
|
2018-01-22 21:57:48 +01:00
|
|
|
my ( $self, $req, %args ) = @_;
|
2016-04-03 08:33:50 +02:00
|
|
|
|
2018-10-31 17:58:46 +01:00
|
|
|
# Store ipAddr in env
|
|
|
|
$req->env->{ipAddr} = $req->address;
|
2016-04-03 08:33:50 +02:00
|
|
|
my $err = PE_OK;
|
|
|
|
while ( my $sub = shift @{ $req->steps } ) {
|
|
|
|
if ( ref $sub ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Processing code ref");
|
2018-01-22 21:57:48 +01:00
|
|
|
last if ( $err = $sub->( $req, %args ) );
|
2016-04-03 08:33:50 +02:00
|
|
|
}
|
|
|
|
else {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Processing $sub");
|
2018-12-13 06:57:10 +01:00
|
|
|
if ( my $as = $self->aroundSub->{$sub} ) {
|
|
|
|
last if ( $err = $as->( $req, %args ) );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
last if ( $err = $self->$sub( $req, %args ) );
|
|
|
|
}
|
2018-12-12 22:09:27 +01:00
|
|
|
if ( $self->afterSub->{$sub} ) {
|
|
|
|
unshift @{ $req->steps }, @{ $self->afterSub->{$sub} };
|
|
|
|
}
|
2016-04-03 08:33:50 +02:00
|
|
|
}
|
|
|
|
}
|
2019-09-17 20:17:57 +02:00
|
|
|
$self->logger->debug(
|
|
|
|
"Returned error: $err (" . portalConsts->{$err} . ")" )
|
|
|
|
if ($err);
|
2016-04-03 08:33:50 +02:00
|
|
|
return $err;
|
|
|
|
}
|
|
|
|
|
2016-04-02 22:17:39 +02:00
|
|
|
# First process block: check args
|
|
|
|
# -------------------------------
|
|
|
|
|
2018-07-05 22:56:16 +02:00
|
|
|
# For post requests, parse data
|
2016-04-02 22:17:39 +02:00
|
|
|
sub restoreArgs {
|
|
|
|
my ( $self, $req ) = @_;
|
2016-04-03 08:33:50 +02:00
|
|
|
$req->mustRedirect(1);
|
2020-01-03 12:36:35 +01:00
|
|
|
PE_OK;
|
2016-04-02 22:17:39 +02:00
|
|
|
}
|
|
|
|
|
2018-07-05 22:56:16 +02:00
|
|
|
sub importHandlerData {
|
2016-04-14 20:42:59 +02:00
|
|
|
my ( $self, $req ) = @_;
|
2016-08-02 15:52:29 +02:00
|
|
|
$req->{sessionInfo} = $req->userData;
|
2016-05-22 19:06:55 +02:00
|
|
|
$req->id( $req->sessionInfo->{_session_id} );
|
2016-07-12 07:15:26 +02:00
|
|
|
$req->user( $req->sessionInfo->{ $self->conf->{whatToTrace} } );
|
2016-04-14 20:42:59 +02:00
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2017-01-01 10:43:48 +01:00
|
|
|
# Verify url and confirm parameter
|
2016-04-02 22:17:39 +02:00
|
|
|
sub controlUrl {
|
|
|
|
my ( $self, $req ) = @_;
|
2017-01-01 10:43:48 +01:00
|
|
|
if ( my $c = $req->param('confirm') ) {
|
|
|
|
|
|
|
|
# Replace confirm stamp by 1 or -1
|
|
|
|
$c =~ s/^(-?)(.*)$/${1}1/;
|
|
|
|
|
|
|
|
# Decrypt confirm stamp if cipher available
|
|
|
|
# and confirm not already decrypted
|
|
|
|
if ( $self->conf->{cipher} and $2 ne "1" ) {
|
|
|
|
my $time = time() - $self->conf->{cipher}->decrypt($2);
|
|
|
|
if ( $time < 600 ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Confirm parameter accepted $c");
|
2017-01-04 17:36:54 +01:00
|
|
|
$req->set_param( 'confirm', $c );
|
2017-01-01 10:43:48 +01:00
|
|
|
}
|
|
|
|
else {
|
2019-09-11 16:20:28 +02:00
|
|
|
$self->logger->notice('Confirmation too old, refused');
|
2017-01-04 17:36:54 +01:00
|
|
|
$req->set_param( 'confirm', 0 );
|
2017-01-01 10:43:48 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-09-28 10:28:32 +02:00
|
|
|
$req->{data}->{_url} ||= '';
|
|
|
|
my $url = $req->param('url') || $req->pdata->{_url};
|
2018-07-05 17:39:44 +02:00
|
|
|
if ($url) {
|
2016-04-02 22:17:39 +02:00
|
|
|
|
2016-04-03 08:33:50 +02:00
|
|
|
# REJECT NON BASE64 URL
|
|
|
|
if ( $req->urlNotBase64 ) {
|
2016-05-23 18:55:18 +02:00
|
|
|
$req->{urldc} = $url;
|
2016-04-03 08:33:50 +02:00
|
|
|
}
|
|
|
|
else {
|
2016-04-02 22:17:39 +02:00
|
|
|
if ( $url =~ m#[^A-Za-z0-9\+/=]# ) {
|
2019-06-09 09:11:10 +02:00
|
|
|
unless ( $req->maybeNotBase64 ) {
|
|
|
|
$self->userLogger->error(
|
|
|
|
"Value must be BASE64 encoded (param: url | value: $url)"
|
|
|
|
);
|
|
|
|
return PE_BADURL;
|
|
|
|
}
|
|
|
|
$req->{urldc} = $url;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$req->{urldc} = decode_base64($url);
|
|
|
|
$req->{urldc} =~ s/[\r\n]//sg;
|
2016-04-02 22:17:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-29 13:16:15 +02:00
|
|
|
# For logout request, test if Referer comes from an authorized site
|
2016-05-22 19:06:55 +02:00
|
|
|
my $tmp = (
|
|
|
|
$req->param('logout')
|
2016-05-23 18:55:23 +02:00
|
|
|
? $req->referer
|
2016-05-23 18:55:18 +02:00
|
|
|
: $req->{urldc}
|
2016-05-22 19:06:55 +02:00
|
|
|
);
|
2016-04-02 22:17:39 +02:00
|
|
|
|
|
|
|
# XSS attack
|
2018-09-27 17:39:36 +02:00
|
|
|
if (
|
|
|
|
$self->checkXSSAttack(
|
2016-04-02 22:17:39 +02:00
|
|
|
$req->param('logout') ? 'HTTP Referer' : 'urldc',
|
2016-05-23 18:55:18 +02:00
|
|
|
$req->{urldc}
|
2016-04-02 22:17:39 +02:00
|
|
|
)
|
2018-09-27 17:39:36 +02:00
|
|
|
)
|
2016-04-02 22:17:39 +02:00
|
|
|
{
|
2016-05-23 18:55:18 +02:00
|
|
|
delete $req->{urldc};
|
2016-04-02 22:17:39 +02:00
|
|
|
return PE_BADURL;
|
|
|
|
}
|
|
|
|
|
2018-08-29 13:16:15 +02:00
|
|
|
# Unprotected hosts
|
2016-04-02 22:17:39 +02:00
|
|
|
if ( $tmp and !$self->isTrustedUrl($tmp) ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->userLogger->error(
|
2018-09-27 17:39:36 +02:00
|
|
|
"URL contains a non protected host (param: "
|
|
|
|
. ( $req->param('logout') ? 'HTTP Referer' : 'urldc' )
|
|
|
|
. " | value: $tmp)" );
|
2016-05-23 18:55:18 +02:00
|
|
|
delete $req->{urldc};
|
2016-04-02 22:17:39 +02:00
|
|
|
return PE_BADURL;
|
|
|
|
}
|
|
|
|
|
2018-09-28 10:28:32 +02:00
|
|
|
$req->env->{urldc} = $req->{urldc};
|
|
|
|
$req->env->{_url} = $req->{_url};
|
2018-09-27 17:39:36 +02:00
|
|
|
$req->data->{_url} = $url;
|
|
|
|
$req->pdata->{_url} = $url;
|
2016-04-02 22:17:39 +02:00
|
|
|
}
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2016-04-14 21:49:27 +02:00
|
|
|
sub checkLogout {
|
|
|
|
my ( $self, $req ) = @_;
|
2017-01-04 17:36:54 +01:00
|
|
|
if ( defined $req->param('logout') ) {
|
2016-05-23 18:55:23 +02:00
|
|
|
$req->steps(
|
|
|
|
[ @{ $self->beforeLogout }, 'authLogout', 'deleteSession' ] );
|
2016-04-18 22:23:40 +02:00
|
|
|
}
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2016-05-01 09:30:21 +02:00
|
|
|
sub authLogout {
|
2016-05-23 23:52:32 +02:00
|
|
|
my ( $self, $req ) = @_;
|
2018-07-06 12:15:14 +02:00
|
|
|
my $res = $self->_authentication->authLogout($req);
|
2019-06-09 09:11:10 +02:00
|
|
|
$self->logger->debug('Cleaning pdata');
|
2019-10-09 17:33:41 +02:00
|
|
|
my $tmp =
|
|
|
|
( ref( $req->pdata->{keepPdata} ) eq 'ARRAY' )
|
|
|
|
? $req->pdata->{keepPdata}
|
|
|
|
: [];
|
2019-06-09 09:11:10 +02:00
|
|
|
foreach my $k ( keys %{ $req->pdata } ) {
|
|
|
|
delete $req->pdata->{$k} unless ( grep { $_ eq $k } @$tmp );
|
2018-07-06 12:15:14 +02:00
|
|
|
}
|
2019-06-09 09:11:10 +02:00
|
|
|
$req->pdata->{keepPdata} = $tmp if @$tmp;
|
2018-07-06 12:15:14 +02:00
|
|
|
return $res;
|
2016-05-01 09:30:21 +02:00
|
|
|
}
|
|
|
|
|
2016-04-18 22:23:40 +02:00
|
|
|
sub deleteSession {
|
|
|
|
my ( $self, $req ) = @_;
|
2019-03-26 07:30:36 +01:00
|
|
|
if ( my $id = $req->id || $req->userData->{_session_id} ) {
|
2019-06-28 13:40:56 +02:00
|
|
|
my $apacheSession = $self->getApacheSession($id);
|
2018-04-09 22:33:59 +02:00
|
|
|
unless ($apacheSession) {
|
|
|
|
$self->logger->debug("Session $id already deleted");
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
unless ( $self->_deleteSession( $req, $apacheSession ) ) {
|
|
|
|
$self->logger->error("Unable to delete session $id");
|
|
|
|
$self->logger->error( $apacheSession->error );
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->logger->debug("Session $id deleted from global storage");
|
|
|
|
}
|
2016-04-18 22:23:40 +02:00
|
|
|
}
|
|
|
|
|
2016-08-09 14:08:49 +02:00
|
|
|
# TODO
|
2016-04-18 22:23:40 +02:00
|
|
|
# Collect logout services and build hidden iFrames
|
2018-09-27 17:39:36 +02:00
|
|
|
if ( $req->data->{logoutServices} and %{ $req->data->{logoutServices} } ) {
|
2016-04-18 22:23:40 +02:00
|
|
|
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Create iFrames to forward logout to services");
|
2016-04-18 22:23:40 +02:00
|
|
|
|
2017-10-10 13:04:40 +02:00
|
|
|
$req->info(
|
|
|
|
$self->loadTemplate(
|
2019-06-28 13:40:56 +02:00
|
|
|
$req, 'simpleInfo',
|
|
|
|
params => { trspan => 'logoutFromOtherApp' }
|
2017-10-10 13:04:40 +02:00
|
|
|
)
|
|
|
|
);
|
2016-04-18 22:23:40 +02:00
|
|
|
|
2018-07-05 22:56:16 +02:00
|
|
|
foreach ( keys %{ $req->data->{logoutServices} } ) {
|
2016-12-20 11:43:22 +01:00
|
|
|
my $logoutServiceName = $_;
|
2018-09-27 17:39:36 +02:00
|
|
|
my $logoutServiceUrl =
|
|
|
|
$req->data->{logoutServices}->{$logoutServiceName};
|
2016-04-18 22:23:40 +02:00
|
|
|
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug(
|
|
|
|
"Find logout service $logoutServiceName ($logoutServiceUrl)");
|
2016-04-14 21:49:27 +02:00
|
|
|
|
2018-09-27 17:39:36 +02:00
|
|
|
my $iframe =
|
|
|
|
qq'<iframe src="$logoutServiceUrl" alt="$logoutServiceName"'
|
|
|
|
. ' marginwidth="0" marginheight="0" scrolling="no"'
|
|
|
|
. ' class="hiddenFrame" width="0" height="0"'
|
|
|
|
. ' frameborder="0"></iframe>';
|
2016-04-14 21:49:27 +02:00
|
|
|
|
2017-02-07 18:57:19 +01:00
|
|
|
$req->info($iframe);
|
2016-12-20 11:43:22 +01:00
|
|
|
}
|
2016-04-14 21:49:27 +02:00
|
|
|
|
2016-12-20 11:43:22 +01:00
|
|
|
# Redirect on logout page if no other target defined
|
|
|
|
if ( !$req->urldc and !$req->postUrl ) {
|
2018-09-27 17:39:36 +02:00
|
|
|
$self->logger->debug('No other target defined, redirect on logout');
|
2017-01-04 17:36:54 +01:00
|
|
|
$req->urldc( $req->script_name . "?logout=1" );
|
2016-12-20 11:43:22 +01:00
|
|
|
}
|
|
|
|
}
|
2019-03-26 07:30:36 +01:00
|
|
|
$req->userData( {} );
|
2016-04-14 21:49:27 +02:00
|
|
|
|
2016-04-18 22:23:40 +02:00
|
|
|
# Redirect or Post if asked by authLogout
|
2016-12-20 11:43:22 +01:00
|
|
|
if ( $req->urldc and $req->urldc ne $self->conf->{portal} ) {
|
|
|
|
$req->steps( [] );
|
|
|
|
return PE_REDIRECT;
|
|
|
|
}
|
2016-04-14 21:49:27 +02:00
|
|
|
|
2016-12-20 11:43:22 +01:00
|
|
|
if ( $req->postUrl ) {
|
|
|
|
$req->steps( ['autoPost'] );
|
|
|
|
return PE_OK;
|
|
|
|
}
|
2016-04-14 21:49:27 +02:00
|
|
|
|
2016-04-18 22:23:40 +02:00
|
|
|
# If logout redirects to another URL, just remove next steps for the
|
|
|
|
# request so autoRedirect will be called
|
|
|
|
if ( $req->{urldc} and $req->{urldc} ne $self->conf->{portal} ) {
|
|
|
|
$req->steps( [] );
|
|
|
|
return PE_OK;
|
2016-04-14 21:49:27 +02:00
|
|
|
}
|
|
|
|
|
2016-04-18 22:23:40 +02:00
|
|
|
# Else display "error"
|
|
|
|
return PE_LOGOUT_OK;
|
2016-04-14 21:49:27 +02:00
|
|
|
}
|
|
|
|
|
2016-04-05 13:12:53 +02:00
|
|
|
# Check value to detect XSS attack
|
|
|
|
# @param name Parameter name
|
|
|
|
# @param value Parameter value
|
|
|
|
# @return 1 if attack detected, 0 else
|
|
|
|
sub checkXSSAttack {
|
|
|
|
my ( $self, $name, $value ) = @_;
|
|
|
|
|
|
|
|
# Empty values are not bad
|
|
|
|
return 0 unless $value;
|
|
|
|
|
|
|
|
# Test value
|
2016-06-29 21:40:42 +02:00
|
|
|
$value =~ s/\%25/\%/g;
|
|
|
|
if ( $value =~ m/(?:\0|<|'|"|`|\%(?:00|3C|22|27|2C))/ ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->userLogger->error(
|
|
|
|
"XSS attack detected (param: $name | value: $value)");
|
2016-04-05 13:12:53 +02:00
|
|
|
return $self->conf->{checkXSS};
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-04-02 22:17:39 +02:00
|
|
|
# Second block: auth process (call auth or userDB object)
|
|
|
|
# -------------------------------------------------------
|
|
|
|
|
2016-04-01 07:24:27 +02:00
|
|
|
sub extractFormInfo {
|
2016-05-23 23:52:32 +02:00
|
|
|
my ( $self, $req ) = @_;
|
2017-09-08 12:10:37 +02:00
|
|
|
return PE_ERROR unless ( $self->_authentication );
|
2016-05-25 21:30:43 +02:00
|
|
|
my $ret = $self->_authentication->extractFormInfo($req);
|
2016-12-01 23:25:05 +01:00
|
|
|
if ( $ret == PE_OK and not( $req->user or $req->continue ) ) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->error(
|
|
|
|
'Authentication module succeed but has not set $req->user');
|
2016-05-25 21:30:43 +02:00
|
|
|
return PE_ERROR;
|
|
|
|
}
|
2017-01-12 18:44:30 +01:00
|
|
|
elsif ( $ret == PE_FIRSTACCESS
|
|
|
|
and $req->cookies->{ $self->conf->{cookieName} } )
|
|
|
|
{
|
2017-01-13 15:35:02 +01:00
|
|
|
$req->addCookie(
|
|
|
|
$self->cookie(
|
|
|
|
name => $self->conf->{cookieName},
|
|
|
|
value => 0,
|
|
|
|
domain => $self->conf->{domain},
|
|
|
|
secure => 0,
|
2017-03-15 11:01:29 +01:00
|
|
|
expires => 'Wed, 21 Oct 2015 00:00:00 GMT'
|
2017-01-13 15:35:02 +01:00
|
|
|
)
|
|
|
|
);
|
2017-04-27 12:21:46 +02:00
|
|
|
if ( $self->conf->{portalErrorOnExpiredSession} ) {
|
|
|
|
$ret = PE_SESSIONEXPIRED;
|
|
|
|
}
|
2017-01-12 18:44:30 +01:00
|
|
|
}
|
2016-05-25 21:30:43 +02:00
|
|
|
return $ret;
|
2016-04-01 07:24:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sub getUser {
|
2018-01-23 23:01:17 +01:00
|
|
|
my ( $self, $req, %args ) = @_;
|
2017-09-08 12:10:37 +02:00
|
|
|
return PE_ERROR unless ( $self->_userDB );
|
2018-01-23 23:01:17 +01:00
|
|
|
return $self->_userDB->getUser( $req, %args );
|
2016-04-01 07:24:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sub authenticate {
|
2016-05-23 23:52:32 +02:00
|
|
|
my ( $self, $req ) = @_;
|
2017-06-13 15:03:13 +02:00
|
|
|
my $ret = $req->authResult( $self->_authentication->authenticate($req) );
|
2018-09-27 17:39:36 +02:00
|
|
|
$self->logger->debug( " -> authResult = " . $req->authResult );
|
2017-06-13 15:03:13 +02:00
|
|
|
if ( $ret == PE_OK ) {
|
|
|
|
$req->{sessionInfo}->{_lastAuthnUTime} = time();
|
2018-09-12 23:14:35 +02:00
|
|
|
return $ret;
|
2017-06-13 15:03:13 +02:00
|
|
|
}
|
|
|
|
|
2018-09-21 21:22:29 +02:00
|
|
|
# Store failed login into history
|
2019-02-07 09:27:56 +01:00
|
|
|
$req->steps( [
|
2018-09-27 17:39:36 +02:00
|
|
|
'setSessionInfo', 'setMacros',
|
2018-09-21 21:22:29 +02:00
|
|
|
'setPersistentSessionInfo', 'storeHistory',
|
2020-01-04 08:21:38 +01:00
|
|
|
@{ $self->afterData }, sub { PE_BADCREDENTIALS }
|
2018-09-21 21:22:29 +02:00
|
|
|
]
|
|
|
|
);
|
2018-09-22 10:14:29 +02:00
|
|
|
|
2019-02-06 15:36:45 +01:00
|
|
|
# Ignore result, process will end at least with PE_BADCREDENTIALS
|
|
|
|
my $tmp = $self->process($req);
|
|
|
|
$ret = $tmp if ( $tmp == PE_WAIT );
|
|
|
|
return $ret;
|
2016-04-01 07:24:27 +02:00
|
|
|
}
|
|
|
|
|
2016-04-02 22:17:39 +02:00
|
|
|
# Third block: Session data providing
|
|
|
|
# -----------------------------------
|
2016-04-01 07:24:27 +02:00
|
|
|
|
2016-12-01 23:25:05 +01:00
|
|
|
sub setAuthSessionInfo {
|
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
my $ret = $self->_authentication->setAuthSessionInfo($req);
|
2016-12-02 06:47:38 +01:00
|
|
|
if ( $ret == PE_OK
|
|
|
|
and not( defined $req->sessionInfo->{authenticationLevel} ) )
|
|
|
|
{
|
2018-09-27 17:39:36 +02:00
|
|
|
$self->logger->error('Authentication level is not set by auth module');
|
2016-12-01 23:25:05 +01:00
|
|
|
}
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
2016-04-01 07:24:27 +02:00
|
|
|
sub setSessionInfo {
|
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
|
2016-04-05 22:46:11 +02:00
|
|
|
# Set _user
|
2020-01-03 12:36:35 +01:00
|
|
|
$req->{sessionInfo}->{_user} //= $req->user;
|
2016-04-05 22:46:11 +02:00
|
|
|
|
2016-04-01 07:24:27 +02:00
|
|
|
# Get the current user module
|
2016-04-03 18:27:22 +02:00
|
|
|
$req->{sessionInfo}->{_auth} = $self->getModule( $req, "auth" );
|
|
|
|
$req->{sessionInfo}->{_userDB} = $self->getModule( $req, "user" );
|
2016-04-01 07:24:27 +02:00
|
|
|
|
|
|
|
# Store IP address from remote address or X-FORWARDED-FOR header
|
2017-01-04 17:36:54 +01:00
|
|
|
$req->{sessionInfo}->{ipAddr} = $req->address;
|
2016-04-01 07:24:27 +02:00
|
|
|
|
|
|
|
# Date and time
|
|
|
|
if ( $self->conf->{updateSession} ) {
|
2018-09-27 17:39:36 +02:00
|
|
|
$req->{sessionInfo}->{_updateTime} =
|
|
|
|
strftime( "%Y%m%d%H%M%S", localtime() );
|
2016-04-01 07:24:27 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
$req->{sessionInfo}->{_utime} ||= time();
|
2018-09-27 17:39:36 +02:00
|
|
|
$req->{sessionInfo}->{_startTime} =
|
|
|
|
strftime( "%Y%m%d%H%M%S", localtime() );
|
2016-04-02 22:17:39 +02:00
|
|
|
$req->{sessionInfo}->{_lastSeen} = time()
|
2018-09-27 17:39:36 +02:00
|
|
|
if $self->conf->{timeoutActivity};
|
2016-04-01 07:24:27 +02:00
|
|
|
}
|
|
|
|
|
2019-06-13 09:25:32 +02:00
|
|
|
# Currently selected language
|
|
|
|
$req->{sessionInfo}->{_language} = $req->cookies->{llnglanguage} || 'en';
|
|
|
|
|
2016-04-01 07:24:27 +02:00
|
|
|
# Store URL origin in session
|
2016-05-23 18:55:18 +02:00
|
|
|
$req->{sessionInfo}->{_url} = $req->{urldc};
|
2016-04-01 07:24:27 +02:00
|
|
|
|
2016-04-03 18:27:17 +02:00
|
|
|
# Share sessionInfo with underlying handler (needed for safe jail)
|
2016-08-03 09:31:36 +02:00
|
|
|
$req->userData( $req->sessionInfo );
|
2016-04-03 18:27:17 +02:00
|
|
|
|
2016-04-01 07:24:27 +02:00
|
|
|
# Call UserDB setSessionInfo
|
2016-04-03 08:33:50 +02:00
|
|
|
return $self->_userDB->setSessionInfo($req);
|
2016-04-01 07:24:27 +02:00
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub setMacros {
|
2016-04-03 08:33:50 +02:00
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
foreach ( sort keys %{ $self->_macros } ) {
|
2018-09-27 17:39:36 +02:00
|
|
|
$req->{sessionInfo}->{$_} =
|
|
|
|
$self->_macros->{$_}->( $req, $req->sessionInfo );
|
2016-04-03 08:33:50 +02:00
|
|
|
}
|
|
|
|
PE_OK;
|
2016-04-01 07:24:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sub setGroups {
|
2016-04-03 08:33:50 +02:00
|
|
|
my ( $self, $req ) = @_;
|
2016-05-23 23:52:32 +02:00
|
|
|
return $self->_userDB->setGroups($req);
|
2016-04-01 07:24:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sub setPersistentSessionInfo {
|
2016-04-03 08:33:50 +02:00
|
|
|
my ( $self, $req ) = @_;
|
2016-04-01 12:10:42 +02:00
|
|
|
|
2016-04-03 08:33:50 +02:00
|
|
|
# Do not restore infos if session already opened
|
2020-01-03 12:36:35 +01:00
|
|
|
unless ( $req->id ) {
|
2016-04-03 08:33:50 +02:00
|
|
|
my $key = $req->{sessionInfo}->{ $self->conf->{whatToTrace} };
|
2016-04-01 12:10:42 +02:00
|
|
|
|
2016-04-03 08:33:50 +02:00
|
|
|
return PE_OK unless ( $key and length($key) );
|
2016-04-01 12:10:42 +02:00
|
|
|
|
2016-04-03 08:33:50 +02:00
|
|
|
my $persistentSession = $self->getPersistentSession($key);
|
2016-04-01 12:10:42 +02:00
|
|
|
|
2016-04-03 08:33:50 +02:00
|
|
|
if ($persistentSession) {
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Persistent session found for $key");
|
2016-04-03 08:33:50 +02:00
|
|
|
foreach my $k ( keys %{ $persistentSession->data } ) {
|
2016-04-01 12:10:42 +02:00
|
|
|
|
2016-04-03 08:33:50 +02:00
|
|
|
# Do not restore some parameters
|
|
|
|
next if $k =~ /^_(?:utime|session_(?:u?id|kind))$/;
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Restore persistent parameter $k");
|
2016-04-03 08:33:50 +02:00
|
|
|
$req->{sessionInfo}->{$k} = $persistentSession->data->{$k};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PE_OK;
|
2016-04-01 07:24:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sub setLocalGroups {
|
2016-04-03 08:33:50 +02:00
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
foreach ( sort keys %{ $self->_groups } ) {
|
2017-03-28 23:07:49 +02:00
|
|
|
if ( $self->_groups->{$_}->( $req, $req->sessionInfo ) ) {
|
2018-09-27 17:39:36 +02:00
|
|
|
$req->{sessionInfo}->{groups} .=
|
|
|
|
$self->conf->{multiValuesSeparator} . $_;
|
2016-04-03 08:33:50 +02:00
|
|
|
$req->{sessionInfo}->{hGroups}->{$_}->{name} = $_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Clear values separator at the beginning
|
|
|
|
if ( $req->{sessionInfo}->{groups} ) {
|
2018-09-27 17:39:36 +02:00
|
|
|
$req->{sessionInfo}->{groups} =~
|
|
|
|
s/^$self->{conf}->{multiValuesSeparator}//o;
|
2016-04-03 08:33:50 +02:00
|
|
|
}
|
|
|
|
PE_OK;
|
2016-04-01 07:24:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sub store {
|
2016-04-03 08:33:50 +02:00
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
|
|
|
|
# Now, user is authenticated => inform handler
|
|
|
|
$req->userData( $req->sessionInfo );
|
|
|
|
|
|
|
|
# Create second session for unsecure cookie
|
2020-01-03 12:36:35 +01:00
|
|
|
if ( $self->conf->{securedCookie} == 2 and !$req->refresh ) {
|
2016-04-03 08:33:50 +02:00
|
|
|
my %infos = %{ $req->{sessionInfo} };
|
2019-05-26 11:56:58 +02:00
|
|
|
$infos{_updateTime} = strftime( "%Y%m%d%H%M%S", localtime() );
|
2019-06-11 16:04:24 +02:00
|
|
|
$self->logger->debug("Set _updateTime with $infos{_updateTime}");
|
2016-04-03 08:33:50 +02:00
|
|
|
$infos{_httpSessionType} = 1;
|
|
|
|
|
2017-02-20 22:00:05 +01:00
|
|
|
my $session2 = $self->getApacheSession( undef, info => \%infos );
|
2019-05-19 13:40:46 +02:00
|
|
|
$self->logger->debug("Create second session for unsecured cookie...");
|
2016-04-03 08:33:50 +02:00
|
|
|
$req->{sessionInfo}->{_httpSession} = $session2->id;
|
2019-05-19 13:40:46 +02:00
|
|
|
$self->logger->debug( " -> Cookie value : " . $session2->id );
|
2016-04-03 08:33:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Fill session
|
|
|
|
my $infos = {};
|
|
|
|
foreach my $k ( keys %{ $req->{sessionInfo} } ) {
|
|
|
|
next unless defined $req->{sessionInfo}->{$k};
|
|
|
|
my $displayValue = $req->{sessionInfo}->{$k};
|
2016-04-04 22:39:22 +02:00
|
|
|
if ( $self->conf->{hiddenAttributes}
|
|
|
|
and $self->conf->{hiddenAttributes} =~ /\b$k\b/ )
|
|
|
|
{
|
2016-04-03 08:33:50 +02:00
|
|
|
$displayValue = '****';
|
|
|
|
}
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Store $displayValue in session key $k");
|
2016-04-03 08:33:50 +02:00
|
|
|
$self->_dump($displayValue) if ref($displayValue);
|
2016-04-05 13:12:53 +02:00
|
|
|
$infos->{$k} = $req->{sessionInfo}->{$k};
|
2016-04-03 08:33:50 +02:00
|
|
|
}
|
2017-02-20 22:00:05 +01:00
|
|
|
|
|
|
|
# Main session
|
|
|
|
my $session = $self->getApacheSession(
|
2020-01-03 12:36:35 +01:00
|
|
|
$req->id,
|
2017-02-20 22:00:05 +01:00
|
|
|
force => $req->{force},
|
|
|
|
info => $infos
|
|
|
|
);
|
|
|
|
return PE_APACHESESSIONERROR unless ($session);
|
2020-01-03 12:36:35 +01:00
|
|
|
|
|
|
|
# Update current request
|
|
|
|
$req->id( $session->id );
|
2020-01-03 23:39:57 +01:00
|
|
|
unless ( $self->_sfEngine->searchForAuthorized2Fmodules($req) ) {
|
2020-01-04 08:21:38 +01:00
|
|
|
$self->logger->debug(
|
|
|
|
"No 2F module authorized -> Update current request");
|
2020-01-03 23:39:57 +01:00
|
|
|
$req->{sessionInfo}->{_session_id} = $session->{id};
|
|
|
|
$req->{sessionInfo}->{_session_kind} = $session->{kind};
|
|
|
|
}
|
2016-04-03 08:33:50 +02:00
|
|
|
|
2019-05-19 13:40:46 +02:00
|
|
|
# Compute unsecured cookie value if needed
|
2020-01-03 12:36:35 +01:00
|
|
|
if ( $self->conf->{securedCookie} == 3 and !$req->refresh ) {
|
2019-05-19 13:40:46 +02:00
|
|
|
$req->{sessionInfo}->{_httpSession} =
|
2020-01-03 12:36:35 +01:00
|
|
|
$self->conf->{cipher}->encryptHex( $req->id, "http" );
|
2019-05-19 13:40:46 +02:00
|
|
|
$self->logger->debug( " -> Compute unsecured cookie value : "
|
|
|
|
. $req->{sessionInfo}->{_httpSession} );
|
|
|
|
}
|
2019-05-20 23:02:40 +02:00
|
|
|
$req->refresh(0);
|
2016-04-03 08:33:50 +02:00
|
|
|
PE_OK;
|
2016-04-01 07:24:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sub buildCookie {
|
2016-04-03 08:33:50 +02:00
|
|
|
my ( $self, $req ) = @_;
|
2017-02-07 23:04:49 +01:00
|
|
|
if ( $req->id ) {
|
2017-01-13 15:35:02 +01:00
|
|
|
$req->addCookie(
|
|
|
|
$self->cookie(
|
2017-02-07 23:04:49 +01:00
|
|
|
name => $self->conf->{cookieName},
|
2020-01-03 12:36:35 +01:00
|
|
|
value => $req->id,
|
2017-01-13 15:35:02 +01:00
|
|
|
domain => $self->conf->{domain},
|
2017-02-07 23:04:49 +01:00
|
|
|
secure => $self->conf->{securedCookie},
|
2017-01-13 15:35:02 +01:00
|
|
|
)
|
|
|
|
);
|
2017-02-07 23:04:49 +01:00
|
|
|
if ( $self->conf->{securedCookie} >= 2 ) {
|
|
|
|
$req->addCookie(
|
|
|
|
$self->cookie(
|
|
|
|
name => $self->conf->{cookieName} . "http",
|
|
|
|
value => $req->{sessionInfo}->{_httpSession},
|
|
|
|
domain => $self->conf->{domain},
|
|
|
|
secure => 0,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2016-04-03 08:33:50 +02:00
|
|
|
}
|
2020-01-04 08:21:38 +01:00
|
|
|
my $ref = (
|
|
|
|
%{ $req->{sessionInfo} }
|
|
|
|
? $req->{sessionInfo}
|
|
|
|
: $req->{userData}
|
|
|
|
);
|
|
|
|
$self->userLogger->notice( 'User '
|
|
|
|
. $ref->{ $self->conf->{whatToTrace} }
|
|
|
|
. " successfully authenticated at level $ref->{authenticationLevel}"
|
2019-09-18 19:59:35 +02:00
|
|
|
);
|
2016-04-03 08:33:50 +02:00
|
|
|
PE_OK;
|
2016-04-01 12:10:42 +02:00
|
|
|
}
|
|
|
|
|
2018-03-08 20:36:32 +01:00
|
|
|
sub secondFactor {
|
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
return $self->_sfEngine->run($req);
|
|
|
|
}
|
|
|
|
|
2018-03-21 20:48:31 +01:00
|
|
|
sub storeHistory {
|
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
if ( $self->conf->{loginHistoryEnabled} ) {
|
|
|
|
$self->registerLogin($req);
|
|
|
|
}
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2016-04-01 07:24:27 +02:00
|
|
|
1;
|