Commit 23455138 authored by Yadd's avatar Yadd

Captcha and token in progress (#1140)

parent 81b47b79
...@@ -23,9 +23,9 @@ use constant HANDLERSECTION => "handler"; ...@@ -23,9 +23,9 @@ use constant HANDLERSECTION => "handler";
use constant MANAGERSECTION => "manager"; use constant MANAGERSECTION => "manager";
use constant SESSIONSEXPLORERSECTION => "sessionsExplorer"; use constant SESSIONSEXPLORERSECTION => "sessionsExplorer";
use constant APPLYSECTION => "apply"; use constant APPLYSECTION => "apply";
our $hashParameters = qr/^(?:(?:l(?:o(?:ca(?:lSessionStorageOption|tionRule)|goutService)|dapExportedVar|wpSslOpt)|(?:(?:d(?:emo|bi)|facebook|webID)ExportedVa|exported(?:Heade|Va))r|ca(?:s(?:StorageOption|Attribute)|ptchaStorageOption)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|re(?:moteGlobalStorageOption|loadUrl)|CAS_proxiedService|macro)s|o(?:idc(?:RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node)|S(?:erviceMetaDataAuthnContext|torageOptions))|penIdExportedVars)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars)|p(?:ersistentStorageOptions|o(?:rtalSkinRules|st))|a(?:uthChoiceModules|pplicationList)|v(?:hostOptions|irtualHost))$/; our $hashParameters = qr/^(?:(?:l(?:o(?:ca(?:lSessionStorageOption|tionRule)|goutService)|dapExportedVar|wpSslOpt)|(?:(?:d(?:emo|bi)|facebook|webID)ExportedVa|exported(?:Heade|Va))r|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|re(?:moteGlobalStorageOption|loadUrl)|cas(?:StorageOption|Attribute)|CAS_proxiedService|macro)s|o(?:idc(?:RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node)|S(?:erviceMetaDataAuthnContext|torageOptions))|penIdExportedVars)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars)|p(?:ersistentStorageOptions|o(?:rtalSkinRules|st))|a(?:uthChoiceModules|pplicationList)|v(?:hostOptions|irtualHost))$/;
our @sessionTypes = ( 'captcha', 'remoteGlobal', 'cas', 'global', 'localSession', 'persistent', 'saml', 'oidc' ); our @sessionTypes = ( 'remoteGlobal', 'cas', 'global', 'localSession', 'persistent', 'saml', 'oidc' );
sub NO {qr/^(?:off|no|0)?$/i} sub NO {qr/^(?:off|no|0)?$/i}
......
...@@ -20,25 +20,21 @@ sub defaultValues { ...@@ -20,25 +20,21 @@ sub defaultValues {
'browserIdAuthnLevel' => 1, 'browserIdAuthnLevel' => 1,
'captcha_register_enabled' => 1, 'captcha_register_enabled' => 1,
'captcha_size' => 6, 'captcha_size' => 6,
'captchaStorage' => 'Apache::Session::File', 'CAS_authnLevel' => 1,
'captchaStorageOptions' => { 'CAS_pgtFile' => '/tmp/pgt.txt',
'Directory' => '/var/lib/lemonldap-ng/captcha/' 'casAccessControlPolicy' => 'none',
}, 'checkXSS' => 1,
'CAS_authnLevel' => 1, 'confirmFormMethod' => 'post',
'CAS_pgtFile' => '/tmp/pgt.txt', 'cookieName' => 'lemonldap',
'casAccessControlPolicy' => 'none', 'cspConnect' => '\'self\'',
'checkXSS' => 1, 'cspDefault' => '\'self\'',
'confirmFormMethod' => 'post', 'cspFont' => '\'self\'',
'cookieName' => 'lemonldap', 'cspImg' => '\'self\'',
'cspConnect' => '\'self\'', 'cspScript' => '\'self\'',
'cspDefault' => '\'self\'', 'cspStyle' => '\'self\'',
'cspFont' => '\'self\'', 'dbiAuthnLevel' => 2,
'cspImg' => '\'self\'', 'dbiExportedVars' => {},
'cspScript' => '\'self\'', 'demoExportedVars' => {
'cspStyle' => '\'self\'',
'dbiAuthnLevel' => 2,
'dbiExportedVars' => {},
'demoExportedVars' => {
'cn' => 'cn', 'cn' => 'cn',
'mail' => 'mail', 'mail' => 'mail',
'uid' => 'uid' 'uid' => 'uid'
...@@ -50,6 +46,7 @@ sub defaultValues { ...@@ -50,6 +46,7 @@ sub defaultValues {
'facebookAuthnLevel' => 1, 'facebookAuthnLevel' => 1,
'facebookExportedVars' => {}, 'facebookExportedVars' => {},
'failedLoginNumber' => 5, 'failedLoginNumber' => 5,
'formTimeout' => 120,
'globalStorage' => 'Apache::Session::File', 'globalStorage' => 'Apache::Session::File',
'globalStorageOptions' => { 'globalStorageOptions' => {
'Directory' => '/var/lib/lemonldap-ng/sessions/', 'Directory' => '/var/lib/lemonldap-ng/sessions/',
...@@ -182,6 +179,7 @@ sub defaultValues { ...@@ -182,6 +179,7 @@ sub defaultValues {
'http://auth.example.com/Lemonldap/NG/Common/CGI/SOAPService', 'http://auth.example.com/Lemonldap/NG/Common/CGI/SOAPService',
'proxy' => 'http://auth.example.com/index.pl/sessions' 'proxy' => 'http://auth.example.com/index.pl/sessions'
}, },
'requireToken' => 1,
'samlAttributeAuthorityDescriptorAttributeServiceSOAP' => 'samlAttributeAuthorityDescriptorAttributeServiceSOAP' =>
'urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/AA/SOAP;', 'urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/AA/SOAP;',
'samlAuthnContextMapKerberos' => 4, 'samlAuthnContextMapKerberos' => 4,
......
...@@ -20,7 +20,7 @@ our $specialNodeHash = { ...@@ -20,7 +20,7 @@ our $specialNodeHash = {
}; };
our $doubleHashKeys = 'issuerDBGetParameters'; our $doubleHashKeys = 'issuerDBGetParameters';
our $simpleHashKeys = '(?:(?:l(?:o(?:calSessionStorageOption|goutService)|dapExportedVar|wpSslOpt)|ca(?:s(?:StorageOption|Attribute)|ptchaStorageOption)|(?:(?:d(?:emo|bi)|facebook|webID)E|e)xportedVar|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|p(?:ersistentStorageOption|ortalSkinRule)|re(?:moteGlobalStorageOption|loadUrl)|CAS_proxiedService|macro)s|o(?:idcS(?:erviceMetaDataAuthnContext|torageOptions)|penIdExportedVars)|s(?:(?:amlStorageOption|laveExportedVar)s|essionDataToRemember)|a(?:uthChoiceModules|pplicationList))'; our $simpleHashKeys = '(?:(?:l(?:o(?:calSessionStorageOption|goutService)|dapExportedVar|wpSslOpt)|(?:(?:d(?:emo|bi)|facebook|webID)E|e)xportedVar|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|p(?:ersistentStorageOption|ortalSkinRule)|re(?:moteGlobalStorageOption|loadUrl)|cas(?:StorageOption|Attribute)|CAS_proxiedService|macro)s|o(?:idcS(?:erviceMetaDataAuthnContext|torageOptions)|penIdExportedVars)|s(?:(?:amlStorageOption|laveExportedVar)s|essionDataToRemember)|a(?:uthChoiceModules|pplicationList))';
our $specialNodeKeys = '(?:(?:saml(?:ID|S)|oidc[OR])PMetaDataNode|virtualHost)s'; our $specialNodeKeys = '(?:(?:saml(?:ID|S)|oidc[OR])PMetaDataNode|virtualHost)s';
our $oidcOPMetaDataNodeKeys = 'oidcOPMetaData(?:Options(?:C(?:lient(?:Secret|ID)|heckJWTSignature|onfigurationURI)|TokenEndpointAuthMethod|(?:JWKSTimeou|Promp)t|I(?:DTokenMaxAge|con)|S(?:toreIDToken|cope)|U(?:iLocales|seNonce)|Display(?:Name)?|AcrValues|MaxAge)|ExportedVars|J(?:SON|WKS))'; our $oidcOPMetaDataNodeKeys = 'oidcOPMetaData(?:Options(?:C(?:lient(?:Secret|ID)|heckJWTSignature|onfigurationURI)|TokenEndpointAuthMethod|(?:JWKSTimeou|Promp)t|I(?:DTokenMaxAge|con)|S(?:toreIDToken|cope)|U(?:iLocales|seNonce)|Display(?:Name)?|AcrValues|MaxAge)|ExportedVars|J(?:SON|WKS))';
our $oidcRPMetaDataNodeKeys = 'oidcRPMetaData(?:Options(?:I(?:DToken(?:Expiration|SignAlg)|con)|(?:RedirectUri|ExtraClaim)s|AccessTokenExpiration|Client(?:Secret|ID)|BypassConsent|DisplayName|UserIDAttr)|ExportedVars)'; our $oidcRPMetaDataNodeKeys = 'oidcRPMetaData(?:Options(?:I(?:DToken(?:Expiration|SignAlg)|con)|(?:RedirectUri|ExtraClaim)s|AccessTokenExpiration|Client(?:Secret|ID)|BypassConsent|DisplayName|UserIDAttr)|ExportedVars)';
......
...@@ -599,16 +599,6 @@ sub attributes { ...@@ -599,16 +599,6 @@ sub attributes {
'default' => 6, 'default' => 6,
'type' => 'int' 'type' => 'int'
}, },
'captchaStorage' => {
'default' => 'Apache::Session::File',
'type' => 'PerlModule'
},
'captchaStorageOptions' => {
'default' => {
'Directory' => '/var/lib/lemonldap-ng/captcha/'
},
'type' => 'keyTextContainer'
},
'CAS_authnLevel' => { 'CAS_authnLevel' => {
'default' => 1, 'default' => 1,
'type' => 'int' 'type' => 'int'
...@@ -883,6 +873,10 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0- ...@@ -883,6 +873,10 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
'default' => 5, 'default' => 5,
'type' => 'int' 'type' => 'int'
}, },
'formTimeout' => {
'default' => 120,
'type' => 'int'
},
'globalStorage' => { 'globalStorage' => {
'default' => 'Apache::Session::File', 'default' => 'Apache::Session::File',
'type' => 'PerlModule' 'type' => 'PerlModule'
...@@ -2097,6 +2091,10 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.] ...@@ -2097,6 +2091,10 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'remotePortal' => { 'remotePortal' => {
'type' => 'text' 'type' => 'text'
}, },
'requireToken' => {
'default' => 1,
'type' => 'bool'
},
'restConfigServer' => { 'restConfigServer' => {
'default' => 0, 'default' => 0,
'type' => 'bool' 'type' => 'bool'
......
...@@ -425,6 +425,16 @@ sub attributes { ...@@ -425,6 +425,16 @@ sub attributes {
}, },
# Security # Security
formTimeout => {
default => 120,
type => 'int',
documentation => 'Token timeout for forms',
},
requireToken => {
default => 1,
type => 'bool',
documentation => 'Enable token for forms',
},
cda => { cda => {
default => 0, default => 0,
type => 'bool', type => 'bool',
...@@ -694,19 +704,6 @@ sub attributes { ...@@ -694,19 +704,6 @@ sub attributes {
documentation => 'Captcha size', documentation => 'Captcha size',
}, },
#captcha_data
#captcha_output
captchaStorage => {
type => 'PerlModule',
default => 'Apache::Session::File',
documentation => 'Captcha backend module',
},
captchaStorageOptions => {
type => 'keyTextContainer',
default => { 'Directory' => '/var/lib/lemonldap-ng/captcha/', },
documentation => 'Captcha backend module options',
},
# Variables # Variables
exportedVars => { exportedVars => {
type => 'keyTextContainer', type => 'keyTextContainer',
......
...@@ -91,8 +91,6 @@ sub tree { ...@@ -91,8 +91,6 @@ sub tree {
'captcha_mail_enabled', 'captcha_mail_enabled',
'captcha_register_enabled', 'captcha_register_enabled',
'captcha_size', 'captcha_size',
'captchaStorage',
'captchaStorageOptions'
] ]
} }
] ]
...@@ -615,7 +613,9 @@ sub tree { ...@@ -615,7 +613,9 @@ sub tree {
'cspScript', 'cspStyle', 'cspScript', 'cspStyle',
'cspConnect', 'cspFont', 'cspConnect', 'cspFont',
] ]
} },
'requireToken',
'formTimeout',
] ]
}, },
{ {
......
...@@ -93,8 +93,6 @@ ...@@ -93,8 +93,6 @@
"captcha_mail_enabled": "Activation in password reset by mail form", "captcha_mail_enabled": "Activation in password reset by mail form",
"captcha_register_enabled": "Activation in register form", "captcha_register_enabled": "Activation in register form",
"captcha_size": "Size", "captcha_size": "Size",
"captchaStorage": "Captcha module name",
"captchaStorageOptions": "Captcha module options",
"CAS_authnLevel": "Authentication level", "CAS_authnLevel": "Authentication level",
"CAS_CAFile": "CA file", "CAS_CAFile": "CA file",
"CAS_gateway": "Gateway authentication", "CAS_gateway": "Gateway authentication",
...@@ -202,6 +200,7 @@ ...@@ -202,6 +200,7 @@
"forceSave": "Force save", "forceSave": "Force save",
"format": "Format", "format": "Format",
"formReplay": "Form replay", "formReplay": "Form replay",
"formTimeout": "Form timeout",
"forms": "Forms", "forms": "Forms",
"friendlyName": "Friendly name", "friendlyName": "Friendly name",
"generalParameters": "General Parameters", "generalParameters": "General Parameters",
...@@ -556,6 +555,7 @@ ...@@ -556,6 +555,7 @@
"remoteParams": "Remote parameters", "remoteParams": "Remote parameters",
"remotePortal": "Portal URL", "remotePortal": "Portal URL",
"replaceByFile": "Replace by file", "replaceByFile": "Replace by file",
"requireToken": "Require token for forms",
"restConfigServer": "REST configuration server", "restConfigServer": "REST configuration server",
"restSessionServer": "REST session server", "restSessionServer": "REST session server",
"restore": "Restore", "restore": "Restore",
......
...@@ -93,8 +93,6 @@ ...@@ -93,8 +93,6 @@
"captcha_mail_enabled": "Activation dans le formulaire de réinitialisation par mail", "captcha_mail_enabled": "Activation dans le formulaire de réinitialisation par mail",
"captcha_register_enabled": "Activation dans le formulaire de création de compte", "captcha_register_enabled": "Activation dans le formulaire de création de compte",
"captcha_size": "Taille", "captcha_size": "Taille",
"captchaStorage": "Nom du module de stockage",
"captchaStorageOptions": "Options du module de stockage",
"CAS_authnLevel": "Niveau d'authentification", "CAS_authnLevel": "Niveau d'authentification",
"CAS_CAFile": "Fichier d'AC", "CAS_CAFile": "Fichier d'AC",
"CAS_gateway": "Authentification transparente", "CAS_gateway": "Authentification transparente",
...@@ -202,6 +200,7 @@ ...@@ -202,6 +200,7 @@
"forceSave": "Forcer la sauvegarde", "forceSave": "Forcer la sauvegarde",
"format": "Format", "format": "Format",
"formReplay": "Rejeu de formulaires", "formReplay": "Rejeu de formulaires",
"formTimeout": "Délai de validation pour les formulaires",
"forms": "Formulaires", "forms": "Formulaires",
"friendlyName": "Nom alternatif", "friendlyName": "Nom alternatif",
"generalParameters": "Paramètres généraux", "generalParameters": "Paramètres généraux",
...@@ -556,6 +555,7 @@ ...@@ -556,6 +555,7 @@
"remoteParams": "Paramètres Remote", "remoteParams": "Paramètres Remote",
"remotePortal": "URL du portail", "remotePortal": "URL du portail",
"replaceByFile": "Remplacer par le fichier", "replaceByFile": "Remplacer par le fichier",
"requireToken": "Exige un jeton pour les formulaires",
"restConfigServer": "Serveur de configurations REST", "restConfigServer": "Serveur de configurations REST",
"restSessionServer": "Serveur de sessions REST", "restSessionServer": "Serveur de sessions REST",
"restore": "Restaurer", "restore": "Restaurer",
......
...@@ -7,8 +7,16 @@ package Lemonldap::NG::Portal::Auth::_WebForm; ...@@ -7,8 +7,16 @@ package Lemonldap::NG::Portal::Auth::_WebForm;
use strict; use strict;
use Mouse; use Mouse;
use Lemonldap::NG::Portal::Main::Constants use Lemonldap::NG::Portal::Main::Constants qw(
qw(PE_OK PE_FIRSTACCESS PE_FORMEMPTY PE_PASSWORDFORMEMPTY PE_CAPTCHAEMPTY PE_CAPTCHAERROR); PE_CAPTCHAEMPTY
PE_CAPTCHAERROR
PE_FIRSTACCESS
PE_FORMEMPTY
PE_NOTOKEN
PE_OK
PE_PASSWORDFORMEMPTY
PE_TOKENEXPIRED
);
our $VERSION = '2.0.0'; our $VERSION = '2.0.0';
...@@ -22,10 +30,24 @@ has authnLevel => ( ...@@ -22,10 +30,24 @@ has authnLevel => (
}, },
); );
has captcha => ( is => 'rw' );
has ott => ( is => 'rw' );
# INITIALIZATION # INITIALIZATION
sub init { sub init {
1; if ( $_[0]->{conf}->{captcha_login_enabled} ) {
$_[0]->captcha(
$_[0]->p->loadModule('Lemonldap::NG::Portal::Lib::Captcha') )
or return 0;
}
elsif ( $_[0]->{conf}->{requireToken} ) {
$_[0]->ott(
$_[0]->p->loadModule('Lemonldap::NG::Portal::Lib::OneTimeToken') )
or return 0;
$_[0]->ott->timeout( $_[0]->conf->{formTimeout} );
}
return 1;
} }
# RUNNING METHODS # RUNNING METHODS
...@@ -34,30 +56,27 @@ sub init { ...@@ -34,30 +56,27 @@ sub init {
sub extractFormInfo { sub extractFormInfo {
my ( $self, $req ) = @_; my ( $self, $req ) = @_;
# Init captcha
if ( $self->conf->{captcha_login_enabled} ) {
eval { $self->initCaptcha(); };
$self->lmLog( "Can't init captcha: $@", "error" ) if $@;
}
# Detect first access and empty forms # Detect first access and empty forms
my $defUser = defined $req->param('user'); my $defUser = defined $req->param('user');
my $defPassword = defined $req->param('password'); my $defPassword = defined $req->param('password');
my $defOldPassword = defined $req->param('oldpassword'); my $defOldPassword = defined $req->param('oldpassword');
my $res = PE_OK;
# 1. No user defined at all -> first access # 1. No user defined at all -> first access
return PE_FIRSTACCESS unless $defUser; unless ($defUser) {
$res = PE_FIRSTACCESS;
}
# 2. If user and password defined -> login form # 2. If user and password defined -> login form
if ( $defUser && $defPassword ) { elsif ( $defUser && $defPassword ) {
return PE_FORMEMPTY $res = PE_FORMEMPTY
unless ( ( $req->{user} = $req->param('user') ) unless ( ( $req->{user} = $req->param('user') )
&& ( $req->datas->{password} = $req->param('password') ) ); && ( $req->datas->{password} = $req->param('password') ) );
} }
# 3. If user and oldpassword defined -> password form # 3. If user and oldpassword defined -> password form
if ( $defUser && $defOldPassword ) { elsif ( $defUser && $defOldPassword ) {
return PE_PASSWORDFORMEMPTY $res = PE_PASSWORDFORMEMPTY
unless ( ( $req->{user} = $req->param('user') ) unless ( ( $req->{user} = $req->param('user') )
&& ( $req->datas->{oldpassword} = $req->param('oldpassword') ) && ( $req->datas->{oldpassword} = $req->param('oldpassword') )
&& ( $req->datas->{newpassword} = $req->param('newpassword') ) && ( $req->datas->{newpassword} = $req->param('newpassword') )
...@@ -65,49 +84,48 @@ sub extractFormInfo { ...@@ -65,49 +84,48 @@ sub extractFormInfo {
$req->param('confirmpassword') ) ); $req->param('confirmpassword') ) );
} }
# 4. Captcha for login form # If form seems empty
if ( $self->conf->{captcha_login_enabled} && $defUser && $defPassword ) { if ( $res != PE_OK ) {
$req->datas->{captcha_user_code} = $req->param('captcha_user_code');
$req->datas->{captcha_check_code} = $req->param('captcha_code');
unless ( $req->datas->{captcha_user_code} # If captcha is enable, prepare it
&& $req->datas->{captcha_check_code} ) if ( $self->captcha ) {
{ $self->setCaptcha($req);
$self->lmLog( "Captcha not filled", 'warn' );
return PE_CAPTCHAEMPTY;
} }
$self->lmLog( # Else get token
"Captcha data received: " elsif ( $self->ott ) {
. $req->datas->{captcha_user_code} . " and " $self->setToken($req);
. $req->datas->{captcha_check_code}, }
'debug' return $res;
); }
# Check captcha # Security: check for captcha or token
my $captcha_result = $self->checkCaptcha( if ( $self->captcha or $self->ott ) {
$req->datas->{captcha_user_code}, my $token;
$req->datas->{captcha_check_code} unless ( $token = $req->param('token') ) {
); $self->p->userError('Authentication tried without token');
return PE_NOTOKEN;
if ( $captcha_result != 1 ) { }
if ( $captcha_result == -3 if ( $self->captcha ) {
or $captcha_result == -2 ) my $code = $req->param('captcha');
{ unless ($code) {
$self->lmLog( "Captcha failed: wrong code", 'warn' ); $self->setCaptcha($req);
return PE_CAPTCHAERROR; return PE_CAPTCHAEMPTY;
} }
elsif ( $captcha_result == 0 ) { unless ( $self->captcha->validateCaptcha( $token, $code ) ) {
$self->lmLog( "Captcha failed: code not checked (file error)", $self->setCaptcha($req);
'warn' ); $self->p->userNotice("Captcha failed: wrong or expired code");
return PE_CAPTCHAERROR; return PE_CAPTCHAERROR;
} }
elsif ( $captcha_result == -1 ) { $self->lmLog( "Captcha code verified", 'debug' );
$self->lmLog( "Captcha failed: code has expired", 'warn' ); }
return PE_CAPTCHAERROR; elsif ( $self->ott ) {
unless ( $self->ott->getToken($token) ) {
$self->setToken($req);
$self->p->userNotice('Token expired');
return PE_TOKENEXPIRED;
} }
} }
$self->lmLog( "Captcha code verified", 'debug' );
} }
# Other parameters # Other parameters
...@@ -141,4 +159,18 @@ sub getDisplayType { ...@@ -141,4 +159,18 @@ sub getDisplayType {
return "standardform"; return "standardform";
} }
sub setCaptcha {
my ( $self, $req ) = @_;
my ( $token, $image ) = $self->captcha->getCaptcha;
$self->lmLog( 'Prepare captcha', 'debug' );
$req->token($token);
$req->captcha($image);
}
sub setToken {
my ( $self, $req ) = @_;
$self->lmLog( 'Prepare token', 'debug' );
$req->token( $self->ott->createToken );
}
1; 1;
...@@ -83,6 +83,8 @@ use constant { ...@@ -83,6 +83,8 @@ use constant {
PE_REGISTERFIRSTACCESS => 78, PE_REGISTERFIRSTACCESS => 78,
PE_REGISTERFORMEMPTY => 79, PE_REGISTERFORMEMPTY => 79,
PE_REGISTERALREADYEXISTS => 80, PE_REGISTERALREADYEXISTS => 80,
PE_NOTOKEN => 81,
PE_TOKENEXPIRED => 82,
}; };
# EXPORTER PARAMETERS # EXPORTER PARAMETERS
...@@ -107,7 +109,7 @@ our @EXPORT_OK = qw( PE_SENDRESPONSE PE_INFO PE_REDIRECT PE_DONE PE_OK ...@@ -107,7 +109,7 @@ our @EXPORT_OK = qw( PE_SENDRESPONSE PE_INFO PE_REDIRECT PE_DONE PE_OK
PE_MAILNOTFOUND PE_PASSWORDFIRSTACCESS PE_MAILCONFIRMOK PE_MAILNOTFOUND PE_PASSWORDFIRSTACCESS PE_MAILCONFIRMOK
PE_MUST_SUPPLY_OLD_PASSWORD PE_FORBIDDENIP PE_CAPTCHAERROR PE_CAPTCHAEMPTY PE_MUST_SUPPLY_OLD_PASSWORD PE_FORBIDDENIP PE_CAPTCHAERROR PE_CAPTCHAEMPTY
PE_REGISTERFIRSTACCESS PE_REGISTERFORMEMPTY PE_REGISTERALREADYEXISTS PE_REGISTERFIRSTACCESS PE_REGISTERFORMEMPTY PE_REGISTERALREADYEXISTS
HANDLER PE_NOTOKEN PE_TOKENEXPIRED HANDLER
); );
our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK, 'import' ], ); our %EXPORT_TAGS = ( 'all' => [ @EXPORT_OK, 'import' ], );
......
...@@ -56,6 +56,14 @@ has menuError => ( is => 'rw' ); ...@@ -56,6 +56,14 @@ has menuError => ( is => 'rw' );
# Frame flag (used by Run to not send Content-Security-Policy header) # Frame flag (used by Run to not send Content-Security-Policy header)
has frame => ( is => 'rw' ); has frame => ( is => 'rw' );
# Security
#
# Captcha
has captcha => ( is => 'rw' );
# Token