Merge pull request #5364 from ZiBiS/master

Password: LDAP PPolicy driver
pull/5468/head
Aleksander Machniak 8 years ago committed by GitHub
commit 7f4ab8c14a

@ -271,6 +271,34 @@ $config['password_ldap_samba_pwattr'] = '';
// Whenever the password is changed, the attribute will be updated if set
$config['password_ldap_samba_lchattr'] = '';
// LDAP PPolicy Driver options
// -----------------------------------
// LDAP Change password command - filename of the perl script
// Example: 'change_ldap_pass.pl'
$config['password_ldap_ppolicy_cmd'] = 'change_ldap_pass.pl';
// LDAP URI
// Example: 'ldap://ldap.example.com/ ldaps://ldap2.example.com:636/'
$config['password_ldap_ppolicy_uri'] = 'ldap://localhost/ ;
// LDAP base name (root directory)
// Exemple: 'dc=exemple,dc=com'
$config['password_ldap_ppolicy_basedn'] = 'dc=example,dc=com';
$config['password_ldap_ppolicy_searchDN'] = 'cn=someuser,dc=example,dc=com';
$config['password_ldap_ppolicy_searchPW'] = 'secret';
// LDAP search filter
// Example: '(uid=%login)'
// Example: '(&(objectClass=posixAccount)(uid=%login))'
$config['password_ldap_ppolicy_search_filter'] = '(uid=%login)';
// CA Certificate file if in URI is LDAPS connection
$config['password_ldap_ppolicy_cafile'] = '/etc/ssl/cacert.crt';
// DirectAdmin Driver options
// --------------------------

@ -0,0 +1,100 @@
<?php
/**
* ldap_ppolicy driver
*
* Driver that adds functionality to change the user password via
* the 'change_ldap_pass.pl' command respecting password policy (history) in LDAP.
*
*
* @version 1.0
* @author Zbigniew Szmyd <zbigniew.szmyd@linseco.pl>
*
*/
class rcube_ldap_ppolicy_password
{
public function save($currpass, $newpass)
{
$rcmail = rcmail::get_instance();
$this->debug = $rcmail->config->get('ldap_debug');
$cmd = $rcmail->config->get('password_ldap_ppolicy_cmd');
$uri = $rcmail->config->get('password_ldap_ppolicy_uri');
$baseDN = $rcmail->config->get('password_ldap_ppolicy_basedn');
$filter = $rcmail->config->get('password_ldap_ppolicy_search_filter');
$bindDN = $rcmail->config->get('password_ldap_ppolicy_searchDN');
$bindPW = $rcmail->config->get('password_ldap_ppolicy_searchPW');
$cafile = $rcmail->config->get('password_ldap_ppolicy_cafile');
$log_dir = $rcmail->config->get('log_dir');
if (empty($log_dir)) {
$log_dir = RCUBE_INSTALL_PATH . 'logs';
}
// try to open specific log file for writing
$logfile = $log_dir.'/password_ldap_ppolicy.err';
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("file", $logfile, "a") // stderr is a file to write to
);
$cmd = 'plugins/password/helpers/'. $cmd;
$this->_debug("parameters:\ncmd:$cmd\nuri:$uri\nbaseDN:$baseDN\nfilter:$filter");
$process = proc_open($cmd, $descriptorspec, $pipes);
if (is_resource($process)) {
// $pipes now looks like this:
// 0 => writeable handle connected to child stdin
// 1 => readable handle connected to child stdout
// Any error output will be appended to /tmp/error-output.txt
fwrite($pipes[0], $uri."\n");
fwrite($pipes[0], $baseDN."\n");
fwrite($pipes[0], $filter."\n");
fwrite($pipes[0], $bindDN."\n");
fwrite($pipes[0], $bindPW."\n");
fwrite($pipes[0], $_SESSION['username']."\n");
fwrite($pipes[0], $currpass."\n");
fwrite($pipes[0], $newpass."\n");
fwrite($pipes[0], $cafile);
fclose($pipes[0]);
$result = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$this->_debug('Result:'.$result);
switch ($result) {
case "OK":
return PASSWORD_SUCCESS;
case "Password is in history of old passwords":
return PASSWORD_IN_HISTORY;
case "Cannot connect to any server":
return PASSWORD_CONNECT_ERROR;
default:
rcube::raise_error(array(
'code' => 600,
'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => $result
), true, false);
}
return PASSWORD_ERROR;
}
}
private function _debug($str)
{
if ($this->debug) {
rcube::write_log('password_ldap_ppolicy', $str);
}
}
}

