diff --git a/build/lemonldap-ng/debian/rules b/build/lemonldap-ng/debian/rules index 2048cd873..ffdad8e43 100755 --- a/build/lemonldap-ng/debian/rules +++ b/build/lemonldap-ng/debian/rules @@ -75,7 +75,7 @@ install: build find $(CURDIR)/debian/tmp -type f -regex '.*/jquery-[0-9].*\.js' -delete find $(CURDIR)/debian/tmp -type f -name jquery.js -delete 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$(LMSHAREDIR)manager-skins/default/*.tpl \ $(CURDIR)/debian/tmp$(LMSHAREDIR)portal-skins/pastel/*.tpl diff --git a/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Uploader.pm b/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Uploader.pm index 24db6a17a..9db98941b 100644 --- a/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Uploader.pm +++ b/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Uploader.pm @@ -43,7 +43,7 @@ sub confUpload { my $newConf = { cfgNum => $self->{cfgNum} }; # Loading returned parameters - my $res; + my $errors = {}; foreach ( @{ $result->getChildrenByTagName('element') } ) { my ( $id, $name, $value ) = ( $_->getAttribute('id'), @@ -63,7 +63,7 @@ sub confUpload { my ( $res, $m ); if ( !defined($test) ) { - $res->{errors}->{$name} = + $errors->{errors}->{$name} = "Key $name: Lemonldap::NG::Manager error, see Apache's logs"; $self->lmLog( "Unknown configuration key $id (name: $name, value: $value)", @@ -78,27 +78,27 @@ sub confUpload { if ( $test->{keyTest} ) { ( $res, $m ) = $self->applyTest( $test->{keyTest}, $name ); unless ($res) { - $res->{errors}->{$name} = $m || $test->{keyMsgFail}; + $errors->{errors}->{$name} = $m || $test->{keyMsgFail}; next; } } if ( $test->{test} ) { ( $res, $m ) = $self->applyTest( $test->{test}, $value ); unless ($res) { - $res->{errors}->{$name} = $m || $test->{msgFail}; + $errors->{errors}->{$name} = $m || $test->{msgFail}; next; } } if ( $test->{warnKeyTest} ) { ( $res, $m ) = $self->applyTest( $test->{warnKeyTest}, $name ); unless ($res) { - $res->{warnings}->{$name} = $m || $test->{keyMsgWarn}; + $errors->{warnings}->{$name} = $m || $test->{keyMsgWarn}; } } if ( $test->{warnTest} ) { ( $res, $m ) = $self->applyTest( $test->{warnTest}, $value ); 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 ); - $res->{result}->{cfgNum} = $self->confObj->saveConf($newConf) - unless ( $res->{errors} ); + #print STDERR Dumper( $newConf, $errors ); + #print STDERR Dumper($errors); + $errors->{result}->{cfgNum} = $self->confObj->saveConf($newConf) + unless ( $errors->{errors} ); my $buf = '{'; my $i = 0; - while ( my ( $type, $h ) = each %$res ) { + while ( my ( $type, $h ) = each %$errors ) { $buf .= ',' if ($i); $buf .= "'$type':{"; $buf .= join( ',', map { "'$_':'$h->{$_}'" } keys %$h ); diff --git a/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_Struct.pm b/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_Struct.pm index d3744e51e..fd7c40c4b 100644 --- a/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_Struct.pm +++ b/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_Struct.pm @@ -52,13 +52,13 @@ sub struct { _nodes => [ qw(portal authentication userDB syslog whatToTrace singleSession singleIP singleUserByIP) ], - _help => 'authParams', - authentication => 'text:/authentication', - portal => 'text:/portal', - userDB => 'text:/userDB', - syslog => 'int:/syslog', + _help => 'authParams', + authentication => 'text:/authentication', + portal => 'text:/portal', + userDB => 'text:/userDB', + syslog => 'int:/syslog', useXForwardedForIP => 'int:/useXForwardedForIP', - whatToTrace => 'text:/whatToTrace:whatToTrace:text', + whatToTrace => 'text:/whatToTrace:whatToTrace:text', singleSession => 'int:/singleSession', singleIP => 'int:/singleIP', singleUserByIP => 'int:/singleUserByIP', @@ -66,7 +66,7 @@ sub struct { cookieParams => { _nodes => [qw(cookieName domain securedCookie cookieExpiration)], - _help => 'cookies', + _help => 'cookies', cookieName => 'text:/cookieName:cookieName:text', domain => 'text:/domain:domain:text', securedCookie => @@ -104,19 +104,19 @@ sub struct { }, advancedParams => { _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', - exportedAttr => 'text:/exportedAttr', + exportedAttr => 'text:/exportedAttr', storePassword => 'int:/storePassword', notifications => { _nodes => [ qw(notification notificationStorage notificationStorageOptions) ], - _help => 'notifications', + _help => 'notifications', notification => 'int:/notification', - notificationStorage => 'text:/notificationStorage', + notificationStorage => 'text:/notificationStorage', notificationStorageOptions => { _nodes => ['hash:/notificationStorageOptions'], _js => 'hashRoot' @@ -135,13 +135,19 @@ sub struct { }, trustedDomains => 'text:/trustedDomains', status => 'int:/status', - protection => 'int:/protection', + userControl => 'text:/userControl:userControl:text', } }, - groups => - { _nodes => ['hash:/groups:groups:btext'], _js => 'hashRoot', _help => 'default', }, - virtualHosts => - { _nodes => ['nhash:/locationRules:virtualHosts:none'], _upload => ['/exportedHeaders'], _help => 'default', }, + groups => { + _nodes => ['hash:/groups:groups:btext'], + _js => 'hashRoot', + _help => 'default', + }, + virtualHosts => { + _nodes => ['nhash:/locationRules:virtualHosts:none'], + _upload => ['/exportedHeaders'], + _help => 'default', + }, }; } @@ -158,8 +164,25 @@ sub testStruct { return ( $@ ? ( 0, $@ ) : 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 { - 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\:]*$/, msgFail => 'Bad module name', }, @@ -175,7 +198,7 @@ sub testStruct { test => qr/^https?:\/\/\S+$/, msgFail => 'Bad portal value', }, - cda => $boolean, + cda => $boolean, cookieName => { test => qr/^[a-zA-Z]\w*$/, msgFail => 'Bad cookie name', @@ -224,7 +247,7 @@ sub testStruct { test => qr/^(?:\w+=.*,\w+=.*)?$/, msgFail => 'Bad LDAP dn', }, - managerPassword => {}, + managerPassword => {}, notificationStorage => { test => qr/^[\w:]+$/, msgFail => 'Bad module name', @@ -233,7 +256,7 @@ sub testStruct { keyTest => qr/^\w+$/, keyMsgFail => 'Bad parameter', }, - groups => { + groups => { keyTest => qr/^\w[\w-]*$/, keyMsgFail => 'Bad group name', test => $perlExpr, @@ -263,13 +286,8 @@ sub testStruct { keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/, msgFail => 'Bad virtual host name', '*' => { - keyTest => sub { - my $r = shift; - my $q; - eval { $q = qr/$r/ }; - return ( $@ ? ( 0, $@ ) : 1 ); - }, - test => sub { + keyTest => $pcre, + test => sub { my $e = shift; return 1 if ( $e eq 'accept' or $e eq 'deny' ); if ( $e =~ s/^logout(?:_(?:app|sso|app_sso))?\s*// ) { @@ -291,9 +309,9 @@ sub testStruct { }, }, exportedHeaders => { - keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/, - msgFail => 'Bad virtual host name', - '*' => { + keyTest => qr/^[a-zA-Z](?:[\w\-\.]*\w)?$/, + keyMsgFail => 'Bad virtual host name', + '*' => { keyTest => qr/^\w([\w\-]*\w)?$/, keyMsgFail => 'Bad header name', test => $perlExpr, @@ -304,10 +322,10 @@ sub testStruct { }, }, }, - syslog => $boolean, - Soap => $boolean, + syslog => $boolean, + Soap => $boolean, storePassword => $boolean, - notification => $boolean, + notification => $boolean, status => $boolean, https => $boolean, protection => { @@ -318,6 +336,10 @@ sub testStruct { singleSession => $boolean, singleIP => $boolean, singleUserByIP => $boolean, + userControl => { + test => $pcre, + msgFail => 'Bad regular expression', + }, }; } @@ -325,15 +347,17 @@ sub testStruct { #@return Hashref of default values sub defaultConf { return { - authentication => 'LDAP', - userDB => 'LDAP', - ldapServer => 'localhost', - globalStorage => 'Apache::Session::File', + authentication => 'LDAP', + userDB => 'LDAP', + ldapServer => 'localhost', + globalStorage => 'Apache::Session::File', globalStorageOptions => { - 'Directory' => '/var/lib/lemonldap-ng/sessions/', + 'Directory' => '/var/lib/lemonldap-ng/sessions/', 'LockDirectory' => '/var/lib/lemonldap-ng/sessions/lock/' }, - timeout => 7200, + timeout => 7200, + userControl => '^[\w\.\-@]+$', + notificationStorage => 'File', }; } diff --git a/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_i18n.pm b/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_i18n.pm index 4d4acd911..fb4c624a3 100644 --- a/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_i18n.pm +++ b/modules/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/_i18n.pm @@ -72,6 +72,7 @@ sub en { sessionStorage => 'Sessions Storage', timeout => 'Sessions timeout', userDB => 'Users database type', + userControl => 'Username control', virtualHosts => 'Virtual Hosts', whatToTrace => "Attribute to use in Apache's logs", }; @@ -105,6 +106,7 @@ sub fr { sessionStorage => 'Stockage des sessions', timeout => 'Durée de vie des sessions', userDB => "Type de base de données d'utilisateurs", + userControl => "Contrôle du nom d'utilisateur", virtualHosts => 'Hôtes virtuels', whatToTrace => "Donnée à inscrire dans les journaux d'Apache", }; diff --git a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthDBI.pm b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthDBI.pm index 321013e8a..0e7c16b6f 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthDBI.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/AuthDBI.pm @@ -47,7 +47,9 @@ sub authenticate { my $loginCol = $self->{dbiAuthLoginCol}; my $passwordCol = $self->{dbiAuthPasswordCol}; my $user = $self->{user}; - my $password; + my $password = $self->{password}; + $user =~ s/'/''/g; + $password =~ s/'/''/g; # Manage password hash if ( $self->{dbiAuthPasswordHash} =~ /^(md5|sha|sha1)$/i ) { @@ -55,24 +57,30 @@ sub authenticate { "Using " . uc( $self->{dbiAuthPasswordHash} ) . " to hash password", 'debug' ); - $password = - uc( $self->{dbiAuthPasswordHash} ) . "('" . $self->{password} . "')"; + $password = uc( $self->{dbiAuthPasswordHash} ) . "('$password')"; } else { $self->lmLog( "No valid password hash, using clear text for password", '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" - ); + ); - $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' ); return PE_OK; } 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 7c9874cbc..e17bb7b37 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Simple.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Simple.pm @@ -78,6 +78,7 @@ use constant { PE_BADURL => 37, PE_NOSCHEME => 38, PE_BADOLDPASSWORD => 39, + PE_MALFORMEDUSER => 40, }; # EXPORTER PARAMETERS @@ -91,7 +92,7 @@ our @EXPORT = PE_PP_PASSWORD_TOO_SHORT PE_PP_PASSWORD_TOO_YOUNG PE_PP_PASSWORD_IN_HISTORY PE_PP_GRACE PE_PP_EXP_WARNING 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_OK = ( @{ $EXPORT_TAGS{'all'} } ); diff --git a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDBDBI.pm b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDBDBI.pm index cfcebda18..244cdae7a 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDBDBI.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/UserDBDBI.pm @@ -30,6 +30,33 @@ sub userDBInit { # Do nothing # @return Lemonldap::NG::Portal constant 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; } @@ -44,27 +71,9 @@ sub setSessionInfo { unless ( $self->{exportedVars} and ref( $self->{exportedVars} ) eq 'HASH' ); - # 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 $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}->{$_} }; - } + while ( my ( $var, $attr ) = each %{ $self->{exportedVars} } ) { + $self->{sessionInfo}->{$var} = $self->{entry}->{$attr} + if ( defined $self->{entry}->{$attr} ); } PE_OK; diff --git a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_WebForm.pm b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_WebForm.pm index b984a594f..0740e9b60 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_WebForm.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_WebForm.pm @@ -27,15 +27,17 @@ sub extractFormInfo { return PE_FORMEMPTY unless ( ( - ( $self->{'user'} = $self->param('user') ) - && ( ( $self->{'password'} = $self->param('password') ) - || ( $self->{'newpassword'} = $self->param('newpassword') ) ) + ( $self->{user} = $self->param('user') ) + && ( ( $self->{password} = $self->param('password') ) + || ( $self->{newpassword} = $self->param('newpassword') ) ) ) - || ( $self->{'mail'} = $self->param('mail') ) + || ( $self->{mail} = $self->param('mail') ) ); - $self->{'oldpassword'} = $self->param('oldpassword'); - $self->{'confirmpassword'} = $self->param('confirmpassword'); - $self->{'timezone'} = $self->param('timezone'); + $self->{oldpassword} = $self->param('oldpassword'); + $self->{confirmpassword} = $self->param('confirmpassword'); + $self->{timezone} = $self->param('timezone'); + $self->{userControl} ||= '^[\w\.\-@]+$'; + return PE_MALFORMEDUSER unless ( $self->{user} =~ /$self->{userControl}/o ); PE_OK; } diff --git a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_i18n.pm b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_i18n.pm index 89a46f754..e92f47eef 100644 --- a/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_i18n.pm +++ b/modules/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/_i18n.pm @@ -127,6 +127,7 @@ sub error_fr { 'Mauvaise URL', 'Aucun schéma disponible', 'Ancien mot de passe invalide', + "Nom d'utilisateur incorrect", ]; } @@ -175,6 +176,7 @@ sub error_en { 'Bad URL', 'No scheme available', 'Bad old password', + 'Bad username', ]; } @@ -224,5 +226,6 @@ sub error_ro { 'Rea URL', 'No scheme available', 'Bad old password', + 'Bad username', ]; }