[Bps-public-commit] RT-Extension-LDAPImport branch, 0.32.03/documentation-updates, updated. 0.32_03-4-g3785d1a

Jim Brandt jbrandt at bestpractical.com
Tue Apr 10 09:06:36 EDT 2012


The branch, 0.32.03/documentation-updates has been updated
       via  3785d1a087e572d0b4ec1b8e0875d1fbaecebe13 (commit)
       via  3bf9a098d0a32c516f9aed41c1f254d7488713db (commit)
      from  f5b2b5c7d0a02577f36782bebfdc5ff2082f9951 (commit)

Summary of changes:
 README => INSTALL                   |    4 +-
 Makefile.PL                         |    1 +
 README                              |  397 ++++++++++++++++++++++++++++++++---
 inc/Module/Install/ReadmeFromPod.pm |  138 ++++++++++++
 lib/RT/Extension/LDAPImport.pm      |  208 ++++++++----------
 t/group-import.t                    |   35 +---
 6 files changed, 604 insertions(+), 179 deletions(-)
 copy README => INSTALL (90%)
 create mode 100644 inc/Module/Install/ReadmeFromPod.pm

- Log -----------------------------------------------------------------
commit 3bf9a098d0a32c516f9aed41c1f254d7488713db
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Mon Apr 9 13:32:22 2012 -0400

    Moved this feature to another branch.
    
    Revert "Added a feature to allow you to use a regex to match an LDAP
    member field. But upon further review, I don't think it would ever
    be needed unless someone's LDAP was really mis-configured. So this
    commit is for posterity only."
    
    This reverts commit f5b2b5c7d0a02577f36782bebfdc5ff2082f9951.

diff --git a/lib/RT/Extension/LDAPImport.pm b/lib/RT/Extension/LDAPImport.pm
index 198a14f..c481021 100644
--- a/lib/RT/Extension/LDAPImport.pm
+++ b/lib/RT/Extension/LDAPImport.pm
@@ -138,7 +138,7 @@ The search filter to apply.
 
     Set($LDAPGroupMapping, {Name               => 'cn',
                             Member_Attr        => 'member',
-                            Member_Attr_Value  => 'dn'});
+                            Member_Attr_Value  => 'dn' });
 
 A mapping of RT attributes to LDAP attributes to identify group members.
 Name will become the name of the group in RT, in this case pulling
@@ -158,21 +158,6 @@ user will be added to that group 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'.
 
-If the LDAP group field you are mapping to doesn't have a
-simple username, you provide a regex to pull the name out
-with Member_Attr_Regex. The capture value in the regex will be
-used to find the username.
-
-    Set($LDAPGroupMapping, {Name               => 'cn',
-                            Member_Attr        => 'member',
-                            Member_Attr_Value  => 'dn'
-                            Member_Attr_Regex   => qr/^cn=(\w+)\,/,
-                           });
-
-The above would pull the name out of an entry something like
-
-    cn=somename,ou=company
-
 =item Set($LDAPSizeLimit, 1000);
 
 You can set this value if your LDAP server has result size limits.
@@ -1082,13 +1067,6 @@ sub _get_group_members_from_ldap {
     my $mapping = $RT::LDAPGroupMapping;
 
     my $members = $ldap_entry->get_value($mapping->{Member_Attr}, asref => 1);
-
-    if ( exists $mapping->{Member_Attr_Regex}
-	 and defined $mapping->{Member_Attr_Regex} ) {
-      @{$members} = map{ /$mapping->{Member_Attr_Regex}/ } @{$members};
-    }
-
-    return $members;
 }
 
 
diff --git a/t/group-import.t b/t/group-import.t
index e15754b..6d28e80 100644
--- a/t/group-import.t
+++ b/t/group-import.t
@@ -1,7 +1,7 @@
 use strict;
 use warnings;
 use lib 't/lib';
-use RT::Extension::LDAPImport::Test tests => 74;
+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';
 };
@@ -99,39 +99,6 @@ RT->Config->Set('LDAPGroupMapping',
                    });
 import_group_members_ok( memberUid => 'uid' );
 
