[rt-users] LDAP auth: should I still create the users in RT even if I use WebExternalAuth?

Carl Makin carl at xena.IPAustralia.gov.au
Tue Dec 17 18:45:43 EST 2002


On Wed, 2002-12-18 at 03:45, Stanislav Sinyagin wrote:
> --- seph <seph at commerceflow.com> wrote:
> > Stephane Bortzmeyer <bortzmeyer at nic.fr> writes:

> > > Does it mean that I still have to create the users in RT (may be using
> > > <URL:http://www.fsck.com/pub/rt/contrib/2.0/rtimportldap.tar> from
> > > cron to automatize it)? Or will LookupExternalUserInfo help me?
> > > (Reading its comments, I do not believe it.)
> 
> rtimportldap will definetely help. That's why I created it :)

Here is what I'm playing with at the moment.  I use
Apache::AuthenNetLDAP in Apache to authenticate against our LDAP server.

Here is what I'm using in Apache's httpd.conf.


--------------- Cut Here -----------------------------------

Alias /rt2 /usr/local/rt2/WebRT/html
PerlRequire /usr/local/rt2/bin/webmux.pl                
<Location /rt2>                         
  SetHandler perl-script
  PerlHandler RT::Mason

  AuthName "Request Tracker"
  AuthType Basic

  PerlSetVar BaseDN "ou=people,dc=ipaustralia,dc=gov,dc=au"
  PerlSetVar LDAPServer our.directory.server.gov.au
  PerlSetVar LDAPPort 389
  PerlSetVar UIDAttr uid

  require valid-user

  PerlAuthenHandler Apache::AuthNetLDAP

</Location>


--------------- Cut Here -----------------------------------

and here is the LookupExternalUserInfo() subroutine that maps inbound
email to valid userids.

Below that is the WebExternalAutoInfo() subroutine that automatically
creates new users based on their LDAP attributes.  The bad side effect
of this is that requestors no longer get the simple page.  I'm still
considering if that is what I want.

Thanks to the authors of the code that I hacked around to get the
following bits.

One thing that is missing is managing group memberships via LDAP
groups.  It's not critical to what I'm doing here, but probably worth
looking at in the new year.

--------------- Cut Here -----------------------------------

  use Net::LDAP;
  use Net::LDAP::Constant qw(LDAP_SUCCESS);

  use constant LDAP       => q(your.ldap.server);
  use constant LDAP_PORT  => q(389);
  use constant LDAP_BASE  => q(your=ldap.base);
  use constant LDAP_UID   => q(uid);
  use constant LDAP_EMAIL => q(mail);
  use constant LDAP_CN    => q(cn);