@ -0,0 +1,89 @@
#!/usr/bin/perl
=pod
Script to change the LDAP password using the set_password method
to proper setting the password policy attributes
author: Zbigniew Szmyd (zbigniew.szmyd@linseco.pl)
version 1.0 2016-02-22
=cut
use Net::LDAP;
use Net::LDAP::Extension::SetPassword;
use URI;
use utf8;
binmode(STDOUT, ':utf8');
my %PAR = ();
if (my $param = shift @ARGV){
print "Password change in LDAP\n\n";
print "Run script without any parameter and pass the following data:\n";
print "URI\nbaseDN\nFilter\nbindDN\nbindPW\nLogin\nuserPass\nnewPass\nCAfile\n";
exit;
}
foreach my $param ('uri','base','filter','binddn','bindpw','user','pass','new_pass','ca'){
$PAR{$param} = <>;
$PAR{$param} =~ s/\r|\n//g;
}
my @servers = split (/\s+/, $PAR{'uri'});
my $active_server = 0;
my $ldap;
while ((my $serwer = shift @servers) && !($active_server)){
my $ldap_uri = URI->new($serwer);
if ($ldap_uri->secure){
$ldap = Net::LDAP->new($ldap_uri->as_string,
version => 3,
verify => 'require',
sslversion => 'tlsv1',
cafile => $PAR{'ca'});
} else {
$ldap = Net::LDAP->new($ldap_uri->as_string, version => 3);
}
$active_server = 1 if ($ldap);
}
if ($active_server){
my $mesg = $ldap->bind( $PAR{'binddn'}, password => $PAR{'bindpw'} );
if ($mesg->code != 0){
print "Cannot login: ". $mesg->error;
} else {
# Wyszukanie usera wg filtra
$PAR{'filter'} =~ s/\%login/$PAR{'user'}/;
my @search_args = (base => $PAR{'base'},
scope => 'sub',
filter => $PAR{'filter'},
attrs => ['1.1'],
);
my $result = $ldap->search( @search_args );
if ($result->code){
print $result->error;
} else {
my $count = $result->count;
if ($count == 1){
my @users = $result->entries;
my $dn = $users[0]->dn();
$result = $ldap->bind($dn, password => $PAR{'pass'});
if ($result->code){
print $result->error;
} else {
$result = $ldap->set_password(
newpasswd => $PAR{'new_pass'},
);
if ($result->code){
print $result->error;
} else {
print "OK";
}
}
} else {
print "User not found in LDAP\n" if $count == 0;
print "Found $count users\n";
}
}
}
$ldap->unbind();
} else {
print "Cannot connect to any server";
}

@ -31,3 +31,4 @@ $messages['passwordweak'] = 'Password must include at least one number and one s
$messages['passwordforbidden'] = 'Password contains forbidden characters.';
$messages['firstloginchange'] = 'This is your first login. Please change your password.';
$messages['disablednotice'] = 'The system is currently under maintenance and password change is not possible at the moment. Everything should be back to normal soon. We apologise for any inconvenience.';
$messages['passwdinhistory'] = 'This password has already been used previously';

@ -35,3 +35,4 @@ $messages['passwordweak'] = 'Password must include at least one number and one p
$messages['passwordforbidden'] = 'Password contains forbidden characters.';
$messages['firstloginchange'] = 'This is your first login. Please change your password.';
$messages['disablednotice'] = 'The system is currently under maintenance and password change is not possible at the moment. Everything should be back to normal soon. We apologize for any inconvenience.';
$messages['passwinhistory'] = 'This password has already been used previously';

@ -31,3 +31,4 @@ $messages['passwordweak'] = 'Hasło musi zawierać co najmniej jedną cyfrę i z
$messages['passwordforbidden'] = 'Hasło zawiera niedozwolone znaki.';
$messages['firstloginchange'] = 'To jest twoje pierwsze logowanie. Proszę zmień hasło.';
$messages['disablednotice'] = 'System jest w trakcie konserwacji i zmiana hasła w tym momencie nie jest możliwa. Wszystko powinno wrócić do normy w niedługim czasie. Przepraszamy za wszelkie niedogodności';
$messages['passwdinhistory'] = 'To hasło było już użyte poprzednio.';

@ -25,6 +25,7 @@
define('PASSWORD_CRYPT_ERROR', 1);
define('PASSWORD_ERROR', 2);
define('PASSWORD_CONNECT_ERROR', 3);
define('PASSWORD_IN_HISTORY', 4);
define('PASSWORD_SUCCESS', 0);
/**
@ -333,6 +334,9 @@ class password extends rcube_plugin
case PASSWORD_CONNECT_ERROR:
$reason = $this->gettext('connecterror');
break;
case PASSWORD_IN_HISTORY:
$reason = $this->gettext('passwdinhistory');
break;
case PASSWORD_ERROR:
default:
$reason = $this->gettext('internalerror');

Loading…
Cancel
Save