-# Test a regex on Member_Attr
-# This is for a case where the member attribute
-# isn't the simple member name.
-
- at ldap_group_entries = ();
-{
-    my $groupname = "Test Group 5";
-    my $dn = "cn=$groupname,ou=groups,dc=bestpractical,dc=com";
-    my $entry = {
-        cn   =>  $groupname,
-        members => [ map { $_->{dn} } @ldap_user_entries[3,7,11] ],
-       # Make an entries that looks like cn=testuser12,ou=foo,dc=bestpractical
-        memberUid => [ map { 'cn=' . $_->{uid} . ',ou=foo,dc=bestpractical' }
-		       @ldap_user_entries[3,7,11] ],
-        objectClass => 'Test5',
-    };
-    $ldap->add( $dn, attr => [%$entry] );
-
-    # Fix entry for expected value after regex.
-    $entry->{memberUid} = [ map { $_->{uid} } @ldap_user_entries[3,7,11] ];
-    push @ldap_group_entries, $entry;
-}
-
-RT->Config->Set('LDAPGroupFilter','(objectClass=Test5)');
-RT->Config->Set('LDAPGroupMapping',
-                   {Name                => 'cn',
-                    Member_Attr         => 'memberUid',
-                    Member_Attr_Value   => 'uid',
-		    Member_Attr_Regex   => qr/^cn=(\w+)\,/,
-                   });
-
-import_group_members_ok( memberUid => 'uid' );
-
 sub import_group_members_ok {
     my $attr = shift;
     my $user_attr = shift;

commit 3785d1a087e572d0b4ec1b8e0875d1fbaecebe13
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Tue Apr 10 09:04:23 2012 -0400

    More updates to documentation.
    
    Moved install instructions to INSTALL.
    
    README is now generated from the pod via ReadmeFromPod.
    
    Some more updates to pod in main file.

diff --git a/README b/INSTALL
similarity index 90%
copy from README
copy to INSTALL
index 6f3fc6f..d8769bf 100644
--- a/README
+++ b/INSTALL
@@ -7,11 +7,11 @@ How to install:
 1. perl Makefile.PL
 2. make
 3. make install (may need root permissions)
-4. Edit your /opt/rt4/etc/RT_SiteConfig.pm 
+4. Edit your /path-to-rt/etc/RT_SiteConfig.pm 
     Set(@Plugins, qw(RT::Extension::LDAPImport));
     or add RT::Extension::LDAPImport to your existing @Plugins line
 5. Clear your mason cache
-     rm -rf /opt/rt4/var/mason_data/obj
+     rm -rf /path-to-rt/var/mason_data/obj
 6. Restart your webserver
 
 This will install an rtldapimport script in
diff --git a/Makefile.PL b/Makefile.PL
index f7a15bc..8ecc144 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -5,6 +5,7 @@ author ('Kevin Falcone <falcone at bestpractical.com>');
 license('perl');
 abstract('Import RT Users from an LDAP store');
 all_from('lib/RT/Extension/LDAPImport.pm');
+readme_from('lib/RT/Extension/LDAPImport.pm');
 
 requires('Test::More');
 requires('Net::LDAP');
diff --git a/README b/README
index 6f3fc6f..b52343b 100644
--- a/README
+++ b/README
@@ -1,41 +1,382 @@
-RT-Extension-LDAPImport
+NAME
+    RT::Extension::LDAPImport - Import Users from an LDAP store
 
-INSTALLATION
+SYNOPSIS
+        # In RT_SiteConfig.pm
 
-How to install:
+        Set($LDAPHost,'my.ldap.host')
+        Set($LDAPUSER,'me');
+        Set($LDAPPassword,'mypass');
+        Set($LDAPFilter, '(&(cn = users))');
+        Set($LDAPMapping, {Name         => 'uid', # required
+                           EmailAddress => 'mail',
+                           RealName     => 'cn',
+                           WorkPhone    => 'telephoneNumber',
+                           Organization => 'departmentName'});
 
-1. perl Makefile.PL
-2. make
-3. make install (may need root permissions)
-4. Edit your /opt/rt4/etc/RT_SiteConfig.pm 
-    Set(@Plugins, qw(RT::Extension::LDAPImport));
-    or add RT::Extension::LDAPImport to your existing @Plugins line
-5. Clear your mason cache
-     rm -rf /opt/rt4/var/mason_data/obj
-6. Restart your webserver
+        # If you want to sync Groups RT <-> LDAP
 
-This will install an rtldapimport script in
-/opt/rt4/local/plugins/RT-Extension-LDAPImport/bin
-and install the RT::Extension::LDAPImport
-module.
+        Set($LDAPGroupBase, 'ou=Groups,o=Our Place');
+        Set($LDAPGroupFilter, '(&(cn = Groups))');
+        Set($LDAPGroupMapping, {Name               => 'cn',
+                                Member_Attr        => 'member',
+                                Member_Attr_Value  => 'dn' });
 
-RUNNING THE IMPORTER
+        # Run a test import
+        /opt/rt4/local/plugins/RT-Extension-LDAPImport/bin/rtldapimport \
+        --debug > ldapimport.debug 2>&1
 
-Set the module documentation for details on
-configuration and running the importer.
+        # Run for real, possibly put in cron
+        /opt/rt4/local/plugins/RT-Extension-LDAPImport/bin/rtldapimport \
+        --import
 
->perldoc RT::Extension::LDAPImmport
+CONFIGURATION
+    All of the configuration for the importer goes your "RT_SiteConfig.pm"
+    file. Some of these values pass through to Net::LDAP so you can check
+    there for valid values and more advanced options.
 
-DEPENDENCIES
+    "Set($LDAPHost,'our.ldap.host');"
+        Hostname or ldap(s):// uri:
 
-  Class::Accessor
-  Net::LDAP
-  RT: 3.8.x
+    "Set($LDAPUser, 'uid=foo,ou=users,dc=example,dc=com');"
+        Your LDAP username or DN. If unset, we'll attempt an anonymous bind.
 
+    "Set($LDAPPassword, 'ldap pass');"
+        Your LDAP password.
 
-COPYRIGHT AND LICENCE
+    "Set($LDAPBase, 'ou=People,o=Our Place');"
+        Base object to search from.
 
-Copyright (C) 2007-2011, Best Practical Solutions LLC.
+    "Set($LDAPFilter, '(&(cn = users))');"
+        The LDAP search filter to apply (in this case, find all the users).
+
+    "Set($LDAPMapping..."
+            Set($LDAPMapping, {Name         => 'uid',
+                               EmailAddress => 'mail',
+                               RealName     => 'cn',
+                               WorkPhone    => 'telephoneNumber',
+                               Organization => 'departmentName'});
+
+        This provides the mapping of attributes in RT to attribute in LDAP.
+        Only Name is required for RT.
+
+        The LDAP attributes can also be an arrayref of LDAP fields
+
+            WorkPhone => [qw/CompanyPhone Extension/]
+
+        which will be concatenated together with a space.
+
+        The LDAP attribute can also be a subroutine reference that returns
+        either an arrayref or a list of attributes.
+
+    "Set($LDAPCreatePrivileged, 1);"
+        By default users are created as Unprivileged, but you can change
+        this by setting $LDAPCreatePrivileged to 1.
+
+    "Set($LDAPGroupName,'My Imported Users');"
+        The RT Group new and updated users belong to. By default, all users
+        added or updated by the importer will belong to the 'Imported from
+        LDAP' group.
+
+    "Set($LDAPSkipAutogeneratedGroup, 1);"
+        Set this to true to prevent users from being automatically added to
+        the group configured by $LDAPGroupName.
+
+    "Set($LDAPUpdateUsers, 1);"
+        By default, existing users are skipped. If you turn on
+        LDAPUpdateUsers, we will clobber existing data with data from LDAP.
+
+    "Set($LDAPUpdateOnly, 1);"
+        By default, we create users who don't exist in RT but do match your
+        LDAP filter and obey $LDAPUpdateUsers for existing users. This
+        setting updates existing users, overriding $LDAPUpdateUsers, but
+        won't create new users who are found in LDAP but not in RT.
+
+    "Set($LDAPGroupBase, 'ou=Groups,o=Our Place');"
+        Where to search for groups to import.
+
+    "Set($LDAPGroupFilter, '(&(cn = Groups))');"
+        The search filter to apply.
+
+    "Set($LDAPGroupMapping..."
+            Set($LDAPGroupMapping, {Name               => 'cn',
+                                    Member_Attr        => 'member',
+                                    Member_Attr_Value  => 'dn' });
+
+        A mapping of RT attributes to LDAP attributes to identify group
+        members. Name will become the name of the group in RT, in this case
+        pulling from the cn attribute on the LDAP group record returned.
+
+        "Member_Attr" is the field in the LDAP group record the importer
+        should look at for group members. These values (there may be
+        multiple members) will then be compared to the RT user name, which
+        came from the LDAP user record.
+
+        "Member_Attr_Value", which defaults to 'dn', specifies where on the
+        LDAP user record the importer should look to compare the member
+        value. 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.
+
+        You can provide a "Description" key which will be added as the group
+        description in RT. The default description is 'Imported from LDAP'.
+
+    "Set($LDAPSizeLimit, 1000);"
+        You can set this value if your LDAP server has result size limits.
+
+Mapping Groups Between RT and LDAP
+    If you are using the importer, you likely want to manage access via LDAP
+    by putting people in groups like 'DBAs' and 'IT Support', but also have
+    groups for other non-RT related things. In this case, you won't want to
+    create all of your LDAP groups in RT. To limit the groups that get
+    mirrored, construct your $LDAPGroupFilter as an OR (|) with all of the
+    RT groups you want to mirror from LDAP. For example:
+
+        Set($LDAPGroupBase, 'OU=Groups,OU=Company,DC=COM');
+        Set($LDAPGroupFilter, '(|(CN=DBAs)(CN=IT Support))');
+
+    The importer will then import only the groups that match. In this case,
+    import means:
+
+    *   Verifying the group is in AD;
+
+    *   Creating the group in RT if it doesn't exist;
+
+    *   Populating the group with the members identified in AD;
+
+    The import script will also issue a warning if a user isn't found in RT,
+    but this should only happen when testing. When running with --import on,
+    users are created before groups are processed, so all users (group
+    members) should exist unless there are inconsistencies in your LDAP
+    configuration.
+
+Running the Import
+    Executing "rtldapimport" will run a test that connects to your LDAP
+    server and prints out a list of the users found. To see more about these
+    users, and to see more general debug information, include the "--debug"
+    flag.
+
+    That debug information is also sent to the RT log with the debug level.
+    Errors are logged to the screen and to the RT log.
+
+    Executing "rtldapimport" with the "--import" flag will cause it to
+    import users into your RT database. It is recommended that you make a
+    database backup before doing this. If your filters aren't set properly
+    this could create a lot of users or groups in your RT instance.
+
+RT Versions
+    The importer works with RT 3.8 and newer including RT 4.
+
+    It may work with RT 3.6.
+
+LDAP Filters
+    The ldapsearch
+    <http://www.openldap.org/software/man.cgi?query=ldapsearch&manpath=OpenL
+    DAP+2.0-Release> utility in openldap can be very helpful while refining
+    your filters.
+
+METHODS
+  connect_ldap
+    Relies on the config variables $RT::LDAPHost, $RT::LDAPUser and
+    $RT::LDAPPassword being set in your RT Config files.
+
+     Set($LDAPHost,'my.ldap.host')
+     Set($LDAPUSER,'me');
+     Set($LDAPPassword,'mypass');
+
+    LDAPUser and LDAPPassword can be blank, which will cause an anonymous
+    bind.
+
+    LDAPHost can be a hostname or an ldap:// ldaps:// uri.
+
+  run_user_search
+    Set up the appropriate arguments for a listing of users.
+
+  _run_search
+    Executes a search using the provided base and filter.
+
+    Will connect to LDAP server using "connect_ldap".
+
+    Returns an array of Net::LDAP::Entry objects, possibly consolidated from
+    multiple LDAP pages.
+
+  import_users import => 1|0
+    Takes the results of the search from run_search and maps attributes from
+    LDAP into "RT::User" attributes using $RT::LDAPMapping. Creates RT users
+    if they don't already exist.
+
+    With no arguments, only prints debugging information. Pass "--import" to
+    actually change data.
+
+    $RT::LDAPMapping> should be set in your "RT_SiteConfig.pm" file and look
+    like this.
+
+     Set($LDAPMapping, { RTUserField => LDAPField, RTUserField => LDAPField });
+
+    RTUserField is the name of a field on an "RT::User" object LDAPField can
+    be a simple scalar and that attribute will be looked up in LDAP.
+
+    It can also be an arrayref, in which case each of the elements will be
+    evaluated in turn. Scalars will be looked up in LDAP and concatenated
+    together with a single space.
+
+    If the value is a sub reference, it will be executed. The sub should
+    return a scalar, which will be examined. If it is a scalar, the value
+    will be looked up in LDAP. If it is an arrayref, the values will be
+    concatenated together with a single space.
+
+    By default users are created as Unprivileged, but you can change this by
+    setting $LDAPCreatePrivileged to 1.
+
+  _import_user
+    The user has run us with --import, so bring data in.
+
+  _cache_user ldap_entry => Net::LDAP::Entry, [user => { ... }]
+    Adds the user to a global cache which is used when importing groups
+    later.
+
+    Optionally takes a second argument which is a user data object returned
+    by _build_user_object. If not given, _cache_user will call
+    _build_user_object itself.
+
+    Returns the user Name.
+
+  _check_ldap_mapping
+    Returns true is there is an "LDAPMapping" configured, returns false,
+    logs an error and disconnects from ldap if there is no mapping.
+
+  _build_user_object
+    Utility method which wraps "_build_object" to provide sane defaults for
+    building users. It also tries to ensure a Name exists in the returned
+    object.
+
+  _build_object
+    Builds up data from LDAP for importing Returns a hash of user or group
+    data ready for "RT::User::Create" or "RT::Group::Create".
+
+   _parse_ldap_mapping
+    Internal helper function for "import_user". If we're passed an arrayref,
+    it will recurse over each of the elements in case one of them is another
+    arrayref or subroutine.
+
+    If we're passed a subref, it executes the code and recurses over each of
+    the returned values so that a returned array or arrayref will work.
+
+    If we're passed a scalar, returns that.
+
+    Returns a list of values that need to be concatenated together.
+
+  create_rt_user
+    Takes a hashref of args to pass to "RT::User::Create" Will try loading
+    the user and will only create a new user if it can't find an existing
+    user with the "Name" or "EmailAddress" arg passed in.
+
+    If the $LDAPUpdateUsers variable is true, data in RT will be clobbered
+    with data in LDAP. Otherwise we will skip to the next user.
+
+    If $LDAPUpdateOnly is true, we will not create new users but we will
+    update existing ones.
+
+  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
+    $LDAPSkipAutogeneratedGroup.
+
+  setup_group
+    Pulls the $LDAPGroupName object out of the DB or creates it if we need
+    to do so.
+
+   add_custom_field_value
+    Adds values to a Select (one|many) Custom Field. The Custom Field should
+    already exist, otherwise this will throw an error and not import any
+    data.
+
+    This could probably use some caching.
+
+  import_groups import => 1|0
+    Takes the results of the search from "run_group_search" and maps
+    attributes from LDAP into "RT::Group" attributes using
+    $RT::LDAPGroupMapping.
+
+    Creates groups if they don't exist.
+
+    Removes users from groups if they have been removed from the group on
+    LDAP.
+
+    With no arguments, only prints debugging information. Pass "--import" to
+    actually change data.
+
+   run_group_search
+    Set up the appropriate arguments for a listing of users.
+
+  _import_group
+    The user has run us with "--import", so bring data in.
+
+  create_rt_group
+    Takes a hashref of args to pass to "RT::Group::Create" Will try loading
+    the group and will only create a new group if it can't find an existing
+    group with the "Name" or "EmailAddress" arg passed in.
+
+    If $LDAPUpdateOnly is true, we will not create new groups but we will
+    update existing ones.
+
+    There is currently no way to prevent Group data from being clobbered
+    from LDAP.
+
+   add_group_members
+    Iterate over the list of values in the "Member_Attr" LDAP entry. Look up
+    the appropriate username from LDAP. Add those users to the group. Remove
+    members of the RT Group who are no longer members of the LDAP group.
+
+  _show_group
+    Show debugging information about the group record we're going to import
+    when the groups reruns us with "--import".
+
+   disconnect_ldap
+    Disconnects from the LDAP server.
+
+    Takes no arguments, returns nothing.
+
+Utility Functions
+   screendebug
+    We always log to the RT log file with level 'debug'. This duplicates the
+    messages to the screen.
+
+BUGS AND LIMITATIONS
+    No bugs have been reported.
+
+    Please report any bugs or feature requests to
+    "bug-rt-extension-ldapimport at rt.cpan.org", or through the web interface
+    at <http://rt.cpan.org>.
+
+AUTHOR
+    Kevin Falcone "<falcone at bestpractical.com>"
+
+LICENCE AND COPYRIGHT
+    Copyright (c) 2007, Best Practical Solutions, LLC. All rights reserved.
+
+    This module is free software; you can redistribute it and/or modify it
+    under the same terms as Perl itself. See perlartistic.
+
+DISCLAIMER OF WARRANTY
+    BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+    FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+    PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+    EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
+    YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+    NECESSARY SERVICING, REPAIR, OR CORRECTION.
+
+    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+    REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE
+    TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR
+    CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+    SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+    RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+    FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+    SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+    DAMAGES.
 
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself.
diff --git a/inc/Module/Install/ReadmeFromPod.pm b/inc/Module/Install/ReadmeFromPod.pm
new file mode 100644
index 0000000..fb7075f
--- /dev/null
+++ b/inc/Module/Install/ReadmeFromPod.pm
@@ -0,0 +1,138 @@
+#line 1
+package Module::Install::ReadmeFromPod;
+
+use 5.006;
+use strict;
+use warnings;
+use base qw(Module::Install::Base);
+use vars qw($VERSION);
+
+$VERSION = '0.18';
+
+sub readme_from {
+  my $self = shift;
+  return unless $self->is_admin;
+
+  # Input file
+  my $in_file  = shift || $self->_all_from
+    or die "Can't determine file to make readme_from";
+
+  # Get optional arguments
+  my ($clean, $format, $out_file, $options);
+  my $args = shift;
+  if ( ref $args ) {
+    # Arguments are in a hashref
+    if ( ref($args) ne 'HASH' ) {
+      die "Expected a hashref but got a ".ref($args)."\n";
+    } else {
+      $clean    = $args->{'clean'};
+      $format   = $args->{'format'};
+      $out_file = $args->{'output_file'};
+      $options  = $args->{'options'};
+    }
+  } else {
+    # Arguments are in a list
+    $clean    = $args;
+    $format   = shift;
+    $out_file = shift;
+    $options  = \@_;
+  }
+
+  # Default values;
+  $clean  ||= 0;
+  $format ||= 'txt';
+
+  # Generate README
+  print "readme_from $in_file to $format\n";
+  if ($format =~ m/te?xt/) {
+    $out_file = $self->_readme_txt($in_file, $out_file, $options);
+  } elsif ($format =~ m/html?/) {
+    $out_file = $self->_readme_htm($in_file, $out_file, $options);
+  } elsif ($format eq 'man') {
+    $out_file = $self->_readme_man($in_file, $out_file, $options);
+  } elsif ($format eq 'pdf') {
+    $out_file = $self->_readme_pdf($in_file, $out_file, $options);
+  }
+
+  if ($clean) {
+    $self->clean_files($out_file);
+  }
+
+  return 1;
+}
+
+
+sub _readme_txt {
+  my ($self, $in_file, $out_file, $options) = @_;
+  $out_file ||= 'README';
+  require Pod::Text;
+  my $parser = Pod::Text->new( @$options );
+  open my $out_fh, '>', $out_file or die "Could not write file $out_file:\n$!\n";
+  $parser->output_fh( *$out_fh );
+  $parser->parse_file( $in_file );
+  close $out_fh;
+  return $out_file;
+}
+
+
+sub _readme_htm {
+  my ($self, $in_file, $out_file, $options) = @_;
+  $out_file ||= 'README.htm';
+  require Pod::Html;
+  Pod::Html::pod2html(
+    "--infile=$in_file",
+    "--outfile=$out_file",
+    @$options,
+  );
+  # Remove temporary files if needed
+  for my $file ('pod2htmd.tmp', 'pod2htmi.tmp') {
+    if (-e $file) {
+      unlink $file or warn "Warning: Could not remove file '$file'.\n$!\n";
+    }
+  }
+  return $out_file;
+}
+
+
+sub _readme_man {
+  my ($self, $in_file, $out_file, $options) = @_;
+  $out_file ||= 'README.1';
+  require Pod::Man;
+  my $parser = Pod::Man->new( @$options );
+  $parser->parse_from_file($in_file, $out_file);
+  return $out_file;
+}
+
+
+sub _readme_pdf {
+  my ($self, $in_file, $out_file, $options) = @_;
+  $out_file ||= 'README.pdf';
+  eval { require App::pod2pdf; }
+    or die "Could not generate $out_file because pod2pdf could not be found\n";
+  my $parser = App::pod2pdf->new( @$options );
+  $parser->parse_from_file($in_file);
+  open my $out_fh, '>', $out_file or die "Could not write file $out_file:\n$!\n";
+  select $out_fh;
+  $parser->output;
+  select STDOUT;
+  close $out_fh;
+  return $out_file;
+}
+
+
+sub _all_from {
+  my $self = shift;
+  return unless $self->admin->{extensions};
+  my ($metadata) = grep {
+    ref($_) eq 'Module::Install::Metadata';
+  } @{$self->admin->{extensions}};
+  return unless $metadata;
+  return $metadata->{values}{all_from} || '';
+}
+
+'Readme!';
+
+__END__
+
+#line 254
+
diff --git a/lib/RT/Extension/LDAPImport.pm b/lib/RT/Extension/LDAPImport.pm
index c481021..8636f31 100644
--- a/lib/RT/Extension/LDAPImport.pm
+++ b/lib/RT/Extension/LDAPImport.pm
@@ -22,9 +22,9 @@ RT::Extension::LDAPImport - Import Users from an LDAP store
 
     # In RT_SiteConfig.pm
 
-    Set(LDAPHost,'my.ldap.host')
-    Set(LDAPUSER,'me');
-    Set(LDAPPassword,'mypass');
+    Set($LDAPHost,'my.ldap.host')
+    Set($LDAPUSER,'me');
+    Set($LDAPPassword,'mypass');
     Set($LDAPFilter, '(&(cn = users))');
     Set($LDAPMapping, {Name         => 'uid', # required
                        EmailAddress => 'mail',
@@ -32,17 +32,20 @@ RT::Extension::LDAPImport - Import Users from an LDAP store
                        WorkPhone    => 'telephoneNumber',
                        Organization => 'departmentName'});
 
+    # Add to any existing plugins
+    Set(@Plugins, qw(RT::Extension::LDAPImport));
+
     # If you want to sync Groups RT <-> LDAP
 
     Set($LDAPGroupBase, 'ou=Groups,o=Our Place');
     Set($LDAPGroupFilter, '(&(cn = Groups))');
     Set($LDAPGroupMapping, {Name               => 'cn',
                             Member_Attr        => 'member',
-                            Member_Attr_Value  => 'dn' });}))
+                            Member_Attr_Value  => 'dn' });
 
     # Run a test import
     /opt/rt4/local/plugins/RT-Extension-LDAPImport/bin/rtldapimport \
