2020-12-20 17:31:50 +01:00
|
|
|
package Lemonldap::NG::Portal::Plugins::FindUser;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use Mouse;
|
|
|
|
use Lemonldap::NG::Portal::Main::Constants qw(
|
|
|
|
PE_OK
|
2020-12-23 10:32:06 +01:00
|
|
|
PE_NOTOKEN
|
2020-12-20 17:31:50 +01:00
|
|
|
PE_FIRSTACCESS
|
2021-03-30 23:54:06 +02:00
|
|
|
PE_TOKENEXPIRED
|
2020-12-20 17:31:50 +01:00
|
|
|
);
|
|
|
|
|
2021-09-24 14:32:36 +02:00
|
|
|
our $VERSION = '2.0.14';
|
2020-12-20 17:31:50 +01:00
|
|
|
|
2020-12-23 10:32:06 +01:00
|
|
|
extends qw(
|
|
|
|
Lemonldap::NG::Portal::Main::Plugin
|
|
|
|
Lemonldap::NG::Portal::Lib::_tokenRule
|
|
|
|
);
|
2020-12-20 17:31:50 +01:00
|
|
|
|
|
|
|
# INITIALIZATION
|
2021-10-02 22:12:42 +02:00
|
|
|
has ott => (
|
2020-12-23 10:32:06 +01:00
|
|
|
is => 'rw',
|
|
|
|
lazy => 1,
|
|
|
|
default => sub {
|
|
|
|
my $ott =
|
|
|
|
$_[0]->{p}->loadModule('Lemonldap::NG::Portal::Lib::OneTimeToken');
|
|
|
|
$ott->timeout( $_[0]->{conf}->{formTimeout} );
|
|
|
|
return $ott;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2020-12-20 17:31:50 +01:00
|
|
|
sub init {
|
|
|
|
my ($self) = @_;
|
2020-12-25 14:54:06 +01:00
|
|
|
( my $imp = grep /::Plugins::Impersonation$/, $self->p->enabledPlugins )
|
|
|
|
? $self->addUnauthRoute( finduser => 'provideUser', ['POST'] )
|
2021-08-12 21:04:30 +02:00
|
|
|
->addAuthRoute(
|
|
|
|
finduser => 'provideUser',
|
|
|
|
['POST']
|
|
|
|
) # Allow findUser with reAuth
|
2020-12-25 14:54:06 +01:00
|
|
|
: $self->logger->warn('FindUser plugin enabled without Impersonation');
|
2020-12-26 14:30:27 +01:00
|
|
|
$self->logger->warn('FindUser plugin enabled without searching attribute')
|
|
|
|
unless keys %{ $self->conf->{findUserSearchingAttributes} };
|
2020-12-20 17:31:50 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
# RUNNING METHOD
|
|
|
|
sub provideUser {
|
|
|
|
my ( $self, $req ) = @_;
|
2020-12-23 10:32:06 +01:00
|
|
|
my $error;
|
|
|
|
|
|
|
|
# Check token
|
|
|
|
if ( $self->ottRule->( $req, {} ) ) {
|
2021-01-31 00:06:31 +01:00
|
|
|
if ( my $token = $req->param('token') ) {
|
2020-12-26 13:42:30 +01:00
|
|
|
unless ( $self->ott->getToken($token) ) {
|
|
|
|
$self->userLogger->warn(
|
|
|
|
'FindUser called with an expired/bad token');
|
|
|
|
$error = PE_TOKENEXPIRED;
|
|
|
|
}
|
2020-12-23 10:32:06 +01:00
|
|
|
}
|
2021-01-31 00:06:31 +01:00
|
|
|
else {
|
|
|
|
$self->userLogger->warn('FindUser called without token');
|
|
|
|
$error = PE_NOTOKEN;
|
|
|
|
}
|
2020-12-23 10:32:06 +01:00
|
|
|
}
|
2021-01-31 00:06:31 +01:00
|
|
|
return $self->_sendResult( $req, $error ) if $error;
|
2020-12-23 10:32:06 +01:00
|
|
|
|
2020-12-20 17:31:50 +01:00
|
|
|
$req->steps( ['findUser'] );
|
2020-12-27 00:45:06 +01:00
|
|
|
$req->data->{findUserChoice} = $self->conf->{authChoiceFindUser};
|
2020-12-23 10:32:06 +01:00
|
|
|
if ( $error = $self->p->process($req) ) {
|
2020-12-20 17:31:50 +01:00
|
|
|
$self->logger->debug("Process returned error: $error");
|
2021-01-31 00:06:31 +01:00
|
|
|
return $self->_sendResult( $req, $error );
|
2020-12-20 17:31:50 +01:00
|
|
|
}
|
2021-01-31 00:06:31 +01:00
|
|
|
return $self->_sendResult($req);
|
2020-12-20 17:31:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
sub retreiveFindUserParams {
|
2021-01-24 18:50:20 +01:00
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
my ( $searching, $excluding, @required ) = ( [], [], () );
|
2021-01-04 20:23:42 +01:00
|
|
|
|
2020-12-20 17:31:50 +01:00
|
|
|
$self->logger->debug("FindUser: reading parameters...");
|
2021-01-04 20:23:42 +01:00
|
|
|
@$searching = map {
|
2021-01-24 18:50:20 +01:00
|
|
|
my ( $key, $value, $null ) = split '#', $_;
|
2021-09-24 14:32:36 +02:00
|
|
|
$key =~ s/^(?:\d+_)?//;
|
2021-01-24 18:50:20 +01:00
|
|
|
my $param = $req->params($key) // '';
|
2021-10-02 22:12:42 +02:00
|
|
|
my @values = grep s/^(?:\d+_)?//,
|
|
|
|
split( $self->conf->{multiValuesSeparator},
|
|
|
|
$self->conf->{findUserSearchingAttributes}->{$_} || '' );
|
2021-01-24 18:50:20 +01:00
|
|
|
my $select = scalar @values > 1 && not scalar @values % 2;
|
|
|
|
my %values = @values if $select;
|
|
|
|
my $defined = length $param;
|
|
|
|
my $regex = '^(?:' . join( '|', keys %values ) . ')$';
|
|
|
|
my $checked =
|
|
|
|
$select
|
2021-08-12 21:04:30 +02:00
|
|
|
? $param =~ /$regex/
|
|
|
|
: $param =~ /$self->{conf}->{findUserControl}/;
|
|
|
|
push @required, $key unless $null;
|
2021-01-24 12:41:41 +01:00
|
|
|
|
2021-01-24 18:50:20 +01:00
|
|
|
# For <select>, accept only set values or empty if allowed
|
|
|
|
if ( $defined && $checked ) {
|
2021-08-12 21:04:30 +02:00
|
|
|
$self->logger->debug("Append searching parameter: $key => $param");
|
2021-01-24 18:50:20 +01:00
|
|
|
{ key => $key, value => $param };
|
2021-01-05 22:46:35 +01:00
|
|
|
}
|
2021-01-23 18:56:19 +01:00
|
|
|
else {
|
2021-08-12 21:04:30 +02:00
|
|
|
if ($defined) {
|
|
|
|
my $warn =
|
|
|
|
"Parameter $key has been rejected by findUserControl: ";
|
|
|
|
$warn .= $select ? $regex : $self->conf->{findUserControl};
|
|
|
|
$self->logger->warn($warn);
|
|
|
|
}
|
2021-01-23 18:56:19 +01:00
|
|
|
();
|
|
|
|
}
|
2021-01-04 20:23:42 +01:00
|
|
|
} sort keys %{ $self->conf->{findUserSearchingAttributes} };
|
2020-12-22 22:51:37 +01:00
|
|
|
|
2021-01-24 18:50:20 +01:00
|
|
|
if ( scalar @required ) {
|
|
|
|
my $test = 0;
|
|
|
|
foreach my $ref (@$searching) {
|
|
|
|
foreach (@required) {
|
|
|
|
$test++ if $ref->{key} eq $_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unless ( scalar @required == $test ) {
|
|
|
|
$self->logger->warn( 'A required parameter is missing ('
|
|
|
|
. join( '|', @required )
|
|
|
|
. ')' );
|
|
|
|
$searching = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-23 22:38:58 +01:00
|
|
|
if ( scalar @$searching
|
|
|
|
&& keys %{ $self->conf->{findUserExcludingAttributes} } )
|
|
|
|
{
|
2020-12-22 22:51:37 +01:00
|
|
|
$self->logger->debug("FindUser: reading excluding parameters...");
|
2021-01-04 20:23:42 +01:00
|
|
|
@$excluding = map {
|
|
|
|
my $key = $_;
|
|
|
|
map {
|
|
|
|
$self->logger->debug("Push excluding parameter: $key => $_");
|
2021-01-05 22:52:21 +01:00
|
|
|
{ # Allow multivalued excluding parameters
|
2021-01-05 22:46:35 +01:00
|
|
|
key => $key,
|
|
|
|
value => $_
|
2021-01-05 22:52:21 +01:00
|
|
|
}
|
2021-01-04 20:23:42 +01:00
|
|
|
} split $self->conf->{multiValuesSeparator},
|
|
|
|
$self->conf->{findUserExcludingAttributes}->{$_};
|
|
|
|
} sort keys %{ $self->conf->{findUserExcludingAttributes} };
|
2020-12-20 17:31:50 +01:00
|
|
|
}
|
2020-12-22 22:51:37 +01:00
|
|
|
|
|
|
|
return ( $searching, $excluding );
|
2020-12-20 17:31:50 +01:00
|
|
|
}
|
|
|
|
|
2021-01-23 22:58:25 +01:00
|
|
|
sub buildForm {
|
|
|
|
my $self = shift;
|
2021-10-02 22:12:42 +02:00
|
|
|
my ( $fields, @required ) = ( [], () );
|
2021-01-31 00:06:31 +01:00
|
|
|
|
2021-01-23 22:58:25 +01:00
|
|
|
$self->logger->debug('Building array ref with searching fields...');
|
|
|
|
@$fields =
|
|
|
|
map {
|
|
|
|
my ( $key, $value, $null ) = split '#', $_;
|
|
|
|
my @values = split $self->conf->{multiValuesSeparator},
|
2021-01-23 23:07:21 +01:00
|
|
|
$self->conf->{findUserSearchingAttributes}->{$_} || $key;
|
2021-09-24 14:32:36 +02:00
|
|
|
$key =~ s/^(?:\d+_)?//;
|
2021-10-02 22:12:42 +02:00
|
|
|
push @required, $key unless $null;
|
2021-01-23 22:58:25 +01:00
|
|
|
my $nbr = scalar @values;
|
|
|
|
if ( $nbr > 1 ) {
|
|
|
|
if ( $nbr % 2 ) { () }
|
|
|
|
else {
|
|
|
|
my %hash = @values;
|
|
|
|
my $choices = [];
|
|
|
|
$nbr /= 2;
|
|
|
|
$self->logger->debug(
|
|
|
|
"Building $key with type 'select' and $nbr entries...");
|
2021-09-24 14:32:36 +02:00
|
|
|
@$choices = map {
|
|
|
|
my $k = $_;
|
|
|
|
$k =~ s/^(?:\d+_)?//;
|
|
|
|
{ key => $k, value => $hash{$_} }
|
|
|
|
} sort keys %hash;
|
2021-01-23 22:58:25 +01:00
|
|
|
{
|
|
|
|
select => 1,
|
|
|
|
key => $key,
|
|
|
|
value => $value ? $value : $key,
|
2021-10-02 22:12:42 +02:00
|
|
|
choices => $choices,
|
|
|
|
null => $null
|
2021-01-23 22:58:25 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
{
|
|
|
|
select => 0,
|
|
|
|
key => $key,
|
2021-10-02 22:12:42 +02:00
|
|
|
value => $values[0],
|
|
|
|
null => $null
|
2021-01-23 22:58:25 +01:00
|
|
|
};
|
|
|
|
}
|
2021-09-24 14:32:36 +02:00
|
|
|
} sort keys %{ $self->conf->{findUserSearchingAttributes} };
|
2021-10-02 22:12:42 +02:00
|
|
|
$self->logger->debug('Mandatory field(s) required') if scalar @required;
|
2021-01-23 22:58:25 +01:00
|
|
|
|
2021-10-02 22:12:42 +02:00
|
|
|
return ( $fields, scalar @required );
|
2021-01-23 22:58:25 +01:00
|
|
|
}
|
|
|
|
|
2021-01-31 00:06:31 +01:00
|
|
|
sub _sendResult {
|
2021-01-30 18:22:13 +01:00
|
|
|
my ( $self, $req, $error ) = @_;
|
2021-01-31 00:06:31 +01:00
|
|
|
|
2021-01-30 23:21:24 +01:00
|
|
|
eval { $self->p->_authentication->setSecurity($req) };
|
2021-01-31 00:06:31 +01:00
|
|
|
my $res =
|
|
|
|
$error
|
|
|
|
? {
|
|
|
|
user => '',
|
|
|
|
error => $error,
|
|
|
|
}
|
|
|
|
: {
|
|
|
|
result => 1,
|
|
|
|
user => ( $req->data->{findUser} ? $req->data->{findUser} : '' )
|
|
|
|
};
|
|
|
|
$res = {
|
|
|
|
%$res,
|
|
|
|
( $req->token ? ( token => $req->token ) : () ),
|
|
|
|
( $req->captcha ? ( captcha => $req->captcha ) : () )
|
|
|
|
};
|
|
|
|
$error ||= PE_FIRSTACCESS;
|
|
|
|
|
2021-01-30 18:22:13 +01:00
|
|
|
return $req->wantJSON
|
2021-01-31 00:06:31 +01:00
|
|
|
? $self->p->sendJSONresponse( $req, $res )
|
|
|
|
: $self->p->do( $req, [ sub { $error } ] );
|
2021-01-30 18:22:13 +01:00
|
|
|
}
|
|
|
|
|
2020-12-20 17:31:50 +01:00
|
|
|
1;
|