[Bps-public-commit] RT-Extension-LDAPImport branch, master, updated. 0.34-4-gece2248
Ruslan Zakirov
ruz at bestpractical.com
Fri Feb 8 16:49:04 EST 2013
The branch, master has been updated
via ece2248ed378526817c914a98a099d6172035daf (commit)
via 5d91d247ac731bbe77a2b6f7978924f452a701ae (commit)
via 96b9ac3dfa9a5e6bde882b10ce044a6809daa504 (commit)
via a2d2b71160aa340c72deba8967e7fb5a117b3192 (commit)
from f955e5a6e526ed98cc1f1f3a904033e22a8a3914 (commit)
Summary of changes:
META.yml | 2 +-
README | 12 ++--
inc/Module/Install/RTx.pm | 2 +-
inc/Module/Install/ReadmeFromPod.pm | 2 +-
lib/RT/Extension/LDAPImport.pm | 104 ++++++++++++++++++++++++++-
t/group-rename.t | 138 ++++++++++++++++++++++++++++++++++++
6 files changed, 250 insertions(+), 10 deletions(-)
create mode 100644 t/group-rename.t
- Log -----------------------------------------------------------------
commit a2d2b71160aa340c72deba8967e7fb5a117b3192
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Fri Feb 8 21:43:22 2013 +0400
update M::I
diff --git a/inc/Module/Install/RTx.pm b/inc/Module/Install/RTx.pm
index 2eba7ad..ce01018 100644
--- a/inc/Module/Install/RTx.pm
+++ b/inc/Module/Install/RTx.pm
@@ -8,7 +8,7 @@ no warnings 'once';
use Module::Install::Base;
use base 'Module::Install::Base';
-our $VERSION = '0.29_02';
+our $VERSION = '0.30';
use FindBin;
use File::Glob ();
diff --git a/inc/Module/Install/ReadmeFromPod.pm b/inc/Module/Install/ReadmeFromPod.pm
index fb7075f..6a80818 100644
--- a/inc/Module/Install/ReadmeFromPod.pm
+++ b/inc/Module/Install/ReadmeFromPod.pm
@@ -7,7 +7,7 @@ use warnings;
use base qw(Module::Install::Base);
use vars qw($VERSION);
-$VERSION = '0.18';
+$VERSION = '0.20';
sub readme_from {
my $self = shift;
commit 96b9ac3dfa9a5e6bde882b10ce044a6809daa504
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Fri Feb 8 21:44:00 2013 +0400
update META, version change
diff --git a/META.yml b/META.yml
index 647cba0..83a3b79 100644
--- a/META.yml
+++ b/META.yml
@@ -28,4 +28,4 @@ requires:
Test::More: 0
resources:
license: http://dev.perl.org/licenses/
-version: 0.33_02
+version: 0.34
commit 5d91d247ac731bbe77a2b6f7978924f452a701ae
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Fri Feb 8 21:45:27 2013 +0400
readme update
diff --git a/README b/README
index b06a008..e4a52fd 100644
--- a/README
+++ b/README
@@ -298,11 +298,6 @@ METHODS
If $LDAPUpdateOnly is true, we will not create new users but we will
update existing ones.
- update_rt_user
- Takes a hash with a user object as "user" and a hashref of updated
- values as "info". Mimics RT::Record's "Update" method, but without
- side-effects of newline normalization.
-
add_user_to_group
Adds new users to the group specified in the $LDAPGroupName variable
(defaults to 'Imported from LDAP'). You can avoid this if you set
commit ece2248ed378526817c914a98a099d6172035daf
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Sat Feb 9 01:36:18 2013 +0400
handle group renames with new option
diff --git a/README b/README
index e4a52fd..1f82ada 100644
--- a/README
+++ b/README
@@ -139,6 +139,13 @@ CONFIGURATION
identifier (dn or other LDAP field) on a user record means the user
will be added to that group in RT.
+ "id" is the field in LDAP group record that uniquely identifies the
+ group. This is optional and shouldn't be equal to mapping for Name
+ field. Group names in RT must be distinct and you don't need another
+ unique identifier in common situation. However, when you rename a
+ group in LDAP, without this option set properly you end up with two
+ groups in RT.
+
You can provide a "Description" key which will be added as the group
description in RT. The default description is 'Imported from LDAP'.
diff --git a/lib/RT/Extension/LDAPImport.pm b/lib/RT/Extension/LDAPImport.pm
index 04e37ba..421ebe6 100644
--- a/lib/RT/Extension/LDAPImport.pm
+++ b/lib/RT/Extension/LDAPImport.pm
@@ -174,6 +174,13 @@ A match between the member field on the group record and this
identifier (dn or other LDAP field) on a user record means the
user will be added to that group in RT.
+C<id> is the field in LDAP group record that uniquely identifies
+the group. This is optional and shouldn't be equal to mapping for
+Name field. Group names in RT must be distinct and you don't need
+another unique identifier in common situation. However, when you
+rename a group in LDAP, without this option set properly you end
+up with two groups in RT.
+
You can provide a C<Description> key which will be added as the group
description in RT. The default description is 'Imported from LDAP'.
@@ -1004,8 +1011,10 @@ sub create_rt_group {
my %args = @_;
my $group = $args{group};
- my $group_obj = RT::Group->new($RT::SystemUser);
- $group_obj->LoadUserDefinedGroup( $group->{Name} );
+ my $group_obj = $self->find_rt_group(%args);
+ return unless defined $group_obj;
+
+ my $id = delete $group->{'id'};
my $created;
if ($group_obj->Id) {
@@ -1031,6 +1040,15 @@ sub create_rt_group {
}
$created = $val;
$self->_debug("Created group for $group->{Name} with id ".$group_obj->Id);
+
+ if ( $id ) {
+ my ($val, $msg) = $group_obj->SetAttribute( Name => 'LDAPImport-gid-'.$id, Content => 1 );
+ unless ($val) {
+ $self->_error("couldn't set attribute: $msg");
+ return;
+ }
+ }
+
} else {
print "Found new group $group->{Name} to create in RT\n";
$self->_show_group_info( %args );
@@ -1045,6 +1063,88 @@ sub create_rt_group {
}
+sub find_rt_group {
+ my $self = shift;
+ my %args = @_;
+ my $group = $args{group};
+
+ my $group_obj = RT::Group->new($RT::SystemUser);
+ $group_obj->LoadUserDefinedGroup( $group->{Name} );
+ return $group_obj unless $group->{'id'};
+
+ unless ( $group_obj->id ) {
+ $self->_debug("No group in RT named $group->{Name}. Looking by $group->{id} LDAP id.");
+ $group_obj = $self->find_rt_group_by_ldap_id( $group->{'id'} );
+ unless ( $group_obj ) {
+ $self->_debug("No group in RT with LDAP id $group->{id}. Creating a new one.");
+ return RT::Group->new($RT::SystemUser);
+ }
+
+ $self->_debug("No group in RT named $group->{Name}, but found group by LDAP id $group->{id}. Renaming the group.");
+ # $group->Update will take care of the name
+ return $group_obj;
+ }
+
+ my $attr_name = 'LDAPImport-gid-'. $group->{'id'};
+ my $rt_gid = $group_obj->FirstAttribute( $attr_name );
+ return $group_obj if $rt_gid;
+
+ my $other_group = $self->find_rt_group_by_ldap_id( $group->{'id'} );
+ if ( $other_group ) {
+ $self->_debug("Group with LDAP id $group->{id} exists, as well as group named $group->{Name}. Renaming both.");
+ }
+ elsif ( grep $_->Name =~ /^LDAPImport-gid-/, @{ $group_obj->Attributes->ItemsArrayRef } ) {
+ $self->_debug("No group in RT with LDAP id $group->{id}, but group $group->{Name} has id. Renaming the group and creating a new one.");
+ }
+ else {
+ $self->_debug("No group in RT with LDAP id $group->{id}, but group $group->{Name} exists and has no LDAP id. Assigning the id to the group.");
+ if ( $args{import} ) {
+ my ($status, $msg) = $group_obj->SetAttribute( Name => $attr_name, Content => 1 );
+ unless ( $status ) {
+ $self->_error("Couldn't set attribute: $msg");
+ return undef;
+ }
+ $self->_debug("Assigned $group->{id} LDAP group id to $group->{Name}");
+ }
+ else {
+ print "Group $group->{'Name'} gets LDAP id $group->{id}\n";
+ }
+
+ return $group_obj;
+ }
+
+ # rename existing group to move it out of our way
+ {
+ my ($old, $new) = ($group_obj->Name, $group_obj->Name .' (LDAPImport '. time . ')');
+ if ( $args{import} ) {
+ my ($status, $msg) = $group_obj->SetName( $new );
+ unless ( $status ) {
+ $self->_error("Couldn't rename group from $old to $new: $msg");
+ return undef;
+ }
+ $self->_debug("Renamed group $old to $new");
+ }
+ else {
+ print "Group $old to be renamed to $new\n";
+ }
+ }
+
+ return $other_group || RT::Group->new($RT::SystemUser);
+}
+
+sub find_rt_group_by_ldap_id {
+ my $self = shift;
+ my $id = shift;
+
+ my $groups = RT::Groups->new( RT->SystemUser );
+ $groups->LimitToUserDefinedGroups;
+ my $attr_alias = $groups->Join( FIELD1 => 'id', TABLE2 => 'Attributes', FIELD2 => 'ObjectId' );
+ $groups->Limit( ALIAS => $attr_alias, FIELD => 'ObjectType', VALUE => 'RT::Group' );
+ $groups->Limit( ALIAS => $attr_alias, FIELD => 'Name', VALUE => 'LDAPImport-gid-'. $id );
+ return $groups->First;
+}
+
+
=head3 add_group_members
Iterate over the list of values in the C<Member_Attr> LDAP entry.
diff --git a/t/group-rename.t b/t/group-rename.t
new file mode 100644
index 0000000..1cf4f07
--- /dev/null
+++ b/t/group-rename.t
@@ -0,0 +1,138 @@
+use strict;
+use warnings;
+use lib 't/lib';
+use RT::Extension::LDAPImport::Test tests => 66;
+eval { require Net::LDAP::Server::Test; 1; } or do {
+ plan skip_all => 'Unable to test without Net::Server::LDAP::Test';
+};
+
+use Net::LDAP::Entry;
+use RT::User;
+
+my $importer = RT::Extension::LDAPImport->new;
+isa_ok($importer,'RT::Extension::LDAPImport');
+
+my $ldap_port = 1024 + int rand(10000) + $$ % 1024;
+ok( my $server = Net::LDAP::Server::Test->new( $ldap_port, auto_schema => 1 ),
+ "spawned test LDAP server on port $ldap_port");
+my $ldap = Net::LDAP->new("localhost:$ldap_port");
+$ldap->bind();
+$ldap->add("dc=bestpractical,dc=com");
+
+my @ldap_user_entries;
+for ( 1 .. 12 ) {
+ my $username = "testuser$_";
+ my $dn = "uid=$username,ou=foo,dc=bestpractical,dc=com";
+ my $entry = {
+ dn => $dn,
+ cn => "Test User $_",
+ mail => "$username\@invalid.tld",
+ uid => $username,
+ objectClass => 'User',
+ };
+ push @ldap_user_entries, $entry;
+ $ldap->add( $dn, attr => [%$entry] );
+}
+
+my @ldap_group_entries;
+for ( 1 .. 4 ) {
+ my $groupname = "Test Group $_";
+ my $dn = "cn=$groupname,ou=groups,dc=bestpractical,dc=com";
+ my $entry = {
+ cn => $groupname,
+ gid => $_,
+ members => [ map { $_->{dn} } @ldap_user_entries[($_-1),($_+3),($_+7)] ],
+ objectClass => 'Group',
+ };
+ $ldap->add( $dn, attr => [%$entry] );
+ push @ldap_group_entries, $entry;
+}
+
+RT->Config->Set('LDAPHost',"ldap://localhost:$ldap_port");
+RT->Config->Set('LDAPMapping',
+ {Name => 'uid',
+ EmailAddress => 'mail',
+ RealName => 'cn'});
+RT->Config->Set('LDAPBase','dc=bestpractical,dc=com');
+RT->Config->Set('LDAPFilter','(objectClass=User)');
+RT->Config->Set('LDAPSkipAutogeneratedGroup',1);
+
+RT->Config->Set('LDAPGroupBase','dc=bestpractical,dc=com');
+RT->Config->Set('LDAPGroupFilter','(objectClass=Group)');
+RT->Config->Set('LDAPGroupMapping',
+ {
+ Name => 'cn',
+ Member_Attr => 'members',
+ });
+
+ok( $importer->import_users( import => 1 ), 'imported users');
+# no id mapping
+{
+ ok( $importer->import_groups( import => 1 ), "imported groups" );
+
+ is_member_of('testuser1', 'Test Group 1');
+ ok !get_group('Test Group 1')->FirstAttribute('LDAPImport-gid-1');
+}
+
+# map id
+{
+ RT->Config->Get('LDAPGroupMapping')->{'id'} = 'gid';
+ ok( $importer->import_groups( import => 1 ), "imported groups" );
+
+ is_member_of('testuser1', 'Test Group 1');
+ ok get_group('Test Group 1')->FirstAttribute('LDAPImport-gid-1');
+}
+
+# rename a group
+{
+ $ldap->modify(
+ "cn=Test Group 1,ou=groups,dc=bestpractical,dc=com",
+ replace => { 'cn' => 'Test Group 1 Renamed' },
+ );
+ ok( $importer->import_groups( import => 1 ), "imported groups" );
+ ok !get_group('Test Group 1')->id;
+ is_member_of('testuser1', 'Test Group 1 Renamed');
+ ok get_group('Test Group 1 Renamed')->FirstAttribute('LDAPImport-gid-1');
+}
+
+# swap two groups
+{
+ is_member_of('testuser2', 'Test Group 2');
+ is_member_of('testuser3', 'Test Group 3');
+ $ldap->modify(
+ "cn=Test Group 2,ou=groups,dc=bestpractical,dc=com",
+ replace => { 'cn' => 'Test Group 3' },
+ );
+ $ldap->modify(
+ "cn=Test Group 3,ou=groups,dc=bestpractical,dc=com",
+ replace => { 'cn' => 'Test Group 2' },
+ );
+ ok( $importer->import_groups( import => 1 ), "imported groups" );
+ is_member_of('testuser2', 'Test Group 3');
+ is_member_of('testuser3', 'Test Group 2');
+ ok get_group('Test Group 2')->FirstAttribute('LDAPImport-gid-3');
+ ok get_group('Test Group 3')->FirstAttribute('LDAPImport-gid-2');
+}
+
+sub is_member_of {
+ my $uname = shift;
+ my $gname = shift;
+
+ my $group = get_group($gname);
+ return ok(0, "found group $gname") unless $group->id;
+
+ my $user = RT::User->new($RT::SystemUser);
+ $user->Load( $uname );
+ return ok(0, "found user $uname") unless $user->id;
+
+ return ok($group->HasMember($user->id), "$uname is member of $gname");
+}
+
+sub get_group {
+ my $gname = shift;
+ my $group = RT::Group->new($RT::SystemUser);
+ $group->LoadUserDefinedGroup( $gname );
+ return $group;
+}
+
+
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list