2016-03-30 07:47:38 +02:00
|
|
|
##@file
|
|
|
|
# Web form authentication backend file
|
|
|
|
|
|
|
|
##@class
|
|
|
|
# Web form authentication backend class
|
|
|
|
package Lemonldap::NG::Portal::Auth::_WebForm;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use Mouse;
|
2017-01-24 23:05:07 +01:00
|
|
|
use Lemonldap::NG::Portal::Main::Constants qw(
|
|
|
|
PE_CAPTCHAEMPTY
|
|
|
|
PE_CAPTCHAERROR
|
|
|
|
PE_FIRSTACCESS
|
|
|
|
PE_FORMEMPTY
|
|
|
|
PE_NOTOKEN
|
|
|
|
PE_OK
|
|
|
|
PE_PASSWORDFORMEMPTY
|
|
|
|
PE_TOKENEXPIRED
|
2019-03-07 18:22:16 +01:00
|
|
|
PE_MALFORMEDUSER
|
2017-01-24 23:05:07 +01:00
|
|
|
);
|
2016-03-30 07:47:38 +02:00
|
|
|
|
2019-02-12 18:21:38 +01:00
|
|
|
our $VERSION = '2.1.0';
|
2016-03-30 07:47:38 +02:00
|
|
|
|
2019-04-05 17:24:07 +02:00
|
|
|
extends 'Lemonldap::NG::Portal::Main::Auth',
|
|
|
|
'Lemonldap::NG::Portal::Lib::_tokenRule';
|
2016-03-30 07:47:38 +02:00
|
|
|
|
2016-12-01 23:25:05 +01:00
|
|
|
has authnLevel => (
|
|
|
|
is => 'rw',
|
2017-03-27 18:51:18 +02:00
|
|
|
lazy => 1,
|
2016-12-01 23:25:05 +01:00
|
|
|
builder => sub {
|
|
|
|
my $conf = $_[0]->{conf};
|
|
|
|
return ( $conf->{portal} =~ /^https/ ? 2 : 1 );
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2017-01-24 23:05:07 +01:00
|
|
|
has captcha => ( is => 'rw' );
|
|
|
|
has ott => ( is => 'rw' );
|
|
|
|
|
2016-06-09 20:40:20 +02:00
|
|
|
# INITIALIZATION
|
|
|
|
|
2016-03-30 07:47:38 +02:00
|
|
|
sub init {
|
2019-04-05 17:24:07 +02:00
|
|
|
my $self = shift;
|
2019-04-03 23:28:45 +02:00
|
|
|
|
|
|
|
if ( $self->{conf}->{captcha_login_enabled} ) {
|
|
|
|
$self->captcha( $self->p->loadModule('::Lib::Captcha') ) or return 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->ott( $self->p->loadModule('::Lib::OneTimeToken') ) or return 0;
|
|
|
|
$self->ott->timeout( $self->conf->{formTimeout} );
|
2017-01-24 23:05:07 +01:00
|
|
|
}
|
|
|
|
return 1;
|
2016-03-30 07:47:38 +02:00
|
|
|
}
|
|
|
|
|
2016-06-09 20:40:20 +02:00
|
|
|
# RUNNING METHODS
|
|
|
|
|
2018-07-05 22:56:16 +02:00
|
|
|
# Read username and password from POST data
|
2016-03-30 07:47:38 +02:00
|
|
|
sub extractFormInfo {
|
2016-04-29 09:27:26 +02:00
|
|
|
my ( $self, $req ) = @_;
|
2016-03-30 07:47:38 +02:00
|
|
|
|
2019-03-06 23:08:22 +01:00
|
|
|
if ( $req->param('user') ) {
|
|
|
|
unless ( $req->param('user') =~ /$self->{conf}->{userControl}/o ) {
|
|
|
|
$self->setSecurity($req);
|
|
|
|
return PE_MALFORMEDUSER;
|
|
|
|
}
|
|
|
|
}
|
2016-03-30 07:47:38 +02:00
|
|
|
|
|
|
|
# Detect first access and empty forms
|
|
|
|
my $defUser = defined $req->param('user');
|
|
|
|
my $defPassword = defined $req->param('password');
|
|
|
|
my $defOldPassword = defined $req->param('oldpassword');
|
2017-01-24 23:05:07 +01:00
|
|
|
my $res = PE_OK;
|
2016-03-30 07:47:38 +02:00
|
|
|
|
|
|
|
# 1. No user defined at all -> first access
|
2017-03-04 09:36:26 +01:00
|
|
|
unless ( $defUser and $req->method =~ /^POST$/i ) {
|
2017-01-24 23:05:07 +01:00
|
|
|
$res = PE_FIRSTACCESS;
|
|
|
|
}
|
2016-03-30 07:47:38 +02:00
|
|
|
|
|
|
|
# 2. If user and password defined -> login form
|
2017-03-04 09:36:26 +01:00
|
|
|
elsif ( $defUser and $defPassword ) {
|
2017-01-24 23:05:07 +01:00
|
|
|
$res = PE_FORMEMPTY
|
2016-03-30 07:47:38 +02:00
|
|
|
unless ( ( $req->{user} = $req->param('user') )
|
2018-07-05 22:56:16 +02:00
|
|
|
&& ( $req->data->{password} = $req->param('password') ) );
|
2016-03-30 07:47:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# 3. If user and oldpassword defined -> password form
|
2017-03-04 09:36:26 +01:00
|
|
|
elsif ( $defUser and $defOldPassword ) {
|
2017-01-24 23:05:07 +01:00
|
|
|
$res = PE_PASSWORDFORMEMPTY
|
2016-03-30 07:47:38 +02:00
|
|
|
unless ( ( $req->{user} = $req->param('user') )
|
2018-07-05 22:56:16 +02:00
|
|
|
&& ( $req->data->{oldpassword} = $req->param('oldpassword') )
|
|
|
|
&& ( $req->data->{newpassword} = $req->param('newpassword') )
|
|
|
|
&& ( $req->data->{confirmpassword} =
|
2016-05-04 13:38:49 +02:00
|
|
|
$req->param('confirmpassword') ) );
|
2016-03-30 07:47:38 +02:00
|
|
|
}
|
|
|
|
|
2017-01-24 23:05:07 +01:00
|
|
|
# If form seems empty
|
|
|
|
if ( $res != PE_OK ) {
|
2017-03-14 17:52:11 +01:00
|
|
|
$self->setSecurity($req);
|
2017-01-24 23:05:07 +01:00
|
|
|
return $res;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Security: check for captcha or token
|
2019-04-05 17:24:07 +02:00
|
|
|
if ( $self->captcha or $self->ottRule->( $req, {} ) ) {
|
2017-01-24 23:05:07 +01:00
|
|
|
my $token;
|
|
|
|
unless ( $token = $req->param('token') ) {
|
2017-02-15 15:16:59 +01:00
|
|
|
$self->userLogger->error('Authentication tried without token');
|
2017-03-14 18:38:50 +01:00
|
|
|
$self->ott->setToken($req);
|
2017-01-24 23:05:07 +01:00
|
|
|
return PE_NOTOKEN;
|
|
|
|
}
|
2019-04-03 23:28:45 +02:00
|
|
|
|
2017-01-24 23:05:07 +01:00
|
|
|
if ( $self->captcha ) {
|
|
|
|
my $code = $req->param('captcha');
|
|
|
|
unless ($code) {
|
2017-01-26 22:42:42 +01:00
|
|
|
$self->captcha->setCaptcha($req);
|
2017-01-24 23:05:07 +01:00
|
|
|
return PE_CAPTCHAEMPTY;
|
2016-03-30 07:47:38 +02:00
|
|
|
}
|
2017-01-24 23:05:07 +01:00
|
|
|
unless ( $self->captcha->validateCaptcha( $token, $code ) ) {
|
2017-01-26 22:42:42 +01:00
|
|
|
$self->captcha->setCaptcha($req);
|
2017-02-19 12:51:58 +01:00
|
|
|
$self->userLogger->warn(
|
|
|
|
"Captcha failed: wrong or expired code");
|
2016-03-30 07:47:38 +02:00
|
|
|
return PE_CAPTCHAERROR;
|
|
|
|
}
|
2017-02-15 07:41:50 +01:00
|
|
|
$self->logger->debug("Captcha code verified");
|
2017-01-24 23:05:07 +01:00
|
|
|
}
|
2019-04-05 17:24:07 +02:00
|
|
|
elsif ( $self->ottRule->( $req, {} ) ) {
|
2018-07-05 22:56:16 +02:00
|
|
|
unless ( $req->data->{tokenVerified}
|
2017-03-27 18:51:18 +02:00
|
|
|
or $self->ott->getToken($token) )
|
|
|
|
{
|
2017-01-26 22:42:42 +01:00
|
|
|
$self->ott->setToken($req);
|
2017-02-15 15:16:59 +01:00
|
|
|
$self->userLogger->warn('Token expired');
|
2017-01-24 23:05:07 +01:00
|
|
|
return PE_TOKENEXPIRED;
|
2016-03-30 07:47:38 +02:00
|
|
|
}
|
2018-07-05 22:56:16 +02:00
|
|
|
$req->data->{tokenVerified} = 1;
|
2016-03-30 07:47:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Other parameters
|
2018-07-05 22:56:16 +02:00
|
|
|
$req->data->{timezone} = $req->param('timezone');
|
2016-03-30 07:47:38 +02:00
|
|
|
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2018-07-05 22:56:16 +02:00
|
|
|
# Set password in session data if wanted.
|
2016-03-30 07:47:38 +02:00
|
|
|
sub setAuthSessionInfo {
|
2016-05-04 13:38:49 +02:00
|
|
|
my ( $self, $req ) = @_;
|
2016-03-30 07:47:38 +02:00
|
|
|
|
|
|
|
# authenticationLevel
|
2016-12-02 06:47:38 +01:00
|
|
|
$req->{sessionInfo}->{authenticationLevel} = $self->authnLevel;
|
2016-03-30 07:47:38 +02:00
|
|
|
|
|
|
|
# Store submitted password if set in configuration
|
|
|
|
# WARNING: it can be a security hole
|
|
|
|
if ( $self->conf->{storePassword} ) {
|
2018-07-05 22:56:16 +02:00
|
|
|
$req->{sessionInfo}->{'_password'} = $req->data->{'newpassword'}
|
|
|
|
|| $req->data->{'password'};
|
2016-03-30 07:47:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Store user timezone
|
2016-12-02 06:47:38 +01:00
|
|
|
$req->{sessionInfo}->{'_timezone'} = $self->{'timezone'};
|
2016-03-30 07:47:38 +02:00
|
|
|
|
|
|
|
PE_OK;
|
|
|
|
}
|
|
|
|
|
2016-05-02 12:30:23 +02:00
|
|
|
# @return display type
|
2019-03-19 05:56:36 +01:00
|
|
|
sub getForm {
|
2016-05-02 12:30:23 +02:00
|
|
|
return "standardform";
|
|
|
|
}
|
|
|
|
|
2017-03-14 17:52:11 +01:00
|
|
|
sub setSecurity {
|
2017-03-27 18:51:18 +02:00
|
|
|
my ( $self, $req ) = @_;
|
|
|
|
|
2017-03-14 17:52:11 +01:00
|
|
|
# If captcha is enable, prepare it
|
|
|
|
if ( $self->captcha ) {
|
|
|
|
$self->captcha->setCaptcha($req);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Else get token
|
2019-04-05 17:24:07 +02:00
|
|
|
elsif ( $self->ottRule->( $req, {} ) ) {
|
2017-03-14 17:52:11 +01:00
|
|
|
$self->ott->setToken($req);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-30 07:47:38 +02:00
|
|
|
1;
|