* Debian upgrade for jquery management

* SQL injection protection for DBI
 * Regexp to control user field
 * Missing parameters in _Struct.pm
 * Bad errors management in Uploader
This commit is contained in:
Xavier Guimard 2009-12-19 08:57:59 +00:00
parent 29b8c86848
commit 4d47d92749
9 changed files with 139 additions and 89 deletions

View File

@ -75,7 +75,7 @@ install: build
find $(CURDIR)/debian/tmp -type f -regex '.*/jquery-[0-9].*\.js' -delete find $(CURDIR)/debian/tmp -type f -regex '.*/jquery-[0-9].*\.js' -delete
find $(CURDIR)/debian/tmp -type f -name jquery.js -delete find $(CURDIR)/debian/tmp -type f -name jquery.js -delete
rm -f $(CURDIR)/debian/tmp$(LMSHAREDIR)*-skins/*/jquery.js rm -f $(CURDIR)/debian/tmp$(LMSHAREDIR)*-skins/*/jquery.js
perl -i -pe 's#(["'"'"'])\S*?jquery(-\d[\.\w\-]*?)?.js#$$1/javascript/jquery/jquery.js#' \ perl -i -pe 's#src=(["'"'"']).*?jquery(-\d[\.\w\-]*?)?.js#src=$$1/javascript/jquery/jquery.js#i' \
$(CURDIR)/debian/tmp/examples/manager/*.pl \ $(CURDIR)/debian/tmp/examples/manager/*.pl \
$(CURDIR)/debian/tmp$(LMSHAREDIR)manager-skins/default/*.tpl \ $(CURDIR)/debian/tmp$(LMSHAREDIR)manager-skins/default/*.tpl \
$(CURDIR)/debian/tmp$(LMSHAREDIR)portal-skins/pastel/*.tpl $(CURDIR)/debian/tmp$(LMSHAREDIR)portal-skins/pastel/*.tpl

View File

@ -43,7 +43,7 @@ sub confUpload {
my $newConf = { cfgNum => $self->{cfgNum} }; my $newConf = { cfgNum => $self->{cfgNum} };
# Loading returned parameters # Loading returned parameters
my $res; my $errors = {};
foreach ( @{ $result->getChildrenByTagName('element') } ) { foreach ( @{ $result->getChildrenByTagName('element') } ) {
my ( $id, $name, $value ) = ( my ( $id, $name, $value ) = (
$_->getAttribute('id'), $_->getAttribute('id'),
@ -63,7 +63,7 @@ sub confUpload {
my ( $res, $m ); my ( $res, $m );
if ( !defined($test) ) { if ( !defined($test) ) {
$res->{errors}->{$name} = $errors->{errors}->{$name} =
"Key $name: Lemonldap::NG::Manager error, see Apache's logs"; "Key $name: Lemonldap::NG::Manager error, see Apache's logs";
$self->lmLog( $self->lmLog(
"Unknown configuration key $id (name: $name, value: $value)", "Unknown configuration key $id (name: $name, value: $value)",
@ -78,27 +78,27 @@ sub confUpload {
if ( $test->{keyTest} ) { if ( $test->{keyTest} ) {
( $res, $m ) = $self->applyTest( $test->{keyTest}, $name ); ( $res, $m ) = $self->applyTest( $test->{keyTest}, $name );
unless ($res) { unless ($res) {
$res->{errors}->{$name} = $m || $test->{keyMsgFail}; $errors->{errors}->{$name} = $m || $test->{keyMsgFail};
next; next;
} }
} }
if ( $test->{test} ) { if ( $test->{test} ) {
( $res, $m ) = $self->applyTest( $test->{test}, $value ); ( $res, $m ) = $self->applyTest( $test->{test}, $value );
unless ($res) { unless ($res) {
$res->{errors}->{$name} = $m || $test->{msgFail}; $errors->{errors}->{$name} = $m || $test->{msgFail};
next; next;
} }
} }
if ( $test->{warnKeyTest} ) { if ( $test->{warnKeyTest} ) {
( $res, $m ) = $self->applyTest( $test->{warnKeyTest}, $name ); ( $res, $m ) = $self->applyTest( $test->{warnKeyTest}, $name );
unless ($res) { unless ($res) {
$res->{warnings}->{$name} = $m || $test->{keyMsgWarn}; $errors->{warnings}->{$name} = $m || $test->{keyMsgWarn};
} }
} }
if ( $test->{warnTest} ) { if ( $test->{warnTest} ) {
( $res, $m ) = $self->applyTest( $test->{warnTest}, $value ); ( $res, $m ) = $self->applyTest( $test->{warnTest}, $value );
unless ($res) { unless ($res) {
$res->{warnings}->{$name} = $m || $test->{keyMsgWarn}; $errors->{warnings}->{$name} = $m || $test->{keyMsgWarn};
} }
} }
} }
@ -124,12 +124,13 @@ sub confUpload {
} }
} }
#print STDERR Dumper( $newConf, $res ); #print STDERR Dumper( $newConf, $errors );
$res->{result}->{cfgNum} = $self->confObj->saveConf($newConf) #print STDERR Dumper($errors);
unless ( $res->{errors} ); $errors->{result}->{cfgNum} = $self->confObj->saveConf($newConf)
unless ( $errors->{errors} );
my $buf = '{'; my $buf = '{';
my $i = 0; my $i = 0;
while ( my ( $type, $h ) = each %$res ) { while ( my ( $type, $h ) = each %$errors ) {
$buf .= ',' if ($i); $buf .= ',' if ($i);
$buf .= "'$type':{"; $buf .= "'$type':{";
$buf .= join( ',', map { "'$_':'$h->{$_}'" } keys %$h ); $buf .= join( ',', map { "'$_':'$h->{$_}'" } keys %$h );

View File

@ -52,13 +52,13 @@ sub struct {
_nodes => [ _nodes => [
qw(portal authentication userDB syslog whatToTrace singleSession singleIP singleUserByIP) qw(portal authentication userDB syslog whatToTrace singleSession singleIP singleUserByIP)
], ],
_help => 'authParams', _help => 'authParams',
authentication => 'text:/authentication', authentication => 'text:/authentication',
portal => 'text:/portal', portal => 'text:/portal',
userDB => 'text:/userDB', userDB => 'text:/userDB',
syslog => 'int:/syslog', syslog => 'int:/syslog',
useXForwardedForIP => 'int:/useXForwardedForIP', useXForwardedForIP => 'int:/useXForwardedForIP',
whatToTrace => 'text:/whatToTrace:whatToTrace:text', whatToTrace => 'text:/whatToTrace:whatToTrace:text',
singleSession => 'int:/singleSession', singleSession => 'int:/singleSession',
singleIP => 'int:/singleIP', singleIP => 'int:/singleIP',
singleUserByIP => 'int:/singleUserByIP', singleUserByIP => 'int:/singleUserByIP',
@ -66,7 +66,7 @@ sub struct {
cookieParams => { cookieParams => {
_nodes => _nodes =>
[qw(cookieName domain securedCookie cookieExpiration)], [qw(cookieName domain securedCookie cookieExpiration)],
_help => 'cookies', _help => 'cookies',
cookieName => 'text:/cookieName:cookieName:text', cookieName => 'text:/cookieName:cookieName:text',
domain => 'text:/domain:domain:text', domain => 'text:/domain:domain:text',
securedCookie => securedCookie =>
@ -104,19 +104,19 @@ sub struct {
}, },
advancedParams => { advancedParams => {
_nodes => [ _nodes => [
qw(Soap exportedAttr storePassword trustedDomains status https protection notifications passwordManagement) qw(Soap exportedAttr storePassword trustedDomains status https notifications passwordManagement userControl)
], ],
Soap => 'int:/Soap', Soap => 'int:/Soap',
https => 'int:/https', https => 'int:/https',
exportedAttr => 'text:/exportedAttr', exportedAttr => 'text:/exportedAttr',
storePassword => 'int:/storePassword', storePassword => 'int:/storePassword',
notifications => { notifications => {
_nodes => [ _nodes => [
qw(notification notificationStorage notificationStorageOptions) qw(notification notificationStorage notificationStorageOptions)
], ],
_help => 'notifications', _help => 'notifications',
notification => 'int:/notification', notification => 'int:/notification',
notificationStorage => 'text:/notificationStorage', notificationStorage => 'text:/notificationStorage',
notificationStorageOptions => { notificationStorageOptions => {
_nodes => ['hash:/notificationStorageOptions'], _nodes => ['hash:/notificationStorageOptions'],
_js => 'hashRoot' _js => 'hashRoot'
@ -135,13 +135,19 @@ sub struct {
}, },
trustedDomains => 'text:/trustedDomains', trustedDomains => 'text:/trustedDomains',
status => 'int:/status', status => 'int:/status',
protection => 'int:/protection', userControl => 'text:/userControl:userControl:text',
} }
}, },
groups => groups => {
{ _nodes => ['hash:/groups:groups:btext'], _js => 'hashRoot', _help => 'default', }, _nodes => ['hash:/groups:groups:btext'],
virtualHosts => _js => 'hashRoot',
{ _nodes => ['nhash:/locationRules:virtualHosts:none'], _upload => ['/exportedHeaders'], _help => 'default', }, _help => 'default',
},
virtualHosts => {
_nodes => ['nhash:/locationRules:virtualHosts:none'],
_upload => ['/exportedHeaders'],
_help => 'default',
},
}; };
} }
@ -158,8 +164,25 @@ sub testStruct {
return ( $@ ? ( 0, $@ ) : 1 ); return ( $@ ? ( 0, $@ ) : 1 );
}; };
my $boolean = { test => qr/^(?:0|1)?$/, msgFail => 'Value must be 0 or 1' }; my $boolean = { test => qr/^(?:0|1)?$/, msgFail => 'Value must be 0 or 1' };
my $pcre = sub {
my $r = shift;
my $q;
eval { $q = qr/$r/ };
return ( $@ ? ( 0, $@ ) : 1 );
};
my $testNotDefined = { test => sub { 1 }, msgFail => 'Ok' };
return { return {
authentication => { mailFrom => $testNotDefined,
trustedDomains => $testNotDefined,
exportedAttr => $testNotDefined,
mailSubject => $testNotDefined,
randomPasswordRegexp => $testNotDefined,
passwordDB => $testNotDefined,
mailBody => $testNotDefined,
SMTPServer => $testNotDefined,
cookieExpiration => $testNotDefined,
notificationStorage => $testNotDefined,
authentication => {
test => qr/^[a-zA-Z][\w\:]*$/, test => qr/^[a-zA-Z][\w\:]*$/,
msgFail => 'Bad module name', msgFail => 'Bad module name',
}, },
@ -175,7 +198,7 @@ sub testStruct {
test => qr/^https?:\/\/\S+$/, test => qr/^https?:\/\/\S+$/,
msgFail => 'Bad portal value', msgFail => 'Bad portal value',
}, },
cda => $boolean, cda => $boolean,
cookieName => { cookieName => {
test => qr/^[a-zA-Z]\w*$/, test => qr/^[a-zA-Z]\w*$/,
msgFail => 'Bad cookie name', msgFail => 'Bad cookie name',
@ -224,7 +247,7 @@ sub testStruct {
test => qr/^(?:\w+=.*,\w+=.*)?$/, test => qr/^(?:\w+=.*,\w+=.*)?$/,
msgFail => 'Bad LDAP dn', msgFail => 'Bad LDAP dn',
}, },
managerPassword => {}, managerPassword => {},
notificationStorage => { notificationStorage => {
test => qr/^[\w:]+$/, test => qr/^[\w:]+$/,
msgFail => 'Bad module name', msgFail => 'Bad module name',
@ -233,7 +256,7 @@ sub testStruct {
keyTest => qr/^\w+$/, keyTest => qr/^\w+$/,
keyMsgFail => 'Bad parameter', keyMsgFail => 'Bad parameter',
}, },
groups => { groups => {
keyTest => qr/^\w[\w-]*$/, keyTest => qr/^\w[\w-]*$/,
keyMsgFail => 'Bad group name', keyMsgFail => 'Bad group name',
test => $perlExpr, test => $perlExpr,
@ -263,13 +286,8 @@ sub testStruct {
keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/, keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/,
msgFail => 'Bad virtual host name', msgFail => 'Bad virtual host name',
'*' => { '*' => {
keyTest => sub { keyTest => $pcre,
my $r = shift; test => sub {
my $q;
eval { $q = qr/$r/ };
return ( $@ ? ( 0, $@ ) : 1 );
},
test => sub {
my $e = shift; my $e = shift;
return 1 if ( $e eq 'accept' or $e eq 'deny' ); return 1 if ( $e eq 'accept' or $e eq 'deny' );
if ( $e =~ s/^logout(?:_(?:app|sso|app_sso))?\s*// ) { if ( $e =~ s/^logout(?:_(?:app|sso|app_sso))?\s*// ) {
@ -291,9 +309,9 @@ sub testStruct {
}, },
}, },
exportedHeaders => { exportedHeaders => {
keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/, keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/,
msgFail => 'Bad virtual host name', keyMsgFail => 'Bad virtual host name',
'*' => { '*' => {
keyTest => qr/^\w([\w\-]*\w)?$/, keyTest => qr/^\w([\w\-]*\w)?$/,
keyMsgFail => 'Bad header name', keyMsgFail => 'Bad header name',
test => $perlExpr, test => $perlExpr,
@ -304,10 +322,10 @@ sub testStruct {
}, },
}, },
}, },
syslog => $boolean, syslog => $boolean,
Soap => $boolean, Soap => $boolean,
storePassword => $boolean, storePassword => $boolean,
notification => $boolean, notification => $boolean,
status => $boolean, status => $boolean,
https => $boolean, https => $boolean,
protection => { protection => {
@ -318,6 +336,10 @@ sub testStruct {
singleSession => $boolean, singleSession => $boolean,
singleIP => $boolean, singleIP => $boolean,
singleUserByIP => $boolean, singleUserByIP => $boolean,
userControl => {
test => $pcre,
msgFail => 'Bad regular expression',
},
}; };
} }
@ -325,15 +347,17 @@ sub testStruct {
#@return Hashref of default values #@return Hashref of default values
sub defaultConf { sub defaultConf {
return { return {
authentication => 'LDAP', authentication => 'LDAP',
userDB => 'LDAP', userDB => 'LDAP',
ldapServer => 'localhost', ldapServer => 'localhost',
globalStorage => 'Apache::Session::File', globalStorage => 'Apache::Session::File',
globalStorageOptions => { globalStorageOptions => {
'Directory' => '/var/lib/lemonldap-ng/sessions/', 'Directory' => '/var/lib/lemonldap-ng/sessions/',
'LockDirectory' => '/var/lib/lemonldap-ng/sessions/lock/' 'LockDirectory' => '/var/lib/lemonldap-ng/sessions/lock/'
}, },
timeout => 7200, timeout => 7200,
userControl => '^[\w\.\-@]+$',
notificationStorage => 'File',
}; };
} }

View File

@ -72,6 +72,7 @@ sub en {
sessionStorage => 'Sessions Storage', sessionStorage => 'Sessions Storage',
timeout => 'Sessions timeout', timeout => 'Sessions timeout',
userDB => 'Users database type', userDB => 'Users database type',
userControl => 'Username control',
virtualHosts => 'Virtual Hosts', virtualHosts => 'Virtual Hosts',
whatToTrace => "Attribute to use in Apache's logs", whatToTrace => "Attribute to use in Apache's logs",
}; };
@ -105,6 +106,7 @@ sub fr {
sessionStorage => 'Stockage des sessions', sessionStorage => 'Stockage des sessions',
timeout => 'Durée de vie des sessions', timeout => 'Durée de vie des sessions',
userDB => "Type de base de données d'utilisateurs", userDB => "Type de base de données d'utilisateurs",
userControl => "Contrôle du nom d'utilisateur",
virtualHosts => 'Hôtes virtuels', virtualHosts => 'Hôtes virtuels',
whatToTrace => "Donnée à inscrire dans les journaux d'Apache", whatToTrace => "Donnée à inscrire dans les journaux d'Apache",
}; };

