· 9 years ago · Aug 13, 2017, 01:06 AM
1#!/usr/bin/perl
2
3 # Name: rt_logins_email2ldap
4 # Description:
5 # This script checks the users logins in a LDAP or AD directory and
6 # rename the RT email logins with these logins.
7 #
8 # It does also some clean-up in the RT User database.
9 #
10 # It might be useful for you if:
11 # - you use LDAP/AD authentication on RT
12 # - it was setup before the automatic user creation with LDAP/AD
13 # logins
14 #
15 # Run rt_logins_email2ldap -h for additionnal information
16 #
17 # Author: Christophe Sahut <christophe.sahut {at} sgs {dot} com>
18 # License: This module is free software; you can redistribute it
19 # and/or modify it under the GPLv2 licence.
20 #
21 # Version 0.01: 21 Jan 2010 : initial release
22 #
23
24 use strict;
25 use Getopt::Std;
26 use Net::LDAP;
27 use lib qw(/opt/rt/lib);
28 use RT;
29 use RT::Queues;
30 use RT::User;
31 RT::LoadConfig();
32 RT::Init();
33
34 my $VERSION = '0.01';
35
36 my ($ldapserver,$ldapuser,$ldappass,$ldapbase,$ldapfilter,$ldapnet_ldap_args,$ldapattr_map_name,@myexceptions,$domain);
37
38 # CONFIGURATION
39 ###############################################################################
40 # > General
41 ###############################################################################
42 # Local account to ignore (root,Nobody,RT_System are ignored by default):
43 #@myexceptions = qw(local1 local2 local3);
44
45 # The domain used for your email addresses
46 $domain = '@foobar.com';
47
48 ###############################################################################
49 # > LDAP :
50 # This configuration is not necessary if you already use RT-Authen-ExternalAuth
51 ###############################################################################
52 #$ldapserver = 'server';
53 #$ldapuser = 'cn=user,ou=foo,dc=bar' ;
54 #$ldappass = 'pass' ;
55 #$ldapbase = 'base' ;
56 #$ldapfilter = '(objectClass=organizationalPerson)(!(sAMAccountName=adm*))';
57 #$ldapnet_ldap_args = '[port=>"3268", version=>"3"]';
58 #$ldapattr_map_name = 'sAMAccountName';
59 ###############################################################################
60
61 # sub usage {{{
62 sub usage()
63 {
64 print STDERR << "EOF";
65
66 rt_logins_email2ldap Version ${VERSION}
67
68 This program cleans up RT User DB and can rename email accounts to LDAP/AD logins.
69 You can run it without arguments, it'll show you the potential problems you might
70 have to resolve before running this script on your RT DB.
71
72 usage: $0 [-hawv] [-f file]
73
74 -v : verbose mode, displays what would be done if -w is used
75 -a : Run on all the users (default runs for privileged users only)
76 -w : WRITE the changes to the db
77 -f file : write old/new usernames to file, to be used as an input of
78 send_login_modif_notification.pl
79 -h : this (help) message
80
81 Recommended usage:
82
83 * Run these commands:
84
85 rt_logins_email2ldap # Check the potential problems and fix them. Such as:
86 - duplicate logins in the directory for the same email
87 - user with LDAP login already existing in RT
88
89 rt_logins_email2ldap -v # Check what would be done
90
91 To check the real changes:
92 rt_logins_email2ldap -v | grep -v "LoginOK\\|External\\|Local"
93
94 * Add to \@myexceptions variable the local privileged accounts you don't want to rename.
95
96 * Run again the two previous commands
97 * Backup your user table (something like "create table users_backup as select * from users;" )
98
99 rt_logins_email2ldap -v -f privileged.txt -w # Rename the privileged accounts, write the
100 output into privileged.txt
101
102 rt_logins_email2ldap -v # Check what would be done
103
104 To check the real changes:
105 rt_logins_email2ldap -v | grep -v "LoginOK\\|External\\|Local"
106
107 Do the same with -a option to run the script on all the users
108
109 rt_logins_email2ldap -v -a -f all.txt -w # Rename all the accounts, write the
110 output into all.txt
111
112 rt_logins_email2ldap -v -a # Check what has been done
113
114 If an unprivileged user with something\@domain.com email address exists, and another privileged user
115 with the same email address, we assume that the privileged user should have the LDAP login.
116 That's why the script is run first on privileged users, and then on all the users.
117
118
119EOF
120 exit;
121 }
122 # }}}
123
124 # sub return_ldap_login {{{
125 # This function takes an email as argument and returns the ldap login
126 sub return_ldap_login
127 {
128 my $email = shift(@_) ;
129 my $return = 0;
130 my ($entry,$ldaplogin);
131 my $ldap = Net::LDAP->new($ldapserver,@$ldapnet_ldap_args) or die "$@";
132 my $mesg = $ldap->bind($ldapuser, password => $ldappass );
133
134 my $result = $ldap->search ( base => $ldapbase,
135 filter => "(&$ldapfilter(mail=$email))",
136 attrs => "['$ldapattr_map_name']"
137 );
138
139 my @entries = $result->entries;
140
141 # Many times the same email for different sAMAccountNames
142 $return = 1 if (@entries > 1);
143
144 foreach $entry (@entries) {
145 $ldaplogin .= $entry->get_value($ldapattr_map_name).",";
146 }
147 $ldaplogin =~ s/,$//;
148
149 return ($return,$ldaplogin);
150 }
151 # }}}
152
153 # Main {{{
154 # Get configuration from RT Config
155 # Only managing first source for now
156 my $service = @$RT::ExternalAuthPriority[0];
157 my $config = $RT::ExternalSettings->{$service};
158 $ldapserver = $config->{'server'} unless $ldapserver;
159 $ldapuser = $config->{'user'} unless $ldapuser;
160 $ldappass = $config->{'pass'} unless $ldappass;
161 $ldapbase = $config->{'base'} unless $ldapbase;
162 $ldapfilter = $config->{'filter'} unless $ldapfilter;
163 $ldapnet_ldap_args = $config->{'net_ldap_args'} unless $ldapnet_ldap_args;
164 $ldapattr_map_name = $config->{'attr_map'}->{'Name'} unless $ldapattr_map_name;
165
166 my @exceptions = (qw(root Nobody RT_System), @myexceptions);
167
168 # Options
169 my %options = ();
170 getopts("vawhf:",\%options) or usage();
171 my $write=$options{w}?1:0;
172 my $verbose=$options{v}?1:0;
173 usage() if $options{h};
174
175 my ($return,$message,$emailnotificationlist);
176 my $users = RT::Users->new(RT->SystemUser);
177
178 open(FILE,"> ".$options{f}) if $options{f};
179 if ($options{a}){
180 $users->UnLimit();
181 }
182 else {
183 $users->LimitToPrivileged();
184 }
185
186 while ( my $user = $users->Next ) {
187
188 # LOCAL ACCOUNTS (exceptions): skipping to the next entry
189 if ( grep {$_ eq $user->Name} @exceptions) {
190 print "[Local] [".$user->Name." -> don't touch: local account / exception] Email:".$user->EmailAddress."\n" if($verbose);
191 next;
192 }
193
194
195 # One of our domain email addresses
196 if ($user->EmailAddress =~ m/$domain/i ){
197
198 my $cleanedemail = $user->EmailAddress;
199
200 # Protection of @ sign
201 $cleanedemail =~ s/@/\\@/;
202 # Keep only first email if account contains several emails
203 $cleanedemail =~ s/([^,]*),.*/$1/;
204 # Remove spaces
205 $cleanedemail =~ s/\ //g;
206
207 # Get LDAP/AD login
208 my ($return,$exist) = return_ldap_login("$cleanedemail");
209
210 # Remove the protection on @ sign
211 $cleanedemail =~ s/\\//g;
212
213 if ( $return == 1 ){
214 print STDERR "[DUPLICATES] [".$user->Name." -> ".$exist." ??? Check your ldap filter, at least 2 accounts with the same ".$user->EmailAddress." email were found in your directory.\n";
215 next;
216 }
217
218 # One of our addresses but no entry in LDAP : disabling account because probably wrong
219 # It's renamed because if the RT login is already a valid AD login, it'll cause trouble for other valid emails/logins
220 if ( $exist eq "" ) {
221 print "[DisableRename] [".$user->Name." -> disabled + renamed -disablednotinDirectory] Email:".$user->EmailAddress."\n" if($verbose);
222 if ($write) {
223 ($return,$message)=$user->SetName($user->Name."-disablednotindirectory");
224 print "--> Setting name ".$message."\n";
225 ($return,$message)=$user->SetDisabled(1);
226 print "---> Disabling user: ".$message."\n";
227 }
228 }
229 elsif (lc($exist) eq lc($user->Name)){
230 # Login already LDAP/AD login, doing nothing
231 print "[LoginOK] [".$user->Name." -> already LDAP login] Email:".$user->EmailAddress."\n" if($verbose);
232 }
233 else {
234 # One of our email addresses and not the good LDAP login but a good LDAP entry exists for this email address in the directory
235 # Check if LDAP login already used in RT
236 my $tempuser = RT::User->new(RT->SystemUser);
237 $tempuser->Load($exist);
238 if ( $tempuser->Id ) {
239 # It's already used !
240 # Keep privileged user, rename and disable this one: in the furture, merge these entries ?
241 if($tempuser->Privileged and ! $user->Privileged) {
242 print "[Disable] [".$user->Name." -> disabled ] Keeping ".$tempuser->Name." with Id ".$tempuser->Id." Email:".$user->EmailAddress."\n" if($verbose);
243 if ($write) {
244 $exist .= "-disablednotprivileged";
245 ($return,$message)=$user->SetName($exist);
246 print "--> Setting name ".$message."\n";
247 ($return,$message)=$user->SetDisabled(1);
248 print "---> Disabling user: ".$message."\n";
249 }
250
251
252 }
253 else {
254 # LDAP login used: to be managed manually.
255 # Login to RT, cehck the two accounts, rename login of one of them and disable it
256 print "[LOGIN USED] [".$user->Name.": LDAP login \"".$exist."\" already used by user with id ".$user->Id.". You should check manually which one you want to keep...]\n";
257 }
258 }
259 else {
260 # LDAP login not used yet: rename to LDAP login
261 print "[Rename] [".$user->Name." -> ". $exist ."] Email:".$user->EmailAddress."\n" if($verbose);
262 print FILE $user->Name.";".$exist.";".$cleanedemail."\n" if $options{f};
263
264 if ($write) {
265 ($return,$message)=$user->SetName($exist);
266 print "--> Setting name ".$message."\n";
267 }
268 $emailnotificationlist .= $cleanedemail.";";
269 }
270 }
271 }
272 # Extenal email addresses and looks like an email address : keep it as it is, probably external users
273 elsif ($user->EmailAddress =~ m/.*\@.*\..*/) {
274 print "[External] [".$user->Name." -> Don't touch: external email] Email:".$user->EmailAddress."\n" if($verbose);
275 }
276 # Strange entry : doesn't look like an email
277 else {
278 print "[Disable] [".$user->Name." -> disabled] Email:".$user->EmailAddress."\n" if($verbose);
279 if ($write) {
280 ($return,$message)=$user->SetDisabled(1);
281 print "--> Disabling user: ".$message."\n";
282 }
283 }
284 }
285
286 print "\nPeople to notify: ".$emailnotificationlist."\n" if $options{f};
287 close(FILE)if $options{f};
288 #}}}