# Base package for simple issuers plugins # # Issuer should just implement a run() method that will be called only for # authenticated users when PATH_INFO starts with issuerDBXXPath # # run() should just return a Lemonldap::NG::Portal::Main::Constants value. It # is called using process() method (Lemonldap::NG::Portal::Main::Process) package Lemonldap::NG::Portal::Main::Issuer; use strict; use Mouse; use Lemonldap::NG::Portal::Main::Constants qw(PE_OK); extends 'Lemonldap::NG::Portal::Main::Plugin'; our $VERSION = '2.0.0'; # PROPERTIES has type => ( is => 'rw' ); has path => ( is => 'rw' ); # INTERFACE # Only logout is called in normal use. Issuer that inherits from this # package are called only by their path sub beforeLogout { 'logout' } # INITIALIZATION sub init { my ($self) = @_; my $type = ref( $_[0] ); $type =~ s/.*:://; $self->type($type); if ( my $path = $self->conf->{"issuerDB${type}Path"} ) { $path =~ s/^.*?(\w+).*?$/$1/; $self->path($path); $self->addUnauthRoute( $path => { '*' => '_redirect' }, ['GET'] ); $self->addUnauthRoute( $path => { '*' => '_pRedirect' }, ['POST'] ); $self->addAuthRoute( $path => { '*' => "_forAuthUser" }, ['GET'] ); $self->addAuthRoute( $path => { '*' => "_pForAuthUser" }, ['POST'] ); } else { $self->lmLog( "No path declared for issuer $type. Skipping", 'debug' ); } } # RUNNING METHODS # Case 1: Unauthentified users are redirected to the main portal sub _redirect { my ( $self, $req, @path ) = @_; $self->lmLog( 'Processing _redirect', 'debug' ); my $prms = $req->params; foreach my $k ( keys %$prms ) { $self->p->setHiddenFormValue( $req, $k, $prms->{$k}, '', 0 ); } $self->p->setHiddenFormValue( $req, 'issuerMethod', $req->method, '', 0 ); $self->p->setHiddenFormValue( $req, 'issuerQuery', $req->query, '', 0 ); $req->{urldc} = $self->conf->{portal} . $req->path . ( $req->query ? '?' . $req->query : '' ); # TODO: launch normal process with 'run' at the end return $self->p->do( $req, [ 'controlUrl', @{ $self->p->beforeAuth }, $self->p->authProcess, @{ $self->p->betweenAuthAndDatas }, $self->p->sessionDatas, @{ $self->p->afterDatas }, sub { return $self->run( @_, @path ); } ] ); } sub _pRedirect { my ( $self, $req, @path ) = @_; $self->lmLog( '_pRedirect: parsing posted datas', 'debug' ); $req->parseBody; return $self->_redirect( $req, @path ); } # Case 3: authentified user, launch sub _forAuthUser { my ( $self, $req, @path ) = @_; $self->lmLog( 'Processing _forAuthUser', 'debug' ); return $self->p->do( $req, [ 'importHandlerDatas', 'controlUrl', @{ $self->p->forAuthUser }, sub { return $self->run( @_, @path ); }, ] ); } sub _pForAuthUser { my ( $self, $req ) = @_; $self->lmLog( 'Parsing posted datas', 'debug' ); $req->parseBody; return $self->_forAuthUser($req); } 1; __END__ =pod =encoding utf8 =head1 NAME Lemonldap::NG::Portal::Main::Issuer - Base class for identity providers. =head1 SYNOPSIS package Lemonldap::NG::Portal::Issuer::My; use strict; use Mouse; extends 'Lemonldap::NG::Portal::Main::Issuer'; use Lemonldap::NG::Portal::Main::Constants qw(PE_OK); # Optional initialization method sub init { my ($self) = @_; ... # Must return 1 (succeed) or 0 (failure) } # Required methods are run() and logout(), they are launched only for # authenticated users # $req is a Lemonldap::NG::Portal::Main::Request object # They must return a Lemonldap::NG::Portal::Main::Constants constant sub run { my ( $self, $req ) = @_ ... return PE_OK } sub logout { my ( $self, $req ) = @_ ... return PE_OK } 1; =head1 DESCRIPTION Lemonldap::NG::Portal::Main::Issuer is a base class to write identity providers for Lemonldap::NG web-SSO system. It provide several methods to write easily an IdP and manage authentication if the identity request comes before authentication. =head1 WRITING AN IDENTITY PROVIDER To write a classic identity provider, you just have to inherit this class and write run() and logout() methods. These methods must return a Lemonldap::NG::Portal::Main::Constants constant. A classic identity provider needs a "issuerDBEXXXEPath" parameter in LLNG configuration to declare its base URI path (see L). Example: /saml/. All requests that starts with /saml/ will call run() after authentication if needed, and no one else. The logout() function is called when user asks for logout on this server. If you want to write an identity provider, you must implement a single logout system. =head2 managing other URI path Lemonldap::NG::Portal::Main::Issuer provides methods to bind a method to an URI path: =over =item addAuthRoute() for authenticated users =item addUnauthRoute() for unauthenticated users =back They must be called during initialization process (so you must write the optional init() sub). Example: sub init { my ($self) = @_; ... $self->addUnauthRoute( saml => { soap => 'soapServer' }, [ 'POST' ] ); return 1; } sub soapServer { my ( $self, $req ) = @_; ... # You must return a valid PSGI response return [ 200, [ 'Content-Type' => 'application/xml' ], [] ]; } =head1 SEE ALSO L =head1 AUTHOR =over =item Clement Oudot, Eclem.oudot@gmail.comE =item Xavier Guimard, Ex.guimard@free.frE =back =head1 BUG REPORT Use OW2 system to report bug or ask for features: L =head1 DOWNLOAD Lemonldap::NG is available at L =head1 COPYRIGHT AND LICENSE =over =item Copyright (C) 2016 by Xavier Guimard, Ex.guimard@free.frE =item Copyright (C) 2016 by Clement Oudot, Eclem.oudot@gmail.comE =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. =cut