Merge branch 'v2.0'

This commit is contained in:
Christophe Maudoux 2019-06-17 22:42:28 +02:00
commit 9ac5834bfe
33 changed files with 796 additions and 422 deletions

View File

@ -24,7 +24,7 @@ use constant MANAGERSECTION => "manager";
use constant SESSIONSEXPLORERSECTION => "sessionsExplorer";
use constant APPLYSECTION => "apply";
our $hashParameters = qr/^(?:(?:l(?:o(?:ca(?:lSessionStorageOption|tionRule)|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|(?:(?:d(?:emo|bi)|facebook|webID)ExportedVa|exported(?:Heade|Va)|issuerDBGetParamete)r|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|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)|c(?:as(?:S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions)|A(?:ppMetaData(?:(?:ExportedVar|Option)s|Node)|ttributes))|(?:ustomAddParam|ombModule)s)|p(?:ersistentStorageOptions|o(?:rtalSkinRules|st))|a(?:ut(?:hChoiceMod|oSigninR)ules|pplicationList)|v(?:hostOptions|irtualHost)|S(?:MTPTLSOpts|SLVarIf))$/;
our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|ingle(?:Session(?:UserByIP)?|(?:UserBy)?IP)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|howLanguages|slByAjax)|o(?:idc(?:ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|RPMetaDataOptions(?:LogoutSessionRequired|BypassConsent|RequirePKCE|Public)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:ErrorOn(?:ExpiredSession|MailNotFound)|DisplayRe(?:setPassword|gister)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|RequireOldPassword|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:User(?:Display(?:PersistentInfo|EmptyValues))?|State|XSS)|orsEnabled|da)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|no(?:tif(?:ication(?:Server)?|y(?:Deleted|Other))|AjaxHook)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|rest(?:(?:Session|Config)Server|ExportSecretKeys)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|(?:activeTim|wsdlServ)er|krb(?:RemoveDomain|ByJs)|dbiDynamicHashEnabled|bruteForceProtection)$/;
our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|ingle(?:Session(?:UserByIP)?|(?:UserBy)?IP)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|fRemovedUseNotif|howLanguages|slByAjax)|o(?:idc(?:ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|RPMetaDataOptions(?:LogoutSessionRequired|BypassConsent|RequirePKCE|Public)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:ErrorOn(?:ExpiredSession|MailNotFound)|DisplayRe(?:setPassword|gister)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|RequireOldPassword|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:User(?:Display(?:PersistentInfo|EmptyValues))?|State|XSS)|orsEnabled|da)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|no(?:tif(?:ication(?:Server)?|y(?:Deleted|Other))|AjaxHook)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|rest(?:(?:Session|Config)Server|ExportSecretKeys)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|(?:activeTim|wsdlServ)er|krb(?:RemoveDomain|ByJs)|dbiDynamicHashEnabled|bruteForceProtection)$/;
our @sessionTypes = ( 'remoteGlobal', 'global', 'localSession', 'persistent', 'saml', 'oidc', 'cas' );

View File

