=head1 NAME
-RT::Authen::ExternalAuth - RT Authentication using External Sources
+ RT::Authen::ExternalAuth - RT Authentication using External Sources
=head1 DESCRIPTION
-A complete package for adding external authentication mechanisms
-to RT. It currently supports LDAP via Net::LDAP and External Database
-authentication for any database with an installed DBI driver.
+ A complete package for adding external authentication mechanisms
+ to RT. It currently supports LDAP via Net::LDAP and External Database
+ authentication for any database with an installed DBI driver.
-It also allows for authenticating cookie information against an
-external database through the use of the RT-Authen-CookieAuth extension.
+ It also allows for authenticating cookie information against an
+ external database through the use of the RT-Authen-CookieAuth extension.
-=head1 CONFIGURATION
+=begin testing
-=head2 Generic
+ok(require RT::Authen::ExternalAuth);
-=head3 attr_match_list
-
-The list of RT attributes that uniquely identify a user. It's
-recommended to use 'Name' and 'EmailAddress' to save
-encountering problems later. Example:
-
- 'attr_match_list' => [
- 'Name',
- 'EmailAddress',
- 'RealName',
- 'WorkPhone',
- ],
-
-=head3 attr_map
-
-Mapping of RT attributes on to attributes in the external source.
-Example:
-
- 'attr_map' => {
- 'Name' => 'sAMAccountName',
- 'EmailAddress' => 'mail',
- 'Organization' => 'physicalDeliveryOfficeName',
- 'RealName' => 'cn',
- ...
- },
-
-Since version 0.10 it's possible to map one RT field to multiple
-external attributes, for example:
-
- attr_map => {
- EmailAddress => ['mail', 'alias'],
- ...
- },
-
-Note that only one value storred in RT. However, search goes by
-all external attributes if such RT field list in L</attr_match_list>.
-On create or update entered value is used as long as it's valid.
-If user didn't enter value then value stored in the first external
-attribute is used. Config example:
-
- attr_match_list => ['Name', 'EmailAddress'],
- attr_map => {
- Name => 'account',
- EmailAddress => ['mail', 'alias'],
- ...
- },
+=end testing
=cut
# Update their info from external service using the username as the lookup key
# CanonicalizeUserInfo will work out for itself which service to use
# Passing it a service instead could break other RT code
- my %args;
- $UserObj->CanonicalizeUserInfo( \%args );
+ my %args = (Name => $username);
+ $UserObj->CanonicalizeUserInfo(\%args);
# For each piece of information returned by CanonicalizeUserInfo,
# run the Set method for that piece of info to change it for the user
my $UserObj = shift;
my $args = shift;
-
- WorkaroundAutoCreate( $UserObj, $args );
-
- my $current_value = sub {
- my $field = shift;
- return $args->{ $field } if keys %$args;
-
- return undef unless $UserObj->can( $field );
- return $UserObj->$field();
- };
-
- my ($found, $config, %params) = (0);
-
+
+ my $found = 0;
+ my %params = (Name => undef,
+ EmailAddress => undef,
+ RealName => undef);
+
$RT::Logger->debug( (caller(0))[3],
"called by",
caller,
sort(keys(%$args))));
# Get the list of defined external services
- my @info_services = $RT::ExternalInfoPriority ? @{$RT::ExternalInfoPriority} : ();
+ my @info_services = $RT::ExternalInfoPriority ? @{$RT::ExternalInfoPriority} : undef;
# For each external service...
foreach my $service (@info_services) {
$service);
# Get the config for the service so that we know what attrs we can canonicalize
- $config = $RT::ExternalSettings->{$service};
-
+ my $config = $RT::ExternalSettings->{$service};
+
if($config->{'type'} eq 'cookie'){
$RT::Logger->debug("You cannot use SSO cookies as an information service!");
next;
}
- # Get the list of unique attrs we need
- my @service_attrs = do {
- my %seen;
- grep !$seen{$_}++, map ref($_)? @$_ : ($_), values %{ $config->{'attr_map'} }
- };
-
# For each attr we've been told to canonicalize in the match list
+ my $attr_map = (defined $config->{'lookup_attr_map'}) ? $config->{'lookup_attr_map'} : $config->{'attr_map'};
foreach my $rt_attr (@{$config->{'attr_match_list'}}) {
# Jump to the next attr in $args if this one isn't in the attr_match_list
$RT::Logger->debug( "Attempting to use this canonicalization key:",$rt_attr);
- my $value = $current_value->( $rt_attr );
- unless( defined $value && length $value ) {
+ unless(defined($args->{$rt_attr})) {
$RT::Logger->debug("This attribute (",
$rt_attr,
- ") is null or incorrectly defined in the attr_match_list for this service (",
+ ") is null or incorrectly defined in the attr_map for this service (",
$service,
")");
next;
}
# Else, use it as a canonicalization key and lookup the user info
- my $key = $config->{'attr_map'}->{$rt_attr};
- unless ( $key ) {
- $RT::Logger->warning(
- "No mapping for $rt_attr in attr_map for this service ($service)"
- );
+ my $key = $attr_map->{$rt_attr};
+ my $value = $args->{$rt_attr};
+
+ # Check to see that the key being asked for is defined in the config's attr_map
+ my $valid = 0;
+ my ($attr_key, $attr_value);
+ while (($attr_key, $attr_value) = each %$attr_map) {
+ $valid = 1 if ($key eq $attr_value);
+ }
+ unless ($valid){
+ $RT::Logger->debug( "This key (",
+ $key,
+ "is not a valid attribute key (",
+ $service,
+ ")");
next;
}
-
+
# Use an if/elsif structure to do a lookup with any custom code needed
# for any given type of external service, or die if no code exists for
# the service requested.
if($config->{'type'} eq 'ldap'){
- ($found, %params) = RT::Authen::ExternalAuth::LDAP::CanonicalizeUserInfo($service,$key,$value, \@service_attrs);
+ ($found, %params) = RT::Authen::ExternalAuth::LDAP::CanonicalizeUserInfo($service,$key,$value);
} elsif ($config->{'type'} eq 'db') {
- ($found, %params) = RT::Authen::ExternalAuth::DBI::CanonicalizeUserInfo($service,$key,$value, \@service_attrs);
+ ($found, %params) = RT::Authen::ExternalAuth::DBI::CanonicalizeUserInfo($service,$key,$value);
} else {
$RT::Logger->debug( (caller(0))[3],
"does not consider",
# Don't Check any more services
last if $found;
}
-
- unless ( $found ) {
- ### HACK: The config var below is to overcome the (IMO) bug in
- ### RT::User::Create() which expects this function to always
- ### return true or rejects the user for creation. This should be
- ### a different config var (CreateUncanonicalizedUsers) and
- ### should be honored in RT::User::Create()
- return($RT::AutoCreateNonExternalUsers);
- }
-
- # If found let's build back RT's fields
- my %res;
- while ( my ($k, $v) = each %{ $config->{'attr_map'} } ) {
- unless ( ref $v ) {
- $res{ $k } = $params{ $v };
- next;
- }
-
- my $current = $current_value->( $k );
- unless ( defined $current ) {
- $res{ $k } = (grep defined && length, map $params{ $_ }, @$v)[0];
- } else {
- unless ( grep defined && length && $_ eq $current, map $params{ $_ }, @$v ) {
- $res{ $k } = (grep defined && length, map $params{ $_ }, @$v)[0];
- }
- }
- }
-
- # It's important that we always have a canonical email address
- if ($res{'EmailAddress'}) {
- $res{'EmailAddress'} = $UserObj->CanonicalizeEmailAddress($res{'EmailAddress'});
- }
-
+
+ # If found, Canonicalize Email Address and
# update the args hash that we were given the hashref for
- %$args = (%$args, %res);
+ if ($found) {
+ # It's important that we always have a canonical email address
+ if ($params{'EmailAddress'}) {
+ $params{'EmailAddress'} = $UserObj->CanonicalizeEmailAddress($params{'EmailAddress'});
+ }
+ %$args = (%$args, %params);
+ }
$RT::Logger->info( (caller(0))[3],
"returning",
join(", ", map {sprintf("%s: %s", $_, $args->{$_})}
sort(keys(%$args))));
- return $found;
+ ### HACK: The config var below is to overcome the (IMO) bug in
+ ### RT::User::Create() which expects this function to always
+ ### return true or rejects the user for creation. This should be
+ ### a different config var (CreateUncanonicalizedUsers) and
+ ### should be honored in RT::User::Create()
+ return($found || $RT::AutoCreateNonExternalUsers);
+
}
{
};
}
-{
- no warnings 'redefine';
- my $orig = RT::User->can('LoadByCols');
- *RT::User::LoadByCols = sub {
- my $self = shift;
- my %args = @_;
-
- my $rv = $orig->( $self, %args );
- return $rv if $self->id;
-
-# we couldn't load a user. ok, but user may exist anyway. It may happen in the following
-# cases:
-# 1) Service has multiple fields in attr_match_list, it's important when we have Name
-# and EmailAddress in there.
-
- my (%other) = FindRecordsByOtherFields( $self, %args );
- while ( my ($search_by, $values) = each %other ) {
- foreach my $value ( @$values ) {
- my $rv = $orig->( $self, $search_by => $value );
- return $rv if $self->id;
- }
- }
-
-# 2) RT fields in attr_match_list are mapped to multiple attributes in an external
-# source, for example: attr_map => { EmailAddress => [qw(mail alias1 alias2 alias3)], }
- my ($search_by, @alternatives) = FindRecordsWithAlternatives( $self, %args );
- foreach my $value ( @alternatives ) {
- my $rv = $orig->( $self, %args, $search_by => $value );
- return $rv if $self->id;
- }
-
- return $rv;
- };
-}
-
-sub FindRecordsWithAlternatives {
- my $user = shift;
- my %args = @_;
-
- # find services that may have alternative values for a field we search by
- my @info_services = $RT::ExternalInfoPriority ? @{$RT::ExternalInfoPriority} : ();
- foreach my $service ( splice @info_services ) {
- my $config = $RT::ExternalSettings->{ $service };
- next if $config->{'type'} eq 'cookie';
- next unless
- grep ref $config->{'attr_map'}{ $_ },
- @{ $config->{'attr_match_list'} };
-
- push @info_services, $service;
- }
- return unless @info_services;
-
- # find user in external service and fetch alternative values
- # for a field
- foreach my $service (@info_services) {
- my $config = $RT::ExternalSettings->{$service};
-
- my $search_by = undef;
- foreach my $rt_attr ( @{ $config->{'attr_match_list'} } ) {
- next unless exists $args{ $rt_attr }
- && defined $args{ $rt_attr }
- && length $args{ $rt_attr };
- next unless ref $config->{'attr_map'}{ $rt_attr };
-
- $search_by = $rt_attr;
- last;
- }
- next unless $search_by;
-
- my @search_args = (
- $service,
- $config->{'attr_map'}{ $search_by },
- $args{ $search_by },
- $config->{'attr_map'}{ $search_by },
- );
-
- my ($found, %params);
- if($config->{'type'} eq 'ldap') {
- ($found, %params) = RT::Authen::ExternalAuth::LDAP::CanonicalizeUserInfo( @search_args );
- } elsif ($config->{'type'} eq 'db') {
- ($found, %params) = RT::Authen::ExternalAuth::DBI::CanonicalizeUserInfo( @search_args );
- } else {
- $RT::Logger->debug( (caller(0))[3],
- "does not consider",
- $service,
- "a valid information service");
- }
- next unless $found;
-
- my @alternatives = grep defined && length && $_ ne $args{ $search_by }, values %params;
-
- # Don't Check any more services
- return @alternatives;
- }
- return;
-}
-
-sub FindRecordsByOtherFields {
- my $user = shift;
- my %args = @_;
-
- my @info_services = $RT::ExternalInfoPriority ? @{$RT::ExternalInfoPriority} : ();
- foreach my $service ( splice @info_services ) {
- my $config = $RT::ExternalSettings->{ $service };
- next if $config->{'type'} eq 'cookie';
- next unless @{ $config->{'attr_match_list'} } > 1;
-
- push @info_services, $service;
- }
- return unless @info_services;
-
- # find user in external service and fetch alternative values
- # for a field
- foreach my $service (@info_services) {
- my $config = $RT::ExternalSettings->{$service};
-
- foreach my $search_by ( @{ $config->{'attr_match_list'} } ) {
- next unless exists $args{ $search_by }
- && defined $args{ $search_by }
- && length $args{ $search_by };
-
- my @fetch;
- foreach my $field ( @{ $config->{'attr_match_list'} } ) {
- next if $field eq $search_by;
-
- my $external = $config->{'attr_map'}{ $field };
- push @fetch, ref $external? (@$external) : ($external);
- }
- my @search_args = (
- $service,
- $config->{'attr_map'}{ $search_by },
- $args{ $search_by },
- \@fetch,
- );
-
- my ($found, %params);
- if($config->{'type'} eq 'ldap') {
- ($found, %params) = RT::Authen::ExternalAuth::LDAP::CanonicalizeUserInfo( @search_args );
- } elsif ($config->{'type'} eq 'db') {
- ($found, %params) = RT::Authen::ExternalAuth::DBI::CanonicalizeUserInfo( @search_args );
- } else {
- $RT::Logger->debug( (caller(0))[3],
- "does not consider",
- $service,
- "a valid information service");
- }
- next unless $found;
-
- my %res =
- map { $_ => $config->{'attr_map'}{ $_ } }
- grep defined $config->{'attr_map'}{ $_ },
- grep $_ ne $search_by,
- @{ $config->{'attr_match_list'} }
- ;
- foreach my $value ( values %res ) {
- $value = ref $value? [ map $params{$_}, @$value ] : [ $params{ $value } ];
- }
- return %res;
- }
- }
- return;
-}
-
-=head2 WorkaroundAutoCreate
-
-RT has C<$AutoCreate> option in the config. However, up to RT 4.0.0 this
-option is no used when account created by incomming email. This module
-workarounds this problem.
-
-=cut
-
-sub WorkaroundAutoCreate {
- my $user = shift;
- my $args = shift;
-
- # CreateUser in RT::Interface::Email doesn't account $RT::AutoCreate
- # config option. Let's workaround it.
-
- return unless $RT::AutoCreate && keys %$RT::AutoCreate;
- return unless keys %$args; # no args - update
- return unless (caller(4))[3] eq 'RT::Interface::Email::CreateUser';
-
- my %tmp = %$RT::AutoCreate;
- delete @tmp{qw(Name EmailAddress RealName Comments)};
- %$args = (%$args, %$RT::AutoCreate);
-}
-
1;
require Net::SSLeay if $RT::ExternalServiceUsesSSLorTLS;\r
\r
sub GetAuth {\r
+ \r
my ($service, $username, $password) = @_;\r
\r
my $config = $RT::ExternalSettings->{$service};\r
my $ldap = _GetBoundLdapObj($config);\r
return 0 unless ($ldap);\r
\r
- $filter = '(&'\r
- .'('. $attr_map->{'Name'} . '=' . $username . ')' . \r
- $filter\r
- .')';\r
-\r
- my $ldap_msg = PerformSearch(\r
- $ldap,\r
- base => $base,\r
- filter => $filter,\r
- attrs => \@attrs\r
- ) or return 0;;\r
+ $filter = Net::LDAP::Filter->new( '(&(' . \r
+ $attr_map->{'Name'} . \r
+ '=' . \r
+ $username . \r
+ ')' . \r
+ $filter . \r
+ ')'\r
+ );\r
+\r
+ $RT::Logger->debug( "LDAP Search === ",\r
+ "Base:",\r
+ $base,\r
+ "== Filter:", \r
+ $filter->as_string,\r
+ "== Attrs:", \r
+ join(',',@attrs));\r
+\r
+ my $ldap_msg = $ldap->search( base => $base,\r
+ filter => $filter,\r
+ attrs => \@attrs);\r
+\r
+ unless ($ldap_msg->code == LDAP_SUCCESS || $ldap_msg->code == LDAP_PARTIAL_RESULTS) {\r
+ $RT::Logger->debug( "search for", \r
+ $filter->as_string, \r
+ "failed:", \r
+ ldap_error_name($ldap_msg->code), \r
+ $ldap_msg->code);\r
+ # Didn't even get a partial result - jump straight to the next external auth service\r
+ return 0;\r
+ }\r
\r
unless ($ldap_msg->count == 1) {\r
$RT::Logger->info( $service,\r
# The user is authenticated ok, but is there an LDAP Group to check?\r
if ($group) {\r
# If we've been asked to check a group...\r
- $ldap_msg = PerformSearch(\r
- $ldap,\r
- base => $group,\r
- filter => "(${group_attr}=${ldap_dn})",\r
- attrs => \@attrs,\r
- scope => 'base'\r
- ) or return 0;\r
+ $filter = Net::LDAP::Filter->new("(${group_attr}=${ldap_dn})");\r
+ \r
+ $RT::Logger->debug( "LDAP Search === ",\r
+ "Base:",\r
+ $base,\r
+ "== Filter:", \r
+ $filter->as_string,\r
+ "== Attrs:", \r
+ join(',',@attrs));\r
+ \r
+ $ldap_msg = $ldap->search( base => $group,\r
+ filter => $filter,\r
+ attrs => \@attrs,\r
+ scope => 'base');\r
+\r
+ # And the user isn't a member:\r
+ unless ($ldap_msg->code == LDAP_SUCCESS || \r
+ $ldap_msg->code == LDAP_PARTIAL_RESULTS) {\r
+ $RT::Logger->critical( "Search for", \r
+ $filter->as_string, \r
+ "failed:",\r
+ ldap_error_name($ldap_msg->code), \r
+ $ldap_msg->code);\r
+\r
+ # Fail auth - jump to next external auth service\r
+ return 0;\r
+ }\r
\r
unless ($ldap_msg->count == 1) {\r
$RT::Logger->info( $service,\r
\r
sub CanonicalizeUserInfo {\r
\r
- my ($service, $key, $value, $attrs) = @_;\r
+ my ($service, $key, $value) = @_;\r
+\r
+ my $found = 0;\r
+ my %params = (Name => undef,\r
+ EmailAddress => undef,\r
+ RealName => undef);\r
\r
# Load the config\r
my $config = $RT::ExternalSettings->{$service};\r
+ \r
+ # Figure out what's what\r
+ my $base = $config->{'base'};\r
+ my $filter = $config->{'filter'};\r
\r
- my $filter = JoinFilters(\r
- '&',\r
- JoinFilters('|', map "($_=$value)", ref $key? @$key: ($key) ),\r
- $config->{'filter'},\r
- ) or return (0);\r
+ # Get the list of unique attrs we need\r
+ my @attrs = values(%{$config->{'attr_map'}});\r
+\r
+ # This is a bit confusing and probably broken. Something to revisit..\r
+ my $filter_addition = ($key && $value) ? "(". $key . "=$value)" : "";\r
+ if(defined($filter) && ($filter ne "()")) {\r
+ $filter = Net::LDAP::Filter->new( "(&" . \r
+ $filter . \r
+ $filter_addition . \r
+ ")"\r
+ ); \r
+ } else {\r
+ $RT::Logger->debug( "LDAP Filter invalid or not present.");\r
+ }\r
\r
- my $base = $config->{'base'};\r
unless (defined($base)) {\r
$RT::Logger->critical( (caller(0))[3],\r
"LDAP baseDN not defined");\r
# Drop out to the next external information service\r
- return (0);\r
+ return ($found, %params);\r
}\r
\r
# Get a Net::LDAP object based on the config we provide\r
\r
# Jump to the next external information service if we can't get one, \r
# errors should be logged by _GetBoundLdapObj so we don't have to.\r
- return (0) unless ($ldap);\r
-\r
- my $ldap_msg = PerformSearch(\r
- $ldap,\r
- base => $base,\r
- filter => $filter,\r
- attrs => $attrs\r
- );\r
- \r
- # If there's only one match, we're good; more than one and\r
- # we don't know which is the right one so we skip it.\r
- unless ($ldap_msg && $ldap_msg->count == 1) {\r
- Unbind( $ldap );\r
- return (0);\r
- }\r
-\r
- my %res;\r
- my $entry = $ldap_msg->first_entry;\r
- foreach my $attr ( @$attrs ) {\r
- if ( $attr eq 'dn' ) {\r
- $res{ $attr } = $entry->dn;\r
+ return ($found, %params) unless ($ldap);\r
+\r
+ # Do a search for them in LDAP\r
+ $RT::Logger->debug( "LDAP Search === ",\r
+ "Base:",\r
+ $base,\r
+ "== Filter:", \r
+ $filter->as_string,\r
+ "== Attrs:", \r
+ join(',',@attrs));\r
+\r
+ my $ldap_msg = $ldap->search(base => $base,\r
+ filter => $filter,\r
+ attrs => \@attrs);\r
+\r
+ # If we didn't get at LEAST a partial result, just die now.\r
+ if ($ldap_msg->code != LDAP_SUCCESS and \r
+ $ldap_msg->code != LDAP_PARTIAL_RESULTS) {\r
+ $RT::Logger->critical( (caller(0))[3],\r
+ ": Search for ",\r
+ $filter->as_string,\r
+ " failed: ",\r
+ ldap_error_name($ldap_msg->code), \r
+ $ldap_msg->code);\r
+ # $found remains as 0\r
+ \r
+ # Drop out to the next external information service\r
+ $ldap_msg = $ldap->unbind();\r
+ if ($ldap_msg->code != LDAP_SUCCESS) {\r
+ $RT::Logger->critical( (caller(0))[3],\r
+ ": Could not unbind: ", \r
+ ldap_error_name($ldap_msg->code), \r
+ $ldap_msg->code);\r
+ }\r
+ undef $ldap;\r
+ undef $ldap_msg;\r
+ return ($found, %params);\r
+ \r
+ } else {\r
+ # If there's only one match, we're good; more than one and\r
+ # we don't know which is the right one so we skip it.\r
+ if ($ldap_msg->count == 1) {\r
+ my $entry = $ldap_msg->first_entry();\r
+ foreach my $key (keys(%{$config->{'attr_map'}})) {\r
+ if ($RT::LdapAttrMap->{$key} eq 'dn') {\r
+ $params{$key} = $entry->dn();\r
+ } else {\r
+ $params{$key} = \r
+ ($entry->get_value($config->{'attr_map'}->{$key}))[0];\r
+ }\r
+\r
+ }\r
+ $found = 1;\r
} else {\r
- $res{ $attr } = ($entry->get_value( $attr ))[0];\r
+ # Drop out to the next external information service\r
+ $ldap_msg = $ldap->unbind();\r
+ if ($ldap_msg->code != LDAP_SUCCESS) {\r
+ $RT::Logger->critical( (caller(0))[3],\r
+ ": Could not unbind: ", \r
+ ldap_error_name($ldap_msg->code), \r
+ $ldap_msg->code);\r
+ }\r
+ undef $ldap;\r
+ undef $ldap_msg;\r
+ return ($found, %params);\r
}\r
}\r
- Unbind( $ldap );\r
- return (1, %res);\r
+ $ldap_msg = $ldap->unbind();\r
+ if ($ldap_msg->code != LDAP_SUCCESS) {\r
+ $RT::Logger->critical( (caller(0))[3],\r
+ ": Could not unbind: ", \r
+ ldap_error_name($ldap_msg->code), \r
+ $ldap_msg->code);\r
+ }\r
+\r
+ undef $ldap;\r
+ undef $ldap_msg;\r
+\r
+ return ($found, %params);\r
}\r
\r
sub UserExists {\r
$RT::Logger->debug("UserExists params:\nusername: $username , service: $service"); \r
my $config = $RT::ExternalSettings->{$service};\r
\r
+ my $base = $config->{'base'};\r
my $filter = $config->{'filter'};\r
\r
# While LDAP filters must be surrounded by parentheses, an empty set\r
my $ldap = _GetBoundLdapObj($config);\r
return unless $ldap;\r
\r
+ my @attrs = values(%{$config->{'attr_map'}});\r
+\r
# Check that the user exists in the LDAP service\r
- my $user_found = PerformSearch(\r
- $ldap,\r
- base => $config->{'base'},\r
- filter => $filter,\r
- attrs => ['uid'],\r
- ) or return 0;\r
+ $RT::Logger->debug( "LDAP Search === ",\r
+ "Base:",\r
+ $base,\r
+ "== Filter:", \r
+ $filter->as_string,\r
+ "== Attrs:", \r
+ join(',',@attrs));\r
+ \r
+ my $user_found = $ldap->search( base => $base,\r
+ filter => $filter,\r
+ attrs => \@attrs);\r
\r
if($user_found->count < 1) {\r
# If 0 or negative integer, no user found or major failure\r
my $ldap = _GetBoundLdapObj($config);\r
next unless $ldap;\r
\r
- my $disabled_users = PerformSearch(\r
- $ldap,\r
- base => $base, \r
- filter => $search_filter, \r
- attrs => ['uid'], # We only need the UID for confirmation now\r
- ) or return 0;\r
-\r
+ # We only need the UID for confirmation now, \r
+ # the other information would waste time and bandwidth\r
+ my @attrs = ('uid'); \r
+ \r
+ $RT::Logger->debug( "LDAP Search === ",\r
+ "Base:",\r
+ $base,\r
+ "== Filter:", \r
+ $search_filter->as_string,\r
+ "== Attrs:", \r
+ join(',',@attrs));\r
+ \r
+ my $disabled_users = $ldap->search(base => $base, \r
+ filter => $search_filter, \r
+ attrs => \@attrs);\r
# If ANY results are returned, \r
# we are going to assume the user should be disabled\r
if ($disabled_users->count) {\r
}\r
}\r
\r
-sub Unbind {\r
- my $ldap = shift;\r
- my $res = $ldap->unbind;\r
- return $res if !$res || $res->code == LDAP_SUCCESS;\r
-\r
- $RT::Logger->error(\r
- (caller(1))[3], ": Could not unbind: ", \r
- ldap_error_name($res->code), \r
- $res->code\r
- );\r
- return $res;\r
-}\r
-\r
-sub PerformSearch {\r
- my $ldap = shift;\r
- my %args = @_;\r
-\r
- $args{'filter'} = Net::LDAP::Filter->new($args{'filter'})\r
- if $args{'filter'} && !ref $args{'filter'};\r
-\r
- $RT::Logger->debug(\r
- "LDAP Search === ",\r
- $args{'base'}? ("Base:", $args{'base'}) : (),\r
- $args{'filter'}? ("== Filter:", $args{'filter'}->as_string) : (),\r
- $args{'attrs'}? ("== Attrs:", join ',', @{ $args{'attrs'} }) : (),\r
- );\r
- \r
- my $res = $ldap->search( %args );\r
- return undef unless $res;\r
-\r
- unless (\r
- $res->code == LDAP_SUCCESS\r
- || $res->code == LDAP_PARTIAL_RESULTS\r
- ) {\r
- $RT::Logger->error(\r
- "Search for", $args{'filter'}->as_string, "failed:",\r
- ldap_error_name($res->code), $res->code\r
- );\r
-\r
- return undef;\r
- }\r
- return $res;\r
-}\r
-\r
-sub JoinFilters {\r
- my $op = shift;\r
- my @list =\r
- grep defined && length && $_ ne '()',\r
- map ref $_? $_->as_string : $_,\r
- @_;\r
- return undef unless @list;\r
-\r
- my $str = @list > 1\r
- ? "($op". join( '', @list ) .')'\r
- : $list[0]\r
- ;\r
- my $obj = Net::LDAP::Filter->new( $str );\r
- $RT::Logger->error("'$str' is not valid LDAP filter")\r
- unless $obj;\r
-\r
- return $obj;\r
-}\r
-\r
# }}}\r
\r
1;\r