Rt logins email2ldap

From Request Tracker Wiki
Revision as of 04:16, 26 April 2011 by 122.116.27.2 (talk) (delete the space before the "EOF" word in rt_logins_email2ldap)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Introduction

  • First script : Rename email addresses to AD/LDAP usernames
  • Second script: Notify users their login changed

Rename email addresses to AD/LDAP usernames

rt_logins_email2ldap

#!/usr/bin/perl
    
    # Name: rt_logins_email2ldap
    # Description:
    # This script checks the users logins in a LDAP or AD directory and
    # rename the RT email logins with these logins.
    #
    # It does also some clean-up in the RT User database.
    #
    # It might be useful for you if:
    #  - you use LDAP/AD authentication on RT
    #  - it was setup before the automatic user creation with LDAP/AD
    #    logins
    #
    # Run rt_logins_email2ldap -h for additionnal information
    #
    # Author: Christophe Sahut <christophe.sahut {at} sgs {dot} com>
    # License: This module is free software; you can redistribute it
    # and/or modify it under the GPLv2 licence.
    #
    # Version 0.01: 21 Jan 2010 : initial release
    #
    
    use strict;
    use Getopt::Std;
    use Net::LDAP;
    use lib qw(/opt/rt/lib);
    use RT;
    use RT::Queues;
    use RT::User;
    RT::LoadConfig();
    RT::Init();
    
    my $VERSION = '0.01';
    
    my ($ldapserver,$ldapuser,$ldappass,$ldapbase,$ldapfilter,$ldapnet_ldap_args,$ldapattr_map_name,@myexceptions,$domain);
    
    # CONFIGURATION
    ###############################################################################
    # > General
    ###############################################################################
    # Local account to ignore (root,Nobody,RT_System are ignored by default):
    #@myexceptions = qw(local1 local2 local3);
    
    # The domain used for your email addresses
    $domain = '@foobar.com';
    
    ###############################################################################
    # > LDAP :
    # This configuration is not necessary if you already use RT-Authen-ExternalAuth
    ###############################################################################
    #$ldapserver        = 'server';
    #$ldapuser          = 'cn=user,ou=foo,dc=bar'  ;
    #$ldappass          = 'pass'  ;
    #$ldapbase          = 'base'  ;
    #$ldapfilter        = '(objectClass=organizationalPerson)(!(sAMAccountName=adm*))';
    #$ldapnet_ldap_args = '[port=>"3268", version=>"3"]';
    #$ldapattr_map_name = 'sAMAccountName';
    ###############################################################################
    
    # sub usage {{{
    sub usage()
    {
    	print STDERR << "EOF";
    
    rt_logins_email2ldap Version ${VERSION}
    
    This program cleans up RT User DB and can rename email accounts to LDAP/AD logins.
    You can run it without arguments, it'll show you the potential problems you might
    have to resolve before running this script on your RT DB.
    
    usage: $0 [-hawv] [-f file]
    
     -v        : verbose mode, displays what would be done if -w is used
     -a        : Run on all the users (default runs for privileged users only)
     -w        : WRITE the changes to the db
     -f file   : write old/new usernames to file, to be used as an input of
    	     send_login_modif_notification.pl
     -h        : this (help) message
    
    Recommended usage:
    
    * Run these commands:
    
    rt_logins_email2ldap  		# Check the potential problems and fix them. Such as:
    				  - duplicate logins in the directory for the same email
    				  - user with LDAP login already existing in RT
    
    rt_logins_email2ldap -v 	# Check what would be done
    
    To check the real changes:
    rt_logins_email2ldap -v | grep -v "LoginOK\\|External\\|Local"
    
    * Add to \@myexceptions variable the local privileged accounts you don't want to rename.
    
    * Run again the two previous commands
    * Backup your user table (something like "create table users_backup as select * from users;" )
    
    rt_logins_email2ldap -v -f privileged.txt -w	# Rename the privileged accounts, write the
    						  output into privileged.txt
    
    rt_logins_email2ldap -v 			# Check what would be done
    
    To check the real changes:
    rt_logins_email2ldap -v | grep -v "LoginOK\\|External\\|Local"
    
    Do the same with -a option to run the script on all the users
    
    rt_logins_email2ldap -v -a -f all.txt -w	# Rename all the accounts, write the
    						  output into all.txt
    
    rt_logins_email2ldap -v -a			# Check what has been done
    
     If an unprivileged user with something\@domain.com email address exists, and another privileged user
    with the same email address, we assume that the privileged user should have the LDAP login.
    That's why the script is run first on privileged users, and then on all the users.
    
    
  EOF
    	exit;
    }
    # }}}
    
    # sub return_ldap_login {{{
    # This function takes an email as argument and returns the ldap login
    sub return_ldap_login
    {
    	my $email = shift(@_) ;
    	my $return = 0;
    	my ($entry,$ldaplogin);
    	my $ldap = Net::LDAP->new($ldapserver,@$ldapnet_ldap_args) or die "$@";
    	my $mesg = $ldap->bind($ldapuser, password => $ldappass );
    
    	my $result = $ldap->search ( base    => $ldapbase,
    				     filter  => "(&$ldapfilter(mail=$email))",
    				     attrs   => "['$ldapattr_map_name']"
    				      );
    
    	my @entries = $result->entries;
    
    	# Many times the same email for different sAMAccountNames
    	$return = 1 if (@entries > 1);
    
    	foreach $entry (@entries) {
    		$ldaplogin .= $entry->get_value($ldapattr_map_name).",";
    	}
    	$ldaplogin =~ s/,$//;
    
    	return ($return,$ldaplogin);
    }
    # }}}
    
    # Main {{{
    # Get configuration from RT Config
    # Only managing first source for now
    my $service = @$RT::ExternalAuthPriority[0];
    my $config  = $RT::ExternalSettings->{$service};
    $ldapserver        = $config->{'server'} unless $ldapserver;
    $ldapuser          = $config->{'user'} unless $ldapuser;
    $ldappass          = $config->{'pass'} unless $ldappass;
    $ldapbase          = $config->{'base'} unless $ldapbase;
    $ldapfilter        = $config->{'filter'} unless $ldapfilter;
    $ldapnet_ldap_args = $config->{'net_ldap_args'} unless $ldapnet_ldap_args;
    $ldapattr_map_name = $config->{'attr_map'}->{'Name'} unless $ldapattr_map_name;
    
    my @exceptions = (qw(root Nobody RT_System), @myexceptions);
    
    # Options
    my %options = ();
    getopts("vawhf:",\%options) or usage();
    my $write=$options{w}?1:0;
    my $verbose=$options{v}?1:0;
    usage() if $options{h};
    
    my ($return,$message,$emailnotificationlist);
    my $users = RT::Users->new(RT->SystemUser);
    
    open(FILE,"> ".$options{f}) if $options{f};
    if ($options{a}){
    	$users->UnLimit();
    }
    else {
    	$users->LimitToPrivileged();
    }
    
    while ( my $user = $users->Next ) {
    
    	# LOCAL ACCOUNTS (exceptions): skipping to the next entry
    	if ( grep {$_ eq $user->Name} @exceptions) {
    		print "[Local]   [".$user->Name." -> don't touch: local account / exception]  Email:".$user->EmailAddress."\n" if($verbose);
    		next;
    	}
    
    
    	# One of our domain email addresses
    	if ($user->EmailAddress =~ m/$domain/i ){
    
    		my $cleanedemail = $user->EmailAddress;
    
    		# Protection of @ sign
    		$cleanedemail =~ s/@/\\@/;
    		# Keep only first email if account contains several emails
    		$cleanedemail =~ s/([^,]*),.*/$1/;
    		# Remove spaces
    		$cleanedemail =~ s/\ //g;
    
    		# Get LDAP/AD login
    		my ($return,$exist) = return_ldap_login("$cleanedemail");
    
    		# Remove the protection on @ sign
    		$cleanedemail =~ s/\\//g;
    
    		if ( $return == 1 ){
    				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";
    				next;
    		}
    
    		# One of our addresses but no entry in LDAP : disabling account because probably wrong
    		# It's renamed because if the RT login is already a valid AD login, it'll cause trouble for other valid emails/logins
    		if ( $exist eq "" ) {
    			print "[DisableRename] [".$user->Name." -> disabled + renamed -disablednotinDirectory]  Email:".$user->EmailAddress."\n"  if($verbose);
    			if ($write) {
    				($return,$message)=$user->SetName($user->Name."-disablednotindirectory");
    				print "--> Setting name ".$message."\n";
    				($return,$message)=$user->SetDisabled(1);
    				print "---> Disabling user: ".$message."\n";
    			}
    		}
    		elsif (lc($exist) eq lc($user->Name)){
    			# Login already LDAP/AD login, doing nothing
    			print "[LoginOK] [".$user->Name." -> already LDAP login]  Email:".$user->EmailAddress."\n"  if($verbose);
    		}
    		else {
    			# One of our email addresses and not the good LDAP login but a good LDAP entry exists for this email address in the directory
    			# Check if LDAP login already used in RT
    			my $tempuser = RT::User->new(RT->SystemUser);
    			$tempuser->Load($exist);
    			if ( $tempuser->Id ) {
    				# It's already used !
    				# Keep privileged user, rename and disable this one: in the furture, merge these entries ?
    				if($tempuser->Privileged and ! $user->Privileged) {
    					print "[Disable] [".$user->Name." -> disabled ] Keeping ".$tempuser->Name." with Id ".$tempuser->Id."  Email:".$user->EmailAddress."\n" if($verbose);
    					if ($write) {
    						$exist .= "-disablednotprivileged";
    						($return,$message)=$user->SetName($exist);
    						print "--> Setting name ".$message."\n";
    						($return,$message)=$user->SetDisabled(1);
    						print "---> Disabling user: ".$message."\n";
    					}
    
    
    				}
    				else {
    					# LDAP login used: to be managed manually.
    					# Login to RT, cehck the two accounts, rename login of one of them and disable it
    					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";
    				}
    			}
    			else {
    				# LDAP login not used yet: rename to LDAP login
    				print "[Rename]  [".$user->Name." -> ". $exist ."]  Email:".$user->EmailAddress."\n"  if($verbose);
    				print FILE $user->Name.";".$exist.";".$cleanedemail."\n" if $options{f};
    
    				if ($write) {
    					($return,$message)=$user->SetName($exist);
    					print "--> Setting name ".$message."\n";
    				}
    				$emailnotificationlist .= $cleanedemail.";";
    			}
    		}
    	}
    	# Extenal email addresses and looks like an email address : keep it as it is, probably external users
    	elsif ($user->EmailAddress =~ m/.*\@.*\..*/) {
    		print "[External] [".$user->Name." -> Don't touch: external email]  Email:".$user->EmailAddress."\n" if($verbose);
    	}
    	# Strange entry : doesn't look like an email
    	else {
    		print "[Disable] [".$user->Name." -> disabled]  Email:".$user->EmailAddress."\n"  if($verbose);
    		if ($write) {
    			($return,$message)=$user->SetDisabled(1);
    			print "--> Disabling user: ".$message."\n";
    		}
    	}
    }
    
    print "\nPeople to notify: ".$emailnotificationlist."\n" if $options{f};
    close(FILE)if $options{f};
    #}}}
    
    