View File

@ -47,7 +47,9 @@ sub authenticate {
my $loginCol = $self->{dbiAuthLoginCol}; my $loginCol = $self->{dbiAuthLoginCol};
my $passwordCol = $self->{dbiAuthPasswordCol}; my $passwordCol = $self->{dbiAuthPasswordCol};
my $user = $self->{user}; my $user = $self->{user};
my $password; my $password = $self->{password};
$user =~ s/'/''/g;
$password =~ s/'/''/g;
# Manage password hash # Manage password hash
if ( $self->{dbiAuthPasswordHash} =~ /^(md5|sha|sha1)$/i ) { if ( $self->{dbiAuthPasswordHash} =~ /^(md5|sha|sha1)$/i ) {
@ -55,24 +57,30 @@ sub authenticate {
"Using " . uc( $self->{dbiAuthPasswordHash} ) . " to hash password", "Using " . uc( $self->{dbiAuthPasswordHash} ) . " to hash password",
'debug' 'debug'
); );
$password = $password = uc( $self->{dbiAuthPasswordHash} ) . "('$password')";
uc( $self->{dbiAuthPasswordHash} ) . "('" . $self->{password} . "')";
} }
else { else {
$self->lmLog( "No valid password hash, using clear text for password", $self->lmLog( "No valid password hash, using clear text for password",
'debug' ); 'debug' );
$password = "'" . $self->{password} . "'"; $password = "'$password'";
} }
my $sth = $dbh->prepare( my @rows = ();
eval {
my $sth = $dbh->prepare(
"SELECT $loginCol FROM $table WHERE $loginCol='$user' AND $passwordCol=$password" "SELECT $loginCol FROM $table WHERE $loginCol='$user' AND $passwordCol=$password"
); );
$sth->execute(); $sth->execute();
my @rows = $sth->fetchrow_array(); @rows = $sth->fetchrow_array();
};
if ($@) {
$self->lmLog( "DBI error: $@", 'error' );
return PE_ERROR;
}
if ( $#rows eq 0 ) { if ( @rows == 1 ) {
$self->lmLog( "One row returned by SQL query", 'debug' ); $self->lmLog( "One row returned by SQL query", 'debug' );
return PE_OK; return PE_OK;
} }

