<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://rt-wiki.bestpractical.com/index.php?action=history&amp;feed=atom&amp;title=LdapUserLocalOverlay</id>
	<title>LdapUserLocalOverlay - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://rt-wiki.bestpractical.com/index.php?action=history&amp;feed=atom&amp;title=LdapUserLocalOverlay"/>
	<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=LdapUserLocalOverlay&amp;action=history"/>
	<updated>2026-08-24T08:22:10Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=LdapUserLocalOverlay&amp;diff=1820&amp;oldid=prev</id>
		<title>Admin: 4 revisions imported</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=LdapUserLocalOverlay&amp;diff=1820&amp;oldid=prev"/>
		<updated>2016-04-06T20:14:18Z</updated>

		<summary type="html">&lt;p&gt;4 revisions imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 16:14, 6 April 2016&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key bestpractical_mediawiki1459887241:diff:1.41:old-1819:rev-1820 --&gt;
&lt;/table&gt;</summary>
		<author><name>Admin</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=LdapUserLocalOverlay&amp;diff=1819&amp;oldid=prev</id>
		<title>66.73.230.190: Undo revision 5652 by 195.16.40.50 (talk)</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=LdapUserLocalOverlay&amp;diff=1819&amp;oldid=prev"/>
		<updated>2010-11-29T15:58:00Z</updated>

		<summary type="html">&lt;p&gt;Undo revision 5652 by &lt;a href=&quot;/wiki/Special:Contributions/195.16.40.50&quot; title=&quot;Special:Contributions/195.16.40.50&quot;&gt;195.16.40.50&lt;/a&gt; (&lt;a href=&quot;/index.php?title=User_talk:195.16.40.50&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;User talk:195.16.40.50 (page does not exist)&quot;&gt;talk&lt;/a&gt;)&lt;/p&gt;
