286 lines
8.9 KiB
Perl
286 lines
8.9 KiB
Perl
package Lemonldap::NG::Portal::Plugins::ContextSwitching;
|
|
|
|
use strict;
|
|
use Mouse;
|
|
use Lemonldap::NG::Portal::Main::Constants
|
|
qw( PE_OK PE_REDIRECT PE_BADCREDENTIALS PE_IMPERSONATION_SERVICE_NOT_ALLOWED PE_MALFORMEDUSER );
|
|
|
|
our $VERSION = '2.0.6';
|
|
|
|
extends
|
|
qw(Lemonldap::NG::Portal::Main::Plugin Lemonldap::NG::Portal::Lib::_tokenRule);
|
|
|
|
# INITIALIZATION
|
|
|
|
has rule => ( is => 'rw', default => sub { 1 } );
|
|
has idRule => ( is => 'rw', default => sub { 1 } );
|
|
|
|
sub hAttr {
|
|
$_[0]->{conf}->{contextSwitchingHiddenAttributes} . ' '
|
|
. $_[0]->{conf}->{hiddenAttributes};
|
|
}
|
|
|
|
has ott => (
|
|
is => 'rw',
|
|
lazy => 1,
|
|
default => sub {
|
|
my $ott =
|
|
$_[0]->{p}->loadModule('Lemonldap::NG::Portal::Lib::OneTimeToken');
|
|
$ott->timeout( $_[0]->{conf}->{formTimeout} );
|
|
return $ott;
|
|
}
|
|
);
|
|
|
|
sub init {
|
|
my ($self) = @_;
|
|
my $hd = $self->p->HANDLER;
|
|
$self->addAuthRoute( switchcontext => 'run', ['POST'] );
|
|
$self->addAuthRoute( switchcontext => 'display', ['GET'] );
|
|
|
|
# Parse activation rule
|
|
$self->logger->debug(
|
|
'ContextSwitching rule -> ' . $self->conf->{contextSwitchingRule} );
|
|
my $rule =
|
|
$hd->buildSub( $hd->substitute( $self->conf->{contextSwitchingRule} ) );
|
|
unless ($rule) {
|
|
$self->error(
|
|
'Bad contextSwitching rule -> ' . $hd->tsv->{jail}->error );
|
|
return 0;
|
|
}
|
|
$self->rule($rule);
|
|
|
|
# Parse identity rule
|
|
$self->logger->debug( "ContextSwitching identities rule -> "
|
|
. $self->conf->{contextSwitchingIdRule} );
|
|
$rule =
|
|
$hd->buildSub( $hd->substitute( $self->conf->{contextSwitchingIdRule} ) );
|
|
unless ($rule) {
|
|
$self->error( "Bad contextSwitching identities rule -> "
|
|
. $hd->tsv->{jail}->error );
|
|
return 0;
|
|
}
|
|
$self->idRule($rule);
|
|
|
|
return 1;
|
|
}
|
|
|
|
# RUNNING METHOD
|
|
|
|
sub display {
|
|
my ( $self, $req ) = @_;
|
|
|
|
# Check access rules
|
|
unless ( $self->rule->( $req, $req->userData )
|
|
|| $req->userData->{"$self->{conf}->{impersonationPrefix}_session_id"} )
|
|
{
|
|
$self->userLogger->error('Context switching service not authorized');
|
|
return $self->p->do( $req,
|
|
[ sub { PE_IMPERSONATION_SERVICE_NOT_ALLOWED } ] );
|
|
}
|
|
|
|
if ( $req->userData->{"$self->{conf}->{impersonationPrefix}_session_id"} ) {
|
|
if ( $self->conf->{contextSwitchingStopWithLogout} ) {
|
|
$self->logger->debug('Stop context switching -> Logout requested');
|
|
return $self->p->do( $req,
|
|
[ @{ $self->p->beforeLogout }, 'authLogout', 'deleteSession' ]
|
|
);
|
|
}
|
|
else {
|
|
$self->p->updateSession( $req, $self->_stopImpersonation($req) );
|
|
return $self->p->do( $req, [ sub { PE_REDIRECT } ] );
|
|
}
|
|
}
|
|
|
|
# Display form
|
|
my $params = {
|
|
PORTAL => $self->conf->{portal},
|
|
MAIN_LOGO => $self->conf->{portalMainLogo},
|
|
LANGS => $self->conf->{showLanguages},
|
|
MSG => 'contextSwitching_ON',
|
|
ALERTE => 'alert-danger',
|
|
LOGIN => '',
|
|
SPOOFID => $self->conf->{contextSwitchingRule},
|
|
TOKEN => (
|
|
$self->ottRule->( $req, {} )
|
|
? $self->ott->createToken()
|
|
: ''
|
|
)
|
|
};
|
|
|
|
return $self->p->sendHtml( $req, 'contextSwitching', params => $params, );
|
|
}
|
|
|
|
sub run {
|
|
my ( $self, $req ) = @_;
|
|
my $statut = PE_OK;
|
|
|
|
# if ( $req->userData->{"$self->{conf}->{impersonationPrefix}_session_id"} ) {
|
|
# if ( $self->conf->{contextSwitchingStopWithLogout} ) {
|
|
# $self->userLogger->error('Stop context switching -> Logout requested');
|
|
# return $self->p->do( $req,
|
|
# [ @{ $self->p->beforeLogout }, 'authLogout', 'deleteSession' ]
|
|
# );
|
|
# }
|
|
# else {
|
|
# $self->p->updateSession( $req, $self->_stopImpersonation($req) );
|
|
# return $self->p->do( $req, [ sub { PE_REDIRECT } ] );
|
|
# }
|
|
# }
|
|
|
|
my $spoofId = $req->param('spoofId') || ''; # Impersonation required ?
|
|
|
|
# Check activation rule
|
|
unless ( $self->rule->( $req, $req->userData ) ) {
|
|
$self->userLogger->error('Context switching service not authorized');
|
|
$spoofId = '';
|
|
return $self->p->do( $req,
|
|
[ sub { PE_IMPERSONATION_SERVICE_NOT_ALLOWED } ] );
|
|
}
|
|
|
|
if ( $spoofId && $spoofId ne $req->{user} ) {
|
|
$self->logger->debug("Spoof Id: $spoofId");
|
|
unless ( $spoofId =~ /$self->{conf}->{userControl}/o ) {
|
|
$self->userLogger->error('Malformed spoofed Id');
|
|
$self->logger->debug(
|
|
"Context switching tried with spoofed Id: $spoofId");
|
|
return $self->p->do( $req, [ sub { PE_MALFORMEDUSER } ] );
|
|
}
|
|
}
|
|
else {
|
|
$self->logger->debug("No context switching required");
|
|
$req->urldc( $self->conf->{portal} );
|
|
return $self->p->do( $req, [ sub { PE_OK } ] );
|
|
}
|
|
|
|
# Fill spoof session
|
|
my ( $realSession, $spoofSession ) = ( {}, {} );
|
|
$self->logger->debug("Rename real attributes...");
|
|
|
|
foreach ( grep { !/^$self->{conf}->{impersonationPrefix}/ }
|
|
keys %{ $req->{userData} } )
|
|
{
|
|
my $spk = "$self->{conf}->{impersonationPrefix}$_";
|
|
$realSession->{$spk} = $req->{userData}->{$_};
|
|
$self->logger->debug("-> Store $_ in realSession key: $spk");
|
|
$self->logger->debug("Delete $_");
|
|
delete $req->{userData}->{$_};
|
|
}
|
|
|
|
$spoofSession = $self->_userData( $req, $spoofId, $realSession );
|
|
if ( $req->error ) {
|
|
if ( $req->error == PE_BADCREDENTIALS ) {
|
|
$statut = PE_MALFORMEDUSER;
|
|
}
|
|
else {
|
|
$statut = $req->error;
|
|
}
|
|
}
|
|
|
|
# Update spoof session
|
|
unless ($statut) {
|
|
$self->logger->debug("Populating spoof session...");
|
|
foreach (qw (_auth _userDB _session_id)) {
|
|
$self->logger->debug("Processing $_...");
|
|
$spk = "$self->{conf}->{impersonationPrefix}$_";
|
|
$spoofSession->{$_} = $realSession->{$spk};
|
|
}
|
|
}
|
|
|
|
# Main session
|
|
$self->p->updateSession( $req, $spoofSession );
|
|
return $self->p->do( $req, [ sub { $statut } ] );
|
|
}
|
|
|
|
sub _userData {
|
|
my ( $self, $req, $spoofId, $realSession ) = @_;
|
|
my $realId = $req->{user};
|
|
$req->{user} = $spoofId;
|
|
my $raz = 0;
|
|
|
|
# Compute Macros and Groups with real and spoof sessions
|
|
$req->{sessionInfo} = {%$realSession};
|
|
|
|
# Search user in database
|
|
$req->steps( [
|
|
'getUser', 'setSessionInfo',
|
|
'setMacros', 'setGroups',
|
|
'setLocalGroups'
|
|
]
|
|
);
|
|
if ( my $error = $self->p->process($req) ) {
|
|
if ( $error == PE_BADCREDENTIALS ) {
|
|
$self->userLogger->warn(
|
|
'ContextSwitching requested for an unvalid user ('
|
|
. $req->{user}
|
|
. ")" );
|
|
}
|
|
$self->logger->debug("Process returned error: $error");
|
|
$req->error($error);
|
|
$raz = 1;
|
|
}
|
|
|
|
# Check identity rule if Impersonation required
|
|
unless ( $self->idRule->( $req, $req->sessionInfo ) ) {
|
|
$self->userLogger->warn(
|
|
'ContextSwitching requested for an unvalid user ('
|
|
. $req->{user}
|
|
. ")" );
|
|
$self->logger->debug('Identity not authorized');
|
|
$req->error(PE_MALFORMEDUSER);
|
|
$raz = 1;
|
|
}
|
|
|
|
return $raz ? $self->_abortImpersonation($req) : $req->{sessionInfo};
|
|
}
|
|
|
|
sub displaySwitchContext {
|
|
my ( $self, $req ) = @_;
|
|
return 'OFF'
|
|
if $req->userData->{"$self->{conf}->{impersonationPrefix}_session_id"};
|
|
return 'ON' if $self->rule->( $req, $req->userData );
|
|
}
|
|
|
|
sub _stopImpersonation {
|
|
my ( $self, $req ) = @_;
|
|
$self->logger->debug("stopImpersonation required");
|
|
$req->{user} = $req->{userData}->{real__user};
|
|
my $realSession = {};
|
|
foreach ( keys %{ $req->{userData} } ) {
|
|
if (/^$self->{conf}->{impersonationPrefix}/) {
|
|
my $key = $_;
|
|
$key =~ s/^$self->{conf}->{impersonationPrefix}//;
|
|
$realSession->{$key} = $req->{userData}->{$_};
|
|
$realSession->{$_} = '';
|
|
$self->logger->debug("Rename userData keys -> $_");
|
|
delete $req->{userData}->{$_};
|
|
}
|
|
}
|
|
$req->urldc( $self->conf->{portal} );
|
|
$req->{id} = $realSession->{_session_id};
|
|
|
|
return $realSession;
|
|
}
|
|
|
|
sub _abortImpersonation {
|
|
my ( $self, $req ) = @_;
|
|
$self->logger->debug("abortImpersonation required");
|
|
$req->{user} = $req->{sessionInfo}->{real__user};
|
|
my $realSession = {};
|
|
foreach ( keys %{ $req->{sessionInfo} } ) {
|
|
if (/^$self->{conf}->{impersonationPrefix}/) {
|
|
my $key = $_;
|
|
$key =~ s/^$self->{conf}->{impersonationPrefix}//;
|
|
$realSession->{$key} = $req->{sessionInfo}->{$_};
|
|
$self->logger->debug("Rename sessionInfo keys -> $_");
|
|
delete $req->{sessionInfo}->{$_};
|
|
}
|
|
}
|
|
$req->urldc( $self->conf->{portal} );
|
|
$req->{userData} = {$realSession};
|
|
$req->{id} = $realSession->{_session_id};
|
|
|
|
return $realSession;
|
|
}
|
|
|
|
1;
|