sub LookupExternalUserInfo {
  my ($EmailAddress, $RealName) = @_;

  my $FoundInExternalDatabase = 0;
  my %params;

  #Name is the RT username you want to use for this user.
  $params{'Name'} = $EmailAddress;
  $params{'EmailAddress'} = $EmailAddress;
  $params{'RealName'} = $RealName;

  $RT::Logger->debug("LookupExternalUserInfo: Entered with:\n",
		     "\tName         = $params{'Name'}\n",
		     "\tEmailAddress = $params{'EmailAddress'}\n",
		     "\tRealName     = $params{'RealName'}\n",
		     "\tFound        = $FoundInExternalDatabase\n");

  $params{'RealName'} =~ s/\"//g;


  my $ldap = new Net::LDAP(LDAP, port => LDAP_PORT)
    or $RT::Logger->critical("LookupExternalUserInfo: Cannot connect to
",
			     "LDAP'\n"),
      return ($FoundInExternalDatabase, %params);

  my $mesg = $ldap->bind();
  if ($mesg->code != LDAP_SUCCESS) {
    $RT::Logger->critical("LookupExternalUserInfo: Cannot bind
anonymously ",
			  "to LDAP:", $mesg->code, "\n");
    return ($FoundInExternalDatabase, %params);
  }

  my $filter = "@{[ LDAP_EMAIL ]}=$params{'EmailAddress'}";
  $RT::Logger->debug("LookupExternalUserInfo: First search filter ",
		     "'$filter'\n");
  $mesg = $ldap->search(base   => LDAP_BASE,
                        filter => $filter,
                        attrs  => [ LDAP_EMAIL, LDAP_CN, LDAP_UID ]);
  if ($mesg->code != LDAP_SUCCESS)  {
    $RT::Logger->critical("LookupExternalUserInfo: Could not search for
",
			  "$filter: ", $mesg->code, "\n");
    return ($FoundInExternalDatabase, %params);
  }

  $RT::Logger->debug("LookupExternalUserInfo: First search produced ",
		     $mesg->count, " results\n");

  # E-mail search failed
  unless ($mesg->count == 1) {
    $filter = "@{[ LDAP_CN ]}=$params{'RealName'}";


    $RT::Logger->debug("LookupExternalUserInfo: Second search filter ",
		       "'$filter'\n");
    $mesg = $ldap->search(base   => LDAP_BASE,
                          filter => $filter,
			  attrs  => [ LDAP_EMAIL, LDAP_CN, LDAP_UID ]);
    if ($mesg->code != LDAP_SUCCESS)  {
      $RT::Logger->critical("LookupExternalUserInfo: Could not search
for ",
			    "$filter: ", $mesg->code, "\n");
      return ($FoundInExternalDatabase, %params);
    }
  }

  $RT::Logger->debug("LookupExternalUserInfo: Second search produced ",
		     $mesg->count, " results with filter $filter\n");

  # One of the two searches succeeded with just one match
  if ($mesg->count == 1) {
    $params{'Name'} = ($mesg->first_entry->get_value(LDAP_UID))[0];
    $params{'EmailAddress'} =
($mesg->first_entry->get_value(LDAP_EMAIL))[0];
    $params{'RealName'} = ($mesg->first_entry->get_value(LDAP_CN))[0];
    ++$FoundInExternalDatabase;
  }

  $mesg = $ldap->unbind();
  if ($mesg->code != LDAP_SUCCESS) {
    $RT::Logger->critical("LookupExternalUserInfo: Could not unbind from
",
			  "LDAP: ", $mesg->code, "\n");
  }
  undef $ldap;
  undef $mesg;

  $RT::Logger->debug("LookupExternalUserInfo: Leaving LDAP examination
",
		     "with:\n",
		     "\tName         = $params{'Name'}\n",
		     "\tEmailAddress = $params{'EmailAddress'}\n",
		     "\tRealName     = $params{'RealName'}\n",
		     "\tFound        = $FoundInExternalDatabase\n");

  return ($FoundInExternalDatabase, %params) if
$FoundInExternalDatabase;

  use Fcntl;
  use NDBM_File;

  use constant LocalUserFile => '/usr/local/rt2/local/localusers';
  use constant LockFile      => '/tmp/rt2-localusers.lock';

  # Lock the database
  my $timeout = 20 + time;
  while (-e LockFile && time < $timeout) {
    sleep(1);
  }
  open(LOCK, ">@{[ LockFile ]}") or
    die "Can't create ", LockFile, " file: $!\n";

  tie(my %users, 'NDBM_File', LocalUserFile, O_RDONLY, 0444);
  my ($tempaddress, $tempname) =
    ($users{$params{'EmailAddress'}} =~ /^([^\"]+)(.*)/);
  untie(%users);

  # Unlock the database
  close(LOCK);
  unlink(@{[ LockFile ]});

  if ($tempaddress) {
    ($params{'EmailAddress'}, $params{'RealName'}) = 
      ($tempaddress, $tempname);
#    $params{'Name'} = $params{'EmailAddress'};
    ++$FoundInExternalDatabase;
  }

  $RT::Logger->debug("LookupExternalUserInfo: Leaving local file ",
		     "examination with:\n",
		     "\tName         = $params{'Name'}\n",
		     "\tEmailAddress = $params{'EmailAddress'}\n",
		     "\tRealName     = $params{'RealName'}\n",
		     "\tFound        = $FoundInExternalDatabase\n");

  return ($FoundInExternalDatabase, %params);
}


# define this if you want to auto create web users
$WebExternalAuto = 1;

# if you're auto creating users, they get their info from this function
# it should be returning an array with various User attributes.
sub WebExternalAutoInfo {
    
    my %info;
    
  my $username = $ENV{'REMOTE_USER'};
  $info{'Name'} = $username; 
  print "username -> $username\n";
  

  my $ldap = new Net::LDAP(LDAP, port => LDAP_PORT)
    or $RT::Logger->critical("LookupExternalUserInfo: Cannot connect to
",
			     "LDAP'\n"),
      return (%info);

  my $mesg = $ldap->bind();
  if ($mesg->code != LDAP_SUCCESS) {
    $RT::Logger->critical("LookupExternalUserInfo: Cannot bind
anonymously ",
			  "to LDAP:", $mesg->code, "\n");
    return(%info);
  }

  my $filter = "(uid=" . $username . ")";
  $RT::Logger->debug("LookupExternalUserInfo: First search filter ",
		     "'$filter'\n");
  $mesg = $ldap->search(base   => LDAP_BASE,
                        filter => $filter,
                        attrs  => [ LDAP_EMAIL, LDAP_CN, LDAP_UID,
"mobile", "departmentNumber", "extensionNumber", "givenName" ]);
  if ($mesg->code != LDAP_SUCCESS)  {
    $RT::Logger->critical("LookupExternalUserInfo: Could not search for
",
			  "$filter: ", $mesg->code, "\n");
    return (%info);
  }
  
  
  $info{'EmailAddress'} =
($mesg->first_entry->get_value(LDAP_EMAIL))[0];
  $info{'RealName'} = ($mesg->first_entry->get_value(LDAP_CN))[0];
  $info{'MobilePhone'} = ($mesg->first_entry->get_value('mobile'))[0];
  $info{'WorkPhone'} =
($mesg->first_entry->get_value('extensionNumber'))[0];
  $info{'Organization'} =
($mesg->first_entry->get_value('departmentNumber'))[0];
  $info{'NickName'} = ($mesg->first_entry->get_value('givenName'))[0];

  $mesg = $ldap->unbind();
  if ($mesg->code != LDAP_SUCCESS) {
    $RT::Logger->critical("LookupExternalUserInfo: Could not unbind from
",
			  "LDAP: ", $mesg->code, "\n");
  }
   
    $info{'Privileged'} = 1;
    # and return the wad of stuff
    return {%info};
}

--------------- Cut Here -----------------------------------

Enjoy!


Carl.




More information about the rt-users mailing list