Merge branch 'v2.0'
This commit is contained in:
commit
d67f32d2b2
5
COPYING
5
COPYING
|
@ -115,6 +115,11 @@ License: CC-3
|
|||
Comment: This work, "star1.png", is a derivative of
|
||||
"Golden star with red border.png" by ANGELUS, under CC-BYSA-3.0.
|
||||
|
||||
Files: lemonldap-ng-portal/site/htdocs/static/common/icons/notifsExplorer.png
|
||||
Copyright: Various artists
|
||||
License: CC-BY-NC-ND-3.0 or GFDL-1.3
|
||||
Comment: downloaded from https://commons.wikimedia.org
|
||||
|
||||
Files: lemonldap-ng-portal/site/htdocs/static/common/icons/decryptValue.png
|
||||
Copyright: Christophe Maudoux <chrmdx@gmail.com>
|
||||
License: CC-3
|
||||
|
|
5
Makefile
5
Makefile
|
@ -1130,6 +1130,11 @@ tidy: clean
|
|||
find lemon*/ -type f \( -name '*.pm' -or -name '*.pl' -or -name '*.fcgi' -or -name '*.t' \) -print -exec perltidy -se -b {} \; ; \
|
||||
else echo "Wrong perltidy version, please install Perl::Tidy@20181120" ; exit 1 ;\
|
||||
fi
|
||||
for f in `find lemon*/ -type f \( -name '*.pm' -or -name '*.pl' -or -name '*.fcgi' -or -name '*.t' \)`; do \
|
||||
echo -n $$f; \
|
||||
perltidy -se -b $$f; \
|
||||
echo; \
|
||||
done
|
||||
find lemon*/ -name '*.bak' -delete
|
||||
$(MAKE) json
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
RewriteCond "%{REQUEST_URI}" "!^/(?:(?:static|javascript|favicon).*|.*\.fcgi(?:/.*)?)$"
|
||||
RewriteRule "^/(.+)$" "/index.fcgi/$1" [PT]
|
||||
|
||||
# Uncomment this to mitigate memory leaks when using Perl 5.16
|
||||
# FcgidMaxRequestsPerProcess 500
|
||||
|
||||
# Note that Content-Security-Policy header is generated by portal itself
|
||||
<Files *.fcgi>
|
||||
SetHandler fcgid-script
|
||||
|
|
|
@ -35,6 +35,9 @@
|
|||
RewriteCond "%{REQUEST_URI}" "!^/(?:(?:static|javascript|favicon).*|.*\.fcgi(?:/.*)?)$"
|
||||
RewriteRule "^/(.+)$" "/index.fcgi/$1" [PT]
|
||||
|
||||
# Uncomment this to mitigate memory leaks when using Perl 5.16
|
||||
# FcgidMaxRequestsPerProcess 500
|
||||
|
||||
# Note that Content-Security-Policy header is generated by portal itself
|
||||
<Files *.fcgi>
|
||||
SetHandler fcgid-script
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
RewriteCond "%{REQUEST_URI}" "!^/(?:(?:static|javascript|favicon).*|.*\.fcgi(?:/.*)?)$"
|
||||
RewriteRule "^/(.+)$" "/index.fcgi/$1" [PT]
|
||||
|
||||
# Uncomment this to mitigate memory leaks when using Perl 5.16
|
||||
# FcgidMaxRequestsPerProcess 500
|
||||
|
||||
# Note that Content-Security-Policy header is generated by portal itself
|
||||
<Files *.fcgi>
|
||||
SetHandler fcgid-script
|
||||
|
|
|
@ -43,7 +43,9 @@ Build-Depends-Indep: libapache-session-perl <!nocheck>,
|
|||
libstring-random-perl <!nocheck>,
|
||||
libtest-mockobject-perl <!nocheck>,
|
||||
libtest-pod-perl <!nocheck>,
|
||||
libtest-output-perl <!nocheck>,
|
||||
libtext-unidecode-perl <!nocheck>,
|
||||
libtime-fake-perl <!nocheck>,
|
||||
libunicode-string-perl <!nocheck>,
|
||||
liburi-perl <!nocheck>,
|
||||
libwww-perl <!nocheck>,
|
||||
|
|
|
@ -21,3 +21,14 @@ GROUP=__GROUP__
|
|||
#ENGINE=FCGI::EV
|
||||
#ENGINE=FCGI::Engine
|
||||
#ENGINE=FCGI::Engine::ProcManager
|
||||
|
||||
# Process recycling
|
||||
# When running with Perl 5.16, you might encounter memory
|
||||
# leaks when running the FastCGI server
|
||||
# By default, we restart each worker after 500 requests to mitigate
|
||||
# the leak. You can finetune these settings here.
|
||||
# See also FCGI::ProcManager::Constrained(3)
|
||||
|
||||
PM_MAX_REQUESTS=500
|
||||
#PM_SIZECHECK_NUM_REQUESTS=10
|
||||
#PM_MAX_SIZE=100000
|
||||
|
|
|
@ -10,9 +10,9 @@ use Lemonldap::NG::Handler::Main::Reload;
|
|||
our $VERSION = '2.1.0';
|
||||
|
||||
our (
|
||||
$foreground, $engine, $nproc, $pidFile,
|
||||
$socket, $user, $listen, $group,
|
||||
$customFunctionsFile, %plackOptions
|
||||
$foreground, $engine, $nproc, $pidFile,
|
||||
$socket, $user, $listen, $group,
|
||||
$procmanager, $customFunctionsFile, %plackOptions
|
||||
);
|
||||
my %_apps;
|
||||
|
||||
|
@ -29,6 +29,9 @@ $user ||= $ENV{USER};
|
|||
$group ||= $ENV{GROUP};
|
||||
$customFunctionsFile ||= $ENV{CUSTOM_FUNCTIONS_FILE};
|
||||
|
||||
# If the user specified any PM_ constrains, run under ::Constrained
|
||||
$procmanager = "FCGI::ProcManager::Constrained" if grep /^PM_/, keys %ENV;
|
||||
|
||||
#Getopt::Long::Configure ("bundling_values");
|
||||
GetOptions(
|
||||
'foreground' => \$foreground,
|
||||
|
@ -93,7 +96,7 @@ my %builder = (
|
|||
die "Unable to load $_[0]->{SCRIPT_FILENAME}";
|
||||
}
|
||||
return $_apps{$script}->(@_);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -126,6 +129,7 @@ $server->parse_options(
|
|||
'--proc-title' => 'llng-fastcgi-server',
|
||||
( $foreground ? () : '--daemonize' ),
|
||||
'--no-default-middleware',
|
||||
( $procmanager ? ( '--manager', $procmanager ) : () ),
|
||||
%plackOptions,
|
||||
);
|
||||
|
||||
|
@ -216,14 +220,10 @@ Plack::Handler engine, default to FCGI (see below)
|
|||
|
||||
=item --plackOptions:
|
||||
|
||||
other options to pass to Plack. This multi-valued parameter must have
|
||||
"key=value" values.
|
||||
other options to pass to the Plack handler. This multi-valued parameter must
|
||||
have "key=value" values.
|
||||
|
||||
Example to use L<FCGI::ProcManager::Constrained> instead of default FCGI manager
|
||||
(L<FCGI::ProcManager>):
|
||||
|
||||
llng-fastcgi-server -u nobody -g nobody -s /run/llng.sock -e FCGI -n 10 \
|
||||
--plackOptions manager=FCGI::ProcManager::Constrained
|
||||
See Plack::Handler::FCGI for a list of options for the default FCGI engine
|
||||
|
||||
=back
|
||||
|
||||
|
@ -236,22 +236,6 @@ other engines can be used:
|
|||
|
||||
It uses L<FCGI::ProcManager> as manager. Other managers:
|
||||
|
||||
=over
|
||||
|
||||
=item L<FCGI::ProcManager::Constrained>
|
||||
|
||||
Example to launch it:
|
||||
|
||||
llng-fastcgi-server -u nobody -g nobody -s /run/llng.sock -e FCGI -n 10 \
|
||||
--plackOptions manager=FCGI::ProcManager::Constrained
|
||||
|
||||
You can then set environment values (in /etc/default/llng-fastcgi-server file
|
||||
for example):
|
||||
|
||||
PM_MAX_REQUESTS=10000
|
||||
PM_SIZECHECK_NUM_REQUESTS=100
|
||||
PM_MAX_SIZE=300000
|
||||
|
||||
=item L<FCGI::ProcManager::Dynamic>
|
||||
|
||||
llng-fastcgi-server -u nobody -g nobody -s /run/llng.sock -e FCGI -n 10 \
|
||||
|
|
|
@ -107,6 +107,7 @@ sub store {
|
|||
$req->content( to_json($conf) );
|
||||
$req->header( 'Content-Type' => 'application/json' );
|
||||
my $resp = $self->ua->request($req);
|
||||
|
||||
if ( $resp->is_success ) {
|
||||
my $res;
|
||||
eval { $res = from_json( $resp->content, { allow_nonref => 1 } ) };
|
||||
|
|
|
@ -41,7 +41,7 @@ sub available {
|
|||
closedir D;
|
||||
@conf =
|
||||
sort { $a <=> $b }
|
||||
map { /lmConf-(\d+)\.yaml/ ? ( $1 + 0 ) : () } @conf;
|
||||
map { /lmConf-(\d+)\.yaml/ ? ( $1 + 0 ) : () } @conf;
|
||||
return @conf;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(?:S(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar|Macro)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node))|penIdExportedVars)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option|Macro)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars|fExtra)|c(?:as(?:A(?:ppMetaData(?:(?:ExportedVar|Option|Macro)s|Node)|ttributes)|S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions))|(?:ustom(?:Plugins|Add)Param|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|fRemovedUseNotif|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|AllowOffline|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:Display(?:Re(?:setPassword|gister)|GeneratePassword|PasswordPolicy)|ErrorOn(?:ExpiredSession|MailNotFound)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|RequireOldPassword|ForceAuthn|AntiFrame)|roxyUseSoap)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:User(?:Display(?:PersistentInfo|EmptyValues))?|State|XSS)|o(?:ntextSwitchingStopWithLogout|mpactConf|rsEnabled)|da)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|no(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?)?|y(?:Deleted|Other))|AjaxHook)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|re(?:st(?:(?:Session|Config)Server|ExportSecretKeys)|freshSessions)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|d(?:isablePersistentStorage|biDynamicHashEnabled)|br(?:owsersDontStorePassword|uteForceProtection)|(?:(?:globalLogout|active)Tim|wsdlServ)er|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs))$/;
|
||||
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|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|AllowOffline|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:Display(?:Re(?:setPassword|gister)|GeneratePassword|PasswordPolicy)|ErrorOn(?:ExpiredSession|MailNotFound)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|RequireOldPassword|ForceAuthn|AntiFrame)|roxyUseSoap)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:User(?:Display(?:PersistentInfo|EmptyValues))?|State|XSS)|o(?:ntextSwitchingStopWithLogout|mpactConf|rsEnabled)|da)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|no(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|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)|br(?:uteForceProtection(?:IncrementalTempo)?|owsersDontStorePassword)|re(?:st(?:(?:Session|Config)Server|ExportSecretKeys)|freshSessions)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|d(?:isablePersistentStorage|biDynamicHashEnabled)|g(?:roupsBeforeMacros|lobalLogoutTimer)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|(?:activeTim|wsdlServ)er|krb(?:RemoveDomain|ByJs))$/;
|
||||
|
||||
our @sessionTypes = ( 'remoteGlobal', 'global', 'localSession', 'persistent', 'saml', 'oidc', 'cas' );
|
||||
|
||||
|
|
|
@ -19,8 +19,10 @@ sub defaultValues {
|
|||
'authentication' => 'Demo',
|
||||
'available2F' => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey,Radius',
|
||||
'available2FSelfRegistration' => 'TOTP,U2F,Yubikey',
|
||||
'bruteForceProtectionLockTimes' => '5 15 60 300 600',
|
||||
'bruteForceProtectionMaxAge' => 300,
|
||||
'bruteForceProtectionMaxFailed' => 3,
|
||||
'bruteForceProtectionMaxLockTime' => 900,
|
||||
'bruteForceProtectionTempo' => 30,
|
||||
'captcha_mail_enabled' => 1,
|
||||
'captcha_register_enabled' => 1,
|
||||
|
@ -172,6 +174,7 @@ sub defaultValues {
|
|||
'notificationServerPOST' => 1,
|
||||
'notificationServerSentAttributes' =>
|
||||
'uid reference date title subtitle text check',
|
||||
'notificationsMaxRetrieve' => 3,
|
||||
'notificationStorage' => 'File',
|
||||
'notificationStorageOptions' => {
|
||||
'dirName' => '/var/lib/lemonldap-ng/notifications'
|
||||
|
@ -220,6 +223,8 @@ sub defaultValues {
|
|||
'passwordPolicyMinSize' => 0,
|
||||
'passwordPolicyMinUpper' => 0,
|
||||
'passwordResetAllowedRetries' => 3,
|
||||
'persistentSessionAttributes' =>
|
||||
'_loginHistory _2fDevices notification_',
|
||||
'port' => -1,
|
||||
'portal' => 'http://auth.example.com/',
|
||||
'portalAntiFrame' => 1,
|
||||
|
@ -321,6 +326,7 @@ sub defaultValues {
|
|||
'slaveExportedVars' => {},
|
||||
'SMTPServer' => '',
|
||||
'SMTPTLS' => '',
|
||||
'soapProxyUrn' => 'urn:Lemonldap/NG/Common/PSGI/SOAPService',
|
||||
'SSLAuthnLevel' => 5,
|
||||
'SSLVar' => 'SSL_CLIENT_S_DN_Email',
|
||||
'SSLVarIf' => {},
|
||||
|
|
|
@ -198,8 +198,8 @@ sub virtualHosts {
|
|||
# If rule contains a comment or an AuthLevel, split them
|
||||
if ( $query eq 'locationRules' ) {
|
||||
$res->{comment} = '';
|
||||
$res->{level} = '';
|
||||
$res->{level} = $1 if ( $r =~ s/\(\?#AuthnLevel=(-?\d+)\)// );
|
||||
$res->{level} = '';
|
||||
$res->{level} = $1 if ( $r =~ s/\(\?#AuthnLevel=(-?\d+)\)// );
|
||||
if ( $r =~ s/\(\?#(.*?)\)// ) {
|
||||
$res->{title} = $res->{comment} = $1;
|
||||
}
|
||||
|
@ -710,9 +710,9 @@ sub combModules {
|
|||
my $res = [];
|
||||
foreach my $mod ( keys %$val ) {
|
||||
my $tmp;
|
||||
$tmp->{title} = $mod;
|
||||
$tmp->{id} = "combModules/$mod";
|
||||
$tmp->{type} = 'cmbModule';
|
||||
$tmp->{title} = $mod;
|
||||
$tmp->{id} = "combModules/$mod";
|
||||
$tmp->{type} = 'cmbModule';
|
||||
$tmp->{data}->{$_} = $val->{$mod}->{$_} foreach (qw(type for));
|
||||
my $over = $val->{$mod}->{over} // {};
|
||||
$tmp->{data}->{over} = [ map { [ $_, $over->{$_} ] } keys %$over ];
|
||||
|
@ -786,8 +786,8 @@ sub metadata {
|
|||
}
|
||||
|
||||
# Find next and previous conf
|
||||
my @a = $self->confAcc->available;
|
||||
my $id = -1;
|
||||
my @a = $self->confAcc->available;
|
||||
my $id = -1;
|
||||
my ($ind) = map { $id++; $_ == $res->{cfgNum} ? ($id) : () } @a;
|
||||
if ($ind) { $res->{prev} = $a[ $ind - 1 ]; }
|
||||
if ( defined $ind and $ind < $#a ) {
|
||||
|
|
|
@ -166,9 +166,9 @@ sub serviceToXML {
|
|||
|
||||
foreach (@param_assertion) {
|
||||
my @_tab = split( /;/, $self->getValue( $_, $conf ) );
|
||||
$template->param( $_ . 'Default', $_tab[0] ? 'true' : 'false' );
|
||||
$template->param( $_ . 'Index', $_tab[1] );
|
||||
$template->param( $_ . 'Binding', $_tab[2] );
|
||||
$template->param( $_ . 'Default', $_tab[0] ? 'true' : 'false' );
|
||||
$template->param( $_ . 'Index', $_tab[1] );
|
||||
$template->param( $_ . 'Binding', $_tab[2] );
|
||||
$template->param( $_ . 'Location', $_tab[3] );
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,11 @@ sub import {
|
|||
}
|
||||
}
|
||||
|
||||
has extension => (
|
||||
is => 'rw',
|
||||
default => 'json'
|
||||
);
|
||||
|
||||
has notifField => (
|
||||
is => 'rw',
|
||||
builder => sub {
|
||||
|
@ -31,6 +36,14 @@ has notifField => (
|
|||
}
|
||||
);
|
||||
|
||||
sub BUILD {
|
||||
my $self = shift;
|
||||
$self->extension('xml') if $self->p->conf->{oldNotifFormat};
|
||||
$self->logger->debug( 'Use extension "'
|
||||
. $self->extension
|
||||
. '" to store notification files' );
|
||||
}
|
||||
|
||||
sub getNotifications {
|
||||
my ( $self, $uid ) = @_;
|
||||
my $forAll = $self->get( $self->conf->{notificationWildcard} );
|
||||
|
@ -49,4 +62,17 @@ sub getNotifications {
|
|||
}
|
||||
}
|
||||
|
||||
sub getAcceptedNotifs {
|
||||
my ( $self, $uid, $ref ) = @_;
|
||||
my $forAll =
|
||||
$self->getAccepted( $self->conf->{notificationWildcard}, $ref );
|
||||
my $forUser = $self->getAccepted( $uid, $ref );
|
||||
if ( $forUser and $forAll ) {
|
||||
return { %$forUser, %$forAll };
|
||||
}
|
||||
else {
|
||||
return ( ( $forUser ? $forUser : $forAll ), $forUser );
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -92,6 +92,38 @@ sub get {
|
|||
return $result;
|
||||
}
|
||||
|
||||
# Returns accepted notifications corresponding to the user $uid.
|
||||
# If $ref is set, returns only notification corresponding to this reference.
|
||||
sub getAccepted {
|
||||
my ( $self, $uid, $ref ) = @_;
|
||||
return () unless ($uid);
|
||||
$self->_execute(
|
||||
"SELECT * FROM "
|
||||
. $self->dbiTable
|
||||
. " WHERE done IS NOT NULL AND uid=?"
|
||||
. ( $ref ? " AND ref=?" : '' )
|
||||
. " ORDER BY date",
|
||||
$uid,
|
||||
( $ref ? $ref : () )
|
||||
) or return ();
|
||||
my $result;
|
||||
while ( my $h = $self->sth->fetchrow_hashref() ) {
|
||||
|
||||
# Get XML message
|
||||
my $xml = $h->{xml};
|
||||
|
||||
# Decode it to get the correct uncoded string
|
||||
Encode::from_to( $xml, "utf8", "iso-8859-1", Encode::FB_CROAK );
|
||||
|
||||
# Store message in result
|
||||
my $identifier =
|
||||
&getIdentifier( $self, $h->{uid}, $h->{ref}, $h->{date} );
|
||||
$result->{$identifier} = $xml;
|
||||
}
|
||||
$self->logger->warn( $self->sth->err() ) if ( $self->sth->err() );
|
||||
return $result;
|
||||
}
|
||||
|
||||
## @method hashref getAll()
|
||||
# Return all pending notifications.
|
||||
# @return hashref where keys are internal reference and values are hashref with
|
||||
|
|
|
@ -14,11 +14,8 @@ our $VERSION = '2.1.0';
|
|||
|
||||
extends 'Lemonldap::NG::Common::Notifications';
|
||||
|
||||
our $ext = 'json';
|
||||
|
||||
sub import {
|
||||
shift;
|
||||
$ext = 'xml' if ( $_[0] eq 'XML' );
|
||||
return Lemonldap::NG::Common::Notifications->import(@_);
|
||||
}
|
||||
|
||||
|
@ -38,6 +35,7 @@ has fileNameSeparator => ( is => 'rw', default => '_' );
|
|||
# If $ref is set, returns only notification corresponding to this reference.
|
||||
sub get {
|
||||
my ( $self, $uid, $ref ) = @_;
|
||||
my $ext = $self->extension;
|
||||
return () unless ($uid);
|
||||
my $fns = $self->{fileNameSeparator};
|
||||
my $identifier = &getIdentifier( $self, $uid, $ref );
|
||||
|
@ -58,12 +56,37 @@ sub get {
|
|||
return $files;
|
||||
}
|
||||
|
||||
# Returns accepted notification corresponding to the user $uid.
|
||||
# If $ref is set, returns only notification corresponding to this reference.
|
||||
sub getAccepted {
|
||||
my ( $self, $uid, $ref ) = @_;
|
||||
return () unless ($uid);
|
||||
my $fns = $self->{fileNameSeparator};
|
||||
my $identifier = &getIdentifier( $self, $uid, $ref );
|
||||
|
||||
opendir D, $self->{dirName};
|
||||
my @notif = grep /^\d{8}${fns}${identifier}\S*\.done$/, readdir(D);
|
||||
closedir D;
|
||||
|
||||
my $files;
|
||||
foreach my $file (@notif) {
|
||||
unless ( open F, '<', $self->{dirName} . "/$file" ) {
|
||||
$self->logger->error(
|
||||
"Unable to read notification $self->{dirName}/$file");
|
||||
next;
|
||||
}
|
||||
$files->{$file} = join( '', <F> );
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
## @method hashref getAll()
|
||||
# Return all pending notifications.
|
||||
# @return hashref where keys are internal reference and values are hashref with
|
||||
# keys date, uid, ref and condition.
|
||||
sub getAll {
|
||||
my $self = shift;
|
||||
my $ext = $self->extension;
|
||||
opendir D, $self->{dirName};
|
||||
my @notif;
|
||||
my $fns = $self->{fileNameSeparator};
|
||||
|
@ -89,6 +112,7 @@ sub getAll {
|
|||
# keys date, uid, ref and condition.
|
||||
sub getExisting {
|
||||
my $self = shift;
|
||||
my $ext = $self->extension;
|
||||
opendir D, $self->{dirName};
|
||||
my @notif;
|
||||
my $fns = $self->{fileNameSeparator};
|
||||
|
@ -113,6 +137,7 @@ sub getExisting {
|
|||
# @param $myref identifier returned by get() or getAll()
|
||||
sub delete {
|
||||
my ( $self, $myref ) = @_;
|
||||
my $ext = $self->extension;
|
||||
my $new = ( $myref =~ /(.*?)(?:\.$ext)$/ )[0] . '.done';
|
||||
return rename( $self->{dirName} . "/$myref", $self->{dirName} . "/$new" );
|
||||
}
|
||||
|
@ -129,6 +154,7 @@ sub purge {
|
|||
# Insert a new notification
|
||||
sub newNotif {
|
||||
my ( $self, $date, $uid, $ref, $condition, $content ) = @_;
|
||||
my $ext = $self->extension;
|
||||
my $fns = $self->{fileNameSeparator};
|
||||
$fns ||= '_';
|
||||
my @t = split( /\D+/, $date );
|
||||
|
|
|
@ -42,10 +42,11 @@ sub newNotification {
|
|||
|
||||
unless ( exists $notif->{condition} ) {
|
||||
$self->userLogger->info(
|
||||
"Set defaultCondition ($defaultCond) for notification $notif->{reference}");
|
||||
"Set defaultCondition ($defaultCond) for notification $notif->{reference}"
|
||||
);
|
||||
$notif->{condition} = $defaultCond;
|
||||
}
|
||||
|
||||
|
||||
push @data, ( $notif->{condition} );
|
||||
$notif->{date} =~ s/^(\d{4}-\d{2}-\d{2}).*$/$1/;
|
||||
my $body = to_json($notif);
|
||||
|
|
|
@ -9,7 +9,7 @@ package Lemonldap::NG::Common::Notifications::LDAP;
|
|||
use strict;
|
||||
use Mouse;
|
||||
use Time::Local;
|
||||
use MIME::Base64;
|
||||
use MIME::Base64 qw/encode_base64url/;
|
||||
use Net::LDAP;
|
||||
use utf8;
|
||||
|
||||
|
@ -45,6 +45,16 @@ has ldapBindDN => (
|
|||
}
|
||||
);
|
||||
|
||||
has ldapBindPassword => (
|
||||
is => 'ro',
|
||||
lazy => 1,
|
||||
default => sub {
|
||||
$_[0]
|
||||
->p->logger->warn('Warning: "ldapBindPassword" parameter is not set');
|
||||
return '';
|
||||
}
|
||||
);
|
||||
|
||||
# Returns notifications corresponding to the user $uid.
|
||||
# If $ref is set, returns only notification corresponding to this reference.
|
||||
sub get {
|
||||
|
@ -57,7 +67,39 @@ sub get {
|
|||
. ( $ref ? '(description={ref}' . $ref . ')' : '' ) . ')';
|
||||
my @entries = _search( $self, $filter );
|
||||
|
||||
my $result = {};
|
||||
my $result;
|
||||
foreach my $entry (@entries) {
|
||||
my @notifValues = $entry->get_value('description');
|
||||
my $f = {};
|
||||
foreach (@notifValues) {
|
||||
my ( $k, $v ) = ( $_ =~ /\{(.*?)\}(.*)/smg );
|
||||
$v = decodeLdapValue($v);
|
||||
$f->{$k} = $v;
|
||||
}
|
||||
my $xml = $f->{xml};
|
||||
utf8::encode($xml);
|
||||
my $identifier =
|
||||
&getIdentifier( $self, $f->{uid}, $f->{ref}, $f->{date} );
|
||||
$result->{$identifier} = "$xml";
|
||||
$self->logger->info("notification $identifier found");
|
||||
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
# Returns accepted notifications corresponding to the user $uid.
|
||||
# If $ref is set, returns only notification corresponding to this reference.
|
||||
sub getAccepted {
|
||||
my ( $self, $uid, $ref ) = @_;
|
||||
return () unless ($uid);
|
||||
|
||||
my $filter =
|
||||
'(&(objectClass=applicationProcess)(description={done}*)'
|
||||
. "(description={uid}$uid)"
|
||||
. ( $ref ? '(description={ref}' . $ref . ')' : '' ) . ')';
|
||||
my @entries = _search( $self, $filter );
|
||||
|
||||
my $result;
|
||||
foreach my $entry (@entries) {
|
||||
my @notifValues = $entry->get_value('description');
|
||||
my $f = {};
|
||||
|
@ -195,9 +237,8 @@ sub newNotif {
|
|||
return ( 0, "Bad date" ) if ($@);
|
||||
$date =~ s/-//g;
|
||||
return ( 0, "Bad date" ) unless ( $date =~ /^\d{8}/ );
|
||||
my $cn = "${date}${fns}${uid}${fns}" . encode_base64( $ref, '' );
|
||||
$cn .= "${fns}" . encode_base64( $condition, '' ) if $condition;
|
||||
$xml = $xml->serialize();
|
||||
my $cn = "${date}${fns}${uid}${fns}" . encode_base64url( $ref, '' );
|
||||
$cn .= "${fns}" . encode_base64url( $condition, '' ) if $condition;
|
||||
|
||||
my $fields =
|
||||
$condition =~ /.+/
|
||||
|
@ -347,7 +388,7 @@ sub _store {
|
|||
);
|
||||
|
||||
if ( $add->code ) {
|
||||
$self->logError($add);
|
||||
$self->logger->error( $add->error );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ sub newNotification {
|
|||
$self->logger->error("$err");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
# Prevent to store time. Keep date only
|
||||
$tmp =~ s/^(\d{4}-\d{2}-\d{2}).*$/$1/;
|
||||
push @data, $tmp;
|
||||
|
@ -59,8 +59,8 @@ sub newNotification {
|
|||
}
|
||||
else {
|
||||
$self->userLogger->info(
|
||||
"Set defaultCondition ($defaultCond) for notification " . $notif->{reference}
|
||||
);
|
||||
"Set defaultCondition ($defaultCond) for notification "
|
||||
. $notif->{reference} );
|
||||
push @data, $defaultCond;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,17 +35,17 @@ sub init {
|
|||
foreach my $k ( keys %$args ) {
|
||||
$self->{$k} = $args->{$k} unless ( $k eq 'logger' );
|
||||
}
|
||||
unless ( $self->logger and $self->userLogger ) {
|
||||
unless ( ref( $self->logger ) and ref( $self->userLogger ) ) {
|
||||
my $logger =
|
||||
$args->{logger}
|
||||
|| $ENV{LLNG_DEFAULTLOGGER}
|
||||
|| 'Lemonldap::NG::Common::Logger::Std';
|
||||
unless ( $self->logger ) {
|
||||
unless ( ref $self->logger ) {
|
||||
eval "require $logger";
|
||||
die $@ if ($@);
|
||||
$self->logger( $logger->new($self) );
|
||||
}
|
||||
unless ( $self->userLogger ) {
|
||||
unless ( ref $self->userLogger ) {
|
||||
$logger = $ENV{LLNG_USERLOGGER} || $args->{userLogger} || $logger;
|
||||
eval "require $logger";
|
||||
die $@ if ($@);
|
||||
|
|
|
@ -52,7 +52,8 @@ sub userData {
|
|||
return $self->{userData}
|
||||
|| {
|
||||
( $Lemonldap::NG::Handler::Main::tsv->{whatToTrace}
|
||||
|| '_whatToTrace' ) => $self->{user}, };
|
||||
|| '_whatToTrace' ) => $self->{user},
|
||||
};
|
||||
}
|
||||
|
||||
sub respHeaders {
|
||||
|
|
|
@ -64,8 +64,8 @@ sub checkLogonHours {
|
|||
# Use time_correction
|
||||
if ($time_correction) {
|
||||
my ( $sign, $time ) = ( $time_correction =~ /([+|-]?)(\d+)/ );
|
||||
if ( $sign =~ /-/ ) { $hourpos -= $time; }
|
||||
else { $hourpos += $time; }
|
||||
if ( $sign =~ /-/ ) { $hourpos -= $time; }
|
||||
else { $hourpos += $time; }
|
||||
}
|
||||
|
||||
# Get the corresponding byte
|
||||
|
|
|
@ -131,6 +131,7 @@ sub BUILD {
|
|||
|
||||
if ( $self->{info} ) {
|
||||
foreach ( keys %{ $self->{info} } ) {
|
||||
next if ( $_ eq "_session_id" and $data->{_session_id} );
|
||||
if ( defined $self->{info}->{$_} ) {
|
||||
$data->{$_} = $self->{info}->{$_};
|
||||
}
|
||||
|
|
|
@ -283,11 +283,11 @@ sub getMod {
|
|||
my ( $self, $req ) = @_;
|
||||
my ( $s, $m );
|
||||
unless ( $s = $req->params('sessionType') ) {
|
||||
$self->error($req->error('Session type is required'));
|
||||
$self->error( $req->error('Session type is required') );
|
||||
return ();
|
||||
}
|
||||
unless ( $m = $self->sessionTypes->{$s} ) {
|
||||
$self->error($req->error('Unknown (or unconfigured) session type'));
|
||||
$self->error( $req->error('Unknown (or unconfigured) session type') );
|
||||
return ();
|
||||
}
|
||||
if ( my $kind = $req->params('kind') ) {
|
||||
|
|
|
@ -22,7 +22,7 @@ for ( my $i = 0 ; $i < @ARGV ; $i++ ) {
|
|||
|
||||
$action ||= "help";
|
||||
|
||||
if ( $action =~ /^(?:[gs]et|(?:add|del)Key|save|restore)$/ ) {
|
||||
if ( $action =~ /^(?:[gs]et|(?:add|del)Key|save|restore|rollback)$/ ) {
|
||||
eval { require Lemonldap::NG::Manager::Cli; };
|
||||
die "Manager libraries not available, aborting ($@)" if ($@);
|
||||
Lemonldap::NG::Manager::Cli->run(@ARGV);
|
||||
|
@ -50,6 +50,14 @@ Available actions:
|
|||
- save : export configuration to STDOUT
|
||||
- restore - : import configuration from STDIN
|
||||
- restore <file> : import configuration from file
|
||||
- rollback : restore previous configuration
|
||||
|
||||
Options:
|
||||
- yes <0|1> : accept confirmation prompt automatically
|
||||
- log <msg> : set configuration log message
|
||||
- safe <0|1> : fail in case the requested configuration is invalid
|
||||
- force <0|1> : allow overwrite of existing config number
|
||||
- cfgNum <num> : set new configuration number (requires -force 1)
|
||||
|
||||
See Lemonldap::NG::Manager::Cli(3) for more
|
||||
};
|
||||
|
@ -75,6 +83,7 @@ Update local configuration cache
|
|||
Save configuration
|
||||
|
||||
$ lemonldap-ng-cli save >conf.json
|
||||
$ lemonldap-ng-cli -cfgNum 19 save >conf-19.json
|
||||
|
||||
Restore configuration
|
||||
|
||||
|
@ -82,6 +91,10 @@ Restore configuration
|
|||
# OR
|
||||
$ lemonldap-ng-cli restore - <conf.json
|
||||
|
||||
Cancel the last configuration change
|
||||
|
||||
$ lemonldap-ng-cli rollback
|
||||
|
||||
Get a configuration parameter value
|
||||
|
||||
$ lemonldap-ng-cli get portal domain cookieName
|
||||
|
@ -92,6 +105,12 @@ Set some values
|
|||
# add or set a key
|
||||
$ lemonldap-ng-cli addKey macro fullname '$givenName." ".$lastName'
|
||||
|
||||
# without changing the version number
|
||||
$ lemonldap-ng-cli -force 1 -cfgNum 1 set portal http://auth.e.com/ domain e.com
|
||||
|
||||
# without asking for confirmation
|
||||
$ lemonldap-ng-cli -yes 1 set portal http://auth.e.com/ domain e.com
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
lemonldap-ng-cli is a command line interface to interact with Lemonldap::NG
|
||||
|
@ -120,6 +139,32 @@ and L<Lemonldap::NG::Common::Cli>
|
|||
|
||||
=back
|
||||
|
||||
=head2 Available options
|
||||
|
||||
=over
|
||||
|
||||
=item -yes
|
||||
|
||||
Confirm modification automatically (default: 0)
|
||||
|
||||
=item -log
|
||||
|
||||
Allows you to set the log message that will be displayed in the manager
|
||||
|
||||
=item -safe
|
||||
|
||||
The configuration change will be aborted if it contains errors (default: 0)
|
||||
|
||||
=item -cfgNum
|
||||
|
||||
Choose a particular configuration number (default: latest)
|
||||
|
||||
=item -force
|
||||
|
||||
Allows you to force overwriting an existing configuration (default: 0)
|
||||
|
||||
=back
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Lemonldap::NG::Manager::Cli>, L<Lemonldap::NG::Common::Cli>
|
||||
|
|
|
@ -64,4 +64,3 @@ t/lmConf-1.json
|
|||
t/sessions/lock/Apache-Session-f5eec18ebb9bc96352595e2d8ce962e8ecf7af7c9a98cb9a43f9cd181cf4b545.lock
|
||||
t/test-psgi-lib.pm
|
||||
t/test.pm
|
||||
t/Time-Fake.pm
|
||||
|
|
|
@ -66,7 +66,7 @@ q"I refuse to compile rules.json when useSafeJail isn't activated! Yes I know, I
|
|||
$json->{rules} ||= { default => 1 };
|
||||
$json->{headers} //= { 'Auth-User' => '$uid' };
|
||||
$class->locationRulesInit( undef, { $vhost => $json->{rules} } );
|
||||
$class->headersInit( undef, { $vhost => $json->{headers} } );
|
||||
$class->headersInit( undef, { $vhost => $json->{headers} } );
|
||||
$class->tsv->{lastVhostUpdate}->{$vhost} = time;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -75,11 +75,13 @@ sub fetchId {
|
|||
|
||||
# Get access token session
|
||||
my $infos = $class->getOIDCInfos($access_token);
|
||||
|
||||
# If this token is tied to a regular session ID
|
||||
if ( my $_session_id = $infos->{user_session_id} ) {
|
||||
$class->logger->debug( 'Get user session id ' . $_session_id );
|
||||
return $_session_id;
|
||||
}
|
||||
|
||||
# If this token is tied to an Offline session
|
||||
if ( my $_session_id = $infos->{offline_session_id} ) {
|
||||
$class->logger->debug( 'Get offline session id ' . $_session_id );
|
||||
|
|
|
@ -45,7 +45,8 @@ sub fetchId {
|
|||
}
|
||||
|
||||
# Is token in good interval ?
|
||||
my $ttl = $class->localConfig->{vhostOptions}->{$vhost}->{vhostServiceTokenTTL}
|
||||
my $ttl =
|
||||
$class->localConfig->{vhostOptions}->{$vhost}->{vhostServiceTokenTTL}
|
||||
|| $class->tsv->{serviceTokenTTL}->{$vhost};
|
||||
$ttl = $class->tsv->{handlerServiceTokenTTL} unless ( $ttl and $ttl > 0 );
|
||||
my $now = time;
|
||||
|
|
|
@ -68,7 +68,8 @@ sub run {
|
|||
my ( $user, $uri, $code ) = ( $1, $2, $3 );
|
||||
|
||||
# Portal error translation
|
||||
$code = portalConsts->{$code} || $code if ( $code =~ /^\-?\d+$/ );
|
||||
$code = portalConsts->{$code} || $code
|
||||
if ( $code =~ /^\-?\d+$/ );
|
||||
|
||||
# Per user activity
|
||||
$status->{user}->{$user}->{$code}++;
|
||||
|
|
|
@ -440,14 +440,15 @@ sub fetchId {
|
|||
my ( $class, $req ) = @_;
|
||||
my $t = $req->{env}->{HTTP_COOKIE} or return 0;
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
$class->logger->debug("VH $vhost is HTTPS") if $class->_isHttps( $req, $vhost );
|
||||
$class->logger->debug("VH $vhost is HTTPS")
|
||||
if $class->_isHttps( $req, $vhost );
|
||||
my $lookForHttpCookie = ( $class->tsv->{securedCookie} =~ /^(2|3)$/
|
||||
and not $class->_isHttps( $req, $vhost ) );
|
||||
my $cn = $class->tsv->{cookieName};
|
||||
my $value =
|
||||
$lookForHttpCookie
|
||||
? ( $t =~ /${cn}http=([^,; ]+)/o ? $1 : 0 )
|
||||
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
|
||||
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
|
||||
|
||||
if ( $value && $lookForHttpCookie && $class->tsv->{securedCookie} == 3 ) {
|
||||
$value = $class->tsv->{cipher}->decryptHex( $value, "http" );
|
||||
|
|
|
@ -49,7 +49,7 @@ sub addAuthRouteWithRedirect {
|
|||
sub _auth_and_redirect {
|
||||
my ( $self, $req ) = @_;
|
||||
$self->api->goToPortal( $req, $req->{env}->{REQUEST_URI} );
|
||||
return [ 302, [$req->spliceHdrs], [] ];
|
||||
return [ 302, [ $req->spliceHdrs ], [] ];
|
||||
}
|
||||
|
||||
sub defaultAuthRoute {
|
||||
|
@ -73,7 +73,7 @@ sub _run {
|
|||
if ( $res->[0] < 300 ) {
|
||||
$self->routes( $self->authRoutes );
|
||||
$req->userData( $self->api->data );
|
||||
$req->respHeaders($res->[1]);
|
||||
$req->respHeaders( $res->[1] );
|
||||
}
|
||||
elsif ( $res->[0] != 403 and not $req->data->{noTry} ) {
|
||||
|
||||
|
|
|
@ -36,17 +36,17 @@ ok(
|
|||
( defined($code) and ref($code) eq 'CODE' ),
|
||||
'encode_base64 function is defined'
|
||||
);
|
||||
ok( $res = &$code, "Function works" );
|
||||
ok( $res = &$code, "Function works" );
|
||||
ok( $res eq 'dGVzdA==', 'Get good result' );
|
||||
|
||||
$sub = "sub { return ( listMatch('ABC; DEF; GHI','abc',1) ) }";
|
||||
my $code = $jail->jail_reval($sub);
|
||||
$sub = "sub { return ( listMatch('ABC; DEF; GHI','abc',1) ) }";
|
||||
$code = $jail->jail_reval($sub);
|
||||
ok( ( defined($code) and ref($code) eq 'CODE' ),
|
||||
'listMatch function is defined' );
|
||||
ok( &$code eq '1', 'Get good result' );
|
||||
|
||||
$sub = "sub { return ( listMatch('ABC; DEF; GHI','ab',1) ) }";
|
||||
my $code = $jail->jail_reval($sub);
|
||||
$sub = "sub { return ( listMatch('ABC; DEF; GHI','ab',1) ) }";
|
||||
$code = $jail->jail_reval($sub);
|
||||
ok( ( defined($code) and ref($code) eq 'CODE' ),
|
||||
'listMatch function is defined' );
|
||||
ok( &$code eq '0', 'Get good result' );
|
||||
|
@ -58,5 +58,5 @@ ok(
|
|||
'checkDate extended function is defined'
|
||||
);
|
||||
ok( $res = &$code, "Function works" );
|
||||
ok( $res == 1, 'Get good result' );
|
||||
ok( $res == 1, 'Get good result' );
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@ ok( ( defined($listMatch) and ref($listMatch) eq 'CODE' ),
|
|||
'listMatch function is defined' );
|
||||
ok( &$listMatch eq '1', 'Get good result' );
|
||||
|
||||
my $sub5 = "sub { return ( listMatch('ABC; DEF; GHI','ab', 1) ) }";
|
||||
my $listMatch = $jail->jail_reval($sub5);
|
||||
my $sub5 = "sub { return ( listMatch('ABC; DEF; GHI','ab', 1) ) }";
|
||||
$listMatch = $jail->jail_reval($sub5);
|
||||
ok( ( defined($listMatch) and ref($listMatch) eq 'CODE' ),
|
||||
'listMatch function is defined' );
|
||||
ok( &$listMatch eq '0', 'Get good result' );
|
||||
|
|
|
@ -41,33 +41,55 @@ ok( $h{'Auth-User'} eq 'dwho', 'Header Auth-User is set to "dwho"' )
|
|||
count(1);
|
||||
|
||||
# Request an URI protected by custom function -> allowed
|
||||
ok( $res = $client->_get( '/test-restricted_uri/dwho/', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Authentified query' );
|
||||
ok( $res->[0] == 200, '/test-restricted_uri -> Code is 200' ) or explain( $res, 200 );
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/test-restricted_uri/dwho/', undef, undef, "lemonldap=$sessionId"
|
||||
),
|
||||
'Authentified query'
|
||||
);
|
||||
ok( $res->[0] == 200, '/test-restricted_uri -> Code is 200' )
|
||||
or explain( $res, 200 );
|
||||
count(2);
|
||||
|
||||
# Request an URI protected by custom function -> denied
|
||||
ok( $res = $client->_get( '/test-restricted_uri/dwho', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Denied query' );
|
||||
ok( $res->[0] == 403, '/test-restricted_uri -> Code is 403' ) or explain( $res->[0], 403 );
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/test-restricted_uri/dwho', undef, undef, "lemonldap=$sessionId"
|
||||
),
|
||||
'Denied query'
|
||||
);
|
||||
ok( $res->[0] == 403, '/test-restricted_uri -> Code is 403' )
|
||||
or explain( $res->[0], 403 );
|
||||
count(2);
|
||||
|
||||
# Request an URI protected by custom function -> allowed
|
||||
ok( $res = $client->_get( '/test-uri2/dwho/dummy', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Authentified query' );
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/test-uri2/dwho/dummy', undef, undef, "lemonldap=$sessionId"
|
||||
),
|
||||
'Authentified query'
|
||||
);
|
||||
ok( $res->[0] == 200, '/test-uri2 -> Code is 200' ) or explain( $res, 200 );
|
||||
count(2);
|
||||
|
||||
# Request an URI protected by custom function -> denied
|
||||
ok( $res = $client->_get( '/test-uri1/dwho/', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Denied query' );
|
||||
ok( $res->[0] == 403, '/test-uri1 -> Code is 403' ) or explain( $res->[0], 403 );
|
||||
ok(
|
||||
$res =
|
||||
$client->_get( '/test-uri1/dwho/', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Denied query'
|
||||
);
|
||||
ok( $res->[0] == 403, '/test-uri1 -> Code is 403' )
|
||||
or explain( $res->[0], 403 );
|
||||
count(2);
|
||||
|
||||
# Request an URI protected by custom function -> denied
|
||||
ok( $res = $client->_get( '/test-uri1/dwh', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Denied query' );
|
||||
ok( $res->[0] == 403, '/test-uri1 -> Code is 403' ) or explain( $res->[0], 403 );
|
||||
ok(
|
||||
$res =
|
||||
$client->_get( '/test-uri1/dwh', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Denied query'
|
||||
);
|
||||
ok( $res->[0] == 403, '/test-uri1 -> Code is 403' )
|
||||
or explain( $res->[0], 403 );
|
||||
count(2);
|
||||
|
||||
# Denied query
|
||||
|
|
|
@ -45,27 +45,42 @@ ok( $h{'Headervalue1'} eq 'dwho', 'Headervalue1 is set to "dwho"' )
|
|||
count(2);
|
||||
|
||||
# Request an URI protected by custom function -> allowed
|
||||
ok( $res = $client->_get( '/test-uri1/dwho', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Authentified query' );
|
||||
ok(
|
||||
$res =
|
||||
$client->_get( '/test-uri1/dwho', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Authentified query'
|
||||
);
|
||||
ok( $res->[0] == 200, '/test-uri1 -> Code is 200' ) or explain( $res, 200 );
|
||||
count(2);
|
||||
|
||||
# Request an URI protected by custom function -> allowed
|
||||
ok( $res = $client->_get( '/test-uri2/dwho/dummy', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Authentified query' );
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/test-uri2/dwho/dummy', undef, undef, "lemonldap=$sessionId"
|
||||
),
|
||||
'Authentified query'
|
||||
);
|
||||
ok( $res->[0] == 200, '/test-uri2 -> Code is 200' ) or explain( $res, 200 );
|
||||
count(2);
|
||||
|
||||
# Request an URI protected by custom function -> denied
|
||||
ok( $res = $client->_get( '/test-uri1/dwho/', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Denied query' );
|
||||
ok( $res->[0] == 403, '/test-uri1 -> Code is 403' ) or explain( $res->[0], 403 );
|
||||
ok(
|
||||
$res =
|
||||
$client->_get( '/test-uri1/dwho/', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Denied query'
|
||||
);
|
||||
ok( $res->[0] == 403, '/test-uri1 -> Code is 403' )
|
||||
or explain( $res->[0], 403 );
|
||||
count(2);
|
||||
|
||||
# Request an URI protected by custom function -> denied
|
||||
ok( $res = $client->_get( '/test-uri1/dwh', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Denied query' );
|
||||
ok( $res->[0] == 403, '/test-uri1 -> Code is 403' ) or explain( $res->[0], 403 );
|
||||
ok(
|
||||
$res =
|
||||
$client->_get( '/test-uri1/dwh', undef, undef, "lemonldap=$sessionId" ),
|
||||
'Denied query'
|
||||
);
|
||||
ok( $res->[0] == 403, '/test-uri1 -> Code is 403' )
|
||||
or explain( $res->[0], 403 );
|
||||
count(2);
|
||||
|
||||
# Denied query
|
||||
|
|
|
@ -39,7 +39,7 @@ my $res;
|
|||
|
||||
# Unauth tests
|
||||
ok( $res = $client->_get('/test'), 'Get response' );
|
||||
ok( $res->[0] == 200, 'Response code is 200' )
|
||||
ok( $res->[0] == 200, 'Response code is 200' )
|
||||
or print "Expect 200, got $res->[0]\n";
|
||||
ok( $res->[2]->[0] eq 'Unauth', 'Get unauth result' )
|
||||
or print "Expect Unauth, got $res->[2]->[0]\n";
|
||||
|
@ -64,7 +64,7 @@ count(3);
|
|||
# Bad path test
|
||||
|
||||
ok( $res = $client->_get('/[]/test'), 'Try a bad path' );
|
||||
ok( $res->[0] == 400, 'Response is 400' );
|
||||
ok( $res->[0] == 400, 'Response is 400' );
|
||||
count(2);
|
||||
|
||||
clean();
|
||||
|
|
|
@ -119,7 +119,7 @@ ok(
|
|||
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res->[0], 200 );
|
||||
count(2);
|
||||
|
||||
my %headers = @{ $res->[1] };
|
||||
%headers = @{ $res->[1] };
|
||||
ok( $headers{'zero'} eq '0', 'Found "zero" header with "0"' )
|
||||
or print STDERR Data::Dumper::Dumper( $res->[1] );
|
||||
ok( $headers{'empty'} eq '', 'Found "empty" header without value' )
|
||||
|
|
|
@ -38,8 +38,9 @@ my $crypt = Lemonldap::NG::Common::Crypto->new('qwertyui');
|
|||
my $token = $crypt->encrypt(
|
||||
join ':', time,
|
||||
$sessionId, 'test1.example.com',
|
||||
'XFromVH=app1-auth.example.com', "serviceHeader1=$sessionId","serviceHeader2=$sessionId",
|
||||
'test2.example.com', '*.example.com'
|
||||
'XFromVH=app1-auth.example.com', "serviceHeader1=$sessionId",
|
||||
"serviceHeader2=$sessionId", 'test2.example.com',
|
||||
'*.example.com'
|
||||
);
|
||||
|
||||
ok(
|
||||
|
|
|
@ -1,235 +0,0 @@
|
|||
package Time::Fake;
|
||||
use Carp;
|
||||
use strict;
|
||||
use vars '$VERSION';
|
||||
$VERSION = "0.11";
|
||||
|
||||
#####################
|
||||
|
||||
my $OFFSET = 0;
|
||||
|
||||
*CORE::GLOBAL::time = sub() { CORE::time() + $OFFSET };
|
||||
|
||||
*CORE::GLOBAL::localtime = sub(;$) {
|
||||
@_ ? CORE::localtime($_[0])
|
||||
: CORE::localtime(CORE::time() + $OFFSET);
|
||||
};
|
||||
|
||||
*CORE::GLOBAL::gmtime = sub(;$) {
|
||||
@_ ? CORE::gmtime($_[0])
|
||||
: CORE::gmtime(CORE::time() + $OFFSET);
|
||||
};
|
||||
|
||||
sub import {
|
||||
my $pkg = shift;
|
||||
$pkg->offset(shift);
|
||||
}
|
||||
|
||||
sub offset {
|
||||
my $pkg = shift;
|
||||
return $OFFSET if !@_;
|
||||
|
||||
my $old_offset = $OFFSET;
|
||||
$OFFSET = _to_offset(shift);
|
||||
return $old_offset;
|
||||
}
|
||||
|
||||
sub reset {
|
||||
shift->offset(0);
|
||||
}
|
||||
|
||||
my %mult = (
|
||||
s => 1,
|
||||
m => 60,
|
||||
h => 60*60,
|
||||
d => 60*60*24,
|
||||
M => 60*60*24*30,
|
||||
y => 60*60*24*365,
|
||||
);
|
||||
|
||||
sub _to_offset {
|
||||
my $t = shift || return 0;
|
||||
|
||||
if ($t =~ m/^([+-]\d+)([smhdMy]?)$/) {
|
||||
$t = $1 * $mult{ $2 || "s" };
|
||||
|
||||
} elsif ($t !~ m/\D/) {
|
||||
$t = $t - CORE::time;
|
||||
|
||||
} else {
|
||||
croak "Invalid time offset: `$t'";
|
||||
}
|
||||
|
||||
return $t;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Time::Fake - Simulate different times without changing your system clock
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
Pretend we are running 1 day in the future:
|
||||
|
||||
use Time::Fake '+1d';
|
||||
|
||||
Pretend we are running 1 year in the past:
|
||||
|
||||
use Time::Fake '-1y';
|
||||
|
||||
Pretend the script started at epoch time 1234567:
|
||||
|
||||
use Time::Fake 1234567;
|
||||
|
||||
See what an existing script would do if run 20 years in the future:
|
||||
|
||||
% perl -MTime::Fake="+20y" test.pl
|
||||
|
||||
Run a section of code in a time warp:
|
||||
|
||||
use Time::Fake;
|
||||
|
||||
# do some setup
|
||||
|
||||
Time::Fake->offset("+1y");
|
||||
run_tests(); # thinks it's a year ahead
|
||||
|
||||
Time::Fake->reset; # back to the present
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Use this module to achieve the effect of changing your system clock, but
|
||||
without actually changing your system clock. It overrides the Perl builtin
|
||||
subs C<time>, C<localtime>, and C<gmtime>, causing them to return a
|
||||
"faked" time of your choice. From the script's point of view, time still
|
||||
flows at the normal rate, but it is just offset as if it were executing
|
||||
in the past or present.
|
||||
|
||||
You may find this module useful in writing test scripts for code that has
|
||||
time-sensitive logic.
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
=head2 Using and importing:
|
||||
|
||||
use Time::Fake $t;
|
||||
|
||||
Is equivalent to:
|
||||
|
||||
use Time::Fake;
|
||||
Time::Fake->offset($t);
|
||||
|
||||
See below for arguments to C<offset>. This usage makes it easy to
|
||||
fake the time for existing scripts, as in:
|
||||
|
||||
% perl -MTime::Fake=+1y script.pl
|
||||
|
||||
=head2 offset
|
||||
|
||||
Time::Fake->offset( [$t] );
|
||||
|
||||
C<$t> is either an epoch time, or a relative offset of the following
|
||||
form:
|
||||
|
||||
+3 # 3 seconds in the future
|
||||
-3s # 3 seconds in the past
|
||||
+1h # 1 hour in the future
|
||||
etc..
|
||||
|
||||
Relative offsets must begin with a plus or minus symbol. The supported
|
||||
units are:
|
||||
|
||||
s second
|
||||
m minute
|
||||
h hour
|
||||
d day (24 hours)
|
||||
M month (30 days)
|
||||
y year (365 days)
|
||||
|
||||
If C<$t> is an epoch time, then C<time>, C<localtime>, and C<gmtime>
|
||||
will act as though the the current time (when C<offset> was called) was
|
||||
actually at C<$t> epoch seconds.
|
||||
Otherwise, the offset C<$t> will be added to the times returned by these
|
||||
builtin subs.
|
||||
|
||||
When C<$t> is false, C<time>, C<localtime>, C<gmtime>
|
||||
remain overridden, but their behavior resets to reflect the actual
|
||||
system time.
|
||||
|
||||
When C<$t> is omitted, nothing is changed, but C<offset> returns the
|
||||
current additive offset (in seconds). Otherwise, its return value is
|
||||
the I<previous> offset.
|
||||
|
||||
C<offset> may be called several times. However, I<The effect of multiple
|
||||
calls is NOT CUMULATIVE.> That is:
|
||||
|
||||
Time::Fake->offset("+1h");
|
||||
Time::Fake->offset("+1h");
|
||||
|
||||
## same as
|
||||
# Time::Fake->offset("+1h");
|
||||
|
||||
## NOT the same as
|
||||
# Time::Fake->offset("+2h");
|
||||
|
||||
Each call to C<offset> completely cancels out the effect of any
|
||||
previous calls. To make the effect cumulative, use the return value
|
||||
of calling C<offset> with no arguments:
|
||||
|
||||
Time::Fake->offset("+1h");
|
||||
...
|
||||
Time::Fake->offset( Time::Fake->offset + 3600 ); # add another hour
|
||||
|
||||
=head2 reset
|
||||
|
||||
Time::Fake->reset;
|
||||
|
||||
Is the same as:
|
||||
|
||||
Time::Fake->offset(0);
|
||||
|
||||
That is, it returns all the affected builtin subs to their
|
||||
default behavior -- reporing the actual system time.
|
||||
|
||||
=head1 KNOWN CAVEATS
|
||||
|
||||
Time::Fake must be loaded at C<BEGIN>-time (e.g., with a standard
|
||||
C<use> statement). It must be loaded before perl I<compiles> any code
|
||||
that uses C<time>, C<localtime>, or C<gmtime>. Due to inherent
|
||||
limitations in overriding builtin subs, any code that was compiled
|
||||
before loading Time::Fake will not be affected.
|
||||
|
||||
Because the system clock is not being changed, only Perl code that
|
||||
uses C<time>, C<localtime>, or C<gmtime> will be fooled about the date.
|
||||
In particular, the operating system is not fooled,
|
||||
nor are other programs. If your Perl code modifies a file for example,
|
||||
the file's modification time will reflect the B<actual> (not faked) time.
|
||||
Along the same lines, if your Perl script obtains the time from somewhere
|
||||
other than the affected builtins subs (e.g., C<qx/date/>), the actual
|
||||
(not faked) time will be reflected.
|
||||
|
||||
Time::Fake doesn't affect -M, -A, -C filetest operators in the way you'd
|
||||
probably want. These still report the B<actual> (not faked) script start
|
||||
time minus file access time.
|
||||
|
||||
Time::Fake has not been tested with other modules that override the time
|
||||
builtins, e.g., Time::HiRes.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
Time::Warp, which uses XS to fool more of Perl.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Time::Fake is written by Mike Rosulek E<lt>mike@mikero.comE<gt>. Feel
|
||||
free to contact me with comments, questions, patches, or whatever.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (c) 2008 Mike Rosulek. All rights reserved. This module is free
|
||||
software; you can redistribute it and/or modify it under the same terms as Perl
|
||||
itself.
|
|
@ -4,15 +4,12 @@ use strict;
|
|||
use 5.10.0;
|
||||
use POSIX 'strftime';
|
||||
use Data::Dumper;
|
||||
use Time::Fake;
|
||||
use_ok('Lemonldap::NG::Common::PSGI::Cli::Lib');
|
||||
|
||||
our $client;
|
||||
our $count = 1;
|
||||
|
||||
BEGIN {
|
||||
require 't/Time-Fake.pm';
|
||||
}
|
||||
|
||||
no warnings 'redefine';
|
||||
|
||||
my $module;
|
||||
|
|
|
@ -26,6 +26,7 @@ lib/Lemonldap/NG/Manager/Conf/Parser.pm
|
|||
lib/Lemonldap/NG/Manager/Conf/Tests.pm
|
||||
lib/Lemonldap/NG/Manager/Conf/Zero.pm
|
||||
lib/Lemonldap/NG/Manager/Notifications.pm
|
||||
lib/Lemonldap/NG/Manager/Plugin.pm
|
||||
lib/Lemonldap/NG/Manager/Sessions.pm
|
||||
lib/Lemonldap/NG/Manager/Viewer.pm
|
||||
Makefile.PL
|
||||
|
|
|
@ -24,6 +24,9 @@ extends 'Lemonldap::NG::Common::Conf::AccessLib',
|
|||
|
||||
has csp => ( is => 'rw' );
|
||||
|
||||
has loadedPlugins => ( is => 'rw', default => sub { [] } );
|
||||
has hLoadedPlugins => ( is => 'rw', default => sub { {} } );
|
||||
|
||||
## @method boolean init($args)
|
||||
# Launch initialization method
|
||||
#
|
||||
|
@ -52,32 +55,50 @@ sub init {
|
|||
return 0;
|
||||
}
|
||||
|
||||
my $conf = $self->confAcc->getConf;
|
||||
$conf->{$_} = $args->{$_} foreach ( keys %$args );
|
||||
|
||||
$self->{enabledModules} ||= "conf, sessions, notifications, 2ndFA, api";
|
||||
my @links;
|
||||
my @enabledModules =
|
||||
map { push @links, $_; "Lemonldap::NG::Manager::" . ucfirst($_) }
|
||||
map {
|
||||
my @res = ( "Lemonldap::NG::Manager::" . ucfirst($_) );
|
||||
if ( my $tmp = $self->loadPlugin( @res, $conf ) ) {
|
||||
$self->logger->debug("Plugin $_ loaded");
|
||||
push @links, $_;
|
||||
push @{ $self->loadedPlugins }, $tmp;
|
||||
$self->hLoadedPlugins->{$_} = $tmp;
|
||||
}
|
||||
else {
|
||||
$self->logger->error("Unable to load $_, skipping");
|
||||
@res = ();
|
||||
}
|
||||
(@res);
|
||||
}
|
||||
split( /[,\s]+/, $self->{enabledModules} );
|
||||
extends 'Lemonldap::NG::Handler::PSGI::Router', @enabledModules;
|
||||
my @working;
|
||||
my $conf = $self->confAcc->getConf;
|
||||
unless (@enabledModules) {
|
||||
$self->logger->error('No plugins loaded, aborting');
|
||||
return 0;
|
||||
}
|
||||
unless ($conf) {
|
||||
require Lemonldap::NG::Manager::Conf::Zero;
|
||||
$conf = Lemonldap::NG::Manager::Conf::Zero::zeroConf();
|
||||
}
|
||||
for ( my $i = 0 ; $i < @enabledModules ; $i++ ) {
|
||||
my $mod = $enabledModules[$i];
|
||||
no strict 'refs';
|
||||
if ( &{"${mod}::addRoutes"}( $self, $conf ) ) {
|
||||
$self->logger->debug("Module $mod enabled");
|
||||
push @working, $mod;
|
||||
}
|
||||
else {
|
||||
$links[$i] = undef;
|
||||
$self->logger->error(
|
||||
"Module $mod can not be enabled: " . $self->error );
|
||||
}
|
||||
}
|
||||
return 0 unless (@working);
|
||||
|
||||
# TODO: -> loadPlugin
|
||||
#for ( my $i = 0 ; $i < @enabledModules ; $i++ ) {
|
||||
# my $mod = $enabledModules[$i];
|
||||
# no strict 'refs';
|
||||
# if ( &{"${mod}::addRoutes"}( $self, $conf ) ) {
|
||||
# $self->logger->debug("Module $mod enabled");
|
||||
# push @working, $mod;
|
||||
# }
|
||||
# else {
|
||||
# $links[$i] = undef;
|
||||
# $self->logger->error(
|
||||
# "Module $mod can not be enabled: " . $self->error );
|
||||
# }
|
||||
#}
|
||||
$self->addRoute( links => 'links', ['GET'] );
|
||||
$self->addRoute( 'psgi.js' => 'sendJs', ['GET'] );
|
||||
|
||||
|
@ -88,13 +109,14 @@ sub init {
|
|||
);
|
||||
|
||||
# Avoid restricted users to access configuration by default route
|
||||
my $defaultMod = $self->{defaultModule} || 'conf';
|
||||
my $defaultMod = $self->{defaultModule} =
|
||||
$self->{defaultModule} || $enabledModules[0];
|
||||
$self->logger->debug("Default module -> $defaultMod");
|
||||
my ($index) =
|
||||
grep { $working[$_] =~ /::$defaultMod$/i } ( 0 .. $#working );
|
||||
$index //= $#working;
|
||||
grep { $enabledModules[$_] eq $defaultMod } ( 0 .. $#enabledModules );
|
||||
$index //= 0;
|
||||
$self->logger->debug("Default index -> $index");
|
||||
$self->defaultRoute( $working[$index]->defaultRoute );
|
||||
$self->defaultRoute( $self->loadedPlugins->[$index]->defaultRoute );
|
||||
|
||||
# Find out more glyphicones at https://www.w3schools.com/icons/bootstrap_icons_glyphicons.asp
|
||||
my $linksIcons = {
|
||||
|
@ -110,7 +132,7 @@ sub init {
|
|||
next unless ( defined $links[$i] );
|
||||
push @{ $self->links },
|
||||
{
|
||||
target => $enabledModules[$i]->defaultRoute,
|
||||
target => $self->loadedPlugins->[$i]->defaultRoute,
|
||||
title => $links[$i],
|
||||
icon => $linksIcons->{ $links[$i] }
|
||||
};
|
||||
|
@ -141,15 +163,20 @@ sub init {
|
|||
|
||||
sub tplParams {
|
||||
my ( $self, $req ) = @_;
|
||||
my $res = $self->brwRule->( $req, $req->{userData} ) || 0;
|
||||
my $res = eval {
|
||||
$self->hLoadedPlugins->{viewer}->brwRule->( $req, $req->{userData} );
|
||||
} || 0;
|
||||
return ( VERSION => $VERSION, ALLOWBROWSER => $res );
|
||||
}
|
||||
|
||||
sub javascript {
|
||||
my ( $self, $req ) = @_;
|
||||
my $res = $self->diffRule->( $req, $req->{userData} ) || 0;
|
||||
my $impPrefix = $self->{impersonationPrefix};
|
||||
my $ttl = $self->{timeout} || 72000;
|
||||
my $res = eval {
|
||||
$self->hLoadedPlugins->{viewer}->diffRule->( $req, $req->{userData} );
|
||||
} || 0;
|
||||
print STDERR $@ if $@;
|
||||
my $impPrefix = $self->{impersonationPrefix} || 'real_';
|
||||
my $ttl = $self->{timeout} || 72000;
|
||||
|
||||
return
|
||||
'var formPrefix=staticPrefix+"forms/";var confPrefix=scriptname+"confs/";var viewPrefix=scriptname+"view/";'
|
||||
|
@ -176,6 +203,32 @@ sub sendHtml {
|
|||
return $res;
|
||||
}
|
||||
|
||||
sub loadPlugin {
|
||||
my ( $self, $plugin, $conf ) = @_;
|
||||
unless ($plugin) {
|
||||
require Carp;
|
||||
Carp::confess('Calling loadPugin without arg !');
|
||||
}
|
||||
my $obj;
|
||||
$plugin = "Lemonldap::NG::Manager$plugin" if ( $plugin =~ /^::/ );
|
||||
|
||||
eval "require $plugin";
|
||||
if ($@) {
|
||||
$self->logger->error("$plugin load error: $@");
|
||||
return 0;
|
||||
}
|
||||
eval {
|
||||
$obj = $plugin->new( { p => $self, conf => $conf } );
|
||||
$self->logger->debug("Module $plugin loaded");
|
||||
};
|
||||
if ($@) {
|
||||
$self->error("Unable to build $plugin object: $@");
|
||||
return 0;
|
||||
}
|
||||
( $obj and $obj->init($conf) ) or return 0;
|
||||
return $obj;
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ use Lemonldap::NG::Common::Conf::ReConstants;
|
|||
|
||||
use feature 'state';
|
||||
|
||||
extends 'Lemonldap::NG::Common::Conf::AccessLib',
|
||||
extends 'Lemonldap::NG::Manager::Plugin',
|
||||
'Lemonldap::NG::Common::Conf::AccessLib',
|
||||
'Lemonldap::NG::Common::Session::REST';
|
||||
|
||||
our $VERSION = '2.1.0';
|
||||
|
@ -24,7 +25,7 @@ our $VERSION = '2.1.0';
|
|||
|
||||
use constant defaultRoute => '2ndfa.html';
|
||||
|
||||
sub addRoutes {
|
||||
sub init {
|
||||
my ( $self, $conf ) = @_;
|
||||
|
||||
# Remote Procedure are defined in Lemonldap::NG::Common::Session::REST
|
||||
|
@ -46,6 +47,7 @@ sub addRoutes {
|
|||
$self->{multiValuesSeparator} ||= '; ';
|
||||
$self->{hiddenAttributes} //= "_password";
|
||||
$self->{TOTPCheck} = $self->{U2FCheck} = $self->{UBKCheck} = '1';
|
||||
return 1;
|
||||
}
|
||||
|
||||
###################
|
||||
|
|
|
@ -5,14 +5,15 @@ use 5.10.0;
|
|||
use utf8;
|
||||
use Mouse;
|
||||
|
||||
extends 'Lemonldap::NG::Common::Conf::RESTServer',
|
||||
extends 'Lemonldap::NG::Manager::Plugin',
|
||||
'Lemonldap::NG::Common::Conf::RESTServer',
|
||||
'Lemonldap::NG::Common::Session::REST';
|
||||
|
||||
use Lemonldap::NG::Manager::Api::2F;
|
||||
use Lemonldap::NG::Manager::Api::Providers::OidcRp;
|
||||
use Lemonldap::NG::Manager::Api::Providers::SamlSp;
|
||||
|
||||
our $VERSION = '2.0.7';
|
||||
our $VERSION = '2.0.8';
|
||||
|
||||
#############################
|
||||
# I. INITIALIZATION METHODS #
|
||||
|
@ -20,7 +21,7 @@ our $VERSION = '2.0.7';
|
|||
|
||||
use constant defaultRoute => 'api.html';
|
||||
|
||||
sub addRoutes {
|
||||
sub init {
|
||||
my ( $self, $conf ) = @_;
|
||||
|
||||
# HTML template
|
||||
|
@ -148,6 +149,7 @@ sub addRoutes {
|
|||
$self->{multiValuesSeparator} ||= '; ';
|
||||
$self->{hiddenAttributes} //= "_password";
|
||||
$self->{TOTPCheck} = $self->{U2FCheck} = $self->{UBKCheck} = '1';
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -60,8 +60,8 @@ sub _hasAllowedAttributes {
|
|||
|
||||
sub _listAttributes {
|
||||
my ( $self, $rootNode ) = @_;
|
||||
my $mainTree = Lemonldap::NG::Manager::Build::CTrees::cTrees();
|
||||
my $rootNodes = [ grep { ref($_) eq "HASH" } @{ $mainTree->{$rootNode} } ];
|
||||
my $mainTree = Lemonldap::NG::Manager::Build::CTrees::cTrees();
|
||||
my $rootNodes = [ grep { ref($_) eq "HASH" } @{ $mainTree->{$rootNode} } ];
|
||||
my @attributes = map { $self->_listNodeAttributes($_) } @$rootNodes;
|
||||
|
||||
return @attributes;
|
||||
|
|
|
@ -621,6 +621,14 @@ sub attributes {
|
|||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'bruteForceProtectionIncrementalTempo' => {
|
||||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'bruteForceProtectionLockTimes' => {
|
||||
'default' => '5 15 60 300 600',
|
||||
'type' => 'text'
|
||||
},
|
||||
'bruteForceProtectionMaxAge' => {
|
||||
'default' => 300,
|
||||
'type' => 'int'
|
||||
|
@ -629,6 +637,10 @@ sub attributes {
|
|||
'default' => 3,
|
||||
'type' => 'int'
|
||||
},
|
||||
'bruteForceProtectionMaxLockTime' => {
|
||||
'default' => 900,
|
||||
'type' => 'int'
|
||||
},
|
||||
'bruteForceProtectionTempo' => {
|
||||
'default' => 30,
|
||||
'type' => 'int'
|
||||
|
@ -1326,6 +1338,10 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
|
|||
},
|
||||
'type' => 'keyTextContainer'
|
||||
},
|
||||
'groupsBeforeMacros' => {
|
||||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'handlerInternalCache' => {
|
||||
'default' => 15,
|
||||
'type' => 'int'
|
||||
|
@ -1883,6 +1899,14 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
|
|||
'default' => 'uid reference date title subtitle text check',
|
||||
'type' => 'text'
|
||||
},
|
||||
'notificationsExplorer' => {
|
||||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'notificationsMaxRetrieve' => {
|
||||
'default' => 3,
|
||||
'type' => 'int'
|
||||
},
|
||||
'notificationStorage' => {
|
||||
'default' => 'File',
|
||||
'type' => 'PerlModule'
|
||||
|
@ -2422,6 +2446,10 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
|
|||
qr/^(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-9]*[a-zA-Z0-9]|[a-zA-Z])[.]?))?$/,
|
||||
'type' => 'text'
|
||||
},
|
||||
'persistentSessionAttributes' => {
|
||||
'default' => '_loginHistory _2fDevices notification_',
|
||||
'type' => 'text'
|
||||
},
|
||||
'persistentStorage' => {
|
||||
'type' => 'PerlModule'
|
||||
},
|
||||
|
@ -3631,6 +3659,10 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
|
|||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'soapProxyUrn' => {
|
||||
'default' => 'urn:Lemonldap/NG/Common/PSGI/SOAPService',
|
||||
'type' => 'text'
|
||||
},
|
||||
'soapSessionServer' => {
|
||||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
|
@ -3652,7 +3684,10 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
|
|||
},
|
||||
'SSLVarIf' => {
|
||||
'default' => {},
|
||||
'type' => 'keyTextContainer'
|
||||
'keyTest' => sub {
|
||||
1;
|
||||
},
|
||||
'type' => 'keyTextContainer'
|
||||
},
|
||||
'staticPrefix' => {
|
||||
'type' => 'text'
|
||||
|
|
|
@ -456,15 +456,16 @@ our \$VERSION = '$Lemonldap::NG::Manager::Build::Attributes::VERSION';
|
|||
use constant HANDLER => 'Lemonldap::NG::Handler::PSGI::Main';
|
||||
use constant {
|
||||
EOF
|
||||
for my $pe ( sort { $portalConstants{$a} <=> $portalConstants{$b} }
|
||||
keys %portalConstants )
|
||||
for my $pe (
|
||||
sort { $portalConstants{$a} <=> $portalConstants{$b} }
|
||||
keys %portalConstants
|
||||
)
|
||||
{
|
||||
my $str = $portalConstants{$pe};
|
||||
$content .= " $pe => $str,\n";
|
||||
}
|
||||
|
||||
my $exports = join ", ",
|
||||
map { "'$_'" }
|
||||
my $exports = join ", ", map { "'$_'" }
|
||||
sort { $portalConstants{$a} <=> $portalConstants{$b} }
|
||||
keys %portalConstants;
|
||||
|
||||
|
@ -569,7 +570,7 @@ sub scanTree {
|
|||
# Subnode
|
||||
elsif ( ref($leaf) ) {
|
||||
$jleaf->{title} = $jleaf->{id} = $leaf->{title};
|
||||
$jleaf->{type} = $leaf->{form} if ( $leaf->{form} );
|
||||
$jleaf->{type} = $leaf->{form} if ( $leaf->{form} );
|
||||
if ( $leaf->{title} =~ /^((?:oidc|saml|cas)Service)MetaData$/ ) {
|
||||
no strict 'refs';
|
||||
my @tmp = $self->scanLeaf( $leaf->{nodes} );
|
||||
|
|
|
@ -358,7 +358,7 @@ sub attributes {
|
|||
msgFail => '__badUrl__',
|
||||
},
|
||||
portalCustomCss => {
|
||||
type => 'text',
|
||||
type => 'text',
|
||||
documentation => 'Path to custom CSS file',
|
||||
},
|
||||
portalStatus => {
|
||||
|
@ -413,6 +413,11 @@ sub attributes {
|
|||
type => 'text',
|
||||
documentation => 'Prefix of static files for HTML templates',
|
||||
},
|
||||
groupsBeforeMacros => {
|
||||
type => 'bool',
|
||||
default => 0,
|
||||
documentation => 'Compute groups before macros',
|
||||
},
|
||||
multiValuesSeparator => {
|
||||
type => 'authParamsText',
|
||||
default => '; ',
|
||||
|
@ -788,6 +793,23 @@ sub attributes {
|
|||
documentation =>
|
||||
'Brute force attack protection -> Max allowed failed login',
|
||||
},
|
||||
bruteForceProtectionMaxLockTime => {
|
||||
default => 900,
|
||||
type => 'int',
|
||||
documentation =>
|
||||
'Brute force attack protection -> Max lock time',
|
||||
},
|
||||
bruteForceProtectionIncrementalTempo => {
|
||||
default => 0,
|
||||
help => 'bruteforceprotection.html',
|
||||
type => 'bool',
|
||||
documentation => 'Enable incremental lock time for brute force attack protection',
|
||||
},
|
||||
bruteForceProtectionLockTimes => {
|
||||
type => 'text',
|
||||
default => '5 15 60 300 600',
|
||||
documentation => 'Incremental lock time values for brute force attack protection',
|
||||
},
|
||||
grantSessionRules => {
|
||||
type => 'grantContainer',
|
||||
keyTest => sub { return perlExpr(@_) },
|
||||
|
@ -800,6 +822,11 @@ sub attributes {
|
|||
default => '_password _2fDevices',
|
||||
documentation => 'Name of attributes to hide in logs',
|
||||
},
|
||||
persistentSessionAttributes => {
|
||||
type => 'text',
|
||||
default => '_loginHistory _2fDevices notification_',
|
||||
documentation => 'Persistent session attributes to hide',
|
||||
},
|
||||
key => {
|
||||
type => 'password',
|
||||
documentation => 'Secret key',
|
||||
|
@ -1142,6 +1169,16 @@ sub attributes {
|
|||
type => 'bool',
|
||||
documentation => 'Notification activation',
|
||||
},
|
||||
notificationsExplorer => {
|
||||
default => 0,
|
||||
type => 'bool',
|
||||
documentation => 'Notifications explorer activation',
|
||||
},
|
||||
notificationsMaxRetrieve => {
|
||||
default => 3,
|
||||
type => 'int',
|
||||
documentation => 'Max number of displayed notifications',
|
||||
},
|
||||
notificationServer => {
|
||||
default => 0,
|
||||
type => 'bool',
|
||||
|
@ -1985,6 +2022,13 @@ sub attributes {
|
|||
documentation => 'Enable /portal.wsdl server',
|
||||
},
|
||||
|
||||
# SOAP Procy client
|
||||
soapProxyUrn => {
|
||||
default => 'urn:Lemonldap/NG/Common/PSGI/SOAPService',
|
||||
type => 'text',
|
||||
documentation => 'SOAP URN for Proxy',
|
||||
},
|
||||
|
||||
# AutoSignin
|
||||
autoSigninRules => {
|
||||
type => 'keyTextContainer',
|
||||
|
@ -3159,6 +3203,7 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
|||
},
|
||||
SSLVarIf => {
|
||||
type => 'keyTextContainer',
|
||||
keyTest => sub { 1 },
|
||||
default => {}
|
||||
},
|
||||
sslByAjax => {
|
||||
|
|
|
@ -584,7 +584,7 @@ sub tree {
|
|||
{
|
||||
title => 'reloadParams',
|
||||
help => 'configlocation.html#configuration_reload',
|
||||
nodes => [ 'reloadUrls', 'reloadTimeout', 'compactConf' ]
|
||||
nodes => [ 'reloadTimeout', 'compactConf', 'reloadUrls' ]
|
||||
},
|
||||
{
|
||||
title => 'plugins',
|
||||
|
@ -620,11 +620,12 @@ sub tree {
|
|||
help => 'notifications.html',
|
||||
nodes => [
|
||||
'notification',
|
||||
'notificationsExplorer',
|
||||
'notificationWildcard',
|
||||
'oldNotifFormat',
|
||||
'notificationXSLTfile',
|
||||
'notificationStorage',
|
||||
'notificationStorageOptions',
|
||||
'notificationWildcard',
|
||||
'notificationXSLTfile',
|
||||
{
|
||||
title => 'serverNotification',
|
||||
help => 'notifications.html#server',
|
||||
|
@ -818,6 +819,25 @@ sub tree {
|
|||
'u2fLogo',
|
||||
]
|
||||
},
|
||||
{
|
||||
title => 'yubikey2f',
|
||||
help => 'yubikey2f.html',
|
||||
form => 'simpleInputContainer',
|
||||
nodes => [
|
||||
'yubikey2fActivation',
|
||||
'yubikey2fSelfRegistration',
|
||||
'yubikey2fClientID',
|
||||
'yubikey2fSecretKey',
|
||||
'yubikey2fNonce',
|
||||
'yubikey2fUrl',
|
||||
'yubikey2fPublicIDSize',
|
||||
'yubikey2fUserCanRemoveKey',
|
||||
'yubikey2fTTL',
|
||||
'yubikey2fAuthnLevel',
|
||||
'yubikey2fLabel',
|
||||
'yubikey2fLogo',
|
||||
],
|
||||
},
|
||||
{
|
||||
title => 'mail2f',
|
||||
help => 'mail2f.html',
|
||||
|
@ -865,25 +885,6 @@ sub tree {
|
|||
'rest2fLabel', 'rest2fLogo',
|
||||
]
|
||||
},
|
||||
{
|
||||
title => 'yubikey2f',
|
||||
help => 'yubikey2f.html',
|
||||
form => 'simpleInputContainer',
|
||||
nodes => [
|
||||
'yubikey2fActivation',
|
||||
'yubikey2fSelfRegistration',
|
||||
'yubikey2fClientID',
|
||||
'yubikey2fSecretKey',
|
||||
'yubikey2fNonce',
|
||||
'yubikey2fUrl',
|
||||
'yubikey2fPublicIDSize',
|
||||
'yubikey2fUserCanRemoveKey',
|
||||
'yubikey2fTTL',
|
||||
'yubikey2fAuthnLevel',
|
||||
'yubikey2fLabel',
|
||||
'yubikey2fLogo',
|
||||
],
|
||||
},
|
||||
'sfExtra',
|
||||
{
|
||||
title => 'sfRemovedNotification',
|
||||
|
@ -904,6 +905,7 @@ sub tree {
|
|||
nodes => [
|
||||
'customFunctions',
|
||||
'multiValuesSeparator',
|
||||
'groupsBeforeMacros',
|
||||
{
|
||||
title => 'SMTP',
|
||||
help => 'smtp.html',
|
||||
|
@ -937,12 +939,21 @@ sub tree {
|
|||
'trustedDomains',
|
||||
'useSafeJail',
|
||||
'checkXSS',
|
||||
'bruteForceProtection',
|
||||
'requireToken',
|
||||
'formTimeout',
|
||||
'tokenUseGlobalStorage',
|
||||
{
|
||||
title => 'bruteForceAttackProtection',
|
||||
help => 'bruteforceprotection.html',
|
||||
form => 'simpleInputContainer',
|
||||
nodes => [
|
||||
'bruteForceProtection',
|
||||
'bruteForceProtectionIncrementalTempo',
|
||||
]
|
||||
},
|
||||
'lwpOpts',
|
||||
'lwpSslOpts',
|
||||
|
||||
{
|
||||
title => 'contentSecurityPolicy',
|
||||
help => 'security.html#portal',
|
||||
|
|
|
@ -26,6 +26,7 @@ has req => ( is => 'ro' );
|
|||
has sep => ( is => 'rw', isa => 'Str', default => '/' );
|
||||
has format => ( is => 'rw', isa => 'Str', default => "%-25s | %-25s | %-25s" );
|
||||
has yes => ( is => 'rw', isa => 'Bool', default => 0 );
|
||||
has safe => ( is => 'rw', isa => 'Bool', default => 0 );
|
||||
has force => ( is => 'rw', isa => 'Bool', default => 0 );
|
||||
has logger => ( is => 'ro', lazy => 1, builder => sub { $_[0]->mgr->logger } );
|
||||
has userLogger =>
|
||||
|
@ -75,7 +76,7 @@ sub set {
|
|||
}
|
||||
}
|
||||
require Clone;
|
||||
my $new = Clone::clone( $self->mgr->currentConf );
|
||||
my $new = Clone::clone( $self->mgr->hLoadedPlugins->{conf}->currentConf );
|
||||
foreach my $key ( keys %pairs ) {
|
||||
$self->_setKey( $new, $key, $pairs{$key} );
|
||||
}
|
||||
|
@ -100,7 +101,7 @@ sub addKey {
|
|||
push @list, [ $root, $newKey, $value ];
|
||||
}
|
||||
require Clone;
|
||||
my $new = Clone::clone( $self->mgr->currentConf );
|
||||
my $new = Clone::clone( $self->mgr->hLoadedPlugins->{conf}->currentConf );
|
||||
foreach my $el (@list) {
|
||||
my @path = split $sep, $el->[0];
|
||||
if ( $#path == 0 ) {
|
||||
|
@ -141,7 +142,7 @@ sub delKey {
|
|||
push @list, [ $root, $key ];
|
||||
}
|
||||
require Clone;
|
||||
my $new = Clone::clone( $self->mgr->currentConf );
|
||||
my $new = Clone::clone( $self->mgr->hLoadedPlugins->{conf}->currentConf );
|
||||
foreach my $el (@list) {
|
||||
my @path = split $sep, $el->[0];
|
||||
if ( $#path == 0 ) {
|
||||
|
@ -199,7 +200,7 @@ sub lastCfg {
|
|||
|
||||
sub save {
|
||||
my ($self) = @_;
|
||||
my $conf = $self->jsonResponse( '/confs/latest', 'full=1' );
|
||||
my $conf = $self->jsonResponse( '/confs/' . $self->cfgNum, 'full=1' );
|
||||
my $json = JSON->new->indent->canonical;
|
||||
print $json->encode($conf);
|
||||
}
|
||||
|
@ -228,6 +229,33 @@ sub restore {
|
|||
print STDERR Dumper($res);
|
||||
}
|
||||
|
||||
sub rollback {
|
||||
my ($self) = @_;
|
||||
my $lastCfg = $self->mgr->confAcc->lastCfg;
|
||||
my $previousCfg = $lastCfg - 1;
|
||||
my $conf =
|
||||
$self->mgr->confAcc->getConf( { cfgNum => $previousCfg, raw => 1 } )
|
||||
or die $Lemonldap::NG::Common::Conf::msg;
|
||||
|
||||
$conf->{cfgNum} = $lastCfg;
|
||||
$conf->{cfgAuthor} = scalar( getpwuid $< ) . '(command-line-interface)';
|
||||
chomp $conf->{cfgAuthor};
|
||||
$conf->{cfgAuthorIP} = '127.0.0.1';
|
||||
$conf->{cfgDate} = time;
|
||||
$conf->{cfgVersion} = $Lemonldap::NG::Manager::VERSION;
|
||||
$conf->{cfgLog} = $self->log // "Rolled back configuration $lastCfg";
|
||||
|
||||
my $s = $self->mgr->confAcc->saveConf($conf);
|
||||
if ( $s > 0 ) {
|
||||
$self->logger->info("CLI: Configuration $lastCfg has been rolled back");
|
||||
print STDERR "Configuration $lastCfg has been rolled back\n";
|
||||
}
|
||||
else {
|
||||
$self->logger->error("CLI: Failed to rollback configuration $lastCfg");
|
||||
print STDERR "Failed to rollback configuration $lastCfg\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub _getKey {
|
||||
my ( $self, $key ) = @_;
|
||||
my $sep = $self->sep;
|
||||
|
@ -236,7 +264,8 @@ sub _getKey {
|
|||
warn "Malformed key $base";
|
||||
return ();
|
||||
}
|
||||
my $value = $self->mgr->getConfKey( $self->req, $base, noCache => 1 );
|
||||
my $value = $self->mgr->hLoadedPlugins->{conf}
|
||||
->getConfKey( $self->req, $base, noCache => 1 );
|
||||
if ( $self->req->error ) {
|
||||
die $self->req->error;
|
||||
}
|
||||
|
@ -272,14 +301,19 @@ sub _save {
|
|||
require Lemonldap::NG::Manager::Conf::Parser;
|
||||
my $parser = Lemonldap::NG::Manager::Conf::Parser->new( {
|
||||
newConf => $new,
|
||||
refConf => $self->mgr->currentConf,
|
||||
refConf => $self->mgr->hLoadedPlugins->{conf}->currentConf,
|
||||
req => $self->req
|
||||
}
|
||||
);
|
||||
unless ( $parser->testNewConf( $self->localConf ) ) {
|
||||
$self->logger->error(
|
||||
"CLI: Configuration rejected with message: $parser->{message}");
|
||||
printf STDERR "Modifications rejected: %s:\n", $parser->{message};
|
||||
my $msg = "Configuration rejected with message: " . $parser->message;
|
||||
$self->logger->error("CLI: $msg");
|
||||
if ( $self->safe ) {
|
||||
die "$msg";
|
||||
}
|
||||
else {
|
||||
print STDERR "$msg\n";
|
||||
}
|
||||
}
|
||||
my $saveParams = { force => $self->force };
|
||||
if ( $self->force and $self->cfgNum ) {
|
||||
|
@ -304,11 +338,13 @@ sub _save {
|
|||
"CLI: Configuration $s has been saved by $new->{cfgAuthor}");
|
||||
$self->logger->info("CLI: Configuration $s saved");
|
||||
print STDERR "Saved under number $s\n";
|
||||
$parser->{status} = [ $self->mgr->applyConf($new) ];
|
||||
$parser->{status} =
|
||||
[ $self->mgr->hLoadedPlugins->{conf}->applyConf($new) ];
|
||||
}
|
||||
else {
|
||||
$self->logger->error("CLI: Configuration not saved!");
|
||||
printf STDERR "Modifications rejected: %s:\n", $parser->{message};
|
||||
printf STDERR "Modifications rejected: %s:\n", $parser->{message}
|
||||
if $parser->{message};
|
||||
print STDERR Dumper($parser);
|
||||
}
|
||||
foreach (qw(errors warnings status)) {
|
||||
|
@ -346,7 +382,7 @@ sub run {
|
|||
}
|
||||
$self->cfgNum( $self->lastCfg ) unless ( $self->cfgNum );
|
||||
my $action = shift;
|
||||
unless ( $action =~ /^(?:get|set|addKey|delKey|save|restore)$/ ) {
|
||||
unless ( $action =~ /^(?:get|set|addKey|delKey|save|restore|rollback)$/ ) {
|
||||
die "Unknown action $action. Only get, set, addKey or delKey allowed";
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@ use URI::URL;
|
|||
|
||||
use feature 'state';
|
||||
|
||||
extends 'Lemonldap::NG::Common::Conf::RESTServer';
|
||||
extends 'Lemonldap::NG::Manager::Plugin',
|
||||
'Lemonldap::NG::Common::Conf::RESTServer';
|
||||
|
||||
our $VERSION = '2.1.0';
|
||||
|
||||
|
@ -27,36 +28,11 @@ our $VERSION = '2.1.0';
|
|||
|
||||
use constant defaultRoute => 'manager.html';
|
||||
|
||||
has ua => ( is => 'rw' );
|
||||
has diffRule => ( is => 'rw', default => sub { 0 } );
|
||||
has brwRule => ( is => 'rw', default => sub { 0 } );
|
||||
has ua => ( is => 'rw' );
|
||||
|
||||
sub addRoutes {
|
||||
sub init {
|
||||
my ( $self, $conf ) = @_;
|
||||
$self->ua( Lemonldap::NG::Common::UserAgent->new($conf) );
|
||||
my $hd = "Lemonldap::NG::Handler::PSGI::Main";
|
||||
|
||||
# Parse Diff activation rule
|
||||
$self->logger->debug(
|
||||
"Diff activation rule -> " . ( $self->{viewerAllowDiff} // 0 ) );
|
||||
my $rule = $hd->buildSub( $hd->substitute( $self->{viewerAllowDiff} ) );
|
||||
unless ($rule) {
|
||||
$self->error(
|
||||
"Bad Diff activation rule -> " . $hd->tsv->{jail}->error );
|
||||
return 0;
|
||||
}
|
||||
$self->diffRule($rule);
|
||||
|
||||
# Parse Browser activation rule
|
||||
$self->logger->debug(
|
||||
"Browser activation rule -> " . ( $self->{viewerAllowBrowser} // 0 ) );
|
||||
$rule = $hd->buildSub( $hd->substitute( $self->{viewerAllowBrowser} ) );
|
||||
unless ($rule) {
|
||||
$self->error(
|
||||
"Bad Browser activation rule -> " . $hd->tsv->{jail}->error );
|
||||
return 0;
|
||||
}
|
||||
$self->brwRule($rule);
|
||||
|
||||
# HTML template
|
||||
$self->addRoute( 'manager.html', undef, ['GET'] )
|
||||
|
@ -95,6 +71,7 @@ sub addRoutes {
|
|||
|
||||
# Url loader
|
||||
->addRoute( 'prx', undef, ['POST'] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
# 35 - New RSA key pair on demand
|
||||
|
@ -268,7 +245,7 @@ sub newConf {
|
|||
}
|
||||
}
|
||||
if ( $res->{result} ) {
|
||||
if ( $self->{demoMode} ) {
|
||||
if ( $self->p->{demoMode} ) {
|
||||
$res->{message} = '__demoModeOn__';
|
||||
}
|
||||
else {
|
||||
|
@ -279,7 +256,7 @@ sub newConf {
|
|||
unless ( @{ $parser->{needConfirmation} } && !$args{force} );
|
||||
if ( $s > 0 ) {
|
||||
$self->userLogger->notice(
|
||||
'User ' . $self->userId($req) . " has stored conf $s" );
|
||||
'User ' . $self->p->userId($req) . " has stored conf $s" );
|
||||
$res->{result} = 1;
|
||||
$res->{cfgNum} = $s;
|
||||
if ( my $status = $self->applyConf( $parser->newConf ) ) {
|
||||
|
@ -291,7 +268,7 @@ sub newConf {
|
|||
else {
|
||||
$self->userLogger->notice(
|
||||
'Saving attempt rejected, asking for confirmation to '
|
||||
. $self->userId($req) );
|
||||
. $self->p->userId($req) );
|
||||
$res->{result} = 0;
|
||||
if ( $s == CONFIG_WAS_CHANGED ) {
|
||||
$res->{needConfirm} = 1;
|
||||
|
@ -324,7 +301,7 @@ sub newRawConf {
|
|||
}
|
||||
|
||||
my $res = {};
|
||||
if ( $self->{demoMode} ) {
|
||||
if ( $self->p->{demoMode} ) {
|
||||
$res->{message} = '__demoModeOn__';
|
||||
}
|
||||
else {
|
||||
|
@ -332,15 +309,16 @@ sub newRawConf {
|
|||
# chances to be equal to last config cfgNum
|
||||
my $s = $self->confAcc->saveConf( $new, force => 1 );
|
||||
if ( $s > 0 ) {
|
||||
$self->userLogger->notice(
|
||||
'User ' . $self->userId($req) . " has stored (raw) conf $s" );
|
||||
$self->userLogger->notice( 'User '
|
||||
. $self->p->userId($req)
|
||||
. " has stored (raw) conf $s" );
|
||||
$res->{result} = 1;
|
||||
$res->{cfgNum} = $s;
|
||||
}
|
||||
else {
|
||||
$self->userLogger->notice(
|
||||
'Raw saving attempt rejected, asking for confirmation to '
|
||||
. $self->userId($req) );
|
||||
. $self->p->userId($req) );
|
||||
$res->{result} = 0;
|
||||
$res->{needConfirm} = 1 if ( $s == CONFIG_WAS_CHANGED );
|
||||
$res->{message} .= '__needConfirmation__';
|
||||
|
@ -359,7 +337,7 @@ sub applyConf {
|
|||
my $status;
|
||||
|
||||
# 1 Apply conf locally
|
||||
$self->api->checkConf();
|
||||
$self->p->api->checkConf();
|
||||
|
||||
# Get apply section values
|
||||
my %reloadUrls =
|
||||
|
|
|
@ -51,7 +51,10 @@ has changes => ( is => 'rw', isa => 'ArrayRef', default => sub { return [] } );
|
|||
has message => (
|
||||
is => 'rw',
|
||||
isa => 'Str',
|
||||
default => '',
|
||||
lazy => 1,
|
||||
default => sub {
|
||||
return join( ', ', map { $_->{message} } @{ $_[0]->errors } );
|
||||
},
|
||||
trigger => sub {
|
||||
hdebug( "Message becomes " . $_[0]->{message} );
|
||||
}
|
||||
|
@ -1111,7 +1114,8 @@ sub _unitTest {
|
|||
my $res = 1;
|
||||
|
||||
foreach my $key ( keys %$conf ) {
|
||||
if ( $localConf->{skippedUnitTests}
|
||||
if ( $localConf
|
||||
and $localConf->{skippedUnitTests}
|
||||
and $localConf->{skippedUnitTests} =~ /\b$key\b/ )
|
||||
{
|
||||
$localConf->logger->debug("-> Ignore test for $key\n");
|
||||
|
@ -1121,7 +1125,8 @@ sub _unitTest {
|
|||
my $attr = $attrs->{$key};
|
||||
my $type = $types->{ $attr->{type} } if $attr;
|
||||
unless ( $type or $attr->{test} ) {
|
||||
$localConf->logger->debug("Unknown attribute $key, deleting it\n");
|
||||
$localConf->logger->debug("Unknown attribute $key, deleting it\n")
|
||||
if $localConf;
|
||||
delete $conf->{$key};
|
||||
next;
|
||||
}
|
||||
|
@ -1156,8 +1161,6 @@ sub _unitTest {
|
|||
if ( $key =~ /^(?:$simpleHashKeys|$doubleHashKeys)$/o
|
||||
or $attr->{type} =~ /Container$/ )
|
||||
{
|
||||
my $keyMsg = $attr->{keyMsgFail} // $type->{keyMsgFail};
|
||||
my $msg = $attr->{msgFail} // $type->{msgFail};
|
||||
$res = 0
|
||||
unless (
|
||||
$self->_execTest( {
|
||||
|
@ -1244,8 +1247,7 @@ sub _execTest {
|
|||
#
|
||||
#@return true if tests succeed
|
||||
sub _globalTest {
|
||||
my $self = shift;
|
||||
my $localConf = shift;
|
||||
my ( $self, $localConf ) = @_;
|
||||
|
||||
require Lemonldap::NG::Manager::Conf::Tests;
|
||||
hdebug('# _globalTest()');
|
||||
|
@ -1253,10 +1255,12 @@ sub _globalTest {
|
|||
my $tests = &Lemonldap::NG::Manager::Conf::Tests::tests( $self->newConf );
|
||||
|
||||
foreach my $name ( keys %$tests ) {
|
||||
if ( $localConf->{skippedGlobalTests}
|
||||
if ( $localConf
|
||||
and $localConf->{skippedGlobalTests}
|
||||
and $localConf->{skippedGlobalTests} =~ /\b$name\b/ )
|
||||
{
|
||||
$localConf->logger->debug("-> Ignore test for $name\n");
|
||||
$localConf->logger->debug("-> Ignore test for $name\n")
|
||||
if $localConf;
|
||||
next;
|
||||
}
|
||||
my $sub = $tests->{$name};
|
||||
|
@ -1278,7 +1282,7 @@ sub _globalTest {
|
|||
};
|
||||
if ($@) {
|
||||
push @{ $self->warnings }, "Test $name failed: $@";
|
||||
$localConf->logger->debug("Test $name failed: $@\n");
|
||||
$localConf->logger->debug("Test $name failed: $@\n") if $localConf;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
|
|
|
@ -607,11 +607,11 @@ sub tests {
|
|||
|
||||
# Warn if issuers token TTL is higher than 30s
|
||||
issuersTimeout => sub {
|
||||
return 1 unless ( defined $conf->{issuerTimeout} );
|
||||
return 1 unless ( defined $conf->{issuersTimeout} );
|
||||
return ( 0, "Issuers token TTL must be higher than 30s" )
|
||||
unless ( $conf->{issuerTimeout} > 30 );
|
||||
unless ( $conf->{issuersTimeout} > 30 );
|
||||
return ( 1, "Issuers token TTL should not be higher than 2mn" )
|
||||
if ( $conf->{issuerTimeout} > 120 );
|
||||
if ( $conf->{issuersTimeout} > 120 );
|
||||
|
||||
# Return
|
||||
return 1;
|
||||
|
@ -755,6 +755,27 @@ sub tests {
|
|||
return ( $res, join( ', ', @msg ) );
|
||||
},
|
||||
|
||||
# RS* OIDC algs require a signing key
|
||||
oidcRPNeedRSAKey => sub {
|
||||
return 1
|
||||
unless ( $conf->{oidcRPMetaDataOptions}
|
||||
and %{ $conf->{oidcRPMetaDataOptions} } );
|
||||
my @usingRSA = grep {
|
||||
$conf->{oidcRPMetaDataOptions}->{$_}
|
||||
->{oidcRPMetaDataOptionsIDTokenSignAlg}
|
||||
and $conf->{oidcRPMetaDataOptions}->{$_}
|
||||
->{oidcRPMetaDataOptionsIDTokenSignAlg} =~ /^RS/
|
||||
} keys %{ $conf->{oidcRPMetaDataOptions} };
|
||||
|
||||
if ( @usingRSA and not $conf->{oidcServicePrivateKeySig} ) {
|
||||
my $msg =
|
||||
join( ", ", @usingRSA )
|
||||
. ": using RS-type encryption, but no RSA key is defined in global OIDC configuration";
|
||||
return ( 0, $msg );
|
||||
}
|
||||
return 1;
|
||||
},
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ require Lemonldap::NG::Common::Notifications;
|
|||
|
||||
use feature 'state';
|
||||
|
||||
extends 'Lemonldap::NG::Common::Conf::AccessLib';
|
||||
extends 'Lemonldap::NG::Manager::Plugin',
|
||||
'Lemonldap::NG::Common::Conf::AccessLib';
|
||||
|
||||
our $VERSION = '2.1.0';
|
||||
|
||||
|
@ -26,7 +27,7 @@ has notifFormat => ( is => 'rw' );
|
|||
|
||||
use constant defaultRoute => 'notifications.html';
|
||||
|
||||
sub addRoutes {
|
||||
sub init {
|
||||
my ( $self, $conf ) = @_;
|
||||
|
||||
if ( $conf->{oldNotifFormat} ) {
|
||||
|
@ -74,6 +75,7 @@ sub addRoutes {
|
|||
{ done => { ':notificationId' => 'deleteDoneNotification' } },
|
||||
['DELETE']
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub setNotifAccess {
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package Lemonldap::NG::Manager::Plugin;
|
||||
|
||||
use strict;
|
||||
use Mouse;
|
||||
our $VERSION = '2.0.8';
|
||||
|
||||
extends 'Lemonldap::NG::Common::Module';
|
||||
|
||||
has _confAcc => (
|
||||
is => 'rw',
|
||||
lazy => 1,
|
||||
default => sub { return $_[0]->p->{_confAcc} },
|
||||
);
|
||||
|
||||
sub sendError {
|
||||
my $self = shift;
|
||||
return $self->p->sendError(@_);
|
||||
}
|
||||
|
||||
sub sendJSONresponse {
|
||||
my $self = shift;
|
||||
return $self->p->sendJSONresponse(@_);
|
||||
}
|
||||
|
||||
sub addRoute {
|
||||
my ( $self, $word, $subName, $methods, $transform ) = @_;
|
||||
$transform //= sub {
|
||||
my ($sub) = @_;
|
||||
if ( ref $sub ) {
|
||||
return sub {
|
||||
shift;
|
||||
return $sub->( $self, @_ );
|
||||
}
|
||||
}
|
||||
else {
|
||||
return sub {
|
||||
shift;
|
||||
return $self->$sub(@_);
|
||||
}
|
||||
}
|
||||
};
|
||||
$self->p->addRoute( $word, $subName, $methods, $transform );
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub loadTemplate {
|
||||
my $self = shift;
|
||||
return $self->p->loadTemplate(@_);
|
||||
}
|
||||
|
||||
1;
|
|
@ -14,7 +14,8 @@ use Lemonldap::NG::Common::IPv6;
|
|||
|
||||
use feature 'state';
|
||||
|
||||
extends 'Lemonldap::NG::Common::Conf::AccessLib',
|
||||
extends 'Lemonldap::NG::Manager::Plugin',
|
||||
'Lemonldap::NG::Common::Conf::AccessLib',
|
||||
'Lemonldap::NG::Common::Session::REST';
|
||||
|
||||
our $VERSION = '2.1.0';
|
||||
|
@ -25,7 +26,7 @@ our $VERSION = '2.1.0';
|
|||
|
||||
use constant defaultRoute => 'sessions.html';
|
||||
|
||||
sub addRoutes {
|
||||
sub init {
|
||||
my ( $self, $conf ) = @_;
|
||||
|
||||
# HTML template
|
||||
|
@ -55,6 +56,7 @@ sub addRoutes {
|
|||
$self->{multiValuesSeparator} ||= '; ';
|
||||
$self->{impersonationPrefix} = $conf->{impersonationPrefix} || 'real_';
|
||||
$self->{hiddenAttributes} //= "_password";
|
||||
return 1;
|
||||
}
|
||||
|
||||
#######################
|
||||
|
@ -98,7 +100,7 @@ sub sessions {
|
|||
or return $self->sendError( $req, undef, 400 );
|
||||
my $params = $req->parameters();
|
||||
my $type = delete $params->{sessionType};
|
||||
$type = $type eq 'global' ? 'SSO' : ucfirst($type);
|
||||
$type = $type eq 'global' ? 'SSO' : ucfirst($type);
|
||||
$type = $type eq 'Offline' ? 'OIDCI' : ucfirst($type);
|
||||
|
||||
my $res;
|
||||
|
|
|
@ -11,6 +11,9 @@ use feature 'state';
|
|||
|
||||
extends 'Lemonldap::NG::Manager::Conf';
|
||||
|
||||
has diffRule => ( is => 'rw', default => sub { 0 } );
|
||||
has brwRule => ( is => 'rw', default => sub { 0 } );
|
||||
|
||||
our $VERSION = '2.1.0';
|
||||
|
||||
#############################
|
||||
|
@ -21,11 +24,36 @@ use constant defaultRoute => 'viewer.html';
|
|||
|
||||
has ua => ( is => 'rw' );
|
||||
|
||||
sub addRoutes {
|
||||
sub init {
|
||||
my ( $self, $conf ) = @_;
|
||||
$self->ua( Lemonldap::NG::Common::UserAgent->new($conf) );
|
||||
my $hd = "Lemonldap::NG::Handler::PSGI::Main";
|
||||
|
||||
my $hiddenKeys = $self->{viewerHiddenKeys} || '';
|
||||
# Parse Diff activation rule
|
||||
$conf->{viewerAllowDiff} //= 0;
|
||||
$self->logger->debug(
|
||||
"Diff activation rule -> " . ( $conf->{viewerAllowDiff} ) );
|
||||
my $rule = $hd->buildSub( $hd->substitute( $conf->{viewerAllowDiff} ) );
|
||||
unless ($rule) {
|
||||
$self->logger->error(
|
||||
"Bad Diff activation rule -> " . $hd->tsv->{jail}->error );
|
||||
return 0;
|
||||
}
|
||||
$self->diffRule($rule);
|
||||
|
||||
# Parse Browser activation rule
|
||||
$conf->{viewerAllowBrowser} //= 0;
|
||||
$self->logger->debug(
|
||||
"Browser activation rule -> " . ( $conf->{viewerAllowBrowser} ) );
|
||||
$rule = $hd->buildSub( $hd->substitute( $conf->{viewerAllowBrowser} ) );
|
||||
unless ($rule) {
|
||||
$self->logger->error(
|
||||
"Bad Browser activation rule -> " . $hd->tsv->{jail}->error );
|
||||
return 0;
|
||||
}
|
||||
$self->brwRule($rule);
|
||||
|
||||
my $hiddenKeys = $conf->{viewerHiddenKeys} || '';
|
||||
my @enabledKeys = ();
|
||||
my @keys = qw(virtualHosts samlIDPMetaDataNodes samlSPMetaDataNodes
|
||||
applicationList oidcOPMetaDataNodes oidcRPMetaDataNodes
|
||||
|
@ -67,6 +95,7 @@ sub addRoutes {
|
|||
|
||||
# Other keys
|
||||
->addRoute( view => { ':cfgNum' => { '*' => 'viewKey' } }, ['GET'] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub getConfByNum {
|
||||
|
@ -80,7 +109,8 @@ sub viewDiff {
|
|||
# Check Diff activation rule
|
||||
unless ( $self->diffRule->( $req, $req->{userData} ) ) {
|
||||
my $user = $req->{userData}->{_whatToTrace} || 'anonymous';
|
||||
$self->userLogger->warn("$user is not authorized to compare configurations");
|
||||
$self->userLogger->warn(
|
||||
"$user is not authorized to compare configurations");
|
||||
return $self->sendJSONresponse( $req, { 'value' => '_Hidden_' } );
|
||||
}
|
||||
|
||||
|
@ -144,7 +174,8 @@ sub viewKey {
|
|||
$self->logger->debug(
|
||||
" $req->{env}->{REQUEST_URI} -> URI FORBIDDEN");
|
||||
my $user = $req->{userData}->{_whatToTrace} || 'anonymous';
|
||||
$self->userLogger->warn("$user is not authorized to browse configurations");
|
||||
$self->userLogger->warn(
|
||||
"$user is not authorized to browse configurations");
|
||||
$self->rejectKey( $req, @args );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,18 +63,17 @@ if (`diff $refFile $editFile`) {
|
|||
# Update author and date
|
||||
$VAR1->{cfgAuthor} = $ENV{SUDO_USER} || $ENV{LOGNAME} || "lmConfigEditor";
|
||||
$VAR1->{cfgAuthorIP} = $ENV{SSH_CONNECTION} || "localhost";
|
||||
$VAR1->{cfgDate} = time();
|
||||
$VAR1->{cfgDate} = time();
|
||||
$VAR1->{cfgLog} ||= 'Edited by lmConfigEditor';
|
||||
|
||||
# Test new configuration
|
||||
my $parser = Lemonldap::NG::Manager::Conf::Parser->new(
|
||||
{
|
||||
my $parser = Lemonldap::NG::Manager::Conf::Parser->new( {
|
||||
refConf => $refConf,
|
||||
newConf => $VAR1,
|
||||
req => 1,
|
||||
}
|
||||
);
|
||||
unless ( $parser->testNewConf ) {
|
||||
unless ( $parser->testNewConf(undef) ) {
|
||||
print STDERR "Configuration seems to have some errors:\n ";
|
||||
print STDERR Dumper(
|
||||
{ errors => $parser->errors, warnings => $parser->warnings } );
|
||||
|
|
|
@ -13,7 +13,7 @@ displayError = (j, status, err) ->
|
|||
console.log 'Error', err
|
||||
res = JSON.parse j.responseText
|
||||
if res and res.error
|
||||
res = res.error.replace /.* /, ''
|
||||
res = res.error.replace(/.* /, '')
|
||||
console.log 'Returned error', res
|
||||
setMsg res, 'warning'
|
||||
|
||||
|
|
|
@ -193,6 +193,14 @@ llapp.controller 'NotificationsExplorerCtrl', [ '$scope', '$translator', '$locat
|
|||
, (resp) ->
|
||||
$scope.waiting = false
|
||||
|
||||
# Highlight current selection
|
||||
console.log "Selection", $scope.type
|
||||
$scope.activesStyle = {color: '#777'}
|
||||
$scope.doneStyle = {color: '#777'}
|
||||
$scope.newStyle = {color: '#777'}
|
||||
$scope.activesStyle = {color: '#333'} if $scope.type == 'actives'
|
||||
$scope.doneStyle = {color: '#333'} if $scope.type == 'done'
|
||||
|
||||
$scope.displayNotification = (scope) ->
|
||||
$scope.waiting = true
|
||||
$scope.currentScope = scope
|
||||
|
@ -206,11 +214,16 @@ llapp.controller 'NotificationsExplorerCtrl', [ '$scope', '$translator', '$locat
|
|||
reference: node.reference
|
||||
condition: node.condition
|
||||
if $scope.type == 'actives'
|
||||
notif = JSON.parse response.data.notifications
|
||||
$scope.currentNotification.text = notif.text
|
||||
$scope.currentNotification.title = notif.title
|
||||
$scope.currentNotification.subtitle = notif.subtitle
|
||||
$scope.currentNotification.notifications = response.data.notifications
|
||||
try
|
||||
console.log "Try to parse a JSON formated notification..."
|
||||
notif = JSON.parse response.data.notifications
|
||||
$scope.currentNotification.date = $scope.notifDate(notif.date)
|
||||
$scope.currentNotification.text = notif.text
|
||||
$scope.currentNotification.title = notif.title
|
||||
$scope.currentNotification.subtitle = notif.subtitle
|
||||
catch e
|
||||
console.log "Unable to parse JSON"
|
||||
$scope.currentNotification.notifications = response.data.notifications
|
||||
else
|
||||
$scope.currentNotification.done = response.data.done
|
||||
$scope.waiting = false
|
||||
|
@ -266,16 +279,19 @@ llapp.controller 'NotificationsExplorerCtrl', [ '$scope', '$translator', '$locat
|
|||
message: data.error
|
||||
$scope.showModal "alert.html"
|
||||
$scope.waiting = false
|
||||
$scope.form.date = new Date()
|
||||
, (response) ->
|
||||
$scope.message =
|
||||
title: 'notificationNotCreated'
|
||||
message: response.statusText
|
||||
$scope.showModal "alert.html"
|
||||
$scope.waiting = false
|
||||
$scope.form.date = new Date()
|
||||
else
|
||||
$scope.message =
|
||||
title: 'incompleteForm'
|
||||
$scope.showModal "alert.html"
|
||||
$scope.form.date = new Date()
|
||||
|
||||
$scope.init = ->
|
||||
$scope.waiting = true
|
||||
|
@ -297,6 +313,9 @@ llapp.controller 'NotificationsExplorerCtrl', [ '$scope', '$translator', '$locat
|
|||
$scope.myStyle = {color: '#ffb84d'}
|
||||
|
||||
$scope.displayCreateForm = ->
|
||||
$scope.activesStyle = {color: '#777'}
|
||||
$scope.doneStyle = {color: '#777'}
|
||||
$scope.newStyle = {color: '#333'}
|
||||
$scope.waiting = true
|
||||
$translator.init($scope.lang).then ->
|
||||
$scope.currentNotification = null
|
||||
|
|
|
@ -492,6 +492,15 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
|||
, (resp) ->
|
||||
$scope.waiting = false
|
||||
|
||||
# Highlight current selection
|
||||
console.log "Selection", sessionType
|
||||
$scope.navssoStyle = {color: '#777'}
|
||||
$scope.offlineStyle = {color: '#777'}
|
||||
$scope.persistentStyle = {color: '#777'}
|
||||
$scope.navssoStyle = {color: '#333'} if sessionType == 'global'
|
||||
$scope.offlineStyle = {color: '#333'} if sessionType == 'offline'
|
||||
$scope.persistentStyle = {color: '#333'} if sessionType == 'persistent'
|
||||
|
||||
# Intialization function
|
||||
# Simply set $scope.waiting to false during $translator and tree root
|
||||
# initialization
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row text-center">
|
||||
<div class="col-md-2" ng-repeat="i in ['attach.png', 'bell.png', 'bookmark.png', 'configure.png', 'database.png', 'demo.png', 'docs.png', 'folder.png', 'gear.png', 'help.png', 'llng.png', 'mailappt.png', 'money.png', 'network.png', 'terminal.png', 'thumbnail.png','tools.png', 'tux.png', 'web.png', 'wheels.png']">
|
||||
<div class="col-md-2" ng-repeat="i in ['attach.png', 'bell.png', 'bookmark.png', 'configure.png', 'database.png', 'demo.png', 'folder.png', 'gear.png', 'help.png', 'llng.png', 'mailappt.png', 'money.png', 'terminal.png', 'thumbnail.png', 'tux.png', 'web.png']">
|
||||
<button class="btn llcontainer" ng-class="{'btn-default':currentNode.data.logo!=i,'btn-info':currentNode.data.logo==i}" ng-click="ok(currentNode.data.logo=i)">
|
||||
<img ng-src="{{elem('portal').data}}static/common/apps/{{i}}" title="{{i}}" alt="{{i}}" />
|
||||
</button>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Generated by CoffeeScript 1.12.7
|
||||
// Generated by CoffeeScript 1.12.8
|
||||
|
||||
/*
|
||||
* 2ndFA Session explorer
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -195,7 +195,7 @@
|
|||
over = 0;
|
||||
}
|
||||
if ($scope.type === 'done' || $scope.type === 'actives') {
|
||||
return $http.get(scriptname + "notifications/" + $scope.type + "?" + query).then(function(response) {
|
||||
$http.get(scriptname + "notifications/" + $scope.type + "?" + query).then(function(response) {
|
||||
var data, i, len, n, ref;
|
||||
data = response.data;
|
||||
if (data.result) {
|
||||
|
@ -221,6 +221,26 @@
|
|||
return $scope.waiting = false;
|
||||
});
|
||||
}
|
||||
console.log("Selection", $scope.type);
|
||||
$scope.activesStyle = {
|
||||
color: '#777'
|
||||
};
|
||||
$scope.doneStyle = {
|
||||
color: '#777'
|
||||
};
|
||||
$scope.newStyle = {
|
||||
color: '#777'
|
||||
};
|
||||
if ($scope.type === 'actives') {
|
||||
$scope.activesStyle = {
|
||||
color: '#333'
|
||||
};
|
||||
}
|
||||
if ($scope.type === 'done') {
|
||||
return $scope.doneStyle = {
|
||||
color: '#333'
|
||||
};
|
||||
}
|
||||
};
|
||||
$scope.displayNotification = function(scope) {
|
||||
var node, notificationId;
|
||||
|
@ -232,18 +252,25 @@
|
|||
notificationId = node.uid + "_" + node.reference;
|
||||
}
|
||||
$http.get(scriptname + "notifications/" + $scope.type + "/" + notificationId).then(function(response) {
|
||||
var notif;
|
||||
var e, notif;
|
||||
$scope.currentNotification = {
|
||||
uid: node.uid,
|
||||
reference: node.reference,
|
||||
condition: node.condition
|
||||
};
|
||||
if ($scope.type === 'actives') {
|
||||
notif = JSON.parse(response.data.notifications);
|
||||
$scope.currentNotification.text = notif.text;
|
||||
$scope.currentNotification.title = notif.title;
|
||||
$scope.currentNotification.subtitle = notif.subtitle;
|
||||
$scope.currentNotification.notifications = response.data.notifications;
|
||||
try {
|
||||
console.log("Try to parse a JSON formated notification...");
|
||||
notif = JSON.parse(response.data.notifications);
|
||||
$scope.currentNotification.date = $scope.notifDate(notif.date);
|
||||
$scope.currentNotification.text = notif.text;
|
||||
$scope.currentNotification.title = notif.title;
|
||||
$scope.currentNotification.subtitle = notif.subtitle;
|
||||
} catch (error) {
|
||||
e = error;
|
||||
console.log("Unable to parse JSON");
|
||||
$scope.currentNotification.notifications = response.data.notifications;
|
||||
}
|
||||
} else {
|
||||
$scope.currentNotification.done = response.data.done;
|
||||
}
|
||||
|
@ -300,7 +327,7 @@
|
|||
$scope.formPost.reference = $scope.form.reference;
|
||||
$scope.formPost.condition = $scope.form.condition;
|
||||
$scope.formPost.xml = $scope.form.xml;
|
||||
return $http.post('notifications/actives', $scope.formPost).then(function(response) {
|
||||
$http.post('notifications/actives', $scope.formPost).then(function(response) {
|
||||
var data;
|
||||
data = response.data;
|
||||
$scope.form = {};
|
||||
|
@ -315,21 +342,24 @@
|
|||
};
|
||||
}
|
||||
$scope.showModal("alert.html");
|
||||
return $scope.waiting = false;
|
||||
$scope.waiting = false;
|
||||
return $scope.form.date = new Date();
|
||||
}, function(response) {
|
||||
$scope.message = {
|
||||
title: 'notificationNotCreated',
|
||||
message: response.statusText
|
||||
};
|
||||
$scope.showModal("alert.html");
|
||||
return $scope.waiting = false;
|
||||
$scope.waiting = false;
|
||||
return $scope.form.date = new Date();
|
||||
});
|
||||
} else {
|
||||
$scope.message = {
|
||||
title: 'incompleteForm'
|
||||
};
|
||||
return $scope.showModal("alert.html");
|
||||
$scope.showModal("alert.html");
|
||||
}
|
||||
return $scope.form.date = new Date();
|
||||
};
|
||||
$scope.init = function() {
|
||||
$scope.waiting = true;
|
||||
|
@ -349,6 +379,15 @@
|
|||
};
|
||||
};
|
||||
$scope.displayCreateForm = function() {
|
||||
$scope.activesStyle = {
|
||||
color: '#777'
|
||||
};
|
||||
$scope.doneStyle = {
|
||||
color: '#777'
|
||||
};
|
||||
$scope.newStyle = {
|
||||
color: '#333'
|
||||
};
|
||||
$scope.waiting = true;
|
||||
return $translator.init($scope.lang).then(function() {
|
||||
$scope.currentNotification = null;
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -537,7 +537,7 @@
|
|||
} else {
|
||||
over = 0;
|
||||
}
|
||||
return $http.get(scriptname + "sessions/" + sessionType + "?" + query).then(function(response) {
|
||||
$http.get(scriptname + "sessions/" + sessionType + "?" + query).then(function(response) {
|
||||
var data, i, len, n, ref;
|
||||
data = response.data;
|
||||
if (data.result) {
|
||||
|
@ -565,6 +565,31 @@
|
|||
}, function(resp) {
|
||||
return $scope.waiting = false;
|
||||
});
|
||||
console.log("Selection", sessionType);
|
||||
$scope.navssoStyle = {
|
||||
color: '#777'
|
||||
};
|
||||
$scope.offlineStyle = {
|
||||
color: '#777'
|
||||
};
|
||||
$scope.persistentStyle = {
|
||||
color: '#777'
|
||||
};
|
||||
if (sessionType === 'global') {
|
||||
$scope.navssoStyle = {
|
||||
color: '#333'
|
||||
};
|
||||
}
|
||||
if (sessionType === 'offline') {
|
||||
$scope.offlineStyle = {
|
||||
color: '#333'
|
||||
};
|
||||
}
|
||||
if (sessionType === 'persistent') {
|
||||
return $scope.persistentStyle = {
|
||||
color: '#333'
|
||||
};
|
||||
}
|
||||
};
|
||||
$scope.init = function() {
|
||||
$scope.waiting = true;
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -104,7 +104,9 @@
|
|||
"browserIdSiteName":"اسم الموقع",
|
||||
"browserIdVerificationURL":"التحقق في اليو آر إل",
|
||||
"browseTree":"تصفح الهيكل",
|
||||
"bruteForceProtection":"Brute-force attack protection",
|
||||
"bruteForceProtection":"Activation",
|
||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
||||
"cancel":"إلغاء",
|
||||
"captcha_login_enabled":"التفعيل في استمارة تسجيل الدخول",
|
||||
"captcha_mail_enabled":"التفعيل في إعادة تعيين كلمة المرور بواسطة استمارة البريد",
|
||||
|
@ -142,7 +144,7 @@
|
|||
"casStorageOptions":" خيارات وحدة جلسات كاس",
|
||||
"categoryName":"اسم الفئة",
|
||||
"cda":"نطاقات متعددة",
|
||||
"certificateMailContent":"Certificate mail content",
|
||||
"certificateMailContent":"Mail content",
|
||||
"certificateResetByMailManagement":"Certificate management",
|
||||
"certificateResetByMailURL":"Reset page URL",
|
||||
"certificateResetByMailCeaAttribute":"Certificate attibute name",
|
||||
|
@ -175,7 +177,7 @@
|
|||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"استئنف",
|
||||
"cfgLog":"Summary",
|
||||
"cfgVersion":"عملية ضبط الإصدارات",
|
||||
"checkXSS":"تحقق من هجمات XSS",
|
||||
"clickHereToForce":"انقر هنا لإجبار",
|
||||
|
@ -326,6 +328,7 @@
|
|||
"gpgParams":"GPG parameters",
|
||||
"grantSessionRules":"ظروف الافتتاح",
|
||||
"groups":"المجموعات",
|
||||
"groupsBeforeMacros":"Compute groups before macros",
|
||||
"hashkey":"المفتاح",
|
||||
"headers":"هيدر إتش تي تي بي ",
|
||||
"hGroups":"المجموعات (هاش ريف)",
|
||||
|
@ -459,7 +462,7 @@
|
|||
"mailCharset":"charset",
|
||||
"mailConfirmBody":"تأكيد محتوى البريد",
|
||||
"mailConfirmSubject":"تأكيد عنوان بريد",
|
||||
"mailContent":"Password mail content",
|
||||
"mailContent":"Mail content",
|
||||
"mailFrom":"مرسل البريد",
|
||||
"mailHeaders":"هيدر البريد",
|
||||
"mailLDAPFilter":"فلتر البريد",
|
||||
|
@ -526,6 +529,7 @@
|
|||
"notificationDeleted":"تم حذف الإشعار",
|
||||
"notificationDone":"انتهى الإشعار",
|
||||
"notificationsDone":"انتهت الإشعارات",
|
||||
"notificationsExplorer":"Explorer",
|
||||
"notificationNotCreated":"لم يتم إنشاء الإشعار",
|
||||
"notificationNotDeleted":"لم يتم وضع علامة على الإشعار بأنه تم الاطلاع عليه",
|
||||
"notificationNotFound":"لم يتم العثور على الإشعار",
|
||||
|
@ -801,7 +805,7 @@
|
|||
"saveReport":"احفظ التقرير",
|
||||
"savingConfirmation":"حفظ التأكيد",
|
||||
"scope":"نطاق",
|
||||
"search":"Search ...",
|
||||
"search":"Search...",
|
||||
"secondFactors":"Second factors",
|
||||
"securedCookie":"ملفات تعريف الارتباط المضمونة (سسل)",
|
||||
"security":"الحماية",
|
||||
|
@ -1111,4 +1115,4 @@
|
|||
"samlRelayStateTimeout":"تناوب حالة مهلة الجلسة ",
|
||||
"samlUseQueryStringSpecific":"استخدام أسلوب query_string المعين",
|
||||
"samlOverrideIDPEntityID":"Override Entity ID when acting as IDP"
|
||||
}
|
||||
}
|
|
@ -104,7 +104,9 @@
|
|||
"browserIdSiteName":"Site name",
|
||||
"browserIdVerificationURL":"Verification URL",
|
||||
"browseTree":"Browse tree",
|
||||
"bruteForceProtection":"Brute-force attack protection",
|
||||
"bruteForceProtection":"Activation",
|
||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
||||
"cancel":"Abbrechen",
|
||||
"captcha_login_enabled":"Activation in login form",
|
||||
"captcha_mail_enabled":"Activation in password reset by mail form",
|
||||
|
@ -142,7 +144,7 @@
|
|||
"casStorageOptions":"CAS sessions module options",
|
||||
"categoryName":"Category name",
|
||||
"cda":"Mehrere Domains",
|
||||
"certificateMailContent":"Certificate mail content",
|
||||
"certificateMailContent":"Mail content",
|
||||
"certificateResetByMailManagement":"Certificate management",
|
||||
"certificateResetByMailURL":"Reset page URL",
|
||||
"certificateResetByMailCeaAttribute":"Certificate CEA attibute",
|
||||
|
@ -175,7 +177,7 @@
|
|||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"Resume",
|
||||
"cfgLog":"Summary",
|
||||
"cfgVersion":"Configuration version",
|
||||
"checkXSS":"Check XSS attacks",
|
||||
"clickHereToForce":"Click here to force",
|
||||
|
@ -326,6 +328,7 @@
|
|||
"gpgParams":"GPG parameters",
|
||||
"grantSessionRules":"Opening conditions",
|
||||
"groups":"Groups",
|
||||
"groupsBeforeMacros":"Compute groups before macros",
|
||||
"hashkey":"Key",
|
||||
"headers":"HTTP Headers",
|
||||
"hGroups":"Groups (HashRef)",
|
||||
|
@ -459,7 +462,7 @@
|
|||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Confirmation mail content",
|
||||
"mailConfirmSubject":"Confirmation mail subject",
|
||||
"mailContent":"Password mail content",
|
||||
"mailContent":"Mail content",
|
||||
"mailFrom":"Mail sender",
|
||||
"mailHeaders":"Mail headers",
|
||||
"mailLDAPFilter":"Mail filter",
|
||||
|
@ -526,6 +529,7 @@
|
|||
"notificationDeleted":"Notification deleted",
|
||||
"notificationDone":"Notification done",
|
||||
"notificationsDone":"Notifications done",
|
||||
"notificationsExplorer":"Explorer",
|
||||
"notificationNotCreated":"The notification was not created",
|
||||
"notificationNotDeleted":"The notification was not marked as done",
|
||||
"notificationNotFound":"The notification was not found",
|
||||
|
@ -801,7 +805,7 @@
|
|||
"saveReport":"Save report",
|
||||
"savingConfirmation":"Saving confirmation",
|
||||
"scope":"Scope",
|
||||
"search":"Search ...",
|
||||
"search":"Search...",
|
||||
"secondFactors":"Second factors",
|
||||
"securedCookie":"Secured Cookie (SSL)",
|
||||
"security":"Security",
|
||||
|
@ -1111,4 +1115,4 @@
|
|||
"samlRelayStateTimeout":"RelayState session timeout",
|
||||
"samlUseQueryStringSpecific":"Use specific query_string method",
|
||||
"samlOverrideIDPEntityID":"Override Entity ID when acting as IDP"
|
||||
}
|
||||
}
|
|
@ -104,7 +104,9 @@
|
|||
"browserIdSiteName":"Site name",
|
||||
"browserIdVerificationURL":"Verification URL",
|
||||
"browseTree":"Browse tree",
|
||||
"bruteForceProtection":"Brute-force attack protection",
|
||||
"bruteForceProtection":"Activation",
|
||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
||||
"cancel":"Cancel",
|
||||
"captcha_login_enabled":"Activation in login form",
|
||||
"captcha_mail_enabled":"Activation in password reset by mail form",
|
||||
|
@ -142,7 +144,7 @@
|
|||
"casStorageOptions":"CAS sessions module options",
|
||||
"categoryName":"Category name",
|
||||
"cda":"Multiple domains",
|
||||
"certificateMailContent":"Certificate mail content",
|
||||
"certificateMailContent":"Mail content",
|
||||
"certificateResetByMailManagement":"Certificate management",
|
||||
"certificateResetByMailURL":"Reset page URL",
|
||||
"certificateResetByMailCeaAttribute":"Certificate CEA attibute",
|
||||
|
@ -326,6 +328,7 @@
|
|||
"gpgParams":"GPG parameters",
|
||||
"grantSessionRules":"Opening conditions",
|
||||
"groups":"Groups",
|
||||
"groupsBeforeMacros":"Compute groups before macros",
|
||||
"hashkey":"Key",
|
||||
"headers":"HTTP Headers",
|
||||
"hGroups":"Groups (HashRef)",
|
||||
|
@ -459,7 +462,7 @@
|
|||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Confirmation mail content",
|
||||
"mailConfirmSubject":"Confirmation mail subject",
|
||||
"mailContent":"Password mail content",
|
||||
"mailContent":"Mail content",
|
||||
"mailFrom":"Mail sender",
|
||||
"mailHeaders":"Mail headers",
|
||||
"mailLDAPFilter":"Mail filter",
|
||||
|
@ -526,6 +529,7 @@
|
|||
"notificationDeleted":"Notification deleted",
|
||||
"notificationDone":"Notification done",
|
||||
"notificationsDone":"Notifications done",
|
||||
"notificationsExplorer":"Explorer",
|
||||
"notificationNotCreated":"The notification was not created",
|
||||
"notificationNotDeleted":"The notification was not marked as done",
|
||||
"notificationNotFound":"The notification was not found",
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
"actives":"Actives",
|
||||
"activeTimer":"Délai d'acceptation automatique",
|
||||
"addAppCasPartner":"Ajouter une application CAS",
|
||||
"addIDPSamlPartner":"Ajouter un IDP SAML",
|
||||
"addIDPSamlPartner":"Ajouter un FI SAML",
|
||||
"addOidcOp":"Ajouter un fournisseur OpenID Connect",
|
||||
"addOidcRp":"Ajouter un client OpenID Connect",
|
||||
"addSamlAttribute":"Ajouter un attribut",
|
||||
"addSPSamlPartner":"Ajouter un SP SAML",
|
||||
"addSPSamlPartner":"Ajouter un FS SAML",
|
||||
"addSrvCasPartner":"Ajouter un serveur CAS",
|
||||
"addU2FKey":"Ajouter une clef U2F",
|
||||
"addTOTPKey":"Ajouter une clef TOTP",
|
||||
|
@ -104,7 +104,9 @@
|
|||
"browserIdSiteName":"Nom du site",
|
||||
"browserIdVerificationURL":"Adresse de vérification",
|
||||
"browseTree":"Parcourir l'arbre",
|
||||
"bruteForceProtection":"Protection contre les attaques par force brute",
|
||||
"bruteForceProtection":"Activation",
|
||||
"bruteForceAttackProtection":"Protection contre les attaques par force brute",
|
||||
"bruteForceProtectionIncrementalTempo":"Temps de verrouillage incrémentiels",
|
||||
"cancel":"Annuler",
|
||||
"captcha_login_enabled":"Activation dans le formulaire d'authentification",
|
||||
"captcha_mail_enabled":"Activation dans le formulaire de réinitialisation par mail",
|
||||
|
@ -142,7 +144,7 @@
|
|||
"casStorageOptions":"Options du module des sessions CAS",
|
||||
"categoryName":"Nom de la catégorie",
|
||||
"cda":"Domaines multiples",
|
||||
"certificateMailContent":"Contenu du mail du certificat",
|
||||
"certificateMailContent":"Contenu du mail",
|
||||
"certificateResetByMailManagement":"Gestion des certificats",
|
||||
"certificateResetByMailURL":"URL de la page de réinitialisation",
|
||||
"certificateResetByMailCeaAttribute":"Attribut CEA du certificat",
|
||||
|
@ -326,6 +328,7 @@
|
|||
"gpgParams":"Paramètres GPG",
|
||||
"grantSessionRules":"Conditions d'ouverture",
|
||||
"groups":"Groupes",
|
||||
"groupsBeforeMacros":"Calculer les groupes avant les macros",
|
||||
"hashkey":"Clef",
|
||||
"headers":"En-têtes HTTP",
|
||||
"hGroups":"Groupes (HashRef)",
|
||||
|
@ -459,7 +462,7 @@
|
|||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Contenu du message de confirmation",
|
||||
"mailConfirmSubject":"Sujet du message de confirmation",
|
||||
"mailContent":"Contenu du mail de mot de passe",
|
||||
"mailContent":"Contenu du mail",
|
||||
"mailFrom":"Expéditeur du message",
|
||||
"mailHeaders":"En-têtes du mail",
|
||||
"mailLDAPFilter":"Filtre mail",
|
||||
|
@ -526,6 +529,7 @@
|
|||
"notificationDeleted":"La notification a été marquée comme lue",
|
||||
"notificationDone":"Notification validée",
|
||||
"notificationsDone":"Notifications validées",
|
||||
"notificationsExplorer":"Explorateur",
|
||||
"notificationNotCreated":"La notification n'a pas été créée",
|
||||
"notificationNotDeleted":"La notification n'a pas été marquée comme lue",
|
||||
"notificationNotFound":"La notification n'a pas été trouvée",
|
||||
|
@ -817,7 +821,7 @@
|
|||
"sessionStorage":"Stockage des sessions",
|
||||
"sessionTitle":"Contenu de la session",
|
||||
"sfaTitle":"Seconds Facteurs d'Authentification",
|
||||
"sfExtra":"Seconds Facteurs additionnels",
|
||||
"sfExtra":"Seconds facteurs additionnels",
|
||||
"sfRequired":"Exiger 2FA",
|
||||
"sfRemovedNotification":"Afficher un message si un SF expiré a été supprimé",
|
||||
"sfRemovedMsgRule":"Activation",
|
||||
|
|
|
@ -104,7 +104,9 @@
|
|||
"browserIdSiteName":"Nome del sito",
|
||||
"browserIdVerificationURL":"URL di verifica",
|
||||
"browseTree":"Naviga albero",
|
||||
"bruteForceProtection":"Protezione da attacchi brute-force",
|
||||
"bruteForceProtection":"Activation",
|
||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
||||
"cancel":"Cancella",
|
||||
"captcha_login_enabled":"Attivazione nel modulo di login",
|
||||
"captcha_mail_enabled":"Attivazione della reimpostazione della password tramite modulo di posta",
|
||||
|
@ -142,17 +144,17 @@
|
|||
"casStorageOptions":"Opzioni del modulo sessioni CAS",
|
||||
"categoryName":"Nome della categoria",
|
||||
"cda":"Domini multipli",
|
||||
"certificateMailContent":"Certificate mail content",
|
||||
"certificateMailContent":"Mail content",
|
||||
"certificateResetByMailManagement":"Certificate management",
|
||||
"certificateResetByMailURL":"Reset page URL",
|
||||
"certificateResetByMailCeaAttribute":"Certificat CEA attribut",
|
||||
"certificateResetByMailCeaAttribute":"Certificate CEA attibute",
|
||||
"certificateResetByMailCertificateAttribute":"Certificate attribute name",
|
||||
"certificateResetByMailStep1Subject":"Reset mail subject",
|
||||
"certificateResetByMailStep1Body":"Reset mail content",
|
||||
"certificateResetByMailStep2Subject":"Confirmation mail subject",
|
||||
"certificateResetByMailStep2Subject":"Soggetto della mail di conferma",
|
||||
"certificateResetByMailStep2Body":"Confirmation mail content",
|
||||
"certificateResetByMailValidityDelay":"Minimum duration before expiration",
|
||||
"portalDisplayCertificateResetByMail":"Reset your crtificate",
|
||||
"portalDisplayCertificateResetByMail":"Reset your certificate",
|
||||
"contentSecurityPolicy":"Politica di protezione dei contenuti",
|
||||
"contextSwitching":"Switch context another user",
|
||||
"contextSwitchingHiddenAttributes":"Attributi nascosti",
|
||||
|
@ -175,7 +177,7 @@
|
|||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"Riprendi",
|
||||
"cfgLog":"Summary",
|
||||
"cfgVersion":"Versione configurazione",
|
||||
"checkXSS":"Verifica attacchi XSS",
|
||||
"clickHereToForce":"Clicca qui per forzare",
|
||||
|
@ -326,6 +328,7 @@
|
|||
"gpgParams":"Parametri GPG",
|
||||
"grantSessionRules":"Condizioni di apertura",
|
||||
"groups":"Gruppi",
|
||||
"groupsBeforeMacros":"Compute groups before macros",
|
||||
"hashkey":"Chiave",
|
||||
"headers":"Intestazioni HTTP",
|
||||
"hGroups":"Gruppi (HashRef)",
|
||||
|
@ -459,7 +462,7 @@
|
|||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Contenuto della mail di conferma",
|
||||
"mailConfirmSubject":"Soggetto della mail di conferma",
|
||||
"mailContent":"Contenuto della mail di ripristino della password",
|
||||
"mailContent":"Mail content",
|
||||
"mailFrom":"Mittente",
|
||||
"mailHeaders":"Intestazioni di posta",
|
||||
"mailLDAPFilter":"Filtro mail",
|
||||
|
@ -526,6 +529,7 @@
|
|||
"notificationDeleted":"La notifica è stata cancellata",
|
||||
"notificationDone":"La notifica è stata effettuata",
|
||||
"notificationsDone":"Notifiche effettuate",
|
||||
"notificationsExplorer":"Explorer",
|
||||
"notificationNotCreated":"La notifica non è stata creata",
|
||||
"notificationNotDeleted":"La notifica non è stata contrassegnata come eseguita",
|
||||
"notificationNotFound":"La notifica non é stata trovata",
|
||||
|
@ -801,7 +805,7 @@
|
|||
"saveReport":"Salva report",
|
||||
"savingConfirmation":"Salvataggio della conferma",
|
||||
"scope":"Ambito",
|
||||
"search":"Cerca ...",
|
||||
"search":"Cerca...",
|
||||
"secondFactors":"Secondi fattori",
|
||||
"securedCookie":"Cookie protetti (SSL)",
|
||||
"security":"Sicurezza",
|
||||
|
@ -1111,4 +1115,4 @@
|
|||
"samlRelayStateTimeout":"Timeout di sessione di RelayState",
|
||||
"samlUseQueryStringSpecific":"Utilizza il metodo specifico query_string",
|
||||
"samlOverrideIDPEntityID":"Sostituisci l'ID entità quando agisce come IDP"
|
||||
}
|
||||
}
|
|
@ -104,7 +104,9 @@
|
|||
"browserIdSiteName":"Site adı",
|
||||
"browserIdVerificationURL":"Doğrulama URL'i",
|
||||
"browseTree":"Ağaca göz at",
|
||||
"bruteForceProtection":"Kaba kuvvet saldırı koruması",
|
||||
"bruteForceProtection":"Activation",
|
||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
||||
"cancel":"İptal Et",
|
||||
"captcha_login_enabled":"Giriş formunda aktivasyon",
|
||||
"captcha_mail_enabled":"E-posta formu tarafından parola sıfırlamada aktivasyon",
|
||||
|
@ -142,15 +144,15 @@
|
|||
"casStorageOptions":"CAS oturumları modül seçenekleri",
|
||||
"categoryName":"Kategori ismi",
|
||||
"cda":"Çoklu alan adları",
|
||||
"certificateMailContent":"Certificate mail content",
|
||||
"certificateMailContent":"Mail content",
|
||||
"certificateResetByMailManagement":"Certificate management",
|
||||
"certificateResetByMailURL":"Reset page URL",
|
||||
"certificateResetByMailURL":"Sayfa URL'sini sıfırla",
|
||||
"certificateResetByMailCeaAttribute":"Certificate CEA attibute",
|
||||
"certificateResetByMailCertificateAttribute":"Certificate attribute name",
|
||||
"certificateResetByMailStep1Subject":"Reset mail subject",
|
||||
"certificateResetByMailStep1Body":"Reset mail content",
|
||||
"certificateResetByMailStep2Subject":"Confirmation mail subject",
|
||||
"certificateResetByMailStep2Body":"Confirmation mail content",
|
||||
"certificateResetByMailStep2Subject":"Doğrulama e-postası konusu",
|
||||
"certificateResetByMailStep2Body":"Doğrulama e-postası içeriği",
|
||||
"certificateResetByMailValidityDelay":"Minimum duration before expiration",
|
||||
"portalDisplayCertificateResetByMail":"Reset your certificate",
|
||||
"contentSecurityPolicy":"İçerik güvenlik ilkesi",
|
||||
|
@ -175,7 +177,7 @@
|
|||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"Sürdür",
|
||||
"cfgLog":"Summary",
|
||||
"cfgVersion":"Yapılandırma sürümü",
|
||||
"checkXSS":"XSS saldırılarını kontrol et",
|
||||
"clickHereToForce":"Zorlamak için buraya tıklayın",
|
||||
|
@ -326,6 +328,7 @@
|
|||
"gpgParams":"GPG parametreleri",
|
||||
"grantSessionRules":"Açılış koşulları",
|
||||
"groups":"Gruplar",
|
||||
"groupsBeforeMacros":"Compute groups before macros",
|
||||
"hashkey":"Anahtar",
|
||||
"headers":"HTTP Başlıkları",
|
||||
"hGroups":"Gruplar (HashRef)",
|
||||
|
@ -459,7 +462,7 @@
|
|||
"mailCharset":"Karakter seti",
|
||||
"mailConfirmBody":"Doğrulama e-postası içeriği",
|
||||
"mailConfirmSubject":"Doğrulama e-postası konusu",
|
||||
"mailContent":"Parola sıfırlama e-postası içeriği",
|
||||
"mailContent":"Mail content",
|
||||
"mailFrom":"E-posta göndericisi",
|
||||
"mailHeaders":"E-posta başlıkları",
|
||||
"mailLDAPFilter":"E-posta filtresi",
|
||||
|
@ -526,6 +529,7 @@
|
|||
"notificationDeleted":"Bildirim silindi",
|
||||
"notificationDone":"Bildirim tamamlandı",
|
||||
"notificationsDone":"Bildirimler tamamlandı",
|
||||
"notificationsExplorer":"Explorer",
|
||||
"notificationNotCreated":"Bildirim oluşturulmadı",
|
||||
"notificationNotDeleted":"Bildirim tamamlandı olarak işaretlenmedi",
|
||||
"notificationNotFound":"Bildirim bulunamadı",
|
||||
|
@ -672,7 +676,7 @@
|
|||
"passwordDB":"Parola modülü",
|
||||
"passwordManagement":"Parola yönetimi",
|
||||
"passwordPolicyMinSize":"Minimum parola uzunluğu",
|
||||
"passwordPolicyMinLower":"Minimum küçük harf karakter sayısı:",
|
||||
"passwordPolicyMinLower":"Minimum küçük harf karakter sayısı",
|
||||
"passwordPolicyMinUpper":"Minimum büyük harf karakter sayısı",
|
||||
"passwordPolicyMinDigit":"Minimum rakam karakter sayısı",
|
||||
"passwordResetAllowedRetries":"Maksimum parola sıfırlama denemesi",
|
||||
|
@ -801,7 +805,7 @@
|
|||
"saveReport":"Raporu kaydet",
|
||||
"savingConfirmation":"Doğrulama kaydediliyor",
|
||||
"scope":"Kapsam",
|
||||
"search":"Ara ...",
|
||||
"search":"Ara...",
|
||||
"secondFactors":"İki faktörlü kimlik doğrulama",
|
||||
"securedCookie":"Güvenli Çerez (SSL)",
|
||||
"security":"Güvenlik",
|
||||
|
@ -1111,4 +1115,4 @@
|
|||
"samlRelayStateTimeout":"RelayState oturum zaman aşımı",
|
||||
"samlUseQueryStringSpecific":"Spesifik query_string metodu kullan",
|
||||
"samlOverrideIDPEntityID":"IDP olarak davrandığında Varlık ID'yi geçersiz kıl"
|
||||
}
|
||||
}
|
|
@ -104,7 +104,9 @@
|
|||
"browserIdSiteName":"Tên trang web",
|
||||
"browserIdVerificationURL":"URL xác minh",
|
||||
"browseTree":"Duyệt cây",
|
||||
"bruteForceProtection":"Brute-force attack protection",
|
||||
"bruteForceProtection":"Activation",
|
||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
||||
"cancel":"Hủy",
|
||||
"captcha_login_enabled":"Kích hoạt ở dạng đăng nhập",
|
||||
"captcha_mail_enabled":"Kích hoạt đặt lại mật khẩu bằng biểu mẫu thư",
|
||||
|
@ -142,7 +144,7 @@
|
|||
"casStorageOptions":"Các tùy chọn mô-đun phiên CAS",
|
||||
"categoryName":"Tên thể loại",
|
||||
"cda":"Nhiều tên miền",
|
||||
"certificateMailContent":"Certificate mail content",
|
||||
"certificateMailContent":"Mail content",
|
||||
"certificateResetByMailManagement":"Certificate management",
|
||||
"certificateResetByMailURL":"Reset page URL",
|
||||
"certificateResetByMailCeaAttribute":"Certificate CEA attibute",
|
||||
|
@ -175,7 +177,7 @@
|
|||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"Tiếp tục",
|
||||
"cfgLog":"Summary",
|
||||
"cfgVersion":"Phiên bản cấu hình",
|
||||
"checkXSS":"Kiểm tra tấn công XSS",
|
||||
"clickHereToForce":"Nhấp vào đây để bắt buộc",
|
||||
|
@ -326,6 +328,7 @@
|
|||
"gpgParams":"Tham số GPG",
|
||||
"grantSessionRules":"Điều kiện mở",
|
||||
"groups":"Nhóm",
|
||||
"groupsBeforeMacros":"Compute groups before macros",
|
||||
"hashkey":"Khóa",
|
||||
"headers":"Tiêu đề HTTP",
|
||||
"hGroups":"Nhóm (HashRef)",
|
||||
|
@ -459,7 +462,7 @@
|
|||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Xác nhận nội dung thư",
|
||||
"mailConfirmSubject":"Xác nhận chủ đề thư",
|
||||
"mailContent":"Password mail content",
|
||||
"mailContent":"Mail content",
|
||||
"mailFrom":"Người gửi thư",
|
||||
"mailHeaders":"Tiêu đề thư",
|
||||
"mailLDAPFilter":"Bộ lọc thư",
|
||||
|
@ -526,6 +529,7 @@
|
|||
"notificationDeleted":"Thông báo đã xoá",
|
||||
"notificationDone":"Thông báo được thực hiện",
|
||||
"notificationsDone":"Thông báo đã hoàn tất",
|
||||
"notificationsExplorer":"Explorer",
|
||||
"notificationNotCreated":"Thông báo không được tạo ra",
|
||||
"notificationNotDeleted":"Thông báo không được đánh dấu là đã hoàn tất",
|
||||
"notificationNotFound":"Không tìm thấy thông báo",
|
||||
|
@ -801,7 +805,7 @@
|
|||
"saveReport":"Lưu báo cáo",
|
||||
"savingConfirmation":"Lưu xác nhận",
|
||||
"scope":"Phạm vi",
|
||||
"search":"Search ...",
|
||||
"search":"Search...",
|
||||
"secondFactors":"Second factors",
|
||||
"securedCookie":"Cookie bảo mật (SSL)",
|
||||
"security":"An ninh",
|
||||
|
@ -1111,4 +1115,4 @@
|
|||
"samlRelayStateTimeout":"Thời gian hết hạn phiên RelayState ",
|
||||
"samlUseQueryStringSpecific":"Sử dụng phương pháp query_string cụ thể",
|
||||
"samlOverrideIDPEntityID":"Override Entity ID when acting as IDP"
|
||||
}
|
||||
}
|
|
@ -104,7 +104,9 @@
|
|||
"browserIdSiteName":"站点名称",
|
||||
"browserIdVerificationURL":"验证 URL",
|
||||
"browseTree":"浏览树",
|
||||
"bruteForceProtection":"Brute-force attack protection",
|
||||
"bruteForceProtection":"Activation",
|
||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
||||
"cancel":"取消",
|
||||
"captcha_login_enabled":" 登录激活",
|
||||
"captcha_mail_enabled":"通过邮件进行密码重置 激活",
|
||||
|
@ -142,7 +144,7 @@
|
|||
"casStorageOptions":"CAS 会话模块选项",
|
||||
"categoryName":"分类名称",
|
||||
"cda":"Multiple domains",
|
||||
"certificateMailContent":"Certificate mail content",
|
||||
"certificateMailContent":"Mail content",
|
||||
"certificateResetByMailManagement":"Certificate management",
|
||||
"certificateResetByMailURL":"Reset page URL",
|
||||
"certificateResetByMailCeaAttribute":"Certificate CEA attibute",
|
||||
|
@ -175,7 +177,7 @@
|
|||
"corsAllow_Origin":"Access-Control-Allow-Origin",
|
||||
"corsExpose_Headers":"Access-Control-Expose-Headers",
|
||||
"corsMax_Age":"Access-Control-Max-Age",
|
||||
"cfgLog":"档案",
|
||||
"cfgLog":"Summary",
|
||||
"cfgVersion":"配置信息",
|
||||
"checkXSS":"Check XSS attacks",
|
||||
"clickHereToForce":"Click here to force",
|
||||
|
@ -326,6 +328,7 @@
|
|||
"gpgParams":"GPG parameters",
|
||||
"grantSessionRules":"Opening conditions",
|
||||
"groups":"Groups",
|
||||
"groupsBeforeMacros":"Compute groups before macros",
|
||||
"hashkey":"Key",
|
||||
"headers":"HTTP Headers",
|
||||
"hGroups":"Groups (HashRef)",
|
||||
|
@ -459,7 +462,7 @@
|
|||
"mailCharset":"Charset",
|
||||
"mailConfirmBody":"Confirmation mail content",
|
||||
"mailConfirmSubject":"Confirmation mail subject",
|
||||
"mailContent":"Password mail content",
|
||||
"mailContent":"Mail content",
|
||||
"mailFrom":"邮件发送者",
|
||||
"mailHeaders":"邮件头",
|
||||
"mailLDAPFilter":"邮件过滤器",
|
||||
|
@ -526,6 +529,7 @@
|
|||
"notificationDeleted":"Notification deleted",
|
||||
"notificationDone":"Notification done",
|
||||
"notificationsDone":"Notifications done",
|
||||
"notificationsExplorer":"Explorer",
|
||||
"notificationNotCreated":"The notification was not created",
|
||||
"notificationNotDeleted":"The notification was not marked as done",
|
||||
"notificationNotFound":"The notification was not found",
|
||||
|
@ -801,7 +805,7 @@
|
|||
"saveReport":"Save report",
|
||||
"savingConfirmation":"Saving confirmation",
|
||||
"scope":"Scope",
|
||||
"search":"Search ...",
|
||||
"search":"Search...",
|
||||
"secondFactors":"Second factors",
|
||||
"securedCookie":"Secured Cookie (SSL)",
|
||||
"security":"Security",
|
||||
|
@ -1111,4 +1115,4 @@
|
|||
"samlRelayStateTimeout":"RelayState session timeout",
|
||||
"samlUseQueryStringSpecific":"Use specific query_string method",
|
||||
"samlOverrideIDPEntityID":"Override Entity ID when acting as IDP"
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -12,9 +12,8 @@
|
|||
<div class="navbar navbar-default">
|
||||
<div class="navbar-collapse">
|
||||
<ul class="nav navbar-nav" role="grid">
|
||||
<li><a id="a-persistent" role="row"><i class="glyphicon glyphicon-filter"></i> {{translate('2faSessions')}} </a></li>
|
||||
<form name="filterForm">
|
||||
<div class="form-check ">
|
||||
<form class="navbar-form" name="filterForm">
|
||||
<div class="form-check ">
|
||||
<input type="checkbox" ng-model="U2FCheck" class="form-check-input" ng-true-value="2" ng-false-value="1" ng-change="search2FA()"/>
|
||||
<label class="form-check-label" for="U2FCheck">U2F</label>
|
||||
&
|
||||
|
@ -26,8 +25,8 @@
|
|||
</div>
|
||||
</form>
|
||||
</ul>
|
||||
<div class="col-lg-6 col-md-6 col-sm-8 col-xs-14" >
|
||||
<form class="navbar-form" role="search">
|
||||
<div class="col-lg-6 col-md-6 col-sm-8 col-xs-14" >
|
||||
<form class="navbar-form" role="search">
|
||||
<div class="input-group add-on">
|
||||
<input class="form-control" placeholder="{{translate('search')}}" type="text" ng-model="searchString" ng-init="" ng-keyup="search2FA()"/>
|
||||
<div class="input-group-btn">
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<div class="navbar navbar-default">
|
||||
<div class="navbar-collapse">
|
||||
<ul class="nav navbar-nav" role="grid">
|
||||
<li><a id="a-actives" href="#" role="row"><i class="glyphicon glyphicon-eye-open"></i> {{translate('actives')}}</a></li>
|
||||
<li><a id="a-done" href="#!/done" role="row"><i class="glyphicon glyphicon-check"></i> {{translate('dones')}}</a></li>
|
||||
<li><a id="a-new" href="#!/new" role="row"><i class="glyphicon glyphicon-plus-sign"></i> {{translate('create')}}</a></li>
|
||||
<li><a id="a-actives" href="#" role="row" ng-style="activesStyle"><i class="glyphicon glyphicon-eye-open"></i> {{translate('actives')}}</a></li>
|
||||
<li><a id="a-done" href="#!/done" role="row" ng-style="doneStyle"><i class="glyphicon glyphicon-check"></i> {{translate('dones')}}</a></li>
|
||||
<li><a id="a-new" href="#!/new" role="row" ng-style="newStyle"><i class="glyphicon glyphicon-plus-sign"></i> {{translate('create')}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -69,6 +69,10 @@
|
|||
<th>{{translate('reference')}}</th>
|
||||
<td>{{currentNotification.reference}}</td>
|
||||
</tr>
|
||||
<tr ng-if="currentNotification.date">
|
||||
<th>{{translate('date')}}</th>
|
||||
<td>{{currentNotification.date}}</td>
|
||||
</tr>
|
||||
<tr ng-if="currentNotification.condition">
|
||||
<th>{{translate('condition')}}</th>
|
||||
<td>{{currentNotification.condition}}</td>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<div class="navbar-collapse">
|
||||
<ul class="nav navbar-nav" role="grid">
|
||||
<li uib-dropdown>
|
||||
<a id="navsso" name="menu" uib-dropdown-toggle data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><i class="glyphicon glyphicon-user"></i> {{translate('ssoSessions')}} <span class="caret"></span></a>
|
||||
<a id="navsso" name="menu" uib-dropdown-toggle data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" ng-style="navssoStyle"><i class="glyphicon glyphicon-user"></i> {{translate('ssoSessions')}} <span class="caret"></span></a>
|
||||
<ul uib-dropdown-menu aria-labelled-by="navsso">
|
||||
<li><a id="a-users" href="#" role="row"><i class="glyphicon glyphicon-user"></i> {{translate('users')}}</a></li>
|
||||
<li><a id="a-ip" href="#!/ipAddr" role="row"><i class="glyphicon glyphicon-sort-by-order"></i> {{translate('ipAddresses')}}</a></li>
|
||||
|
@ -25,8 +25,8 @@
|
|||
<li><a id="a-updatetime" href="#!/_updateTime" role="row"><i class="glyphicon glyphicon-hourglass"></i> {{translate('_updateTime')}}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a id="a-persistent" href="#!/persistent" role="row"><i class="glyphicon glyphicon-lock"></i> {{translate('persistentSessions')}}</a></li>
|
||||
<li><a id="a-offline" href="#!/offline" role="row"><i class="glyphicon glyphicon-time"></i> {{translate('offlineSessions')}}</a></li>
|
||||
<li><a id="a-persistent" href="#!/persistent" role="row" ng-style="persistentStyle"><i class="glyphicon glyphicon-lock"></i> {{translate('persistentSessions')}}</a></li>
|
||||
<li><a id="a-offline" href="#!/offline" role="row" ng-style="offlineStyle"><i class="glyphicon glyphicon-time"></i> {{translate('offlineSessions')}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -41,7 +41,8 @@ sub newSession {
|
|||
_session_kind => $kind,
|
||||
_2fDevices => to_json($sfaDevices),
|
||||
}
|
||||
), "New $kind session for $uid"
|
||||
),
|
||||
"New $kind session for $uid"
|
||||
);
|
||||
count(1);
|
||||
}
|
||||
|
@ -96,7 +97,7 @@ sub checkGet {
|
|||
my ( $uid, $id ) = splice @_;
|
||||
my ( $test, $res, $ret );
|
||||
$test = "$uid should have one 2F with id \"$id\"";
|
||||
$res = get( $test, $uid, undef, $id );
|
||||
$res = get( $test, $uid, undef, $id );
|
||||
check200( $test, $res );
|
||||
|
||||
#diag Dumper($res);
|
||||
|
@ -110,7 +111,7 @@ sub checkGet404 {
|
|||
my ( $uid, $id ) = splice @_;
|
||||
my ( $test, $res, $ret );
|
||||
$test = "$uid should not have any 2F with id \"$id\"";
|
||||
$res = get( $test, $uid, undef, $id );
|
||||
$res = get( $test, $uid, undef, $id );
|
||||
check404( $test, $res );
|
||||
}
|
||||
|
||||
|
@ -138,7 +139,7 @@ sub checkGetBadType {
|
|||
my ( $uid, $type ) = splice @_;
|
||||
my ( $test, $res );
|
||||
$test = "Get for uid $uid and type \"$type\" should get rejected.";
|
||||
$res = get( $test, $uid, $type );
|
||||
$res = get( $test, $uid, $type );
|
||||
check405( $test, $res );
|
||||
}
|
||||
|
||||
|
@ -176,7 +177,7 @@ sub checkDelete {
|
|||
my ( $uid, $id ) = splice @_;
|
||||
my ( $test, $res );
|
||||
$test = "$uid should have a 2F with id \"$id\" to be deleted.";
|
||||
$res = del( $test, $uid, undef, $id );
|
||||
$res = del( $test, $uid, undef, $id );
|
||||
check200( $test, $res );
|
||||
}
|
||||
|
||||
|
@ -184,7 +185,7 @@ sub checkDelete404 {
|
|||
my ( $uid, $id ) = splice @_;
|
||||
my ( $test, $res );
|
||||
$test = "$uid should not have a 2F with id \"$id\" to be deleted.";
|
||||
$res = del( $test, $uid, undef, $id );
|
||||
$res = del( $test, $uid, undef, $id );
|
||||
check404( $test, $res );
|
||||
}
|
||||
|
||||
|
@ -209,7 +210,7 @@ sub checkDeleteBadType {
|
|||
my ( $uid, $type ) = splice @_;
|
||||
my ( $test, $res );
|
||||
$test = "Delete for uid $uid and type \"$type\" should get rejected.";
|
||||
$res = del( $test, $uid, $type );
|
||||
$res = del( $test, $uid, $type );
|
||||
check405( $test, $res );
|
||||
}
|
||||
|
||||
|
@ -218,7 +219,7 @@ my $ret;
|
|||
|
||||
## Sessions creation
|
||||
# msmith
|
||||
newSession( 'msmith', '127.10.0.1', 'SSO', $sfaDevices );
|
||||
newSession( 'msmith', '127.10.0.1', 'SSO', $sfaDevices );
|
||||
newSession( 'msmith', '127.10.0.1', 'Persistent', $sfaDevices );
|
||||
|
||||
# dwho
|
||||
|
@ -242,7 +243,7 @@ $sfaDevices = [ {
|
|||
"epoch" => time
|
||||
}
|
||||
];
|
||||
newSession( 'dwho', '127.10.0.1', 'SSO', $sfaDevices );
|
||||
newSession( 'dwho', '127.10.0.1', 'SSO', $sfaDevices );
|
||||
newSession( 'dwho', '127.10.0.1', 'Persistent', $sfaDevices );
|
||||
|
||||
# rtyler
|
||||
|
@ -266,7 +267,7 @@ $sfaDevices = [ {
|
|||
"epoch" => time
|
||||
}
|
||||
];
|
||||
newSession( 'rtyler', '127.10.0.1', 'SSO', $sfaDevices );
|
||||
newSession( 'rtyler', '127.10.0.1', 'SSO', $sfaDevices );
|
||||
newSession( 'rtyler', '127.10.0.1', 'Persistent', $sfaDevices );
|
||||
|
||||
# davros
|
||||
|
@ -284,7 +285,7 @@ $sfaDevices = [ {
|
|||
"epoch" => time
|
||||
}
|
||||
];
|
||||
newSession( 'davros', '127.10.0.1', 'SSO', $sfaDevices );
|
||||
newSession( 'davros', '127.10.0.1', 'SSO', $sfaDevices );
|
||||
newSession( 'davros', '127.10.0.1', 'Persistent', $sfaDevices );
|
||||
|
||||
# tof
|
||||
|
@ -296,7 +297,7 @@ $sfaDevices = [ {
|
|||
"epoch" => time
|
||||
}
|
||||
];
|
||||
newSession( 'tof', '127.10.0.1', 'SSO', $sfaDevices );
|
||||
newSession( 'tof', '127.10.0.1', 'SSO', $sfaDevices );
|
||||
newSession( 'tof', '127.10.0.1', 'Persistent', $sfaDevices );
|
||||
|
||||
# dwho
|
||||
|
|
|
@ -90,7 +90,7 @@ sub checkGet {
|
|||
my $res = get( $test, $type, $confKey );
|
||||
check200( $test, $res );
|
||||
my @path = split '/', $attrPath;
|
||||
my $key = from_json( $res->[2]->[0] );
|
||||
my $key = from_json( $res->[2]->[0] );
|
||||
for (@path) {
|
||||
$key = $key->{$_};
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ while (<F>) {
|
|||
close F;
|
||||
|
||||
ok( $hstruct = from_json($hstruct), 'struct.json is JSON' );
|
||||
ok( ref $hstruct eq 'ARRAY', 'struct.json is an array' )
|
||||
ok( ref $hstruct eq 'ARRAY', 'struct.json is an array' )
|
||||
or print STDERR "Expected: ARRAY, got: " . ( ref $hstruct ) . "\n";
|
||||
count(2);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ ok(
|
|||
),
|
||||
"Request succeed"
|
||||
);
|
||||
ok( $res->[0] == 200, "Result code is 200" );
|
||||
ok( $res->[0] == 200, "Result code is 200" );
|
||||
ok( $key = from_json( $res->[2]->[0] ), 'Response is JSON' );
|
||||
count(3);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ mkdir 't/sessions';
|
|||
my ( $res, $resBody );
|
||||
ok( $res = &client->_post( '/confs/', 'cfgNum=1', &body, 'application/json' ),
|
||||
"Request succeed" );
|
||||
ok( $res->[0] == 200, "Result code is 200" );
|
||||
ok( $res->[0] == 200, "Result code is 200" );
|
||||
ok( $resBody = from_json( $res->[2]->[0] ), "Result body contains JSON text" );
|
||||
|
||||
ok( $resBody->{result} == 0, "JSON response contains \"result:0\"" )
|
||||
|
@ -248,7 +248,7 @@ sub changes {
|
|||
},
|
||||
{
|
||||
'confCompacted' => '1',
|
||||
'removedKeys' => 'some; keys'
|
||||
'removedKeys' => 'some; keys'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ ok( $resBody = from_json( $res->[2]->[0] ), "Result body contains JSON text" );
|
|||
ok( $resBody->{result} == 1, "JSON response contains \"result:1\"" )
|
||||
or print STDERR Dumper($resBody);
|
||||
ok(
|
||||
@{ $resBody->{details}->{__warnings__} } == 2,
|
||||
$resBody->{details}->{__warnings__}
|
||||
and @{ $resBody->{details}->{__warnings__} } == 2,
|
||||
'JSON response contains 2 warnings'
|
||||
) or print STDERR Dumper($resBody);
|
||||
|
||||
|
@ -38,18 +39,18 @@ foreach my $i ( 0 .. 1 ) {
|
|||
}
|
||||
|
||||
ok(
|
||||
@{ $resBody->{details}->{__changes__} } == 24,
|
||||
$resBody->{details}->{__changes__}
|
||||
and @{ $resBody->{details}->{__changes__} } == 24,
|
||||
'JSON response contains 24 changes'
|
||||
) or print STDERR Dumper($resBody);
|
||||
ok(
|
||||
$resBody->{details}->{__changes__}->[23]->{confCompacted} == 1,
|
||||
'Conf. has been compacted'
|
||||
) or print STDERR Dumper($resBody);
|
||||
ok( $resBody->{details}->{__changes__}->[23]->{confCompacted} == 1,
|
||||
'Conf. has been compacted' )
|
||||
or print STDERR Dumper($resBody);
|
||||
|
||||
my @removedKeys = split /; /, $resBody->{details}->{__changes__}->[23]->{removedKeys};
|
||||
ok(
|
||||
@removedKeys == 60, 'All removed keys found'
|
||||
) or print STDERR Dumper(\@removedKeys);
|
||||
my @removedKeys = split /; /,
|
||||
$resBody->{details}->{__changes__}->[23]->{removedKeys};
|
||||
ok( @removedKeys == 60, 'All removed keys found' )
|
||||
or print STDERR Dumper( \@removedKeys );
|
||||
|
||||
#print STDERR Dumper($resBody);
|
||||
ok( -f $confFiles->[1], 'File is created' );
|
||||
|
@ -105,8 +106,7 @@ ok( @c2 == 15, '15 keys changed or created in conf 2' )
|
|||
|
||||
count(5);
|
||||
|
||||
ok( $res = &client->jsonResponse('/confs/latest'),
|
||||
'Get last config metadata' );
|
||||
ok( $res = &client->jsonResponse('/confs/latest'), 'Get last config metadata' );
|
||||
ok( $res->{prev} == 1, ' Get previous configuration' );
|
||||
count(2);
|
||||
|
||||
|
@ -119,8 +119,7 @@ done_testing( count() );
|
|||
`rm -rf t/sessions`;
|
||||
|
||||
sub changes {
|
||||
return [
|
||||
{
|
||||
return [ {
|
||||
'key' => 'portal',
|
||||
'new' => 'http://auth2.example.com/',
|
||||
'old' => 'http://auth.example.com/'
|
||||
|
|
|
@ -16,7 +16,7 @@ unlink 't/conf/lmConf-2.json';
|
|||
my ( $res, $resBody );
|
||||
ok( $res = &client->_post( '/confs/', 'cfgNum=1', &body, 'application/json' ),
|
||||
"Request succeed" );
|
||||
ok( $res->[0] == 200, "Result code is 200" );
|
||||
ok( $res->[0] == 200, "Result code is 200" );
|
||||
ok( $resBody = from_json( $res->[2]->[0] ), "Result body contains JSON text" );
|
||||
ok( $resBody->{result} == 0, "JSON response contains \"result:0\"" )
|
||||
or print STDERR Dumper($res);
|
||||
|
|
|
@ -17,7 +17,7 @@ mkdir 't/sessions';
|
|||
my ( $res, $resBody );
|
||||
ok( $res = &client->_post( '/confs/', 'cfgNum=1', &body, 'application/json' ),
|
||||
"Request succeed" );
|
||||
ok( $res->[0] == 200, "Result code is 200" );
|
||||
ok( $res->[0] == 200, "Result code is 200" );
|
||||
ok( $resBody = from_json( $res->[2]->[0] ), "Result body contains JSON text" );
|
||||
ok( $resBody->{result} == 1, "JSON response contains \"result:1\"" )
|
||||
or print STDERR Dumper($res);
|
||||
|
|
|
@ -1,112 +1,114 @@
|
|||
use Test::More;
|
||||
use Test::Output;
|
||||
use JSON;
|
||||
use strict;
|
||||
require 't/test-lib.pm';
|
||||
|
||||
my $tests = 14;
|
||||
my $tests = 17;
|
||||
|
||||
use_ok('Lemonldap::NG::Common::Cli');
|
||||
use_ok('Lemonldap::NG::Manager::Cli');
|
||||
&cleanConfFiles;
|
||||
|
||||
SKIP: {
|
||||
eval 'use Test::Output;';
|
||||
if ($@) {
|
||||
skip 'Test::Output is missing, skipping', $tests - 2;
|
||||
}
|
||||
my $client =
|
||||
Lemonldap::NG::Manager::Cli->new( iniFile => 't/lemonldap-ng.ini' );
|
||||
my $commonClient =
|
||||
Lemonldap::NG::Common::Cli->new( iniFile => 't/lemonldap-ng.ini' );
|
||||
my @cmd;
|
||||
my $res;
|
||||
|
||||
# Test 'set' command
|
||||
@cmd = qw(-yes 1 set notification 1);
|
||||
Capture::Tiny::capture_stdout( sub { $client->run(@cmd) } );
|
||||
|
||||
# Test 'get' command
|
||||
@cmd = qw(get notification);
|
||||
$res = Capture::Tiny::capture_stdout( sub { $client->run(@cmd) } );
|
||||
ok( $res =~ /^notification\s+=\s+1$/, '"get notification" OK' )
|
||||
or diag " $res";
|
||||
|
||||
# Test 'addKey' command
|
||||
@cmd = qw(-yes 1 addKey locationRules/test1.example.com ^/reject deny);
|
||||
Test::Output::combined_like(
|
||||
sub { $client->run(@cmd) },
|
||||
qr#'\^/reject' => 'deny'#s,
|
||||
'"addKey" OK'
|
||||
);
|
||||
|
||||
# Test 'delKey' command
|
||||
@cmd = qw(-yes 1 delKey locationRules/test1.example.com ^/reject);
|
||||
Test::Output::combined_unlike(
|
||||
sub { $client->run(@cmd) },
|
||||
qr#'\^/reject' => 'deny'#s,
|
||||
'"delKey" OK'
|
||||
);
|
||||
|
||||
# Test 'get' command with key/subkey
|
||||
@cmd = qw(get locationRules/test1.example.com);
|
||||
$res = Capture::Tiny::capture_stdout( sub { $client->run(@cmd) } );
|
||||
ok( $res =~ m#(?:/logout|default)#, '"get key/subkey" OK' )
|
||||
or diag "$res";
|
||||
|
||||
# Test 'set' command with key/subkey
|
||||
@cmd = qw(-yes 1 set locationRules/test1.example.com/default deny);
|
||||
Capture::Tiny::capture_stdout( sub { $client->run(@cmd) } );
|
||||
|
||||
|
||||
# Test 'save' command
|
||||
@cmd = ('save');
|
||||
$res = Capture::Tiny::capture_stdout( sub { $client->run(@cmd) } );
|
||||
ok( $res =~ /^\s*(\{.*\})\s*$/s, '"save" result looks like JSON' );
|
||||
eval { JSON::from_json($res) };
|
||||
ok( not($@), ' result is JSON' ) or diag "error: $@";
|
||||
|
||||
# Test 'restore' command
|
||||
close STDIN;
|
||||
open STDIN, '<', \$res;
|
||||
@cmd = ( 'restore', '-' );
|
||||
Test::Output::combined_like( sub { $client->run(@cmd) },
|
||||
qr/"cfgNum"\s*:\s*"3"/s, 'New config: 3' );
|
||||
|
||||
# Test 'set' command with force
|
||||
@cmd = qw(-yes 1 -force 1 -cfgNum 2 set useSafeJail 0);
|
||||
Test::Output::combined_like(
|
||||
sub { $client->run(@cmd) },
|
||||
qr#cfgNum forced with 2#s,
|
||||
'"Force cfgNum" OK'
|
||||
);
|
||||
|
||||
# Test 'update-cache' command with force
|
||||
@cmd = qw(update-cache);
|
||||
Test::Output::combined_like(
|
||||
sub { $commonClient->run(@cmd) },
|
||||
qr#Cache updated to configuration 3#s,
|
||||
'"update-cache" OK'
|
||||
);
|
||||
|
||||
# Test 'info' command with force
|
||||
@cmd = qw(info);
|
||||
Test::Output::combined_like(
|
||||
$res = sub { $commonClient->run(@cmd) },
|
||||
qr#\bAuthor IP\b#s,
|
||||
'"Author IP" OK'
|
||||
);
|
||||
Test::Output::combined_like(
|
||||
$res = sub { $commonClient->run(@cmd) },
|
||||
qr#\bLog\b#s,
|
||||
'"Log" OK'
|
||||
);
|
||||
Test::Output::combined_like(
|
||||
$res = sub { $commonClient->run(@cmd) },
|
||||
qr#\bVersion\b#s,
|
||||
'"Version" OK'
|
||||
);
|
||||
sub llclient {
|
||||
return Lemonldap::NG::Manager::Cli->new( iniFile => 't/lemonldap-ng.ini' );
|
||||
}
|
||||
|
||||
sub llcommonClient {
|
||||
return Lemonldap::NG::Common::Cli->new( iniFile => 't/lemonldap-ng.ini' );
|
||||
}
|
||||
|
||||
my @cmd;
|
||||
my $res;
|
||||
|
||||
# Test 'set' command
|
||||
@cmd = qw(-yes 1 set notification 1);
|
||||
combined_like(
|
||||
sub { llclient->run(@cmd) },
|
||||
qr/Saved under/,
|
||||
'"addKey" OK'
|
||||
);
|
||||
|
||||
# Test 'get' command
|
||||
@cmd = qw(get notification);
|
||||
$res = Test::Output::stdout_from( sub { llclient->run(@cmd) } );
|
||||
ok( $res =~ /^notification\s+=\s+1$/, '"get notification" OK' )
|
||||
or diag " $res";
|
||||
|
||||
# Test 'addKey' command
|
||||
@cmd = qw(-yes 1 addKey locationRules/test1.example.com ^/reject deny);
|
||||
combined_like(
|
||||
sub { llclient->run(@cmd) },
|
||||
qr/Saved under/,
|
||||
'"addKey" OK'
|
||||
);
|
||||
|
||||
# Test 'delKey' command
|
||||
@cmd = qw(-yes 1 delKey locationRules/test1.example.com ^/reject);
|
||||
combined_unlike(
|
||||
sub { llclient->run(@cmd) },
|
||||
qr#'\^/reject' => 'deny'#s,
|
||||
'"delKey" OK'
|
||||
);
|
||||
|
||||
# Test 'get' command with key/subkey
|
||||
@cmd = qw(get locationRules/test1.example.com/default);
|
||||
$res = Test::Output::stdout_from( sub { llclient->run(@cmd) } );
|
||||
ok( $res =~ m#accept#, '"get key/subkey" OK' )
|
||||
or diag "$res";
|
||||
|
||||
# Test 'set' command with key/subkey
|
||||
@cmd = qw(-yes 1 set locationRules/test1.example.com/default deny);
|
||||
combined_like(
|
||||
sub { llclient->run(@cmd) },
|
||||
qr/Saved under/,
|
||||
'"addKey" OK'
|
||||
);
|
||||
|
||||
# Test 'save' command
|
||||
@cmd = qw(-cfgNum 1 save);
|
||||
$res = Test::Output::stdout_from( sub { llclient->run(@cmd) } );
|
||||
ok( $res =~ /^\s*(\{.*\})\s*$/s, '"save" result looks like JSON' );
|
||||
my $j;
|
||||
eval { $j = JSON::from_json($res) };
|
||||
is( $j->{cfgNum}, 1, "correct version number" );
|
||||
ok( not($@), ' result is JSON' ) or diag "error: $@";
|
||||
|
||||
# Test 'restore' command
|
||||
my $tmpFile = File::Temp->new();
|
||||
print $tmpFile $res;
|
||||
@cmd = ( 'restore', $tmpFile->filename );
|
||||
combined_like( sub { llclient->run(@cmd) },
|
||||
qr/"cfgNum"\s*:\s*\d*/s, 'New config' );
|
||||
|
||||
# Test 'set' command with force
|
||||
@cmd = qw(-yes 1 -force 1 -cfgNum 2 set useSafeJail 0);
|
||||
combined_like(
|
||||
sub { llclient->run(@cmd) },
|
||||
qr#cfgNum forced with 2#s,
|
||||
'"Force cfgNum" OK'
|
||||
);
|
||||
|
||||
# Test 'info' command with force
|
||||
@cmd = qw(info);
|
||||
combined_like(
|
||||
sub { llcommonClient->run(@cmd) },
|
||||
qr#\bAuthor IP\b#s,
|
||||
'"Author IP" OK'
|
||||
);
|
||||
combined_like( sub { llcommonClient->run(@cmd) },
|
||||
qr#\bLog\b#s, '"Log" OK' );
|
||||
combined_like( sub { llcommonClient->run(@cmd) },
|
||||
qr#\bVersion\b#s, '"Version" OK' );
|
||||
|
||||
# Test 'rollback' command
|
||||
@cmd = qw(rollback);
|
||||
combined_like(
|
||||
sub { llclient->run(@cmd) },
|
||||
qr/Configuration \d+ has been rolled back/,
|
||||
'"Author IP" OK'
|
||||
);
|
||||
|
||||
count($tests);
|
||||
done_testing( count() );
|
||||
&cleanConfFiles;
|
||||
|
|
|
@ -17,7 +17,7 @@ mkdir 't/sessions';
|
|||
my ( $res, $resBody );
|
||||
ok( $res = &client->_post( '/confs/', 'cfgNum=1', &body, 'application/json' ),
|
||||
"Request succeed" );
|
||||
ok( $res->[0] == 200, "Result code is 200" );
|
||||
ok( $res->[0] == 200, "Result code is 200" );
|
||||
ok( $resBody = from_json( $res->[2]->[0] ), "Result body contains JSON text" );
|
||||
ok( $resBody->{result} == 1, "JSON response contains \"result:1\"" )
|
||||
or print STDERR Dumper($res);
|
||||
|
|
|
@ -148,7 +148,7 @@ count(5);
|
|||
foreach (@ids) {
|
||||
my $res;
|
||||
ok( $res = &client->_del("/sessions/global/$_"), "Delete $_" );
|
||||
ok( $res->[0] == 200, 'Result code is 200' );
|
||||
ok( $res->[0] == 200, 'Result code is 200' );
|
||||
ok( from_json( $res->[2]->[0] )->{result} == 1,
|
||||
'Body is JSON and result==1' );
|
||||
count(3);
|
||||
|
|
|
@ -44,7 +44,8 @@ SKIP: {
|
|||
$client->jsonPostResponse( 'notifications/actives', '',
|
||||
IO::String->new($notif),
|
||||
'application/json', length($notif) );
|
||||
ok( $res->{error} =~ /^Notification not created: Bad date/, 'Notification not inserted' );
|
||||
ok( $res->{error} =~ /^Notification not created: Bad date/,
|
||||
'Notification not inserted' );
|
||||
|
||||
$notif =
|
||||
'{"date":"2099-13-30","uid":"dwho","reference":"Test","xml":"{\"title\":\"Test\"}"}';
|
||||
|
@ -52,7 +53,8 @@ SKIP: {
|
|||
$client->jsonPostResponse( 'notifications/actives', '',
|
||||
IO::String->new($notif),
|
||||
'application/json', length($notif) );
|
||||
ok( $res->{error} =~ /^Notification not created: Bad date/, 'Notification not inserted' );
|
||||
ok( $res->{error} =~ /^Notification not created: Bad date/,
|
||||
'Notification not inserted' );
|
||||
|
||||
$notif =
|
||||
'{"date":"2099-05_12","uid":"dwho","reference":"Test","xml":"{\"title\":\"Test\"}"}';
|
||||
|
@ -98,7 +100,7 @@ SKIP: {
|
|||
$res =
|
||||
$client->jsonResponse( 'notifications/done', 'groupBy=substr(uid,1)' );
|
||||
ok( $res->{result} == 1, 'Result = 1' );
|
||||
ok( $res->{count} == 0, 'Count = 0' ) or diag Dumper($res);
|
||||
ok( $res->{count} == 0, 'Count = 0' ) or diag Dumper($res);
|
||||
|
||||
#print STDERR Dumper($res);
|
||||
}
|
||||
|
|
|
@ -16,21 +16,23 @@ my $res =
|
|||
&client->jsonPostResponse( 'notifications/actives', '',
|
||||
IO::String->new($notif),
|
||||
'application/json', length($notif) );
|
||||
ok( $res->{error} =~ /^Notification not created: Bad date/, 'Notification not inserted' );
|
||||
ok( $res->{error} =~ /^Notification not created: Bad date/,
|
||||
'Notification not inserted' );
|
||||
count(1);
|
||||
|
||||
$notif =
|
||||
'{"date":"2099-13-30","uid":"dwho","reference":"Test","xml":"{\"title\":\"Test\"}"}';
|
||||
my $res =
|
||||
$res =
|
||||
&client->jsonPostResponse( 'notifications/actives', '',
|
||||
IO::String->new($notif),
|
||||
'application/json', length($notif) );
|
||||
ok( $res->{error} =~ /^Notification not created: Bad date/, 'Notification not inserted' );
|
||||
ok( $res->{error} =~ /^Notification not created: Bad date/,
|
||||
'Notification not inserted' );
|
||||
count(1);
|
||||
|
||||
$notif =
|
||||
'{"date":"2099-05_12","uid":"dwho","reference":"Test","xml":"{\"title\":\"Test\"}"}';
|
||||
my $res =
|
||||
$res =
|
||||
&client->jsonPostResponse( 'notifications/actives', '',
|
||||
IO::String->new($notif),
|
||||
'application/json', length($notif) );
|
||||
|
|
|
@ -277,7 +277,7 @@ $res = &client->jsonResponse( '/sfa/persistent',
|
|||
'uid=*&groupBy=substr(uid,0)&U2FCheck=2&TOTPCheck=2&UBKCheck=2' );
|
||||
ok( $res->{result} == 1,
|
||||
'Search "uid"=* & UBK & TOTP & UBK - Result code = 1' );
|
||||
ok( $res->{count} == 1, 'Found 1 result' ) or print STDERR Dumper($res);
|
||||
ok( $res->{count} == 1, 'Found 1 result' ) or print STDERR Dumper($res);
|
||||
ok( @{ $res->{values} } == 1, 'List 1 result' );
|
||||
ok( $res->{values}->[0]->{value} && $res->{values}->[0]->{value} eq 'd',
|
||||
'Result match "uid=d"' )
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue