Create a Common::Safe module, to be able to disable Safe jail with useSafeJail in Portal (#270)

This commit is contained in:
Clément Oudot 2011-02-07 10:27:36 +00:00
parent b7b2681967
commit 0865635a7b
8 changed files with 156 additions and 30 deletions

View File

@ -20,6 +20,7 @@ lib/Lemonldap/NG/Common/Conf/Serializer.pm
lib/Lemonldap/NG/Common/Conf/SOAP.pm
lib/Lemonldap/NG/Common/Crypto.pm
lib/Lemonldap/NG/Common/Regexp.pm
lib/Lemonldap/NG/Common/Safe.pm
lib/Lemonldap/NG/Common/Safelib.pm
Makefile.PL
MANIFEST This list of files

View File

@ -0,0 +1,82 @@
## @file
# LL::NG module for Safe jail
## @package
# LL::NG module for Safe jail
package Lemonldap::NG::Common::Safe;
use strict;
use base qw(Safe);
use constant SAFEWRAP => ( Safe->can("wrap_code_ref") ? 1 : 0 );
our $VERSION = 1.0.2;
our $self; # Safe cannot share a variable declared with my
## @constructor Lemonldap::NG::Common::Safe new(Lemonldap::NG::Portal::Simple portal)
# Build a new Safe object
# @param portal Lemonldap::NG::Portal::Simple object
# @return Lemonldap::NG::Common::Safe object
sub new {
my ( $class, $portal ) = splice @_;
my $self = {};
unless ( $portal->{useSafeJail} ) {
# Fake jail
$portal->lmLog( "Creating a fake Safe jail", 'debug' );
bless $self, $class;
}
else {
# Safe jail
$self = $class->SUPER::new();
$portal->lmLog( "Creating a real Safe jail", 'debug' );
}
# Store portal object
$self->{p} = $portal;
return $self;
}
## @method reval(string $e)
# Evaluate an expression, inside or outside jail
# @param e Expression to evaluate
sub reval {
local $self = shift;
my ($e) = splice @_;
my $result;
# Replace $date
$e =~ s/\$date/&POSIX::strftime("%Y%m%d%H%M%S",localtime())/e;
# Replace variables by session content
$e =~ s/\$(?!ENV)(\w+)/\$self->{p}->{sessionInfo}->{$1}/g;
$self->{p}->lmLog( "Evaluate expression: $e", 'debug' );
if ( $self->{p}->{useSafeJail} ) {
# Share $self to access sessionInfo HASH
$self->SUPER::share('$self');
# Test SAFEWRAP and run reval
$result = (
SAFEWRAP
? $self->SUPER::wrap_code_ref( $self->SUPER::reval($e) )
: $self->SUPER::reval($e)
);
}
else {
# Use a standard eval
$result = eval $e;
}
$self->{p}->lmLog( "Evaluation result: $result", 'debug' );
return $result;
}
1;

View File

@ -187,6 +187,7 @@ 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

View File

@ -11,7 +11,7 @@ use Lemonldap::NG::Portal::Simple;
use Lemonldap::NG::Portal::_LibAccess;
use base qw(Lemonldap::NG::Portal::_LibAccess);
our $VERSION = '1.0.0';
our $VERSION = '1.0.2';
our $catlevel = 0;
## @method void menuInit()
@ -84,7 +84,6 @@ sub displayModules {
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' );

View File

@ -17,10 +17,10 @@ use Lemonldap::NG::Common::CGI;
use CGI::Cookie;
require POSIX;
use Lemonldap::NG::Portal::_i18n; #inherits
use Lemonldap::NG::Common::Safelib; #link protected safe Safe object
use Lemonldap::NG::Common::Apache::Session
; #link protected session Apache::Session object
use Safe;
use Lemonldap::NG::Common::Safe; #link protected safe Safe object
use Lemonldap::NG::Common::Safelib;
use Digest::MD5;
# Special comments for doxygen
@ -188,9 +188,8 @@ our %EXPORT_TAGS = ( 'all' => [ @EXPORT, 'import' ], );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
# Secure jail
# Share secure jail between threads
our $safe;
our $self; # Safe cannot share a variable declared with my
BEGIN {
eval {
@ -581,6 +580,7 @@ sub setDefaultValues {
# Other
$self->{logoutServices} ||= {};
$self->{useSafeJail} = 1 unless defined $self->{useSafeJail};
}
@ -1091,7 +1091,10 @@ sub get_module {
sub safe {
my $self = shift;
return $safe if ($safe);
$safe = new Safe;
$safe = Lemonldap::NG::Common::Safe->new($self);
# Get custom functions
my @t =
$self->{customFunctions}
? split( /\s+/, $self->{customFunctions} )
@ -1110,10 +1113,17 @@ sub safe {
}";
$self->lmLog( $@, 'error' ) if ($@);
}
# Share %ENV
$safe->share_from( 'main', ['%ENV'] );
# Share Safelib
$safe->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
# Share custom functions and &encode_base64
$safe->share( '&encode_base64', @t );
return $safe;
}
@ -1736,15 +1746,13 @@ sub setSessionInfo {
PE_OK;
}
##@apmethod int setMacro()
##@apmethod int setMacros()
# Macro mechanism.
# * store macro results in $self->{sessionInfo}
#@return Lemonldap::NG::Portal constant
sub setMacros {
local $self = shift;
$self->safe->share('$self');
my $self = shift;
while ( my ( $n, $e ) = each( %{ $self->{macros} } ) ) {
$e =~ s/\$(?!ENV)(\w+)/\$self->{sessionInfo}->{$1}/g;
$self->{sessionInfo}->{$n} = $self->safe->reval($e);
}
PE_OK;
@ -1755,11 +1763,9 @@ sub setMacros {
# * store all groups name that the user match in $self->{sessionInfo}->{groups}
#@return Lemonldap::NG::Portal constant
sub setLocalGroups {
local $self = shift;
my $self = shift;
my $groups;
$self->safe->share('$self');
while ( my ( $group, $expr ) = each %{ $self->{groups} } ) {
$expr =~ s/\$(\w+)/\$self->{sessionInfo}->{$1}/g;
$groups .= $group . $self->{multiValuesSeparator}
if ( $self->safe->reval($expr) );
}
@ -1937,7 +1943,6 @@ sub grantSession {
# Eval grantSessionRule
my $grantSessionRule = $self->{grantSessionRule};
$grantSessionRule =~ s/\$(\w+)/\$self->{sessionInfo}->{$1}/g;
unless ( $self->safe->reval($grantSessionRule) ) {
$self->lmLog(
@ -2070,7 +2075,6 @@ sub issuerForAuthUser {
my $rule = $self->{ 'issuerDB' . $issuerDBtype . 'Rule' };
if ( defined $rule ) {
$rule =~ s/\$(\w+)/\$self->{sessionInfo}->{$1}/g;
$self->lmLog( "Applying rule: $rule", 'debug' );

View File

@ -6,9 +6,8 @@
package Lemonldap::NG::Portal::_LibAccess;
use strict;
use Lemonldap::NG::Common::Safelib; #link protected safe Safe object
use Safe;
use constant SAFEWRAP => ( Safe->can("wrap_code_ref") ? 1 : 0 );
our $VERSION = '1.0.2';
# Global variables
our ( $defaultCondition, $locationCondition, $locationRegexp, $cfgNum ) =
@ -94,15 +93,8 @@ sub _conditionSub {
if ( $cond =~ /^(?:accept|unprotect)$/i );
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->{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)
);
return $sub;
return $self->safe->reval($sub);
}
1;

View File

@ -9,11 +9,9 @@ use strict;
use Lemonldap::NG::Portal::Simple;
use Lemonldap::NG::Portal::_LibAccess;
require SOAP::Lite;
use Safe;
use constant SAFEWRAP => ( Safe->can("wrap_code_ref") ? 1 : 0 );
use base qw(Lemonldap::NG::Portal::_LibAccess);
our $VERSION = '1.0.0';
our $VERSION = '1.0.2';
## @method void startSoapServices()
# Check the URI requested (PATH_INFO environment variable) and launch the

View File

@ -0,0 +1,49 @@
# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl Lemonldap-NG-Portal.t'
#########################
# change 'tests => 1' to 'tests => last_test_to_print';
use Test::More tests => 8;
BEGIN { use_ok( 'Lemonldap::NG::Portal::Simple', ':all' ) }
#########################
# 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.
# Create portal object with Safe jail (the default)
my $p;
$ENV{REQUEST_METHOD} = "GET";
ok(
$p = Lemonldap::NG::Portal::Simple->new(
{
globalStorage => 'Apache::Session::File',
domain => 'example.com',
}
),
'Portal object'
);
# Fake data
my $sessionData = "coudot";
$p->{sessionInfo}->{uid} = $sessionData;
my $envData = "127.0.0.1";
$ENV{REMOTE_ADDR} = $envData;
# Real Safe jail
ok( $p->{useSafeJail} == 1, 'Safe jail on' );
ok( $p->safe->reval('$uid') eq $sessionData, 'Safe jail on - session data' );
ok( $p->safe->reval('$ENV{REMOTE_ADDR}') eq $envData, 'Safe jail on - env data' );
# Fake Safe jail
$p->{useSafeJail} = 0;
ok( $p->{useSafeJail} == 0, 'Safe jail off' );
ok( $p->safe->reval('$uid') eq $sessionData, 'Safe jail off - session data' );
ok( $p->safe->reval('$ENV{REMOTE_ADDR}') eq $envData, 'Safe jail off - env data' );