Merge branch 'favapps' into 'master'

Favapps

Closes #1689

See merge request lemonldap-ng/lemonldap-ng!74
This commit is contained in:
Christophe Maudoux 2019-05-02 14:46:49 +02:00
commit c233ef37ef
45 changed files with 857 additions and 42 deletions

12
COPYING
View File

@ -99,6 +99,18 @@ License: CC-3
Comment: This work, "sfa_manager.png", is a derivative of
"Noun project 1162.svg" by Christopher T. Howlett, under CC-BY-3.0.
Files: lemonldap-ng-portal/site/htdocs/static/common/icons/star0.png
Copyright: Christophe Maudoux <chrmdx@gmail.com>
License: CC-3
Comment: This work, "star0.png", is a derivative of
"Silver star with red border.png" by ANGELUS, under CC-BYSA-3.0.
Files: lemonldap-ng-portal/site/htdocs/static/common/icons/star1.png
Copyright: Christophe Maudoux <chrmdx@gmail.com>
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/modules/CustomAuth.png
Copyright: Christophe Maudoux <chrmdx@gmail.com>
License: CC-3

View File

@ -57,6 +57,7 @@ sub defaultValues {
'facebookExportedVars' => {},
'facebookUserField' => 'id',
'failedLoginNumber' => 5,
'favAppsMaxNumber' => 3,
'formTimeout' => 120,
'globalStorage' => 'Apache::Session::File',
'globalStorageOptions' => {
@ -190,6 +191,7 @@ sub defaultValues {
'portalCheckLogins' => 1,
'portalDisplayAppslist' => 1,
'portalDisplayChangePassword' => '$_auth =~ /^(LDAP|DBI|Demo)$/',
'portalDisplayFavApps' => 1,
'portalDisplayLoginHistory' => 1,
'portalDisplayLogout' => 1,
'portalDisplayOidcConsents' => '$_oidcConnectedRP',

View File

@ -1147,6 +1147,10 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'default' => 5,
'type' => 'int'
},
'favAppsMaxNumber' => {
'default' => 3,
'type' => 'int'
},
'formTimeout' => {
'default' => 120,
'type' => 'int'
@ -2261,6 +2265,10 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'default' => '$_auth =~ /^(LDAP|DBI|Demo)$/',
'type' => 'boolOrExpr'
},
'portalDisplayFavApps' => {
'default' => 1,
'type' => 'boolOrExpr'
},
'portalDisplayLoginHistory' => {
'default' => 1,
'type' => 'boolOrExpr'

View File

@ -446,6 +446,18 @@ sub attributes {
documentation => 'Display session empty values',
flags => 'p',
},
favAppsMaxNumber => {
default => 3,
type => 'int',
documentation => 'Maximum favorite Apps number',
flags => 'p',
},
portalDisplayFavApps => {
type => 'boolOrExpr',
default => 1,
documentation => 'Display favorite applications tab in portal',
flags => 'p',
},
impersonationMergeSSOgroups => {
default => 0,
type => 'bool',

View File

@ -43,6 +43,15 @@ sub tree {
'portalDisplayAppslist',
'portalDisplayLoginHistory',
'portalDisplayOidcConsents',
{
title => 'favApps',
help => 'favapps.html',
form => 'simpleInputContainer',
nodes => [
'portalDisplayFavApps',
'favAppsMaxNumber',
]
},
]
},
'applicationList'

View File

@ -263,6 +263,8 @@
"facebookParams":"معاييرفاسيبوك",
"facebookUserField":"Field containing user identifier",
"failedLoginNumber":"عدد عمليات تسجيل الدخول الفاشلة المسجلة",
"favApps":"Favorite Apps",
"favAppsMaxNumber":"Max number of favorite Apps",
"fileToUpload":"الملف الذي ستحمله",
"forbidden":"لست مخولا بعرض هذه الصفحة",
"forceSave":"فرض الحفظ",
@ -612,6 +614,7 @@
"portalCustomization":"التخصيص",
"portalDisplayAppslist":"قائمة التطبيقات",
"portalDisplayChangePassword":"تغيير كلمة المرور",
"portalDisplayFavApps":"Activation rule",
"portalDisplayLoginHistory":"سجل تسجيل الدخول",
"portalDisplayLogout":"تسجيل الخروج",
"portalDisplayOidcConsents":"OIDC Consents",

View File

@ -263,6 +263,8 @@
"facebookParams":"Facebook parameters",
"facebookUserField":"Field containing user identifier",
"failedLoginNumber":"Number of registered failed logins",
"favApps":"Favorite Apps",
"favAppsMaxNumber":"Max number of favorite Apps",
"fileToUpload":"File to upload",
"forbidden":"You're not authorized to show this page",
"forceSave":"Force save",
@ -612,6 +614,7 @@
"portalCustomization":"Customization",
"portalDisplayAppslist":"Applications list",
"portalDisplayChangePassword":"Password change",
"portalDisplayFavApps":"Activation rule",
"portalDisplayLoginHistory":"Login History",
"portalDisplayLogout":"Logout",
"portalDisplayOidcConsents":"OIDC Consents",

View File

@ -263,6 +263,8 @@
"facebookParams":"Facebook parameters",
"facebookUserField":"Field containing user identifier",
"failedLoginNumber":"Number of registered failed logins",
"favApps":"Favorite Apps",
"favAppsMaxNumber":"Max number of favorite Apps",
"fileToUpload":"File to upload",
"forbidden":"You're not authorized to show this page",
"forceSave":"Force save",
@ -611,6 +613,7 @@
"portalCheckLogins":"Check last logins",
"portalCustomization":"Customization",
"portalDisplayAppslist":"Applications list",
"portalDisplayFavApps":"Activation rule",
"portalDisplayChangePassword":"Password change",
"portalDisplayLoginHistory":"Login History",
"portalDisplayLogout":"Logout",

View File

@ -263,6 +263,8 @@
"facebookParams":"Paramètres Facebook",
"facebookUserField":"Champ contenant l'identifiant de l'utilisateur",
"failedLoginNumber":"Nombre d'échecs de connexion mémorisés",
"favApps":"Applications favorites",
"favAppsMaxNumber":"Nombre maximum d'applications",
"fileToUpload":"Fichier à télécharger",
"forbidden":"Vous n'êtes pas autorisé à visualiser cette page",
"forceSave":"Forcer la sauvegarde",
@ -611,6 +613,7 @@
"portalCheckLogins":"Vérifier l'historique",
"portalCustomization":"Personnalisation",
"portalDisplayAppslist":"Liste des applications",
"portalDisplayFavApps":"Règle d'utilisation",
"portalDisplayChangePassword":"Changement de mot de passe",
"portalDisplayLoginHistory":"Historique des connexions",
"portalDisplayLogout":"Déconnexion",

View File

@ -263,6 +263,8 @@
"facebookParams":"Parametri di Facebook",
"facebookUserField":"Campo contenente l'identificatore dell'utente",
"failedLoginNumber":"Numero di login registrati non riusciti",
"favApps":"Favorite Apps",
"favAppsMaxNumber":"Max number of favorite Apps",
"fileToUpload":"File da caricare",
"forbidden":"Non sei autorizzato a mostrare questa pagina",
"forceSave":"Forza salvataggio",
@ -611,6 +613,7 @@
"portalCheckLogins":"Controllare ultimi accessi",
"portalCustomization":"Personalizzazione",
"portalDisplayAppslist":"Lista delle applicazioni",
"portalDisplayFavApps":"Activation rule",
"portalDisplayChangePassword":"Cambio password",
"portalDisplayLoginHistory":"Cronologia login",
"portalDisplayLogout":"Logout",

View File

@ -58,6 +58,7 @@
"authChoiceParam":"Tham số URL",
"authentication":"Mô đun xác thực",
"authenticationNeeded":"Xác thực cần thiết",
"portalDisplayFavApps":"Activation rule",
"authenticationLevel":"Mức xác thực",
"authenticationTitle":"Xác thực",
"AuthLDAPFilter":"Bộ lọc xác thực",
@ -263,6 +264,8 @@
"facebookParams":"Tham số Facebook",
"facebookUserField":"Field containing user identifier",
"failedLoginNumber":"Số lượt đăng nhập thất bại",
"favApps":"Favorite Apps",
"favAppsMaxNumber":"Max number of favorite Apps",
"fileToUpload":"Tập tin để tải lên",
"forbidden":"Bạn không được ủy quyền để hiển thị trang này",
"forceSave":"Bắt buộc lưu",

View File

@ -263,6 +263,8 @@
"facebookParams":"Facebook 参数",
"facebookUserField":"Field containing user identifier",
"failedLoginNumber":"Number of registered failed logins",
"favApps":"Favorite Apps",
"favAppsMaxNumber":"Max number of favorite Apps",
"fileToUpload":"上传的文件",
"forbidden":"You're not authorized to show this page",
"forceSave":"强制保存",
@ -611,6 +613,7 @@
"portalCheckLogins":"Check last logins",
"portalCustomization":"Customization",
"portalDisplayAppslist":"Applications list",
"portalDisplayFavApps":"Activation rule",
"portalDisplayChangePassword":"Password change",
"portalDisplayLoginHistory":"Login History",
"portalDisplayLogout":"Logout",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -102,6 +102,7 @@ lib/Lemonldap/NG/Portal/Plugins/BruteForceProtection.pm
lib/Lemonldap/NG/Portal/Plugins/CDA.pm
lib/Lemonldap/NG/Portal/Plugins/CheckState.pm
lib/Lemonldap/NG/Portal/Plugins/CheckUser.pm
lib/Lemonldap/NG/Portal/Plugins/FavApps.pm
lib/Lemonldap/NG/Portal/Plugins/ForceAuthn.pm
lib/Lemonldap/NG/Portal/Plugins/GrantSession.pm
lib/Lemonldap/NG/Portal/Plugins/History.pm
@ -148,6 +149,7 @@ scripts/llngDeleteSession
site/coffee/2fregistration.coffee
site/coffee/autoRenew.coffee
site/coffee/confirm.coffee
site/coffee/favapps.coffee
site/coffee/idpchoice.coffee
site/coffee/info.coffee
site/coffee/kerberos.coffee
@ -256,6 +258,8 @@ site/htdocs/static/common/icons/key.png
site/htdocs/static/common/icons/oidc.png
site/htdocs/static/common/icons/ok.png
site/htdocs/static/common/icons/sfa_manager.png
site/htdocs/static/common/icons/star0.png
site/htdocs/static/common/icons/star1.png
site/htdocs/static/common/icons/vcard_edit.png
site/htdocs/static/common/icons/warning.png
site/htdocs/static/common/it.png
@ -265,6 +269,8 @@ site/htdocs/static/common/js/autoRenew.js
site/htdocs/static/common/js/autoRenew.min.js
site/htdocs/static/common/js/confirm.js
site/htdocs/static/common/js/confirm.min.js
site/htdocs/static/common/js/favapps.js
site/htdocs/static/common/js/favapps.min.js
site/htdocs/static/common/js/idpchoice.js
site/htdocs/static/common/js/idpchoice.min.js
site/htdocs/static/common/js/info.js
@ -399,7 +405,6 @@ site/templates/common/mail_register_done.tpl
site/templates/common/notification.xsl
site/templates/common/notifinclude.tpl
site/templates/common/oidc_checksession.tpl
site/templates/common/redirect.tpl
site/templates/common/registerBrowser.tpl
site/templates/common/script.tpl
t/01-AuthDemo.t
@ -518,6 +523,7 @@ t/67-CheckUser-with-token.t
t/67-CheckUser.t
t/68-Impersonation-with-merge.t
t/68-Impersonation.t
t/69-FavApps.t
t/70-2F-TOTP-with-History.t
t/70-2F-TOTP.t
t/70-2F-TOTP_8.t

View File

@ -1168,17 +1168,17 @@ sub createJWT {
my $digest;
if ( $alg eq "HS256" ) {
if ( $alg eq "HS256" && $client_secret ) {
$digest = hmac_sha256_base64( $jwt_header . "." . $jwt_payload,
$client_secret );
}
if ( $alg eq "HS384" ) {
if ( $alg eq "HS384" && $client_secret ) {
$digest = hmac_sha384_base64( $jwt_header . "." . $jwt_payload,
$client_secret );
}
if ( $alg eq "HS512" ) {
if ( $alg eq "HS512" && $client_secret ) {
$digest = hmac_sha512_base64( $jwt_header . "." . $jwt_payload,
$client_secret );
}

View File

@ -11,6 +11,7 @@ use JSON;
use Data::Dumper;
has skinRules => ( is => 'rw' );
has favAppsRule => ( is => 'rw', default => sub { 1 } );
sub displayInit {
my ($self) = @_;
@ -29,6 +30,18 @@ sub displayInit {
}
}
}
# Parse FavApps activation rule
$self->logger->debug(
"FavApps activation rule -> " . $self->conf->{portalDisplayFavApps} );
my $rule =
HANDLER->buildSub( HANDLER->substitute( $self->conf->{portalDisplayFavApps} ) );
unless ($rule) {
$self->error(
"Bad FavApps activation rule -> " . HANDLER->tsv->{jail}->error );
return 0;
}
$self->favAppsRule($rule);
}
# Call portal process and set template parameters
@ -206,6 +219,7 @@ sub display {
PING => $self->conf->{portalPingInterval},
REQUIRE_OLDPASSWORD => $self->conf->{portalRequireOldPassword},
HIDE_OLDPASSWORD => 0,
STARS => $self->favAppsRule->( $req, $req->userData ),
$self->menu->params($req),
(
$req->data->{customScript}

View File

@ -5,6 +5,7 @@ package Lemonldap::NG::Portal::Main::Menu;
use strict;
use Mouse;
use Clone 'clone';
use JSON qw(from_json to_json);
our $VERSION = '2.1.0';
@ -18,7 +19,10 @@ has menuModules => (
builder => sub {
my $conf = $_[0]->{conf};
my @res;
foreach (qw(Appslist ChangePassword LoginHistory OidcConsents Logout)) {
foreach (
qw(FavApps Appslist ChangePassword LoginHistory OidcConsents Logout)
)
{
my $cond = $conf->{"portalDisplay$_"} // 1;
$_[0]->p->logger->debug("Evaluate condition $cond for module $_");
my $tmp =
@ -59,9 +63,14 @@ sub params {
my ( $self, $req ) = @_;
$self->{conf}->{imgPath} ||= $self->{staticPrefix};
my %res;
my @defaultTabs = (qw/appslist password logout loginHistory oidcConsents/);
my @defaultTabs =
(qw/favApps appslist password logout loginHistory oidcConsents/);
my @customTabs = split( /,\s*/, $self->{conf}->{customMenuTabs} || '' );
$res{DISPLAY_MODULES} = $self->displayModules($req);
$res{AUTH_ERROR_TYPE} =
$req->error_type( $res{AUTH_ERROR} = $req->menuError );
# Tab to display
# Get the tab URL parameter
@ -101,14 +110,10 @@ sub params {
$res{DISPLAY_TAB} = $req->param("tab");
}
else {
$res{DISPLAY_TAB} = "appslist";
$res{DISPLAY_TAB} = $res{DISPLAY_MODULES}->[0]->{FavApps} ? "favApps" : "appslist";
}
}
$res{DISPLAY_MODULES} = $self->displayModules($req);
$res{AUTH_ERROR_TYPE} =
$req->error_type( $res{AUTH_ERROR} = $req->menuError );
# Display menu 2fRegisters link only if at least a 2F device is registered
$res{sfaManager} =
$self->p->_sfEngine->display2fRegisters( $req, $req->userData );
@ -123,30 +128,36 @@ sub params {
sub displayModules {
my ( $self, $req ) = @_;
my $displayModules = [];
my $favAppslistRef = $self->favAppslist($req);
# Foreach module, eval condition
# Store module in result if condition is valid
foreach my $module ( @{ $self->menuModules } ) {
$self->logger->debug("Check if $module->[0] has to be displayed");
if ( $module->[1]->( $req, $req->sessionInfo ) ) {
if ( $module->[1]->( $req, $req->userData ) ) {
my $moduleHash = { $module->[0] => 1 };
if ( $module->[0] eq 'Appslist' ) {
$moduleHash->{'APPSLIST_LOOP'} = $self->appslist($req);
if ( $module->[0] eq 'FavApps' ) {
$moduleHash->{'FavApps'} = scalar @{$favAppslistRef};
$moduleHash->{'FAVAPPS_LOOP'} = $favAppslistRef;
}
elsif ( $module->[0] eq 'Appslist' ) {
$moduleHash->{'APPSLIST_LOOP'} =
$self->appslist( $req, $favAppslistRef );
}
elsif ( $module->[0] eq 'LoginHistory' ) {
$moduleHash->{'SUCCESS_LOGIN'} =
$self->p->mkSessionArray(
$req->{sessionInfo}->{_loginHistory}->{successLogin},
$req->{userData}->{_loginHistory}->{successLogin},
"", 0, 0 );
$moduleHash->{'FAILED_LOGIN'} =
$self->p->mkSessionArray(
$req->{sessionInfo}->{_loginHistory}->{failedLogin},
$req->{userData}->{_loginHistory}->{failedLogin},
"", 0, 1 );
}
elsif ( $module->[0] eq 'OidcConsents' ) {
$moduleHash->{'OIDC_CONSENTS'} =
$self->p->mkOidcConsent( $req->sessionInfo );
$self->p->mkOidcConsent( $req->userData );
}
push @$displayModules, $moduleHash;
}
@ -155,11 +166,40 @@ sub displayModules {
return $displayModules;
}
## @method arrayref favAppslist()
# Returns favorite applications list as HTML::Template loop
# @return applications list
sub favAppslist {
my ( $self, $req ) = @_;
my $user = $req->userData->{ $self->conf->{whatToTrace} };
# Read existing favorite Apps
$self->logger->debug("Looking for favorite Apps...");
my $_favApps;
if ( $req->userData->{_favApps} ) {
$_favApps = eval {
from_json( $req->userData->{_favApps}, { allow_nonref => 1 } );
};
if ($@) {
$self->logger->error("Corrupted session (_favApps): $@");
return $self->p->sendError( $req, "Corrupted session", 500 );
}
}
else {
$self->logger->debug("No favorite Apps found");
$_favApps = [];
}
$self->logger->debug(
scalar @$_favApps . " favorite Apps found for $user" );
return $_favApps;
}
## @method arrayref appslist()
# Returns categories and applications list as HTML::Template loop
# @return categories and applications list
sub appslist {
my ( $self, $req ) = @_;
my ( $self, $req, $favAppslistRef ) = @_;
my $appslist = [];
return $appslist unless defined $self->conf->{applicationList};
@ -168,7 +208,8 @@ sub appslist {
my $catlevel = 0;
my $applicationList = clone( $self->conf->{applicationList} );
my $filteredList = $self->_filter( $req, $applicationList );
my $filteredList =
$self->_filter( $req, $applicationList, $favAppslistRef );
push @$appslist,
$self->_buildCategoryHash( $req, "", $filteredList, $catlevel );
@ -238,10 +279,11 @@ sub _buildApplicationHash {
my $applications;
# Get application items
my $appname = $apphash->{options}->{name} || $appid;
my $appuri = $apphash->{options}->{uri} || "";
my $appdesc = $apphash->{options}->{description};
my $applogo = $apphash->{options}->{logo};
my $appname = $apphash->{options}->{name} || $appid;
my $appuri = $apphash->{options}->{uri} || "";
my $appdesc = $apphash->{options}->{description};
my $applogo = $apphash->{options}->{logo};
my $appIsFavApp = $apphash->{options}->{isFavApp} || "0";
# Detect sub applications
my $subapphash;
@ -267,6 +309,7 @@ sub _buildApplicationHash {
appdesc => $appdesc,
applogo => $applogo,
appid => $appid,
appisfav => $appIsFavApp,
};
$applicationHash->{applications} = $applications if $applications;
return $applicationHash;
@ -279,7 +322,7 @@ sub _buildApplicationHash {
# @param $apphash Menu elements
# @return filtered hash
sub _filter {
my ( $self, $req, $apphash ) = @_;
my ( $self, $req, $apphash, $favAppslistRef ) = @_;
my $filteredHash;
my $key;
@ -289,7 +332,7 @@ sub _filter {
}
# Filter hash
$self->_filterHash( $req, $filteredHash );
$self->_filterHash( $req, $filteredHash, $favAppslistRef );
# Hide empty categories
$self->_isCategoryEmpty($filteredHash);
@ -302,8 +345,7 @@ sub _filter {
# @param $apphash Menu elements
# @return filtered hash
sub _filterHash {
my ( $self, $req, $apphash ) = @_;
my ( $self, $req, $apphash, $favAppslistRef ) = @_;
foreach my $key ( keys %$apphash ) {
next if $key =~ /(type|options|catname)/;
if ( $apphash->{$key}->{type}
@ -311,7 +353,7 @@ sub _filterHash {
{
# Filter the category
$self->_filterHash( $req, $apphash->{$key} );
$self->_filterHash( $req, $apphash->{$key}, $favAppslistRef );
}
if ( $apphash->{$key}->{type}
and $apphash->{$key}->{type} eq "application" )
@ -322,7 +364,17 @@ sub _filterHash {
next if $appkey =~ /(type|options|catname)/;
# We have sub elements, so we filter them
$self->_filterHash( $req, $apphash->{$key} );
$self->_filterHash( $req, $apphash->{$key}, $favAppslistRef );
}
# Check if app is marked as favorite
my $uri = $apphash->{$key}->{options}->{uri};
foreach (@$favAppslistRef) {
if ( $_->{appuri} eq $uri ) {
$apphash->{$key}->{options}->{isFavApp} = "1";
$self->logger->debug("App $uri is marked as favorite");
last;
}
}
# Check rights
@ -348,7 +400,7 @@ sub _filterHash {
if ( my $sub = $self->p->spRules->{$p} ) {
eval {
delete $apphash->{$key}
unless ( $sub->( $req, $req->sessionInfo ) );
unless ( $sub->( $req, $req->userData ) );
};
if ($@) {
$self->logger->error("Partner rule $p returns: $@");
@ -373,7 +425,7 @@ sub _filterHash {
delete $apphash->{$key}
unless (
$self->p->HANDLER->grant(
$req, $req->sessionInfo, $appuri, $cond, $vhost
$req, $req->userData, $appuri, $cond, $vhost
)
);
next;

View File

@ -27,6 +27,7 @@ our @pList = (
portalForceAuthn => '::Plugins::ForceAuthn',
checkUser => '::Plugins::CheckUser',
impersonationRule => '::Plugins::Impersonation',
portalDisplayFavApps => '::Plugins::FavApps',
);
##@method list enabledPlugins

View File

@ -15,7 +15,6 @@ extends 'Lemonldap::NG::Portal::Main::Plugin',
'Lemonldap::NG::Portal::Lib::_tokenRule';
# INITIALIZATION
has ott => (
is => 'rw',
lazy => 1,
@ -54,8 +53,7 @@ sub init {
return 1;
}
# RUNNING METHOD
# RUNNING METHODS
sub check {
my ( $self, $req ) = @_;
my ( $attrs, $array_attrs, $array_hdrs ) = ( {}, [], [] );

View File

@ -0,0 +1,213 @@
package Lemonldap::NG::Portal::Plugins::FavApps;
use strict;
use Mouse;
use JSON qw(from_json to_json);
our $VERSION = '2.1.0';
extends 'Lemonldap::NG::Portal::Main::Plugin';
# INITIALIZATION
has rule => ( is => 'rw', default => sub { 1 } );
sub init {
my $self = shift;
my $hd = $self->p->HANDLER;
$self->addAuthRoute( favapps => 'register', ['POST'] );
$self->addAuthRoute( favapps => 'read', ['GET'] );
$self->addAuthRoute( favapps => 'reset', ['DELETE'] );
# Parse activation rule
$self->logger->debug(
"FavApps activation rule -> " . $self->conf->{portalDisplayFavApps} );
my $rule =
$hd->buildSub( $hd->substitute( $self->conf->{portalDisplayFavApps} ) );
unless ($rule) {
$self->error(
"Bad FavApps activation rule -> " . $hd->tsv->{jail}->error );
return 0;
}
$self->rule($rule);
return 1;
}
# RUNNING METHODS
sub register {
my ( $self, $req ) = @_;
my $user = $req->userData->{ $self->conf->{whatToTrace} };
# Check activation rule
unless ( $self->rule->( $req, $req->userData ) ) {
$self->userLogger->warn(
'FavApps requested by an unauthorized user ('
. $req->{user}
. ')' );
$self->logger->debug('FavApps not authorized');
return [
200,
[
'Content-Type' => 'application/json',
'Content-Length' => 11,
],
['{"error":0}']
];
}
my ( $uri, $result );
unless ( $uri = $req->param('uri') ) {
return $self->p->sendError( $req, 'Missing App. URI', 400 );
}
$self->logger->debug("Favorite application URI received : $uri");
my $id = $req->param('id') || '';
my $logo = $req->param('logo') || '';
my $desc = $req->param('desc') || '';
my $name = $req->param('name') || '';
# Read existing favorite Apps
$self->logger->debug("Looking for $user favorite Apps...");
my $_favApps;
if ( $req->userData->{_favApps} ) {
$_favApps = eval {
from_json( $req->userData->{_favApps}, { allow_nonref => 1 } );
};
if ($@) {
$self->logger->error("Corrupted session (_favApps): $@");
return $self->p->sendError( $req, "Corrupted session", 500 );
}
}
else {
$self->logger->debug("No favorite Apps found for $user");
$_favApps = [];
}
# Append or remove favorite application
my $nbrApps = @$_favApps;
$self->logger->debug("$nbrApps favorite Apps found");
if ( $nbrApps && $self->_isFavApp( $_favApps, $uri ) ) {
$_favApps = $self->_removeFavApp( $_favApps, $uri );
$self->p->updatePersistentSession( $req,
{ _favApps => to_json($_favApps) } );
$result = '{"result":0}';
$self->userLogger->notice(
"Favorite apps deletion of $uri succeeds for $user");
}
else {
if ( $nbrApps < $self->conf->{favAppsMaxNumber} ) {
$_favApps =
$self->_appendFavApp( $_favApps, $uri, $id, $logo, $desc, $name );
$self->p->updatePersistentSession( $req,
{ _favApps => to_json($_favApps) } );
$result = '{"result":1}';
$self->userLogger->notice(
"Favorite apps registration of $uri succeeds for $user");
}
else {
$result = '{"error":1}';
$self->userLogger->notice(
"Max number of favorite apps reached for $user");
}
}
return [
200,
[
'Content-Type' => 'application/json',
'Content-Length' => length($result),
],
[$result]
];
}
sub read {
my ( $self, $req ) = @_;
my $user = $req->userData->{ $self->conf->{whatToTrace} };
# Read existing favorite Apps
$self->logger->debug("Looking for favorite Apps...");
my $_favApps;
if ( $req->userData->{_favApps} ) {
$_favApps = eval {
from_json( $req->userData->{_favApps}, { allow_nonref => 1 } );
};
if ($@) {
$self->logger->error("Corrupted session (_favApps): $@");
return $self->p->sendError( $req, "Corrupted session", 500 );
}
}
else {
$self->logger->debug("No favorite Apps found");
$_favApps = [];
}
# Serialize data
my $data = to_json( {
result => 1,
apps => $_favApps
}
);
$self->logger->debug(
scalar @$_favApps . " favorite Apps found for $user" );
return [
200,
[
'Content-Type' => 'application/json',
'Content-Length' => length($data),
],
[$data]
];
}
sub reset {
my ( $self, $req ) = @_;
my $user = $req->userData->{ $self->conf->{whatToTrace} };
$self->p->updatePersistentSession( $req, { _favApps => '' } );
$self->userLogger->notice("$user favorite Apps. RESET");
return [
200,
[
'Content-Type' => 'application/json',
'Content-Length' => 12,
],
['{"result":1}']
];
}
sub _isFavApp {
my ( $self, $_favApps, $uri ) = @_;
my $test = 0;
foreach (@$_favApps) {
if ( $_->{appuri} eq $uri ) {
$test = 1;
last;
}
}
$self->logger->debug("App. already registered? $test");
return $test;
}
sub _appendFavApp {
my ( $self, $_favApps, $uri, $id, $logo, $desc, $name ) = @_;
push @$_favApps,
{
appuri => $uri,
appid => $id,
applogo => $logo,
appdesc => $desc,
appname => $name
};
$self->logger->debug("App. $uri appended");
return $_favApps;
}
sub _removeFavApp {
my ( $self, $_favApps, $uri ) = @_;
@$_favApps = grep { $_->{appuri} ne $uri } @$_favApps;
$self->logger->debug("App. $uri removed");
return $_favApps;
}
1;

View File

@ -0,0 +1,50 @@
###
LemonLDAP::NG Favorite Applications script
###
# FavApps function (launched by "star" icon)
FavApps = (star) ->
$.ajax
type: "POST"
url: "#{portal}favapps"
data:
id: star.attr 'aid'
uri: star.attr 'uri'
name: star.attr 'name'
logo: star.attr 'logo'
desc: star.attr 'desc'
dataType: 'json'
success: (resp) ->
if resp.error
console.log 'Max number reached'
switchStar star, 0
else if resp.error == 0
console.log 'Not authorized'
switchStar star, 0
else if resp.result
console.log 'App. registered'
switchStar star, 1
else
console.log 'App. unregistered'
switchStar star, 0
error: switchStar star, '0'
ResetFavApps = ->
$.ajax
type: "DELETE"
url: "#{portal}favapps"
success: (resp) ->
if resp.result
console.log 'Favorite Apps. reset'
window.location.reload()
else
console.log 'Error'
switchStar = (star, status) ->
star.attr('src', "#{window.staticPrefix}common/icons/star#{status}.png")
#window.location.reload()
# Switch "star" ans Reset events
$(document).ready ->
$('body').on 'click', '.star', () -> FavApps $(this)
$('#reset').on 'click', () -> ResetFavApps()

View File

@ -17,7 +17,7 @@ displayError = (j, status, err) ->
console.log 'Returned error', res
setMsg res, 'warning'
token=''
token = ''
getKey = (reset) ->
setMsg 'yourTotpKey', 'warning'

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,69 @@
// Generated by CoffeeScript 1.12.7
/*
LemonLDAP::NG Favorite Applications script
*/
(function() {
var FavApps, ResetFavApps, switchStar;
FavApps = function(star) {
return $.ajax({
type: "POST",
url: portal + "favapps",
data: {
id: star.attr('aid'),
uri: star.attr('uri'),
name: star.attr('name'),
logo: star.attr('logo'),
desc: star.attr('desc')
},
dataType: 'json',
success: function(resp) {
if (resp.error) {
console.log('Max number reached');
return switchStar(star, 0);
} else if (resp.error === 0) {
console.log('Not authorized');
return switchStar(star, 0);
} else if (resp.result) {
console.log('App. registered');
return switchStar(star, 1);
} else {
console.log('App. unregistered');
return switchStar(star, 0);
}
},
error: switchStar(star, '0')
});
};
ResetFavApps = function() {
return $.ajax({
type: "DELETE",
url: portal + "favapps",
success: function(resp) {
if (resp.result) {
console.log('Favorite Apps. reset');
return window.location.reload();
} else {
return console.log('Error');
}
}
});
};
switchStar = function(star, status) {
return star.attr('src', window.staticPrefix + "common/icons/star" + status + ".png");
};
$(document).ready(function() {
$('body').on('click', '.star', function() {
return FavApps($(this));
});
return $('#reset').on('click', function() {
return ResetFavApps();
});
});
}).call(this);

View File

@ -0,0 +1 @@
(function(){var FavApps,ResetFavApps,switchStar;FavApps=function(star){return $.ajax({type:"POST",url:portal+"favapps",data:{id:star.attr("aid"),uri:star.attr("uri"),name:star.attr("name"),logo:star.attr("logo"),desc:star.attr("desc")},dataType:"json",success:function(resp){if(resp.error){console.log("Max number reached");return switchStar(star,0)}else if(resp.error===0){console.log("Not authorized");return switchStar(star,0)}else if(resp.result){console.log("App. registered");return switchStar(star,1)}else{console.log("App. unregistered");return switchStar(star,0)}},error:switchStar(star,"0")})};ResetFavApps=function(){return $.ajax({type:"DELETE",url:portal+"favapps",success:function(resp){if(resp.result){console.log("Favorite Apps. reset");return window.location.reload()}else{return console.log("Error")}}})};switchStar=function(star,status){return star.attr("src",window.staticPrefix+"common/icons/star"+status+".png")};$(document).ready(function(){$("body").on("click",".star",function(){return FavApps($(this))});return $("#reset").on("click",function(){return ResetFavApps()})})}).call(this);

View File

@ -1,4 +1,4 @@
// Generated by CoffeeScript 1.12.8
// Generated by CoffeeScript 1.12.7
/*
LemonLDAP::NG TOTP registration script

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Enter TOTP code",
"enterYubikey":"يرجى استخدام يوبي كي الخاص بك",
"errorMsg":"رسالة خاطئة",
"yourFavApps":"Favorite applications",
"fillTheForm":"Fill the form",
"firstName":"الاسم الاول",
"forbidden":"Access FORBIDDEN",
@ -199,6 +200,7 @@
"removeOtherSessions":"إزالة الجلسات الأخرى",
"resendConfirmMail":"هل تريد إعادة إرسال رسالة التأكيد؟",
"resentConfirm":"هل تريد إعادة إرسال رسالة التأكيد؟",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"إعادة تعيين كلمة المرور الخاصة بي",
"rightsReloadNeedsLogout":" إعادة تحميل الحقوق تحتاج إلى تسجيل الخروج وتسجيل الدخول مرة أخرى",
"scope":"نطاق",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Gebe den TOTP Code ein",
"enterYubikey":"Benutze bitte deinen Yubikey",
"errorMsg":"Fehlermeldung",
"yourFavApps":"Favorite applications",
"fillTheForm":"Fülle das Formular aus",
"firstName":"Vorname",
"forbidden":"Access FORBIDDEN",
@ -199,6 +200,7 @@
"removeOtherSessions":"Andere Sitzungen löschen",
"resendConfirmMail":"Bestätigungsmail erneuert senden ?",
"resentConfirm":"Möchtest du, dass die Bestätigungsmail erneut gesendet wird ?",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"Mein Passwort zurücksetzen",
"rightsReloadNeedsLogout":"Zum Neuladen der Rechte musst du dich ab- und wieder anmelden",
"scope":"Scope",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Enter TOTP code",
"enterYubikey":"Please use your Yubikey",
"errorMsg":"Error Message",
"yourFavApps":"Favorite applications",
"fillTheForm":"Fill the form",
"firstName":"First name",
"forbidden":"Access FORBIDDEN",
@ -199,6 +200,7 @@
"removeOtherSessions":"Remove other sessions",
"resendConfirmMail":"Resend confirmation mail?",
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"Reset my password",
"rightsReloadNeedsLogout": "Rights reloads need to logout and login again",
"scope":"Scope",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Enter TOTP code",
"enterYubikey":"Please use your Yubikey",
"errorMsg":"Error Message",
"yourFavApps":"Favorite applications",
"fillTheForm":"Fill the form",
"firstName":"First name",
"forbidden":"Access FORBIDDEN",
@ -199,6 +200,7 @@
"removeOtherSessions":"Remove other sessions",
"resendConfirmMail":"Resend confirmation mail?",
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"Reset my password",
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"scope":"Scope",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Enter TOTP code",
"enterYubikey":"Please use your Yubikey",
"errorMsg":"Virhe viesti",
"yourFavApps":"Favorite applications",
"fillTheForm":"Fill the form",
"firstName":"Etunimi",
"forbidden":"Access FORBIDDEN",
@ -199,6 +200,7 @@
"removeOtherSessions":"Remove other sessions",
"resendConfirmMail":"Uudelleen lähetä vahvistus sähköposti?",
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"Palauta salasanani?",
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"scope":"Scope",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Entrez le code TOTP",
"enterYubikey":"Utilisez votre Yubikey",
"errorMsg":"Message d'erreur",
"yourFavApps":"Applications favorites",
"fillTheForm":"Remplissez le formulaire",
"forbidden":"Accès INTERDIT",
"firstName":"Prénom",
@ -199,6 +200,7 @@
"removeOtherSessions":"Fermer les autres sessions",
"resendConfirmMail":"Renvoyer le mail de confirmation ?",
"resentConfirm":"Voulez-vous que le message de confirmation soit renvoyé ?",
"resetFavApps":"Réinitialiser mes applications favorites",
"resetPwd":"Réinitialiser mon mot de passe",
"rightsReloadNeedsLogout": "Le rechargement des droits nécessite une déconnexion",
"scope": "Informations",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Inserisci il codice TOTP",
"enterYubikey":"Utilizza il tuo Yubikey",
"errorMsg":"Messaggio di errore",
"yourFavApps":"Favorite applications",
"fillTheForm":"Compila il modulo",
"firstName":"Nome",
"forbidden":"Accesso VIETATO",
@ -199,6 +200,7 @@
"removeOtherSessions":"Rimuovere altre sessioni",
"resendConfirmMail":"Inviare nuovamente mail di conferma?",
"resentConfirm":"Vuoi inviare di nuovo la mail di conferma?",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"Reimpostare la password",
"rightsReloadNeedsLogout":"Le ricariche dei diritti necessitano di disconnettersi e di riconnettersi",
"scope":"Ambito",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Enter TOTP code",
"enterYubikey":"Please use your Yubikey",
"errorMsg":"Error Message",
"yourFavApps":"Favorite applications",
"fillTheForm":"Fill the form",
"firstName":"First name",
"forbidden":"Access FORBIDDEN",
@ -199,6 +200,7 @@
"removeOtherSessions":"Remove other sessions",
"resendConfirmMail":"Resend confirmation mail?",
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"Reset my password",
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"scope":"Scope",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Enter TOTP code",
"enterYubikey":"Please use your Yubikey",
"errorMsg":"Error Message",
"yourFavApps":"Favorite applications",
"fillTheForm":"Fill the form",
"firstName":"First name",
"forbidden":"Access FORBIDDEN",
@ -199,6 +200,7 @@
"removeOtherSessions":"Remove other sessions",
"resendConfirmMail":"Resend confirmation mail?",
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"Reset my password",
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"scope":"Scope",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Enter TOTP code",
"enterYubikey":"Please use your Yubikey",
"errorMsg":"Error Message",
"yourFavApps":"Favorite applications",
"fillTheForm":"Fill the form",
"firstName":"First name",
"forbidden":"Access FORBIDDEN",
@ -199,6 +200,7 @@
"removeOtherSessions":"Remove other sessions",
"resendConfirmMail":"Resend confirmation mail?",
"resentConfirm":"Do you want the confirmation mail to be resent?",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"Reset my password",
"rightsReloadNeedsLogout":"Rights reloads need to logout and login again",
"scope":"Scope",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Enter TOTP code",
"enterYubikey":"Vui lòng sử dụng Yubikey của bạn",
"errorMsg":"Thông báo lỗi",
"yourFavApps":"Favorite applications",
"fillTheForm":"Fill the form",
"firstName":"Tên",
"forbidden":"Access FORBIDDEN",
@ -199,6 +200,7 @@
"removeOtherSessions":"Xóa các phiên khác",
"resendConfirmMail":"Gửi lại thư xác nhận?",
"resentConfirm":"Bạn có muốn gửi lại thư xác nhận không?",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"Đặt lại mật khẩu của tôi",
"rightsReloadNeedsLogout":"Tải lại quyền cần đăng xuất và đăng nhập lại",
"scope":"Phạm vi",

View File

@ -129,6 +129,7 @@
"enterTotpCode":"Enter TOTP code",
"enterYubikey":"请使用您的Yubikey",
"errorMsg":"错误消息",
"yourFavApps":"Favorite applications",
"fillTheForm":"Fill the form",
"firstName":"名",
"forbidden":"Access FORBIDDEN",
@ -199,6 +200,7 @@
"removeOtherSessions":"移除其他会话",
"resendConfirmMail":"重新发送确认邮件?",
"resentConfirm":"您想确认邮件被重新发送吗?",
"resetFavApps":"Reset my favorite Apps.",
"resetPwd":"重置我的密码",
"rightsReloadNeedsLogout":"重新加载权限需要登出并且再次登录",
"scope":"Scope",

View File

@ -42,14 +42,17 @@
<!-- //if:usedebianlibs
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX"><TMPL_VAR NAME="SKIN">/js/skin.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">common/js/portal.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">common/js/favapps.min.js"></script>
<script type="text/javascript" src="/javascript/bootstrap4/js/bootstrap.min.js"></script>
//elsif:jsminified
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX"><TMPL_VAR NAME="SKIN">/js/skin.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">common/js/portal.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">common/js/favapps.min.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">bwr/bootstrap/dist/js/bootstrap.min.js"></script>
//else -->
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX"><TMPL_VAR NAME="SKIN">/js/skin.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">common/js/portal.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">common/js/favapps.js"></script>
<script type="text/javascript" src="<TMPL_VAR NAME="STATIC_PREFIX">bwr/bootstrap/dist/js/bootstrap.js"></script>
<!-- //endif -->
<TMPL_VAR NAME="CUSTOM_SCRIPT">

View File

@ -20,7 +20,12 @@
<!-- Tabs list -->
<ul class="navbar-nav mr-auto">
<TMPL_LOOP NAME="DISPLAY_MODULES">
<TMPL_IF NAME="FavApps">
<li class="nav-item"><a class="nav-link" href="#favApps"><span>
<img src="<TMPL_VAR NAME="STATIC_PREFIX">common/icons/star1.png" width="16" height="16" alt="yourFavApps" />
<span trspan="yourFavApps">Your favorite applications</span>
</span></a></li>
</TMPL_IF>
<TMPL_IF NAME="Appslist">
<li class="nav-item"><a class="nav-link" href="#appslist"><span>
<img src="<TMPL_VAR NAME="STATIC_PREFIX">common/icons/application_cascade.png" width="16" height="16" alt="appslist" />
@ -42,7 +47,7 @@
<TMPL_IF NAME="OidcConsents">
<li class="nav-item"><a class="nav-link" href="#oidcConsents"><span>
<img src="<TMPL_VAR NAME="STATIC_PREFIX">common/icons/oidc.png" width="16" height="16" alt="login history" />
<span trspan="oidcConsents">OIDC Consent</span>
<span trspan="oidcConsents">OIDC Consents</span>
</span></a></li>
</TMPL_IF>
<TMPL_IF NAME="Logout">
@ -82,8 +87,70 @@
<!-- Tabs content -->
<TMPL_LOOP NAME="DISPLAY_MODULES">
<TMPL_IF NAME="FavApps">
<div id="favApps">
<div class="category cat-level-1 card border-secondary">
<div class="card-header text-white bg-secondary">
<h4 class="catname card-title" trspan="yourFavApps">Your favorite applications</h4>
</div>
<div id="favApps">
<div class="card-body">
<!-- Applications -->
<div class="row">
<TMPL_LOOP NAME="FAVAPPS_LOOP">
<TMPL_IF NAME="Appslist">
<!-- Application -->
<div class="col-md-4">
<div class="application <TMPL_VAR NAME="appid"> card">
<a href="<TMPL_VAR NAME="appuri">" title="<TMPL_VAR NAME="appname">" >
<div class="card-body">
<div class="row">
<!-- Logo (optional) -->
<TMPL_IF NAME="applogo">
<div class="col-3">
<img src="<TMPL_VAR NAME="STATIC_PREFIX">common/apps/<TMPL_VAR NAME="applogo">"
class="applogo <TMPL_VAR NAME="appid"> img-fluid"
alt="<TMPL_VAR NAME="appname">" />
</div>
<div class="col-9">
<TMPL_ELSE>
<div class="col-12">
</TMPL_IF>
<!-- Name and link (mandatory) -->
<h5 class="appname <TMPL_VAR NAME="appid"> card-title">
<TMPL_VAR NAME="appname">
</h5>
<!-- Description (optional) -->
<TMPL_IF NAME="appdesc">
<p class="appdesc <TMPL_VAR NAME="appid"> card-subtitle mb-2 text-muted">
<TMPL_VAR NAME="appdesc">
</p>
</TMPL_IF>
</div>
</div>
</div>
</a>
</div>
</div>
<!-- End of applications loop -->
</TMPL_LOOP>
</div>
</div>
<div class="buttons">
<span id="reset" class="btn btn-danger" role="button">
<span class="fa fa-trash-o"></span>
<span trspan="resetFavApps">Reset my favorite Apps.</span>
</span>
</div>
&nbsp;
</div>
</div>
</div>
</TMPL_IF>
<TMPL_IF NAME="Appslist">
<div id="appslist">
<TMPL_LOOP NAME="APPSLIST_LOOP">
@ -107,7 +174,19 @@
<!-- Application -->
<div class="col-md-4">
<TMPL_IF NAME="STARS">
<div>
<img class="star"
aid="<TMPL_VAR NAME="appid">"
uri="<TMPL_VAR NAME="appuri">"
name="<TMPL_VAR NAME="appname">"
logo="<TMPL_VAR NAME="applogo">"
desc="<TMPL_VAR NAME="appdesc">"
src="<TMPL_VAR NAME="STATIC_PREFIX">common/icons/star<TMPL_VAR NAME="appisfav">.png"/>
</div>
</TMPL_IF>
<div class="application <TMPL_VAR NAME="appid"> card">
<a href="<TMPL_VAR NAME="appuri">" title="<TMPL_VAR NAME="appname">" >
<div class="card-body">
@ -126,6 +205,7 @@
<!-- Name and link (mandatory) -->
<h5 class="appname <TMPL_VAR NAME="appid"> card-title">
<TMPL_VAR NAME="appname">
</h5>

View File

@ -344,7 +344,7 @@ sub op {
oidcRPMetaDataOptionsDisplayName => "RP",
oidcRPMetaDataOptionsIDTokenExpiration => 3600,
oidcRPMetaDataOptionsClientID => "rpid",
oidcRPMetaDataOptionsIDTokenSignAlg => "HS512",
oidcRPMetaDataOptionsIDTokenSignAlg => "RS512",
oidcRPMetaDataOptionsBypassConsent => 0,
oidcRPMetaDataOptionsPublic => 1,
oidcRPMetaDataOptionsUserIDAttr => "",

View File

@ -0,0 +1,200 @@
use Test::More;
use strict;
use IO::String;
BEGIN {
require 't/test-lib.pm';
}
my $res;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
authentication => 'Demo',
userDB => 'Same',
brutForceProtection => 0,
portalMainLogo => 'common/logos/logo_llng_old.png',
checkUser => 0,
portalDisplayFavApps => 1,
portalDisplayOidcConsents => 1,
portalDisplayLoginHistory => 1,
portalDisplayAppslist => 1,
portalDisplayLogout => 1,
}
}
);
## Try to authenticate
ok(
$res = $client->_post(
'/',
IO::String->new('user=dwho&password=dwho'),
length => 23,
accept => 'text/html',
),
'Auth query'
);
count(1);
my $id = expectCookie($res);
expectRedirection( $res, 'http://auth.example.com/' );
ok(
$res = $client->_get(
'/',
cookie => "lemonldap=$id",
accept => 'text/html'
),
'Get Menu'
);
count(1);
# Parse Menu
my @menu =
map m%<li class="nav-item"><a class="nav-link" href="#(.+)?"><span>%g,
$res->[2]->[0];
ok( scalar @menu == 5, 'Menu with five links found' )
or print STDERR Dumper($res);
ok( $menu[0] eq 'appslist', 'appslist link found' )
or print STDERR Dumper( \@menu );
ok( $menu[1] eq 'password', 'password link found' )
or print STDERR Dumper( \@menu );
ok( $menu[2] eq 'loginHistory', 'loginHistory link found' )
or print STDERR Dumper( \@menu );
ok( $menu[3] eq 'oidcConsents', 'oidcConsents link found' )
or print STDERR Dumper( \@menu );
ok( $menu[4] eq 'logout', 'logout link found' )
or print STDERR Dumper( \@menu );
count(6);
my @stars =
map m%src="/static/common/icons/star0\.png"/>%g,
$res->[2]->[0];
ok( scalar @stars == 3, 'Three silver stars found' )
or print STDERR Dumper($res);
count(1);
## Try to register a favorite app
my $query =
'id=0002-app&uri=http%3A%2F%2Ftest1.example.com%2F&name=Application+Test+1&logo=demo.png&desc=A+simple+application+displaying+authenticated+user';
ok(
$res = $client->_post(
'/favapps',
IO::String->new($query),
cookie => "lemonldap=$id",
length => length($query),
accept => 'text/html',
),
'Register Test1 FavApp query'
);
$query =
'id=0006-app&uri=http%3A%2F%2Fmanager.example.com%2Fnotifications.html&name=Notifications+explorer&logo=database.png&desc=Explore+WebSSO+notifications
';
ok(
$res = $client->_post(
'/favapps',
IO::String->new($query),
cookie => "lemonldap=$id",
length => length($query),
accept => 'text/html',
),
'Register Notifications FavApp query'
);
count(2);
# Parse Page
ok(
$res = $client->_get(
'/',
cookie => "lemonldap=$id",
accept => 'text/html'
),
'Get Menu'
);
ok( $res->[2]->[0] =~ qr%<img src="/static/common/logos/logo_llng_old.png"%,
'Found custom Main Logo' )
or print STDERR Dumper( $res->[2]->[0] );
@stars =
map m%src="/static/common/icons/star1\.png"/>%g,
$res->[2]->[0];
ok( scalar @stars == 2, 'Two gold stars found' )
or print STDERR Dumper($res);
@stars =
map m%src="/static/common/icons/star0\.png"/>%g,
$res->[2]->[0];
ok( scalar @stars == 1, 'One silver star found' )
or print STDERR Dumper($res);
ok(
$res->[2]->[0] =~
m%<span trspan="resetFavApps">Reset my favorite Apps\.</span>%,
'Found resetFavApps button'
) or print STDERR Dumper( $res->[2]->[0] );
count(5);
ok(
$res = $client->_get(
'/favapps',
cookie => "lemonldap=$id",
accept => 'application/json',
),
'Get FavApps'
);
eval { $res = JSON::from_json( $res->[2]->[0] ) };
ok( not($@), 'Content is JSON' )
or explain( $res->[2]->[0], 'JSON content' );
ok( $res->{result} == 1, 'FavApps received' );
ok(
$res->{apps}->[0]->{appuri} =~ m%http://test1.example.com/%,
'Found favorite Apps -> http://test1.example.com'
) or explain( $res->{apps}, "test1 FavApps NOT registered" );
ok(
$res->{apps}->[0]->{appdesc} =~
m%A simple application displaying authenticated user%,
'Found favorite Apps description'
) or explain( $res->{apps}, "description NOT registered" );
ok( $res->{apps}->[0]->{applogo} =~ m%demo\.png%, 'Found favorite Apps logo' )
or explain( $res->{apps}, "logo NOT registered" );
ok( $res->{apps}->[0]->{appname} =~ m%Application Test 1%,
'Found favorite Apps name' )
or explain( $res->{apps}, "name NOT registered" );
ok( $res->{apps}->[0]->{appid} =~ m%0002-app%, 'Found favorite Apps id' )
or explain( $res->{apps}, "id NOT registered" );
ok(
$res->{apps}->[1]->{appuri} =~
m%http://manager.example.com/notifications.html%,
'Found favorite Apps -> http://manager.example.com/notifications.html'
) or explain( $res->{apps}, "notifications FavApps NOT registered" );
count(9);
ok(
$res = $client->_delete(
'/favapps',
cookie => "lemonldap=$id",
accept => 'application/json',
),
'Delete FavApps'
);
count(1);
ok(
$res = $client->_get(
'/favapps',
cookie => "lemonldap=$id",
accept => 'application/json',
),
'Get FavApps'
);
eval { $res = JSON::from_json( $res->[2]->[0] ) };
ok( not($@), 'Content is JSON' )
or explain( $res->[2]->[0], 'JSON content' );
ok( $res->{result} == 1, 'FavApps received' );
ok( scalar @{ $res->{apps} } == 0, 'NO favorite Apps found' )
or explain( $res->{apps}, "FavApps NOT deleted" );
count(4);
$client->logout($id);
clean_sessions();
done_testing( count() );

View File

@ -1,4 +1,44 @@
{
"applicationList" : {
"1sample" : {
"catname" : "Sample applications",
"test1" : {
"options" : {
"description" : "A simple application displaying authenticated user",
"display" : "auto",
"logo" : "demo.png",
"name" : "Application Test 1",
"uri" : "http://test1.example.com/"
},
"type" : "application"
},
"test2" : {
"options" : {
"description" : "The same simple application displaying authenticated user",
"display" : "auto",
"logo" : "thumbnail.png",
"name" : "Application Test 2",
"uri" : "http://test2.example.com/"
},
"type" : "application"
},
"type" : "category"
},
"2administration" : {
"catname" : "Administration",
"notifications" : {
"options" : {
"description" : "Explore WebSSO notifications",
"display" : "auto",
"logo" : "database.png",
"name" : "Notifications explorer",
"uri" : "http://manager.example.com/notifications.html"
},
"type" : "application"
},
"type" : "category"
}
},
"authentication": "Demo",
"cfgAuthor": "The LemonLDAP::NG team",
"cfgAuthorIP": "127.0.0.1",