[Bps-public-commit] rt-authen-externalauth branch, multiple-emails, created. 0.10_01-64-gb3d3ca4
Jim Brandt
jbrandt at bestpractical.com
Tue Jun 26 15:51:31 EDT 2012
The branch, multiple-emails has been created
at b3d3ca4285d32a8e29771d81980bb2ac5806472e (commit)
- Log -----------------------------------------------------------------
commit 512d7f2f0dc3197bb03d449a3716f1b32555c6dc
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon May 9 02:05:39 2011 +0400
PerformSearch function, cut duplicated code
diff --git a/lib/RT/Authen/ExternalAuth/LDAP.pm b/lib/RT/Authen/ExternalAuth/LDAP.pm
index b228e77..9e27e23 100644
--- a/lib/RT/Authen/ExternalAuth/LDAP.pm
+++ b/lib/RT/Authen/ExternalAuth/LDAP.pm
@@ -9,7 +9,6 @@ use strict;
require Net::SSLeay if $RT::ExternalServiceUsesSSLorTLS;
sub GetAuth {
-
my ($service, $username, $password) = @_;
my $config = $RT::ExternalSettings->{$service};
@@ -36,36 +35,21 @@ sub GetAuth {
my $ldap = _GetBoundLdapObj($config);
return 0 unless ($ldap);
- $filter = Net::LDAP::Filter->new( '(&(' .
+ $filter = '(&(' .
$attr_map->{'Name'} .
'=' .
escape_filter_value($username) .
')' .
$filter .
')'
- );
-
- $RT::Logger->debug( "LDAP Search === ",
- "Base:",
- $base,
- "== Filter:",
- $filter->as_string,
- "== Attrs:",
- join(',', at attrs));
-
- my $ldap_msg = $ldap->search( base => $base,
- filter => $filter,
- attrs => \@attrs);
-
- unless ($ldap_msg->code == LDAP_SUCCESS || $ldap_msg->code == LDAP_PARTIAL_RESULTS) {
- $RT::Logger->debug( "search for",
- $filter->as_string,
- "failed:",
- ldap_error_name($ldap_msg->code),
- $ldap_msg->code);
- # Didn't even get a partial result - jump straight to the next external auth service
- return 0;
- }
+ ;
+
+ my $ldap_msg = PerformSearch(
+ $ldap,
+ base => $base,
+ filter => $filter,
+ attrs => \@attrs
+ ) or return 0;;
unless ($ldap_msg->count == 1) {
$RT::Logger->info( $service,
@@ -113,33 +97,13 @@ sub GetAuth {
# We only need the dn for the actual group since all we care about is existence
@attrs = qw(dn);
- $filter = Net::LDAP::Filter->new("(${group_attr}=" . escape_filter_value($group_val) . ")");
-
- $RT::Logger->debug( "LDAP Search === ",
- "Base:",
- $group,
- "== Filter:",
- $filter->as_string,
- "== Attrs:",
- join(',', at attrs));
-
- $ldap_msg = $ldap->search( base => $group,
- filter => $filter,
- attrs => \@attrs,
- scope => 'base');
-
- # And the user isn't a member:
- unless ($ldap_msg->code == LDAP_SUCCESS ||
- $ldap_msg->code == LDAP_PARTIAL_RESULTS) {
- $RT::Logger->critical( "Search for",
- $filter->as_string,
- "failed:",
- ldap_error_name($ldap_msg->code),
- $ldap_msg->code);
-
- # Fail auth - jump to next external auth service
- return 0;
- }
+ $ldap_msg = PerformSearch(
+ $ldap,
+ base => $group,
+ filter => "(${group_attr}=" . escape_filter_value($group_val) . ")",
+ attrs => \@attrs,
+ scope => 'base'
+ ) or return 0;
unless ($ldap_msg->count == 1) {
$RT::Logger->debug(
@@ -213,31 +177,15 @@ sub CanonicalizeUserInfo {
# errors should be logged by _GetBoundLdapObj so we don't have to.
return ($found, %params) unless ($ldap);
- # Do a search for them in LDAP
- $RT::Logger->debug( "LDAP Search === ",
- "Base:",
- $base,
- "== Filter:",
- $filter->as_string,
- "== Attrs:",
- join(',', at attrs));
-
- my $ldap_msg = $ldap->search(base => $base,
- filter => $filter,
- attrs => \@attrs);
-
- # If we didn't get at LEAST a partial result, just die now.
- if ($ldap_msg->code != LDAP_SUCCESS and
- $ldap_msg->code != LDAP_PARTIAL_RESULTS) {
- $RT::Logger->critical( (caller(0))[3],
- ": Search for ",
- $filter->as_string,
- " failed: ",
- ldap_error_name($ldap_msg->code),
- $ldap_msg->code);
- # $found remains as 0
-
- # Drop out to the next external information service
+ my $ldap_msg = PerformSearch(
+ $ldap,
+ base => $base,
+ filter => $filter,
+ attrs => \@attrs
+ );
+
+ unless ( $ldap_msg ) {
+ # If we didn't get at LEAST a partial result, just die now.
$ldap_msg = $ldap->unbind();
if ($ldap_msg->code != LDAP_SUCCESS) {
$RT::Logger->critical( (caller(0))[3],
@@ -248,7 +196,6 @@ sub CanonicalizeUserInfo {
undef $ldap;
undef $ldap_msg;
return ($found, %params);
-
} else {
# If there's only one match, we're good; more than one and
# we don't know which is the right one so we skip it.
@@ -299,7 +246,6 @@ sub UserExists {
$RT::Logger->debug("UserExists params:\nusername: $username , service: $service");
my $config = $RT::ExternalSettings->{$service};
- my $base = $config->{'base'};
my $filter = $config->{'filter'};
# While LDAP filters must be surrounded by parentheses, an empty set
@@ -323,20 +269,13 @@ sub UserExists {
my $ldap = _GetBoundLdapObj($config);
return unless $ldap;
- my @attrs = values(%{$config->{'attr_map'}});
-
# Check that the user exists in the LDAP service
- $RT::Logger->debug( "LDAP Search === ",
- "Base:",
- $base,
- "== Filter:",
- $filter->as_string,
- "== Attrs:",
- join(',', at attrs));
-
- my $user_found = $ldap->search( base => $base,
- filter => $filter,
- attrs => \@attrs);
+ my $user_found = PerformSearch(
+ $ldap,
+ base => $config->{'base'},
+ filter => $filter,
+ attrs => ['uid'],
+ ) or return 0;
if($user_found->count < 1) {
# If 0 or negative integer, no user found or major failure
@@ -416,21 +355,13 @@ sub UserDisabled {
my $ldap = _GetBoundLdapObj($config);
next unless $ldap;
- # We only need the UID for confirmation now,
- # the other information would waste time and bandwidth
- my @attrs = ('uid');
-
- $RT::Logger->debug( "LDAP Search === ",
- "Base:",
- $base,
- "== Filter:",
- $search_filter->as_string,
- "== Attrs:",
- join(',', at attrs));
-
- my $disabled_users = $ldap->search(base => $base,
- filter => $search_filter,
- attrs => \@attrs);
+ my $disabled_users = PerformSearch(
+ $ldap,
+ base => $base,
+ filter => $search_filter,
+ attrs => ['uid'], # We only need the UID for confirmation now
+ ) or return 0;
+
# If ANY results are returned,
# we are going to assume the user should be disabled
if ($disabled_users->count) {
@@ -499,6 +430,38 @@ sub _GetBoundLdapObj {
}
}
+sub PerformSearch {
+ my $ldap = shift;
+ my %args = @_;
+
+ $args{'filter'} = Net::LDAP::Filter->new($args{'filter'})
+ if $args{'filter'} && !ref $args{'filter'};
+
+ $RT::Logger->debug(
+ "LDAP Search === ",
+ $args{'base'}? ("Base:", $args{'base'}) : (),
+ $args{'filter'}? ("== Filter:", $args{'filter'}->as_string) : (),
+ $args{'attrs'}? ("== Attrs:", join ',', @{ $args{'attrs'} }) : (),
+ );
+
+ my $res = $ldap->search( %args );
+ return undef unless $res;
+
+ # And the user isn't a member:
+ unless (
+ $res->code == LDAP_SUCCESS
+ || $res->code == LDAP_PARTIAL_RESULTS
+ ) {
+ $RT::Logger->error(
+ "Search for", $args{'filter'}->as_string, "failed:",
+ ldap_error_name($res->code), $res->code
+ );
+
+ return undef;
+ }
+ return $res;
+}
+
# }}}
1;
commit 5a3d89078e981881ed35e54768926000efac07f0
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon May 9 02:25:54 2011 +0400
Unbind function to get rid of repeated code
diff --git a/lib/RT/Authen/ExternalAuth/LDAP.pm b/lib/RT/Authen/ExternalAuth/LDAP.pm
index 9e27e23..0636432 100644
--- a/lib/RT/Authen/ExternalAuth/LDAP.pm
+++ b/lib/RT/Authen/ExternalAuth/LDAP.pm
@@ -35,14 +35,10 @@ sub GetAuth {
my $ldap = _GetBoundLdapObj($config);
return 0 unless ($ldap);
- $filter = '(&(' .
- $attr_map->{'Name'} .
- '=' .
- escape_filter_value($username) .
- ')' .
- $filter .
- ')'
- ;
+ $filter = '(&'
+ .'('. $attr_map->{'Name'} . '=' . escape_filter_value( $username ) . ')' .
+ $filter
+ .')';
my $ldap_msg = PerformSearch(
$ldap,
@@ -186,15 +182,7 @@ sub CanonicalizeUserInfo {
unless ( $ldap_msg ) {
# If we didn't get at LEAST a partial result, just die now.
- $ldap_msg = $ldap->unbind();
- if ($ldap_msg->code != LDAP_SUCCESS) {
- $RT::Logger->critical( (caller(0))[3],
- ": Could not unbind: ",
- ldap_error_name($ldap_msg->code),
- $ldap_msg->code);
- }
- undef $ldap;
- undef $ldap_msg;
+ Unbind( $ldap );
return ($found, %params);
} else {
# If there's only one match, we're good; more than one and
@@ -215,28 +203,11 @@ sub CanonicalizeUserInfo {
$found = 1;
} else {
# Drop out to the next external information service
- $ldap_msg = $ldap->unbind();
- if ($ldap_msg->code != LDAP_SUCCESS) {
- $RT::Logger->critical( (caller(0))[3],
- ": Could not unbind: ",
- ldap_error_name($ldap_msg->code),
- $ldap_msg->code);
- }
- undef $ldap;
- undef $ldap_msg;
+ Unbind( $ldap );
return ($found, %params);
}
}
- $ldap_msg = $ldap->unbind();
- if ($ldap_msg->code != LDAP_SUCCESS) {
- $RT::Logger->critical( (caller(0))[3],
- ": Could not unbind: ",
- ldap_error_name($ldap_msg->code),
- $ldap_msg->code);
- }
-
- undef $ldap;
- undef $ldap_msg;
+ Unbind( $ldap );
return ($found, %params);
}
@@ -430,6 +401,19 @@ sub _GetBoundLdapObj {
}
}
+sub Unbind {
+ my $ldap = shift;
+ my $res = $ldap->unbind;
+ return $res if !$res || $res->code == LDAP_SUCCESS;
+
+ $RT::Logger->error(
+ (caller(1))[3], ": Could not unbind: ",
+ ldap_error_name($res->code),
+ $res->code
+ );
+ return $res;
+}
+
sub PerformSearch {
my $ldap = shift;
my %args = @_;
commit 778f0d92d0d1910bb199a423894c51d482f47b45
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon May 9 11:28:10 2011 +0400
several level 'if/else' -> one level 'if'
diff --git a/lib/RT/Authen/ExternalAuth/LDAP.pm b/lib/RT/Authen/ExternalAuth/LDAP.pm
index 0636432..f21d6b8 100644
--- a/lib/RT/Authen/ExternalAuth/LDAP.pm
+++ b/lib/RT/Authen/ExternalAuth/LDAP.pm
@@ -180,32 +180,22 @@ sub CanonicalizeUserInfo {
attrs => \@attrs
);
- unless ( $ldap_msg ) {
- # If we didn't get at LEAST a partial result, just die now.
- Unbind( $ldap );
- return ($found, %params);
- } else {
- # If there's only one match, we're good; more than one and
- # we don't know which is the right one so we skip it.
- if ($ldap_msg->count == 1) {
- my $entry = $ldap_msg->first_entry();
- foreach my $key (keys(%{$config->{'attr_map'}})) {
+ # If there's only one match, we're good; more than one and
+ # we don't know which is the right one so we skip it.
+ if ($ldap_msg && $ldap_msg->count == 1) {
+ my $entry = $ldap_msg->first_entry();
+ foreach my $key (keys(%{$config->{'attr_map'}})) {
# XXX TODO: This legacy code wants to be removed since modern
# configs will always fall through to the else and the logic is
# weird even if you do have the old config.
if ($RT::LdapAttrMap and $RT::LdapAttrMap->{$key} eq 'dn') {
- $params{$key} = $entry->dn();
- } else {
- $params{$key} =
- ($entry->get_value($config->{'attr_map'}->{$key}))[0];
- }
+ $params{$key} = $entry->dn();
+ } else {
+ $params{$key} =
+ ($entry->get_value($config->{'attr_map'}->{$key}))[0];
}
- $found = 1;
- } else {
- # Drop out to the next external information service
- Unbind( $ldap );
- return ($found, %params);
}
+ $found = 1;
}
Unbind( $ldap );
commit 3a50575e954227a5067c5025a220ae6713201f58
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon May 9 13:54:56 2011 +0400
avoid array with one undef when empty array expected
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 948939a..c12f3c3 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -580,7 +580,7 @@ sub CanonicalizeUserInfo {
sort(keys(%$args))));
# Get the list of defined external services
- my @info_services = $RT::ExternalInfoPriority ? @{$RT::ExternalInfoPriority} : undef;
+ my @info_services = $RT::ExternalInfoPriority ? @{$RT::ExternalInfoPriority} : ();
# For each external service...
foreach my $service (@info_services) {
commit c84859d9fa42bb05264a3241067671c3c1c0a15c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon May 9 14:28:39 2011 +0400
valid == 0 is only possible when key is undef
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index c12f3c3..8548b95 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -611,23 +611,13 @@ sub CanonicalizeUserInfo {
# Else, use it as a canonicalization key and lookup the user info
my $key = $config->{'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);
- my $attr_map = $config->{'attr_map'};
- 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,
- ")");
+ unless ( $key ) {
+ $RT::Logger->warning(
+ "No mapping for $rt_attr in attr_map for this service ($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.
commit 49949593dae7782b32382f811c50bb8184ab6cb8
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon May 9 14:31:12 2011 +0400
correct log message
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 8548b95..4c35575 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -589,7 +589,7 @@ sub CanonicalizeUserInfo {
# Get the config for the service so that we know what attrs we can canonicalize
my $config = $RT::ExternalSettings->{$service};
-
+
if($config->{'type'} eq 'cookie'){
$RT::Logger->debug("You cannot use SSO cookies as an information service!");
next;
@@ -602,7 +602,7 @@ sub CanonicalizeUserInfo {
unless(defined($args->{$rt_attr})) {
$RT::Logger->debug("This attribute (",
$rt_attr,
- ") is null or incorrectly defined in the attr_map for this service (",
+ ") is null or incorrectly defined in the attr_match_list for this service (",
$service,
")");
next;
commit 24ca77d567fa36cf74f1e76838e240f2354272f0
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon May 9 14:39:57 2011 +0400
move $value declaration earlier, so we can re-use
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 4c35575..bc41770 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -599,7 +599,8 @@ sub CanonicalizeUserInfo {
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);
- unless(defined($args->{$rt_attr})) {
+ my $value = $args->{$rt_attr};
+ unless( defined $value && length $value ) {
$RT::Logger->debug("This attribute (",
$rt_attr,
") is null or incorrectly defined in the attr_match_list for this service (",
@@ -610,7 +611,6 @@ sub CanonicalizeUserInfo {
# Else, use it as a canonicalization key and lookup the user info
my $key = $config->{'attr_map'}->{$rt_attr};
- my $value = $args->{$rt_attr};
unless ( $key ) {
$RT::Logger->warning(
"No mapping for $rt_attr in attr_map for this service ($service)"
commit 53d142facd926e56c82c9f41af5f0be42e8b0765
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon May 9 14:40:37 2011 +0400
pass all available info into XXXX::CanonicalizeUserInfo
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index bc41770..191cf66 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -623,9 +623,9 @@ sub CanonicalizeUserInfo {
# the service requested.
if($config->{'type'} eq 'ldap'){
- ($found, %params) = RT::Authen::ExternalAuth::LDAP::CanonicalizeUserInfo($service,$key,$value);
+ ($found, %params) = RT::Authen::ExternalAuth::LDAP::CanonicalizeUserInfo($service,$key,$value, $args);
} elsif ($config->{'type'} eq 'db') {
- ($found, %params) = RT::Authen::ExternalAuth::DBI::CanonicalizeUserInfo($service,$key,$value);
+ ($found, %params) = RT::Authen::ExternalAuth::DBI::CanonicalizeUserInfo($service,$key,$value, $args);
} else {
$RT::Logger->debug( (caller(0))[3],
"does not consider",
commit 90ebd777119007382532c26f0747c7fb3a6313d2
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 01:48:58 2011 +0400
get rid of $found and params
diff --git a/lib/RT/Authen/ExternalAuth/LDAP.pm b/lib/RT/Authen/ExternalAuth/LDAP.pm
index f21d6b8..529eeac 100644
--- a/lib/RT/Authen/ExternalAuth/LDAP.pm
+++ b/lib/RT/Authen/ExternalAuth/LDAP.pm
@@ -132,11 +132,6 @@ sub CanonicalizeUserInfo {
my ($service, $key, $value) = @_;
- my $found = 0;
- my %params = (Name => undef,
- EmailAddress => undef,
- RealName => undef);
-
# Load the config
my $config = $RT::ExternalSettings->{$service};
@@ -163,7 +158,7 @@ sub CanonicalizeUserInfo {
$RT::Logger->critical( (caller(0))[3],
"LDAP baseDN not defined");
# Drop out to the next external information service
- return ($found, %params);
+ return (0);
}
# Get a Net::LDAP object based on the config we provide
@@ -171,7 +166,7 @@ sub CanonicalizeUserInfo {
# Jump to the next external information service if we can't get one,
# errors should be logged by _GetBoundLdapObj so we don't have to.
- return ($found, %params) unless ($ldap);
+ return (0) unless ($ldap);
my $ldap_msg = PerformSearch(
$ldap,
@@ -182,24 +177,27 @@ sub CanonicalizeUserInfo {
# If there's only one match, we're good; more than one and
# we don't know which is the right one so we skip it.
- if ($ldap_msg && $ldap_msg->count == 1) {
- my $entry = $ldap_msg->first_entry();
- foreach my $key (keys(%{$config->{'attr_map'}})) {
+ unless ($ldap_msg && $ldap_msg->count == 1) {
+ Unbind( $ldap );
+ return (0);
+ }
+
+ my %res;
+ my $entry = $ldap_msg->first_entry();
+ foreach my $key (keys(%{$config->{'attr_map'}})) {
# XXX TODO: This legacy code wants to be removed since modern
# configs will always fall through to the else and the logic is
# weird even if you do have the old config.
if ($RT::LdapAttrMap and $RT::LdapAttrMap->{$key} eq 'dn') {
- $params{$key} = $entry->dn();
- } else {
- $params{$key} =
- ($entry->get_value($config->{'attr_map'}->{$key}))[0];
- }
+ $res{$key} = $entry->dn();
+ } else {
+ $res{$key} =
+ ($entry->get_value($config->{'attr_map'}->{$key}))[0];
}
- $found = 1;
}
- Unbind( $ldap );
- return ($found, %params);
+ Unbind( $ldap );
+ return (1, %res);
}
sub UserExists {
commit 55eb0a73598a0b403bb8db232b02c2efb190d615
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 02:42:50 2011 +0400
support not only Name matching on update
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 191cf66..b7a3ad3 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -408,8 +408,8 @@ sub UpdateUserInfo {
# 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 = (Name => $username);
- $UserObj->CanonicalizeUserInfo(\%args);
+ my %args;
+ $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
@@ -572,6 +572,14 @@ sub CanonicalizeUserInfo {
EmailAddress => undef,
RealName => undef);
+ my $current_value = sub {
+ my $field = shift;
+ return $args->{ $field } if keys %$args;
+
+ return undef unless $UserObj->can( $field );
+ return $UserObj->$field();
+ };
+
$RT::Logger->debug( (caller(0))[3],
"called by",
caller,
@@ -599,7 +607,7 @@ sub CanonicalizeUserInfo {
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 = $args->{$rt_attr};
+ my $value = $current_value->( $rt_attr );
unless( defined $value && length $value ) {
$RT::Logger->debug("This attribute (",
$rt_attr,
commit 3d13ea850c73ba91f7c614dceac7f5ba1c296940
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 02:50:19 2011 +0400
in CanonicalizeUserInfo deal with attr_map outside implementations
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index b7a3ad3..e3351a7 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -566,12 +566,7 @@ sub CanonicalizeUserInfo {
my $UserObj = shift;
my $args = shift;
-
- my $found = 0;
- my %params = (Name => undef,
- EmailAddress => undef,
- RealName => undef);
-
+
my $current_value = sub {
my $field = shift;
return $args->{ $field } if keys %$args;
@@ -580,6 +575,8 @@ sub CanonicalizeUserInfo {
return $UserObj->$field();
};
+ my ($found, $config, %params) = (0);
+
$RT::Logger->debug( (caller(0))[3],
"called by",
caller,
@@ -596,13 +593,19 @@ sub CanonicalizeUserInfo {
$service);
# Get the config for the service so that we know what attrs we can canonicalize
- my $config = $RT::ExternalSettings->{$service};
+ $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
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
@@ -631,9 +634,9 @@ sub CanonicalizeUserInfo {
# the service requested.
if($config->{'type'} eq 'ldap'){
- ($found, %params) = RT::Authen::ExternalAuth::LDAP::CanonicalizeUserInfo($service,$key,$value, $args);
+ ($found, %params) = RT::Authen::ExternalAuth::LDAP::CanonicalizeUserInfo($service,$key,$value, \@service_attrs);
} elsif ($config->{'type'} eq 'db') {
- ($found, %params) = RT::Authen::ExternalAuth::DBI::CanonicalizeUserInfo($service,$key,$value, $args);
+ ($found, %params) = RT::Authen::ExternalAuth::DBI::CanonicalizeUserInfo($service,$key,$value, \@service_attrs);
} else {
$RT::Logger->debug( (caller(0))[3],
"does not consider",
@@ -647,29 +650,40 @@ sub CanonicalizeUserInfo {
# Don't Check any more services
last if $found;
}
-
- # If found, Canonicalize Email Address and
- # update the args hash that we were given the hashref for
- 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);
+
+ 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'} } ) {
+ if ( keys %$args ) {
+ $res{ $k } = $params{ $v };
+ } else {
+ $res{ $k } = $params{ $v };
+ }
}
+ # It's important that we always have a canonical email address
+ if ($res{'EmailAddress'}) {
+ $res{'EmailAddress'} = $UserObj->CanonicalizeEmailAddress($res{'EmailAddress'});
+ }
+
+ # update the args hash that we were given the hashref for
+ %$args = (%$args, %res);
+
$RT::Logger->info( (caller(0))[3],
"returning",
join(", ", map {sprintf("%s: %s", $_, ($args->{$_} ? $args->{$_} : ''))}
sort(keys(%$args))));
- ### 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);
-
+ return $found;
}
{
diff --git a/lib/RT/Authen/ExternalAuth/LDAP.pm b/lib/RT/Authen/ExternalAuth/LDAP.pm
index 529eeac..d2844f4 100644
--- a/lib/RT/Authen/ExternalAuth/LDAP.pm
+++ b/lib/RT/Authen/ExternalAuth/LDAP.pm
@@ -130,7 +130,7 @@ sub GetAuth {
sub CanonicalizeUserInfo {
- my ($service, $key, $value) = @_;
+ my ($service, $key, $value, $attrs) = @_;
# Load the config
my $config = $RT::ExternalSettings->{$service};
@@ -139,9 +139,6 @@ sub CanonicalizeUserInfo {
my $base = $config->{'base'};
my $filter = $config->{'filter'};
- # Get the list of unique attrs we need
- my @attrs = values(%{$config->{'attr_map'}});
-
# This is a bit confusing and probably broken. Something to revisit..
my $filter_addition = ($key && $value) ? "(". $key . "=". escape_filter_value($value) .")" : "";
if(defined($filter) && ($filter ne "()")) {
@@ -172,7 +169,7 @@ sub CanonicalizeUserInfo {
$ldap,
base => $base,
filter => $filter,
- attrs => \@attrs
+ attrs => $attrs
);
# If there's only one match, we're good; more than one and
@@ -183,19 +180,17 @@ sub CanonicalizeUserInfo {
}
my %res;
- my $entry = $ldap_msg->first_entry();
- foreach my $key (keys(%{$config->{'attr_map'}})) {
- # XXX TODO: This legacy code wants to be removed since modern
- # configs will always fall through to the else and the logic is
- # weird even if you do have the old config.
- if ($RT::LdapAttrMap and $RT::LdapAttrMap->{$key} eq 'dn') {
- $res{$key} = $entry->dn();
+ my $entry = $ldap_msg->first_entry;
+ foreach my $attr ( @$attrs ) {
+ # XXX TODO: This if branch was inactive for a while
+ # now it works, but is it right thing to do? entry->dn
+ # is it at all diiferent from get_value('dn')?
+ if ( $attr eq 'dn' ) {
+ $res{ $attr } = $entry->dn;
} else {
- $res{$key} =
- ($entry->get_value($config->{'attr_map'}->{$key}))[0];
+ $res{ $attr } = ($entry->get_value( $attr ))[0];
}
}
-
Unbind( $ldap );
return (1, %res);
}
commit 2238a54866bc1e490e8028d6750bf2f5b8571abf
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 17:04:14 2011 +0400
::Test->add_ldap_user_simple method
diff --git a/lib/RT/Authen/ExternalAuth/Test.pm b/lib/RT/Authen/ExternalAuth/Test.pm
index b7c1c59..7a19e77 100644
--- a/lib/RT/Authen/ExternalAuth/Test.pm
+++ b/lib/RT/Authen/ExternalAuth/Test.pm
@@ -117,4 +117,21 @@ sub add_ldap_user {
return $ldap{'client'}->add( $dn, attr => [%args] );
}
+{ my $i = 0;
+sub add_ldap_user_simple {
+ my $self = shift;
+ my %args = @_;
+
+ my $name = "testuser". ++$i;
+
+ s/\%name\b/$name/g foreach grep defined, values %args;
+
+ $self->add_ldap_user(
+ cn => $name,
+ mail => "$name\@invalid.tld",
+ %args,
+ );
+ return $name;
+} }
+
1;
commit 9f2edc9da1a4e135d7dc7a538214bd4f309b6ff6
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 17:03:28 2011 +0400
test that AutoCreate works on submission by email
diff --git a/xt/ldap/privileged.t b/xt/ldap/privileged.t
index 4dd277b..d54997a 100644
--- a/xt/ldap/privileged.t
+++ b/xt/ldap/privileged.t
@@ -1,51 +1,65 @@
use strict;
use warnings;
-use RT::Authen::ExternalAuth::Test ldap => 1, tests => 15;
+use RT::Authen::ExternalAuth::Test ldap => 1, tests => 20;
my $class = 'RT::Authen::ExternalAuth::Test';
-
my ($server, $client) = $class->bootstrap_ldap_basics;
ok( $server, "spawned test LDAP server" );
-my $username = "testuser";
-$class->add_ldap_user(
- uid => $username,
- mail => "$username\@invalid.tld",
-);
-
RT->Config->Set( AutoCreate => { Privileged => 1 } );
+RT::Test->set_rights(
+ { Principal => 'Everyone', Right => [qw(SeeQueue ShowTicket CreateTicket)] },
+);
+
my ( $baseurl, $m ) = RT::Test->started_ok();
-diag "test uri login";
+
+diag "login, make sure user privileged";
{
- ok( !$m->login( 'fakeuser', 'password' ), 'not logged in with fake user' );
- ok( $m->login( 'testuser', 'password' ), 'logged in' );
+ my $username = $class->add_ldap_user_simple;
+ ok( $m->login( $username, 'password' ), 'logged in' );
+
+ {
+ my $user = RT::User->new($RT::SystemUser);
+ my ($ok,$msg) = $user->Load( $username );
+ ok($user->id);
+ is($user->EmailAddress, "$username\@invalid.tld");
+ ok($user->Privileged, 'privileged user');
+ }
+
+ unlike( $m->uri, qr!SelfService!, 'privileged home page' );
}
-diag "test user creation";
+diag "send mail, make sure user privileged";
{
- my $testuser = RT::User->new($RT::SystemUser);
- my ($ok,$msg) = $testuser->Load( 'testuser' );
- ok($ok,$msg);
- is($testuser->EmailAddress,'testuser at invalid.tld');
-}
+ my $username = $class->add_ldap_user_simple;
+ {
+ my $mail = << "MAIL";
+Subject: Test
+From: $username\@invalid.tld
+test
+MAIL
-diag "test form login";
-{
- $m->logout;
- $m->get_ok( $baseurl, 'base url' );
- $m->submit_form(
- form_number => 1,
- fields => { user => 'testuser', pass => 'password', },
- );
- $m->text_contains( 'Logout', 'logged in via form' );
-}
+ my ($status, $id) = RT::Test->send_via_mailgate($mail);
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "got id of a newly created ticket - $id");
-like( $m->uri, qr!$baseurl/(index\.html)?!, 'privileged home page' );
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok ($ticket->id, 'loaded ticket');
-$client->unbind();
+ my $user = $ticket->CreatorObj;
+ is($user->EmailAddress, "$username\@invalid.tld");
+ ok($user->Privileged, 'privileged user');
+ }
+ {
+ ok( $m->login( $username, 'password' ), 'logged in' );
+ unlike( $m->uri, qr!SelfService!, 'privileged home page' );
+ }
+}
+$client->unbind();
$m->get_warnings;
commit 29cc01fd4996af61833e703003c27fa3ab96dfbb
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 17:11:39 2011 +0400
tests for setups with multiple emails stored in LDAP
diff --git a/xt/ldap/multiple-emails.t b/xt/ldap/multiple-emails.t
new file mode 100644
index 0000000..5ebe609
--- /dev/null
+++ b/xt/ldap/multiple-emails.t
@@ -0,0 +1,164 @@
+use strict;
+use warnings;
+
+use RT::Authen::ExternalAuth::Test ldap => 1, tests => 43;
+my $class = 'RT::Authen::ExternalAuth::Test';
+
+my ($server, $client) = $class->bootstrap_ldap_basics;
+ok( $server, "spawned test LDAP server" );
+
+my $queue = RT::Test->load_or_create_queue(Name => 'General');
+ok($queue->id, "loaded the General queue");
+
+RT->Config->Set( AutoCreate => { Privileged => 1 } );
+
+RT->Config->Get('ExternalSettings')->{'My_LDAP'}{'attr_map'}{'EmailAddress'}
+ = ['mail', 'alias'];
+
+RT::Test->set_rights(
+ { Principal => 'Everyone', Right => [qw(SeeQueue ShowTicket CreateTicket)] },
+);
+
+my ( $baseurl, $m ) = RT::Test->started_ok();
+
+diag "login then send emails from different addresses";
+{
+ my $username = new_user();
+ my $first_user;
+ {
+ ok( $m->login( $username, 'password' ), 'logged in' );
+
+ ok( $m->goto_create_ticket( $queue ), "go to create ticket" );
+ $m->form_name('TicketCreate');
+ $m->submit;
+
+ my ($id) = ($m->content =~ /.*Ticket (\d+) created.*/g);
+ ok $id, "created a ticket";
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok ($ticket->id, 'loaded ticket');
+
+ my $user = $first_user = $ticket->CreatorObj;
+ is( $user->Name, $username );
+ is( $user->EmailAddress, "$username\@invalid.tld" );
+ }
+
+ {
+ my $mail = << "MAIL";
+Subject: Test
+From: $username\@invalid.tld
+
+test
+MAIL
+
+ my ($status, $id) = RT::Test->send_via_mailgate($mail);
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "got id of a newly created ticket - $id");
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok ($ticket->id, 'loaded ticket');
+
+ my $user = $ticket->CreatorObj;
+ is( $user->id, $first_user->id );
+ is( $user->Name, $username );
+ is( $user->EmailAddress, "$username\@invalid.tld" );
+ }
+
+ {
+ my $mail = << "MAIL";
+Subject: Test
+From: $username\@alternative.tld
+
+test
+MAIL
+
+ my ($status, $id) = RT::Test->send_via_mailgate($mail);
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "got id of a newly created ticket - $id");
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok ($ticket->id, 'loaded ticket');
+
+ my $user = $ticket->CreatorObj;
+ is( $user->id, $first_user->id );
+ is( $user->Name, $username );
+ is( $user->EmailAddress, "$username\@invalid.tld" );
+ }
+}
+
+diag "send a mail from alternative address, then try other credentials";
+{
+ my $username = new_user();
+ my $first_user;
+ {
+ my $mail = << "MAIL";
+Subject: Test
+From: $username\@alternative.tld
+
+test
+MAIL
+
+ my ($status, $id) = RT::Test->send_via_mailgate($mail);
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "got id of a newly created ticket - $id");
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok ($ticket->id, 'loaded ticket');
+
+ my $user = $first_user = $ticket->CreatorObj;
+ is( $user->Name, $username );
+ is( $user->EmailAddress, "$username\@alternative.tld" );
+ }
+
+ {
+ ok( $m->login( $username, 'password' ), 'logged in' );
+
+ ok( $m->goto_create_ticket( $queue ), "go to create ticket" );
+ $m->form_name('TicketCreate');
+ $m->submit;
+
+ my ($id) = ($m->content =~ /.*Ticket (\d+) created.*/g);
+ ok $id, "created a ticket";
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok ($ticket->id, 'loaded ticket');
+
+ my $user = $ticket->CreatorObj;
+ is( $user->id, $first_user->id );
+ is( $user->Name, $username );
+ is( $user->EmailAddress, "$username\@alternative.tld" );
+ }
+
+ {
+ my $mail = << "MAIL";
+Subject: Test
+From: $username\@invalid.tld
+
+test
+MAIL
+
+ my ($status, $id) = RT::Test->send_via_mailgate($mail);
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "got id of a newly created ticket - $id");
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok ($ticket->id, 'loaded ticket');
+
+ my $user = $ticket->CreatorObj;
+ is( $user->id, $user->id );
+ is( $user->Name, $username );
+ is( $user->EmailAddress, "$username\@alternative.tld" );
+ }
+}
+
+$client->unbind();
+$m->get_warnings;
+
+sub new_user { return $class->add_ldap_user_simple( alias => '%name at alternative.tld' ) }
+
commit 8e43ba70b77b5a4893aaf85ded715b04695c9efd
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 17:15:00 2011 +0400
method to join zero or more LDAP filters with '&' or '|' op
diff --git a/lib/RT/Authen/ExternalAuth/LDAP.pm b/lib/RT/Authen/ExternalAuth/LDAP.pm
index d2844f4..8482d4c 100644
--- a/lib/RT/Authen/ExternalAuth/LDAP.pm
+++ b/lib/RT/Authen/ExternalAuth/LDAP.pm
@@ -429,6 +429,25 @@ sub PerformSearch {
return $res;
}
+sub JoinFilters {
+ my $op = shift;
+ my @list =
+ grep defined && length && $_ ne '()',
+ map ref $_? $_->as_string : $_,
+ @_;
+ return undef unless @list;
+
+ my $str = @list > 1
+ ? "($op". join( '', @list ) .')'
+ : $list[0]
+ ;
+ my $obj = Net::LDAP::Filter->new( $str );
+ $RT::Logger->error("'$str' is not valid LDAP filter")
+ unless $obj;
+
+ return $obj;
+}
+
# }}}
1;
commit 7fdd4df538d0cb9a3620e4be46620fbbdda3f2a7
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 18:07:18 2011 +0400
change how we build main filter in LDAP::CanonicalizeUserInfo
* support key to be an array to mean any of these LDAP attributes
* key and value are always defined by the caller
* use JoinFilters
** support situation when filter in the config is empty
diff --git a/lib/RT/Authen/ExternalAuth/LDAP.pm b/lib/RT/Authen/ExternalAuth/LDAP.pm
index 8482d4c..15e0774 100644
--- a/lib/RT/Authen/ExternalAuth/LDAP.pm
+++ b/lib/RT/Authen/ExternalAuth/LDAP.pm
@@ -134,23 +134,14 @@ sub CanonicalizeUserInfo {
# Load the config
my $config = $RT::ExternalSettings->{$service};
-
- # Figure out what's what
- my $base = $config->{'base'};
- my $filter = $config->{'filter'};
- # This is a bit confusing and probably broken. Something to revisit..
- my $filter_addition = ($key && $value) ? "(". $key . "=". escape_filter_value($value) .")" : "";
- if(defined($filter) && ($filter ne "()")) {
- $filter = Net::LDAP::Filter->new( "(&" .
- $filter .
- $filter_addition .
- ")"
- );
- } else {
- $RT::Logger->debug( "LDAP Filter invalid or not present.");
- }
+ my $filter = JoinFilters(
+ '&',
+ JoinFilters('|', map "($_=". escape_filter_value( $value ) .")", ref $key? @$key: ($key) ),
+ $config->{'filter'},
+ ) or return (0);
+ my $base = $config->{'base'};
unless (defined($base)) {
$RT::Logger->critical( (caller(0))[3],
"LDAP baseDN not defined");
commit d46ad6aab2285ec1b5b4a4b1d7de53bf0ed6fe5a
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 18:11:06 2011 +0400
change how we process hash from XXX::CanonicalizeUserInfo
support the following config when we map hash returned by
CanonicalizeUserInfo to RT user's fields.
attr_map => {
EmailAddress => ['mail', 'alias'],
...
},
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index e3351a7..22523f5 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -663,10 +663,18 @@ sub CanonicalizeUserInfo {
# If found let's build back RT's fields
my %res;
while ( my ($k, $v) = each %{ $config->{'attr_map'} } ) {
- if ( keys %$args ) {
+ 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 {
- $res{ $k } = $params{ $v };
+ unless ( grep defined && length && $_ eq $current, map $params{ $_ }, @$v ) {
+ $res{ $k } = (grep defined && length, map $params{ $_ }, @$v)[0];
+ }
}
}
commit 201a7883f1d1d62de5b83f68ca9f243c063efa5d
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 18:18:49 2011 +0400
extend ::User->LoadByCols to support alternative values
RT's default ::User->LoadByCols failed, but user record may be
still there if we have info providing service with alternative
values for fields from 'attr_match_list' list
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 22523f5..239ed24 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -703,4 +703,91 @@ sub CanonicalizeUserInfo {
};
}
+{
+ 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 when
+# 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)], }
+
+ # 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 $_,
+ map $config->{'attr_map'}{ $_ },
+ @{ $config->{'attr_match_list'} };
+
+ push @info_services, $service;
+ }
+ return $rv unless @info_services;
+
+ # find user in external service and fetch alternative values
+ # for a field
+ my ($found, $search_by, @alternatives);
+ foreach my $service (@info_services) {
+ my $config = $RT::ExternalSettings->{$service};
+
+ # Get the list of unique attrs we need
+ my @service_attrs = do {
+ my %seen;
+ grep !$seen{$_}++, map ref($_)? @$_ : ($_), values %{ $config->{'attr_map'} }
+ };
+
+ 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 %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;
+
+ @alternatives = grep defined && length && $_ ne $args{ $search_by }, values %params;
+
+ # Don't Check any more services
+ last;
+ }
+ return $rv unless $found;
+
+ # lookup by alternatives
+ foreach my $value ( @alternatives ) {
+ my $rv = $orig->( $self, %args, $search_by => $value );
+ return $rv if $self->id;
+ }
+ return $rv;
+ };
+}
+
1;
commit c51375c60d64931cb8f61a61df6519f5042c6385
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 21:55:41 2011 +0400
drop unused code
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 239ed24..b0a5723 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -737,12 +737,6 @@ sub CanonicalizeUserInfo {
foreach my $service (@info_services) {
my $config = $RT::ExternalSettings->{$service};
- # Get the list of unique attrs we need
- my @service_attrs = do {
- my %seen;
- grep !$seen{$_}++, map ref($_)? @$_ : ($_), values %{ $config->{'attr_map'} }
- };
-
foreach my $rt_attr ( @{ $config->{'attr_match_list'} } ) {
next unless exists $args{ $rt_attr }
&& defined $args{ $rt_attr }
commit aca46e2a3abda9a95a45bfe9248eb7eba66c4fa3
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 11 22:55:24 2011 +0400
clean search_by to avoid leftovers from previouse service
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index b0a5723..5118264 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -737,6 +737,7 @@ sub CanonicalizeUserInfo {
foreach my $service (@info_services) {
my $config = $RT::ExternalSettings->{$service};
+ $search_by = undef;
foreach my $rt_attr ( @{ $config->{'attr_match_list'} } ) {
next unless exists $args{ $rt_attr }
&& defined $args{ $rt_attr }
commit 9ddaab4ee6650e6468741c911dc05718f43485a2
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu May 12 00:41:27 2011 +0400
bring AutoCreate option into ::Interface::Email::CreateUser()
Workaround for a bug in RT. When a user that is not in the DB
submits a ticket via Email then a new account created without
AutoCreate config option.
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 5118264..24573e0 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -567,6 +567,8 @@ sub CanonicalizeUserInfo {
my $UserObj = shift;
my $args = shift;
+ WorkaroundAutoCreate( $UserObj, $args );
+
my $current_value = sub {
my $field = shift;
return $args->{ $field } if keys %$args;
@@ -785,4 +787,20 @@ sub CanonicalizeUserInfo {
};
}
+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;
commit e6301e99d665987f84b72665bc9cf19b0948765d
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu May 12 01:49:51 2011 +0400
port xt/sqlite.t over ::Test
diff --git a/lib/RT/Authen/ExternalAuth/Test.pm b/lib/RT/Authen/ExternalAuth/Test.pm
index 7a19e77..20c376a 100644
--- a/lib/RT/Authen/ExternalAuth/Test.pm
+++ b/lib/RT/Authen/ExternalAuth/Test.pm
@@ -42,6 +42,20 @@ sub import {
exit;
}
}
+ if ( my $driver = delete $args{'dbi'} ) {
+ local $@;
+ eval {
+ require DBI;
+ require File::Temp;
+ require Digest::MD5;
+ require File::Spec;
+ eval "require DBD::$driver; 1";
+ } or do {
+ require Test::More;
+ Test::More::plan( skip_all => 'Unable to test without DB modules: '. $@ );
+ exit;
+ }
+ }
$class->SUPER::import( %args );
$class->export_to_level(1);
diff --git a/xt/sqlite.t b/xt/sqlite.t
index 3c52649..0e04b22 100644
--- a/xt/sqlite.t
+++ b/xt/sqlite.t
@@ -1,15 +1,8 @@
use strict;
use warnings;
-use RT::Authen::ExternalAuth::Test;
-use DBI;
-use File::Temp;
-use Digest::MD5;
-use File::Spec;
-
-eval { require DBD::SQLite; } or do {
- plan skip_all => 'Unable to test without DBD::SQLite';
-};
+use RT::Authen::ExternalAuth::Test dbi => 'SQLite', tests => 19;
+my $class = 'RT::Authen::ExternalAuth::Test';
my $dir = File::Temp::tempdir( CLEANUP => 1 );
my $dbname = File::Spec->catfile( $dir, 'rtauthtest' );
commit 585a3b6a9cf9ef1f5012985c5236c04f11512ffa
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Thu May 12 01:52:02 2011 +0400
port ::DBI::CanonicalizeUserInfo over new API
diff --git a/lib/RT/Authen/ExternalAuth/DBI.pm b/lib/RT/Authen/ExternalAuth/DBI.pm
index 7099632..adc5a38 100644
--- a/lib/RT/Authen/ExternalAuth/DBI.pm
+++ b/lib/RT/Authen/ExternalAuth/DBI.pm
@@ -120,12 +120,10 @@ sub GetAuth {
sub CanonicalizeUserInfo {
- my ($service, $key, $value) = @_;
+ my ($service, $key, $value, $attrs) = @_;
my $found = 0;
- my %params = (Name => undef,
- EmailAddress => undef,
- RealName => undef);
+ my %params = ();
# Load the config
my $config = $RT::ExternalSettings->{$service};
@@ -147,27 +145,21 @@ sub CanonicalizeUserInfo {
return ($found, %params);
}
- # "where" refers to WHERE section of SQL query
- my ($where_key,$where_value) = ("@{[ $key ]}",$value);
-
# Get the list of unique attrs we need
- my %db_attrs = map {$_ => 1} values(%{$config->{'attr_map'}});
- my @attrs = keys(%db_attrs);
- my $fields = join(',', at attrs);
- my $query = "SELECT $fields FROM $table WHERE $where_key=?";
- my @bind_params = ($where_value);
+ my $query = "SELECT ". join(', ', @$attrs) ." FROM $table WHERE $key=?";
+ my @bind_params = ($value);
# Uncomment this to trace basic DBI throughput in a log
# DBI->trace(1,'/tmp/dbi.log');
my $dbh = _GetBoundDBIObj($config);
- my $results_hashref = $dbh->selectall_hashref($query,$key,{}, at bind_params);
+ my $results = $dbh->selectall_arrayref($query, undef, @bind_params);
$dbh->disconnect();
- if ((scalar keys %$results_hashref) != 1) {
+ if ( @$results != 1 ) {
# If returned users <> 1, we have no single unique user, so prepare to die
my $death_msg;
- if ((scalar keys %$results_hashref) == 0) {
+ if ( @$results == 0) {
# If no user...
$death_msg = "No User Found in External Database!";
} else {
@@ -190,14 +182,8 @@ sub CanonicalizeUserInfo {
# We haven't dropped out, so DB search must have succeeded with
# exactly 1 result. Get the result and set $found to 1
- my $result = $results_hashref->{$value};
-
- # Use the result to populate %params for every key we're given in the config
- foreach my $key (keys(%{$config->{'attr_map'}})) {
- $params{$key} = ($result->{$config->{'attr_map'}->{$key}})[0];
- }
-
$found = 1;
+ @params{ @$attrs } = @{ $results->[0] };
return ($found, %params);
}
commit d9d06f6a895270bdea4df985b8d66ade982c7062
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Fri May 13 01:28:37 2011 +0400
use M::I::Substitute for 'use lib ...' in ::Test
diff --git a/Makefile.PL b/Makefile.PL
index bf93ff5..a62a8ef 100755
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -32,6 +32,14 @@ recursive_author_tests('xt');
requires_rt('3.8.2');
+my ($lib_path) = $INC{'RT.pm'} =~ /^(.*)[\\\/]/;
+my $local_lib_path = "$RT::LocalPath/lib";
+substitute( {
+ RT_LIB_PATH => join( ' ', $local_lib_path, $lib_path ),
+ },
+ 'lib/RT/Authen/ExternalAuth/Test.pm',
+);
+
&auto_install();
my ($lib_path) = $INC{'RT.pm'} =~ /^(.*)[\\\/]/;
commit 462b2bd8fab377ffd0663328d181080f43470255
Author: Kevin Falcone <falcone at bestpractical.com>
Date: Thu May 12 18:12:17 2011 -0400
Remove comment copied from first refactored chunk
diff --git a/lib/RT/Authen/ExternalAuth/LDAP.pm b/lib/RT/Authen/ExternalAuth/LDAP.pm
index 15e0774..0bb5917 100644
--- a/lib/RT/Authen/ExternalAuth/LDAP.pm
+++ b/lib/RT/Authen/ExternalAuth/LDAP.pm
@@ -405,7 +405,6 @@ sub PerformSearch {
my $res = $ldap->search( %args );
return undef unless $res;
- # And the user isn't a member:
unless (
$res->code == LDAP_SUCCESS
|| $res->code == LDAP_PARTIAL_RESULTS
commit 6cd868e6f2264aea6cce2b51596846128c00f489
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Sat May 14 11:20:00 2011 +0400
test late sync, e.g. ExtAuth enabled on live system
diff --git a/xt/ldap/late-sync.t b/xt/ldap/late-sync.t
new file mode 100644
index 0000000..0673910
--- /dev/null
+++ b/xt/ldap/late-sync.t
@@ -0,0 +1,72 @@
+use strict;
+use warnings;
+
+use RT::Authen::ExternalAuth::Test ldap => 1, tests => 43;
+my $class = 'RT::Authen::ExternalAuth::Test';
+
+my ($server, $client) = $class->bootstrap_ldap_basics;
+ok( $server, "spawned test LDAP server" );
+
+my $queue = RT::Test->load_or_create_queue(Name => 'General');
+ok($queue->id, "loaded the General queue");
+
+RT->Config->Set( AutoCreate => { Privileged => 1 } );
+RT->Config->Set( AutoCreateNonExternalUsers => 1 );
+
+RT::Test->set_rights(
+ { Principal => 'Everyone', Right => [qw(SeeQueue ShowTicket CreateTicket)] },
+);
+
+my ( $baseurl, $m ) = RT::Test->started_ok();
+
+diag "send email w/o LDAP, login with LDAP";
+{
+ my $username = 'test1';
+ my $first_user;
+ {
+ my $mail = << "MAIL";
+Subject: Test
+From: $username\@invalid.tld
+
+test
+MAIL
+
+ my ($status, $id) = RT::Test->send_via_mailgate($mail);
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "got id of a newly created ticket - $id");
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok ($ticket->id, 'loaded ticket');
+
+ # no LDAP account
+ my $user = $first_user = $ticket->CreatorObj;
+ is( $user->Name, "$username\@invalid.tld" );
+ is( $user->EmailAddress, "$username\@invalid.tld" );
+ }
+
+ $class->add_ldap_user_simple( cn => $username );
+
+ {
+ ok( $m->login( $username, 'password' ), 'logged in' );
+
+ ok( $m->goto_create_ticket( $queue ), "go to create ticket" );
+ $m->form_name('TicketCreate');
+ $m->submit;
+
+ my ($id) = ($m->content =~ /.*Ticket (\d+) created.*/g);
+ ok $id, "created a ticket";
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok ($ticket->id, 'loaded ticket');
+
+ my $user = $ticket->CreatorObj;
+ is( $user->id, $first_user->id );
+ is( $user->Name, $username );
+ is( $user->EmailAddress, "$username\@invalid.tld" );
+ }
+}
+
+$client->unbind();
+$m->get_warnings;
commit d66ddaf6af9774ace89d1eae33eb40f603cb6be6
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Sat May 14 11:20:52 2011 +0400
make it possible to pass cn (name) into add_ldap_user_simple
diff --git a/lib/RT/Authen/ExternalAuth/Test.pm b/lib/RT/Authen/ExternalAuth/Test.pm
index 20c376a..9226a9d 100644
--- a/lib/RT/Authen/ExternalAuth/Test.pm
+++ b/lib/RT/Authen/ExternalAuth/Test.pm
@@ -136,7 +136,7 @@ sub add_ldap_user_simple {
my $self = shift;
my %args = @_;
- my $name = "testuser". ++$i;
+ my $name = delete $args{'cn'} || "testuser". ++$i;
s/\%name\b/$name/g foreach grep defined, values %args;
commit b45afe3016ce51a58d1a7bc87ca0dfb7e534f349
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Sat May 14 11:22:46 2011 +0400
split LoadByCols addition into two attempts
new attempt checks for not yet synced records, for example
user (foo at xxx, foo at xxx) logs in as foo which exist in external
source as (foo, foo at xxx).
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 24573e0..4796b7a 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -715,50 +715,132 @@ sub CanonicalizeUserInfo {
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 when
-# RT fields in attr_match_list are mapped to multiple attributes in an external
+# 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;
+ }
- # 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 $_,
- map $config->{'attr_map'}{ $_ },
- @{ $config->{'attr_match_list'} };
+ return $rv;
+ };
+}
+
+sub FindRecordsWithAlternatives {
+ my $user = shift;
+ my %args = @_;
- push @info_services, $service;
+ # 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 $_,
+ map $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;
}
- return $rv unless @info_services;
-
- # find user in external service and fetch alternative values
- # for a field
- my ($found, $search_by, @alternatives);
- foreach my $service (@info_services) {
- my $config = $RT::ExternalSettings->{$service};
-
- $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;
+ 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 =
+ map ref $_? @$_ : $_,
+ grep defined,
+ map $config->{'attr_map'}{ $_ },
+ grep $_ ne $search_by,
+ @{ $config->{'attr_match_list'} };
my @search_args = (
$service,
$config->{'attr_map'}{ $search_by },
$args{ $search_by },
- $config->{'attr_map'}{ $search_by },
+ \@fetch,
);
- my %params;
+ my ($found, %params);
if($config->{'type'} eq 'ldap') {
($found, %params) = RT::Authen::ExternalAuth::LDAP::CanonicalizeUserInfo( @search_args );
} elsif ($config->{'type'} eq 'db') {
@@ -771,20 +853,19 @@ sub CanonicalizeUserInfo {
}
next unless $found;
- @alternatives = grep defined && length && $_ ne $args{ $search_by }, values %params;
-
- # Don't Check any more services
- last;
- }
- return $rv unless $found;
-
- # lookup by alternatives
- foreach my $value ( @alternatives ) {
- my $rv = $orig->( $self, %args, $search_by => $value );
- return $rv if $self->id;
+ 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 $rv;
- };
+ }
+ return;
}
sub WorkaroundAutoCreate {
commit 20d1b2e392ba81bf152da2dee622d4c7a2730e23
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Sat May 14 12:32:54 2011 +0400
workaround some cache issues in a test
diff --git a/xt/ldap/late-sync.t b/xt/ldap/late-sync.t
index 0673910..b7028d8 100644
--- a/xt/ldap/late-sync.t
+++ b/xt/ldap/late-sync.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Authen::ExternalAuth::Test ldap => 1, tests => 43;
+use RT::Authen::ExternalAuth::Test ldap => 1, tests => 19;
my $class = 'RT::Authen::ExternalAuth::Test';
my ($server, $client) = $class->bootstrap_ldap_basics;
@@ -43,12 +43,16 @@ MAIL
my $user = $first_user = $ticket->CreatorObj;
is( $user->Name, "$username\@invalid.tld" );
is( $user->EmailAddress, "$username\@invalid.tld" );
+
+ # make user privileged to stop $m->login failing
+ $user->SetPrivileged(1) unless $user->Privileged;
}
+ DBIx::SearchBuilder::Record::Cachable->FlushCache;
$class->add_ldap_user_simple( cn => $username );
{
- ok( $m->login( $username, 'password' ), 'logged in' );
+ ok( custom_login( $username, 'password' ), 'logged in' );
ok( $m->goto_create_ticket( $queue ), "go to create ticket" );
$m->form_name('TicketCreate');
@@ -68,5 +72,18 @@ MAIL
}
}
+sub custom_login {
+ my $user = shift || 'root';
+ my $pass = shift || 'password';
+
+ $m->logout;
+
+ my $url = $m->rt_base_url;
+ $m->get($url . "?user=$user;pass=$pass");
+ return $m->status == 200
+ && $m->content =~ qr/Logout/i
+ && $m->content =~ m{<span>\Q$user\E\@invalid\.tld</span>}i;
+}
+
$client->unbind();
$m->get_warnings;
commit 5a11a1c2801a251f95ca6f489a77eacd330ef6ad
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Sat May 14 14:00:13 2011 +0400
drop inline tests
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 4796b7a..10542d1 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -128,7 +128,6 @@ This software is released under version 2 of the GNU
General Public License. The license is distributed with
this package in the LICENSE file found in the directory
root.
-
=cut
use RT::Authen::ExternalAuth::LDAP;
commit 096996ce3b708f84774b7b1a4939c37d631c4f06
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Sat May 14 14:01:37 2011 +0400
delete indent from POD
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 10542d1..d1cce38 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -4,16 +4,16 @@ our $VERSION = '0.10_01';
=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 UPGRADING
commit 7ba0ba3049a7e7deffdfd73b9209066b89a5307b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Sat May 14 14:25:13 2011 +0400
update changelog
diff --git a/ChangeLog b/ChangeLog
index 352ccfe..cdb0e0d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+
+ * avoid some user create/update conflicts when module enabled
+ on old system
+ * enable $AutoCreate config option for accounts created through
+ email submission
+ * support mapping user's field in RT to multiple attributes
+ in external source (LDAP/DBI)
+
0.10_01 2012-02-23 Thomas Sibley
* Escape usernames in filter values so special characters don't die
commit 1625971e01c9abd67426c7c834540051f1ac5bdd
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Sun May 15 00:14:51 2011 +0400
add documentation
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index d1cce38..e92ca83 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -113,6 +113,57 @@ Then use the examples provided to prepare your own custom
configuration which should be added to your site configuration in
$RTHOME/etc/RT_SiteConfig.pm
+=head1 CONFIGURATION
+
+=head2 Generic
+
+=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'],
+ ...
+ },
+
=head1 AUTHOR
Mike Peachey
Jennic Ltd.
@@ -867,6 +918,14 @@ sub FindRecordsByOtherFields {
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;
commit bd33ec167be6832224b89033494780c1e4f0e365
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon May 16 12:24:40 2011 +0400
update manifest
diff --git a/MANIFEST b/MANIFEST
index 5fe7c31..9935788 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -16,19 +16,24 @@ inc/Module/Install/Makefile.pm
inc/Module/Install/Metadata.pm
inc/Module/Install/ReadmeFromPod.pm
inc/Module/Install/RTx.pm
+inc/Module/Install/Substitute.pm
inc/Module/Install/Win32.pm
inc/Module/Install/WriteAll.pm
lib/RT/Authen/ExternalAuth.pm
lib/RT/Authen/ExternalAuth/DBI.pm
lib/RT/Authen/ExternalAuth/DBI/Cookie.pm
lib/RT/Authen/ExternalAuth/LDAP.pm
+lib/RT/Authen/ExternalAuth/Test.pm
LICENSE
Makefile.PL
MANIFEST This list of files
META.yml
README
-xt/ldap.t
+xt/ldap/basics.t
xt/ldap_escaping.t
xt/ldap_group.t
-xt/ldap_privileged.t
+xt/ldap/late-sync.t
+xt/ldap/multiple-emails.t
+xt/ldap/privileged.t
+xt/ldap/user-create.t
xt/sqlite.t
commit b7dd9ad8186f78a6c3dfd9b6d21dff67b8584a5b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Mon May 16 13:05:03 2011 +0400
update cangelog
diff --git a/ChangeLog b/ChangeLog
index cdb0e0d..bb274e1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,7 +3,9 @@
on old system
* enable $AutoCreate config option for accounts created through
email submission
- * support mapping user's field in RT to multiple attributes
+ * external info update was only possible by Name, now it
+ works for any field from attr_match_list
+ * support mapping fields in RT to multiple attributes
in external source (LDAP/DBI)
0.10_01 2012-02-23 Thomas Sibley
commit 6a21a97eba86250337c7f64046ec4a8164db3b44
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed May 18 01:41:15 2011 +0400
refactor long grep/map chains
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index e92ca83..e0d9e47 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -800,8 +800,7 @@ sub FindRecordsWithAlternatives {
my $config = $RT::ExternalSettings->{ $service };
next if $config->{'type'} eq 'cookie';
next unless
- grep ref $_,
- map $config->{'attr_map'}{ $_ },
+ grep ref $config->{'attr_map'}{ $_ },
@{ $config->{'attr_match_list'} };
push @info_services, $service;
@@ -877,12 +876,13 @@ sub FindRecordsByOtherFields {
&& defined $args{ $search_by }
&& length $args{ $search_by };
- my @fetch =
- map ref $_? @$_ : $_,
- grep defined,
- map $config->{'attr_map'}{ $_ },
- grep $_ ne $search_by,
- @{ $config->{'attr_match_list'} };
+ 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 },
commit 959c776e6f519bef2df5bb106a4a66151304cad3
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Tue Jun 5 22:09:04 2012 +0400
update M:I
diff --git a/META.yml b/META.yml
index f11a001..57463eb 100644
--- a/META.yml
+++ b/META.yml
@@ -1,5 +1,5 @@
---
-abstract: 'RT Authen-ExternalAuth Extension'
+abstract: 'RT Authentication using External Sources'
author:
- 'Mike Peachey'
- 'Mike Peachey <zordrak at cpan.org>'
commit 411b4e3553c7042728d76b50a5a3b8e3607f8082
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Jun 6 14:37:04 2012 +0400
on cold server record may not have method
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index e0d9e47..319afb3 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -623,7 +623,7 @@ sub CanonicalizeUserInfo {
my $field = shift;
return $args->{ $field } if keys %$args;
- return undef unless $UserObj->can( $field );
+ return undef if !$UserObj->can( $field ) && !exists $UserObj->_ClassAccessible->{$field};
return $UserObj->$field();
};
diff --git a/xt/ldap/late-sync.t b/xt/ldap/late-sync.t
index b7028d8..645eab5 100644
--- a/xt/ldap/late-sync.t
+++ b/xt/ldap/late-sync.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Authen::ExternalAuth::Test ldap => 1, tests => 19;
+use RT::Authen::ExternalAuth::Test ldap => 1, tests => 20;
my $class = 'RT::Authen::ExternalAuth::Test';
my ($server, $client) = $class->bootstrap_ldap_basics;
@@ -75,15 +75,14 @@ MAIL
sub custom_login {
my $user = shift || 'root';
my $pass = shift || 'password';
-
+
$m->logout;
my $url = $m->rt_base_url;
$m->get($url . "?user=$user;pass=$pass");
return $m->status == 200
&& $m->content =~ qr/Logout/i
- && $m->content =~ m{<span>\Q$user\E\@invalid\.tld</span>}i;
+ && $m->content =~ m{<span class="current-user">\Q$user\E\@invalid\.tld</span>}i;
}
$client->unbind();
-$m->get_warnings;
commit e1a555b59a873bafb93487d8240a7209cc014b18
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Jun 6 14:37:49 2012 +0400
minor test tweaks to pass on 4.0-trunk
diff --git a/xt/ldap/multiple-emails.t b/xt/ldap/multiple-emails.t
index 5ebe609..290923b 100644
--- a/xt/ldap/multiple-emails.t
+++ b/xt/ldap/multiple-emails.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Authen::ExternalAuth::Test ldap => 1, tests => 43;
+use RT::Authen::ExternalAuth::Test ldap => 1, tests => 44;
my $class = 'RT::Authen::ExternalAuth::Test';
my ($server, $client) = $class->bootstrap_ldap_basics;
@@ -115,7 +115,7 @@ MAIL
}
{
- ok( $m->login( $username, 'password' ), 'logged in' );
+ ok( $m->login( $username, 'password', logout => 1 ), 'logged in' );
ok( $m->goto_create_ticket( $queue ), "go to create ticket" );
$m->form_name('TicketCreate');
@@ -158,7 +158,6 @@ MAIL
}
$client->unbind();
-$m->get_warnings;
sub new_user { return $class->add_ldap_user_simple( alias => '%name at alternative.tld' ) }
diff --git a/xt/ldap/privileged.t b/xt/ldap/privileged.t
index d54997a..fc8210d 100644
--- a/xt/ldap/privileged.t
+++ b/xt/ldap/privileged.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Authen::ExternalAuth::Test ldap => 1, tests => 20;
+use RT::Authen::ExternalAuth::Test ldap => 1, tests => 19;
my $class = 'RT::Authen::ExternalAuth::Test';
my ($server, $client) = $class->bootstrap_ldap_basics;
@@ -56,10 +56,9 @@ MAIL
ok($user->Privileged, 'privileged user');
}
{
- ok( $m->login( $username, 'password' ), 'logged in' );
+ ok( $m->login( $username, 'password', logout => 1 ), 'logged in' );
unlike( $m->uri, qr!SelfService!, 'privileged home page' );
}
}
$client->unbind();
-$m->get_warnings;
diff --git a/xt/sqlite.t b/xt/sqlite.t
index 0e04b22..fa4313e 100644
--- a/xt/sqlite.t
+++ b/xt/sqlite.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Authen::ExternalAuth::Test dbi => 'SQLite', tests => 19;
+use RT::Authen::ExternalAuth::Test dbi => 'SQLite', tests => 21;
my $class = 'RT::Authen::ExternalAuth::Test';
my $dir = File::Temp::tempdir( CLEANUP => 1 );
commit 3d57a3dac5e24c70e544af2237eb9a12d6fc4b6f
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Jun 6 14:39:00 2012 +0400
update README
diff --git a/README b/README
index 5ee8a9e..6b2c65a 100644
--- a/README
+++ b/README
@@ -1,13 +1,13 @@
NAME
- RT::Authen::ExternalAuth - RT Authentication using External Sources
+ RT::Authen::ExternalAuth - RT Authentication using External Sources
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.
UPGRADING
If you are upgrading from an earlier version of this extension, you must
@@ -95,6 +95,53 @@ INSTALLATION
which should be added to your site configuration in
$RTHOME/etc/RT_SiteConfig.pm
+CONFIGURATION
+ Generic
+ 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',
+ ],
+
+ 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 "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'],
+ ...
+ },
+
AUTHOR
Mike Peachey
Jennic Ltd.
@@ -108,3 +155,8 @@ COPYRIGHT AND LICENCE
License. The license is distributed with this package in the LICENSE
file found in the directory root.
+ WorkaroundAutoCreate
+ RT has $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.
+
commit 4270c0fe09410f56a115d71d8ff101ae58b312eb
Author: Jim Brandt <jbrandt at bestpractical.com>
Date: Tue Jun 26 13:01:01 2012 -0400
Skip LDAP entries in config that have no value
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 319afb3..6c00647 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -179,6 +179,7 @@ This software is released under version 2 of the GNU
General Public License. The license is distributed with
this package in the LICENSE file found in the directory
root.
+
=cut
use RT::Authen::ExternalAuth::LDAP;
@@ -773,6 +774,7 @@ sub CanonicalizeUserInfo {
my (%other) = FindRecordsByOtherFields( $self, %args );
while ( my ($search_by, $values) = each %other ) {
foreach my $value ( @$values ) {
+ next if not defined $value; # Entry in config, but no value in LDAP
my $rv = $orig->( $self, $search_by => $value );
return $rv if $self->id;
}
diff --git a/xt/ldap/multiple-emails.t b/xt/ldap/multiple-emails.t
index 290923b..5d762c4 100644
--- a/xt/ldap/multiple-emails.t
+++ b/xt/ldap/multiple-emails.t
@@ -13,7 +13,7 @@ ok($queue->id, "loaded the General queue");
RT->Config->Set( AutoCreate => { Privileged => 1 } );
RT->Config->Get('ExternalSettings')->{'My_LDAP'}{'attr_map'}{'EmailAddress'}
- = ['mail', 'alias'];
+ = ['mail', 'alias', 'proxyAddresses', 'foo'];
RT::Test->set_rights(
{ Principal => 'Everyone', Right => [qw(SeeQueue ShowTicket CreateTicket)] },
commit a49670bfa14b559070987561d6d1dd2e8682bc7d
Author: Jim Brandt <jbrandt at bestpractical.com>
Date: Tue Jun 26 13:05:57 2012 -0400
Return search_by as first value from FindRecordsWithAlternatives
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 6c00647..80b0ca1 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -849,7 +849,7 @@ sub FindRecordsWithAlternatives {
my @alternatives = grep defined && length && $_ ne $args{ $search_by }, values %params;
# Don't Check any more services
- return @alternatives;
+ return ($search_by, @alternatives);
}
return;
}
commit b3d3ca4285d32a8e29771d81980bb2ac5806472e
Author: Jim Brandt <jbrandt at bestpractical.com>
Date: Tue Jun 26 15:30:41 2012 -0400
Add option to prepend values on LDAP search filter
Customer AD configurations contain entries in the form:
proxyAddresses: smtp:email at test.com
where AD puts the 'smtp:' prefix on the email address. This commit
adds a configuration option to pass in a value to be prepended
to the incoming email address in the LDAP filter. This allows
alternate email addresses listed in attributes like proxyAddresses
to match.
It sets smtp: as a default for proxyAddresses since it seems to be
the common case for AD.
diff --git a/lib/RT/Authen/ExternalAuth.pm b/lib/RT/Authen/ExternalAuth.pm
index 80b0ca1..f9c725d 100644
--- a/lib/RT/Authen/ExternalAuth.pm
+++ b/lib/RT/Authen/ExternalAuth.pm
@@ -151,10 +151,10 @@ external attributes, for example:
...
},
-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
+Note that only one value is stored in RT. However, the search includes
+all external attributes if the RT field is listed in L</attr_match_list>.
+On create or update, the entered value is used as long as it's valid.
+If the user didn't enter a value then the value stored in the first external
attribute is used. Config example:
attr_match_list => ['Name', 'EmailAddress'],
@@ -164,6 +164,25 @@ attribute is used. Config example:
...
},
+=head3 attr_prefix
+
+In some cases, multiple-value LDAP attributes may have a prefix on the values
+in the LDAP entry. The C<attr_prefix> allows you to set values to prepend to
+filter terms before searching. For example, if you want an email address to
+match 'alias' in an LDAP entry that prepends 'other:' to the email
+address, you can do the following:
+
+ attr_prefix => {
+ alias => ['other:'],
+ ...
+ },
+
+The key must be included in the C<attr_map> or it won't be checked.
+To search on an attribute with no value prepended in addition to
+some prepended values, include an empty string C<''> in the list.
+The most common case for this is the proxyAddresses needing the
+value 'smtp:' prepended, so that happens automatically.
+
=head1 AUTHOR
Mike Peachey
Jennic Ltd.
diff --git a/lib/RT/Authen/ExternalAuth/LDAP.pm b/lib/RT/Authen/ExternalAuth/LDAP.pm
index 0bb5917..c0b6651 100644
--- a/lib/RT/Authen/ExternalAuth/LDAP.pm
+++ b/lib/RT/Authen/ExternalAuth/LDAP.pm
@@ -135,9 +135,28 @@ sub CanonicalizeUserInfo {
# Load the config
my $config = $RT::ExternalSettings->{$service};
+ # Default smtp: as the most common case
+ my %filter_prefix = (
+ proxyAddresses => [ 'smtp:'],
+ %{$config->{'attr_prefix'}}
+ );
+
+ # Build the LDAP filters
+ my @filter_list;
+ foreach my $filter_key ( ref $key ? @$key : ($key) ){
+ push @filter_list, "($filter_key=" . escape_filter_value( $value ) . ")";
+
+ # Prepend prefixes for AD
+ if( exists $filter_prefix{$filter_key} ){
+ foreach my $prefix ( @{ $filter_prefix{$filter_key} } ){
+ push @filter_list, "($filter_key=" . escape_filter_value( $prefix . $value ) . ")";
+ }
+ }
+ }
+
my $filter = JoinFilters(
'&',
- JoinFilters('|', map "($_=". escape_filter_value( $value ) .")", ref $key? @$key: ($key) ),
+ JoinFilters('|', @filter_list ),
$config->{'filter'},
) or return (0);
diff --git a/xt/ldap/multiple-emails.t b/xt/ldap/multiple-emails.t
index 5d762c4..495f6e8 100644
--- a/xt/ldap/multiple-emails.t
+++ b/xt/ldap/multiple-emails.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Authen::ExternalAuth::Test ldap => 1, tests => 44;
+use RT::Authen::ExternalAuth::Test ldap => 1, tests => 50;
my $class = 'RT::Authen::ExternalAuth::Test';
my ($server, $client) = $class->bootstrap_ldap_basics;
@@ -15,6 +15,9 @@ RT->Config->Set( AutoCreate => { Privileged => 1 } );
RT->Config->Get('ExternalSettings')->{'My_LDAP'}{'attr_map'}{'EmailAddress'}
= ['mail', 'alias', 'proxyAddresses', 'foo'];
+RT->Config->Get('ExternalSettings')->{'My_LDAP'}{'attr_prefix'}{'proxyAddresses'}
+ = [ 'smtp:', 'SMTP:', 'X400:', '' ];
+
RT::Test->set_rights(
{ Principal => 'Everyone', Right => [qw(SeeQueue ShowTicket CreateTicket)] },
);
@@ -44,6 +47,7 @@ diag "login then send emails from different addresses";
is( $user->EmailAddress, "$username\@invalid.tld" );
}
+ diag "Send first email from initial address.";
{
my $mail = << "MAIL";
Subject: Test
@@ -66,6 +70,7 @@ MAIL
is( $user->EmailAddress, "$username\@invalid.tld" );
}
+ diag "Send email from alias address.";
{
my $mail = << "MAIL";
Subject: Test
@@ -87,6 +92,31 @@ MAIL
is( $user->Name, $username );
is( $user->EmailAddress, "$username\@invalid.tld" );
}
+
+ diag "Send email from smtp: address.";
+ my $smtp = substr($username, 1);
+ {
+ my $mail = << "MAIL";
+Subject: Test
+From: $smtp\@alternative.tld
+
+test
+MAIL
+
+ my ($status, $id) = RT::Test->send_via_mailgate($mail);
+ is ($status >> 8, 0, "The mail gateway exited normally");
+ ok ($id, "got id of a newly created ticket - $id");
+
+ my $ticket = RT::Ticket->new( $RT::SystemUser );
+ $ticket->Load( $id );
+ ok ($ticket->id, 'loaded ticket');
+
+ my $user = $ticket->CreatorObj;
+ is( $user->id, $first_user->id );
+ is( $user->Name, $username );
+ is( $user->EmailAddress, "$username\@invalid.tld", "Got original email address with smtp email." );
+ }
+
}
diag "send a mail from alternative address, then try other credentials";
@@ -159,5 +189,6 @@ MAIL
$client->unbind();
-sub new_user { return $class->add_ldap_user_simple( alias => '%name at alternative.tld' ) }
+sub new_user { return $class->add_ldap_user_simple( alias => '%name at alternative.tld',
+ add_proxy_addresses => 'alternative.tld') }
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list