RT 5.x TLS on LDAPImport.pm

We’ve been moving to use TLS for all of our LDAP interactions here, in preparation for Microsoft to eventually decide to switch off unsecure LDAP to ActiveDirectory servers (which they’ve postponed a couple of times). RT seems to understand the tls flag for one half of its LDAP support, but not for the LDAP import. This has been mentioned several times in the past on the forum for 4.x versions of RT, but I thought’d I’d give a heads up that this is still the case in RT5.x.

To help folk out if you want to turn on LDAP’s TLS option for imports, here’s a simple local overlay you can pop into /opt/rt5/local/lib/RT/LDAPImport_Local.pm:

package RT::LDAPImport;

use warnings;
use strict;
use base qw(Class::Accessor);
__PACKAGE__->mk_accessors(qw(_ldap _group _users));
use Carp;
use Net::LDAP;
use Net::LDAP::Util qw(escape_filter_value);
use Net::LDAP::Control::Paged;
use Net::LDAP::Constant qw(LDAP_CONTROL_PAGED);
use Net::LDAP::Constant qw(LDAP_EXTENSION_START_TLS);
use Authen::SASL;
use Data::Dumper;
no warnings qw(redefine);

sub connect_ldap {
    my $self = shift;

    $RT::LDAPOptions = [] unless $RT::LDAPOptions;
    my $ldap = Net::LDAP->new($RT::LDAPHost, @$RT::LDAPOptions);

    $RT::Logger->debug("connecting to $RT::LDAPHost");
    unless ($ldap) {
        $RT::Logger->error("Can't connect to $RT::LDAPHost $@");
        return;
    }

    if($RT::LDAPTLS) {
	unless ($ldap->root_dse->supported_extension( LDAP_EXTENSION_START_TLS )) {
	    $RT::Logger->error("START_TLS Extension Required");
	    return;
	}

	my $mesg = $ldap->start_tls($RT::LDAPTLSOptions);

	if( $mesg->is_error() ) {
	    $RT::Logger->error("Failed to start_tls ( " . 
			       $mesg->code() . " - " . 
			       $mesg->error() . " )\n");
	    return;
        }
	    $RT::Logger->debug("TLS turned on - about to try binding");
    }
    my $msg;
    if ($RT::LDAPUser) {
        $RT::Logger->debug("binding as $RT::LDAPUser");
        $msg = $ldap->bind($RT::LDAPUser, password => $RT::LDAPPassword);
    } else {
        $RT::Logger->debug("binding anonymously");
        $msg = $ldap->bind;
    }

    if ($msg->code) {
        $RT::Logger->error("LDAP bind failed " . $msg->error);
        return;
    }

    $self->_ldap($ldap);
    return $ldap;

}

1;

This just overlays the LDAP connection subroutine and uses two new RT_SiteConfig.pm options:

  • LDAPTLS which is a boolean to turn on the LDAP TLS support
  • LDAPTLSOptions which is a hash of options to pass to the Net::LDAP start_tls method.

For example:

Set($LDAPTLS, 1);
Set($LDAPTLSOptions, {
    verify => 'require',
    sslversion => 'tlsv1_2',
    cafile => '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem'
    });

Is it worth popping a copy over to the RT bug tracker to see if this sort of thing can finally get slipped into the RT 5.x code base for 5.0.2 or beyond? Or are there some technical/ideological reasons why previous TLS patches for LDAPImport.pm didn’t make it into the main code?

1 Like

I’ve just had to apply this to a test install of RT 5.0.5, as the connect_ldap() call in LDAPImport.pm still doesn’t seem to handle TLS before binding LDAP connections. Do I take it from the lack of response to my original post that most people who are doing LDAP against Active Directory servers aren’t enforcing secure TLS connections?

We have typically used ldaps, which you can set using the existing LDAPOptions on the initial connection. The example configuration in the docs shows the SSL version with ldaps, the secure port 636, verify option, etc. My understanding is StartTLS is most useful if you need to re-use the existing connection and can’t switch the port. I found some discussion on ldaps vs. StartTLS, which provides some good links, but nothing very conclusive.

Do you know if Active Directory won’t support ldaps or port 636? I feel like we have used that before to connect ldapimport to AD servers, but I can’t say 100%.

We’ve been using StartTLS for some years now with our AD servers, partially pushed by an “imminent” change that Microsoft were going to to implement to turn off insecure LDAP access to domain controllers, which doesn’t appear to have happened (yet!). Either way, we’d want the secure LDAP connections for our own auditing and peace of mind.

I don’t think that Microsoft will be turning away from implicit TLS on port 636, but in some places that privileged port might be firewalled, whereas port 386 with explicit TLS would be available to user LANs. Considering this is a reasonably minor addition to the connect_ldap() method would giving folk the option be useful?

Hi. Calling:

/opt/rt5/sbin/rt-ldapimport --verbose

Throws me the following error:

[critical]: Can't call method "supported_extension" on an undefined value at /opt/rt5/sbin/../local/lib/RT/LDAPImport_Local.pm line 30. (/opt/rt5/sbin/../lib/RT.pm:409)
Can't call method "supported_extension" on an undefined value at /opt/rt5/sbin/../local/lib/RT/LDAPImport_Local.pm line 30.

I comment lines 30-33 launching again rt-import:

[error]: Failed to start_tls ( 1 - TLS already started ) (/opt/rt5/sbin/../local/lib/RT/LDAPImport_Local.pm:38)

Does LDAP->new() start a TLS connection so we don’t need to call start_tls() method?

I’ll continue investigating.

I would assume it depends if you have a scheme => 'ldaps' in your $LDAPOptions in the RT_SiteConfig.pm. We don’t so the above code works for us.

Changed to ldap port 389 but still complains about:

"Can't call method 'supported_extension' on an undefined value ..."

ldapsearch on port 389 works fine (there’s no firewall blocking connections to the LDAP)
I’ll continue with SSL by now.