syncLDAP.pl 7.91 KB
Newer Older
1
#!/usr/bin/perl -wT
2 3 4
# 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/.
5
#
6 7
# This Source Code Form is "Incompatible With Secondary Licenses", as
# defined by the Mozilla Public License, v. 2.0.
8 9 10

use strict;

11
use lib qw(. lib);
12 13

use Net::LDAP;
14 15
use Bugzilla;
use Bugzilla::User;
16 17

my $cgi = Bugzilla->cgi;
18
my $dbh = Bugzilla->dbh;
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

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";
54
         print " -d No disable, don't disable login by users who are not in LDAP\n";
55 56 57 58 59 60 61 62 63 64 65 66 67
         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
###
68
my %bugzilla_users = %{ $dbh->selectall_hashref(
69
    'SELECT login_name AS new_login_name, realname, disabledtext ' .
70
    'FROM profiles', 'new_login_name') };
71

72
foreach my $login_name (keys %bugzilla_users) {
73
    # remove whitespaces
74
    $bugzilla_users{$login_name}{'realname'} =~ s/^\s+|\s+$//g;
75 76 77 78 79
}

###
# Get current LDAP users
###
80
my $LDAPserver = Bugzilla->params->{"LDAPserver"};
81 82 83 84
if ($LDAPserver eq "") {
   print "No LDAP server defined in bugzilla preferences.\n";
   exit;
}
85 86

my $LDAPconn;
87
if($LDAPserver =~ /:\/\//) {
88 89 90 91 92 93 94 95
    # 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);
96 97 98 99 100 101 102
}

if(!$LDAPconn) {
   print "Connecting to LDAP server failed. Check LDAPserver setting.\n";
   exit;
}
my $mesg;
103 104
if (Bugzilla->params->{"LDAPbinddn"}) {
    my ($LDAPbinddn,$LDAPbindpass) = split(":",Bugzilla->params->{"LDAPbinddn"});
105 106 107 108 109 110 111 112 113 114 115
    $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.
116
$mesg = $LDAPconn->search( base   => Bugzilla->params->{"LDAPBaseDN"},
117
                           scope  => "sub",
118
                           filter => '(&(' . Bugzilla->params->{"LDAPuidattribute"} . "=*)" . Bugzilla->params->{"LDAPfilter"} . ')',
119 120 121 122 123 124 125 126
                         );
                         

if(! $mesg->count) {
   print "LDAP lookup failure. Check LDAPBaseDN setting.\n";
   exit;
}
   
127
my %val = %{ $mesg->as_struct };
128

129
while( my ($key, $value) = each(%val) ) {
130

131 132
   my @login_name = @{ $value->{Bugzilla->params->{"LDAPmailattribute"}} };
   my @realname  = @{ $value->{"cn"} };
133 134

   # no mail entered? go to next
135
   if(! @login_name) { 
136 137 138 139 140
      print "$key has no valid mail address\n";
      next; 
   }

   # no cn entered? use uid instead
141 142
   if(! @realname) { 
       @realname = @{ $value->{Bugzilla->params->{"LDAPuidattribute"}} };
143 144
   }
  
145 146
   my $login = shift @login_name;
   my $real = shift @realname;
147 148 149 150 151 152 153 154 155 156 157 158 159
   $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;
160 161
while( my ($key, $value) = each(%bugzilla_users) ) {
  print " " . $key . " '" . $value->{'realname'} . "' " . $value->{'disabledtext'} ."\n" unless $quiet==1;
162
  if(!exists $ldap_users{$key}){
163
     if($value->{'disabledtext'} eq '') {
164 165 166 167 168 169 170
       $disable_users{$key} = $value;
     }
  }
}

print "\nLDAP-Users: \n" unless $quiet;
while( my ($key, $value) = each(%ldap_users) ) {
171 172
  print " " . $key . " '" . $value->{'realname'} . "'\n" unless $quiet==1;
  if(!defined $bugzilla_users{$key}){
173 174 175
    $create_users{$key} = $value;
  }
  else { 
176 177
    my $bugzilla_user_value = $bugzilla_users{$key};
    if($bugzilla_user_value->{'realname'} ne $value->{'realname'}) {
178 179 180 181 182 183 184 185
      $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) ) {
186
    if($create_value->{'realname'} eq $disable_value->{'realname'}) {
187
       print " " . $disable_key . " => " . $create_key ."'\n" unless $quiet==1;
188
       $update_users{$disable_key} = { realname => $create_value->{'realname'},
189 190 191 192 193 194 195 196
                                       new_login_name => $create_key };
       delete $create_users{$create_key};
       delete $disable_users{$disable_key};
    }
  }
}

if($quiet == 0) {
197
   print "\nUsers to disable login for: \n";
198
   while( my ($key, $value) = each(%disable_users) ) {
199
     print " " . $key . " '" . $value->{'realname'} . "'\n";
200 201 202 203
   }
   
   print "\nUsers to update: \n";
   while( my ($key, $value) = each(%update_users) ) {
204 205 206
     print " " . $key . " '" . $value->{'realname'} . "' ";
     if(defined $value->{'new_login_name'}) {
       print "has changed email to " . $value->{'new_login_name'};
207 208 209 210 211 212
     }
     print "\n";
   }
   
   print "\nUsers to create: \n";
   while( my ($key, $value) = each(%create_users) ) {
213
     print " " . $key . " '" . $value->{'realname'} . "'\n";
214 215 216 217 218 219 220 221 222 223
   }
   
   print "\n\n";
}


###
# now do the DB-Update
###
if($readonly == 0) {
224
   print "Performing DB update:\nPhase 1: disabling login for users not in LDAP... " unless $quiet;
225 226 227 228 229 230

   my $sth_disable = $dbh->prepare(
       'UPDATE profiles
           SET disabledtext = ?
         WHERE ' . $dbh->sql_istrcmp('login_name', '?'));

231 232
   if($nodisable == 0) {
      while( my ($key, $value) = each(%disable_users) ) {
233
        $sth_disable->execute('auto-disabled by ldap sync', $key);
234 235 236 237 238 239 240 241
      }
      print "done!\n" unless $quiet;
   }
   else {
      print "disabled!\n" unless $quiet;
   }
   
   print "Phase 2: updating existing users... " unless $quiet;
242 243 244 245 246 247 248 249 250 251

   my $sth_update_login = $dbh->prepare(
       'UPDATE profiles
           SET login_name = ? 
         WHERE ' . $dbh->sql_istrcmp('login_name', '?'));
   my $sth_update_realname = $dbh->prepare(
       'UPDATE profiles
           SET realname = ? 
         WHERE ' . $dbh->sql_istrcmp('login_name', '?'));

252 253
   if($noupdate == 0) {
      while( my ($key, $value) = each(%update_users) ) {
254 255
        if(defined $value->{'new_login_name'}) {
          $sth_update_login->execute($value->{'new_login_name'}, $key);
256
        } else {
257
          $sth_update_realname->execute($value->{'realname'}, $key);
258 259 260 261 262 263 264 265 266 267 268
        }
      }
      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) ) {
269 270
        Bugzilla::User->create({
            login_name => $key, 
271
            realname   => $value->{'realname'},
272
            cryptpassword   => '*'});
273 274 275 276 277 278 279 280 281 282 283
      }
      print "done!\n" unless $quiet;
   }
   else {
      print "disabled!\n" unless $quiet;
   }
}
else
{
   print "No changes to DB because readonly mode\n" unless $quiet;
}