&lt;a href=&quot;https://rt-wiki.bestpractical.com/index.php?title=LdapUserLocalOverlay&amp;amp;diff=1819&amp;amp;oldid=1818&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>66.73.230.190</name></author>
	</entry>
	<entry>
		<id>https://rt-wiki.bestpractical.com/index.php?title=LdapUserLocalOverlay&amp;diff=1818&amp;oldid=prev</id>
		<title>195.16.40.50: Adding categories</title>
		<link rel="alternate" type="text/html" href="https://rt-wiki.bestpractical.com/index.php?title=LdapUserLocalOverlay&amp;diff=1818&amp;oldid=prev"/>
		<updated>2010-11-26T13:20:43Z</updated>

		<summary type="html">&lt;p&gt;Adding categories&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;This code is now deprecated. Please see [http://wiki.bestpractical.com/view/LDAP the new LDAP page] instead.&lt;br /&gt;
&lt;br /&gt;
This code is part of the [http://wiki.bestpractical.com/view/LDAP LDAP integration overlay]; you&amp;#039;ll also need [[LdapSiteConfigSettings]] and, optionally, [[LdapAutocreateAuthCallback]].&lt;br /&gt;
&lt;br /&gt;
Put this in [=${RTHOME}/local/lib/RT/[[User Local|User_Local]].pm]:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;### User_Local.pm overlay for LDAP authentication and information&lt;br /&gt;
 ### v1.1b2  2005.08.03  purp@acm.org&lt;br /&gt;
 #&lt;br /&gt;
 # The latest version of this module may be found at:&lt;br /&gt;
 #   http://wiki.bestpractical.com/view/LdapUserLocalOverlay&lt;br /&gt;
 #&lt;br /&gt;
 # THIS MODULE REQUIRES SETTINGS IN YOUR RT_SiteConfig.pm;&lt;br /&gt;
 # you can find these at:&lt;br /&gt;
 #   http://wiki.bestpractical.com/view/LdapSiteConfigSettings&lt;br /&gt;
 #&lt;br /&gt;
 &lt;br /&gt;
 ### CREDITS&lt;br /&gt;
 # IsLDAPPassword() based on implementation of IsPassword() found at:&lt;br /&gt;
 #&lt;br /&gt;
 # http://www.justatheory.com/computers/programming/perl/rt/User_Local.pm.ldap&lt;br /&gt;
 #&lt;br /&gt;
 # Author&amp;#039;s credits:&lt;br /&gt;
 # Modification Originally by Marcelo Bartsch &amp;amp;lt;bartschm_cl@hotmail.com&amp;amp;gt;&lt;br /&gt;
 # Update by Stewart James &amp;amp;lt;stewart.james@vu.edu.au for rt3.&lt;br /&gt;
 # Update by David Wheeler &amp;amp;lt;david@kineticode.com&amp;amp;gt; for TLS and&lt;br /&gt;
 #    Group membership support.&lt;br /&gt;
 #&lt;br /&gt;
 #&lt;br /&gt;
 # CaonicalizeEmailAddress(), CanonicalizeUserInfo(), and LookupExternalInfo()&lt;br /&gt;
 # based on work by Phillip Cole (phillip d cole @ uk d coltgroup d com)&lt;br /&gt;
 # found at:&lt;br /&gt;
 #&lt;br /&gt;
 # http://wiki.bestpractical.com/view/AutoCreateAndCanonicalizeUserInfo&lt;br /&gt;
 #&lt;br /&gt;
 # His credits:&lt;br /&gt;
 #   based on CurrentUser_Local.pm and much help from the mailing lists&lt;br /&gt;
 #&lt;br /&gt;
 # All integrated, refactored, and updated by Jim Meyer (purp@acm.org)&lt;br /&gt;
 #&lt;br /&gt;
 # Changes:&lt;br /&gt;
 # v1.1b2 (2006.08.03) Modified by Phil Cole&lt;br /&gt;
 #  * Add $LdapEmailAttrMatchPrefix config variable to make alternate email&lt;br /&gt;
 #    addresses work on Windows 2003 AD.&lt;br /&gt;
 # v1.1b1 (2006.06.05) Punch-Drunk Hamster Release&lt;br /&gt;
 #  * Added UpdateFromLdap() to update the user&amp;#039;s info from their LDAP entry;&lt;br /&gt;
 #    this also uses the newly invented $RT::*DisableFilter settings to know&lt;br /&gt;
 #    to disable their RT account when their LDAP account is disabled.&lt;br /&gt;
 #  * Added $RT::*DisableFilter settings for RT_SiteConfig.pm and refactored&lt;br /&gt;
 #    LdapConfigInfo() to include them. Also refactored logic to grep for&lt;br /&gt;
 #    filter keys rather than enumerate them&lt;br /&gt;
 #  * Added _GetBoundLdapObj() and refactored IsLdapPassword() and&lt;br /&gt;
 #    LookupExternalUserInfo() to use it&lt;br /&gt;
 #  * Added LdapConfigAuthAndInfoAreSame() to compare Auth and Info settings&lt;br /&gt;
 # v1.0b1 (2006.01.06)&lt;br /&gt;
 #  * Added $RT::AuthMethods as basis for auth method lists;&lt;br /&gt;
 #    currently supports LDAP, Internal&lt;br /&gt;
 #  * Implemented Phillip Cole&amp;#039;s suggested $RT::LdapAttrMap&lt;br /&gt;
 #  * Implemented $RT::LdapRTAttrMatchList and $RT::LdapEmailAttrMatchList&lt;br /&gt;
 #    to help guide LDAP searches more effectively&lt;br /&gt;
 #  * Added LdapAuth* and LdapInfo* variables to allow authentication&lt;br /&gt;
 #    and information from separate LDAP servers; didn&amp;#039;t invalidate&lt;br /&gt;
 #    older Ldap{Server,Base,User,Pass,etc} variables.&lt;br /&gt;
 #  * Added LdapConfigInfo() to get integrated config info&lt;br /&gt;
 &lt;br /&gt;
 no warnings qw(redefine);&lt;br /&gt;
 use strict;&lt;br /&gt;
 use Net::LDAP qw(LDAP_SUCCESS LDAP_PARTIAL_RESULTS);&lt;br /&gt;
 use Net::LDAP::Util qw(ldap_error_name);&lt;br /&gt;
 use Net::LDAP::Filter;&lt;br /&gt;
 &lt;br /&gt;
 # We only need Net::SSLeay if we&amp;#039;re using TLS to encrypt our LDAP connections&lt;br /&gt;
 require Net::SSLeay&lt;br /&gt;
   if $RT::LdapTLS || $RT::LdapAuthTLS || $RT::LdapInfoTLS;&lt;br /&gt;
 &lt;br /&gt;
 =head2 LdapConfigInfo&lt;br /&gt;
 &lt;br /&gt;
 returns the LDAP attr mapped to EmailAddress in $RT::LdapAttrMap.&lt;br /&gt;
 &lt;br /&gt;
 If no result is found, returns the ADDRESS passed in.&lt;br /&gt;
 &lt;br /&gt;
 =cut&lt;br /&gt;
 &lt;br /&gt;
 sub LdapConfigInfo {&lt;br /&gt;
     my $self = shift;&lt;br /&gt;
 &lt;br /&gt;
     my %config;&lt;br /&gt;
 &lt;br /&gt;
     # Figure out what&amp;#039;s what&lt;br /&gt;
     $config{&amp;#039;AuthServer&amp;#039;}     = $RT::LdapServer     || $RT::LdapAuthServer;&lt;br /&gt;
     $config{&amp;#039;AuthBase&amp;#039;}       = $RT::LdapBase       || $RT::LdapAuthBase;&lt;br /&gt;
     $config{&amp;#039;AuthUser&amp;#039;}       = $RT::LdapUser       || $RT::LdapAuthUser;&lt;br /&gt;
     $config{&amp;#039;AuthPass&amp;#039;}       = $RT::LdapPass       || $RT::LdapAuthPass;&lt;br /&gt;
     $config{&amp;#039;AuthFilter&amp;#039;}     = $RT::LdapFilter     || $RT::LdapAuthFilter;&lt;br /&gt;
     $config{&amp;#039;AuthGroup&amp;#039;}      = $RT::LdapGroup      || $RT::LdapAuthGroup;&lt;br /&gt;
     $config{&amp;#039;AuthTLS&amp;#039;}        = $RT::LdapTLS        || $RT::LdapAuthTLS;&lt;br /&gt;
     $config{&amp;#039;AuthSSLVersion&amp;#039;} = $RT::LdapSSLVersion || $RT::LdapAuthSSLVersion;&lt;br /&gt;
     $config{&amp;#039;AuthDisableFilter&amp;#039;} =&lt;br /&gt;
       $RT::LdapDisableFilter || $RT::LdapAuthDisableFilter;&lt;br /&gt;
 &lt;br /&gt;
     # We grandfather in LdapGroupAttribute; we&amp;#039;ll default&lt;br /&gt;
     # to &amp;#039;uniqueMember&amp;#039;&lt;br /&gt;
     $config{&amp;#039;AuthGroupAttr&amp;#039;} =&lt;br /&gt;
       $RT::LdapGroupAttribute || $RT::LdapGroupAttr ||&lt;br /&gt;
       $RT::LdapAuthGroupAttr || &amp;#039;uniqueMember&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
     # Figure out what&amp;#039;s what&lt;br /&gt;
     $config{&amp;#039;InfoServer&amp;#039;}     = $RT::LdapServer     || $RT::LdapInfoServer;&lt;br /&gt;
     $config{&amp;#039;InfoBase&amp;#039;}       = $RT::LdapBase       || $RT::LdapInfoBase;&lt;br /&gt;
     $config{&amp;#039;InfoUser&amp;#039;}       = $RT::LdapUser       || $RT::LdapInfoUser;&lt;br /&gt;
     $config{&amp;#039;InfoPass&amp;#039;}       = $RT::LdapPass       || $RT::LdapInfoPass;&lt;br /&gt;
     $config{&amp;#039;InfoFilter&amp;#039;}     = $RT::LdapFilter     || $RT::LdapInfoFilter;&lt;br /&gt;
     $config{&amp;#039;InfoTLS&amp;#039;}        = $RT::LdapTLS        || $RT::LdapInfoTLS;&lt;br /&gt;
     $config{&amp;#039;InfoSSLVersion&amp;#039;} = $RT::LdapSSLVersion || $RT::LdapInfoSSLVersion;&lt;br /&gt;
     $config{&amp;#039;InfoDisableFilter&amp;#039;} =&lt;br /&gt;
       $RT::LdapDisableFilter || $RT::LdapInfoDisableFilter;&lt;br /&gt;
 &lt;br /&gt;
     # Filters need parens if they don&amp;#039;t have &amp;#039;em&lt;br /&gt;
     foreach my $filter (grep {/Filter$/} keys(%config)) {&lt;br /&gt;
         $config{$filter} = &amp;quot;($config{$filter})&amp;quot;&lt;br /&gt;
           unless $config{$filter} =~ /^\(.*\)$/;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return wantarray ? %config : \%config;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 sub LdapConfigAuthAndInfoAreSame {&lt;br /&gt;
     my $self = shift;&lt;br /&gt;
 &lt;br /&gt;
     my %ldap_config = $self-&amp;amp;gt;LdapConfigInfo();&lt;br /&gt;
 &lt;br /&gt;
     # Quick lazy check: same number of keys for Auth and Info?&lt;br /&gt;
     return 0&lt;br /&gt;
       unless scalar(grep {/^Info/} keys(%ldap_config)) ==&lt;br /&gt;
         scalar(grep {/^Auth/} keys(%ldap_config));&lt;br /&gt;
 &lt;br /&gt;
     # Longer check&lt;br /&gt;
     foreach my $key (grep {/^Auth/} keys(%ldap_config)) {&lt;br /&gt;
         my ($key_base) = $key =~ /^Auth(.*)/;&lt;br /&gt;
         return 0&lt;br /&gt;
           unless $ldap_config{&amp;quot;Auth${key_base}&amp;quot;} eq&lt;br /&gt;
             $ldap_config{&amp;quot;Info${key_base}&amp;quot;};&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return 1;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 sub IsLDAPPassword {&lt;br /&gt;
     my $self = shift;&lt;br /&gt;
     my $value = shift;&lt;br /&gt;
 &lt;br /&gt;
     # Don&amp;#039;t ask for external authentication unless enabled in RT_SiteConfig&lt;br /&gt;
     unless ($RT::LdapExternalAuth) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;warning((caller(0))[3],&lt;br /&gt;
                              &amp;#039;$RT::LdapExternalAuth is not set&amp;#039;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     $RT::Logger-&amp;amp;gt;debug(&amp;quot;Trying LDAP authentication\n&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
     # Figure out what&amp;#039;s what&lt;br /&gt;
     my %ldap_config     = $self-&amp;amp;gt;LdapConfigInfo;&lt;br /&gt;
     my $ldap_base       = $ldap_config{&amp;#039;AuthBase&amp;#039;};&lt;br /&gt;
     my $ldap_filter     = $ldap_config{&amp;#039;AuthFilter&amp;#039;};&lt;br /&gt;
     my $ldap_group      = $ldap_config{&amp;#039;AuthGroup&amp;#039;};&lt;br /&gt;
     my $ldap_group_attr = $ldap_config{&amp;#039;AuthGroupAttr&amp;#039;};&lt;br /&gt;
 &lt;br /&gt;
     # Now let&amp;#039;s get connected&lt;br /&gt;
     my $ldap = $self-&amp;amp;gt;_GetBoundLdapObj(&amp;#039;Auth&amp;#039;, version=&amp;amp;gt;3);&lt;br /&gt;
     return unless ($ldap);&lt;br /&gt;
 &lt;br /&gt;
     my $filter_string = &amp;#039;(&amp;amp;amp;(&amp;#039; . $RT::LdapAttrMap-&amp;amp;gt;{&amp;#039;Name&amp;#039;} . &amp;#039;=&amp;#039; .&lt;br /&gt;
       $self-&amp;amp;gt;Name . &amp;#039;)&amp;#039; . $ldap_filter . &amp;#039;)&amp;#039;;&lt;br /&gt;
     my $filter = Net::LDAP::Filter-&amp;amp;gt;new($filter_string);&lt;br /&gt;
 &lt;br /&gt;
     my $ldap_msg = $ldap-&amp;amp;gt;search(base   =&amp;amp;gt; $ldap_base,&lt;br /&gt;
                          filter =&amp;amp;gt; $filter,&lt;br /&gt;
                          attrs  =&amp;amp;gt; [&amp;#039;dn&amp;#039;]);&lt;br /&gt;
 &lt;br /&gt;
     unless ($ldap_msg-&amp;amp;gt;code == LDAP_SUCCESS ||&lt;br /&gt;
             $ldap_msg-&amp;amp;gt;code == LDAP_PARTIAL_RESULTS) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;debug((caller(0))[3], &amp;quot;search for&amp;quot;, $filter-&amp;amp;gt;as_string,&lt;br /&gt;
                           &amp;quot;failed:&amp;quot;, ldap_error_name($ldap_msg-&amp;amp;gt;code), $ldap_msg-&amp;amp;gt;code);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     unless ($ldap_msg-&amp;amp;gt;count == 1) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;info((caller(0))[3], &amp;quot;AUTH FAILED:&amp;quot;, $self-&amp;amp;gt;Name);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     my $ldap_dn = $ldap_msg-&amp;amp;gt;first_entry-&amp;amp;gt;dn;&lt;br /&gt;
     $RT::Logger-&amp;amp;gt;debug((caller(0))[3], &amp;quot;Found LDAP DN:&amp;quot;, $ldap_dn);&lt;br /&gt;
 &lt;br /&gt;
     $ldap_msg = $ldap-&amp;amp;gt;bind($ldap_dn, password =&amp;amp;gt; $value);&lt;br /&gt;
 &lt;br /&gt;
     unless ($ldap_msg-&amp;amp;gt;code == LDAP_SUCCESS) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;info((caller(0))[3], &amp;quot;AUTH FAILED&amp;quot;, $self-&amp;amp;gt;Name,&lt;br /&gt;
                           &amp;quot;(can&amp;#039;t bind:&amp;quot;, ldap_error_name($ldap_msg-&amp;amp;gt;code),&lt;br /&gt;
                           $ldap_msg-&amp;amp;gt;code, &amp;quot;)&amp;quot;);&lt;br /&gt;
         return;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     # Is there an LDAP Group to check?&lt;br /&gt;
     if ($ldap_group) {&lt;br /&gt;
         $filter = Net::LDAP::Filter-&amp;amp;gt;new(&amp;quot;(${ldap_group_attr}=${ldap_dn})&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
         $ldap_msg = $ldap-&amp;amp;gt;search(base   =&amp;amp;gt; $ldap_group,&lt;br /&gt;
                              filter =&amp;amp;gt; $filter,&lt;br /&gt;
                              attrs  =&amp;amp;gt; [&amp;#039;dn&amp;#039;],&lt;br /&gt;
                              scope  =&amp;amp;gt; &amp;#039;base&amp;#039;);&lt;br /&gt;
 &lt;br /&gt;
         unless ($ldap_msg-&amp;amp;gt;code == LDAP_SUCCESS ||&lt;br /&gt;
                 $ldap_msg-&amp;amp;gt;code == LDAP_PARTIAL_RESULTS) {&lt;br /&gt;
             $RT::Logger-&amp;amp;gt;critical((caller(0))[3],&lt;br /&gt;
                                   &amp;quot;Search for&amp;quot;, $filter-&amp;amp;gt;as_string, &amp;quot;failed:&amp;quot;,&lt;br /&gt;
                                   ldap_error_name($ldap_msg-&amp;amp;gt;code), $ldap_msg-&amp;amp;gt;code);&lt;br /&gt;
             return;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         unless ($ldap_msg-&amp;amp;gt;count == 1) {&lt;br /&gt;
             $RT::Logger-&amp;amp;gt;info((caller(0))[3], &amp;quot;AUTH FAILED:&amp;quot;, $self-&amp;amp;gt;Name);&lt;br /&gt;
             return;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     # If we&amp;#039;ve survived to this point, we&amp;#039;re good.&lt;br /&gt;
     $RT::Logger-&amp;amp;gt;info((caller(0))[3], &amp;quot;AUTH OK:&amp;quot;, $self-&amp;amp;gt;Name, &amp;quot;($ldap_dn)&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
     return 1;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 sub IsInternalPassword {&lt;br /&gt;
     my $self = shift;&lt;br /&gt;
     my $value = shift;&lt;br /&gt;
 &lt;br /&gt;
     unless ($self-&amp;amp;gt;HasPassword) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;info((caller(0))[3],&lt;br /&gt;
                           &amp;quot;AUTH FAILED (no passwd):&amp;quot;, $self-&amp;amp;gt;Name);&lt;br /&gt;
         return undef;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     # generate an md5 password&lt;br /&gt;
     if ($self-&amp;amp;gt;_GeneratePassword($value) eq $self-&amp;amp;gt;__Value(&amp;#039;Password&amp;#039;)) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;info((caller(0))[3],&lt;br /&gt;
                           &amp;quot;AUTH OKAY:&amp;quot;, $self-&amp;amp;gt;Name);&lt;br /&gt;
         return 1;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     #  if it&amp;#039;s a historical password we say ok.&lt;br /&gt;
     if ($self-&amp;amp;gt;__Value(&amp;#039;Password&amp;#039;) eq crypt($value, $self-&amp;amp;gt;__Value(&amp;#039;Password&amp;#039;))&lt;br /&gt;
         or $self-&amp;amp;gt;_GeneratePasswordBase64($value) eq $self-&amp;amp;gt;__Value(&amp;#039;Password&amp;#039;))&lt;br /&gt;
       {&lt;br /&gt;
           # ...but upgrade the legacy password inplace.&lt;br /&gt;
           $self-&amp;amp;gt;SUPER::SetPassword( $self-&amp;amp;gt;_GeneratePassword($value) );&lt;br /&gt;
           $RT::Logger-&amp;amp;gt;info((caller(0))[3],&lt;br /&gt;
                             &amp;quot;AUTH OKAY:&amp;quot;, $self-&amp;amp;gt;Name);&lt;br /&gt;
           return 1;&lt;br /&gt;
       }&lt;br /&gt;
 &lt;br /&gt;
     $RT::Logger-&amp;amp;gt;info((caller(0))[3], &amp;quot;AUTH FAILED:&amp;quot;, $self-&amp;amp;gt;Name);&lt;br /&gt;
 &lt;br /&gt;
     return undef;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 # {{{ sub IsPassword&lt;br /&gt;
 &lt;br /&gt;
 sub IsPassword {&lt;br /&gt;
     my $self  = shift;&lt;br /&gt;
     my $value = shift;&lt;br /&gt;
 &lt;br /&gt;
     #TODO there isn&amp;#039;t any apparent way to legitimately ACL this&lt;br /&gt;
 &lt;br /&gt;
     # RT does not allow null passwords&lt;br /&gt;
     if ( !defined($value) || $value eq &amp;#039;&amp;#039; ) {&lt;br /&gt;
         return undef;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if ( $self-&amp;amp;gt;PrincipalObj-&amp;amp;gt;Disabled ) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;info(&amp;quot;Disabled user &amp;quot; . $self-&amp;amp;gt;Name .&lt;br /&gt;
                           &amp;quot; tried to log in&amp;quot; );&lt;br /&gt;
         return undef;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     my @auth_methods = $RT::AuthMethods ? @{$RT::AuthMethods} : (&amp;#039;Internal&amp;#039;);&lt;br /&gt;
     my $success;&lt;br /&gt;
 &lt;br /&gt;
     foreach my $method (@auth_methods) {&lt;br /&gt;
         $method = &amp;quot;Is${method}Password&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
         # Eval this since they might specify an auth method without&lt;br /&gt;
         # an &amp;quot;Is&amp;amp;lt;auth&amp;amp;gt;Password&amp;quot; method implemented&lt;br /&gt;
         eval {&lt;br /&gt;
             $success = $self-&amp;amp;gt;$method($value);&lt;br /&gt;
         };&lt;br /&gt;
 &lt;br /&gt;
         $RT::Logger-&amp;amp;gt;debug((caller(0))[3], &amp;quot;auth method $method&amp;quot;,&lt;br /&gt;
                            ($success ? &amp;#039;SUCCEEDED&amp;#039; : &amp;#039;FAILED&amp;#039;));&lt;br /&gt;
         last if $success;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     # We either got it or we didn&amp;#039;t&lt;br /&gt;
     return $success;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 # }}}&lt;br /&gt;
 &lt;br /&gt;
 =head2 CanonicalizeEmailAddress ADDRESS&lt;br /&gt;
 &lt;br /&gt;
 returns the LDAP attr mapped to EmailAddress in $RT::LdapAttrMap.&lt;br /&gt;
 &lt;br /&gt;
 If no result is found, returns the ADDRESS passed in.&lt;br /&gt;
 &lt;br /&gt;
 =cut&lt;br /&gt;
 &lt;br /&gt;
 sub CanonicalizeEmailAddress {&lt;br /&gt;
     my $self = shift;&lt;br /&gt;
     my $email = shift;&lt;br /&gt;
 &lt;br /&gt;
     my $found = undef;&lt;br /&gt;
     my %params = (&amp;#039;EmailAddress&amp;#039; =&amp;amp;gt; $email);&lt;br /&gt;
 &lt;br /&gt;
     $self = RT::User-&amp;amp;gt;new($RT::SystemUser) unless $self;&lt;br /&gt;
 &lt;br /&gt;
     # Don&amp;#039;t ask for external info unless enabled in RT_SiteConfig&lt;br /&gt;
     unless ($RT::LdapExternalInfo) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;warning((caller(0))[3],&lt;br /&gt;
                              &amp;#039;$RT::LdapExternalInfo is not set&amp;#039;);&lt;br /&gt;
         return $email;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     $RT::Logger-&amp;amp;gt;debug((caller(0))[3], &amp;quot;: called with \&amp;quot;$email\&amp;quot; by&amp;quot;, caller);&lt;br /&gt;
 &lt;br /&gt;
     if ($email) {&lt;br /&gt;
        foreach my $prefix (@{$RT::LdapEmailAttrMatchPrefix}) {&lt;br /&gt;
            if (!$found) {&lt;br /&gt;
                foreach my $attr (@{$RT::LdapEmailAttrMatchList}) {&lt;br /&gt;
                    ($found, %params) =&lt;br /&gt;
                      $self-&amp;amp;gt;LookupExternalUserInfo($attr, &amp;quot;$prefix$email&amp;quot;);&lt;br /&gt;
                    if ($found) {&lt;br /&gt;
                        $RT::Logger-&amp;amp;gt;debug(&amp;quot;FOUND OK&amp;quot;);&lt;br /&gt;
                    }&lt;br /&gt;
                    last if $found;&lt;br /&gt;
 &lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     my $new_email = $found ? $params{&amp;#039;EmailAddress&amp;#039;} : $email;&lt;br /&gt;
 &lt;br /&gt;
     $RT::Logger-&amp;amp;gt;info((caller(0))[3], &amp;quot;$email =&amp;amp;gt;  $new_email&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
     return $new_email;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 # {{{ sub CanonicalizeUserInfo&lt;br /&gt;
 &lt;br /&gt;
 =head2 CanonicalizeUserInfo HASHREF&lt;br /&gt;
 &lt;br /&gt;
 Get all LDAP attrs listed in $RT::LdapAttrMap and put them into&lt;br /&gt;
 the hash referred to by HASHREF.&lt;br /&gt;
 &lt;br /&gt;
 returns true (1) if LDAP lookup was successful, false (undef)&lt;br /&gt;
 in all other cases.&lt;br /&gt;
 &lt;br /&gt;
 =cut&lt;br /&gt;
 &lt;br /&gt;
 sub CanonicalizeUserInfo {&lt;br /&gt;
     my $self = shift;&lt;br /&gt;
     my $args = shift;&lt;br /&gt;
 &lt;br /&gt;
     my $found = 0;&lt;br /&gt;
     my %params;&lt;br /&gt;
 &lt;br /&gt;
     # Don&amp;#039;t ask for external info unless enabled in RT_SiteConfig&lt;br /&gt;
     unless ($RT::LdapExternalInfo) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;warning((caller(0))[3],&lt;br /&gt;
                              &amp;#039;$RT::LdapExternalInfo is not set&amp;#039;);&lt;br /&gt;
         # We return true so that they&amp;#039;ll go forward with what info they have&lt;br /&gt;
         return 1;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     $RT::Logger-&amp;amp;gt;debug((caller(0))[3], &amp;quot; called by&amp;quot;, caller, &amp;quot;with:&amp;quot;,&lt;br /&gt;
                        join(&amp;quot;, &amp;quot;, map {sprintf(&amp;quot;%s: %s&amp;quot;, $_, $args-&amp;amp;gt;{$_})}&lt;br /&gt;
                             sort(keys(%$args))));&lt;br /&gt;
 &lt;br /&gt;
     # $args is a hash ref; to get at its values, use $args-&amp;amp;gt;{&amp;amp;lt;key&amp;amp;gt;}&lt;br /&gt;
     #&lt;br /&gt;
     # $args has keys:&lt;br /&gt;
     #    RealName     - User human name (e.g. Cole, Phillip)&lt;br /&gt;
     #    Name         - Username or login (e.g. ukpgc)&lt;br /&gt;
     #    EmailAddress - Email address (e.g. phillip.cole@company.com)&lt;br /&gt;
     #    Comments     - Comments created during creation&lt;br /&gt;
 &lt;br /&gt;
     # How may I know thee? Let me count the ways ...&lt;br /&gt;
     foreach my $rt_attr (@{$RT::LdapRTAttrMatchList}) {&lt;br /&gt;
         next unless $args-&amp;amp;gt;{$rt_attr};&lt;br /&gt;
 &lt;br /&gt;
         ($found, %params) =&lt;br /&gt;
           $self-&amp;amp;gt;LookupExternalUserInfo($RT::LdapAttrMap-&amp;amp;gt;{$rt_attr},&lt;br /&gt;
                                            $args-&amp;amp;gt;{$rt_attr});&lt;br /&gt;
         last if $found;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if ($found) {&lt;br /&gt;
         # It&amp;#039;s important that we always have a canonical email address&lt;br /&gt;
         if ($params{&amp;#039;EmailAddress&amp;#039;}) {&lt;br /&gt;
             my $email =&lt;br /&gt;
               $self-&amp;amp;gt;CanonicalizeEmailAddress($params{&amp;#039;EmailAddress&amp;#039;});&lt;br /&gt;
             $params{&amp;#039;EmailAddress&amp;#039;} = $email if $email;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         %$args = (%$args, %params);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     $RT::Logger-&amp;amp;gt;info((caller(0))[3], &amp;quot;returning&amp;quot;,&lt;br /&gt;
                        join(&amp;quot;, &amp;quot;, map {sprintf(&amp;quot;%s: %s&amp;quot;, $_, $args-&amp;amp;gt;{$_})}&lt;br /&gt;
                             sort(keys(%$args))));&lt;br /&gt;
     ### HACK: The config var below is to overcome the (IMO) bug in&lt;br /&gt;
     ### RT::User::Create() which expects this function to always&lt;br /&gt;
     ### return true or rejects the user for creation. This should be&lt;br /&gt;
     ### a different config var (CreateUncanonicalizedUsers) and&lt;br /&gt;
     ### should be honored in RT::User::Create()&lt;br /&gt;
     return $found || $RT::LdapAutoCreateNonLdapUsers;&lt;br /&gt;
 }&lt;br /&gt;
 # }}}&lt;br /&gt;
 &lt;br /&gt;
 sub _GetBoundLdapObj {&lt;br /&gt;
     my $self = shift;&lt;br /&gt;
     my ($service, @ldap_args) = @_;&lt;br /&gt;
 &lt;br /&gt;
     # Figure out what&amp;#039;s what&lt;br /&gt;
     my %ldap_config     = $self-&amp;amp;gt;LdapConfigInfo();&lt;br /&gt;
     my $ldap_server     = $ldap_config{&amp;quot;${service}Server&amp;quot;};&lt;br /&gt;
     my $ldap_base       = $ldap_config{&amp;quot;${service}Base&amp;quot;};&lt;br /&gt;
     my $ldap_user       = $ldap_config{&amp;quot;${service}User&amp;quot;};&lt;br /&gt;
     my $ldap_pass       = $ldap_config{&amp;quot;${service}Pass&amp;quot;};&lt;br /&gt;
     my $ldap_filter     = $ldap_config{&amp;quot;${service}Filter&amp;quot;};&lt;br /&gt;
     my $ldap_tls        = $ldap_config{&amp;quot;${service}TLS&amp;quot;};&lt;br /&gt;
     my $ldap_ssl_ver    = $ldap_config{&amp;quot;${service}SSLVersion&amp;quot;};&lt;br /&gt;
 &lt;br /&gt;
     my $ldap = new Net::LDAP($ldap_server, @ldap_args);&lt;br /&gt;
     unless ($ldap) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;critical((caller(0))[3],&lt;br /&gt;
                               &amp;quot;: Cannot connect to $ldap_server&amp;quot;);&lt;br /&gt;
         return undef;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     if ($ldap_tls) {&lt;br /&gt;
         $Net::SSLeay::ssl_version = $ldap_ssl_ver;&lt;br /&gt;
         # Thanks to David Narayan for the fault tolerance bits&lt;br /&gt;
         eval { $ldap-&amp;amp;gt;start_tls; };&lt;br /&gt;
         if ($@) {&lt;br /&gt;
             $RT::Logger-&amp;amp;gt;critical((caller(0))[3], &amp;quot;Can&amp;#039;t start TLS: $@&amp;quot;);&lt;br /&gt;
             return;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     my $msg = undef;&lt;br /&gt;
 &lt;br /&gt;
     if ($ldap_user) {&lt;br /&gt;
         $msg = $ldap-&amp;amp;gt;bind($ldap_user, password =&amp;amp;gt; $ldap_pass);&lt;br /&gt;
     } else {&lt;br /&gt;
         $msg = $ldap-&amp;amp;gt;bind;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     unless ($msg-&amp;amp;gt;code == LDAP_SUCCESS) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;critical((caller(0))[3], &amp;quot;Can&amp;#039;t bind:&amp;quot;,&lt;br /&gt;
                              ldap_error_name($msg-&amp;amp;gt;code), $msg-&amp;amp;gt;code);&lt;br /&gt;
         return undef;&lt;br /&gt;
     } else {&lt;br /&gt;
         return $ldap;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 # {{{ sub LookupExternalUserInfo&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 =head2 LookupExternalUserInfo KEY VALUE [BASE_DN]&lt;br /&gt;
 &lt;br /&gt;
 LookupExternalUserInfo takes a key/value pair with optional LDAP baseDN,&lt;br /&gt;
 looks it up in LDAP, and returns a params hash containing all LDAP attrs&lt;br /&gt;
 listed in $RT::LdapAttrMap, suitable for creating an RT::User object.&lt;br /&gt;
 &lt;br /&gt;
 Returns a tuple, ($found, %params)&lt;br /&gt;
 &lt;br /&gt;
 =cut&lt;br /&gt;
 &lt;br /&gt;
 sub LookupExternalUserInfo {&lt;br /&gt;
     my $self = shift;&lt;br /&gt;
     my ($key, $value, $baseDN) = @_;&lt;br /&gt;
 &lt;br /&gt;
     my $found = 0;&lt;br /&gt;
     my %params = (Name         =&amp;amp;gt; undef,&lt;br /&gt;
                   EmailAddress =&amp;amp;gt; undef,&lt;br /&gt;
                   RealName     =&amp;amp;gt; undef);&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
     # Don&amp;#039;t ask for external info unless enabled in RT_SiteConfig&lt;br /&gt;
     unless ($RT::LdapExternalInfo) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;warning((caller(0))[3],&lt;br /&gt;
                              &amp;#039;$RT::LdapExternalInfo is not set&amp;#039;);&lt;br /&gt;
         return ($found, %params);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     # Figure out what&amp;#039;s what&lt;br /&gt;
     my %ldap_config     = $self-&amp;amp;gt;LdapConfigInfo();&lt;br /&gt;
     my $ldap_base       = $ldap_config{&amp;#039;InfoBase&amp;#039;};&lt;br /&gt;
     my $ldap_filter     = $ldap_config{&amp;#039;InfoFilter&amp;#039;};&lt;br /&gt;
 &lt;br /&gt;
     $baseDN = $baseDN || $ldap_base;&lt;br /&gt;
 &lt;br /&gt;
     ### This should use Net::LDAP::Filter, too&lt;br /&gt;
     my $filter = ($key &amp;amp;amp;&amp;amp;amp; $value) ? &amp;quot;@{[ $key ]}=$value&amp;quot; : &amp;quot;&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     $RT::Logger-&amp;amp;gt;debug((caller(0))[3], &amp;quot;called with baseDN \&amp;quot;$baseDN\&amp;quot;&amp;quot;,&lt;br /&gt;
                        &amp;quot;and filter \&amp;quot;$filter\&amp;quot; by&amp;quot;, caller);&lt;br /&gt;
 &lt;br /&gt;
     unless ($baseDN) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;critical((caller(0))[3] . &amp;quot; No baseDN given&amp;quot;);&lt;br /&gt;
         return ($found, %params);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     my $ldap = $self-&amp;amp;gt;_GetBoundLdapObj(&amp;#039;Info&amp;#039;);&lt;br /&gt;
 &lt;br /&gt;
     return ($found, %params) unless ($ldap);&lt;br /&gt;
 &lt;br /&gt;
     # Get the list of unique attrs we need&lt;br /&gt;
     my %ldap_attrs = map {$_ =&amp;amp;gt; 1} values(%{$RT::LdapAttrMap});&lt;br /&gt;
     my @attrs = keys(%ldap_attrs);&lt;br /&gt;
     my $ldap_msg = $ldap-&amp;amp;gt;search(base   =&amp;amp;gt; $baseDN,&lt;br /&gt;
                                  filter =&amp;amp;gt; $filter,&lt;br /&gt;
                                  attrs  =&amp;amp;gt; \@attrs);&lt;br /&gt;
 &lt;br /&gt;
     if ($ldap_msg-&amp;amp;gt;code != LDAP_SUCCESS and&lt;br /&gt;
         $ldap_msg-&amp;amp;gt;code != LDAP_PARTIAL_RESULTS) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;critical((caller(0))[3],&lt;br /&gt;
                               &amp;quot;: Search for $filter failed: &amp;quot;,&lt;br /&gt;
                               ldap_error_name($ldap_msg-&amp;amp;gt;code), $ldap_msg-&amp;amp;gt;code);&lt;br /&gt;
 &lt;br /&gt;
         # Why on earth do we return the same RealName, just quoted?!&lt;br /&gt;
         $params{&amp;#039;RealName&amp;#039;} = &amp;quot;\&amp;quot;$params{&amp;#039;RealName&amp;#039;}\&amp;quot;&amp;quot;;&lt;br /&gt;
     } else {&lt;br /&gt;
         # If there&amp;#039;s only one match, we&amp;#039;re good; more than one and&lt;br /&gt;
         # we don&amp;#039;t know which is the right one so we skip it.&lt;br /&gt;
         if ($ldap_msg-&amp;amp;gt;count == 1) {&lt;br /&gt;
             my $entry = $ldap_msg-&amp;amp;gt;first_entry();&lt;br /&gt;
             foreach my $key (keys(%{$RT::LdapAttrMap})) {&lt;br /&gt;
                 if ($RT::LdapAttrMap-&amp;amp;gt;{$key} eq &amp;#039;dn&amp;#039;) {&lt;br /&gt;
                     $params{$key} = $entry-&amp;amp;gt;dn();&lt;br /&gt;
                 } else {&lt;br /&gt;
                     $params{$key} =&lt;br /&gt;
                       ($entry-&amp;amp;gt;get_value($RT::LdapAttrMap-&amp;amp;gt;{$key}))[0];&lt;br /&gt;
                 }&lt;br /&gt;
             }&lt;br /&gt;
             $found = 1;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     $ldap_msg = $ldap-&amp;amp;gt;unbind();&lt;br /&gt;
     if ($ldap_msg-&amp;amp;gt;code != LDAP_SUCCESS) {&lt;br /&gt;
         $RT::Logger-&amp;amp;gt;critical((caller(0))[3],&lt;br /&gt;
                               &amp;quot;: Could not unbind: &amp;quot;,&lt;br /&gt;
                               ldap_error_name($ldap_msg-&amp;amp;gt;code), $ldap_msg-&amp;amp;gt;code);&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     undef $ldap;&lt;br /&gt;
     undef $ldap_msg;&lt;br /&gt;
 &lt;br /&gt;
     $RT::Logger-&amp;amp;gt;info((caller(0))[3],&lt;br /&gt;
                        &amp;quot;: $baseDN $filter =&amp;amp;gt; &amp;quot;,&lt;br /&gt;
                        join(&amp;quot;, &amp;quot;, map {sprintf(&amp;quot;%s: %s&amp;quot;, $_, $params{$_})}&lt;br /&gt;
                             sort(keys(%params))));&lt;br /&gt;
 &lt;br /&gt;
     return ($found, %params);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 # }}}&lt;br /&gt;
 &lt;br /&gt;
 sub UpdateFromLdap {&lt;br /&gt;
     my $self = shift;&lt;br /&gt;
     my $updated = 0;&lt;br /&gt;
     my $msg = &amp;quot;User NOT updated&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
     my %ldap_config = $self-&amp;amp;gt;LdapConfigInfo;&lt;br /&gt;
 &lt;br /&gt;
     my @services;&lt;br /&gt;
     push(@services, &amp;#039;Auth&amp;#039;) if $ldap_config{&amp;#039;AuthDisableFilter&amp;#039;};&lt;br /&gt;
     push(@services, &amp;#039;Info&amp;#039;) if $ldap_config{&amp;#039;InfoDisableFilter&amp;#039;};&lt;br /&gt;
 &lt;br /&gt;
     # If Auth and Info use exactly the same params, only check one&lt;br /&gt;
     @services = (&amp;#039;Auth&amp;#039;)&lt;br /&gt;
       if (@services &amp;amp;amp;&amp;amp;amp; $self-&amp;amp;gt;LdapConfigAuthAndInfoAreSame);&lt;br /&gt;
 &lt;br /&gt;
     foreach my $service (@services) {&lt;br /&gt;
         my $ldap = $self-&amp;amp;gt;_GetBoundLdapObj($service);&lt;br /&gt;
         next unless $ldap;&lt;br /&gt;
 &lt;br /&gt;
         my $ldap_base    = $ldap_config{&amp;quot;${service}Base&amp;quot;};&lt;br /&gt;
         my $ldap_filter  = $ldap_config{&amp;quot;${service}Filter&amp;quot;};&lt;br /&gt;
         my $ldap_disable = $ldap_config{&amp;quot;${service}DisableFilter&amp;quot;};&lt;br /&gt;
 &lt;br /&gt;
         # Construct the complex filter&lt;br /&gt;
         my $filter = &amp;#039;(&amp;amp;amp;&amp;#039; . $ldap_filter . $ldap_disable .&lt;br /&gt;
           &amp;#039;(uid=&amp;#039; . $self-&amp;amp;gt;Name . &amp;#039;))&amp;#039;;&lt;br /&gt;
 &lt;br /&gt;
         my $disabled_users = $ldap-&amp;amp;gt;search(base   =&amp;amp;gt; $ldap_base,&lt;br /&gt;
                                            filter =&amp;amp;gt; $filter,&lt;br /&gt;
                                            attrs  =&amp;amp;gt; [&amp;#039;uid&amp;#039;]);&lt;br /&gt;
 &lt;br /&gt;
         if ($disabled_users-&amp;amp;gt;count) {&lt;br /&gt;
             my $UserObj = RT::User-&amp;amp;gt;new($RT::SystemUser);&lt;br /&gt;
             $UserObj-&amp;amp;gt;Load($self-&amp;amp;gt;Name);&lt;br /&gt;
             my ($val, $message) = $UserObj-&amp;amp;gt;SetDisabled(1);&lt;br /&gt;
 &lt;br /&gt;
             $RT::Logger-&amp;amp;gt;info(&amp;quot;DISABLED user &amp;quot; . $self-&amp;amp;gt;Name .&lt;br /&gt;
                               &amp;quot; per LDAP ($val, $message)\n&amp;quot;);&lt;br /&gt;
             $msg = &amp;quot;User disabled&amp;quot;;&lt;br /&gt;
         } else {&lt;br /&gt;
             # Update their info from LDAP&lt;br /&gt;
             my %args = (Name =&amp;amp;gt; $self-&amp;amp;gt;Name);&lt;br /&gt;
             $self-&amp;amp;gt;CanonicalizeUserInfo(\%args);&lt;br /&gt;
 &lt;br /&gt;
             foreach my $key (sort(keys(%args))) {&lt;br /&gt;
                 next unless $args{$key};&lt;br /&gt;
                 my $method = &amp;quot;Set$key&amp;quot;;&lt;br /&gt;
                 $self-&amp;amp;gt;$method($args{$key});&lt;br /&gt;
             }&lt;br /&gt;
 &lt;br /&gt;
             $updated = 1;&lt;br /&gt;
             $RT::Logger-&amp;amp;gt;debug(&amp;quot;UPDATED user &amp;quot; . $self-&amp;amp;gt;Name . &amp;quot; from LDAP\n&amp;quot;);&lt;br /&gt;
             $msg = &amp;#039;User updated&amp;#039;;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     return ($updated, $msg);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 1;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
[[Category:пензец]]&lt;/div&gt;</summary>
		<author><name>195.16.40.50</name></author>
	</entry>
</feed>