View File

@ -78,6 +78,7 @@ use constant {
PE_BADURL => 37, PE_BADURL => 37,
PE_NOSCHEME => 38, PE_NOSCHEME => 38,
PE_BADOLDPASSWORD => 39, PE_BADOLDPASSWORD => 39,
PE_MALFORMEDUSER => 40,
}; };
# EXPORTER PARAMETERS # EXPORTER PARAMETERS
@ -91,7 +92,7 @@ our @EXPORT =
PE_PP_PASSWORD_TOO_SHORT PE_PP_PASSWORD_TOO_YOUNG PE_PP_PASSWORD_TOO_SHORT PE_PP_PASSWORD_TOO_YOUNG
PE_PP_PASSWORD_IN_HISTORY PE_PP_GRACE PE_PP_EXP_WARNING PE_PP_PASSWORD_IN_HISTORY PE_PP_GRACE PE_PP_EXP_WARNING
PE_PASSWORD_MISMATCH PE_PASSWORD_OK PE_NOTIFICATION PE_BADURL PE_PASSWORD_MISMATCH PE_PASSWORD_OK PE_NOTIFICATION PE_BADURL
PE_NOSCHEME PE_BADOLDPASSWORD); PE_NOSCHEME PE_BADOLDPASSWORD PE_MALFORMEDUSER);
our %EXPORT_TAGS = ( 'all' => [ @EXPORT, 'import' ], ); our %EXPORT_TAGS = ( 'all' => [ @EXPORT, 'import' ], );
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

