Problem implementing LDAP and RT 3.6.3

Hi,
I’m having problems implementing LDAP user authentication in RT and perhaps
someone has done this on RT 3.6.3. Basically, its not allowing me to
authenticate either using an existing RT user or an LDAP user. I copied
the CurrentUser_Local.pm over to my /opt/rt3/lib/RT directory and from what
I can observe, RT is not calling the IsPassword function. I know this
because I added a bunch of debug statements and don’t see it being
generated in any of the logs that I know. Is there anything I need to do
different? or anyone know of any gotchas I should be aware of? I’ve
included in this note the output from the /var/log/error_log, and
CustomUser_Local.pm. Any help is very much appreciated. Thanks.

BTW, I modified the autohandler to print out my user and password.
[Fri Mar 02 14:33:25 2007] [notice] suEXEC mechanism enabled (wrapper:
/usr/sbin/suexec)
[Fri Mar 02 14:33:25 2007] [notice] Digest: generating secret for digest
authentication …
[Fri Mar 02 14:33:25 2007] [notice] Digest: done
[Fri Mar 02 14:33:25 2007] [notice] LDAP: Built with OpenLDAP LDAP SDK
[Fri Mar 02 14:33:25 2007] [notice] LDAP: SSL support unavailable
[Fri Mar 02 14:33:26 2007] [notice] FastCGI: process manager initialized
(pid 26008)
[Fri Mar 02 14:33:26 2007] [warn] FastCGI: server
“/opt/rt3/bin/mason_handler.fcgi” started (pid 26010)
[Fri Mar 02 14:33:26 2007] [notice] Apache/2.0.52 (Red Hat) configured –
resuming normal operations
[Fri Mar 02 14:33:27 2007] [warn] FastCGI: server
“/opt/rt3/bin/mason_handler.fcgi” started (pid 26018)
[Fri Mar 02 14:33:28 2007] [warn] FastCGI: server
“/opt/rt3/bin/mason_handler.fcgi” started (pid 26019)
[Fri Mar 02 14:33:29 2007] [warn] FastCGI: server
“/opt/rt3/bin/mason_handler.fcgi” started (pid 26020)
[Fri Mar 02 14:34:49 2007] [error] [client 9.41.30.100] FastCGI: server
“/opt/rt3/bin/mason_handler.fcgi” stderr: [Fri Mar 2 20:34:49 2007]
[error]: DEBUG: egaona@us.ibm.com password: boo
(/opt/rt3/share/html/autohandler:248), referer:
http://austrack01.austin.ibm.com/index.html
[Fri Mar 02 14:34:49 2007] [error] [client 9.41.30.100] FastCGI: server
“/opt/rt3/bin/mason_handler.fcgi” stderr: [Fri Mar 2 20:34:49 2007]
[error]: FAILED LOGIN for egaona@us.ibm.com from 9.41.30.100
(/opt/rt3/share/html/autohandler:250), referer:
http://austrack01.austin.ibm.com/index.html

Here are the contents of CurrentUser_Local.pm and the LDAP settings. We
have another instance of RT, but its using the 3.4.x release and its
working beautifully.

RT_SiteConfig.pm:
Set($LdapServer, “bluepages.ibm.com:389”);
Set($LdapUser, “”);
Set($LdapPass, “”);
Set($LdapBase, “ou=bluepages,o=ibm.com”);
Set($LdapUidAttr, “mail”);
Set($LdapFilter, “(objectclass=*)”);
Set($LdapTLS, 0);
Set($LdapNameAttr, “cn”);
Set($LdapMailAttr, “mail”);
Set($AutoCreateFromExternalUserInfo, 1);
Set($MaxInlineBody, 13456);

CurrentUser_Local.pm:

AutoCreateFromExternalUserInfo overlay

author: Robin Battey

based in part by the LookupExternalUserInfo function

written by Jeff Hoover <jeff.hoover at infotechfl dot com>

This Overlay is useful if you want the following behavior:

* Whenever RT tries – and fails – to load a user from the

RT user database, it queries an Ldap server for the account

information and creates it on the fly (for both email lookups

and web logins)

* RT behaves as though the account has always been there – i.e.

there is no reason to give “Everyone” the “Create Ticket” right,

because the account has been there all along …

* NO synchronization with the Ldap server once the account has

been created, so any changes in RT stay in RT and any changes

in Ldap stay in Ldap (unless you run some other script, of course)

The situation I had at my place of employment, which caused me

to write this, is we have an Active Directory server with a fairly

large number of users on it, with a fair bit of adding/deleting of

users going on. I wanted a way for users to send a request to the

help queue, and then immediately be able to see the ticket, the

ticket’s status, etc using their Active Directory (i.e. windows

domain) username and password. I wrote this overlay for the account

generation, and used the LdapOverlay available in the “Contributions”

