2016-06-09 20:40:20 +02:00
|
|
|
# Base package for LLNG portal plugins. It adds somme wrapper to
|
|
|
|
# Lemonldap::NG::Handler::PSGI::Try (base of portal)
|
2016-05-28 10:33:39 +02:00
|
|
|
package Lemonldap::NG::Portal::Main::Plugin;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use Mouse;
|
2017-10-10 11:24:08 +02:00
|
|
|
use HTML::Template;
|
2019-06-18 22:00:03 +02:00
|
|
|
use Lemonldap::NG::Portal::Main::Constants qw(
|
|
|
|
PE_OK
|
|
|
|
PE_INFO
|
|
|
|
PE_ERROR
|
|
|
|
);
|
2016-05-28 10:33:39 +02:00
|
|
|
|
2019-09-12 21:56:49 +02:00
|
|
|
our $VERSION = '2.0.6';
|
2016-05-28 10:33:39 +02:00
|
|
|
|
2016-06-02 23:20:36 +02:00
|
|
|
extends 'Lemonldap::NG::Common::Module';
|
2016-05-28 10:33:39 +02:00
|
|
|
|
2017-01-09 07:11:28 +01:00
|
|
|
sub sendError {
|
|
|
|
my $self = shift;
|
|
|
|
return $self->p->sendError(@_);
|
|
|
|
}
|
|
|
|
|
|
|
|
sub sendJSONresponse {
|
|
|
|
my $self = shift;
|
|
|
|
return $self->p->sendJSONresponse(@_);
|
|
|
|
}
|
|
|
|
|
2016-05-28 10:33:39 +02:00
|
|
|
sub addAuthRoute {
|
|
|
|
my $self = shift;
|
2016-12-17 21:19:46 +01:00
|
|
|
return $self->_addRoute( 'addAuthRoute', @_ );
|
2016-05-28 10:33:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sub addUnauthRoute {
|
|
|
|
my $self = shift;
|
2016-12-17 21:19:46 +01:00
|
|
|
return $self->_addRoute( 'addUnauthRoute', @_ );
|
2016-05-28 10:33:39 +02:00
|
|
|
}
|
|
|
|
|
2019-06-06 22:59:02 +02:00
|
|
|
sub addAuthRouteWithRedirect {
|
|
|
|
my $self = shift;
|
|
|
|
return $self->_addRoute( 'addAuthRouteWithRedirect', @_ );
|
|
|
|
}
|
|
|
|
|
2016-05-28 10:33:39 +02:00
|
|
|
sub _addRoute {
|
2016-12-17 21:19:46 +01:00
|
|
|
my ( $self, $type, $word, $subName, $methods, $transform ) = @_;
|
|
|
|
$transform //= sub {
|
|
|
|
my ($sub) = @_;
|
|
|
|
if ( ref $sub ) {
|
|
|
|
return sub {
|
|
|
|
shift;
|
|
|
|
return $sub->( $self, @_ );
|
2019-07-02 20:03:40 +02:00
|
|
|
}
|
2016-12-17 21:19:46 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
return sub {
|
|
|
|
shift;
|
|
|
|
return $self->$sub(@_);
|
2019-07-02 20:03:40 +02:00
|
|
|
}
|
2016-12-17 21:19:46 +01:00
|
|
|
}
|
|
|
|
};
|
2017-01-08 07:25:10 +01:00
|
|
|
$self->p->$type( $word, $subName, $methods, $transform );
|
|
|
|
return $self;
|
2016-05-28 10:33:39 +02:00
|
|
|
}
|
|
|
|
|
2017-10-10 11:24:08 +02:00
|
|
|
sub loadTemplate {
|
2017-10-10 13:04:40 +02:00
|
|
|
my $self = shift;
|
|
|
|
return $self->p->loadTemplate(@_);
|
2017-10-10 11:24:08 +02:00
|
|
|
}
|
|
|
|
|
2019-06-18 22:00:03 +02:00
|
|
|
sub displayTemplate {
|
|
|
|
my ( $self, $req, $template, $params ) = @_;
|
|
|
|
$self->logger->debug("Return $template template");
|
2019-06-28 13:40:56 +02:00
|
|
|
$req->info( $self->loadTemplate( $req, $template, params => $params ) );
|
2019-06-18 22:00:03 +02:00
|
|
|
return PE_INFO;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub createNotification {
|
|
|
|
my ( $self, $req, $uid, $date, $ref, $title, $msg ) = @_;
|
|
|
|
my $notifEngine = $self->p->loadedModules->{
|
|
|
|
'Lemonldap::NG::Portal::Plugins::Notifications'};
|
|
|
|
|
|
|
|
return PE_ERROR unless $notifEngine;
|
|
|
|
|
|
|
|
# Prepare notification
|
|
|
|
my $content =
|
|
|
|
$self->conf->{oldNotifFormat}
|
|
|
|
? '<?xml version="1.0" encoding="UTF-8"?><root><notification uid="_uid_" date="_date_" reference="_ref_"><title>_title_</title><text>_msg_</text></notification></root>'
|
|
|
|
: '[{"uid":"_uid_","date":"_date_","title":"_title_","reference":"_ref_","text":"_msg_"}]';
|
|
|
|
$content =~ s/_uid_/$uid/;
|
|
|
|
$content =~ s/_date_/$date/;
|
|
|
|
$content =~ s/_ref_/$ref/;
|
|
|
|
$content =~ s/_title_/$title/;
|
|
|
|
$content =~ s/_msg_/$msg/;
|
|
|
|
|
2019-06-28 13:40:56 +02:00
|
|
|
if ( $notifEngine->module->notifObject->newNotification($content) ) {
|
2019-06-18 22:00:03 +02:00
|
|
|
$self->logger->debug("Notification $ref successfully created");
|
|
|
|
$self->userLogger->notice(
|
|
|
|
"Notification $ref / $date successfully created for $uid");
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$self->logger->debug("Notification $ref NOT created!");
|
|
|
|
return PE_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-28 10:33:39 +02:00
|
|
|
1;
|
2017-01-30 21:21:58 +01:00
|
|
|
__END__
|
|
|
|
|
|
|
|
=pod
|
|
|
|
|
|
|
|
=encoding utf8
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
Lemonldap::NG::Portal::Main::Plugin - Base class for
|
|
|
|
L<Lemonldap::NG::Portal> modules I<(plugins, authentication modules,...)>.
|
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
|
|
package Lemonldap::NG::Portal::My::Plugin;
|
|
|
|
use Mouse;
|
|
|
|
extends 'Lemonldap::NG::Portal::Main::Plugin';
|
|
|
|
|
|
|
|
use constant beforeAuth => 'verifyIP';
|
|
|
|
|
|
|
|
sub init {
|
|
|
|
my ($self) = @_;
|
|
|
|
$self->addUnauthRoute( mypath => 'hello', [ 'GET', 'PUT' ] );
|
2018-06-12 12:23:35 +02:00
|
|
|
$self->addAuthRoute( mypath => 'welcome', [ 'GET', 'PUT' ] );
|
2017-01-30 21:21:58 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
sub verifyIP {
|
|
|
|
my ($self, $req) = @_;
|
|
|
|
return PE_ERROR if($req->address !~ /^10/);
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
sub hello {
|
|
|
|
my ($self, $req) = @_;
|
|
|
|
...
|
|
|
|
return $self->p->sendJSONresponse($req, { hello => 1 });
|
|
|
|
}
|
2018-06-12 12:23:35 +02:00
|
|
|
sub welcome {
|
2017-01-30 21:21:58 +01:00
|
|
|
my ($self, $req) = @_;
|
|
|
|
...
|
2018-06-12 12:23:35 +02:00
|
|
|
return $self->p->sendHtml($req, 'template', params => { WELCOME => 1 });
|
2017-01-30 21:21:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
2018-08-16 09:39:27 +02:00
|
|
|
Lemonldap::NG::Portal::Main::Plugin provides many methods to easily write
|
2017-01-30 21:21:58 +01:00
|
|
|
Lemonldap::NG addons.
|
|
|
|
|
2018-08-16 09:39:27 +02:00
|
|
|
init() is called for each plugin. If a plugin initialization fails (init()
|
2017-01-30 21:21:58 +01:00
|
|
|
returns 0), the portal responds a 500 status code for each request.
|
|
|
|
|
|
|
|
=head1 Writing plugins
|
|
|
|
|
|
|
|
Custom plugins can be inserted in portal by declaring them in
|
|
|
|
C<lemonldap-ng.ini> file, section C<[portal]>, key C<customPlugins>:
|
|
|
|
|
|
|
|
[portal]
|
|
|
|
customPlugins = My::Plugin1, My::Plugin2
|
|
|
|
|
|
|
|
Plugins must be valid packages well found in C<@INC>.
|
|
|
|
|
|
|
|
=head2 Plugin entry points
|
|
|
|
|
|
|
|
=head3 Entry point based on PATH_INFO
|
|
|
|
|
2018-08-16 09:39:27 +02:00
|
|
|
Plugins can declare unauthRoutes/authRoutes during initialization (=
|
2017-01-30 21:21:58 +01:00
|
|
|
/path/info). Methods declared in this way must be declared in the plugin class.
|
2018-08-16 09:39:27 +02:00
|
|
|
They will be called with $req argument. $req is the HTTP request.
|
|
|
|
(See L<Lemonldap::NG::Portal::Main::Request>). These methods must return a valid
|
2017-01-30 21:21:58 +01:00
|
|
|
L<PSGI> response. You can also use sendJSONresponse() or sendHtml() methods
|
|
|
|
(see L<Lemonldap::NG::Common::PSGI>).
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
|
|
|
sub init {
|
|
|
|
my ($self) = @_;
|
|
|
|
$self->addUnauthRoute( mypath => 'hello', [ 'GET', 'PUT' ] );
|
2018-08-16 09:39:27 +02:00
|
|
|
$self->addAuthRoute( mypath => 'welcome', [ 'GET', 'PUT' ] );
|
2017-01-30 21:21:58 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
sub hello {
|
|
|
|
my ($self, $req) = @_;
|
|
|
|
...
|
|
|
|
return $self->p->sendJSONresponse($req, { hello => 1 });
|
|
|
|
}
|
2018-08-16 09:39:27 +02:00
|
|
|
sub welcome {
|
2017-01-30 21:21:58 +01:00
|
|
|
my ($self, $req) = @_;
|
|
|
|
...
|
|
|
|
return $self->p->sendHtml($req, 'template', params => { WELLCOME => 1 });
|
|
|
|
}
|
|
|
|
|
2019-06-06 23:02:46 +02:00
|
|
|
If you want to get a "protected application" behavior, you can use
|
|
|
|
B<addAuthRouteWithRedirect>. This methods calls B<addAuthRoute> with given
|
|
|
|
arguments and build a "unAuth" route that build a redirection after
|
|
|
|
authentication.
|
|
|
|
|
2017-01-30 21:21:58 +01:00
|
|
|
=head3 Entry point in auth process
|
|
|
|
|
|
|
|
A plugin which wants to be inserted in authentication process has to declare
|
2018-08-16 09:39:27 +02:00
|
|
|
constants set with method name to run. Following entry points are available.
|
2017-01-30 21:21:58 +01:00
|
|
|
|
|
|
|
=over
|
|
|
|
|
|
|
|
=item C<beforeAuth>: method called before authentication process
|
|
|
|
|
2018-07-05 22:56:16 +02:00
|
|
|
=item C<betweenAuthAndData>: method called after authentication and before
|
2017-01-30 21:21:58 +01:00
|
|
|
setting C<sessionInfo> provisionning
|
|
|
|
|
2018-07-05 22:56:16 +02:00
|
|
|
=item C<afterData>: method called after C<sessionInfo> provisionning
|
2017-01-30 21:21:58 +01:00
|
|
|
I<(macros, groups,...)>
|
|
|
|
|
2018-09-05 09:19:01 +02:00
|
|
|
=item C<endAuth>: method called when session is validated (after cookie build)
|
|
|
|
|
2018-07-10 07:11:08 +02:00
|
|
|
=item C<authCancel>: method called when user click on "cancel" during auth
|
|
|
|
process
|
|
|
|
|
2017-01-30 21:21:58 +01:00
|
|
|
=item C<forAuthUser>: method called for already authenticated users
|
|
|
|
|
|
|
|
=item C<beforeLogout>: method called before logout
|
|
|
|
|
2018-12-13 06:57:10 +01:00
|
|
|
=back
|
|
|
|
|
|
|
|
B<Note>: methods inserted so must return a PE_* constant. See
|
|
|
|
Lemonldap::NG::Portal::Main::Constants.
|
|
|
|
|
|
|
|
=head4 Advanced entry points
|
|
|
|
|
|
|
|
These entry points are not stored in C<$req-E<gt>step> but launched on the fly:
|
|
|
|
|
|
|
|
=over
|
|
|
|
|
2018-12-12 22:09:27 +01:00
|
|
|
=item C<afterSub>: hash ref that give methods to call after given main method
|
|
|
|
is called. Example:
|
|
|
|
|
|
|
|
use constant afterSub => {
|
|
|
|
getUser => 'mysub',
|
|
|
|
}
|
|
|
|
sub mysub {
|
|
|
|
my ( $self ,$req ) = @_;
|
|
|
|
# Do something
|
|
|
|
return PE_OK;
|
|
|
|
}
|
|
|
|
|
2018-12-13 06:57:10 +01:00
|
|
|
=item C<aroundSub>: hash ref that give methods to call instead of given main
|
|
|
|
method. Example:
|
2017-01-30 21:21:58 +01:00
|
|
|
|
2018-12-13 06:57:10 +01:00
|
|
|
use constant aroundSub => {
|
|
|
|
getUser => 'mysub',
|
|
|
|
};
|
|
|
|
sub mysub {
|
|
|
|
my ( $self, $sub, $req ) = @_;
|
|
|
|
# Do something before
|
|
|
|
my $ret = $sub->($req);
|
|
|
|
# Do something after
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
Do not launch "getUser" but use the given C<$sub>. This permits multiple
|
|
|
|
plugins to use "aroundSub" in the same time.
|
|
|
|
|
|
|
|
=back
|
2017-01-30 21:21:58 +01:00
|
|
|
|
2019-07-04 07:09:39 +02:00
|
|
|
=head1 LOGGING
|
|
|
|
|
|
|
|
Logging is provided by $self->logger and $self->userLogger. The following rules
|
|
|
|
must be applied:
|
|
|
|
|
|
|
|
=over
|
|
|
|
|
|
|
|
=item logger->debug: technical debugging messages
|
|
|
|
|
|
|
|
=item logger->info: simple technical information
|
|
|
|
|
|
|
|
=item logger->notice: technical information that could interest administrators
|
|
|
|
|
|
|
|
=item logger->warn: technical warning
|
|
|
|
|
|
|
|
=item logger->error: error that must be reported to administrator
|
|
|
|
|
|
|
|
=item userLogger->info: simple information about user's action
|
|
|
|
|
|
|
|
=item userLogger->notice: information that may be registered (auth success,...)
|
|
|
|
|
|
|
|
=item userLogger->warn: bad action of a user (auth failure). Auth/Combination
|
|
|
|
transform it to "info" when another authentication scheme is available
|
|
|
|
|
|
|
|
=item userLogger->error: bad action of a user that must be reported, (even if
|
|
|
|
another backend is available with Combination)
|
|
|
|
|
|
|
|
=back
|
|
|
|
|
2017-01-30 21:21:58 +01:00
|
|
|
=head1 SEE ALSO
|
|
|
|
|
|
|
|
L<http://lemonldap-ng.org>
|
|
|
|
|
|
|
|
=head2 OTHER POD FILES
|
|
|
|
|
|
|
|
=over
|
|
|
|
|
2018-02-19 22:07:20 +01:00
|
|
|
=item Writing an authentication module: L<Lemonldap::NG::Portal::Auth>
|
|
|
|
|
|
|
|
=item Writing a UserDB module: L<Lemonldap::NG::Portal::UserDB>
|
|
|
|
|
|
|
|
=item Writing a second factor module: L<Lemonldap::NG::Portal::Main::SecondFactor>
|
2017-01-30 21:21:58 +01:00
|
|
|
|
|
|
|
=item Writing an issuer module: L<Lemonldap::NG::Portal::Main::Issuer>
|
|
|
|
|
2018-03-15 21:20:03 +01:00
|
|
|
=item Writing another plugin: L<Lemonldap::NG::Portal::Main::Plugin>
|
2018-02-19 22:07:20 +01:00
|
|
|
|
2017-01-30 21:21:58 +01:00
|
|
|
=item Request object: L<Lemonldap::NG::Portal::Main::Request>
|
|
|
|
|
|
|
|
=item Adding parameters in the manager: L<Lemonldap::NG::Manager::Build>
|
|
|
|
|
|
|
|
=back
|
|
|
|
|
|
|
|
=head1 AUTHORS
|
|
|
|
|
|
|
|
=over
|
|
|
|
|
|
|
|
=item LemonLDAP::NG team L<http://lemonldap-ng.org/team>
|
|
|
|
|
|
|
|
=back
|
|
|
|
|
|
|
|
=head1 BUG REPORT
|
|
|
|
|
|
|
|
Use OW2 system to report bug or ask for features:
|
2017-11-11 14:06:23 +01:00
|
|
|
L<https://gitlab.ow2.org/lemonldap-ng/lemonldap-ng/issues>
|
2017-01-30 21:21:58 +01:00
|
|
|
|
|
|
|
=head1 DOWNLOAD
|
|
|
|
|
|
|
|
Lemonldap::NG is available at
|
|
|
|
L<http://forge.objectweb.org/project/showfiles.php?group_id=274>
|
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
|
|
|
|
|
|
|
See COPYING file for details.
|
|
|
|
|
|
|
|
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
|