Many changes in notifications (#595)

environments/ppa-mbqj77/deployments/1
Xavier Guimard 9 years ago
parent 201913d603
commit c1fb44a2b7
  1. 2
      Makefile
  2. 8
      lemonldap-ng-common/MANIFEST
  3. 5
      lemonldap-ng-common/lib/Lemonldap/NG/Common/Module.pm
  4. 604
      lemonldap-ng-common/lib/Lemonldap/NG/Common/Notification.pm
  5. 150
      lemonldap-ng-common/lib/Lemonldap/NG/Common/Notifications.pm
  6. 145
      lemonldap-ng-common/lib/Lemonldap/NG/Common/Notifications/DBI.pm
  7. 6
      lemonldap-ng-common/lib/Lemonldap/NG/Common/Notifications/File.pm
  8. 95
      lemonldap-ng-common/lib/Lemonldap/NG/Common/Notifications/LDAP.pm
  9. 45
      lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Notifications.pm
  10. 1
      lemonldap-ng-manager/t/lemonldap-ng.ini
  11. 101
      lemonldap-ng-portal/MANIFEST
  12. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Base.pm
  13. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/DBI.pm
  14. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Menu.pm
  15. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Plugin.pm
  16. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CDA.pm
  17. 63
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Notifications.pm
  18. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/Demo.pm
  19. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/Facebook.pm
  20. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/LDAP.pm
  21. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/Null.pm
  22. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/Remote.pm
  23. 2
      lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDB/Slave.pm
  24. 0
      lemonldap-ng-portal/t/10-Notifications-File.t
  25. 123
      lemonldap-ng-portal/t/11-Notifications-DBI.t

@ -899,8 +899,8 @@ zip-dist:
manifest: configure
@for i in ${SRCCOMMONDIR} ${SRCHANDLERDIR} ${SRCPORTALDIR} ${SRCMANAGERDIR}; do \
cd $$i; \
rm -vf MANIFEST*; \
make manifest; \
rm -vf MANIFEST.*; \
cd -; \
done

@ -27,10 +27,12 @@ lib/Lemonldap/NG/Common/Conf/SAML/Metadata.pm
lib/Lemonldap/NG/Common/Conf/Serializer.pm
lib/Lemonldap/NG/Common/Conf/SOAP.pm
lib/Lemonldap/NG/Common/Crypto.pm
lib/Lemonldap/NG/Common/Module.pm
lib/Lemonldap/NG/Common/Notification.pm
lib/Lemonldap/NG/Common/Notification/DBI.pm
lib/Lemonldap/NG/Common/Notification/File.pm
lib/Lemonldap/NG/Common/Notification/LDAP.pm
lib/Lemonldap/NG/Common/Notifications.pm
lib/Lemonldap/NG/Common/Notifications/DBI.pm
lib/Lemonldap/NG/Common/Notifications/File.pm
lib/Lemonldap/NG/Common/Notifications/LDAP.pm
lib/Lemonldap/NG/Common/PSGI.pm
lib/Lemonldap/NG/Common/PSGI/Cli/Lib.pm
lib/Lemonldap/NG/Common/PSGI/Constants.pm

@ -1,11 +1,14 @@
package Lemonldap::NG::Portal::Main::Module;
package Lemonldap::NG::Common::Module;
use strict;
use Mouse;
our $VERSION = '2.0.0';
# Object that provides lmLog and error methods (typically PSGI object)
has p => ( is => 'rw', weak_ref => 1 );
# Lemonldap::NG configuration hash ref
has conf => ( is => 'rw', weak_ref => 1 );
sub lmLog {

@ -1,604 +0,0 @@
##@file
# Notification system for Lemonldap::NG
##@class
# Notification system for Lemonldap::NG
package Lemonldap::NG::Common::Notification;
use strict;
use utf8;
use XML::LibXML;
use XML::LibXSLT;
use CGI::Cookie;
use Scalar::Util 'weaken';
#inherits Lemonldap::NG::Common::Notification::DBI
#inherits Lemonldap::NG::Common::Notification::File
our $VERSION = '2.0.0';
our ( $msg, $parser );
## @cmethod Lemonldap::NG::Common::Notification new(hashref storage)
# Constructor.
# @param $storage same syntax as Lemonldap::NG::Common::Conf object
# @return Lemonldap::NG::Common::Notification object
sub new {
my ( $class, $storage ) = @_;
my $self = bless {}, $class;
(%$self) = (%$storage);
unless ( $self->{p} ) {
$msg = "p=>portal is required";
return 0;
}
weaken $self->{p};
my $type = $self->{type};
$self->{type} = "Lemonldap::NG::Common::Notification::$self->{type}"
unless ( $self->{type} =~ /::/ );
eval "require $self->{type}";
if ($@) {
$msg = "Error: unknown storage type $type ($@)";
return 0;
}
unless ( $self->_prereq ) {
return 0;
}
# Initiate XML parser
$parser = XML::LibXML->new();
return $self;
}
## @method protected void lmLog(string mess, string level)
# Log subroutine. Call Lemonldap::NG::Portal::lmLog().
# @param $mess Text to log
# @param $level Level (debug|info|notice|error)
sub lmLog {
my ( $self, $mess, $level ) = @_;
$self->{p}->lmLog( "[Notification] $mess", $level );
}
## @method string getNotification(Lemonldap::NG::Portal portal)
# Check if notification(s) are available for the connected user.
# If it is, encrypt cookies and generate HTML form content.
# @param $portal Lemonldap::NG::Portal object that call
# @return HTML fragment containing form content
sub getNotification {
my ( $self, $portal ) = @_;
my ( @files, $form );
# Get user datas,
my $uid = $portal->{notificationField} || $portal->{whatToTrace} || 'uid';
$uid =~ s/\$//g;
$uid = $portal->{sessionInfo}->{$uid};
# Check if some notifications have to be done
# 1. For the user
my $user = $self->_get($uid);
# 2. For all users
my $all = $self->_get( $portal->{notificationWildcard} );
# 3. Join results
my $n = {};
if ( $user and $all ) { $n = { %$user, %$all }; }
else { $n = $user ? $user : $all; }
# Return 0 if no files were found
return 0 unless ($n);
# Create XSLT object
my $xslt = XML::LibXSLT->new();
my $style_file = (
-e $portal->{notificationXSLTfile}
? $portal->{notificationXSLTfile}
: $portal->getApacheHtdocsPath() . "/skins/common/notification.xsl"
);
my $style_doc = $parser->parse_file($style_file);
my $stylesheet = $xslt->parse_stylesheet($style_doc);
# Prepare HTML code
@files = map { $n->{$_} } sort keys %$n;
my $i = 0; # Files count
foreach my $file (@files) {
eval {
my $xml = $parser->parse_string($file);
my $j = 0; # Notifications count
# Browse notifications in file
foreach my $notif (
$xml->documentElement->getElementsByTagName('notification') )
{
# Get the reference
my $reference = $notif->getAttribute('reference');
$self->lmLog( "Get reference $reference", 'debug' );
# Check it in session
if (
exists $portal->{sessionInfo}
->{ "notification_" . $reference } )
{
# The notification was already accepted
$self->lmLog(
"Notification $reference was already accepted",
'debug' );
# Remove it from XML
$notif->unbindNode();
next;
}
# Check condition if any
my $condition = $notif->getAttribute('condition');
if ($condition) {
$self->lmLog( "Get condition $condition", 'debug' );
unless ( $portal->safe->reval($condition) ) {
$self->lmLog( "Notification condition not accepted",
'debug' );
# Remove it from XML
$notif->unbindNode();
next;
}
}
$j++;
}
# Go to next file if no notification found
next unless $j;
$i++;
# Transform XML into HTML
my $results = $stylesheet->transform( $xml, start => $i );
$form .= $stylesheet->output_string($results);
};
if ($@) {
$self->lmLog(
"Bad XML file: a notification for $uid was not done ($@)",
'warn' );
return 0;
}
}
# Stop here if nothing to display
return 0 unless $i;
# Now a notification has to be done. Replace cookies by hidden fields
$i = 0;
while ( my $tmp = shift @{ $portal->{cookie} } ) {
$i++;
my $t = $portal->{cipher}->encrypt( $tmp->value );
unless ( defined($t) ) {
$self->lmLog(
"Notification for $uid was not done : $Lemonldap::NG::Common::Crypto::msg",
'warn'
);
return 0;
}
$tmp->value($t);
$form .= qq{<input type="hidden" id="cookie$i" name="cookie$i" value="}
. $tmp->as_string . '" />';
}
$form .= '<input type="hidden" name="type" value="notification"/>';
return $form;
}
## @method boolean checkNotification(Lemonldap::NG::Portal portal)
# Check if notifications have been displayed and accepted.
# @param $portal Lemonldap::NG::Portal object that call
# @return true if all checkboxes have been checked
sub checkNotification {
my ( $self, $portal ) = ( @_, 0, 2 );
my ( $refs, $checks );
# First, rebuild environment (cookies,...)
foreach ( $portal->param() ) {
if (/^cookie/) {
my @tmp = split /(?:=|;\s+)/, $portal->param($_);
my %tmp = @tmp;
my $value = $portal->{cipher}->decrypt( $tmp[1] );
unless ( defined($value) ) {
$self->lmLog( "Unable to decrypt cookie", 'warn' );
return 0;
}
push @{ $portal->{cookie} },
$portal->cookie(
-name => $tmp[0],
-value => $value,
-domain => $tmp{domain},
-path => "/",
-secure => ( grep( /^secure$/, @tmp ) ? 1 : 0 ),
@_,
);
if ( $tmp[0] eq $portal->{cookieName} ) {
my $tmp = $portal->{existingSession};
$portal->{existingSession} = sub { 0 };
$portal->controlExistingSession($value);
$portal->{existingSession} = $tmp;
}
}
elsif (s/^reference//) {
$refs->{$_} = $portal->param("reference$_");
}
elsif ( s/^check// and /^(\d+x\d+)x(\d+)$/ ) {
push @{ $checks->{$1} }, $2;
}
}
$portal->controlExistingSession() unless ( $portal->{sessionInfo} );
unless ( $portal->{sessionInfo} ) {
$self->lmLog( "Invalid session", 'warn' );
return 0;
}
my $result = 1;
foreach my $ref ( keys %$refs ) {
my $uid =
$portal->{notificationField}
|| $portal->{whatToTrace}
|| 'uid';
$uid =~ s/\$//g;
$uid = $portal->{sessionInfo}->{$uid};
# Get notifications by references
# 1. For the user
my $user = $self->_get( $uid, $refs->{$ref} );
# 2. For all users
my $all = $self->_get( $portal->{notificationWildcard}, $refs->{$ref} );
# 3. Join results
my $files = {};
if ( $user and $all ) { $files = { %$user, %$all }; }
else { $files = $user ? $user : $all; }
unless ($files) {
$self->lmLog( "Can't find notification $refs->{$ref} for $uid",
'error' );
next;
}
# Browse found files
foreach my $file ( keys %$files ) {
my $xml;
eval { $xml = $parser->parse_string( $files->{$file} ) };
if ($@) {
$self->lmLog( "Bad XML notification for $uid", 'error' );
next;
}
# Browse notifications in file
foreach my $notif (
$xml->documentElement->getElementsByTagName('notification') )
{
my $reference = $notif->getAttribute('reference');
my @tmp = $notif->getElementsByTagName('check');
my $checkCount = @tmp;
if ( $checkCount == 0
or
( $checks->{$ref} and $checkCount == @{ $checks->{$ref} } )
)
{
# Notification is accepted
$self->lmLog(
"$uid has accepted notification $refs->{$ref}",
'notice' );
# 1. Register acceptation in persistent session
my $time = time();
my $notifkey = "notification_" . $refs->{$ref};
$portal->updatePersistentSession(
{ $notifkey => $time },
);
$self->lmLog(
"Notification "
. $refs->{$ref}
. " registered in persistent session",
'debug'
);
# 2. Delete it if not a wildcard notification
if ( exists $user->{$file} ) {
if ( $self->_delete($file) ) {
$self->lmLog(
"Notification " . $refs->{$ref} . " deleted",
'debug' );
}
else {
$self->lmLog(
"Unable to delete notification $refs->{$ref} for $uid",
'error'
);
}
}
}
else {
$self->lmLog(
"$uid has not accepted notification $refs->{$ref}",
'notice' );
$result = 0;
}
}
}
}
return $result;
}
## @method int newNotification(string xml)
# Check XML datas and insert new notifications.
# @param $xml XML string containing notification
# @return number of notifications done
sub newNotification {
my ( $self, $xml ) = @_;
eval { $xml = $parser->parse_string($xml); };
if ($@) {
$self->lmLog( "Unable to read XML file : $@", 'error' );
return 0;
}
my @notifs;
my ( $version, $encoding ) = ( $xml->version(), $xml->encoding() );
foreach
my $notif ( $xml->documentElement->getElementsByTagName('notification') )
{
my @datas = ();
# Mandatory information
foreach (qw(date uid reference)) {
my $tmp;
unless ( $tmp = $notif->getAttribute($_) ) {
$self->lmLog( "Attribute $_ is missing", 'error' );
return 0;
}
push @datas, $tmp;
}
# Other information
foreach (qw(condition)) {
my $tmp;
if ( $tmp = $notif->getAttribute($_) ) {
push @datas, $tmp;
}
else { push @datas, ""; }
}
my $result = XML::LibXML::Document->new( $version, $encoding );
my $root = XML::LibXML::Element->new('root');
$root->appendChild($notif);
$result->setDocumentElement($root);
push @notifs, [ @datas, $result ];
}
my $tmp = $self->{type};
my $count;
foreach (@notifs) {
$count++;
my ( $r, $err ) = $self->_newNotif(@$_);
die "$err" unless ($r);
}
return $count;
}
## @method int deleteNotification(string $uid, string $myref)
## Delete notifications for the connected user
## @param $uid of the user
## @param $myref notification's reference
## @return number of deleted notifications
sub deleteNotification {
my ( $self, $uid, $myref ) = @_;
my @data;
# Check input parameters
unless ( $uid and $myref ) {
$self->lmLog(
"SOAP service deleteNotification called without all parameters",
'error' );
return 0;
}
$self->lmLog(
"SOAP service deleteNotification called for uid $uid and reference $myref",
'debug'
);
# Get notifications
my $user = $self->_get($uid);
# Return 0 if no files were found
return 0 unless ($user);
# Counting
my $count = 0;
foreach my $ref ( keys %$user ) {
my $xml = $parser->parse_string( $user->{$ref} );
# Browse notification in file
foreach my $notif (
$xml->documentElement->getElementsByTagName('notification') )
{
# Get notification's data
if ( $notif->getAttribute('reference') eq $myref ) {
push @data, $ref;
}
# Delete the notification (really)
foreach (@data) {
if ( $self->purge( $_, 1 ) ) {
$self->lmLog( "Notification $_ was removed.", 'debug' );
$count++;
}
}
}
}
return $count;
}
## @method hashref getAll()
# Return all messages not notified. Wrapper for storage module getAll()
# @return hashref where keys are internal reference and values are hashref with
# keys date, uid and ref.
sub getAll {
no strict 'refs';
return &{ $_[0]->{type} . '::getAll' }(@_);
}
## @method hashref getDone()
# Returns a list of notification that have been done. Wrapper for storage module
# getDone().
# @return hashref where keys are internal reference and values are hashref with
# keys notified, uid and ref.
sub getDone {
no strict 'refs';
return &{ $_[0]->{type} . '::getDone' }(@_);
}
## @method boolean purge(string myref, boolean force)
# Purge notification (really delete record). Wrapper for storage module purge()
# @param $myref identifier returned by get or getAll
# @param $force force purge for not deleted session
# @return true if something was deleted
sub purge {
no strict 'refs';
return &{ $_[0]->{type} . '::purge' }(@_);
}
## @method private hashref _get(string uid,string ref)
# Returns notifications corresponding to the user $uid. Wrapper for storage
# module get().
# If $ref is set, returns only notification corresponding to this reference.
# @param $uid UID
# @param $ref Notification reference
# @return hashref where keys are internal reference and values are XML strings
sub _get {
no strict 'refs';
my $self = $_[0];
# Debug lines. Must be removed ?
die ref($self)
unless ( ref($self) eq 'Lemonldap::NG::Common::Notification' );
return &{ $_[0]->{type} . '::get' }(@_);
}
## @method private boolean _delete(string myref)
# Mark a notification as done. Wrapper for storage module delete()
# @param $myref identifier returned by get() or getAll()
sub _delete {
no strict 'refs';
return &{ $_[0]->{type} . '::delete' }(@_);
}
## @method private boolean _prereq()
# Check if storage module parameters are set. Wrapper for storage module
# prereq()
# @return true if all is OK
sub _prereq {
no strict 'refs';
return &{ $_[0]->{type} . '::prereq' }(@_);
}
## @method private boolean _newNotif(string date, string uid, string ref, string xml)
# Insert a new notification. Wrapper for storage module newNotif()
# @param date Date
# @param uid UID
# @param ref Reference of the notification
# @param xml XML notification
# @return true if succeed
sub _newNotif {
no strict 'refs';
return &{ $_[0]->{type} . '::newNotif' }(@_);
}
## @method private string _getIdentifier(string uid, string ref, string date)
# Get notification identifier
# @param $uid uid
# @param $ref ref
# @param $date date
# @return the notification identifier
sub _getIdentifier {
no strict 'refs';
return &{ $_[0]->{type} . '::getIdentifier' }(@_);
}
1;
__END__
=head1 NAME
=encoding utf8
Lemonldap::NG::Common::Notification - Provides notification messages system.
=head1 SYNOPSIS
use Lemonldap::NG::Portal;
=head1 DESCRIPTION
Lemonldap::NG::Common::Notification.
=head1 SEE ALSO
L<Lemonldap::NG::Portal>,
=head1 AUTHOR
=over
=item Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
=item Xavier Guimard, E<lt>x.guimard@free.frE<gt>
=item Sandro Cazzaniga, E<lt>cazzaniga.sandro@gmail.comE<gt>
=back
=head1 BUG REPORT
Use OW2 system to report bug or ask for features:
L<http://jira.ow2.org>
=head1 DOWNLOAD
Lemonldap::NG is available at
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
=head1 COPYRIGHT AND LICENSE
=over
=item Copyright (C) 2009-2016 by Xavier Guimard, E<lt>x.guimard@free.frE<gt>
=item Copyright (C) 2012 by Sandro Cazzaniga, E<lt>cazzaniga.sandro@gmail.comE<gt>
=item Copyright (C) 2010-2012 by Clement Oudot, E<lt>clem.oudot@gmail.comE<gt>
=back
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see L<http://www.gnu.org/licenses/>.
=cut

@ -0,0 +1,150 @@
package Lemonldap::NG::Common::Notifications;
use strict;
use Mouse;
use XML::LibXML;
our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Common::Module';
# XML parser. TODO: replace this by JSON
has parser => (
is => 'rw',
builder => sub {
return XML::LibXML->new();
}
);
has notifField => (
is => 'rw',
builder => sub {
my $uid =
$_[0]->conf->{notificationField}
|| $_[0]->conf->{whatToTrace}
|| 'uid';
$uid =~ s/^\$//;
return $uid;
}
);
sub getNotifications {
my ( $self, $uid ) = @_;
my $forUser = $self->get($uid);
my $forAll = $self->get( $self->conf->{notificationWildcard} );
if ( $forUser and $forAll ) {
return { %$forUser, %$forAll };
}
else {
return ( ( $forUser ? $forUser : $forAll ), $forUser );
}
}
# Check XML datas and insert new notifications.
# @param $xml XML string containing notification
# @return number of notifications done
sub newNotification {
my ( $self, $xml ) = @_;
eval { $xml = $self->parser->parse_string($xml); };
if ($@) {
$self->lmLog( "Unable to read XML file : $@", 'error' );
return 0;
}
my @notifs;
my ( $version, $encoding ) = ( $xml->version(), $xml->encoding() );
foreach
my $notif ( $xml->documentElement->getElementsByTagName('notification') )
{
my @datas = ();
# Mandatory information
foreach (qw(date uid reference)) {
my $tmp;
unless ( $tmp = $notif->getAttribute($_) ) {
$self->lmLog( "Attribute $_ is missing", 'error' );
return 0;
}
push @datas, $tmp;
}
# Other information
foreach (qw(condition)) {
my $tmp;
if ( $tmp = $notif->getAttribute($_) ) {
push @datas, $tmp;
}
else { push @datas, ""; }
}
my $result = XML::LibXML::Document->new( $version, $encoding );
my $root = XML::LibXML::Element->new('root');
$root->appendChild($notif);
$result->setDocumentElement($root);
push @notifs, [ @datas, $result ];
}
my $tmp = $self->{type};
my $count;
foreach (@notifs) {
$count++;
my ( $r, $err ) = $self->newNotif(@$_);
die "$err" unless ($r);
}
return $count;
}
## Delete notifications for the connected user
## @param $uid of the user
## @param $myref notification's reference
## @return number of deleted notifications
sub deleteNotification {
my ( $self, $uid, $myref ) = @_;
my @data;
# Check input parameters
unless ( $uid and $myref ) {
$self->lmLog(
"SOAP service deleteNotification called without all parameters",
'error' );
return 0;
}
$self->lmLog(
"SOAP service deleteNotification called for uid $uid and reference $myref",
'debug'
);
# Get notifications
my $user = $self->get($uid);
# Return 0 if no files were found
return 0 unless ($user);
# Counting
my $count = 0;
foreach my $ref ( keys %$user ) {
my $xml = $self->parser->parse_string( $user->{$ref} );
# Browse notification in file
foreach my $notif (
$xml->documentElement->getElementsByTagName('notification') )
{
# Get notification's data
if ( $notif->getAttribute('reference') eq $myref ) {
push @data, $ref;
}
# Delete the notification (really)
foreach (@data) {
if ( $self->purge( $_, 1 ) ) {
$self->lmLog( "Notification $_ was removed.", 'debug' );
$count++;
}
}
}
}
return $count;
}
1;

@ -3,42 +3,62 @@
## @class
# DBI storage methods for notifications
package Lemonldap::NG::Common::Notification::DBI;
package Lemonldap::NG::Common::Notifications::DBI;
use strict;
use Mouse;
use Time::Local;
use DBI;
use utf8;
use Encode;
our $VERSION = '2.0.0';
## @method boolean prereq()
# Check if DBI parameters are set.
# @return true if all is OK
sub prereq {
my $self = shift;
$self->{dbiTable} = $self->{table} if ( $self->{table} );
unless ( $self->{dbiChain} ) {
$Lemonldap::NG::Common::Notification::msg =
'"dbiChain" is required in DBI notification type';
return 0;
extends 'Lemonldap::NG::Common::Notifications';
has dbiTable => (
is => 'ro',
default => sub { $_[0]->{table} || 'notifications' }
);
has dbiChain => (
is => 'ro',
required => 1
);
has dbiUser => (
is => 'ro',
default => sub {
$_[0]->p->lmLog( 'Warning: "dbiUser" parameter is not set', 'warn' );
return '';
}
$self->lmLog( 'Warning: "dbiUser" parameter is not set', 'warn' )
unless ( $self->{dbiUser} );
1;
}
);
has dbiPassword => ( is => 'ro', default => '' );
# Database handle object
has _dbh => (
is => 'rw',
lazy => 1,
builder => sub {
my $self = shift;
my $r = DBI->connect_cached(
$self->{dbiChain}, $self->{dbiUser},
$self->{dbiPassword}, { RaiseError => 0 }
);
$self->lmLog( $DBI::errstr, 'error' ) unless ($r);
return $r;
}
);
# Current query
has sth => ( is => 'rw' );
## @method hashref get(string uid,string ref)
# Returns notifications corresponding to the user $uid.
# If $ref is set, returns only notification corresponding to this reference.
# @param $uid UID
# @param $ref Notification reference
# @return hashref where keys are internal reference and values are XML strings
sub get {
my ( $self, $uid, $ref ) = @_;
return () unless ($uid);
_execute(
$self,
$self->_execute(
"SELECT * FROM $self->{dbiTable} WHERE done IS NULL AND uid=?"
. ( $ref ? " AND ref=?" : '' )
. "ORDER BY date",
@ -46,7 +66,7 @@ sub get {
( $ref ? $ref : () )
) or return ();
my $result;
while ( my $h = $self->{sth}->fetchrow_hashref() ) {
while ( my $h = $self->sth->fetchrow_hashref() ) {
# Get XML message
my $xml = $h->{xml};
@ -59,7 +79,7 @@ sub get {
&getIdentifier( $self, $h->{uid}, $h->{ref}, $h->{date} );
$result->{$identifier} = $xml;
}
$self->lmLog( $self->{sth}->err(), 'warn' ) if ( $self->{sth}->err() );
$self->lmLog( $self->sth->err(), 'warn' ) if ( $self->sth->err() );
return $result;
}
@ -69,10 +89,10 @@ sub get {
# keys date, uid and ref.
sub getAll {
my $self = shift;
_execute( $self,
"SELECT * FROM $self->{dbiTable} WHERE done IS NULL ORDER BY date" );
$self->_execute(
"SELECT * FROM $self->{dbiTable} WHERE done IS NULL ORDER BY date");
my $result;
while ( my $h = $self->{sth}->fetchrow_hashref() ) {
while ( my $h = $self->sth->fetchrow_hashref() ) {
$result->{"$h->{date}#$h->{uid}#$h->{ref}"} = {
date => $h->{date},
uid => $h->{uid},
@ -80,7 +100,7 @@ sub getAll {
condition => $h->{condition}
};
}
$self->lmLog( $self->{sth}->err(), 'warn' ) if ( $self->{sth}->err() );
$self->lmLog( $self->sth->err(), 'warn' ) if ( $self->sth->err() );
return $result;
}
@ -98,15 +118,10 @@ sub delete {
my @ts = localtime();
$ts[5] += 1900;
$ts[4]++;
return _execute(
$self,
"UPDATE $self->{dbiTable} "
return $self->_execute( "UPDATE $self->{dbiTable} "
. "SET done='$ts[5]-$ts[4]-$ts[3] $ts[2]:$ts[1]' "
. "WHERE done IS NULL AND uid=? AND ref=? AND date=?",
$u,
$r,
$d
);
$u, $r, $d );
}
## @method boolean purge(string myref, boolean force)
@ -126,14 +141,9 @@ sub purge {
my $clause;
$clause = "done IS NOT NULL AND" unless ($force);
return _execute(
$self,
"DELETE FROM $self->{dbiTable} "
return $self->_execute( "DELETE FROM $self->{dbiTable} "
. "WHERE $clause uid=? AND ref=? AND date=?",
$u,
$r,
$d
);
$u, $r, $d );
}
## @method boolean newNotif(string date, string uid, string ref, string condition, string xml)
@ -152,24 +162,13 @@ sub newNotif {
my $res =
$condition =~ /.+/
? _execute(
$self,
? $self->_execute(
"INSERT INTO $self->{dbiTable} (date,uid,ref,cond,xml) "
. "VALUES(?,?,?,?,?)",
$date,
$uid,
$ref,
$condition,
$xml
)
: _execute(
$self,
$date, $uid, $ref, $condition, $xml )
: $self->_execute(
"INSERT INTO $self->{dbiTable} (date,uid,ref,xml) " . "VALUES(?,?,?,?)",
$date,
$uid,
$ref,
$xml
);
$date, $uid, $ref, $xml );
return $res;
}
@ -179,17 +178,16 @@ sub newNotif {
# keys notified, uid and ref.
sub getDone {
my ($self) = @_;
_execute( $self,
"SELECT * FROM $self->{dbiTable} WHERE done IS NOT NULL ORDER BY done"
);
$self->_execute(
"SELECT * FROM $self->{dbiTable} WHERE done IS NOT NULL ORDER BY done");
my $result;
while ( my $h = $self->{sth}->fetchrow_hashref() ) {
while ( my $h = $self->sth->fetchrow_hashref() ) {
my @t = split( /\D+/, $h->{date} );
my $done = timelocal( $t[5], $t[4], $t[3], $t[2], $t[1], $t[0] );
$result->{"$h->{date}#$h->{uid}#$h->{ref}"} =
{ notified => $done, uid => $h->{uid}, ref => $h->{ref}, };
}
$self->lmLog( $self->{sth}->err(), 'warn' ) if ( $self->{sth}->err() );
$self->lmLog( $self->sth->err(), 'warn' ) if ( $self->sth->err() );
return $result;
}
@ -198,34 +196,19 @@ sub getDone {
# @return number of lines touched or 1 if select succeed
sub _execute {
my ( $self, $query, @args ) = @_;
my $dbh = _dbh($self) or return 0;
unless ( $self->{sth} = $dbh->prepare($query) ) {
my $dbh = $self->_dbh or return 0;
unless ( $self->sth( $dbh->prepare($query) ) ) {
$self->lmLog( $dbh->errstr(), 'warn' );
return 0;
}
my $tmp;
unless ( $tmp = $self->{sth}->execute(@args) ) {
$self->lmLog( $self->{sth}->errstr(), 'warn' );
unless ( $tmp = $self->sth->execute(@args) ) {
$self->lmLog( $self->sth->errstr(), 'warn' );
return 0;
}
return $tmp;
}
## @method object private _dbh()
# Return the DBI object (build it if needed).
# @return database handle object
sub _dbh {
my $self = shift;
$self->{dbiTable} ||= "notifications";
return $self->{dbh} if ( $self->{dbh} and $self->{dbh}->ping );
my $r = DBI->connect_cached(
$self->{dbiChain}, $self->{dbiUser},
$self->{dbiPassword}, { RaiseError => 0 }
);
$self->lmLog( $DBI::errstr, 'error' ) unless ($r);
return $r;
}
## @method string getIdentifier(string uid, string ref, string date)
# Get notification identifier
# @param $uid uid

@ -3,7 +3,7 @@
## @class
# File storage methods for notifications
package Lemonldap::NG::Common::Notification::File;
package Lemonldap::NG::Common::Notifications::File;
use strict;
use Mouse;
@ -11,7 +11,9 @@ use MIME::Base64;
our $VERSION = '2.0.0';
has dirName => ( is => 'rw', required => 1 );
extends 'Lemonldap::NG::Common::Notifications';
has dirName => ( is => 'ro', required => 1 );
has table => (
is => 'rw',

@ -4,9 +4,10 @@
## @class
# LDAP storage methods for notifications
package Lemonldap::NG::Common::Notification::LDAP;
package Lemonldap::NG::Common::Notifications::LDAP;
use strict;
use Mouse;
use Time::Local;
use MIME::Base64;
use Net::LDAP;
@ -14,42 +15,41 @@ use utf8;
our $VERSION = '2.0.0';
## @method boolean prereq()
# Check if LDAP parameters are set.
# @return true if all is OK
sub prereq {
my $self = shift;
unless ( $self->{ldapServer} ) {
$self->lmLog( '"ldapServer" is required in LDAP notification type',
'error' );
$Lemonldap::NG::Common::Notification::msg =
'"ldapServer" is required in LDAP notification type';
return 0;
}
if ( $self->{table} ) {
$self->{ldapConfBase} =~ s/^\w+=\w+(,.*)$/ou=$self->{table}$1/;
extends 'Lemonldap::NG::Common::Notifications';
has ldapServer => (
is => 'ro',
required => 1,
);
has ldapConfBase => (
is => 'ro',
trigger => sub {
if ( my $table = $_[0]->{table} ) {
$_[0]->{ldapConfBase} =~ s/^\w+=\w+(,.*)$/ou=$table$1/;
}
}
);
$self->lmLog( 'Warning: "ldapBindDN" parameter is not set', 'warn' )
unless ( $self->{ldapBindDN} );
1;
}
has ldapBindDN => (
is => 'ro',
default => sub {
$_[0]->p->lmLog( 'Warning: "ldapBindDN" parameter is not set', 'warn' );
return '';
}
);
## @method hashref get(string uid,string ref)
# Returns notifications corresponding to the user $uid.
# If $ref is set, returns only notification corresponding to this reference.
# @param $uid UID
# @param $ref Notification reference
# @return hashref where keys are internal reference and values are XML strings
sub get {
my ( $self, $uid, $ref ) = @_;
return () unless ($uid);
my $filter = '(&(objectClass=applicationProcess)(!(description={done}*))';
$filter .= '(description={uid}' . $uid . ')';
$filter .= '(description={ref}' . $ref . ')' if $ref;
$filter .= ')';
my @entries = _search( $self, "$filter" );
my $filter =
'(&(objectClass=applicationProcess)(!(description={done}*))'
. "(description={uid}$uid)"
. ( $ref ? '(description={ref}' . $ref . ')' : '' ) . ')';
my @entries = _search( $self, $filter );
my $result = {};
foreach my $entry (@entries) {
@ -69,7 +69,6 @@ sub get {
}
return $result;
}
## @method hashref getAll()
@ -79,8 +78,8 @@ sub get {
sub getAll {
my $self = shift;
my @entries = _search( $self,
'(&(objectClass=applicationProcess)(!(description={done}*)))' );
my @entries = $self->_search(
'(&(objectClass=applicationProcess)(!(description={done}*)))');
my $result = {};
foreach my $entry (@entries) {
@ -110,7 +109,6 @@ sub delete {
my ( $self, $myref ) = @_;
my ( $d, $u, $r );
unless ( ( $d, $u, $r ) = ( $myref =~ /^([^#]+)#(.+?)#(.+)$/ ) ) {
$Lemonldap::NG::Common::Notification::msg = "Bad reference $myref";
$self->lmLog( "Bad reference $myref", 'warn' );
return 0;
}
@ -119,13 +117,11 @@ sub delete {
$ts[4]++;
return _modify(
$self,
'(&(objectClass=applicationProcess)(description={uid}'
. $u
. ')(description={ref}'
. $r
. ')(description={date}'
. $d
. ')(!(description={done}*)))',
'(&(objectClass=applicationProcess)'
. "(description={uid}$u)"
. "(description={ref}$r)"
. "(description={date}$d)"
. '(!(description={done}*)))',
"description",
"{done}$ts[5]-$ts[4]-$ts[3] $ts[2]:$ts[1]"
);
@ -140,25 +136,18 @@ sub purge {
my ( $self, $myref, $force ) = @_;
my ( $d, $u, $r );
unless ( ( $d, $u, $r ) = ( $myref =~ /^([^#]+)#(.+?)#(.+)$/ ) ) {
$Lemonldap::NG::Common::Notification::msg = "Bad reference $myref";
$self->lmLog( "Bad reference $myref", 'warn' );
return 0;
}
my $clause;
$clause = '(description={done}*)' unless ($force);
return _delete( $self,
'(&(objectClass=applicationProcess)(description={uid}'
. $u
. ')(description={ref}'
. $r
. ')(description={date}'
. $d . ')'
. $clause
. ')' );
my $clause = ($force ? '' : '(description={done}*)');
return $self->_delete( '(&(objectClass=applicationProcess)'
. "(description={uid}$u)"
. "(description={ref}$r)"
. "(description={date}$d)"
. "$clause)" );
}
## @method boolean newNotif(string date, string uid, string ref, string condition, string xml)
# Insert a new notification
# @param date Date
# @param uid UID
@ -168,7 +157,7 @@ sub purge {
# @return true if succeed
sub newNotif {
my ( $self, $date, $uid, $ref, $condition, $xml ) = @_;
my $fns = $self->{fileNameSeparator};
my $fns = $self->conf->{fileNameSeparator};
$fns ||= '_';
$date =~ s/-//g;
return ( 0, "Bad date" ) unless ( $date =~ /^\d{8}/ );

@ -74,7 +74,6 @@ sub notifAccess {
$self->error($Lemonldap::NG::Common::Conf::msg);
return 0;
}
my $args;
# TODO: refresh system
$self->{$_} //= $conf->{$_}
@ -91,29 +90,31 @@ sub notifAccess {
'notificationStorage is not defined in configuration' );
return 0;
}
$args->{type} = $self->{notificationStorage};
foreach ( keys %{ $self->{notificationStorageOptions} } ) {
$args->{$_} = $self->{notificationStorageOptions}->{$_};
}
# Get the type
$args->{type} =~ s/.*:://;
$args->{type} =~ s/(CBDI|RDBI)/DBI/; # CDBI/RDBI are DBI
# If type not File or DBI, abort
unless ( $args->{type} =~ /^(File|DBI|LDAP)$/ ) {
$self->handlerAbort( notifications =>
"Only File, DBI or LDAP supported for Notifications" );
my $type =
"Lemonldap::NG::Common::Notifications::$self->{notificationStorage}";
$type =~ s/(?:C|R)DBI$/DBI/;
eval "require $type";
if ($@) {
$self->handlerAbort( notifications => "Unable to load $type: $@" );
return 0;
}
# Force table name
$args->{p} = $self;
unless (
$self->_notifAccess( Lemonldap::NG::Common::Notification->new($args) ) )
eval {
$self->_notifAccess(
$type->new(
{
%{ $self->{notificationStorageOptions} },
p => $self,
conf => $self
}
)
);
}
)
{
$self->handlerAbort(
notifications => $Lemonldap::NG::Common::Notification::msg );
$self->handlerAbort( notifications => $@ );
return 0;
}
return $self->_notifAccess();
@ -224,7 +225,7 @@ sub notification {
if ( $type eq 'actives' ) {
my ( $uid, $ref ) = ( $id =~ /([^_]+?)_(.+)/ );
my $n = $self->notifAccess->_get( $uid, $ref );
my $n = $self->notifAccess->get( $uid, $ref );
unless ($n) {
$self->lmLog( "Notification $ref not found for user $uid",
'notice' );
@ -309,7 +310,7 @@ sub updateNotification {
my $id = $req->params('notificationId') or die;
my ( $uid, $ref ) = ( $id =~ /([^_]+?)_(.+)/ );
my ( $n, $res );
unless ( $n = $self->notifAccess->_get( $uid, $ref ) ) {
unless ( $n = $self->notifAccess->get( $uid, $ref ) ) {
$self->lmLog( "Notification $ref not found for user $uid", 'notice' );
return $self->sendError( $req,
"Notification $ref not found for user $uid" );
@ -318,7 +319,7 @@ sub updateNotification {
# Delete notifications
my $status = 1;
foreach ( keys %$n ) {
$status = 0 unless ( $self->notifAccess->_delete($_) );
$status = 0 unless ( $self->notifAccess->delete($_) );
}
unless ($status) {
@ -340,7 +341,7 @@ sub deleteDoneNotification {
# Purge notification
my $id = $req->params('notificationId') or die;
my ( $uid, $ref, $date ) = ( $id =~ /([^_]+?)_([^_]+?)_(.+)/ );
my $identifier = $self->notifAccess->_getIdentifier( $uid, $ref, $date );
my $identifier = $self->notifAccess->getIdentifier( $uid, $ref, $date );
unless ( $self->notifAccess->purge($identifier) ) {
$self->lmLog(
"Notification $identifier not purged ($Lemonldap::NG::Common::Notification::msg)",

@ -7,7 +7,6 @@ dirName=t/conf
[portal]
notification = 0
checkXSS = 0
[handler]

@ -14,51 +14,42 @@ example/openid-configuration.pl
example/PortalStatus.pl
example/register.pl
example/scripts/buildPortalWSDL
example/scripts/purgeCentralCache
example/scripts/purgeCentralCache.cron.d
example/soapconfigtest.pl
example/soaperrortest.pl
example/soaptest.pl
KINEMATIC.md
lib/Lemonldap/NG/Portal.pm
lib/Lemonldap/NG/Portal/_Browser.pm
lib/Lemonldap/NG/Portal/_CAS.pm
lib/Lemonldap/NG/Portal/_Choice.pm
lib/Lemonldap/NG/Portal/_DBI.pm
lib/Lemonldap/NG/Portal/_i18n.pm
lib/Lemonldap/NG/Portal/_LDAP.pm
lib/Lemonldap/NG/Portal/_LibAccess.pm
lib/Lemonldap/NG/Portal/_Multi.pm
lib/Lemonldap/NG/Portal/_OpenIDConnect.pm
lib/Lemonldap/NG/Portal/_Proxy.pm
lib/Lemonldap/NG/Portal/_Remote.pm
lib/Lemonldap/NG/Portal/_SAML.pm
lib/Lemonldap/NG/Portal/_Slave.pm
lib/Lemonldap/NG/Portal/_SMTP.pm
lib/Lemonldap/NG/Portal/_SOAP.pm
lib/Lemonldap/NG/Portal/_WebForm.pm
lib/Lemonldap/NG/Portal/Auth/_WebForm.pm
lib/Lemonldap/NG/Portal/Auth/AD.pm
lib/Lemonldap/NG/Portal/Auth/Apache.pm
lib/Lemonldap/NG/Portal/Auth/Base.pm
lib/Lemonldap/NG/Portal/Auth/BrowserID.pm
lib/Lemonldap/NG/Portal/Auth/DBI.pm
lib/Lemonldap/NG/Portal/Auth/Demo.pm
lib/Lemonldap/NG/Portal/AuthAD.pm
lib/Lemonldap/NG/Portal/AuthApache.pm
lib/Lemonldap/NG/Portal/AuthBrowserID.pm
lib/Lemonldap/NG/Portal/Auth/Facebook.pm
lib/Lemonldap/NG/Portal/Auth/LDAP.pm
lib/Lemonldap/NG/Portal/Auth/Null.pm
lib/Lemonldap/NG/Portal/Auth/Remote.pm
lib/Lemonldap/NG/Portal/Auth/Slave.pm
lib/Lemonldap/NG/Portal/AuthCAS.pm
lib/Lemonldap/NG/Portal/AuthChoice.pm
lib/Lemonldap/NG/Portal/AuthDBI.pm
lib/Lemonldap/NG/Portal/AuthDemo.pm
lib/Lemonldap/NG/Portal/AuthFacebook.pm
lib/Lemonldap/NG/Portal/AuthGoogle.pm
lib/Lemonldap/NG/Portal/AuthLDAP.pm
lib/Lemonldap/NG/Portal/AuthMulti.pm
lib/Lemonldap/NG/Portal/AuthNull.pm
lib/Lemonldap/NG/Portal/AuthOpenID.pm
lib/Lemonldap/NG/Portal/AuthOpenIDConnect.pm
lib/Lemonldap/NG/Portal/AuthProxy.pm
lib/Lemonldap/NG/Portal/AuthRadius.pm
lib/Lemonldap/NG/Portal/AuthRemote.pm
lib/Lemonldap/NG/Portal/AuthSAML.pm
lib/Lemonldap/NG/Portal/AuthSlave.pm
lib/Lemonldap/NG/Portal/AuthSSL.pm
lib/Lemonldap/NG/Portal/AuthTwitter.pm
lib/Lemonldap/NG/Portal/AuthWebID.pm
@ -70,13 +61,17 @@ lib/Lemonldap/NG/Portal/IssuerDBNull.pm
lib/Lemonldap/NG/Portal/IssuerDBOpenID.pm
lib/Lemonldap/NG/Portal/IssuerDBOpenIDConnect.pm
lib/Lemonldap/NG/Portal/IssuerDBSAML.pm
lib/Lemonldap/NG/Portal/Lib/DBI.pm
lib/Lemonldap/NG/Portal/Lib/LDAP.pm
lib/Lemonldap/NG/Portal/Lib/Remote.pm
lib/Lemonldap/NG/Portal/Lib/Slave.pm
lib/Lemonldap/NG/Portal/MailReset.pm
lib/Lemonldap/NG/Portal/Main.pm
lib/Lemonldap/NG/Portal/Main/Constants.pm
lib/Lemonldap/NG/Portal/Main/Display.pm
lib/Lemonldap/NG/Portal/Main/Init.pm
lib/Lemonldap/NG/Portal/Main/Menu.pm
lib/Lemonldap/NG/Portal/Main/Module.pm
lib/Lemonldap/NG/Portal/Main/Plugin.pm
lib/Lemonldap/NG/Portal/Main/Plugins.pm
lib/Lemonldap/NG/Portal/Main/Process.pm
lib/Lemonldap/NG/Portal/Main/Request.pm
@ -91,6 +86,7 @@ lib/Lemonldap/NG/Portal/PasswordDBDemo.pm
lib/Lemonldap/NG/Portal/PasswordDBLDAP.pm
lib/Lemonldap/NG/Portal/PasswordDBNull.pm
lib/Lemonldap/NG/Portal/Plugins/CDA.pm
lib/Lemonldap/NG/Portal/Plugins/Notifications.pm
lib/Lemonldap/NG/Portal/Register.pm
lib/Lemonldap/NG/Portal/RegisterDBAD.pm
lib/Lemonldap/NG/Portal/RegisterDBDemo.pm
@ -98,22 +94,21 @@ lib/Lemonldap/NG/Portal/RegisterDBLDAP.pm
lib/Lemonldap/NG/Portal/RegisterDBNull.pm
lib/Lemonldap/NG/Portal/SharedConf.pm
lib/Lemonldap/NG/Portal/Simple.pm
lib/Lemonldap/NG/Portal/UserDB/AD.pm
lib/Lemonldap/NG/Portal/UserDB/DBI.pm
lib/Lemonldap/NG/Portal/UserDB/Demo.pm
lib/Lemonldap/NG/Portal/UserDBAD.pm
lib/Lemonldap/NG/Portal/UserDB/Facebook.pm
lib/Lemonldap/NG/Portal/UserDB/LDAP.pm
lib/Lemonldap/NG/Portal/UserDB/Null.pm
lib/Lemonldap/NG/Portal/UserDB/Remote.pm
lib/Lemonldap/NG/Portal/UserDB/Slave.pm
lib/Lemonldap/NG/Portal/UserDBChoice.pm
lib/Lemonldap/NG/Portal/UserDBDBI.pm
lib/Lemonldap/NG/Portal/UserDBDemo.pm
lib/Lemonldap/NG/Portal/UserDBFacebook.pm
lib/Lemonldap/NG/Portal/UserDBGoogle.pm
lib/Lemonldap/NG/Portal/UserDBLDAP.pm
lib/Lemonldap/NG/Portal/UserDBMulti.pm
lib/Lemonldap/NG/Portal/UserDBNull.pm
lib/Lemonldap/NG/Portal/UserDBOpenID.pm
lib/Lemonldap/NG/Portal/UserDBOpenIDConnect.pm
lib/Lemonldap/NG/Portal/UserDBProxy.pm
lib/Lemonldap/NG/Portal/UserDBRemote.pm
lib/Lemonldap/NG/Portal/UserDBSAML.pm
lib/Lemonldap/NG/Portal/UserDBSlave.pm
lib/Lemonldap/NG/Portal/UserDBWebID.pm
Makefile.PL
MANIFEST This list of files
@ -121,6 +116,8 @@ META.yml
README
REST-API.md
site/coffee/portal.coffee
site/cron/purgeCentralCache
site/cron/purgeCentralCache.cron.d
site/htdocs/index.fcgi
site/htdocs/static/bootstrap/css/styles.css
site/htdocs/static/bootstrap/css/styles.min.css
@ -204,7 +201,6 @@ site/htdocs/static/common/js/portal.js
site/htdocs/static/common/js/portal.min.js
site/htdocs/static/common/key.png
site/htdocs/static/common/lemonldap-ng_square.png
site/htdocs/static/common/notification.xsl
site/htdocs/static/common/ok.png
site/htdocs/static/common/openid-16x16.gif
site/htdocs/static/common/OpenIDConnect.png
@ -232,7 +228,6 @@ site/htdocs/static/impact/images/logo-lock.png
site/htdocs/static/impact/images/logo-ok.png
site/htdocs/static/impact/images/logo-warn.png
site/htdocs/static/impact/README
site/htdocs/static/js/portal.js
site/htdocs/static/js/portal.min.js
site/htdocs/static/languages/en.json
site/htdocs/static/languages/fr.json
@ -240,8 +235,6 @@ site/htdocs/static/pastel/css/styles.css
site/htdocs/static/pastel/css/styles.min.css
site/htdocs/static/pastel/images/hatch.gif
site/htdocs/static/pastel/images/lock.png
site/static/js/portal.js
site/static/js/portal.min.js
site/templates/bootstrap/checklogins.tpl
site/templates/bootstrap/confirm.tpl
site/templates/bootstrap/customfooter.tpl
@ -269,6 +262,7 @@ site/templates/common/mail_header.tpl
site/templates/common/mail_password.tpl
site/templates/common/mail_register_confirm.tpl
site/templates/common/mail_register_done.tpl
site/templates/common/notification.xsl
site/templates/common/redirect.tpl
site/templates/common/saml2-metadata.tpl
site/templates/common/script.tpl
@ -331,39 +325,24 @@ site/templates/pastel/register.tpl
site/templates/pastel/standardform.tpl
site/templates/pastel/yubikeyform.tpl
t/01-AuthDemo.t
t/01-Lemonldap-NG-Portal-Simple.t
t/02-Lemonldap-NG-Portal-SharedConf.t
t/03-XSS-protection.t
t/04-Lemonldap-NG-Portal-SOAP.t
t/05-Lemonldap-NG-Portal-Safe.t
t/10-Lemonldap-NG-Portal-i18n.t
t/20-Lemonldap-NG-Portal-AuthApache.t
t/21-Lemonldap-NG-Portal-AuthSSL.t
t/22-Lemonldap-NG-Portal-AuthCAS.t
t/24-Lemonldap-NG-Portal-AuthRemote.t
t/25-Lemonldap-NG-Portal-Multi.t
t/26-Lemonldap-NG-Portal-AuthChoice.t
t/26-Lemonldap-NG-Portal-AuthProxy.t
t/27-Lemonldap-NG-Portal-AuthFacebook.t
t/27-Lemonldap-NG-Portal-AuthGoogle.t
t/27-Lemonldap-NG-Portal-AuthOpenID.t
t/27-Lemonldap-NG-Portal-IssuerDBOpenID.t
t/27-Lemonldap-NG-Portal-UserDBFacebook.t
t/27-Lemonldap-NG-Portal-UserDBGoogle.t
t/27-Lemonldap-NG-Portal-UserDBOpenID.t
t/30-Lemonldap-NG-Portal-UserDBNull.t
t/50-Lemonldap-NG-Portal-Menu.t
t/60-Lemonldap-NG-Portal-IssuerDBSAML.t
t/61-Lemonldap-NG-Portal-SAML.t
t/63-Lemonldap-NG-Portal-AuthSAML.t
t/64-Lemonldap-NG-Portal-UserDBSAML.t
t/65-Lemonldap-NG-Portal-IssuerDBCAS.t
t/66-Lemonldap-NG-Portal-Captcha.t
t/67-Lemonldap-NG-Portal-AuthBrowserID.t
t/70-Lemonldap-NG-Portal-AuthOpenIDConnect.t
t/02-AuthAD.t
t/02-AuthLDAP.t
t/03-AuthDBI.t
t/04-AuthNull.t
t/05-AuthApache.t
t/06-AuthSlave.t
t/07-AuthRemote.t
t/10-Notifications-File.t
t/11-Notifications-DBI.t
t/20-XSS-protection.t
t/90-translations.t
t/99-pod.t
t/lmConf-1.js
t/notifications.db
t/sessions/lock/.exists
t/sessions2/6e30af4ffa5689b3e49a104d1b160d316db2b2161a0f45776994eed19dbdc101
t/sessions2/lock/Apache-Session-6e30af4ffa5689b3e49a104d1b160d316db2b2161a0f45776994eed19dbdc101.lock
t/test-lib.pm
TODO.md
xt/PE_Constants.t
xt/test-weaken-portal.t

@ -5,7 +5,7 @@ use Mouse;
our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Portal::Main::Module';
extends 'Lemonldap::NG::Common::Module';
has authnLevel => ( is => 'rw' );

@ -9,7 +9,7 @@ use DBI;
use strict;
use Mouse;
extends 'Lemonldap::NG::Portal::Main::Module';
extends 'Lemonldap::NG::Common::Module';
our $VERSION = '2.0.0';

@ -7,7 +7,7 @@ use utf8;
use Mouse;
use Clone 'clone';
extends 'Lemonldap::NG::Portal::Main::Module';
extends 'Lemonldap::NG::Common::Module';
has menuModules => (
is => 'rw',

@ -5,7 +5,7 @@ use Mouse;
our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Portal::Main::Module';
extends 'Lemonldap::NG::Common::Module';
sub addAuthRoute {
my $self = shift;

@ -3,7 +3,7 @@ package Lemonldap::NG::Portal::Plugins::CDA;
use strict;
use Mouse;
extends 'Lemonldap::NG::Portal::Main::Module';
extends 'Lemonldap::NG::Common::Module';
sub afterDatas {
return 'changeUrldc';

@ -13,23 +13,18 @@ package Lemonldap::NG::Portal::Plugins::Notifications;
use strict;
use Mouse;
use XML::LibXML;
use XML::LibXSLT;
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_NOTIFICATION);
our $VERSION = '2.0.0';
# Lemonldap::NG::Portal::Main::Plugin provides addAuthRoute() and
# addUnauthRoute() methods in addition of Lemonldap::NG::Portal::Main::Module.
# addUnauthRoute() methods in addition of Lemonldap::NG::Common::Module.
extends 'Lemonldap::NG::Portal::Main::Plugin';
# XML parser. TODO: replace this by JSON
has parser => (
is => 'rw',
builder => sub {
return XML::LibXML->new();
}
);
sub parser {
return $_[0]->notifObject->parser;
}
# XSLT document
has stylesheet => (
@ -54,18 +49,6 @@ has stylesheet => (
# Underlying notifications storage object (File, DBI, LDAP,...)
has notifObject => ( is => 'rw' );
has notifField => (
is => 'rw',
builder => sub {
my $uid =
$_[0]->conf->{notificationField}
|| $_[0]->conf->{whatToTrace}
|| 'uid';
$uid =~ s/^\$//;
return $uid;
}
);
# Declare additional process steps
sub afterDatas { 'checkNotifDuringAuth' }
@ -85,22 +68,22 @@ sub init {
}
# Initialize notifications storage object
$type = "Lemonldap::NG::Common::Notification::$type";
$type = "Lemonldap::NG::Common::Notifications::$type";
eval "require $type";
if ($@) {
$self->error($@);
$self->error(
"Unable to load Lemonldap::NG::Common::Notifications::$type: $@");
return 0;
}
# TODO: use conf database?
unless (
eval {
$self->notifObject(
$type->new( $self->conf->{notificationStorageOptions} ) );
}
)
{
my $prms = {
%{ $self->conf->{notificationStorageOptions} },
p => $self->p,
conf => $self->p->conf
};
unless ( eval { $self->notifObject( $type->new($prms) ); } ) {
$self->error($@);
return 0;
}
@ -141,8 +124,8 @@ sub checkForNotifications {
my ( $self, $req ) = @_;
# Look for pending notifications in database
my $uid = $req->sessionInfo->{ $self->notifField };
my ( $notifs, $forUser ) = $self->getNotifications($uid);
my $uid = $req->sessionInfo->{ $self->notifObject->notifField };
my ( $notifs, $forUser ) = $self->notifObject->getNotifications($uid);
my $form;
return 0 unless ($notifs);
@ -241,9 +224,9 @@ sub getNotifBack {
# Restore datas
$self->p->importHandlerDatas($req);
my $uid = $req->sessionInfo->{ $self->notifField };
my $uid = $req->sessionInfo->{ $self->notifObject->notifField };
my ( $notifs, $forUser ) = $self->getNotifications($uid);
my ( $notifs, $forUser ) = $self->notifObject->getNotifications($uid);
if ($notifs) {
# Get accepted notifications
@ -334,18 +317,6 @@ sub getNotifBack {
}
}
sub getNotifications {
my ( $self, $uid ) = @_;
my $forUser = $self->notifObject->get($uid);
my $forAll = $self->notifObject->get( $self->conf->{notificationWildcard} );
if ( $forUser and $forAll ) {
return { %$forUser, %$forAll };
}
else {
return ( ( $forUser ? $forUser : $forAll ), $forUser );
}
}
sub rebuildCookies {
my ( $self, $req ) = @_;
my @tmp;

@ -9,7 +9,7 @@ use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_USERNOTFOUND);
extends 'Lemonldap::NG::Portal::Main::Module';
extends 'Lemonldap::NG::Common::Module';
our $VERSION = '2.0.0';

@ -4,7 +4,7 @@ use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_MISSINGREQATTR);
extends 'Lemonldap::NG::Portal::Main::Module';
extends 'Lemonldap::NG::Common::Module';
our $VERSION = '2.0.0';

@ -6,7 +6,7 @@ use Lemonldap::NG::Portal::Main::Constants
qw(PE_OK PE_LDAPCONNECTFAILED PE_LDAPERROR PE_BADCREDENTIALS);
use Lemonldap::NG::Portal::Lib::LDAP;
extends 'Lemonldap::NG::Portal::Main::Module';
extends 'Lemonldap::NG::Common::Module';
our $VERSION = '2.0.0';

@ -4,7 +4,7 @@ use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants;
extends 'Lemonldap::NG::Portal::Main::Module';
extends 'Lemonldap::NG::Common::Module';
our $VERSION = '2.0.0';

@ -6,7 +6,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(PE_OK);
our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Portal::Main::Module',
extends 'Lemonldap::NG::Common::Module',
'Lemonldap::NG::Portal::Lib::Remote';
*getUser = *Lemonldap::NG::Portal::Lib::Remote::checkRemoteId;

@ -12,7 +12,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(PE_FORBIDDENIP PE_OK);
our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Portal::Main::Module';
extends 'Lemonldap::NG::Common::Module';
sub init { 1 }

@ -0,0 +1,123 @@
use Test::More;
use strict;
use IO::String;
require 't/test-lib.pm';
my $res;
my $file = 't/notifications.db';
eval { unlink $file };
SKIP: {
eval { require DBI; require DBD::SQLite; };
if ($@) {
skip 'DBD::SQLite not found', 1;
}
my $dbh = DBI->connect("dbi:SQLite:dbname=$file");
$dbh->do(
'CREATE TABLE notifications (uid text,ref text,date datetime,xml text,cond text,done datetime)'
);
$dbh->do(
qq{INSERT INTO notifications VALUES ('dwho','testref','2016-05-30 00:00:00','<?xml version="1.0" encoding="UTF-8"?>
<root><notification uid="dwho" date="2016-05-30" reference="testref">
<title>Test title</title>
<subtitle>Test subtitle</subtitle>
<text>This is a test text</text>
<check>Accept test</check>
</notification></root>',null,null)}
);
init(
{
logLevel => 'error',
useSafeJail => 1,
notifications => 1,
templatesDir => 'site/templates/',
notificationStorage => 'DBI',
notificationStorageOptions => {
dbiChain => "dbi:SQLite:dbname=$file",
},
}
);
# Try yo authenticate
# -------------------
ok(
$res = &client->_post(
'/',
IO::String->new(
'user=dwho&password=dwho&url=aHR0cDovL3Rlc3QxLmV4YW1wbGUuY29tLw=='
),
accept => 'text/html',
length => 64,
),
'Auth query'
);
ok( $res->[0] == 200, 'Response is 200' ) or explain( $res->[0], 200 );
my $cookies = getCookies($res);
my $id;
ok( $id = $cookies->{lemonldap}, 'Get cookie' )
or explain( $res, 'Set-Cookie: something' );
count(3);
# Verify that cookie is ciphered (session unvalid)
ok(
$res = &client->_get(
'/',
query => 'url=aHR0cDovL3Rlc3QxLmV4YW1wbGUuY29tLw==',
cookie => "lemonldap=$id",
),
'Test cookie received'
);
ok( $res->[0] == 401, "Session isn't valid" )
or explain( [ $res->[0], $res->[1] ], 401 );
count(2);
# Try to validate notification without accepting it
my $str = 'reference1x1=testref&url=aHR0cDovL3Rlc3QxLmV4YW1wbGUuY29tLw==';
ok(
$res = &client->_post(
'/notifback',
IO::String->new($str),
cookie => "lemonldap=$id",
accept => 'text/html',
length => length($str),
),
"Don't accept notification"
);
ok( $res->[0] == 200, "Don't receive redirection" )
or explain( [ $res->[0], $res->[1] ], 200 );
count(2);
# Try to validate notification
my $str =
'reference1x1=testref&check1x1x1=accepted&url=aHR0cDovL3Rlc3QxLmV4YW1wbGUuY29tLw==';
ok(
$res = &client->_post(
'/notifback',
IO::String->new($str),
cookie => "lemonldap=$id",
accept => 'text/html',
length => length($str),
),
"Accept notification"
);
ok( $res->[0] == 302, "Get redirection" )
or explain( [ $res->[0], $res->[1] ], 302 );
# Verify that notification was tagged as 'done'
my $sth =
$dbh->prepare('SELECT * FROM notifications WHERE done IS NOT NULL');
$sth->execute;
my $i = 0;
while ( $sth->fetchrow_hashref ) { $i++ }
ok( $i == 1, 'Notification was deleted' );
count(3);
clean_sessions();
}
eval { unlink $file };
done_testing( count() );
Loading…
Cancel
Save