-    --debug > ldapimport.debug
+    --debug > ldapimport.debug 2>&1
 
     # Run for real, possibly put in cron
     /opt/rt4/local/plugins/RT-Extension-LDAPImport/bin/rtldapimport \
@@ -51,33 +54,33 @@ RT::Extension::LDAPImport - Import Users from an LDAP store
 =head1 CONFIGURATION
 
 All of the configuration for the importer goes
-your RT_SiteConfig.pm file. Some of these values pass through
+your C<RT_SiteConfig.pm> file. Some of these values pass through
 to L<Net::LDAP> so you can check there for valid values and more
 advanced options.
 
 =over
 
-=item Set($LDAPHost,'our.ldap.host');
+=item C<< Set($LDAPHost,'our.ldap.host'); >>
 
 Hostname or ldap(s):// uri:
 
-=item Set($LDAPUser, 'uid=foo,ou=users,dc=example,dc=com');
+=item C<< Set($LDAPUser, 'uid=foo,ou=users,dc=example,dc=com'); >>
 
 Your LDAP username or DN. If unset, we'll attempt an anonymous bind.
 
-=item Set($LDAPPassword, 'ldap pass');
+=item C<< Set($LDAPPassword, 'ldap pass'); >>
 
 Your LDAP password.
 
-=item Set($LDAPBase, 'ou=People,o=Our Place');
+=item C<< Set($LDAPBase, 'ou=People,o=Our Place'); >>
 
 Base object to search from.
 