@ -28,7 +28,7 @@ sub defaultValues {
'casAccessControlPolicy' => 'none',
'casAuthnLevel' => 1,
'checkTime' => 600,
'checkUserHiddenAttributes' => '_2fDevices _loginHistory hGroups',
'checkUserHiddenAttributes' => '_loginHistory hGroups',
'checkUserIdRule' => 1,
'checkXSS' => 1,
'confirmFormMethod' => 'post',
@ -78,7 +78,7 @@ sub defaultValues {
'groups' => {},
'handlerInternalCache' => 15,
'handlerServiceTokenTTL' => 30,
'hiddenAttributes' => '_password',
'hiddenAttributes' => '_password _2fDevices',
'httpOnly' => 1,
'https' => -1,
'impersonationHiddenAttributes' => '_2fDevices _loginHistory',
@ -279,43 +279,47 @@ sub defaultValues {
'samlSPSSODescriptorWantAssertionsSigned' => 1,
'securedCookie' => 0,
'sfEngine' => '::2F::Engines::Default',
'sfRemovedMsg' => 0,
'sfRequired' => 0,
'showLanguages' => 1,
'slaveAuthnLevel' => 2,
'slaveExportedVars' => {},
'SMTPServer' => '',
'SMTPTLS' => '',
'SSLAuthnLevel' => 5,
'SSLVar' => 'SSL_CLIENT_S_DN_Email',
'SSLVarIf' => {},
'successLoginNumber' => 5,
'timeout' => 72000,
'timeoutActivity' => 0,
'timeoutActivityInterval' => 60,
'totp2fActivation' => 0,
'totp2fDigits' => 6,
'totp2fInterval' => 30,
'totp2fRange' => 1,
'totp2fSelfRegistration' => 0,
'totp2fUserCanRemoveKey' => 1,
'twitterAuthnLevel' => 1,
'twitterUserField' => 'screen_name',
'u2fActivation' => 0,
'u2fSelfRegistration' => 0,
'u2fUserCanRemoveKey' => 1,
'upgradeSession' => 1,
'userControl' => '^[\\w\\.\\-@]+$',
'userDB' => 'Same',
'useRedirectOnError' => 1,
'useSafeJail' => 1,
'utotp2fActivation' => 0,
'viewerHiddenKeys' => 'samlIDPMetaDataNodes samlSPMetaDataNodes',
'webIDAuthnLevel' => 1,
'webIDExportedVars' => {},
'whatToTrace' => 'uid',
'yubikey2fActivation' => 0,
'yubikey2fPublicIDSize' => 12,
'sfRemovedMsgRule' => 0,
'sfRemovedNotifMsg' =>
'_removedSF_ expired second factor(s) has/have been removed!',
'sfRemovedNotifRef' => 'RemoveSF',
'sfRemovedNotifTitle' => 'Second factor notification',
'sfRequired' => 0,
'showLanguages' => 1,
'slaveAuthnLevel' => 2,
'slaveExportedVars' => {},
'SMTPServer' => '',
'SMTPTLS' => '',
'SSLAuthnLevel' => 5,
'SSLVar' => 'SSL_CLIENT_S_DN_Email',
'SSLVarIf' => {},
'successLoginNumber' => 5,
'timeout' => 72000,
'timeoutActivity' => 0,
'timeoutActivityInterval' => 60,
'totp2fActivation' => 0,
'totp2fDigits' => 6,
'totp2fInterval' => 30,
'totp2fRange' => 1,
'totp2fSelfRegistration' => 0,
'totp2fUserCanRemoveKey' => 1,
'twitterAuthnLevel' => 1,
'twitterUserField' => 'screen_name',
'u2fActivation' => 0,
'u2fSelfRegistration' => 0,
'u2fUserCanRemoveKey' => 1,
'upgradeSession' => 1,
'userControl' => '^[\\w\\.\\-@]+$',
'userDB' => 'Same',
'useRedirectOnError' => 1,
'useSafeJail' => 1,
'utotp2fActivation' => 0,
'viewerHiddenKeys' => 'samlIDPMetaDataNodes samlSPMetaDataNodes',
'webIDAuthnLevel' => 1,
'webIDExportedVars' => {},
'whatToTrace' => 'uid',
'yubikey2fActivation' => 0,
'yubikey2fPublicIDSize' => 12,
'yubikey2fSelfRegistration' => 0,
'yubikey2fUserCanRemoveKey' => 1
};

View File

@ -786,7 +786,7 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'type' => 'bool'
},
'checkUserHiddenAttributes' => {
'default' => '_2fDevices _loginHistory hGroups',
'default' => '_loginHistory hGroups',
'type' => 'text'
},
'checkUserIdRule' => {
@ -1216,7 +1216,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'type' => 'int'
},
'hiddenAttributes' => {
'default' => '_password',
'default' => '_password _2fDevices',
'type' => 'text'
},
'hideOldPassword' => {
@ -3197,10 +3197,27 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'default' => '::2F::Engines::Default',
'type' => 'text'
},
'sfRemovedMsg' => {
'sfRemovedMsgRule' => {
'default' => 0,
'type' => 'boolOrExpr'
},
'sfRemovedNotifMsg' => {
'default' =>
'_removedSF_ expired second factor(s) has/have been removed!',
'type' => 'text'
},
'sfRemovedNotifRef' => {
'default' => 'RemoveSF',
'type' => 'text'
},
'sfRemovedNotifTitle' => {
'default' => 'Second factor notification',
'type' => 'text'
},
'sfRemovedUseNotif' => {
'default' => 0,
'type' => 'bool'
},
'sfRequired' => {
'default' => 0,
'type' => 'boolOrExpr'

View File

@ -435,7 +435,7 @@ sub attributes {
},
checkUserHiddenAttributes => {
type => 'text',
default => '_2fDevices _loginHistory hGroups',
default => '_loginHistory hGroups',
documentation => 'Attributes to hide in CheckUser plugin',
flags => 'p',
},
@ -716,7 +716,7 @@ sub attributes {
},
hiddenAttributes => {
type => 'text',
default => '_password',
default => '_password _2fDevices',
documentation => 'Name of attributes to hide in logs',
},
key => {
@ -2587,11 +2587,36 @@ sub attributes {
help => 'secondfactor.html',
documentation => 'Second factor required',
},
sfRemovedMsg => {
type => 'boolOrExpr',
sfRemovedMsgRule => {
type => 'boolOrExpr',
default => 0,
help => 'secondfactor.html',
documentation =>
'Display a message if at leat one expired SF has been removed',
},
sfRemovedUseNotif => {
default => 0,
type => 'bool',
documentation => 'Use Notifications plugin to display message',
},
sfRemovedNotifRef => {
type => 'text',
default => 'RemoveSF',
help => 'secondfactor.html',
documentation => 'Display a message if at leat one expired SF has been removed',
documentation => 'Notification reference',
},
sfRemovedNotifTitle => {
type => 'text',
default => 'Second factor notification',
help => 'secondfactor.html',
documentation => 'Notification title',
},
sfRemovedNotifMsg => {
type => 'text',
default =>
'_removedSF_ expired second factor(s) has/have been removed!',
help => 'secondfactor.html',
documentation => 'Notification message',
},
available2F => {
type => 'text',
@ -2692,7 +2717,6 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
documentation => 'LDAP password encoding',
},
ldapUsePasswordResetAttribute => {
default => 0,
type => 'bool',
default => 1,
documentation => 'LDAP store reset flag in an attribute',

View File

@ -763,7 +763,17 @@ sub tree {
'yubikey2fTTL',
],
},
'sfRequired', 'sfRemovedMsg',
{
title => 'sfRemovedNotification',
help => 'secondfactor.html',
form => 'simpleInputContainer',
nodes => [
'sfRemovedMsgRule', 'sfRemovedUseNotif',
'sfRemovedNotifRef', 'sfRemovedNotifTitle',
'sfRemovedNotifMsg',
],
},
'sfRequired',
]
},
{

View File

@ -734,6 +734,12 @@
"sessionTitle":"محتوى الجلسة",
"sfaTitle":"Second Factors Authentication",
"sfRequired":"Require 2FA",
"sfRemovedNotification":"Display a message if an expired SF is removed",
"sfRemovedMsgRule":"تفعيل",
"sfRemovedUseNotif":"Use Notifications plugin",
"sfRemovedNotifMsg":"Notification message",
"sfRemovedNotifRef":"Notification reference",
"sfRemovedNotifTitle":"Notification title",
"sfRemovedMsg":"Display a message if an expired SF is removed",
"show":"عرض",
"showHelp":"عرض المساعدة",

View File

@ -733,6 +733,12 @@
"sessionTitle":"Session content",
"sfaTitle":"Second Factors Authentication",
"sfRequired":"Require 2FA",
"sfRemovedNotification":"Display a message if an expired SF is removed",
"sfRemovedMsgRule":"Activation",
"sfRemovedUseNotif":"Use Notifications plugin",
"sfRemovedNotifMsg":"Notification message",
"sfRemovedNotifRef":"Notification reference",
"sfRemovedNotifTitle":"Notification title",
"sfRemovedMsg":"Display a message if an expired SF is removed",
"show":"Show",
"showHelp":"Show help",

View File

@ -733,6 +733,12 @@
"sessionTitle":"Session content",
"sfaTitle":"Second Factors Authentication",
"sfRequired":"Require 2FA",
"sfRemovedNotification":"Display a message if an expired SF is removed",
"sfRemovedMsgRule":"Activation",
"sfRemovedUseNotif":"Use Notifications plugin",
"sfRemovedNotifMsg":"Notification message",
"sfRemovedNotifRef":"Notification reference",
"sfRemovedNotifTitle":"Notification title",
"sfRemovedMsg":"Display a message if an expired SF is removed",
"show":"Show",
"showHelp":"Show help",

View File

@ -733,6 +733,12 @@
"sessionTitle":"Contenu de la session",
"sfaTitle":"Seconds Facteurs d'Authentification",
"sfRequired":"Exiger 2FA",
"sfRemovedNotification":"Afficher un message si un SF expiré a été supprimé",
"sfRemovedMsgRule":"Activation",
"sfRemovedUseNotif":"Utiliser les notifications",
"sfRemovedNotifMsg":"Message de la notification",
"sfRemovedNotifRef":"Référence de la notification",
"sfRemovedNotifTitle":"Titre de la notification",
"sfRemovedMsg":"Afficher un message si un SF expiré est supprimé",
"show":"Montrer",
"showHelp":"Montrer l'aide",

View File

@ -733,6 +733,12 @@
"sessionTitle":"Contenuto della sessione",
"sfaTitle":"Autenticazione a due fattori",
"sfRequired":"Richiedi 2FA",
"sfRemovedNotification":"Display a message if an expired SF is removed",
"sfRemovedMsgRule":"Attivazione",
"sfRemovedUseNotif":"Use Notifications plugin",
"sfRemovedNotifMsg":"Notification message",
"sfRemovedNotifRef":"Notification reference",
"sfRemovedNotifTitle":"Notification title",
"sfRemovedMsg":"Display a message if an expired SF is removed",
"show":"Mostra",
"showHelp":"Mostra aiuto",

View File

@ -148,7 +148,7 @@
"cspConnect":"Đích cúa Ajax",
"cspFont":"Nguồn phông chữ",
"crossOrigineResourceSharing":"Cross-Origin Resource Sharing",
"corsEnabled":"Activation",
"corsEnabled":"Kích hoạt",
"corsAllow_Credentials":"Access-Control-Allow-Credentials",
"corsAllow_Headers":"Access-Control-Allow-Headers",
"corsAllow_Methods":"Access-Control-Allow-Methods",
@ -733,6 +733,12 @@
"sessionTitle":"Nội dung phiên",
"sfaTitle":"Second Factors Authentication",
"sfRequired":"Require 2FA",
"sfRemovedNotification":"Display a message if an expired SF is removed",
"sfRemovedMsgRule":"Kích hoạt",
"sfRemovedUseNotif":"Use Notifications plugin",
"sfRemovedNotifMsg":"Notification message",
"sfRemovedNotifRef":"Notification reference",
"sfRemovedNotifTitle":"Notification title",
"sfRemovedMsg":"Display a message if an expired SF is removed",
"show":"Hiển thị",
"showHelp":"Hiển thị trợ giúp",

View File

@ -733,6 +733,12 @@
"sessionTitle":"Session content",
"sfaTitle":"Second Factors Authentication",
"sfRequired":"Require 2FA",
"sfRemovedNotification":"Display a message if an expired SF is removed",
"sfRemovedMsgRule":"Activation",
"sfRemovedUseNotif":"Use Notifications plugin",
"sfRemovedNotifMsg":"Notification message",
"sfRemovedNotifRef":"Notification reference",
"sfRemovedNotifTitle":"Notification title",
"sfRemovedMsg":"Display a message if an expired SF is removed",
"show":"Show",
"showHelp":"Show help",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -12,6 +12,7 @@ package Lemonldap::NG::Portal::2F::Engines::Default;
use strict;
use Mouse;
use JSON qw(from_json to_json);
use POSIX qw(strftime);
use Lemonldap::NG::Portal::Main::Constants qw(
PE_ERROR
PE_NOTOKEN
@ -30,7 +31,7 @@ extends 'Lemonldap::NG::Portal::Main::Plugin';
has sfModules => ( is => 'rw', default => sub { [] } );
has sfRModules => ( is => 'rw', default => sub { [] } );
has sfReq => ( is => 'rw' );
has sfMsg => ( is => 'rw' );
has sfRule => ( is => 'rw' );
has ott => (
is => 'rw',
@ -107,9 +108,11 @@ sub init {
}
unless (
$self->sfMsg(
$self->sfRule(
$self->p->HANDLER->buildSub(
$self->p->HANDLER->substitute( $self->conf->{sfRemovedMsg} )
$self->p->HANDLER->substitute(
$self->conf->{sfRemovedMsgRule}
)
)
)
)
@ -199,23 +202,20 @@ sub run {
$self->p->updatePersistentSession( $req,
{ _2fDevices => to_json($_2fDevices) } );
# Display message if required
if ( $self->sfMsg->( $req, $req->sessionInfo ) ) {
$req->info(
$self->loadTemplate(
'simpleInfo',
(
$removed > 1
? (
params => {
trspan => "expired2Fremoved, $removed"
}
)
: ( params => { trspan => "oneExpired2Fremoved" } )
)
)
);
return PE_INFO;
# Display notification or message if required
my $res = 0;
if ( $self->sfRule->( $req, $req->sessionInfo ) ) {
my $notifEngine = $self->p->loadedModules->{
'Lemonldap::NG::Portal::Plugins::Notifications'};
if ( $notifEngine && $self->conf->{sfRemovedUseNotif} ) {
$self->logger->debug("Notifications plugin enabled");
$res =
$self->_sendNotification( $req, $notifEngine, $removed );
}
else {
$res = $self->_sendInfo( $req, $removed );
}
return $res if $res;
}
}
}
@ -494,4 +494,57 @@ sub restoreSession {
: $self->_displayRegister( $req, @path );
}
sub _sendInfo {
my ( $self, $req, $removed ) = @_;
$self->logger->debug("Return simpleInfo template");
$req->info(
$self->loadTemplate(
'simpleInfo',
(
$removed > 1
? (
params => {
trspan => "expired2Fremoved, $removed"
}
)
: ( params => { trspan => "oneExpired2Fremoved" } )
)
)
);
return PE_INFO;
}
sub _sendNotification {
my ( $self, $req, $notifEngine, $removed ) = @_;
my $uid = $req->user;
my $date = strftime "%Y-%m-%d", localtime;
my $ref = $self->conf->{sfRemovedNotifRef} || 'RemoveSF';
my $title =
$self->conf->{sfRemovedNotifTitle} || 'Second factor notification';
my $msg = $self->conf->{sfRemovedNotifMsg}
|| "$removed expired second factor(s) has/have been removed!";
$msg =~ s/_removedSF_/$removed/;
# Prepare notification
my $content =
$self->conf->{oldNotifFormat}
? '<?xml version="1.0" encoding="UTF-8"?><root><notification uid="_uid_" date="_date_" reference="_ref_"><title>_title_</title><text>_msg_</text></notification></root>'
: '[{"uid":"_uid_","date":"_date_","title":"_title_","reference":"_ref_","text":"_msg_"}]';
$content =~ s/_uid_/$uid/;
$content =~ s/_ref_/$ref/;
$content =~ s/_date_/$date/;
$content =~ s/_title_/$title/;
$content =~ s/_msg_/$msg/;
if ( $notifEngine->module->notifObject->newNotification($content) ) {
$self->logger->debug("Notification SF successfully appended");
$self->userLogger->notice("Notification SF successfully appended");
return PE_OK;
}
else {
$self->logger->debug("Notification NOT created!");
return $self->_sendInfo( $req, $removed );
}
}
1;

View File

@ -42,7 +42,8 @@ sub authenticate {
# Set the dn unless done before
unless ( $req->data->{dn} ) {
if ( my $tmp = $self->getUser($req) ) {
$self->setSecurity($req);
eval { $self->setSecurity($req) };
$self->logger->warn($@) if ($@);
return $tmp;
}
}

View File

@ -3,6 +3,8 @@ package Lemonldap::NG::Portal::Lib::LDAP;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Lib::Net::LDAP;
use Lemonldap::NG::Portal::Main::Constants
qw(PE_OK PE_LDAPCONNECTFAILED PE_LDAPERROR PE_BADCREDENTIALS);
extends 'Lemonldap::NG::Common::Module';
@ -16,6 +18,17 @@ has ldap => (
builder => 'newLdap',
);
has attrs => (
is => 'rw',
lazy => 1,
builder => sub {
return [
values %{ $_[0]->{conf}->{exportedVars} },
values %{ $_[0]->{conf}->{ldapExportedVars} }
];
}
);
sub newLdap {
my $self = $_[0];
my $ldap;
@ -98,6 +111,38 @@ sub init {
# RUNNING METHODS
sub getUser {
my ( $self, $req, %args ) = @_;
return PE_LDAPCONNECTFAILED unless $self->ldap and $self->bind();
my $mesg = $self->ldap->search(
base => $self->conf->{ldapBase},
scope => 'sub',
filter => (
$args{useMail}
? $self->mailFilter->($req)
: $self->filter->($req)
),
defer => $self->conf->{ldapSearchDeref} || 'find',
attrs => $self->attrs,
);
if ( $mesg->code() != 0 ) {
$self->logger->error( 'LDAP Search error: ' . $mesg->error );
return PE_LDAPERROR;
}
if ( $mesg->count() > 1 ) {
$self->logger->error('More than one entry returned by LDAP directory');
eval { $self->p->_authentication->setSecurity($req) };
return PE_BADCREDENTIALS;
}
unless ( $req->data->{entry} = $mesg->entry(0) ) {
$self->userLogger->warn("$req->{user} was not found in LDAP directory");
eval { $self->p->_authentication->setSecurity($req) };
return PE_BADCREDENTIALS;
}
$req->data->{dn} = $req->data->{entry}->dn();
PE_OK;
}
# Test LDAP connection before trying to bind
sub bind {
my $self = shift;

View File

@ -3,8 +3,7 @@ package Lemonldap::NG::Portal::UserDB::LDAP;
use strict;
use Mouse;
use utf8;
use Lemonldap::NG::Portal::Main::Constants
qw(PE_OK PE_LDAPCONNECTFAILED PE_LDAPERROR PE_BADCREDENTIALS);
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK);
extends 'Lemonldap::NG::Portal::Lib::LDAP';
@ -25,50 +24,9 @@ has ldapGroupAttributeNameSearch => (
}
);
has attrs => (
is => 'rw',
lazy => 1,
builder => sub {
return [
values %{ $_[0]->{conf}->{exportedVars} },
values %{ $_[0]->{conf}->{ldapExportedVars} }
];
}
);
# RUNNING METHODS
sub getUser {
my ( $self, $req, %args ) = @_;
return PE_LDAPCONNECTFAILED unless $self->ldap and $self->bind();
my $mesg = $self->ldap->search(
base => $self->conf->{ldapBase},
scope => 'sub',
filter => (
$args{useMail}
? $self->mailFilter->($req)
: $self->filter->($req)
),
defer => $self->conf->{ldapSearchDeref} || 'find',
attrs => $self->attrs,
);
if ( $mesg->code() != 0 ) {
$self->logger->error( 'LDAP Search error: ' . $mesg->error );
return PE_LDAPERROR;
}
if ( $mesg->count() > 1 ) {
$self->logger->error('More than one entry returned by LDAP directory');
eval { $self->p->_authentication->setSecurity($req) };
return PE_BADCREDENTIALS;
}
unless ( $req->data->{entry} = $mesg->entry(0) ) {
$self->userLogger->warn("$req->{user} was not found in LDAP directory");
eval { $self->p->_authentication->setSecurity($req) };
return PE_BADCREDENTIALS;
}
$req->data->{dn} = $req->data->{entry}->dn();
PE_OK;
}
#
# getUser is provided by Portal::Lib::LDAP
# Load all parameters included in exportedVars parameter.
# Multi-value parameters are loaded in a single string with

View File

@ -162,4 +162,4 @@ div.oidc_consent_message > ul {
.progress-bar-animated {
width: 100%;
}
}

View File

@ -1,146 +1,124 @@
<TMPL_INCLUDE NAME="header.tpl">
<div id="errorcontent" class="container">
<!--
<div class="message message-positive alert"><span trspan="<TMPL_VAR NAME="MSG">"></span></div>
<!--
<div class="message message-positive alert"><span trspan="<TMPL_VAR NAME="MSG">"></span></div>
-->
<div class="alert <TMPL_VAR NAME="ALERTE"> alert"><span trspan="<TMPL_VAR NAME="MSG">"></span></div>
<form id="checkuser" action="/checkuser" method="post" class="password" role="form">
<div class="buttons">
<TMPL_IF NAME="TOKEN">
<input type="hidden" name="token" value="<TMPL_VAR NAME="TOKEN">" />
</TMPL_IF>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-user"></i> </span>
<div class="alert <TMPL_VAR NAME="ALERTE"> alert"><div class="text-center"><span trspan="<TMPL_VAR NAME="MSG">"></span></div></div>
<form id="checkuser" action="/checkuser" method="post" class="password" role="form">
<div class="buttons">
<TMPL_IF NAME="TOKEN">
<input type="hidden" name="token" value="<TMPL_VAR NAME="TOKEN">" />
</TMPL_IF>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-user"></i> </span>
</div>
<input name="user" type="text" class="form-control" value="<TMPL_VAR NAME="LOGIN">" trplaceholder="user" aria-required="true"/>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-link"></i> </span>
</div>
<input name="url" type="text" class="form-control" value="<TMPL_VAR NAME="URL">" trplaceholder="URL / DNS" aria-required="true"/>
</div>
<button type="submit" class="btn btn-success">
<span class="fa fa-search"></span>
<span trspan="search">Search</span>
</button>
</div>
<input name="user" type="text" class="form-control" value="<TMPL_VAR NAME="LOGIN">" trplaceholder="user" aria-required="true"/>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-link"></i> </span>
</form>
<div>
<TMPL_IF NAME="ALLOWED">
<div class="alert <TMPL_VAR NAME="ALERTE_AUTH">"><div class="text-center"><b><span trspan="<TMPL_VAR NAME="ALLOWED">"></span></b></div></div>
</TMPL_IF>
<TMPL_IF NAME="HEADERS">
<div class="row">
<div class="card col border-secondary">
<div class="text-center bg-light text-dark"><b><span trspan="headers">HEADERS</span></b></div>
<div class="font-weight-bold">
<TMPL_LOOP NAME="HEADERS">
<TMPL_VAR NAME="key">: <TMPL_VAR NAME="value"><br/>
</TMPL_LOOP>
</div>
</div>
</div>
</TMPL_IF>
<div class="row">
<TMPL_IF NAME="GROUPS">
<div class="card col border-secondary">
<div class="text-center bg-light text-dark"><b><span trspan="groups_sso">SSO GROUPS</span></b></div>
<div class="row">
<TMPL_LOOP NAME="GROUPS">
<div class="w-100"></div>
<div class="col"><TMPL_VAR NAME="value"></div>
</TMPL_LOOP>
</div>
</div>
</TMPL_IF>
<div class="col">
<div class="row">
<TMPL_IF NAME="ATTRIBUTES">
<div class="card col border-secondary">
<div class="text-center bg-light text-dark"><b><span trspan="attributes">ATTRIBUTES</span></b></div>
<table class="table table-sm table-hover">
<thead>
<tr>
<th scope="col"><span trspan="key">Key</span></th>
<th scope="col"><span trspan="value">Value</span></th>
</tr>
</thead>
<tbody>
<TMPL_LOOP NAME="ATTRIBUTES">
<tr>
<td scope="row"><TMPL_VAR NAME="key"></td>
<td scope="row"><TMPL_VAR NAME="value"></td>
</tr>
</TMPL_LOOP>
</tbody>
</table>
</div>
</TMPL_IF>
<TMPL_IF NAME="GROUPS"><div class="w-100"></div></TMPL_IF>
<TMPL_IF NAME="MACROS">
<div class="card col border-secondary">
<div class="text-center bg-light text-dark"><b><span trspan="macros">MACROS</span></b></div>
<table class="table table-sm table-hover">
<thead>
<tr>
<th scope="col"><span trspan="key">Key</span></th>
<th scope="col"><span trspan="value">Value</span></th>
</tr>
</thead>
<tbody>
<TMPL_LOOP NAME="MACROS">
<tr>
<td scope="row"><TMPL_VAR NAME="key"></td>
<td scope="row"><TMPL_VAR NAME="value"></td>
</tr>
</TMPL_LOOP>
</tbody>
</table>
</div>
</TMPL_IF>
</div>
</div>
</div>
<input name="url" type="text" class="form-control" value="<TMPL_VAR NAME="URL">" trplaceholder="URL / DNS" aria-required="true"/>
</div>
<button type="submit" class="btn btn-success">
<span class="fa fa-search"></span>
<span trspan="search">Search</span>
</button>
</div>
&nbsp;
<TMPL_IF NAME="ALLOWED">
<div class="alert <TMPL_VAR NAME="ALERTE_AUTH">"><b><span trspan="<TMPL_VAR NAME="ALLOWED">"></span></b></div>
</TMPL_IF>
<TMPL_IF NAME="HEADERS">
<div class="card mb-3 border-secondary">
<div class="card-body table-responsive">
<table class="table table-hover">
<thead>
<tr class="align-middle"><b><span trspan="headers">HEADERS</span></b></tr>
<tr>
<th class="align-middle"><span trspan="key">Key</span></th>
<th class="align-middle"><span trspan="value">Value</span></th>
</tr>
</thead>
<tbody>
<TMPL_LOOP NAME="HEADERS">
<tr>
<td class="align-middle"><TMPL_VAR NAME="key"></td>
<td class="align-middle"><TMPL_VAR NAME="value"></td>
</tr>
</TMPL_LOOP>
</tbody>
</table>
</div>
</div>
</TMPL_IF>
<div class="container">
<div class="row">
<TMPL_IF NAME="GROUPS">
<div class="card col-md-2 border-secondary">
<div class="card-body table-responsive">
<table class="table table-hover">
<thead>
<tr class="align-middle"><b><span trspan="groups_sso">SSO GROUPS</span></b></tr>
</thead>
<tbody>
<TMPL_LOOP NAME="GROUPS">
<tr>
<td class="align-middle"><TMPL_VAR NAME="value"></td>
</tr>
</TMPL_LOOP>
</tbody>
</table>
<div class="buttons">
<!--
<button type="submit" class="btn btn-success">
<span class="fa fa-sign-in"></span>
<span trspan="search">Search</span>
</button>
-->
<a href="<TMPL_VAR NAME="PORTAL_URL">" class="btn btn-primary" role="button">
<span class="fa fa-home"></span>
<span trspan="goToPortal">Go to portal</span>
</a>
</div>
</div>
</div>
</TMPL_IF>
<TMPL_IF NAME="MACROS">
<div class="card col-md-4 border-secondary">
<div class="card-body table-responsive">
<table class="table table-hover">
<thead>
<tr class="align-middle"><b><span trspan="macros">MACROS</span></b></tr>
<tr>
<th class="align-middle"><span trspan="key">Key</span></th>
<th class="align-middle"><span trspan="value">Value</span></th>
</tr>
</thead>
<tbody>
<TMPL_LOOP NAME="MACROS">
<tr>
<td class="align-middle"><TMPL_VAR NAME="key"></td>
<td class="align-middle"><TMPL_VAR NAME="value"></td>
</tr>
</TMPL_LOOP>
</tbody>
</table>
</div>
</div>
</TMPL_IF>
<TMPL_IF NAME="ATTRIBUTES">
<div class="card col-md-6 border-secondary">
<div class="card-body table-responsive">
<table class="table table-hover">
<thead>
<tr class="align-middle"><b><span trspan="attributes">ATTRIBUTES</span></b></tr>
<tr>
<th class="text-left"><span trspan="key">Key</span></th>
<th class="text-left"><span trspan="value">Value</span></th>
</tr>
</thead>
<tbody>
<TMPL_LOOP NAME="ATTRIBUTES">
<tr>
<td class="text-left"><TMPL_VAR NAME="key"></td>
<td class="text-left"><TMPL_VAR NAME="value"></td>
</tr>
</TMPL_LOOP>
</tbody>
</table>
</div>
</div>
</TMPL_IF>
</div>
</div>
<div class="buttons">
<!--
<button type="submit" class="btn btn-success">
<span class="fa fa-sign-in"></span>
<span trspan="search">Search</span>
</button>
-->
<a href="<TMPL_VAR NAME="PORTAL_URL">" class="btn btn-primary" role="button">
<span class="fa fa-home"></span>
<span trspan="goToPortal">Go to portal</span>
</a>
</div>
</form>
</div>
<TMPL_INCLUDE NAME="footer.tpl">

View File

@ -114,8 +114,8 @@ ok(
),
'POST checkuser'
);
my %attributes = map /<td class="text-left">(.+)?<\/td>/g, $res->[2]->[0];
ok( scalar keys %attributes == 16, 'Found 16 attributes' )
my %attributes = map /<td scope="row">(.+)?<\/td>/g, $res->[2]->[0];
ok( scalar keys %attributes == 17, 'Found 17 attributes' )
or print STDERR "Missing attributes -> " . scalar keys %attributes;
ok( $attributes{'_updateTime'} =~ /^\d{14}$/, 'Timestamp found' )
or print STDERR Dumper( \%attributes );
@ -182,8 +182,8 @@ ok(
),
'POST checkuser'
);
my %attributes2 = map /<td class="text-left">(.+)?<\/td>/g, $res->[2]->[0];
ok( scalar keys %attributes2 == 16, 'Found 16 attributes' )
my %attributes2 = map /<td scope="row">(.+)?<\/td>/g, $res->[2]->[0];
ok( scalar keys %attributes2 == 17, 'Found 17 attributes' )
or print STDERR "Missing attributes -> " . scalar keys %attributes2;
ok( $attributes2{'_updateTime'} =~ /^\d{14}$/, 'Timestamp found' )
or print STDERR Dumper( \%attributes2 );

View File

@ -110,7 +110,7 @@ ok( $res->[2]->[0] =~ m%<span trspan="checkUserComputeSession">%,
or explain( $res->[2]->[0], 'trspan="checkUserComputeSession"' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
m%<div class="alert alert-success"><div class="text-center"><b><span trspan="allowed"></span></b></div></div>%,
'Found trspan="allowed"'
) or explain( $res->[2]->[0], 'trspan="allowed"' );
ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
@ -118,23 +118,22 @@ ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
ok( $res->[2]->[0] =~ m%<span trspan="groups_sso">%,
'Found trspan="groups_sso"' )
or explain( $res->[2]->[0], 'trspan="groups_sso"' );
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
'Found trspan="attributes"' )
or explain( $res->[2]->[0], 'trspan="attributes"' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">rtyler</td>%, 'Found rtyler' )
ok( $res->[2]->[0] =~ m%: rtyler<br/>%, 'Found rtyler' )
or explain( $res->[2]->[0], 'Header Value: rtyler' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%, 'Found su' )
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
or explain( $res->[2]->[0], 'SSO Groups: su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
count(11);
$query =~ s/user=dwho/user=msmith/;
@ -153,7 +152,7 @@ ok(
);
ok(
$res->[2]->[0] =~
m%<div class="alert alert-danger"><b><span trspan="forbidden"></span></b></div>%,
m%<div class="alert alert-danger"><div class="text-center"><b><span trspan="forbidden"></span></b></div></div>%,
'Found trspan="forbidden"'
) or explain( $res->[2]->[0], 'trspan="forbidden"' );
count(2);

View File

@ -259,11 +259,9 @@ SKIP: {
ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%,
'Found trspan="checkUser"' )
or explain( $res->[2]->[0], 'trspan="checkUser"' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%,
'Found attribute uid' )
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found attribute uid' )
or explain( $res->[2]->[0], 'Attribute uid' );
ok( $res->[2]->[0] =~ m%<td class="text-left">french</td>%,
'Found value french' )
ok( $res->[2]->[0] =~ m%<td scope="row">french</td>%, 'Found value french' )
or explain( $res->[2]->[0], 'Value french' );
count(4);
@ -304,13 +302,11 @@ m%<div class="message message-positive alert"><span trspan="PE5"></span></div>%,
ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%,
'Found trspan="checkUser"' )
or explain( $res->[2]->[0], 'trspan="checkUser"' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%,
'Found attribute uid' )
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found attribute uid' )
or explain( $res->[2]->[0], 'Attribute uid' );
ok( $res->[2]->[0] =~ m%<td class="text-left">mail</td>%,
'Found attribute mail' )
ok( $res->[2]->[0] =~ m%<td scope="row">mail</td>%, 'Found attribute mail' )
or explain( $res->[2]->[0], 'Attribute mail' );
ok( $res->[2]->[0] =~ m%<td class="text-left">davros\@badguy.org</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">davros\@badguy.org</td>%,
'Found value davros@badguy.org' )
or explain( $res->[2]->[0], 'Value davros@badguy.org' );
count(5);

View File

@ -110,7 +110,7 @@ ok( $res->[2]->[0] =~ m%<span trspan="checkUserComputeSession">%,
or explain( $res->[2]->[0], 'trspan="checkUserComputeSession"' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
m%<div class="alert alert-success"><div class="text-center"><b><span trspan="allowed"></span></b></div></div>%,
'Found trspan="allowed"'
) or explain( $res->[2]->[0], 'trspan="allowed"' );
ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
@ -118,23 +118,22 @@ ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
ok( $res->[2]->[0] =~ m%<span trspan="groups_sso">%,
'Found trspan="groups_sso"' )
or explain( $res->[2]->[0], 'trspan="groups_sso"' );
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
'Found trspan="attributes"' )
or explain( $res->[2]->[0], 'trspan="attributes"' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">rtyler</td>%, 'Found rtyler' )
ok( $res->[2]->[0] =~ m%: rtyler%, 'Found rtyler' )
or explain( $res->[2]->[0], 'Header Value: rtyler' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%, 'Found su' )
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
or explain( $res->[2]->[0], 'SSO Groups: su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
count(11);
$query =~ s/user=dwho/user=msmith/;
@ -153,7 +152,7 @@ ok(
);
ok(
$res->[2]->[0] =~
m%<div class="alert alert-danger"><b><span trspan="forbidden"></span></b></div>%,
m%<div class="alert alert-danger"><div class="text-center"><b><span trspan="forbidden"></span></b></div></div>%,
'Found trspan="forbidden"'
) or explain( $res->[2]->[0], 'trspan="forbidden"' );
count(2);

View File

@ -21,6 +21,11 @@ my $client = LLNG::Manager::Test->new( {
checkUserIdRule => '$uid ne "msmith"',
checkUserDisplayPersistentInfo => 1,
checkUserDisplayEmptyValues => 1,
totp2fSelfRegistration => 1,
totp2fActivation => 1,
totp2fDigits => 6,
#hiddenAttributes => 'test',
}
}
);
@ -93,6 +98,92 @@ count(1);
$id = expectCookie($res);
expectRedirection( $res, 'http://auth.example.com/' );
# TOTP form
ok(
$res = $client->_get(
'/2fregisters',
cookie => "lemonldap=$id",
accept => 'text/html',
),
'Form registration'
);
expectRedirection( $res, qr#/2fregisters/totp$# );
ok(
$res = $client->_get(
'/2fregisters/totp',
cookie => "lemonldap=$id",
accept => 'text/html',
),
'Form registration'
);
ok( $res->[2]->[0] =~ /totpregistration\.(?:min\.)?js/, 'Found TOTP js' );
# JS query
ok(
$res = $client->_post(
'/2fregisters/totp/getkey', IO::String->new(''),
cookie => "lemonldap=$id",
length => 0,
),
'Get new key'
);
eval { $res = JSON::from_json( $res->[2]->[0] ) };
ok( not($@), 'Content is JSON' )
or explain( $res->[2]->[0], 'JSON content' );
my ( $key, $token );
ok( $key = $res->{secret}, 'Found secret' );
ok( $token = $res->{token}, 'Found token' );
$key = Convert::Base32::decode_base32($key);
# Post code
my $code;
ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ),
'Code' );
ok( $code =~ /^\d{6}$/, 'Code contains 6 digits' );
my $s = "code=$code&token=$token";
ok(
$res = $client->_post(
'/2fregisters/totp/verify',
IO::String->new($s),
length => length($s),
cookie => "lemonldap=$id",
),
'Post code'
);
eval { $res = JSON::from_json( $res->[2]->[0] ) };
ok( not($@), 'Content is JSON' )
or explain( $res->[2]->[0], 'JSON content' );
ok( $res->{result} == 1, 'Key is registered' );
count(12);
# Try to sign-in
$client->logout($id);
ok(
$res = $client->_post(
'/',
IO::String->new('user=dwho&password=dwho'),
length => 23,
accept => 'text/html',
),
'Auth query'
);
my ( $host, $url, $query ) = expectForm( $res, undef, '/totp2fcheck', 'token' );
# Generate TOTP with LLNG
my $totp = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 );
$query =~ s/code=/code=$code/;
ok(
$res = $client->_post(
'/totp2fcheck',
IO::String->new($query),
length => length($query),
),
'Post code'
);
$id = expectCookie($res);
# CheckUser form -> granted
# ------------------------
@ -104,20 +195,19 @@ ok(
),
'CheckUser form',
);
count(1);
count(3);
my ( $host, $url, $query ) =
expectForm( $res, undef, '/checkuser', 'user', 'url' );
ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%, 'Found trspan="checkUser"' )
or explain( $res->[2]->[0], 'trspan="checkUser"' );
count(1);
ok( $res->[2]->[0] =~ m%<td class="text-left">_user</td>%,
'Found attribute _user' )
ok( $res->[2]->[0] =~ m%<td scope="row">_user</td>%, 'Found attribute _user' )
or explain( $res->[2]->[0], 'Attribute _user' );
ok( $res->[2]->[0] =~ m%<td class="text-left">dwho</td>%, 'Found value dwho' )
ok( $res->[2]->[0] =~ m%<td scope="row">dwho</td>%, 'Found value dwho' )
or explain( $res->[2]->[0], 'Value dwho' );
count(2);
ok( $res->[2]->[0] !~ m%_2fDevices</td>%, '_2fDevices NOT Found!' )
or explain( $res->[2]->[0], 'Value _2fDevices' );
count(4);
$query =~ s/url=/url=http%3A%2F%2Ftest1.example.com/;
ok(
@ -138,15 +228,14 @@ ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%, 'Found trspan="checkUser"' )
or explain( $res->[2]->[0], 'trspan="checkUser"' );
count(2);
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">dwho</td>%, 'Found dwho' )
ok( $res->[2]->[0] =~ m%: dwho<br/>%, 'Found dwho' )
or explain( $res->[2]->[0], 'Header Value: dwho' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">dwho</td>%, 'Found dwho' )
ok( $res->[2]->[0] =~ m%<td scope="row">dwho</td>%, 'Found dwho' )
or explain( $res->[2]->[0], 'Macro Value dwho' );
count(3);
@ -189,7 +278,7 @@ ok(
expectForm( $res, undef, '/checkuser', 'user', 'url' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-danger"><b><span trspan="forbidden"></span></b></div>%,
m%<div class="alert alert-danger"><div class="text-center"><b><span trspan="forbidden"></span></b></div></div>%,
'Found trspan="forbidden"'
) or explain( $res->[2]->[0], 'trspan="forbidden"' );
count(2);
@ -222,7 +311,7 @@ ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%, 'Found trspan="checkUser"' )
or explain( $res->[2]->[0], 'trspan="checkUser"' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
m%<div class="alert alert-success"><div class="text-center"><b><span trspan="allowed"></span></b></div></div>%,
'Found trspan="allowed"'
) or explain( $res->[2]->[0], 'trspan="allowed"' );
ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
@ -230,27 +319,26 @@ ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
ok( $res->[2]->[0] =~ m%<span trspan="groups_sso">%,
'Found trspan="groups_sso"' )
or explain( $res->[2]->[0], 'trspan="groups_sso"' );
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
'Found trspan="attributes"' )
or explain( $res->[2]->[0], 'trspan="attributes"' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">rtyler</td>%, 'Found rtyler' )
ok( $res->[2]->[0] =~ m%: rtyler<br/>%, 'Found rtyler' )
or explain( $res->[2]->[0], 'Header Value: rtyler' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%, 'Found su' )
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
or explain( $res->[2]->[0], 'SSO Groups: su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
count(11);
my @c = ( $res->[2]->[0] =~ /<td class="align-middle">rtyler/gs );
ok( @c == 2, ' -> Two entries found' );
my @c = ( $res->[2]->[0] =~ /<td scope="row">rtyler<\/td>/gs );
ok( @c == 3, ' -> Three entries found' );
count(1);
# Request with short VH url & user
@ -282,7 +370,7 @@ ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%, 'Found trspan="checkUser"' )
or explain( $res->[2]->[0], 'trspan="checkUser"' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
m%<div class="alert alert-success"><div class="text-center"><b><span trspan="allowed"></span></b></div></div>%,
'Found trspan="allowed"'
) or explain( $res->[2]->[0], 'trspan="allowed"' );
ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
@ -290,23 +378,22 @@ ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
ok( $res->[2]->[0] =~ m%<span trspan="groups_sso">%,
'Found trspan="groups_sso"' )
or explain( $res->[2]->[0], 'trspan="groups_sso"' );
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
'Found trspan="attributes"' )
or explain( $res->[2]->[0], 'trspan="attributes"' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">rtyler</td>%, 'Found rtyler' )
ok( $res->[2]->[0] =~ m%: rtyler<br/>%, 'Found rtyler' )
or explain( $res->[2]->[0], 'Header Value: rtyler' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%, 'Found su' )
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
or explain( $res->[2]->[0], 'SSO Groups: su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
count(11);
# Request a forbidden identity

View File

@ -205,7 +205,7 @@ SKIP: {
or explain( $res->[2]->[0], 'trspan="checkUserMerged"' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
m%<div class="alert alert-success"><div class="text-center"><b><span trspan="allowed"></span></b></div></div>%,
'Found trspan="allowed"'
) or explain( $res->[2]->[0], 'trspan="allowed"' );
ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
@ -213,26 +213,24 @@ m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
ok( $res->[2]->[0] =~ m%<span trspan="groups_sso">%,
'Found trspan="groups_sso"' )
or explain( $res->[2]->[0], 'trspan="groups_sso"' );
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
'Found trspan="attributes"' )
or explain( $res->[2]->[0], 'trspan="attributes"' );
ok( $res->[2]->[0] =~ m%<td class="text-left">_userDB</td>%,
'Found _userDB' )
or explain( $res->[2]->[0], '_userDB' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%<td scope="row">_userDB</td>%, 'Found _userDB' )
or explain( $res->[2]->[0], 'Attribute Value: _userDB' );
ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">dwho</td>%, 'Found dwho' )
ok( $res->[2]->[0] =~ m%: dwho<br/>%, 'Found dwho' )
or explain( $res->[2]->[0], 'Header Value: dwho' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%, 'Found su' )
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
or explain( $res->[2]->[0], 'SSO Groups: su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
count(12);
$client->logout($id);

View File

@ -192,10 +192,10 @@ ok(
);
count(1);
ok( $res->[2]->[0] =~ m%<td class="align-middle">test_impersonation</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">test_impersonation</td>%,
'Found macro test_impersonation' )
or explain( $res->[2]->[0], 'test_impersonation' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">msmith/msmith</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">msmith/msmith</td>%,
'Found msmith/msmith' )
or explain( $res->[2]->[0], 'Found msmith/msmith' );
count(2);
@ -279,7 +279,7 @@ ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%, 'Found trspan="checkUser"' )
or explain( $res->[2]->[0], 'trspan="checkUser"' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
m%<div class="alert alert-success"><div class="text-center"><b><span trspan="allowed"></span></b></div></div>%,
'Found trspan="allowed"'
) or explain( $res->[2]->[0], 'trspan="allowed"' );
ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
@ -294,39 +294,37 @@ ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
'Found trspan="attributes"' )
or explain( $res->[2]->[0], 'trspan="attributes"' );
ok( $res->[2]->[0] =~ m%<td class="text-left">_userDB</td>%, 'Found _userDB' )
ok( $res->[2]->[0] =~ m%<td scope="row">_userDB</td>%, 'Found _userDB' )
or explain( $res->[2]->[0], '_userDB' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">dwho</td>%, 'Found dwho' )
ok( $res->[2]->[0] =~ m%: dwho%, 'Found dwho' )
or explain( $res->[2]->[0], 'Header Value: dwho' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">testPrefix_groups</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">testPrefix_groups</td>%,
'Found testPrefix_groups' )
or explain( $res->[2]->[0], 'testPrefix_groups' );
ok( $res->[2]->[0] =~ m%<td class="text-left">su; su_test; test_su</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">su; su_test; test_su</td>%,
'Found "su; su_test; test_su"' )
or explain( $res->[2]->[0], 'su' );
ok( $res->[2]->[0] =~ m%<td class="text-left">testPrefix_uid</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">testPrefix_uid</td>%,
'Found testPrefix_uid' )
or explain( $res->[2]->[0], 'testPrefix_groups' );
ok( $res->[2]->[0] =~ m%<td class="text-left">rtyler</td>%, 'Found rtyler' )
ok( $res->[2]->[0] =~ m%<td scope="row">rtyler</td>%, 'Found rtyler' )
or explain( $res->[2]->[0], 'su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">test_impersonation</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">test_impersonation</td>%,
'Found macro test_impersonation' )
or explain( $res->[2]->[0], 'test_impersonation' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">rtyler/dwho</td>%,
'Found rtyler/dwo' )
ok( $res->[2]->[0] =~ m%<td scope="row">rtyler/dwho</td>%, 'Found rtyler/dwo' )
or explain( $res->[2]->[0], 'Found rtyler/dwo' );
count(16);
my %attributes = map /<td class="text-left">(.+)?<\/td>/g, $res->[2]->[0];
ok( scalar keys %attributes == 33, 'Found 33 attributes' )
or print STDERR ( keys %attributes < 33 )
my %attributes = map /<td scope="row">(.+)?<\/td>/g, $res->[2]->[0];
ok( scalar keys %attributes == 35, 'Found 35 attributes' )
or print STDERR ( keys %attributes < 35 )
? "Missing attributes -> " . scalar keys %attributes
: "Too much attributes -> " . scalar keys %attributes;
ok( $attributes{'_auth'} eq 'Demo', '_auth' )

View File

@ -105,7 +105,7 @@ ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%, 'Found trspan="checkUser"' )
or explain( $res->[2]->[0], 'trspan="checkUser"' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
m%<div class="alert alert-success"><div class="text-center"><b><span trspan="allowed"></span></b></div></div>%,
'Found trspan="allowed"'
) or explain( $res->[2]->[0], 'trspan="allowed"' );
ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
@ -118,29 +118,25 @@ ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
'Found trspan="attributes"' )
or explain( $res->[2]->[0], 'trspan="attributes"' );
ok( $res->[2]->[0] =~ m%<td class="text-left">_userDB</td>%, 'Found _userDB' )
ok( $res->[2]->[0] =~ m%<td scope="row">_userDB</td>%, 'Found _userDB' )
or explain( $res->[2]->[0], '_userDB' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">dwho</td>%, 'Found dwho' )
ok( $res->[2]->[0] =~ m%: dwho<br/>%, 'Found dwho' )
or explain( $res->[2]->[0], 'Header Value: dwho' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%, 'Found su' )
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
or explain( $res->[2]->[0], 'SSO Groups: su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su_test</td>%,
'Found su_test' )
ok( $res->[2]->[0] =~ m%<div class="col">su_test</div>%, 'Found su_test' )
or explain( $res->[2]->[0], 'SSO Groups: su_test' );
ok( $res->[2]->[0] !~ m%<td class="align-middle">_test_</td>%,
'NOT found _test_' )
ok( $res->[2]->[0] !~ m%<div class="col">_test_</div>%, 'NOT found _test_' )
or explain( $res->[2]->[0], 'SSO Groups: _test_' );
ok( $res->[2]->[0] !~ m%<td class="align-middle">test_su</td>%,
'NOT found test_su' )
ok( $res->[2]->[0] !~ m%<div class="col">test_su</td>%, 'NOT found test_su' )
or explain( $res->[2]->[0], 'SSO Groups: test_su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
count(15);
$client->logout($id);

View File

@ -106,7 +106,7 @@ ok( $res->[2]->[0] =~ m%<span trspan="checkUserMerged">%,
or explain( $res->[2]->[0], 'trspan="checkUserMerged"' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
m%<div class="alert alert-success"><div class="text-center"><b><span trspan="allowed"></span></b></div></div>%,
'Found trspan="allowed"'
) or explain( $res->[2]->[0], 'trspan="allowed"' );
ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
@ -114,42 +114,37 @@ ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
ok( $res->[2]->[0] =~ m%<span trspan="groups_sso">%,
'Found trspan="groups_sso"' )
or explain( $res->[2]->[0], 'trspan="groups_sso"' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%,
'Found SSO group "su"' )
or explain( $res->[2]->[0], 'Found SSOO group "su"' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su_test</td>%,
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found SSO group "su"' )
or explain( $res->[2]->[0], 'Found SSO group "su"' );
ok( $res->[2]->[0] =~ m%<div class="col">su_test</div>%,
'Found SSO group "su_test"' )
or explain( $res->[2]->[0], 'Found SSO group "su_test"' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">test_su</td>%,
ok( $res->[2]->[0] =~ m%<div class="col">test_su</div>%,
'Found SSO group "test_su"' )
or explain( $res->[2]->[0], 'Found SSO group "test_su"' );
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
'Found trspan="attributes"' )
or explain( $res->[2]->[0], 'trspan="attributes"' );
ok( $res->[2]->[0] =~ m%<td class="text-left">_userDB</td>%, 'Found _userDB' )
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%<td scope="row">_userDB</td>%, 'Found _userDB' )
or explain( $res->[2]->[0], '_userDB' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">dwho</td>%, 'Found dwho' )
ok( $res->[2]->[0] =~ m%: dwho<br/>%, 'Found dwho' )
or explain( $res->[2]->[0], 'Header Value: dwho' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%, 'Found su' )
ok( $res->[2]->[0] =~ m%<div class="col">su</div>%, 'Found su' )
or explain( $res->[2]->[0], 'SSO Groups: su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su_test</td>%,
'Found su_test' )
ok( $res->[2]->[0] =~ m%<div class="col">su_test</div>%, 'Found su_test' )
or explain( $res->[2]->[0], 'SSO Groups: su_test' );
ok( $res->[2]->[0] !~ m%<td class="align-middle">_test_</td>%,
'NOT found _test_' )
ok( $res->[2]->[0] !~ m%<div class="col">_test_</div>%, 'NOT found _test_' )
or explain( $res->[2]->[0], 'SSO Groups: _test_' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">test_su</td>%,
'Found test_su' )
ok( $res->[2]->[0] =~ m%<div class="col">test_su</div>%, 'Found test_su' )
or explain( $res->[2]->[0], 'SSO Groups: test_su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%, 'Found uid' )
ok( $res->[2]->[0] =~ m%<td scope="row">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
count(18);

View File

@ -189,10 +189,10 @@ ok(
);
count(1);
ok( $res->[2]->[0] =~ m%<td class="align-middle">test_impersonation</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">test_impersonation</td>%,
'Found macro test_impersonation' )
or explain( $res->[2]->[0], 'test_impersonation' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">msmith/msmith</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">msmith/msmith</td>%,
'Found msmith/msmith' )
or explain( $res->[2]->[0], 'Found msmith/msmith' );
count(2);
@ -277,7 +277,7 @@ ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%, 'Found trspan="checkUser"' )
or explain( $res->[2]->[0], 'trspan="checkUser"' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
m%<div class="alert alert-success"><div class="text-center"><b><span trspan="allowed"></span></b></div></div>%,
'Found trspan="allowed"'
) or explain( $res->[2]->[0], 'trspan="allowed"' );
ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
@ -292,38 +292,36 @@ ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
'Found trspan="attributes"' )
or explain( $res->[2]->[0], 'trspan="attributes"' );
ok( $res->[2]->[0] =~ m%<td class="text-left">_userDB</td>%, 'Found _userDB' )
ok( $res->[2]->[0] =~ m%<td scope="row">_userDB</td>%, 'Found _userDB' )
or explain( $res->[2]->[0], '_userDB' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
ok( $res->[2]->[0] =~ m%Auth-User: %, 'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">dwho</td>%, 'Found dwho' )
ok( $res->[2]->[0] =~ m%: dwho<br/>%, 'Found dwho' )
or explain( $res->[2]->[0], 'Header Value: dwho' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">testPrefix_groups</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">testPrefix_groups</td>%,
'Found testPrefix_groups' )
or explain( $res->[2]->[0], 'testPrefix_groups' );
ok( $res->[2]->[0] =~ m%<td class="text-left">su; su_test; test_su</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">su; su_test; test_su</td>%,
'Found "su; su_test; test_su"' )
or explain( $res->[2]->[0], 'su' );
ok( $res->[2]->[0] =~ m%<td class="text-left">testPrefix_uid</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">testPrefix_uid</td>%,
'Found testPrefix_uid' )
or explain( $res->[2]->[0], 'testPrefix_groups' );
ok( $res->[2]->[0] =~ m%<td class="text-left">rtyler</td>%, 'Found rtyler' )
ok( $res->[2]->[0] =~ m%<td scope="row">rtyler</td>%, 'Found rtyler' )
or explain( $res->[2]->[0], 'su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">test_impersonation</td>%,
ok( $res->[2]->[0] =~ m%<td scope="row">test_impersonation</td>%,
'Found macro test_impersonation' )
or explain( $res->[2]->[0], 'test_impersonation' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">rtyler/dwho</td>%,
'Found rtyler/dwo' )
ok( $res->[2]->[0] =~ m%<td scope="row">rtyler/dwho</td>%, 'Found rtyler/dwo' )
or explain( $res->[2]->[0], 'Found rtyler/dwo' );
count(16);
my %attributes = map /<td class="text-left">(.+)?<\/td>/g, $res->[2]->[0];
ok( keys %attributes == 31, 'Found 31 attributes' )
my %attributes = map /<td scope="row">(.+)?<\/td>/g, $res->[2]->[0];
ok( keys %attributes == 33, 'Found 33 attributes' )
or print STDERR "Missing attributes -> " . scalar %attributes;
ok( $attributes{'_auth'} eq 'Demo', '_auth' )
or print STDERR Dumper( \%attributes );

View File

@ -0,0 +1,165 @@
use Test::More;
use strict;
use IO::String;
require 't/test-lib.pm';
my $maintests = 20;
my $file = '20190616_dwho_Tm90aWZpY2F0aW9uX1NG.json';
SKIP: {
eval { require Convert::Base32 };
if ($@) {
skip 'Convert::Base32 is missing', $maintests;
}
require Lemonldap::NG::Common::TOTP;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
totp2fSelfRegistration => 1,
totp2fActivation => 1,
totp2fTTL => 2,
sfRemovedMsgRule => '$uid eq "dwho"',
sfRemovedUseNotif => 1,
portalMainLogo => 'common/logos/logo_llng_old.png',
notification => 1,
templatesDir => 'site/templates/',
notificationStorage => 'File',
notificationStorageOptions => { dirName => 't' },
oldNotifFormat => 0,
}
}
);
my $res;
# Try to authenticate
# -------------------
ok(
$res = $client->_post(
'/',
IO::String->new('user=dwho&password=dwho'),
length => 23
),
'Auth query'
);
my $id = expectCookie($res);
# TOTP form
ok(
$res = $client->_get(
'/2fregisters',
cookie => "lemonldap=$id",
accept => 'text/html',
),
'Form registration'
);
expectRedirection( $res, qr#/2fregisters/totp$# );
ok(
$res = $client->_get(
'/2fregisters/totp',
cookie => "lemonldap=$id",
accept => 'text/html',
),
'Form registration'
);
ok( $res->[2]->[0] =~ /totpregistration\.(?:min\.)?js/, 'Found TOTP js' );
ok(
$res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
'Found custom Main Logo'
) or print STDERR Dumper( $res->[2]->[0] );
# JS query
ok(
$res = $client->_post(
'/2fregisters/totp/getkey', IO::String->new(''),
cookie => "lemonldap=$id",
length => 0,
),
'Get new key'
);
eval { $res = JSON::from_json( $res->[2]->[0] ) };
ok( not($@), 'Content is JSON' )
or explain( $res->[2]->[0], 'JSON content' );
my ( $key, $token );
ok( $key = $res->{secret}, 'Found secret' );
ok( $token = $res->{token}, 'Found token' );
$key = Convert::Base32::decode_base32($key);
# Post code
my $code;
ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ),
'Code' );
ok( $code =~ /^\d{6}$/, 'Code contains 6 digits' );
my $s = "code=$code&token=$token&TOTPName=myTOTP";
ok(
$res = $client->_post(
'/2fregisters/totp/verify',
IO::String->new($s),
length => length($s),
cookie => "lemonldap=$id",
),
'Post code'
);
eval { $res = JSON::from_json( $res->[2]->[0] ) };
ok( not($@), 'Content is JSON' )
or explain( $res->[2]->[0], 'JSON content' );
ok( $res->{result} == 1, 'Key is registered' );
# Try to sign-in
$client->logout($id);
ok(
$res = $client->_post(
'/',
IO::String->new('user=dwho&password=dwho'),
length => 23,
accept => 'text/html',
),
'Auth query'
);
my ( $host, $url, $query ) =
expectForm( $res, undef, '/totp2fcheck', 'token' );
ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ),
'Code' );
$query =~ s/code=/code=$code/;
ok(
$res = $client->_post(
'/totp2fcheck', IO::String->new($query),
length => length($query),
),
'Post code'
);
$id = expectCookie($res);
$client->logout($id);
diag 'Waiting';
sleep 3;
# Try to sign-in
ok(
$res = $client->_post(
'/',
IO::String->new('user=dwho&password=dwho'),
length => 23,
accept => 'text/html',
),
'Auth query'
);
expectOK($res);
ok(
$res->[2]->[0] =~
qr%<input type="hidden" name="reference1x1" value="RemoveSF">%,
'Notification reference found'
) or print STDERR Dumper( $res->[2]->[0] );
ok(
$res->[2]->[0] =~
qr%<p class="notifText">1 expired second factor\(s\) has/have been removed!</p>%,
'Notification message found'
) or print STDERR Dumper( $res->[2]->[0] );
$id = expectCookie($res);
$client->logout($id);
}
count($maintests);
system 'rm -f t/*_dwho_UmVtb3ZlU0Y=.json';
clean_sessions();
done_testing( count() );

View File

@ -4,6 +4,7 @@ use IO::String;
require 't/test-lib.pm';
my $maintests = 20;
my $file = '20190616_dwho_Tm90aWZpY2F0aW9uX1NG.json';
SKIP: {
eval { require Convert::Base32 };
@ -14,12 +15,18 @@ SKIP: {
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
totp2fSelfRegistration => 1,
totp2fActivation => 1,
totp2fTTL => 2,
sfRemovedMsg => '$uid eq "dwho"',
portalMainLogo => 'common/logos/logo_llng_old.png',
logLevel => 'error',
totp2fSelfRegistration => 1,
totp2fActivation => 1,
totp2fTTL => 2,
sfRemovedMsgRule => '$uid eq "dwho"',
sfRemovedUseNotif => 1,
portalMainLogo => 'common/logos/logo_llng_old.png',
notification => 1,
templatesDir => 'site/templates/',
notificationStorage => 'File',
notificationStorageOptions => { dirName => 't' },
oldNotifFormat => 1,
}
}
);
@ -140,15 +147,19 @@ SKIP: {
expectOK($res);
ok(
$res->[2]->[0] =~
qr%<h3 trspan="oneExpired2Fremoved">oneExpired2Fremoved</h3>%,
'Found expired 2F message'
qr%<input type="hidden" name="reference1x1" value="RemoveSF">%,
'Notification reference found'
) or print STDERR Dumper( $res->[2]->[0] );
my $c = getCookies($res);
ok( not(%$c), 'No cookie' );
ok(
$res->[2]->[0] =~
qr%<p class="notifText">1 expired second factor\(s\) has/have been removed!</p>%,
'Notification message found'
) or print STDERR Dumper( $res->[2]->[0] );
$id = expectCookie($res);
$client->logout($id);
}
count($maintests);
system 'rm -f t/*_dwho_UmVtb3ZlU0Y=.xml';
clean_sessions();
done_testing( count() );

View File

@ -20,7 +20,7 @@ SKIP: {
portalMainLogo => 'common/logos/logo_llng_old.png',
totp2fTTL => 2,
u2fTTL => 2,
sfRemovedMsg => 1,
sfRemovedMsgRule => 1,
}
}
);