Rt logins email2ldap

From Request Tracker Wiki
Jump to: navigation, 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};
#}}}

</nowiki>

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,"&lt; ".$options{f}) or die "File ".$options{f}." not found";
while(&lt;FILE&gt;){
        my ($oldlogin,$newlogin,$email) = split(';',$_);

        my $mailer = Mail::Mailer-&gt;new();
        $mailer-&gt;open({ From    =&gt;  'RT System &lt;rt-noreply@'.$domain.'&gt;',
                        To      =&gt;  $email,
                        Subject =&gt; "$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";
}
</nowiki>