diff --git a/modules/lemonldap-ng-portal/example/index_skin.pl b/modules/lemonldap-ng-portal/example/index_skin.pl index 61f0d5b66..66700fb05 100755 --- a/modules/lemonldap-ng-portal/example/index_skin.pl +++ b/modules/lemonldap-ng-portal/example/index_skin.pl @@ -75,41 +75,26 @@ if ( $portal->process() ) { # 1.3 Case : display menu else { - $skinfile = 'menu.tpl'; - # Menu creation - use Lemonldap::NG::Portal::Menu; - my $menu = Lemonldap::NG::Portal::Menu->new( - { - portalObject => $portal, - modules => { - appslist => $portal->{portalDisplayAppslist}, - password => $portal->{portalDisplayChangePassword}, - logout => $portal->{portalDisplayLogout}, - }, - } - ); + # Initialize menu elements + $portal->_sub('menuInit'); + + $skinfile = 'menu2.tpl'; + %templateParams = ( AUTH_USER => $portal->{sessionInfo}->{ $portal->{portalUserAttr} }, AUTOCOMPLETE => $portal->{portalAutocomplete}, SKIN => $skin, - AUTH_ERROR => $portal->error, - AUTH_ERROR_TYPE => $portal->error_type, - DISPLAY_APPSLIST => $menu->displayModule("appslist"), - DISPLAY_PASSWORD => $menu->displayModule("password"), - DISPLAY_LOGOUT => $menu->displayModule("logout"), - DISPLAY_TAB => $menu->displayTab, + AUTH_ERROR => $portal->error( undef, $portal->{menuError} ), + AUTH_ERROR_TYPE => $portal->error_type( $portal->{menuError} ), + DISPLAY_TAB => $portal->{menuDisplayTab}, LOGOUT_URL => "$ENV{SCRIPT_NAME}?logout=1", REQUIRE_OLDPASSWORD => $portal->{portalRequireOldPassword}, + DISPLAY_MODULES => $portal->{menuDisplayModules}, + APPSLIST_MENU => $portal->{menuAppslistMenu}, + APPSLIST_DESC => $portal->{menuAppslistDesc}, ); - if ( $menu->displayModule("appslist") ) { - %templateParams = ( - %templateParams, - APPSLIST_MENU => $menu->appslistMenu, - APPSLIST_DESC => $menu->appslistDescription - ); - } } } diff --git a/modules/lemonldap-ng-portal/example/skins/pastel/login.tpl b/modules/lemonldap-ng-portal/example/skins/pastel/login.tpl index e5d03ef21..aa1084b7d 100644 --- a/modules/lemonldap-ng-portal/example/skins/pastel/login.tpl +++ b/modules/lemonldap-ng-portal/example/skins/pastel/login.tpl @@ -101,8 +101,12 @@ + + + +
diff --git a/modules/lemonldap-ng-portal/example/skins/pastel/menu.tpl b/modules/lemonldap-ng-portal/example/skins/pastel/menu.tpl index 96f2d8a3e..dce94888f 100644 --- a/modules/lemonldap-ng-portal/example/skins/pastel/menu.tpl +++ b/modules/lemonldap-ng-portal/example/skins/pastel/menu.tpl @@ -8,30 +8,47 @@
+ +
    - + + +
  • appslist
  • - +
  • password
  • - +
  • logout
  • + +
+
- + + + + + +
+ + +
+ + - +

@@ -41,6 +58,9 @@
+ +
+
diff --git a/modules/lemonldap-ng-portal/example/skins/pastel/password.tpl b/modules/lemonldap-ng-portal/example/skins/pastel/password.tpl index e629ccbfa..b32ca5f6c 100644 --- a/modules/lemonldap-ng-portal/example/skins/pastel/password.tpl +++ b/modules/lemonldap-ng-portal/example/skins/pastel/password.tpl @@ -1,4 +1,3 @@ -

@@ -29,4 +28,3 @@
-
diff --git a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Menu.pm b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Menu.pm index 86f72f99a..79fef1bbf 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Menu.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Menu.pm @@ -7,143 +7,48 @@ package Lemonldap::NG::Portal::Menu; use strict; use warnings; -require Lemonldap::NG::Common::CGI; -use Lemonldap::NG::Portal::SharedConf; +use Lemonldap::NG::Portal::Simple; use Lemonldap::NG::Common::Safelib; #link protected safe Safe object use Safe; use constant SAFEWRAP => ( Safe->can("wrap_code_ref") ? 1 : 0 ); -#inherits Net::LDAP::Control::PasswordPolicy +our $VERSION = '0.4'; -our $VERSION = '0.3'; +# Global variables +our ( $defaultCondition, $locationCondition, $locationRegexp, $cfgNum, + $catlevel ) = ( undef, undef, undef, 0, 0 ); -### ACCESS CONTROL DISPLAY SYSTEM - -our ( $defaultCondition, $locationCondition, $locationRegexp, $cfgNum, $path ) = - ( undef, undef, undef, 0 ); - -## @method private Safe _safe() -# Build and returns security jail. -# Includes custom functions -# @return Safe object -sub _safe { +## @method void menuInit() +# Prepare menu template elements +# @return nothing +sub menuInit { my $self = shift; - return $self->{_safe} if ( $self->{_safe} ); - $self->{_safe} = new Safe; - $self->{customFunctions} ||= $self->{portalObject}->{customFunctions}; - my @t = - $self->{customFunctions} ? split( /\s+/, $self->{customFunctions} ) : (); - foreach (@t) { - my $sub = $_; - unless (/::/) { - $sub = "$self->{caller}::$_"; - } - else { - s/^.*:://; - } - next if ( __PACKAGE__->can($_) ); - eval "sub $_ { - return $sub(\$path,\@_); - }"; - $self->{portalObject}->lmLog( $@, 'error' ) if ($@); - } - $self->{_safe}->share_from( 'main', ['%ENV'] ); - $self->{_safe}->share_from( 'Lemonldap::NG::Common::Safelib', - $Lemonldap::NG::Common::Safelib::functions ); - $self->{_safe}->share( '&encode_base64', @t ); - return $self->{_safe}; -} - -my $catlevel = 0; - -##@cmethod Lemonldap::NG::Portal::Menu new(hashRef args) -# Constructor. -# $args->{portalObject} is required. -#@param $args hash reference -#@return new object -sub new { - my $class = shift; - my $self = {}; - bless( $self, $class ); - - # Get configuration - $self->Lemonldap::NG::Portal::Simple::getConf(@_) - or Lemonldap::NG::Common::CGI->abort( - "Unable to read $class->new() parameters"); - - # Portal is required - Lemonldap::NG::Common::CGI->abort("Portal object required") - unless ( $self->{portalObject} ); - - # Fill sessionInfo (yet done in portal...) - #&Lemonldap::NG::Portal::Simple::getSessionInfo( $self->{portalObject} ); - - # Default values $self->{apps}->{imgpath} ||= '/apps/'; - $self->{modules}->{appslist} = 0 - unless defined $self->{modules}->{appslist}; - $self->{modules}->{password} = 0 - unless defined $self->{modules}->{password}; - $self->{modules}->{logout} = 1 unless defined $self->{modules}->{logout}; - $self->{'caller'} = caller; - # Store POST data in $self->{portalObject} - $self->{portalObject}->{'newpassword'} = - $self->{portalObject}->param('newpassword'); - $self->{portalObject}->{'confirmpassword'} = - $self->{portalObject}->param('confirmpassword'); - $self->{portalObject}->{'oldpassword'} = - $self->{portalObject}->param('oldpassword'); - $self->{portalObject}->{'dn'} = - $self->{portalObject}->{sessionInfo}->{'dn'}; - $self->{portalObject}->{'user'} = - $self->{portalObject}->{sessionInfo}->{'_user'}; + # Modules to display + $self->{menuModules} ||= "Appslist ChangePassword Logout"; + $self->{menuDisplayModules} = $self->displayModules(); - # Change password (only if newpassword submitted) - $self->{portalObject}->{error} = - $self->{portalObject}->_subProcess(qw(passwordDBInit modifyPassword)) - if $self->{portalObject}->{'newpassword'}; + # Extract password from POST data + $self->{oldpassword} = $self->param('oldpassword'); + $self->{newpassword} = $self->param('newpassword'); + $self->{confirmpassword} = $self->param('confirmpassword'); + $self->{dn} = $self->{sessionInfo}->{dn}; + $self->{user} = $self->{sessionInfo}->{_user}; - return $self; -} + # Try to change password + $self->{menuError} = $self->_subProcess(qw(passwordDBInit modifyPassword)); -## @method boolean displayModule(string modulename) -# Return true if the user can see the module. -# Use for HTML::Template variable. -# @param $modulename string -# @return boolean -sub displayModule { - my ( $self, $modulename ) = splice @_; + # Default menu error code + $self->{menuError} ||= $self->{error}; - # Manage "0" and "1" rules - return 1 if ( $self->{modules}->{$modulename} eq "1" ); - return 0 if ( $self->{modules}->{$modulename} eq "0" ); - - # Else parse display condition - my $cond = $self->{modules}->{$modulename}; - $cond =~ s/\$(\w+)/$self->{portalObject}->{sessionInfo}->{$1}/g; - return ( - SAFEWRAP - ? $self->_safe->wrap_code_ref( - $self->_safe->reval("sub{return($cond)}") - ) - : $self->_safe->reval("sub{return($cond)}") - ); -} - -## @method string displayTab() -# Tells which tab should be selected. -# Design for Jquery tabs. -# @return password, appslist or logout -sub displayTab { - my $self = shift; - - # Display password tab if password change is needed or failed - return "password" + # Tab to display + $self->{menuDisplayTab} = "appslist"; + $self->{menuDisplayTab} = "password" if ( ( scalar( - grep { $_ == $self->{portalObject}->{error} } ( + grep { $_ == $self->{menuError} } ( 25, #PE_PP_CHANGE_AFTER_RESET 27, #PE_PP_MUST_SUPPLY_OLD_PASSWORD 28, #PE_PP_INSUFFICIENT_PASSWORD_QUALITY @@ -157,11 +62,40 @@ sub displayTab { ) ) ) - && $self->displayModule("password") ); - return "appslist" if ( $self->displayModule("appslist") ); - return "logout"; + # Application list + $self->{menuAppslistMenu} = $self->appslistMenu(); + $self->{menuAppslistDesc} = $self->appslistDescription(); + + return; +} + +## @method arrayref displayModules() +# List modules that can be displayed in Menu +# @return modules list +sub displayModules { + my $self = shift; + my $displayModules = []; + + # Modules list + my @modules = split( /\s/, $self->{menuModules} ); + + # Foreach module, eval condition + # Store module in result if condition is valid + foreach my $module (@modules) { + my $cond = $self->{ 'portalDisplay' . $module }; + $cond = 1 unless defined $cond; + $cond =~ s/\$(\w+)/$self->{sessionInfo}->{$1}/g; + + $self->lmLog( "Evaluate condition $cond for module $module", 'debug' ); + + if ( $self->safe->reval($cond) ) { + push @$displayModules, { $module => 1 }; + } + } + + return $displayModules; } ## @method string appslistMenu() @@ -171,15 +105,15 @@ sub appslistMenu { my $self = shift; # We no more use XML file for menu configuration - unless ( defined $self->{portalObject}->{applicationList} ) { - $self->{portalObject}->abort( + unless ( defined $self->{applicationList} ) { + $self->abort( "XML menu configuration is deprecated", "Please use lmMigrateConfFiles2ini to migrate your menu configuration" ); } # Use configuration to get menu parameters - my $applicationList = $self->{portalObject}->{applicationList}; + my $applicationList = $self->{applicationList}; my $filteredList = $self->_filter($applicationList); return $self->_displayConfCategory( "", $applicationList, $catlevel ); } @@ -191,8 +125,8 @@ sub appslistDescription { my $self = shift; # We no more use XML file for menu configuration - unless ( defined $self->{portalObject}->{applicationList} ) { - $self->{portalObject}->lmLog( + unless ( defined $self->{applicationList} ) { + $self->lmLog( "XML menu configuration is deprecated. Please use lmMigrateConfFiles2ini to migrate your menu configuration", 'error' ); @@ -200,7 +134,7 @@ sub appslistDescription { } # Use configuration to get menu parameters - my $applicationList = $self->{portalObject}->{applicationList}; + my $applicationList = $self->{applicationList}; return $self->_displayConfDescription( "", $applicationList ); } @@ -257,16 +191,6 @@ sub _displayConfCategory { return $html; } -## @method private string _userParam(string arg) -# Returns value of $arg variable stored in session. -# @param $arg string to modify -# @return string modified -sub _userParam { - my ( $self, $arg ) = splice @_; - $arg =~ s/\$([\w]+)/$self->{portalObject}->{sessionInfo}->{$1}/g; - return $arg; -} - ## @method private string _displayConfApplication() # Creates HTML code for an application. # @param $appid Application ID @@ -475,11 +399,11 @@ sub _isCategoryEmpty { sub _grant { my ( $self, $uri ) = splice @_; $uri =~ m{(\w+)://([^/:]+)(:\d+)?(/.*)?$} or return 0; - my ( $protocol, $vhost, $port ); + my ( $protocol, $vhost, $port, $path ); ( $protocol, $vhost, $port, $path ) = ( $1, $2, $3, $4 ); $path ||= '/'; $self->_compileRules() - if ( $cfgNum != $self->{portalObject}->{cfgNum} ); + if ( $cfgNum != $self->{cfgNum} ); return -1 unless ( defined( $defaultCondition->{$vhost} ) ); if ( defined $locationRegexp->{$vhost} ) { # Not just a default rule @@ -490,8 +414,8 @@ sub _grant { } } unless ( $defaultCondition->{$vhost} ) { - $self->{portalObject} - ->lmLog( "Application $uri did not match any configured virtual host", + $self->lmLog( + "Application $uri did not match any configured virtual host", 'warn' ); return 0; } @@ -504,18 +428,18 @@ sub _grant { # @return True sub _compileRules { my $self = shift; - foreach my $vhost ( keys %{ $self->{portalObject}->{locationRules} } ) { + foreach my $vhost ( keys %{ $self->{locationRules} } ) { my $i = 0; - foreach ( keys %{ $self->{portalObject}->{locationRules}->{$vhost} } ) { + foreach ( keys %{ $self->{locationRules}->{$vhost} } ) { if ( $_ eq 'default' ) { $defaultCondition->{$vhost} = $self->_conditionSub( - $self->{portalObject}->{locationRules}->{$vhost}->{$_} ); + $self->{locationRules}->{$vhost}->{$_} ); } else { $locationCondition->{$vhost}->[$i] = $self->_conditionSub( - $self->{portalObject}->{locationRules}->{$vhost}->{$_} ); + $self->{locationRules}->{$vhost}->{$_} ); $locationRegexp->{$vhost}->[$i] = qr/$_/; $i++; } @@ -524,7 +448,7 @@ sub _compileRules { # Default policy $defaultCondition->{$vhost} ||= $self->_conditionSub('accept'); } - $cfgNum = $self->{portalObject}->{cfgNum}; + $cfgNum = $self->{cfgNum}; 1; } @@ -539,12 +463,12 @@ sub _conditionSub { return sub { 0 } if ( $cond =~ /^(?:deny$|logout)/i ); $cond =~ s/\$date/&POSIX::strftime("%Y%m%d%H%M%S",localtime())/e; - $cond =~ s/\$(\w+)/\$self->{portalObject}->{sessionInfo}->{$1}/g; + $cond =~ s/\$(\w+)/\$self->{sessionInfo}->{$1}/g; my $sub = "sub {my \$self = shift; return ( $cond )}"; $sub = ( SAFEWRAP - ? $self->_safe->wrap_code_ref( $self->_safe->reval($sub) ) - : $self->_safe->reval($sub) + ? $self->safe->wrap_code_ref( $self->safe->reval($sub) ) + : $self->safe->reval($sub) ); return $sub; } @@ -557,45 +481,23 @@ __END__ =encoding utf8 -Lemonldap::NG::Portal::Menu - Enhanced menu to display to authenticated users +Lemonldap::NG::Portal::Menu - Portal menu functions =head1 SYNOPSIS - use Lemonldap::NG::Portal::Menu; - my $menu = Lemonldap::NG::Portal::Menu->new( + use Lemonldap::NG::Portal::Simple; + my $portal = Lemonldap::NG::Portal::Simple->new( { - portalObject => $portal, - apps => { - xmlfile => "/var/lib/lemonldap-ng/conf/apps-list.xml", - imgpath => "apps/", - }, - modules => { - appslist => 1, - password => 1, - logout => 1, - }, } ); - # Print HTML code of authorized applications list - print $menu->appslistMenu; + # Init portal menu + $portal->menuInit(); + =head1 DESCRIPTION -Lemonldap::NG::Portal::Menu provides these web modules: - -=over - -=item * Application list: display a full menu with all authorized applications - -=item * Password: allow the user to change its password (with LDAP auth only) - -=item * Logout: display a simple logout confirmation page - -=back - -These web modules are designed to be used in HTML::Template, with the help of -Jquery scripts. Without that, this will only output raw HTML code. +Lemonldap::NG::Portal::Menu is used to build menu. =head1 SEE ALSO diff --git a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Simple.pm b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Simple.pm index 4c7c98db8..1897d88c6 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Simple.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Simple.pm @@ -362,6 +362,9 @@ sub new { . ')'; } + # Load Menu functions + $self->loadModule('Lemonldap::NG::Portal::Menu'); + return $self; } @@ -644,9 +647,10 @@ _RETURN $string Error string =cut -##@method string error(string lang) +##@method string error(string lang, int code) # error calls Portal/_i18n.pm to display error in the wanted language. #@param $lang optional (browser language is used instead) +#@param $code optional error code #@return error message sub error { my $self = shift; @@ -1904,7 +1908,7 @@ sub issuerForAuthUser { sub autoRedirect { my $self = shift; - # default redirection URL + # Default redirection URL $self->{urldc} ||= $self->{portal} if ( $self->{mustRedirect} or $self->info() ); diff --git a/modules/lemonldap-ng-portal/t/50-Lemonldap-NG-Portal-Menu.t b/modules/lemonldap-ng-portal/t/50-Lemonldap-NG-Portal-Menu.t index ac6e6a2b2..e2b060221 100644 --- a/modules/lemonldap-ng-portal/t/50-Lemonldap-NG-Portal-Menu.t +++ b/modules/lemonldap-ng-portal/t/50-Lemonldap-NG-Portal-Menu.t @@ -5,7 +5,7 @@ # change 'tests => 1' to 'tests => last_test_to_print'; -use Test::More tests => 3; +use Test::More tests => 2; BEGIN { use_ok('Lemonldap::NG::Portal::Menu') } ######################### @@ -13,14 +13,19 @@ BEGIN { use_ok('Lemonldap::NG::Portal::Menu') } # Insert your test code below, the Test::More module is use()ed here so read # its man page ( perldoc Test::More ) for help writing this test script. -my $tmp; +$ENV{REQUEST_METHOD} = 'GET'; -my ( $m, $p ); +# Build portal +my $p = Lemonldap::NG::Portal::Simple->new({ + globalStorage => 'Apache::Session::File', + domain => 'example.com', + error => 0, + applicationList => {}, +}); -$p = bless { cookieName => 'lemonldap', }, 'Lemonldap::NG::Portal::SharedConf'; +# Init menu +$p->menuInit(); -ok( $m = Lemonldap::NG::Portal::Menu->new( { portalObject => $p } ), - 'constructor' ); - -ok( $m->isa('Lemonldap::NG::Portal::Menu'), 'object returned' ); +ok( ref $p->{menuDisplayModules} eq 'ARRAY' , + 'Modules displayed' );