Reset Certificate module for v2.0.7 (#1605)
parent
ae0d455e7f
commit
a465a5d768
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,72 @@ |
||||
package Lemonldap::NG::Portal::CertificateResetByMail::LDAP; |
||||
|
||||
use strict; |
||||
use Mouse; |
||||
use Lemonldap::NG::Portal::Main::Constants qw( |
||||
PE_LDAPCONNECTFAILED |
||||
PE_LDAPERROR |
||||
PE_OK |
||||
PE_ERROR |
||||
); |
||||
|
||||
extends 'Lemonldap::NG::Portal::Lib::LDAP'; |
||||
|
||||
our $VERSION = '2.1.0'; |
||||
|
||||
# RUNNING METHODS |
||||
|
||||
# PRIVATE METHODS |
||||
sub modifCertificate { |
||||
|
||||
my $self = shift; |
||||
my $newcertif = shift; |
||||
my $usercertif = shift; |
||||
my $req = shift; |
||||
my $ceaAttribute = $self->conf->{certificateResetByMailCeaAttribute} |
||||
|| "description"; |
||||
my $certificateAttribute = |
||||
$self->conf->{certificateResetByMailCertificateAttribute} |
||||
|| "userCertificate;binary"; |
||||
|
||||
# Set the dn unless done before |
||||
# |
||||
# |
||||
my $dn; |
||||
if ( $req->userData->{_dn} ) { |
||||
$dn = $req->userData->{_dn}; |
||||
$self->logger->debug("Get DN from request data: $dn"); |
||||
} |
||||
else { |
||||
$dn = $req->sessionInfo->{_dn}; |
||||
$self->logger->debug("Get DN from session data: $dn"); |
||||
} |
||||
unless ($dn) { |
||||
$self->logger->error('"dn" is not set, aborting password modification'); |
||||
return PE_ERROR; |
||||
} |
||||
|
||||
#my $dn = "uid=" . $req->{user}. "," . $self->conf->{ldapBase}; |
||||
|
||||
my $result = $self->ldap->modify( |
||||
$dn, |
||||
replace => [ |
||||
$ceaAttribute => $newcertif, |
||||
"$certificateAttribute" => [$usercertif] |
||||
] |
||||
); |
||||
|
||||
unless ( $result->code == 0 ) { |
||||
$self->logger->debug( "LDAP modify Error: " . $result->code ); |
||||
$self->ldap->unbind; |
||||
$self->{flags}->{ldapActive} = 0; |
||||
$self->ldap->unbind; |
||||
return PE_LDAPERROR; |
||||
} |
||||
|
||||
$self->logger->debug("$ceaAttribute set to $newcertif"); |
||||
|
||||
return PE_OK; |
||||
|
||||
} |
||||
|
||||
1; |
@ -0,0 +1,784 @@ |
||||
package Lemonldap::NG::Portal::Plugins::CertificateResetByMail; |
||||
|
||||
use strict; |
||||
use Encode; |
||||
use Mouse; |
||||
use Net::SSLeay; |
||||
use DateTime::Format::RFC3339; |
||||
use Digest::SHA qw(sha256_hex); |
||||
use MIME::Base64; |
||||
use POSIX qw(strftime); |
||||
use Lemonldap::NG::Common::FormEncode; |
||||
use Lemonldap::NG::Portal::Main::Constants qw( |
||||
PE_BADCREDENTIALS |
||||
PE_BADMAILTOKEN |
||||
PE_CAPTCHAEMPTY |
||||
PE_CAPTCHAERROR |
||||
PE_MAILCONFIRMATION_ALREADY_SENT |
||||
PE_MAILCONFIRMOK |
||||
PE_MAILERROR |
||||
PE_MAILFIRSTACCESS |
||||
PE_MAILFORMEMPTY |
||||
PE_MAILNOTFOUND |
||||
PE_MAILOK |
||||
PE_MALFORMEDUSER |
||||
PE_NOTOKEN |
||||
PE_OK |
||||
PE_PASSWORDFIRSTACCESS |
||||
PE_PASSWORDFORMEMPTY |
||||
PE_PASSWORD_OK |
||||
PE_TOKENEXPIRED |
||||
PE_USERNOTFOUND |
||||
PE_RESETCERTIFICATE_INVALID |
||||
PE_RESETCERTIFICATE_FORMEMPTY |
||||
PE_RESETCERTIFICATE_FIRSTACCESS |
||||
); |
||||
|
||||
our $VERSION = '2.1.0'; |
||||
|
||||
extends 'Lemonldap::NG::Portal::Main::Plugin', |
||||
'Lemonldap::NG::Portal::Lib::SMTP', 'Lemonldap::NG::Portal::Lib::_tokenRule'; |
||||
|
||||
# PROPERTIES |
||||
|
||||
# Mail timeout token generator |
||||
# Form timout token generator (used even if requireToken is not set) |
||||
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 module (Demo, LDAP,...) |
||||
has registerModule => ( is => 'rw' ); |
||||
|
||||
# Captcha generator |
||||
has captcha => ( is => 'rw' ); |
||||
|
||||
# certificate reset url |
||||
has certificateResetUrl => ( |
||||
is => 'rw', |
||||
lazy => 1, |
||||
default => sub { |
||||
my $p = $_[0]->conf->{portal}; |
||||
$p =~ s#/*$##; |
||||
return "$p/certificateReset"; |
||||
} |
||||
); |
||||
|
||||
# Mail timeout token generator |
||||
has mailott => ( |
||||
is => 'rw', |
||||
lazy => 1, |
||||
default => sub { |
||||
my $ott = |
||||
$_[0]->{p}->loadModule('Lemonldap::NG::Portal::Lib::OneTimeToken'); |
||||
$ott->cache(0); |
||||
$ott->timeout( $_[0]->conf->{registerTimeout} |
||||
|| $_[0]->conf->{timeout} ); |
||||
return $ott; |
||||
} |
||||
); |
||||
|
||||
# INITIALIZATION |
||||
|
||||
sub init { |
||||
my ($self) = @_; |
||||
|
||||
# Declare REST route |
||||
$self->addUnauthRoute( |
||||
certificateReset => 'certificateReset', |
||||
[ 'POST', 'GET' ] |
||||
); |
||||
|
||||
# Initialize Captcha if needed |
||||
if ( $self->conf->{captcha_mail_enabled} ) { |
||||
$self->captcha( $self->p->loadModule('::Lib::Captcha') ) or return 0; |
||||
} |
||||
|
||||
# Load registered module |
||||
$self->registerModule( |
||||
$self->p->loadPlugin( |
||||
'::CertificateResetByMail::' . $self->conf->{registerDB} |
||||
) |
||||
) or return 0; |
||||
return 1; |
||||
} |
||||
|
||||
# RUNNIG METHODS |
||||
|
||||
# Handle reset requests |
||||
sub certificateReset { |
||||
my ( $self, $req ) = @_; |
||||
|
||||
$self->p->controlUrl($req); |
||||
|
||||
# Check parameters |
||||
$req->error( $self->_certificateReset($req) ); |
||||
|
||||
# Display form |
||||
my ( $tpl, $prms ) = $self->display($req); |
||||
return $self->p->sendHtml( $req, $tpl, params => $prms ); |
||||
} |
||||
|
||||
sub _certificateReset { |
||||
my ( $self, $req ) = @_; |
||||
my ( $mailToken, %tplPrms ); |
||||
|
||||
# CertificatReset FORM => modifyCertificate() |
||||
if ( $req->method =~ /^POST$/i |
||||
and ( $req->uploads->{certif} ) ) |
||||
{ |
||||
my $upload = $req->uploads->{certif}; |
||||
|
||||
return $self->modifyCertificate($req); |
||||
} |
||||
|
||||
# FIRST FORM |
||||
$mailToken = $req->data->{mailToken} = $req->param('mail_token'); |
||||
unless ( $req->param('mail') || $mailToken ) { |
||||
$self->setSecurity($req); |
||||
return PE_MAILFIRSTACCESS if ( $req->method eq 'GET' ); |
||||
return PE_MAILFORMEMPTY; |
||||
} |
||||
|
||||
my $searchByMail = 1; |
||||
|
||||
# OTHER FORMS |
||||
if ($mailToken) { |
||||
$self->logger->debug("Token given for certificate reset: $mailToken"); |
||||
|
||||
# Check if token is valid |
||||
my $mailSession = |
||||
$self->p->getApacheSession( $mailToken, kind => "TOKEN" ); |
||||
unless ($mailSession) { |
||||
$self->userLogger->warn('Bad reset token'); |
||||
return PE_BADMAILTOKEN; |
||||
} |
||||
|
||||
$req->{user} = $mailSession->data->{user}; |
||||
$req->data->{mailAddress} = |
||||
$mailSession->data->{ $self->conf->{mailSessionKey} }; |
||||
$self->logger->debug( 'User associated to: ' . $req->{user} ); |
||||
|
||||
# Restore pdata if any |
||||
$req->pdata( $mailSession->data->{_pdata} || {} ); |
||||
$mailSession->remove; |
||||
$searchByMail = 0 unless ( $req->{user} =~ /\@/ ); |
||||
} |
||||
|
||||
# Check for posted values |
||||
else { |
||||
|
||||
# Use submitted value |
||||
$req->{user} = $req->param('mail'); |
||||
|
||||
# Check if token exists |
||||
my $token; |
||||
if ( $self->ottRule->( $req, {} ) or $self->captcha ) { |
||||
$token = $req->param('token'); |
||||
unless ($token) { |
||||
$self->setSecurity($req); |
||||
$self->userLogger->warn('Reset try without token'); |
||||
return PE_NOTOKEN; |
||||
} |
||||
} |
||||
|
||||
# Captcha for register form |
||||
if ( $self->captcha ) { |
||||
my $captcha = $req->param('captcha'); |
||||
|
||||
unless ($captcha) { |
||||
$self->userLogger->notice('Reset try with captcha not filled'); |
||||
|
||||
# Set captcha or token |
||||
$self->setSecurity($req); |
||||
return PE_CAPTCHAEMPTY; |
||||
} |
||||
|
||||
# Check captcha |
||||
unless ( $self->captcha->validateCaptcha( $token, $captcha ) ) { |
||||
$self->userLogger->info('Captcha failed: wrong code'); |
||||
|
||||
# Set captcha or token |
||||
$self->setSecurity($req); |
||||
return PE_CAPTCHAERROR; |
||||
} |
||||
$self->logger->debug('Captcha code verified'); |
||||
} |
||||
elsif ( $self->ottRule->( $req, {} ) ) { |
||||
unless ( $self->ott->getToken($token) ) { |
||||
$self->setSecurity($req); |
||||
$self->userLogger->warn('Reset try with expired/bad token'); |
||||
return PE_TOKENEXPIRED; |
||||
} |
||||
} |
||||
unless ( $req->{user} =~ /$self->{conf}->{userControl}/o ) { |
||||
$self->setSecurity($req); |
||||
return PE_MALFORMEDUSER; |
||||
} |
||||
} |
||||
|
||||
# Search user in database |
||||
$req->steps( [ |
||||
'getUser', 'setSessionInfo', |
||||
'setMacros', 'setGroups', |
||||
'setPersistentSessionInfo', 'setLocalGroups' |
||||
] |
||||
); |
||||
if ( my $error = $self->p->process( $req, useMail => $searchByMail ) ) { |
||||
if ( $error == PE_USERNOTFOUND or $error == PE_BADCREDENTIALS ) { |
||||
$self->userLogger->warn( 'Reset asked for an unvalid user (' |
||||
. $req->param('mail') |
||||
. ')' ); |
||||
|
||||
# To avoid mail enumeration, return OK |
||||
# unless portalErrorOnMailNotFound is set |
||||
|
||||
if ( $self->conf->{portalErrorOnMailNotFound} ) { |
||||
$self->setSecurity($req); |
||||
return PE_MAILNOTFOUND; |
||||
} |
||||
|
||||
my $mailTimeout = |
||||
$self->conf->{mailTimeout} || $self->conf->{timeout}; |
||||
my $expTimestamp = time() + $mailTimeout; |
||||
$req->data->{expMailDate} = |
||||
strftime( '%d/%m/%Y', localtime $expTimestamp ); |
||||
$req->data->{expMailTime} = |
||||
strftime( '%H:%M', localtime $expTimestamp ); |
||||
return PE_MAILCONFIRMOK; |
||||
} |
||||
return $error; |
||||
} |
||||
|
||||
# Build temporary session |
||||
my $mailSession = $self->getCertificateSession( $req->{user} ); |
||||
unless ( $mailSession or $mailToken ) { |
||||
|
||||
# Create a new session |
||||
|
||||
my $infos = {}; |
||||
|
||||
# Set _utime for session autoremove |
||||
# Use default session timeout and mail session timeout to compute it |
||||
my $time = time(); |
||||
my $timeout = $self->conf->{timeout}; |
||||
my $mailTimeout = $self->conf->{mailTimeout} || $timeout; |
||||
|
||||
$infos->{_utime} = $time + ( $mailTimeout - $timeout ); |
||||
|
||||
# Store expiration timestamp for further use |
||||
$infos->{mailSessionTimeoutTimestamp} = $time + $mailTimeout; |
||||
|
||||
# Store start timestamp for further use |
||||
$infos->{mailSessionStartTimestamp} = $time; |
||||
|
||||
# Store mail |
||||
$infos->{ $self->conf->{mailSessionKey} } = |
||||
$self->p->getFirstValue( |
||||
$req->{sessionInfo}->{ $self->conf->{mailSessionKey} } ); |
||||
|
||||
# Store user |
||||
$infos->{user} = $req->{user}; |
||||
|
||||
# Store type |
||||
$infos->{_type} = 'certificate'; |
||||
|
||||
# Store pdata |
||||
$infos->{_pdata} = $req->pdata; |
||||
|
||||
# create session |
||||
$mailSession = |
||||
$self->p->getApacheSession( undef, kind => "TOKEN", info => $infos ); |
||||
|
||||
$req->id( $mailSession->id ); |
||||
} |
||||
elsif ($mailSession) { |
||||
$self->logger->debug( 'Mail session found: ' . $mailSession->id ); |
||||
$req->id( $mailSession->id ); |
||||
$req->data->{mailAlreadySent} = 1; |
||||
} |
||||
|
||||
# Send confirmation mail |
||||
unless ($mailToken) { |
||||
|
||||
# Mail session expiration date |
||||
my $expTimestamp = $mailSession->data->{mailSessionTimeoutTimestamp}; |
||||
|
||||
$self->logger->debug("Mail expiration timestamp: $expTimestamp"); |
||||
|
||||
$req->data->{expMailDate} = |
||||
strftime( '%d/%m/%Y', localtime $expTimestamp ); |
||||
$req->data->{expMailTime} = |
||||
strftime( '%H:%M', localtime $expTimestamp ); |
||||
|
||||
# Mail session start date |
||||
my $startTimestamp = $mailSession->data->{mailSessionStartTimestamp}; |
||||
|
||||
$self->logger->debug("Mail start timestamp: $startTimestamp"); |
||||
$req->data->{startMailDate} = |
||||
strftime( '%d/%m/%Y', localtime $startTimestamp ); |
||||
$req->data->{startMailTime} = |
||||
strftime( '%H:%M', localtime $startTimestamp ); |
||||
|
||||
# Ask if user wants an another confirmation email |
||||
if ( $req->data->{mailAlreadySent} |
||||
and not $req->param('resendconfirmation') ) |
||||
{ |
||||
$self->userLogger->notice( |
||||
'Reset mail already sent to ' . $req->{user} ); |
||||
|
||||
# Return mail already sent only if it is allowed at previous step |
||||
if ( $self->conf->{portalErrorOnMailNotFound} ) { |
||||
$self->setSecurity($req); |
||||
return PE_MAILCONFIRMATION_ALREADY_SENT; |
||||
} |
||||
} |
||||
|
||||
# Get mail address |
||||
$req->data->{mailAddress} ||= |
||||
$self->p->getFirstValue( |
||||
$req->{sessionInfo}->{ $self->conf->{mailSessionKey} } ); |
||||
return PE_MAILERROR unless ( $req->data->{mailAddress} ); |
||||
|
||||
# Build confirmation url |
||||
my $req_url = $req->data->{_url}; |
||||
my $skin = $self->p->getSkin($req); |
||||
my $url = |
||||
$self->certificateResetUrl . '?' |
||||
. build_urlencoded( |
||||
mail_token => $req->{id}, |
||||
skin => $skin, |
||||
( $req_url ? ( url => $req_url ) : () ), |
||||
); |
||||
|
||||
# Build mail content |
||||
$tplPrms{MAIN_LOGO} = $self->conf->{portalMainLogo}; |
||||
my $tr = $self->translate($req); |
||||
my $subject = $self->conf->{certificateResetByMailStep1Subject}; |
||||
unless ($subject) { |
||||
$subject = 'certificateResetByMailStep1Subject'; |
||||
$tr->( \$subject ); |
||||
} |
||||
my $body; |
||||
my $html; |
||||
if ( $self->conf->{certificateResetByMailStep1Body} ) { |
||||
|
||||
# We use a specific text message, no html |
||||
$body = $self->conf->{certificateResetByMailStep1Body}; |
||||
} |
||||
else { |
||||
|
||||
# Use HTML template |
||||
$body = $self->loadTemplate( |
||||
'mail_confirm', |
||||
filter => $tr, |
||||
params => \%tplPrms |
||||
); |
||||
$html = 1; |
||||
} |
||||
|
||||
# Replace variables in body |
||||
$body =~ s/\$expMailDate/$req->data->{expMailDate}/ge; |
||||
$body =~ s/\$expMailTime/$req->data->{expMailTime}/ge; |
||||
$body =~ s/\$url/$url/g; |
||||
$body =~ s/\$(\w+)/$req->{sessionInfo}->{$1} || ''/ge; |
||||
|
||||
# Send mail |
||||
unless ( |
||||
$self->sendmail( |
||||
$req->data->{mailAddress}, $subject, $body, $html |
||||
) |
||||
) |
||||
{ |
||||
$self->logger->debug('Unable to send reset mail'); |
||||
|
||||
# Don't return an error here to avoid enumeration |
||||
} |
||||
return PE_MAILCONFIRMOK; |
||||
} |
||||
|
||||
# User has a valid mailToken, allow to reset certificate |
||||
# A token is required |
||||
$self->ott->setToken( |
||||
$req, |
||||
{ |
||||
%{ $req->sessionInfo }, certificateResetAllowed => 1 |
||||
} |
||||
); |
||||
return PE_RESETCERTIFICATE_FIRSTACCESS if ( $req->method eq 'GET' ); |
||||
return PE_RESETCERTIFICATE_FORMEMPTY; |
||||
} |
||||
|
||||
sub modifyCertificate { |
||||
my ( $self, $req ) = @_; |
||||
my %tplPrms; |
||||
my $nbio; |
||||
my $x509; |
||||
my $notAfter; |
||||
|
||||
$self->logger->debug('Change your Certificate form response'); |
||||
|
||||
if ( my $token = $req->param('token') ) { |
||||
$req->sessionInfo( $self->ott->getToken($token) ); |
||||
unless ( $req->sessionInfo ) { |
||||
$self->userLogger->warn( |
||||
'User tries to change certificate with an invalid or expired token' |
||||
); |
||||
return PE_NOTOKEN; |
||||
} |
||||
} |
||||
|
||||
# These 2 cases means that a user tries to reset certificate without |
||||
# following valid links!!! |
||||
else { |
||||
$self->userLogger->error( |
||||
'User tries to reset certificate without token'); |
||||
return PE_NOTOKEN; |
||||
} |
||||
|
||||
unless ( $req->sessionInfo->{certificateResetAllowed} ) { |
||||
$self->userLogger->error( |
||||
'User tries to use another token to reset certificate'); |
||||
return PE_NOTOKEN; |
||||
} |
||||
|
||||
#Updload certificate |
||||
my $upload = $req->uploads->{certif}; |
||||
unless ( $upload->size > 0 ) { return PE_RESETCERTIFICATE_FORMEMPTY; } |
||||
|
||||
# Get Certificate |
||||
|
||||
my $file = $upload->path; |
||||
$self->userLogger->debug( "Temporaly file " . $file ); |
||||
|
||||
# Convert certificate file uploaded on DER format with openssl library |
||||
|
||||
#my $certifbase64 =`openssl x509 -outform der -in $file -out $file`; |
||||
|
||||
# load certificate from file with openssl library |
||||
$nbio = Net::SSLeay::BIO_new_file( $file, 'r' ) or die $!; |
||||
|
||||
# for PEM certificate |
||||
$x509 = Net::SSLeay::PEM_read_bio_X509($nbio); |
||||
|
||||
Net::SSLeay::BIO_free($nbio); |
||||
unless ($x509) { |
||||
$self->userLogger->debug( "Unable to decode certificate for user " |
||||
. Net::SSLeay::ERR_error_string( Net::SSLeay::ERR_get_error() ) ); |
||||
|
||||
#return PE_CERTIFICATE_INVALID; |
||||
return PE_RESETCERTIFICATE_INVALID; |
||||
} |
||||
$self->userLogger->debug("Certificate decoded successfully"); |
||||
$notAfter = Net::SSLeay::P_ASN1_TIME_get_isotime( |
||||
Net::SSLeay::X509_get_notAfter($x509) ); |
||||
|
||||
my $x509issuer = Net::SSLeay::X509_NAME_oneline( |
||||
Net::SSLeay::X509_get_issuer_name($x509) ); |
||||
|
||||
my $x509serial = Net::SSLeay::P_ASN1_INTEGER_get_hex( |
||||
Net::SSLeay::X509_get_serialNumber($x509) ); |
||||
|
||||
$self->userLogger->debug( |
||||
"Certificate will expire after $notAfter, Issuer $x509issuer and serialNumber $x509serial" |
||||
); |
||||
|
||||
# Check Certificate Validity before store |
||||
if ( |
||||
$self->checkCertificateValidity( $notAfter, |
||||
$self->conf->{certificateResetByMailValidityDelay} ) == 0 |
||||
) |
||||
{ |
||||
$self->userLogger->debug( |
||||
"Your cettificate is no longer valid in $self->conf->{certificateValidityDelay}" |
||||
); |
||||
return PE_RESETCERTIFICATE_INVALID; |
||||
|
||||
#return PE_PASSWORD_MISMATCH; |
||||
} |
||||
|
||||
# Build serial number hex: example f3:08:52:63:28:29:fa:e2 |
||||
|
||||
my @numberstring = split //, lc($x509serial); |
||||
my $serial = ""; |
||||
for ( my $i = 0 ; $i <= $#numberstring ; $i += 2 ) { |
||||
$serial = $serial . $numberstring[$i] . $numberstring[ $i + 1 ]; |
||||
if ( $i + 2 < $#numberstring ) { $serial = $serial . ":"; } |
||||
} |
||||
|
||||
# format issuer in the good format example "CN=CA,OU=CISIRH,O=MINEFI,L=Paris,ST=France,C=FR" |
||||
|
||||
my @issuertab = split /\//, $x509issuer; |
||||
shift(@issuertab); |
||||
my $issuer = join( ",", reverse(@issuertab) ); |
||||
|
||||
#$issuer = lc($issuer); |
||||
|
||||
my $certificatExactAssertion = |
||||
'{ serialNumber ' . $serial . ', issuer rdnSequence:"' . $issuer . '" }'; |
||||
$self->userLogger->debug( "Description:: " . $certificatExactAssertion ); |
||||
|
||||
# Get attribut userCertificate;binary value |
||||
my $cert = $self->certificateHash($file); |
||||
|
||||
# modif the ldap certificate attribute |
||||
$req->user( $req->{sessionInfo}->{_user} ); |
||||
my $result = |
||||
$self->registerModule->modifCertificate( $certificatExactAssertion, |
||||
$cert, $req ); |
||||
$self->{user} = undef; |
||||
|
||||
# Mail token can be used only one time, delete the session if all is ok |
||||
# |
||||
return $result unless ( $result == PE_OK ); |
||||
|
||||
# Send mail to notify the certificate reset sucessfully |
||||
$req->data->{mailAddress} ||= |
||||
$self->p->getFirstValue( |
||||
$req->{sessionInfo}->{ $self->conf->{mailSessionKey} } ); |
||||
|
||||
# Build mail content |
||||
$tplPrms{MAIN_LOGO} = $self->conf->{portalMainLogo}; |
||||
my $tr = $self->translate($req); |
||||
my $subject = $self->conf->{certificateResetByMailStep2Subject}; |
||||
unless ($subject) { |
||||
$subject = 'certificateResetByMailStep2Subject'; |
||||
$tr->( \$subject ); |
||||
} |
||||
my $body; |
||||
my $html; |
||||
if ( $self->conf->{certificateResetByMailStep2Body} ) { |
||||
|
||||
# We use a specific text message, no html |
||||
$body = $self->conf->{certificateResetByMailStep2Body}; |
||||
} |
||||
else { |
||||
|
||||
# Use HTML template |
||||
$body = $self->loadTemplate( |
||||
'mail_certificatReset', |
||||
filter => $tr, |
||||
params => \%tplPrms |
||||
); |
||||
$html = 1; |
||||
} |
||||
|
||||
# Replace variables in body |
||||
$body =~ s/\$(\w+)/$req->{sessionInfo}->{$1} || ''/ge; |
||||
|
||||
# Send mail |
||||
return PE_MAILERROR |
||||
unless $self->sendmail( $req->data->{mailAddress}, $subject, $body, |
||||
$html ); |
||||
|
||||
return PE_MAILOK; |
||||
} |
||||
|
||||
sub setSecurity { |
||||
my ( $self, $req ) = @_; |
||||
if ( $self->captcha ) { |
||||
$self->captcha->setCaptcha($req); |
||||
} |
||||
elsif ( $self->ottRule->( $req, {} ) ) { |
||||
$self->ott->setToken($req); |
||||
} |
||||
return 1; |
||||
} |
||||
|
||||
sub display { |
||||
my ( $self, $req ) = @_; |
||||
$self->logger->debug( 'Display called with code: ' . $req->error ); |
||||
my %tplPrm = ( |
||||
SKIN_PATH => $self->conf->{staticPrefix}, |
||||
SKIN => $self->p->getSkin($req), |
||||
SKIN_BG => $self->conf->{portalSkinBackground}, |
||||
MAIN_LOGO => $self->conf->{portalMainLogo}, |
||||
AUTH_ERROR => $req->error, |
||||
AUTH_ERROR_TYPE => $req->error_type, |
||||
AUTH_URL => $req->data->{_url}, |
||||
CHOICE_VALUE => $req->{_authChoice}, |
||||
EXPMAILDATE => $req->data->{expMailDate}, |
||||
EXPMAILTIME => $req->data->{expMailTime}, |
||||
STARTMAILDATE => $req->data->{startMailDate}, |
||||
STARTMAILTIME => $req->data->{startMailTime}, |
||||
MAILALREADYSENT => $req->data->{mailAlreadySent}, |
||||
MAIL => ( |
||||
$self->p->checkXSSAttack( 'mail', $req->{user} ) |
||||
? '' |
||||
: $req->{user} |
||||
), |
||||
DISPLAY_FORM => 0, |
||||
DISPLAY_RESEND_FORM => 0, |
||||
DISPLAY_CONFIRMMAILSENT => 0, |
||||
DISPLAY_MAILSENT => 0, |
||||
DISPLAY_CERTIF_FORM => 0, |
||||
); |
||||
if ( $req->data->{mailToken} |
||||
and |
||||
not $self->p->checkXSSAttack( 'mail_token', $req->data->{mailToken} ) ) |
||||
{ |
||||
$tplPrm{MAIL_TOKEN} = $req->data->{mailToken}; |
||||
} |
||||
|
||||
# Display captcha if it's enabled |
||||
if ( $req->captcha ) { |
||||
$tplPrm{CAPTCHA_SRC} = $req->captcha; |
||||
$tplPrm{CAPTCHA_SIZE} = $self->conf->{captcha_size}; |
||||
} |
||||
if ( $req->token ) { |
||||
$tplPrm{TOKEN} = $req->token; |
||||
} |
||||
|
||||
# Display form the first time |
||||
if ( ( |
||||
$req->error == PE_MAILFORMEMPTY |
||||
or $req->error == PE_MAILFIRSTACCESS |
||||
or $req->error == PE_MAILNOTFOUND |
||||
or $req->error == PE_CAPTCHAERROR |
||||
or $req->error == PE_CAPTCHAEMPTY |
||||
) |
||||
and not $req->data->{mailToken} |
||||
) |
||||
{ |
||||
$self->logger->debug('Display form'); |
||||
$tplPrm{DISPLAY_FORM} = 1; |
||||
} |
||||
|
||||
# Display mail confirmation resent form |
||||
elsif ( $req->error == PE_MAILCONFIRMATION_ALREADY_SENT ) { |
||||
$self->logger->debug('Display resend form'); |
||||
$tplPrm{DISPLAY_RESEND_FORM} = 1; |
||||
} |
||||
|
||||
# Display confirmation mail sent |
||||
elsif ( $req->error == PE_MAILCONFIRMOK ) { |
||||
$self->logger->debug('Display "confirm mail sent"'); |
||||
$tplPrm{DISPLAY_CONFIRMMAILSENT} = 1; |
||||
} |
||||
|
||||
# Display mail sent |
||||
elsif ( $req->error == PE_MAILOK ) { |
||||
$self->logger->debug('Display "mail sent"'); |
||||
$tplPrm{DISPLAY_MAILSENT} = 1; |
||||
} |
||||
|
||||
# Display Certificate Reset form |
||||
elsif ( $req->data->{mailToken} |
||||
and $req->error != PE_MAILERROR |
||||
and $req->error != PE_BADMAILTOKEN |
||||
and $req->error != PE_MAILOK ) |
||||
{ |
||||
$self->logger->debug('Display certificate reset form'); |
||||
$tplPrm{DISPLAY_CERTIF_FORM} = 1; |
||||
} |
||||
|
||||
# Display Certificate Reset form again if certificate invalid |
||||
elsif ($req->error == PE_RESETCERTIFICATE_FORMEMPTY |
||||
|| $req->error == PE_RESETCERTIFICATE_INVALID ) |
||||
{ |
||||
$self->logger->debug('Display Certificate Reset form'); |
||||
$tplPrm{DISPLAY_CERTIF_FORM} = 1; |
||||
} |
||||
|
||||
return 'certificateReset', \%tplPrm; |
||||
} |
||||
|
||||
#tring getCertifResetSession (string mail) |
||||
# Check if a certificate reset session exists |
||||
# @param mail the value of the mail key in session |
||||
# @return the first session id found or nothing if no session |
||||
sub getCertificateSession { |
||||
my ( $self, $user ) = @_; |
||||
|
||||
my $moduleOptions = $self->conf->{globalStorageOptions} || {}; |
||||
$moduleOptions->{backend} = $self->conf->{globalStorage}; |
||||
my $module = "Lemonldap::NG::Common::Apache::Session"; |
||||
|
||||
# Search on modifyaccount sessions |
||||
my $sessions = $module->searchOn( $moduleOptions, "user", $user ); |
||||
|
||||
# Browse found sessions to check if it's a modifyaccount session |
||||
foreach my $id ( keys %$sessions ) { |
||||
my $certificateResetSession = |
||||
$self->p->getApacheSession( $id, ( kind => "TOKEN" ) ); |
||||
next unless ($certificateResetSession); |
||||
return $certificateResetSession |
||||
if ( $certificateResetSession->data->{_type} |
||||
and $certificateResetSession->data->{_type} =~ /^certificate$/ ); |
||||
} |
||||
|
||||
# No modifyaccount session found, return empty string |
||||
return ""; |
||||
} |
||||
|
||||
# Use Certificate Update parameter to send mail |
||||
|
||||
sub sendmail { |
||||
|
||||
my ( $self, $mail, $subject, $body, $html ) = @_; |
||||
|
||||
$self->{mailFrom} = $self->conf->{certificateResetByMailSender}; |
||||
$self->{mailReplyTo} = $self->conf->{certificateResetByMailReplyTo}; |
||||
|
||||
return $self->send_mail( $mail, $subject, $body, $html ); |
||||
} |
||||
|
||||
sub checkCertificateValidity { |
||||
|
||||
my ( $self, $notAfter, $delay ) = @_; |
||||
my $dtNow; # now in format DateTime |
||||
my $days; # difference between NotAfter and now |
||||
|
||||
my $f = DateTime::Format::RFC3339->new(); |
||||
|
||||
my $dtNotAfter = $f->parse_datetime($notAfter); |
||||
$self->userLogger->debug("Not After Date: $dtNotAfter"); |
||||
|
||||
$dtNow = DateTime->now; |
||||
$days = $dtNotAfter->delta_days($dtNow)->delta_days; |
||||
$dtNow->add_duration( DateTime::Duration->new( days => $delay ) ); |
||||
|
||||
# test if ( now + $validity ) > certificate_expiration |
||||
if ( DateTime::compare( $dtNow, $dtNotAfter ) >= 0 ) { |
||||
|
||||
# certificate is about to expire |
||||
$self->userLogger->debug( |
||||
"Certificate is about to expire or already expired"); |
||||
return 0; |
||||
} |
||||
else { |
||||
# certificate is still valid |
||||
$self->userLogger->debug("Certificate is still valid for $days days"); |
||||
return 1; |
||||
} |
||||
} |
||||
|
||||
sub certificateHash { |
||||
|
||||
my ( $self, $file ) = @_; |
||||
my $cert; |
||||
|
||||
{ |
||||
local $/ = undef; # Slurp mode |
||||
open CERT, "$file" or die; |
||||
$cert = <CERT>; |
||||
close CERT; |
||||
} |
||||
|
||||
# Normalize certificate |
||||
$cert =~ s/-----(BEGIN|END) CERTIFICATE-----//gi; |
||||
$cert =~ s/["]//gi; |
||||
$cert = decode_base64($cert); |
||||
|
||||
#$self->userLogger->debug( "UserBinary::".$cert); |
||||
return $cert; |
||||
} |
||||
|
||||
1; |
@ -0,0 +1,182 @@ |
||||
<TMPL_INCLUDE NAME="header.tpl"> |
||||
|
||||
<div id="mailcontent" class="container"> |
||||
|
||||
<TMPL_IF NAME="AUTH_ERROR"> |
||||
<div class="message message-<TMPL_VAR NAME="AUTH_ERROR_TYPE"> alert"> |
||||
<span trmsg="<TMPL_VAR NAME="AUTH_ERROR">"></span> |
||||
</div> |
||||
</TMPL_IF> |
||||
|
||||
<TMPL_IF NAME="DISPLAY_FORM"> |
||||
<div class="card"> |
||||
<form action="#" method="post" class="login" role="form"> |
||||
<div class="form"> |
||||
|
||||
<input type="hidden" name="skin" value="<TMPL_VAR NAME="SKIN">" /> |
||||
<input type="hidden" name="url" value="<TMPL_VAR NAME="AUTH_URL">" /> |
||||
<TMPL_IF NAME="CHOICE_VALUE"> |
||||
<input type="hidden" id="authKey" name="<TMPL_VAR NAME="CHOICE_PARAM">" value="<TMPL_VAR NAME="CHOICE_VALUE">" /> |
||||
</TMPL_IF> |
||||
|
||||
<h3 trspan="certificateReset"> Reset Your Certificate</h3> |
||||
|
||||
<div class="input-group mb-3"> |
||||
<div class="input-group-prepend"> |
||||
<span class="input-group-text"><i class="fa fa-envelope"></i> </span> |
||||
</div> |
||||
<input name="mail" type="text" value="<TMPL_VAR NAME="MAIL">" class="form-control" trplaceholder="mail" required /> |
||||
</div> |
||||
|
||||
<TMPL_IF NAME=CAPTCHA_SRC> |
||||
<div class="form-group"> |
||||
<img src="<TMPL_VAR NAME=CAPTCHA_SRC>" class="img-thumbnail" /> |
||||
</div> |
||||
<div class="input-group mb-3"> |
||||
<div class="input-group-prepend"> |
||||
<span class="input-group-text"><i class="fa fa-eye"></i> </span> |
||||
</div> |
||||
<input type="text" name="captcha" size="<TMPL_VAR NAME=CAPTCHA_SIZE>" class="form-control" trplaceholder="captcha" required autocomplete="off" /> |
||||
</div> |
||||
</TMPL_IF> |
||||
<TMPL_IF NAME="TOKEN"> |
||||
<input type="hidden" name="token" value="<TMPL_VAR NAME="TOKEN">" /> |
||||
</TMPL_IF> |
||||
|
||||
<button type="submit" class="btn btn-success"> |
||||
<span class="fa fa-envelope-open"></span> |
||||
<span trspan="sendPwd">Send me a link</span> |
||||
</button> |
||||
|
||||
</div> |
||||
</form> |
||||
</div> |
||||
</TMPL_IF> |
||||
|
||||
<TMPL_IF NAME="DISPLAY_RESEND_FORM"> |
||||
<div class="card"> |
||||
<form action="#" method="post" class="login" role="form"> |
||||
<div class="form"> |
||||
|
||||
<input type="hidden" name="skin" value="<TMPL_VAR NAME="SKIN">" /> |
||||
<input type="hidden" name="url" value="<TMPL_VAR NAME="AUTH_URL">" /> |
||||
<TMPL_IF NAME="CHOICE_VALUE"> |
||||
<input type="hidden" id="authKey" name="<TMPL_VAR NAME="CHOICE_PARAM">" value="<TMPL_VAR NAME="CHOICE_VALUE">" /> |
||||
</TMPL_IF> |
||||
<TMPL_IF NAME="MAIL"> |
||||
<input type="hidden" value="<TMPL_VAR NAME="MAIL">" name="mail"> |
||||
</TMPL_IF> |
||||
|
||||
<TMPL_IF NAME="TOKEN"> |
||||
<input type="hidden" name="token" value="<TMPL_VAR NAME="TOKEN">" /> |
||||
</TMPL_IF> |
||||
|
||||
<h3 trspan="resendConfirmMail">Resend confirmation mail?</h3> |
||||
|
||||
<p class="alert alert-info"> |
||||
<span trspan="pwdResetAlreadyIssued">A Certificate reset request was already issued on</span> |
||||
<TMPL_VAR NAME="STARTMAILDATE">. |
||||
<span trspan="resentConfirm">Do you want the confirmation mail to be resent?</span> |
||||
</p> |
||||
|
||||
<TMPL_IF NAME=CAPTCHA_SRC> |
||||
<div class="form-group"> |
||||
<img src="<TMPL_VAR NAME=CAPTCHA_SRC>" class="img-thumbnail" /> |
||||
</div> |
||||
<div class="input-group mb-3"> |
||||
<div class="input-group-prepend"> |
||||
<span class="input-group-text"><i class="fa fa-eye"></i> </span> |
||||
</div> |
||||
<input type="text" name="captcha" size="<TMPL_VAR NAME=CAPTCHA_SIZE>" class="form-control" trplaceholder="captcha" required autocomplete="off"/> |
||||
</div> |
||||
</TMPL_IF> |
||||
|
||||
<div class="input-group mb-3"> |
||||
<div class="input-group-prepend"> |
||||
<div class="input-group-text"> |
||||
<input id="resendconfirmation" type="checkbox" name="resendconfirmation" aria-describedby="resendconfirmationlabel" /> |
||||
</div> |
||||
</div> |
||||
<p class="form-control"> |
||||
<label for="resendconfirmation" id="resendconfirmationlabel" trspan="confirmPwd">Yes , resend the mail</label> |
||||
</p> |
||||
</div> |
||||
|
||||
<button type="submit" class="btn btn-success"> |
||||
<span class="fa fa-envelope-open"></span> |
||||
<span trspan="submit">Submit</span> |
||||
</button> |
||||
|
||||
</div> |
||||
</form> |
||||
</div> |
||||
</TMPL_IF> |
||||
|
||||
<TMPL_IF NAME="DISPLAY_CERTIF_FORM"> |
||||
<div class="card" id="password"> |
||||
<form action="#" method="post" enctype="multipart/form-data" class="password" role="form"> |
||||
<div class="form"> |
||||
|
||||
<input type="hidden" name="skin" value="<TMPL_VAR NAME="SKIN">" /> |
||||
<input type="hidden" name="url" value="<TMPL_VAR NAME="AUTH_URL">" /> |
||||
<TMPL_IF NAME="CHOICE_VALUE"> |
||||
<input type="hidden" id="authKey" name="<TMPL_VAR NAME="CHOICE_PARAM">" value="<TMPL_VAR NAME="CHOICE_VALUE">" /> |
||||
</TMPL_IF> |
||||
|
||||
<TMPL_IF NAME="TOKEN"> |
||||
<input type="hidden" id="token" name="token" value="<TMPL_VAR NAME="TOKEN">" /> |
||||
</TMPL_IF> |
||||
|
||||
<h3 trspan="certificateReset">Reset your Certificate</h3> |
||||
|
||||
<div class="input-group mb-3"> |
||||
<div class="input-group-prepend"> |
||||
<span class="input-group-text"><i class="fa fa-upload"></i> </span> |
||||
</div> |
||||
<input name="certif" type="file" class="form-control" accept=".pem, .crt,application/x-pem-file", trplaceholder="UploadCertificate" required /> |
||||
</div> |
||||
|
||||
<button type="submit" class="btn btn-success"> |
||||
<span class="fa fa-envelope-open"></span> |
||||
<span trspan="submit">Submit</span> |
||||
</button> |
||||
|
||||
</div> |
||||
</form> |
||||
</div> |
||||
</TMPL_IF> |
||||
|
||||
<TMPL_IF NAME="DISPLAY_CONFIRMMAILSENT"> |
||||
<div class="card"> |
||||
<form action="#" method="post" class="login" role="form"> |
||||
<div class="form"> |
||||
<h3 trspan="mailSent2">A message has been sent to your mail address.</h3> |
||||
<p class="alert alert-info"> |
||||
<span trspan="linkValidUntilCertif">This message contains a link to reset your certificate. This link is valid until </span> |
||||
<TMPL_VAR NAME="EXPMAILDATE">. |
||||
</p> |
||||
</div> |
||||
</form> |
||||
</div> |
||||
</TMPL_IF> |
||||
|
||||
<TMPL_IF NAME="DISPLAY_MAILSENT"> |
||||
<div class="card"> |
||||
<form action="#" method="post" class="login" role="form"> |
||||
<div class="form"> |
||||
<h3 trspan="resetCertificateOK">A confirmation has been sent to your mail address.</h3> |
||||
</div> |
||||
</form> |
||||
</div> |
||||
</TMPL_IF> |
||||
|
||||
<div class="buttons"> |
||||
<a href="<TMPL_VAR NAME="PORTAL_URL">?skin=<TMPL_VAR NAME="SKIN"><TMPL_IF NAME="CHOICE_VALUE">&<TMPL_VAR NAME="CHOICE_PARAM">=<TMPL_VAR NAME="CHOICE_VALUE"></TMPL_IF><TMPL_IF NAME="AUTH_URL">&url=<TMPL_VAR NAME="AUTH_URL"></TMPL_IF>" class="btn btn-primary" role="button"> |
||||
<span class="fa fa-home"></span> |
||||
<span trspan="back2Portal">Go back to portal</span> |
||||
</a> |
||||
</div> |
||||
|
||||
</div> |
||||
|
||||
<TMPL_INCLUDE NAME="footer.tpl"> |
@ -0,0 +1,9 @@ |
||||
<TMPL_INCLUDE NAME="mail_header.tpl"> |
||||
|
||||
<p> |
||||
<span trspan="hello">Hello</span> $cn,<br /> |
||||
<br /> |
||||
<span trspan="certificatReset">Your certificate was reset sucessfully.</span> |
||||
</p> |
||||
|
||||
<TMPL_INCLUDE NAME="mail_footer.tpl"> |
@ -0,0 +1,218 @@ |
||||
#!/usr/bin/perl |
||||
|
||||
use Test::More; |
||||
use strict; |
||||
use IO::String; |
||||
use File::Copy; |
||||
|
||||
BEGIN { |
||||
eval { |
||||
require 't/test-lib.pm'; |
||||
require 't/smtp.pm'; |
||||
}; |
||||
} |
||||
|
||||
my ( $res, $user ); |
||||
my $maintests = 6; |
||||
|
||||
SKIP: { |
||||
eval |
||||
'require Email::Sender::Simple; use GD::SecurityImage;use Image::Magick;'; |
||||
if ($@) { |
||||
skip 'Missing dependencies ' . $@, $maintests; |
||||
|
||||
} |
||||
|
||||
skip 'LLNGTESTLDAP is not set', $maintests unless ( $ENV{LLNGTESTLDAP} ); |
||||
require 't/test-ldap.pm'; |
||||
|
||||
my $client = LLNG::Manager::Test->new( { |
||||
ini => { |
||||
logLevel => 'debug', |
||||
useSafeJail => 1, |
||||
portalDisplayRegister => 1, |
||||
authentication => 'SSL', |
||||
userDB => 'LDAP', |
||||
passwordDB => 'LDAP', |
||||
registerDB => 'LDAP', |
||||
ldapServer => 'ldap://127.0.0.1:19389/', |
||||
ldapBase => 'ou=users,dc=example,dc=com', |
||||
managerDn => 'cn=admin,dc=example,dc=com', |
||||
managerPassword => 'admin', |
||||
captcha_mail_enabled => 0, |
||||
portalDisplayCertificateResetByMail => 1, |
||||
certificateResetByMailCeaAttribute => 'description', |
||||
certificateResetByMailCertificateAttribute => |
||||
'userCertificate;binary', |
||||
certificateResetByMailStep1Body => |
||||
'Click here <a href="$url"> to confirm your mail. It will expire $expMailDate', |
||||
certificateResetByMailStep2Body => |
||||
'Certificate Reset sucessfully!', |
||||
certificateValidityDelay => 30 |
||||
|
||||
} |
||||
} |
||||
); |
||||
|
||||
# Test form |
||||
# ------------------------ |
||||
ok( $res = $client->_get( '/certificateReset', accept => 'text/html' ), |
||||
'Reset form', ); |
||||
my ( $host, $url, $query ) = expectForm( $res, '#', undef, 'mail' ); |
||||
|
||||
$query = 'mail=dwho%40badwolf.org'; |
||||
|
||||
# Post email |
||||
ok( |
||||
$res = $client->_post( |
||||
'/certificateReset', IO::String->new($query), |
||||
length => length($query), |
||||
accept => 'text/html' |
||||
), |
||||
'Post mail' |
||||
); |
||||
|
||||
ok( mail() =~ m#a href="http://auth.example.com/certificateReset\?(.*?)"#, |
||||
'Found link in mail' ); |
||||
$query = $1; |
||||
my $querymail = $query; |
||||
ok( |
||||
$res = $client->_get( |
||||
'/certificateReset', |
||||
query => $query, |
||||
accept => 'text/html' |
||||
), |
||||
'Post mail token received by mail' |
||||
); |
||||
|
||||
# print STDERR Dumper($res); |
||||
|
||||
( $host, $url, $query ) = expectForm( $res, '#', undef, 'token' ); |
||||
ok( $res->[2]->[0] =~ /certif/s, ' Ask for a new certificate file' ); |
||||
|
||||
#print STDERR Dumper($query); |
||||
my %inputs = split( /[=&]/, $query ); |
||||
my %querytab = split( /[=&]/, $querymail ); |
||||
|
||||
# Create the certificate file |
||||
my $cert = "-----BEGIN CERTIFICATE----- |
||||
MIIDdzCCAl+gAwIBAgIJAKGx8siw7lkRMA0GCSqGSIb3DQEBCwUAMFExCzAJBgNV |
||||
BAYTAkZSMQ8wDQYDVQQIDAZGcmFuY2UxDjAMBgNVBAcMBVBBcmlzMREwDwYDVQQK |
||||
DAhMaW5hZ29yYTEOMAwGA1UECwwFTElOSUQwIBcNMTkwNzA0MTcyNjI4WhgPMjEx |
||||
OTA2MTAxNzI2MjhaMFExCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZGcmFuY2UxDjAM |
||||
BgNVBAcMBVBBcmlzMREwDwYDVQQKDAhMaW5hZ29yYTEOMAwGA1UECwwFTElOSUQw |
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3iyeNE2vpURgdY7xwxS16 |
||||
xUJANPuMSrCfy1E/xpCtbP02zK0B11DkT81AnTHgvsWYuiubR1P3Phhh+JLsLRho |
||||
Grzu9xjaiKXQ+kT1cAiq6skZljphykXBfKUb73W9CPntHL/zl3XyIfu+dWyCGbqa |
||||
jHw0Llomi8JqU/XKB6XAYumsV3QzFMM7ECm5HeV3BxfIBwoIOwfwINDUrAGS3h4k |
||||
WH/iiqwG7uSuADupSfdmOrvE7rYZupPas4YATX1m5hmON++9pRRFVEoNeOV1qyGY |
||||
G7swH1uoO2hAgwKIw0vinft/pJLqe3qhrJwNCIZFHaDEx/PRERFeeEH9/6HSz5kt |
||||
AgMBAAGjUDBOMB0GA1UdDgQWBBTFv6pQT/9IBWEAGhILGCcweVfHmTAfBgNVHSME |
||||
GDAWgBTFv6pQT/9IBWEAGhILGCcweVfHmTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 |
||||
DQEBCwUAA4IBAQBFYneMW5etMnsA3/PdvOqx/ijBF98aKlB4U4IKZpdDRAcsstdL |
||||
BSsHRQbHXtb9VdlDWvUnNg5DmjsA8DkOXKXGPGM9ncu9tQi9EoInbOJTMaEsIr2j |
||||
zrLj6PHTvazy+6Au+R/9N5u3WQtq/Z2xoN/+bbQ1dyjXgQmBZFizHP32l5AdgBDT |
||||
jF7xMHxJ6Jxz9lkI+d9v0TzpxTStsaC+pbDfoouNc2deZkv84YTIrD0EPSHFDH5d |
||||
u5i9b+lrWZeCtpVEPzSYpnBwGfepbZAzfVRKJm7wZPCe7KxqMGXQLVBkD8oN7vA1 |
||||
lkRrWfQftwmLyNIu3HfSgXlgAZS30ymfbzBU |
||||
-----END CERTIFICATE-----"; |
||||
|
||||
open my $FH2, '>', '/tmp/v296ZJQ_kG'; |
||||
print {$FH2} "$cert"; |
||||
close $FH2; |
||||
|
||||
$res = $client->app->( { |
||||
'plack.request.query' => bless( { |
||||
'skin' => $querytab{'skin'}, |
||||
'mail_token' => $querytab{'mail_token'} |
||||
}, |
||||
'Hash::MultiValue' |
||||
), |
||||
'PATH_INFO' => '/certificateReset', |
||||
'HTTP_ACCEPT' => |
||||
'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3', |
||||
'REQUEST_METHOD' => 'POST', |
||||
'HTTP_ORIGIN' => 'http://auth.example.com', |
||||
'HTTP_ACCEPT_LANGUAGE' => 'fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3', |
||||
'REQUEST_SCHEME' => 'http', |
||||
'HTTP_CACHE_CONTROL' => 'max-age=0', |
||||
|
||||
'plack.request.merged' => bless( { |
||||
'skin' => $querytab{'skin'}, |
||||
'mail_token' => $querytab{'mail_token'}, |
||||
'url' => '', |
||||
'token' => $inputs{'token'} |
||||
}, |
||||
'Hash::MultiValue' |
||||
), |
||||
'REMOTE_PORT' => '36674', |
||||
'QUERY_STRING' => $querymail, |
||||
'SERVER_SIGNATURE' => '', |
||||
'psgix.input.buffered' => 1, |
||||
'HTTP_UPGRADE_INSECURE_REQUESTS' => '1', |
||||
'CONTENT_TYPE' => |
||||
'multipart/form-data; boundary=----WebKitFormBoundarybabRY9u6K9tERoLr', |
||||
'plack.request.upload' => bless( { |
||||
'certif' => bless( { |
||||
'headers' => bless( { |
||||
'content-disposition' => |
||||
'form-data; name="certif"; filename="user.pem"', |
||||
'content-type' => |
||||
'application/x-x509-ca-cert', |
||||
'::std_case' => { |
||||
'content-disposition' => |
||||
'Content-Disposition' |
||||
} |
||||
}, |
||||
'HTTP::Headers' |
||||
), |
||||
'filename' => 'user.pem', |
||||
'tempname' => '/tmp/v296ZJQ_kG', |
||||
'size' => 1261 |
||||
}, |
||||
'Plack::Request::Upload' |
||||
) |
||||
}, |
||||
'Hash::MultiValue' |
||||
), |
||||
'psgi.streaming' => 1, |
||||
'plack.request.body' => bless( { |
||||
'skin' => 'bootstrap', |
||||
'url' => '', |
||||
'token' => $inputs{'token'} |
||||
}, |
||||
'Hash::MultiValue' |
||||
), |
||||
'SCRIPT_URL' => '/certificateReset', |
||||
'SERVER_NAME' => 'auth.example.com', |
||||
'HTTP_REFERER' => 'http://auth.example.com/certificateReset?' |
||||
. $querymail, |
||||
'HTTP_CONNECTION' => 'close', |
||||
'CONTENT_LENGTH' => '1759', |
||||
'SCRIPT_URI' => 'http://auth.example.com/certificateReset', |
||||
'plack.cookie.parsed' => { |
||||
'llnglanguage' => 'fr' |
||||
}, |
||||
'SERVER_PORT' => '80', |
||||
'SERVER_NAME' => 'auth.example.com', |
||||
'SERVER_PROTOCOL' => 'HTTP/1.1', |
||||
'SCRIPT_NAME' => '', |
||||
'HTTP_USER_AGENT' => |
||||
'Mozilla/5.0 (VAX-4000; rv:36.0) Gecko/20350101 Firefox', |
||||
'HTTP_COOKIE' => 'llnglanguage=fr', |
||||
'REMOTE_ADDR' => '127.0.0.1', |
||||
'REQUEST_URI' => '/certificateReset?' . $querymail, |
||||
'plack.cookie.string' => 'llnglanguage=fr', |
||||
'SERVER_ADDR' => '127.0.0.1', |
||||
'psgi.url_scheme' => 'http', |
||||
'psgix.harakiri' => '', |
||||
'HTTP_HOST' => 'auth.example.com' |
||||
} |
||||
); |
||||
|
||||
ok( mail() =~ /Certificate Reset sucessfully/, 'Certificate was changed' ); |
||||
|
||||
} |
||||
count($maintests); |
||||
stopLdapServer() if $ENV{LLNGTESTLDAP}; |
||||
done_testing( count() ); |
Loading…
Reference in new issue