View File

@ -30,6 +30,33 @@ sub userDBInit {
# Do nothing # Do nothing
# @return Lemonldap::NG::Portal constant # @return Lemonldap::NG::Portal constant
sub getUser { sub getUser {
my $self = shift;
# Connect
my $dbh =
$self->dbh( $self->{dbiUserChain}, $self->{dbiUserUser},
$self->{dbiUserPassword} );
return PE_ERROR unless $dbh;
my $table = $self->{dbiUserTable};
my $pivot = $self->{userPivot};
my $user = $self->{user};
$user =~ s/'/''/g;
eval {
my $sth = $dbh->prepare("SELECT * FROM $table WHERE $pivot='$user'");
$sth->execute();
unless ( $self->{entry} = $sth->fetchrow_hashref() ) {
$self->lmLog( "User $user not found", 'notice' );
return PE_BADCREDENTIALS;
}
};
if ($@) {
$self->lmLog( "DBI error: $@", 'error' );
return PE_ERROR;
}
PE_OK; PE_OK;
} }
@ -44,27 +71,9 @@ sub setSessionInfo {
unless ( $self->{exportedVars} unless ( $self->{exportedVars}
and ref( $self->{exportedVars} ) eq 'HASH' ); and ref( $self->{exportedVars} ) eq 'HASH' );
# Connect while ( my ( $var, $attr ) = each %{ $self->{exportedVars} } ) {
my $dbh = $self->{sessionInfo}->{$var} = $self->{entry}->{$attr}
$self->dbh( $self->{dbiUserChain}, $self->{dbiUserUser}, if ( defined $self->{entry}->{$attr} );
$self->{dbiUserPassword} );
return PE_ERROR unless $dbh;
my $table = $self->{dbiUserTable};
my $pivot = $self->{userPivot};
my $sth = $dbh->prepare(
"SELECT * FROM $table WHERE $pivot='" . $self->{user} . "'" );
$sth->execute();
my $result = $sth->fetchrow_hashref();
foreach ( keys %{ $self->{exportedVars} } ) {
if ( exists $result->{ $self->{exportedVars}->{$_} } ) {
$self->{sessionInfo}->{$_} =
$result->{ $self->{exportedVars}->{$_} };
}
} }
PE_OK; PE_OK;

View File

@ -27,15 +27,17 @@ sub extractFormInfo {
return PE_FORMEMPTY return PE_FORMEMPTY
unless ( unless (
( (
( $self->{'user'} = $self->param('user') ) ( $self->{user} = $self->param('user') )
&& ( ( $self->{'password'} = $self->param('password') ) && ( ( $self->{password} = $self->param('password') )
|| ( $self->{'newpassword'} = $self->param('newpassword') ) ) || ( $self->{newpassword} = $self->param('newpassword') ) )
) )
|| ( $self->{'mail'} = $self->param('mail') ) || ( $self->{mail} = $self->param('mail') )
); );
$self->{'oldpassword'} = $self->param('oldpassword'); $self->{oldpassword} = $self->param('oldpassword');
$self->{'confirmpassword'} = $self->param('confirmpassword'); $self->{confirmpassword} = $self->param('confirmpassword');
$self->{'timezone'} = $self->param('timezone'); $self->{timezone} = $self->param('timezone');
$self->{userControl} ||= '^[\w\.\-@]+$';
return PE_MALFORMEDUSER unless ( $self->{user} =~ /$self->{userControl}/o );
PE_OK; PE_OK;
} }

View File

@ -127,6 +127,7 @@ sub error_fr {
'Mauvaise URL', 'Mauvaise URL',
'Aucun schéma disponible', 'Aucun schéma disponible',
'Ancien mot de passe invalide', 'Ancien mot de passe invalide',
"Nom d'utilisateur incorrect",
]; ];
} }
@ -175,6 +176,7 @@ sub error_en {
'Bad URL', 'Bad URL',
'No scheme available', 'No scheme available',
'Bad old password', 'Bad old password',
'Bad username',
]; ];
} }
@ -224,5 +226,6 @@ sub error_ro {
'Rea URL', 'Rea URL',
'No scheme available', 'No scheme available',
'Bad old password', 'Bad old password',
'Bad username',
]; ];
} }