lemonldap-ng/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/RESTProxy.pm
2021-09-10 22:40:11 +02:00

185 lines
5.3 KiB
Perl

package Lemonldap::NG::Portal::Lib::RESTProxy;
use strict;
use JSON;
use Mouse;
use Lemonldap::NG::Common::UserAgent;
use Lemonldap::NG::Portal::Main::Constants qw(
URIRE
PE_OK
PE_ERROR
PE_BADCREDENTIALS
);
use Lemonldap::NG::Common::FormEncode;
our $VERSION = '2.0.14';
has ua => ( is => 'rw' );
has cookieName => ( is => 'rw' );
has sessionService => ( is => 'rw' );
# INITIALIZATION
sub init {
my ($self) = @_;
unless ( defined $self->conf->{proxyAuthService}
&& $self->conf->{proxyAuthService} =~ URIRE )
{
$self->error("Bad or missing proxyAuthService parameter");
return 0;
}
my $sessionService = $self->conf->{proxySessionService}
|| $self->conf->{proxyAuthService} . '/session/my';
$sessionService =~ s#/*$##;
unless ( $sessionService =~ URIRE ) {
$self->error("Malformed proxySessionService parameter");
return 0;
}
$self->sessionService($sessionService);
$self->ua( Lemonldap::NG::Common::UserAgent->new( $self->conf ) );
$self->ua->default_header( Accept => 'application/json' );
$self->cookieName( $self->conf->{proxyCookieName}
|| $self->conf->{cookieName} );
return 1;
}
no warnings 'once';
*authenticate = \&getUser;
sub getUser {
my ( $self, $req ) = @_;
return PE_OK if ( $req->data->{_proxyQueryDone} );
$self->logger->debug(
'Proxy push auth to ' . $self->conf->{proxyAuthService} );
my $resp = $self->ua->post(
$self->conf->{proxyAuthService},
{
user => $req->{user},
password => $req->data->{password},
(
$self->conf->{proxyAuthServiceChoiceParam}
&& $self->conf->{proxyAuthServiceChoiceValue}
? ( $self->conf->{proxyAuthServiceChoiceParam} =>
$self->conf->{proxyAuthServiceChoiceValue} )
: ()
),
(
$self->conf->{proxyAuthServiceImpersonation}
&& $req->param('spoofId')
? ( spoofId => $req->param('spoofId') )
: ()
)
}
);
unless ( $resp->is_success ) {
$self->logger->error(
'Unable to query authentication service: ' . $resp->status_line );
return PE_ERROR;
}
$self->logger->debug('Proxy gets a response');
my $res = eval { JSON::from_json( $resp->content, { allow_nonref => 1 } ) };
if ($@) {
$self->logger->error("Bad content: $@");
return PE_ERROR;
}
unless ( $res->{result} ) {
$self->userLogger->warn("Authentication failed for $req->{user}");
$self->setSecurity($req);
return PE_BADCREDENTIALS;
}
my $name = $self->cookieName;
unless ( grep /\b$name=/, $resp->header('Set-Cookie') ) {
$self->logger->error("No cookie named '$name'");
return PE_ERROR;
}
$req->sessionInfo->{_proxyCookies} = join '; ',
map { s/;.*$//; $_ } $resp->header('Set-Cookie');
$self->logger->debug( 'Store remote cookies in session ('
. $req->sessionInfo->{_proxyCookies}
. ')' );
$req->data->{_proxyQueryDone}++;
return PE_OK;
}
sub findUser {
# Nothing to do here
return PE_OK;
}
sub setSessionInfo {
my ( $self, $req ) = @_;
return PE_OK if ( $req->data->{_setSessionInfoDone} );
$self->logger->debug(
'Proxy requests sessionInfo to ' . $self->sessionService . '/global' );
my $q = HTTP::Request->new(
GET => $self->sessionService . '/global',
[
Cookie => $req->sessionInfo->{_proxyCookies},
Accept => 'application/json'
]
);
my $resp = $self->ua->request($q);
unless ( $resp->is_success ) {
$self->logger->error(
'Unable to query session service: ' . $resp->status_line );
return PE_ERROR;
}
$self->logger->debug('Proxy gets a response');
my $res = eval { JSON::from_json( $resp->content, { allow_nonref => 1 } ) };
if ($@) {
$self->logger->error("Bad content: $@");
return PE_ERROR;
}
foreach ( keys %$res ) {
$req->{sessionInfo}->{$_} ||= $res->{$_} unless (/^_/);
}
$req->data->{_setSessionInfoDone}++;
return PE_OK;
}
sub authLogout {
my ( $self, $req ) = @_;
$self->logger->debug(
'Proxy ask logout to ' . $self->conf->{proxyAuthService} );
my $q = HTTP::Request->new(
GET => $self->conf->{proxyAuthService} . '?logout=1',
[
Cookie => $req->sessionInfo->{_proxyCookies},
Accept => 'application/json'
]
);
my $resp = $self->ua->request($q);
unless ( $resp->is_success ) {
$self->logger->error(
'Unable to query authentication service: ' . $resp->status_line );
return PE_OK;
}
$self->logger->debug('Proxy gets a response');
my $res = eval { JSON::from_json( $resp->content, { allow_nonref => 1 } ) };
if ($@) {
$self->logger->error("Bad content: $@");
return PE_OK;
}
my $user = $req->{sessionInfo}->{ $self->conf->{whatToTrace} };
unless ( $res->{result} ) {
$self->userLogger->warn("Internal Portal logout failed for $user")
if $user;
return PE_OK;
}
$self->userLogger->notice(
"User $user has been disconnected from internal Portal")
if $user;
return PE_OK;
}
1;