section of the RT3 Wiki (http://wiki.bestpractical.com) for the

authentication. This overlay was therefore designed to work well

with the LdapOverlay, and actually uses (some of) the same Ldap

variables.

I spent a bit of effort making sure this was modular, particularly

in the case of a different external user info source. It currently

works with LDAP (and, of course, Active Directory), but there’s no

good reason why you can’t just replace the LookupExternalUserInfo

function to get your data from somewhere else.

no warnings qw(redefine);
use Net::LDAP qw(LDAP_SUCCESS LDAP_PARTIAL_RESULTS);
use Net::LDAP::Util qw (ldap_error_name);
use Net::LDAP::Filter;
use constant DEBUG => 1; # Change to 1 to log debugging info.

{{{ sub IsPassword

Modification Originally by Marcelo Bartsch bartschm_cl@hotmail.com

Update by Stewart James <stewart.james@vu.edu.au for rt3.

Update by David Wheeler david@kineticode.com for TLS and Group

membership support.

Drop this file in /opt/rt3/lib/RT/User_Local.pm

Drop something like below in yout RT_SiteConfig.pm

$LDAPExternalAuth = 1;

$LdapServer=“127.0.0.1”;

$LdapUser=“”;

$LdapPass=“”;

$LdapBase=“ou=Users,dc=example,dc=com”;

$LdapUidAttr=“uid”;

$LdapFilter=“(objectclass=*)”;

$LdapTLS = 1;

$LdapGroup =“cn=RT,ou=Group,dc=example,dc=com”;

$LdapGroupAttribute = ‘uniqueMember’;

$LdapSSLVersion = 3;

$Net::SSLeay::ssl_version = $RT::LdapSSLVersion
if $RT::LdapTLS && defined $RT::LdapSSLVersion;

sub IsPassword {
my $self = shift;
my $user = shift;
my $pass = shift;

#TODO there isn't any apparent way to legitimately ACL this

# RT does not allow null passwords
return unless defined $pass && $pass ne '';

 $RT::Logger->debug("DEBUG self: ", $self, "\n");
 $RT::Logger->debug("DEBUG user: ", $user, "\n");
 $RT::Logger->debug("DEBUG pass: ", $pass, "\n");

if ( $self->PrincipalObj->Disabled ) {

$RT::Logger->info("Disabled user " . $self->Name . " tried to log

in" ); return;

}

my $password = $self->__Value(‘Password’);

return unless defined $password && $password ne ‘’;

#  if it's a historical password we say ok.

return 1 if $RT::User->_GeneratePassword($pass) eq $password;

if ($RT::LDAPExternalAuth) {

$user = RT::Interface::Web::WebCanonicalizeInfo();

    my %user_info;
    my $ldap = Net::LDAP->new($RT::LdapServer, version=>3)
      or $RT::Logger->critical("GetExternalUserWithLDAP: Cannot connect

to LDAP\n"),
return;

    my $mesg = defined $RT::LdapUser && $RT::LdapUser ne ''
      ? $ldap->bind($RT::LdapUser, password => $RT::LdapPass )
      : $ldap->bind;

    unless ($mesg->code == LDAP_SUCCESS) {
        $RT::Logger->critical("GetExternalUserWithLDAP: Cannot bind to

LDAP: ", $mesg->code, “\n”);
return;
}
my $filter = Net::LDAP::Filter->new(
“mail=$user”
);
$RT::Logger->debug(“GetExternalUserWithLDAP: First search filter
'”,
$filter->as_string . “'\n”) if DEBUG;
$mesg = $ldap->search(
base => $RT::LdapBase,
filter => $filter,
attrs => [‘mail’,‘telephonenumber’,‘cn’,‘uid’]
);

    unless ($mesg->code == LDAP_SUCCESS || $mesg->code ==

LDAP_PARTIAL_RESULTS) {
$RT::Logger->debug("GetExternalUserWithLDAP: Could not search
for ", $filter->as_string, ": ", $mesg->code,
“”,
ldap_error_name($mesg->code), “\n”) if
DEBUG;
return;
}

    $RT::Logger->debug("GetExternalUserWithLDAP: First search produced

“,
$mesg->count, " results\n”) if DEBUG;
unless ($mesg->count) {
$RT::Logger->info("AUTH FAILED: " . $self->Name . “\n”);
return;
}

    my $mesg2 = $ldap->bind($mesg->first_entry->dn, password => $pass

);
if ($mesg2->code == LDAP_SUCCESS) {

        # Create user on the fly if they don't already exist
        if (!$self->Id()) {
            my $entry = $mesg->entry(0);
            $user_info{'RealName'} = $entry->get_value('cn');
            $user_info{'EmailAddress'} = $entry->get_value('mail');
            $user_info{'WorkPhone'} =

$entry->get_value(‘telephonenumber’);
$user_info{‘Gecos’} = $entry->get_value(‘uid’);

            my $UserObj =

RT::User->new(RT::CurrentUser->new(‘RT_System’));
my ($val, $msg) = $UserObj->Create(
Name=> $user_info{‘EmailAddress’},
Gecos=> $user_info{‘Gecos’}
);
unless ($val) {
$RT::Logger->info (“CreateFromExternalUserInfo: failed
to create user with args: “, %params, “\nval=”.$val.”\nmsg=”.$msg);
return undef;
}

            # Set several attributes
            $UserObj->SetRealName($user_info{'RealName'});
            $UserObj->SetEmailAddress($user_info{'EmailAddress'});
            $UserObj->SetWorkPhone($user_info{'WorkPhone'});

            $RT::Logger->info ("CreateFromExternalUserInfo: created

user $val ("$msg")\n");

$self->LoadByCol(“EmailAddress”,$user_info{‘EmailAddress’});

        }
        $RT::Logger->info("AUTH OK: " . $user_info{'EmailAddress'} . "

(" .$user_info{‘Gecos’} . “)\n”);
return 1;
} else {
$RT::Logger->critical(“GetExternalUserWithLDAP: Cannot bind to
LDAP:”,
$mesg2->code, “\n”);
return;
}
} else {
return 1 if crypt($pass, $password) eq $password;
}

# no password check has succeeded. get out
return;

}

}}}

1;

Enrique