[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