-=item Set($LDAPFilter, '(&(cn = users))');
+=item C<< Set($LDAPFilter, '(&(cn = users))'); >>
 
 The LDAP search filter to apply (in this case, find all the users).
 
-=item Set($LDAPMapping...
+=item C<< Set($LDAPMapping... >>
 
     Set($LDAPMapping, {Name         => 'uid',
                        EmailAddress => 'mail',
@@ -97,44 +100,45 @@ which will be concatenated together with a space.
 The LDAP attribute can also be a subroutine reference
 that returns either an arrayref or a list of attributes.
 
-=item Set($LDAPCreatePrivileged, 1);
+=item C<< Set($LDAPCreatePrivileged, 1); >>
 
 By default users are created as Unprivileged, but you can change this by
-setting $LDAPCreatePrivileged to 1.
+setting C<$LDAPCreatePrivileged> to 1.
 
-=item Set($LDAPGroupName,'My Imported Users');
+=item C<< Set($LDAPGroupName,'My Imported Users'); >>
 
-The RT Group new users belong to. By default, all new users will belong
-to the 'Imported from LDAP' group.
+The RT Group new and updated users belong to. By default, all users
+added or updated by the importer will belong to the 'Imported from LDAP'
+group.
 
-=item Set($LDAPSkipAutogeneratedGroup, 1);
+=item C<< Set($LDAPSkipAutogeneratedGroup, 1); >>
 
 Set this to true to prevent users from being automatically
-added to this group.
+added to the group configured by C<$LDAPGroupName>.
 
-=item Set($LDAPUpdateUsers, 1);
+=item C<< Set($LDAPUpdateUsers, 1); >>
 
 By default, existing users are skipped.  If you
 turn on LDAPUpdateUsers, we will clobber existing
 data with data from LDAP.
 
-=item Set($LDAPUpdateOnly, 1);
+=item C<< Set($LDAPUpdateOnly, 1); >>
 
 By default, we create users who don't exist in RT but do
-match your LDAP filter and obey $LDAPUpdateUsers for existing
+match your LDAP filter and obey C<$LDAPUpdateUsers> for existing
 users.  This setting updates existing users, overriding
-$LDAPUpdateUsers, but won't create new
+C<$LDAPUpdateUsers>, but won't create new
 users who are found in LDAP but not in RT.
 
-=item Set($LDAPGroupBase, 'ou=Groups,o=Our Place');
+=item C<< Set($LDAPGroupBase, 'ou=Groups,o=Our Place'); >>
 
 Where to search for groups to import.
 
-=item Set($LDAPGroupFilter, '(&(cn = Groups))');
+=item C<< Set($LDAPGroupFilter, '(&(cn = Groups))'); >>
 
 The search filter to apply.
 
-=item Set($LDAPGroupMapping...
+=item C<< Set($LDAPGroupMapping... >>
 
     Set($LDAPGroupMapping, {Name               => 'cn',
                             Member_Attr        => 'member',
@@ -144,21 +148,21 @@ A mapping of RT attributes to LDAP attributes to identify group members.
 Name will become the name of the group in RT, in this case pulling
 from the cn attribute on the LDAP group record returned.
 
-Member_Attr is the field in the LDAP group record the importer should
+C<Member_Attr> is the field in the LDAP group record the importer should
 look at for group members. These values (there may be multiple members)
 will then be compared to the RT user name, which came from the LDAP
 user record.
 
-Member_Attr_Value, which defaults to 'dn', specifies where on the LDAP
+C<Member_Attr_Value>, which defaults to 'dn', specifies where on the LDAP
 user record the importer should look to compare the member value.
 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.
 
-You can provide a Description key which will be added as the group
+You can provide a C<Description> key which will be added as the group
 description in RT. The default description is 'Imported from LDAP'.
 
-=item Set($LDAPSizeLimit, 1000);
+=item C<< Set($LDAPSizeLimit, 1000); >>
 
 You can set this value if your LDAP server has result size limits.
 
@@ -170,7 +174,7 @@ If you are using the importer, you likely want to manage access via
 LDAP by putting people in groups like 'DBAs' and 'IT Support', but
 also have groups for other non-RT related things. In this case, you
 won't want to create all of your LDAP groups in RT. To limit the groups
-that get mirrored, construct your $LDAPGroupFilter as an OR (|) with
+that get mirrored, construct your C<$LDAPGroupFilter> as an OR (|) with
 all of the RT groups you want to mirror from LDAP. For example:
 
     Set($LDAPGroupBase, 'OU=Groups,OU=Company,DC=COM');
@@ -196,20 +200,14 @@ members) should exist unless there are inconsistencies in your LDAP configuratio
 
 =head1 Running the Import
 
-If RT is not installed in /opt/rt4, you will need to change the
-
-    use lib '/opt/rt4/lib';
-
-line in rtldapimport to point to the directory where RT.pm can be found.
-
-Executing rtldapimport will run a test that connects to your LDAP server
+Executing C<rtldapimport> will run a test that connects to your LDAP server
 and prints out a list of the users found. To see more about these users,
-and to see more general debug information, include the --debug flag.
+and to see more general debug information, include the C<--debug> flag.
 
 That debug information is also sent to the RT log with the debug level.
 Errors are logged to the screen and to the RT log.
 
-Executing rtldapimport with the --import flag will cause it to import
+Executing C<rtldapimport> with the C<--import> flag will cause it to import
 users into your RT database. It is recommended that you make a database
 backup before doing this. If your filters aren't set properly this could
 create a lot of users or groups in your RT instance.
@@ -229,18 +227,18 @@ utility in openldap can be very helpful while refining your filters.
 
 =head2 connect_ldap
 
-Relies on the config variables $RT::LDAPHost,
-$RT::LDAPUser and $RT::LDAPPassword being set
+Relies on the config variables C<$RT::LDAPHost>,
+C<$RT::LDAPUser> and C<$RT::LDAPPassword> being set
 in your RT Config files.
 
- Set(LDAPHost,'my.ldap.host')
- Set(LDAPUSER,'me');
- Set(LDAPPassword,'mypass');
+ Set($LDAPHost,'my.ldap.host')
+ Set($LDAPUSER,'me');
+ Set($LDAPPassword,'mypass');
 
 LDAPUser and LDAPPassword can be blank,
 which will cause an anonymous bind.
 
-LDAPHost can be a hostname or an ldap:// ldaps:// uri
+LDAPHost can be a hostname or an ldap:// ldaps:// uri.
 
 =cut
 
@@ -275,7 +273,7 @@ sub connect_ldap {
 
 =head2 run_user_search
 
-Set up the appropriate arguments for a listing of users
+Set up the appropriate arguments for a listing of users.
 
 =cut
 
@@ -290,9 +288,9 @@ sub run_user_search {
 
 =head2 _run_search
 
-Executes a search using the provided base and filter
+Executes a search using the provided base and filter.
 
-Will connect to LDAP server using connect_ldap
+Will connect to LDAP server using C<connect_ldap>.
 
 Returns an array of L<Net::LDAP::Entry> objects, possibly consolidated from
 multiple LDAP pages.
@@ -365,23 +363,23 @@ sub _run_search {
 =head2 import_users import => 1|0
 
 Takes the results of the search from run_search
-and maps attributes from LDAP into RT::User attributes
-using $RT::LDAPMapping.
+and maps attributes from LDAP into C<RT::User> attributes
+using C<$RT::LDAPMapping>.
 Creates RT users if they don't already exist.
 
 With no arguments, only prints debugging information.
-Pass import => 1 to actually change data.
+Pass C<--import> to actually change data.
 
-RT::LDAPMapping should be set in your RT_SiteConfig
-file and looks like this.
+C<$RT::LDAPMapping>> should be set in your C<RT_SiteConfig.pm>
+file and look like this.
 
  Set($LDAPMapping, { RTUserField => LDAPField, RTUserField => LDAPField });
 
-RTUserField is the name of a field on an RT::User object
+RTUserField is the name of a field on an C<RT::User> object
 LDAPField can be a simple scalar and that attribute
-will be looked up in LDAP.  
+will be looked up in LDAP.
 
-It can also be an arrayref, in which case each of the 
+It can also be an arrayref, in which case each of the
 elements will be evaluated in turn.  Scalars will be
 looked up in LDAP and concatenated together with a single
 space.
@@ -393,7 +391,7 @@ If it is an arrayref, the values will be concatenated
 together with a single space.
 
 By default users are created as Unprivileged, but you can change this by
-setting $LDAPCreatePrivileged to 1.
+setting C<$LDAPCreatePrivileged> to 1.
 
 =cut
 
@@ -433,7 +431,7 @@ sub import_users {
 
 =head2 _import_user
 
-The user has run us with --import, so bring data in
+The user has run us with --import, so bring data in.
 
 =cut
 
@@ -510,7 +508,7 @@ sub _show_user_info {
 
 =head2 _check_ldap_mapping
 
-Returns true is there is an LDAPMapping configured,
+Returns true is there is an C<LDAPMapping> configured,
 returns false, logs an error and disconnects from
 ldap if there is no mapping.
 
@@ -533,8 +531,9 @@ sub _check_ldap_mapping {
 
 =head2 _build_user_object
 
-Utility method which wraps _build_object to provide sane defaults for building
-users.  It also tries to ensure a Name exists in the returned object.
+Utility method which wraps C<_build_object> to provide sane
+defaults for building users.  It also tries to ensure a Name
+exists in the returned object.
 
 =cut
 
@@ -552,7 +551,8 @@ sub _build_user_object {
 =head2 _build_object
 
 Builds up data from LDAP for importing
-Returns a hash of user or group data ready for RT::User::Create or RT::Group::Create
+Returns a hash of user or group data ready for
+C<RT::User::Create> or C<RT::Group::Create>.
 
 =cut
 
@@ -586,8 +586,8 @@ sub _build_object {
 
 =head3 _parse_ldap_mapping
 
-Internal helper function for import_user
-If we're passed an arrayref, it will recurse 
+Internal helper function for C<import_user>.
+If we're passed an arrayref, it will recurse
 over each of the elements in case one of them is
 another arrayref or subroutine.
 
@@ -620,16 +620,16 @@ sub _parse_ldap_mapping {
 
 =head2 create_rt_user
 
-Takes a hashref of args to pass to RT::User::Create
+Takes a hashref of args to pass to C<RT::User::Create>
 Will try loading the user and will only create a new
-user if it can't find an existing user with the Name
-or EmailAddress arg passed in.
+user if it can't find an existing user with the C<Name>
+or C<EmailAddress> arg passed in.
 
-If the $LDAPUpdateUsers variable is true, data in RT
+If the C<$LDAPUpdateUsers> variable is true, data in RT
 will be clobbered with data in LDAP.  Otherwise we
 will skip to the next user.
 
-If $LDAPUpdateOnly is true, we will not create new users
+If C<$LDAPUpdateOnly> is true, we will not create new users
 but we will update existing ones.
 
 =cut
@@ -700,9 +700,9 @@ sub _load_rt_user {
 
 =head2 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 $LDAPSkipAutogeneratedGroup
+Adds new users to the group specified in the C<$LDAPGroupName>
+variable (defaults to 'Imported from LDAP').
+You can avoid this if you set C<$LDAPSkipAutogeneratedGroup>.
 
 =cut
 
@@ -738,8 +738,8 @@ sub add_user_to_group {
 
 =head2 setup_group
 
-Pulls the $LDAPGroupName object out of the DB or
-creates it if we ened to do so.
+Pulls the C<$LDAPGroupName> object out of the DB or
+creates it if we need to do so.
 
 =cut
 
@@ -765,7 +765,7 @@ Adds values to a Select (one|many) Custom Field.
 The Custom Field should already exist, otherwise
 this will throw an error and not import any data.
 
-This could probably use some caching
+This could probably use some caching.
 
 =cut
 
@@ -827,16 +827,16 @@ sub add_custom_field_value {
 
 =head2 import_groups import => 1|0
 
-Takes the results of the search from run_group_search
-and maps attributes from LDAP into RT::Group attributes
-using $RT::LDAPGroupMapping.
+Takes the results of the search from C<run_group_search>
+and maps attributes from LDAP into C<RT::Group> attributes
+using C<$RT::LDAPGroupMapping>.
 
-Creates groups if they don't exist
+Creates groups if they don't exist.
 
-Removes users from groups if they have been removed from the group on LDAP
+Removes users from groups if they have been removed from the group on LDAP.
 
 With no arguments, only prints debugging information.
-Pass import => 1 to actually change data.
+Pass C<--import> to actually change data.
 
 =cut
 
@@ -875,7 +875,7 @@ sub import_groups {
 
 =head3 run_group_search
 
-Set up the approviate arguments for a listing of users
+Set up the appropriate arguments for a listing of users.
 
 =cut
 
@@ -896,7 +896,7 @@ sub run_group_search {
 
 =head2 _import_group
 
-The user has run us with --import, so bring data in
+The user has run us with C<--import>, so bring data in.
 
 =cut
 
@@ -915,12 +915,12 @@ sub _import_group {
 
 =head2 create_rt_group
 
-Takes a hashref of args to pass to RT::Group::Create
+Takes a hashref of args to pass to C<RT::Group::Create>
 Will try loading the group and will only create a new
-group if it can't find an existing group with the Name
-or EmailAddress arg passed in.
+group if it can't find an existing group with the C<Name>
+or C<EmailAddress> arg passed in.
 
-If $LDAPUpdateOnly is true, we will not create new groups
+If C<$LDAPUpdateOnly> is true, we will not create new groups
 but we will update existing ones.
 
 There is currently no way to prevent Group data from being
@@ -976,7 +976,7 @@ sub create_rt_group {
 
 =head3 add_group_members
 
-Iterate over the list of values in the Member_Attr LDAP entry.
+Iterate over the list of values in the C<Member_Attr> LDAP entry.
 Look up the appropriate username from LDAP.
 Add those users to the group.
 Remove members of the RT Group who are no longer members
@@ -1073,7 +1073,7 @@ sub _get_group_members_from_ldap {
 =head2 _show_group
 
 Show debugging information about the group record we're going to import
-when the groups reruns us with --import
+when the groups reruns us with C<--import>.
 
 =cut
 
@@ -1119,9 +1119,9 @@ sub _show_group_info {
 
 =head3 disconnect_ldap
 
-Disconnects from the LDAP server
+Disconnects from the LDAP server.
 
-Takes no arguments, returns nothing
+Takes no arguments, returns nothing.
 
 =cut
 

-----------------------------------------------------------------------



More information about the Bps-public-commit mailing list