blob: f618624ec3195c0f512404cebd829ab9024f9ac4 [file] [log] [blame]
#!/usr/bin/perl -T
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
use 5.10.1;
use strict;
use warnings;
use lib qw(. lib);
use Net::LDAP;
use Bugzilla;
use Bugzilla::User;
my $cgi = Bugzilla->cgi;
my $dbh = Bugzilla->dbh;
my $readonly = 0;
my $nodisable = 0;
my $noupdate = 0;
my $nocreate = 0;
my $quiet = 0;
###
# Do some preparations
###
foreach my $arg (@ARGV)
{
if($arg eq '-r') {
$readonly = 1;
}
elsif($arg eq '-d') {
$nodisable = 1;
}
elsif($arg eq '-u') {
$noupdate = 1;
}
elsif($arg eq '-c') {
$nocreate = 1;
}
elsif($arg eq '-q') {
$quiet = 1;
}
else {
print "LDAP Sync Script\n";
print "Syncronizes the users table from the LDAP server with the Bugzilla users.\n";
print "Takes mail-attribute from preferences and description from 'cn' or,\n";
print "if not available, from the uid-attribute.\n\n";
print "usage:\n syncLDAP.pl [options]\n\n";
print "options:\n";
print " -r Readonly, do not make changes to Bugzilla tables\n";
print " -d No disable, don't disable login by users who are not in LDAP\n";
print " -u No update, don't update users, which have different description in LDAP\n";
print " -c No create, don't create users, which are in LDAP but not in Bugzilla\n";
print " -q Quiet mode, give less output\n";
print "\n";
exit;
}
}
my %ldap_users;
###
# Get current bugzilla users
###
my %bugzilla_users = %{ $dbh->selectall_hashref(
'SELECT login_name AS new_login_name, realname, disabledtext ' .
'FROM profiles', 'new_login_name') };
foreach my $login_name (keys %bugzilla_users) {
# remove whitespaces
$bugzilla_users{$login_name}{'realname'} =~ s/^\s+|\s+$//g;
}
###
# Get current LDAP users
###
my $LDAPserver = Bugzilla->params->{"LDAPserver"};
if ($LDAPserver eq "") {
print "No LDAP server defined in bugzilla preferences.\n";
exit;
}
my $LDAPconn;
if($LDAPserver =~ /:\/\//) {
# if the "LDAPserver" parameter is in uri scheme
$LDAPconn = Net::LDAP->new($LDAPserver, version => 3);
} else {
my $LDAPport = "389"; # default LDAP port
if($LDAPserver =~ /:/) {
($LDAPserver, $LDAPport) = split(":",$LDAPserver);
}
$LDAPconn = Net::LDAP->new($LDAPserver, port => $LDAPport, version => 3);
}
if(!$LDAPconn) {
print "Connecting to LDAP server failed. Check LDAPserver setting.\n";
exit;
}
my $mesg;
if (Bugzilla->params->{"LDAPbinddn"}) {
my ($LDAPbinddn,$LDAPbindpass) = split(":",Bugzilla->params->{"LDAPbinddn"});
$mesg = $LDAPconn->bind($LDAPbinddn, password => $LDAPbindpass);
}
else {
$mesg = $LDAPconn->bind();
}
if($mesg->code) {
print "Binding to LDAP server failed: " . $mesg->error . "\nCheck LDAPbinddn setting.\n";
exit;
}
# We've got our anonymous bind; let's look up the users.
$mesg = $LDAPconn->search( base => Bugzilla->params->{"LDAPBaseDN"},
scope => "sub",
filter => '(&(' . Bugzilla->params->{"LDAPuidattribute"} . "=*)" . Bugzilla->params->{"LDAPfilter"} . ')',
);
if(! $mesg->count) {
print "LDAP lookup failure. Check LDAPBaseDN setting.\n";
exit;
}
my %val = %{ $mesg->as_struct };
while( my ($key, $value) = each(%val) ) {
my @login_name = @{ $value->{Bugzilla->params->{"LDAPmailattribute"}} };
my @realname = @{ $value->{"cn"} };
# no mail entered? go to next
if(! @login_name) {
print "$key has no valid mail address\n";
next;
}
# no cn entered? use uid instead
if(! @realname) {
@realname = @{ $value->{Bugzilla->params->{"LDAPuidattribute"}} };
}
my $login = shift @login_name;
my $real = shift @realname;
$ldap_users{$login} = { realname => $real };
}
print "\n" unless $quiet;
###
# Sort the users into disable/update/create-Lists and display everything
###
my %disable_users;
my %update_users;
my %create_users;
print "Bugzilla-Users: \n" unless $quiet;
while( my ($key, $value) = each(%bugzilla_users) ) {
print " " . $key . " '" . $value->{'realname'} . "' " . $value->{'disabledtext'} ."\n" unless $quiet==1;
if(!exists $ldap_users{$key}){
if($value->{'disabledtext'} eq '') {
$disable_users{$key} = $value;
}
}
}
print "\nLDAP-Users: \n" unless $quiet;
while( my ($key, $value) = each(%ldap_users) ) {
print " " . $key . " '" . $value->{'realname'} . "'\n" unless $quiet==1;
if(!defined $bugzilla_users{$key}){
$create_users{$key} = $value;
}
else {
my $bugzilla_user_value = $bugzilla_users{$key};
if($bugzilla_user_value->{'realname'} ne $value->{'realname'}) {
$update_users{$key} = $value;
}
}
}
print "\nDetecting email changes: \n" unless $quiet;
while( my ($create_key, $create_value) = each(%create_users) ) {
while( my ($disable_key, $disable_value) = each(%disable_users) ) {
if($create_value->{'realname'} eq $disable_value->{'realname'}) {
print " " . $disable_key . " => " . $create_key ."'\n" unless $quiet==1;
$update_users{$disable_key} = { realname => $create_value->{'realname'},
new_login_name => $create_key };
delete $create_users{$create_key};
delete $disable_users{$disable_key};
}
}
}
if($quiet == 0) {
print "\nUsers to disable login for: \n";
while( my ($key, $value) = each(%disable_users) ) {
print " " . $key . " '" . $value->{'realname'} . "'\n";
}
print "\nUsers to update: \n";
while( my ($key, $value) = each(%update_users) ) {
print " " . $key . " '" . $value->{'realname'} . "' ";
if(defined $value->{'new_login_name'}) {
print "has changed email to " . $value->{'new_login_name'};
}
print "\n";
}
print "\nUsers to create: \n";
while( my ($key, $value) = each(%create_users) ) {
print " " . $key . " '" . $value->{'realname'} . "'\n";
}
print "\n\n";
}
###
# now do the DB-Update
###
if($readonly == 0) {
print "Performing DB update:\nPhase 1: disabling login for users not in LDAP... " unless $quiet;
my $sth_disable = $dbh->prepare(
'UPDATE profiles
SET disabledtext = ?
WHERE ' . $dbh->sql_istrcmp('login_name', '?'));
if($nodisable == 0) {
while( my ($key, $value) = each(%disable_users) ) {
$sth_disable->execute('auto-disabled by ldap sync', $key);
}
print "done!\n" unless $quiet;
}
else {
print "disabled!\n" unless $quiet;
}
print "Phase 2: updating existing users... " unless $quiet;
if($noupdate == 0) {
while( my ($key, $value) = each(%update_users) ) {
my $user = Bugzilla::User->check($key);
if(defined $value->{'new_login_name'}) {
$user->set_login($value->{'new_login_name'});
} else {
$user->set_name($value->{'realname'});
}
$user->update();
}
print "done!\n" unless $quiet;
}
else {
print "disabled!\n" unless $quiet;
}
print "Phase 3: creating new users... " unless $quiet;
if($nocreate == 0) {
while( my ($key, $value) = each(%create_users) ) {
Bugzilla::User->create({
login_name => $key,
realname => $value->{'realname'},
cryptpassword => '*'});
}
print "done!\n" unless $quiet;
}
else {
print "disabled!\n" unless $quiet;
}
}
else
{
print "No changes to DB because readonly mode\n" unless $quiet;
}