lemonldap-ng/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Init.pm
2016-04-13 21:06:04 +00:00

273 lines
7.8 KiB
Perl

##@class Lemonldap::NG::Portal::Main::Init
# Initialization part of Lemonldap::NG portal
#
# 2 public methods:
# - init(): launch at startup. Load 'portal' section of lemonldap-ng.ini,
# initialize default route and launch reloadConf()
# - reloadConf(): (re)load configuration using localConf (ie 'portal' section
# of lemonldap-ng.ini) and underlying handler configuration
package Lemonldap::NG::Portal::Main::Init;
our $VERSION = '2.0.0';
package Lemonldap::NG::Portal::Main;
use strict;
use Mouse;
use Regexp::Assemble;
# Configuration storage
has localConfig => ( is => 'rw', default => sub { {} } );
has conf => ( is => 'rw', default => sub { {} } );
has menu => ( is => 'rw', default => sub { {} } );
# Sub modules
has _authentication => ( is => 'rw' );
has _userDB => ( is => 'rw' );
# Macros and groups
has _macros => ( is => 'rw' );
has _groups => ( is => 'rw' );
# TrustedDomain regexp
has trustedDomains => ( is => 'rw' );
# Lists to store plugins entry-points
has beforeAuth => (
is => 'rw',
isa => 'ArrayRef',
default => sub { [] }
);
has betweenAuthAndDatas => (
is => 'rw',
isa => 'ArrayRef',
default => sub { [] }
);
has afterDatas => (
is => 'rw',
isa => 'ArrayRef',
default => sub { [] }
);
has forAuthUser => (
is => 'rw',
isa => 'ArrayRef',
default => sub { [] }
);
sub init {
my ( $self, $args ) = @_;
$args ||= {};
$self->localConfig(
{
%{ Lemonldap::NG::Common::Conf->new( $args->{configStorage} )
->getLocalConf('portal')
},
%$args
}
);
Lemonldap::NG::Handler::Main::Reload->onReload( $self, 'reloadConf' );
return 0 unless ( $self->SUPER::init($args) );
return 0 if ( $self->error );
# Handle requests (other path may be declared in enabled plugins)
$self
# "/"
->addUnauthRoute( '*', 'login', ['GET'] )
->addUnauthRoute( '*', 'postLogin', ['POST'] )
->addAuthRoute( '*', 'authenticatedRequest', ['GET'] )
->addAuthRoute( '*', 'postAuthenticatedRequest', ['POST'] )
# Core REST API
->addUnauthRoute( 'test', 'pleaseAuth', ['GET'] )
->addAuthRoute( 'test', 'authenticated', ['GET'] );
# Default routes must point to routines declared above
$self->defaultAuthRoute('');
$self->defaultUnauthRoute('');
1;
}
sub reloadConf {
my ( $self, $conf ) = @_;
# Reinitialize $self->conf
%{ $self->{conf} } = %{ $self->localConfig };
# Reinitialize arrays
foreach (
qw(_macros _groups beforeAuth betweenAuthAndDatas afterDatas forAuthUser)
)
{
$self->{$_} = [];
}
# Load conf in portal object
foreach my $key ( keys %$conf ) {
$self->{conf}->{$key} ||= $conf->{$key};
}
# Initialize templateDir
$self->{templateDir} =
$self->conf->{templateDir} . '/' . $self->conf->{portalSkin};
$self->{staticPrefix} = $self->conf->{staticPrefix} || '/';
# Initialize session DBs
unless ( $self->conf->{globalStorage} ) {
$self->error(
'globalStorage not defined (perhaps configuration can not be read)'
);
return 0;
}
# Initialize persistent session DB
unless ( $self->conf->{persistentStorage} ) {
$self->conf->{persistentStorage} = $self->conf->{globalStorage};
$self->conf->{persistentStorageOptions} =
$self->conf->{globalStorageOptions};
}
# Initialize cookie domain
unless ( $self->conf->{domain} ) {
$self->error('Configuration error: no domain');
return 0;
}
$self->conf->{domain} =~ s/^([^\.])/.$1/;
# Load authentication/userDB
# --------------------------
for my $type (qw(authentication userDB)) {
unless ( $self->conf->{$type} ) {
$self->error("$type is not set");
return 0;
}
my $module = '::' . ucfirst($type) . '::' . $self->conf->{$type};
$module =~ s/Authentication/Auth/;
# Launch and initialize module
return 0
unless ( $self->{"_$type"} = $self->loadModule($module)
and $self->{"_$type"}->init );
}
$self->_authentication->authnLevel(
$self->conf->{ $self->conf->{authentication} . "AuthnLevel" } );
# Initialize trusted domain regexp
if ( $self->conf->{trustedDomains}
and $self->conf->{trustedDomains} =~ /^\s*\*\s*$/ )
{
$self->trustedDomains(qr#^https?://#);
}
else {
my $re = Regexp::Assemble->new();
if ( my $td = $self->conf->{trustedDomains} ) {
$td =~ s/^\s*(.*?)\s*/$1/;
$self->lmLog( "Domain $_ added in trusted domains", 'debug' );
foreach ( split( /\s+/, $td ) ) {
s#^\.#([^/]+\.)?#;
s/\./\\./;
$re->add($_);
}
}
foreach my $vhost ( keys %{ $self->conf->{locationRules} } ) {
$self->lmLog( "Vhost $vhost added in trusted domains", 'debug' );
$re->add( quotemeta($vhost) );
if ( my $tmp =
$self->conf->{vhostOptions}->{$vhost}->{vhostAliases} )
{
foreach my $alias ( split /\s+/, $tmp ) {
$self->lmLog( "Alias $alias added in trusted domains",
'debug' );
$re->add( quotemeta($alias) );
}
}
}
my $tmp = 'https?://' . $re->as_string . '(?:/|$)';
$self->trustedDomains(qr/$tmp/);
}
if ( my $td = $self->conf->{trustedDomains} ) {
$td =~ s/^\s*(.*?)\s*/$1/;
if ( $td eq '*' ) {
$self->trustedDomains(qr#^https?://#);
}
else {
my $tmp =
join( '|', map { s#^\.#([^/]+\.)?# } split( /\s+/, $td ) );
$tmp =~ s/\./\\./g;
$self->trustedDomains(qr#^https?://$tmp(?:\d+)?(?:/|$)#);
}
}
# Compile macros in _macros, groups in _groups
foreach my $type (qw(macros groups)) {
$self->{"_$type"} = {};
if ( $self->conf->{$type} ) {
for my $name ( sort keys %{ $self->conf->{$type} } ) {
my $sub =
HANDLER->tsv->{jail}->jail_reval( "sub{return("
. HANDLER->substitute( $self->conf->{$type}->{$name} )
. ")}" );
if ($sub) {
$self->{"_$type"}->{$name} = $sub;
}
else {
$self->lmLog(
"$type $name returns an error: "
. HANDLER->tsv->{jail}->error,
'error'
);
}
}
}
}
# Load plugins
foreach my $plugin ( $self->enabledPlugins ) {
$self->loadPlugin($plugin) or return 0;
}
$self->menu( $self->loadModule('::Main::Menu') );
1;
}
sub loadPlugin {
my ( $self, $plugin ) = @_;
my $obj;
return 0
unless ( $obj = $self->loadModule("$plugin") );
foreach my $sub (
qw(beforeAuthProcess addSessionData afterAuthProcess forAuthUser))
{
if ( $obj->can($sub) ) {
if ( my $callback = $obj->$sub ) {
push @{ $self->{$sub} }, sub { $obj->$callback( $_[1] ) };
}
}
}
return $obj->init;
}
sub loadModule {
my ( $self, $module ) = @_;
my $obj;
$module = "Lemonldap::NG::Portal$module" if ( $module =~ /^::/ );
eval "require $module";
if ($@) {
$self->error("$module load error: $@");
return 0;
}
eval {
$obj = $module->new( { p => $self, conf => $self->conf } );
$self->lmLog( "Module $module loaded", 'debug' );
};
if ($@) {
$self->error("Unable to build $module object: $@");
return 0;
}
return $obj;
}
1;