Notify users their login changed

send_login_modif_notification.pl

#!/usr/bin/perl
    use strict;
    use Mail::Mailer;
    use Getopt::Std;
    
    my %options = ();
    getopts("f:",\%options) or usage();
    
    my $RTURL="http://rt.foobar.com";
    my $RTADMINS="Mr Foo, Mr Bar";
    my $someexceptions="account1, account2";
    my $domain="foobar.com";
    my $mydirectory="Active Directory";
    
    open(FILE,"< ".$options{f}) or die "File ".$options{f}." not found";
    while(<FILE>){
            my ($oldlogin,$newlogin,$email) = split(';',$_);
    
            my $mailer = Mail::Mailer->new();
            $mailer->open({ From    =>  'RT System <rt-noreply@'.$domain.'>',
                            To      =>  $email,
                            Subject => "$mydirectory authentication on $RTURL",
                            })
                    or die "open impossible : $!\n";
            print $mailer "
    Dear RT user,
    
     $RTURL is now linked to $mydirectory.
    
     Your login on this system was \"$oldlogin\" and is now your $mydirectory login \"$newlogin\". Your old local password will still work for a couple of weeks and will then be disabled, your $mydirectory password will be the only one to work.
    
     Please logout and login with this new login and your $mydirectory password.
    
     Note the local accounts such as $someexceptions will still work with the local password.
    
     Don't hesitate to contact us if you have any trouble.
    
    Best regards,
    $RTADMINS
    ";
            close($mailer);
            print "Email sent to $email\n";
    }