[Jifty-commit] jifty-plugin-authentication-ldap branch, master, updated. 210b8bb80046caea23788bdfbd2b8ce0f8a4fb2e

Jifty commits jifty-commit at lists.jifty.org
Tue Oct 12 12:50:47 EDT 2010


The branch, master has been updated
       via  210b8bb80046caea23788bdfbd2b8ce0f8a4fb2e (commit)
       via  fb309dd907b8b79936c1b9406388a5feed976a53 (commit)
       via  8a5a4cf2a8781bea9e27411151d6cdf0fa701a4b (commit)
       via  05dad7fd1d25c2ea3013cc666f4188c5c90a8f7b (commit)
       via  02c5871e50258fe337857949ec4fc12b84f8e54d (commit)
       via  ed2ee0a162d9a94d1000ee56070ecae8ccbcb9fc (commit)
      from  cbd2f438812d5e78b2035ca3a4a3e668b31dd7ba (commit)

Summary of changes:
 .gitignore                                         |    5 +
 Changes                                            |    4 +
 README                                             |  191 ++++++++++++++++++++
 lib/Jifty/Plugin/Authentication/Ldap.pm            |  123 +++++++++++--
 .../Plugin/Authentication/Ldap/Action/LDAPLogin.pm |   26 +++-
 5 files changed, 333 insertions(+), 16 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 README

- Log -----------------------------------------------------------------
commit ed2ee0a162d9a94d1000ee56070ecae8ccbcb9fc
Author: Stanislav Sinyagin <ssinyagin at k-open.com>
Date:   Tue Sep 14 17:07:24 2010 +0200

    Support for MS AD and authorization hooks

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c3d4674
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+META.yml
+Makefile
+blib/
+inc/
+jifty-plugin-authentication-ldap/
+pm_to_blib
diff --git a/lib/Jifty/Plugin/Authentication/Ldap.pm b/lib/Jifty/Plugin/Authentication/Ldap.pm
index c77b424..215765f 100644
--- a/lib/Jifty/Plugin/Authentication/Ldap.pm
+++ b/lib/Jifty/Plugin/Authentication/Ldap.pm
@@ -121,6 +121,11 @@ Your LDAP server.
 
 The base object where your users live.
 
+=item C<LDAPBindTemplate>
+
+Alternatively to C<LDAPbase>, you can specify here the whole DN string, with
+I<%u> as a placeholder for UID.
+
 =item C<LDAPMail>
 
 The DN that your organization uses to store Email addresses.  This
@@ -153,8 +158,70 @@ Other options you may want :
 See C<Net::LDAP> for a full list.  You can overwrite the defaults
 selectively or not at all.
 
+=item C<LDAPLoginHooks>
+
+Optional list of Perl functions that would be called after a successful login
+and after a corresponding User object is loaded and updated. The function is
+called with a hash array arguments, as follows:
+
+  username => string
+  user_object => User object
+  ldap => Net::LDAP object
+  infos => User attributes as returned by get_infos  
+
+=item C<LDAPFetchUserAttr>
+
+Optional list of LDAP user attributes fetched by get_infos. The values are
+returned to the login hook as arrayrefs.
+
 =back
 
+=head2 Example
+
+The following example authenticates the application against a MS Active
+Directory server for the domain MYDOMAIN. Each user entry has the attribute
+'department' which is used for authorization. C<LDAPbase> is used for user
+searching, and binding is done in a Microsoft way. The login hook checks
+if the user belongs to specific departments and updates the user record.
+
+
+ ######
+ #   etc/config.yml:  
+  Plugins: 
+    - User: {}
+    - Authentication::Ldap:
+       LDAPhost: ldap1.mydomain.com
+       LDAPbase: 'DC=mydomain,DC=com'
+       LDAPBindTemplate: 'MYDOMAIN\%u'
+       LDAPName: displayName
+       LDAPMail: mail
+       LDAPuid: cn
+       LDAPFetchUserAttr:
+         - department
+       LDAPLoginHooks:
+         - 'Myapp::Model::User::ldap_login_hook'
+
+  ######
+  #  package Myapp::Model::User;
+  sub ldap_login_hook
+  {
+      my %args = @_;
+
+      my $u = $args{'user_object'};    
+      my $department = $args{'infos'}->{'department'}[0];
+
+      my $editor = 0;
+      if( $department eq 'NOC' or
+          $department eq 'ENGINEERING' )
+      {
+          $editor = 1;
+      }
+
+      $u->__set( column => 'is_content_editor', value => $editor );
+  }
+
+
+  
 =cut
 
 sub init {
@@ -162,10 +229,21 @@ sub init {
     my %args = @_;
 
     $params{'Hostname'} = $args{LDAPhost};
-    $params{'base'}     = $args{LDAPbase} or die "Need LDAPbase in plugin config";
+    $params{'bind_template'} = $args{LDAPBindTemplate};
+    $params{'base'}     = $args{LDAPbase};
+    $params{'bind_template'} or $params{'base'} or
+        die "Need LDAPbase or LDAPBindTemplate in plugin config";
+        
     $params{'uid'}      = $args{LDAPuid}     || "uid";
     $params{'email'}    = $args{LDAPMail}    || "";
     $params{'name'}     = $args{LDAPName}    || "cn";
+    $params{'login_hooks'} = $args{LDAPLoginHooks}    || [];
+    $params{'fetch_attrs'} = $args{LDAPFetchUserAttr} || [];
+    
+    if( not $params{'bind_template'} ) {
+        $params{'bind_template'} = $params{'uid'}.'=%u,'.$params{'base'};
+    }
+    
     my $opts            = $args{LDAPOptions} || {};
 
     # Default options for Net::LDAP
@@ -182,6 +260,10 @@ sub LDAP {
     return $LDAP;
 }
 
+sub bind_template {
+    return $params{'bind_template'};
+}
+
 sub base {
     return $params{'base'};
 }
@@ -202,22 +284,31 @@ sub opts {
     return $params{'opts'};
 };
 
+sub login_hooks {
+    return @{$params{'login_hooks'}};
+}
 
 sub get_infos {
     my ($self,$user) = @_;
 
     my $result = $self->LDAP()->search (
             base   => $self->base(),
-            filter => '(uid= '.$user.')',
-            attrs  =>  [$self->name(),$self->email()],
+            filter => '('.$self->uid().'='.$user.')',
+            attrs  =>  [$self->name(),$self->email(), @{$params{'fetch_attrs'}}],
             sizelimit => 1
              );
     $result->code && Jifty->log->error( 'LDAP uid=' . $user . ' ' . $result->error );
-    my ($ret) = $result->entries;
-    my $name = $ret->get_value($self->name());
-    my $email = $ret->get_value($self->email());
-
-    return ({ name => $name, email => $email });
+    my ($entry) = $result->entries;
+    my $ret = {
+        dn => $entry->dn(),
+        name => $entry->get_value($self->name()),
+        email => $entry->get_value($self->email()),
+    };    
+    foreach my $attr (@{$params{'fetch_attrs'}}) {
+        my @val = $entry->get_value($attr);
+        $ret->{$attr} = [ @val ];
+    }
+    return $ret;
 };
 
 
diff --git a/lib/Jifty/Plugin/Authentication/Ldap/Action/LDAPLogin.pm b/lib/Jifty/Plugin/Authentication/Ldap/Action/LDAPLogin.pm
index 93cc32a..9c4cd1d 100644
--- a/lib/Jifty/Plugin/Authentication/Ldap/Action/LDAPLogin.pm
+++ b/lib/Jifty/Plugin/Authentication/Ldap/Action/LDAPLogin.pm
@@ -63,8 +63,9 @@ sub take_action {
     my $self = shift;
     my $username = $self->argument_value('ldap_id');
     my ($plugin)  = Jifty->find_plugin('Jifty::Plugin::Authentication::Ldap');
-    my $dn = $plugin->uid().'='.$username.','.
-        $plugin->base();
+    
+    my $dn = $plugin->bind_template();
+    $dn =~ s/\%u/$username/g;
 
     Jifty->log->debug( "dn = $dn" );
 
@@ -124,6 +125,16 @@ sub take_action {
     Jifty->web->current_user( $user );
     Jifty->web->session->set_cookie;
 
+    foreach my $proc ($plugin->login_hooks()) {
+        eval( '&' . $proc . '( username => $username, ' . 
+              'user_object => $u, ldap => $plugin->LDAP(), infos => $infos )' );
+        if( $@ ) {
+            Jifty->log->error('Cannot eval ' . $proc . ': ' . $@);
+            $self->result->error('Cannot eval ' . $proc . ': ' . $@);
+            return;
+        }
+    }
+
     # Success!
     $self->report_success;
 

commit 02c5871e50258fe337857949ec4fc12b84f8e54d
Author: Stanislav Sinyagin <ssinyagin at k-open.com>
Date:   Tue Sep 14 17:14:22 2010 +0200

    minor bugfix

diff --git a/.gitignore b/.gitignore
index c3d4674..b08f9f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,5 +2,4 @@ META.yml
 Makefile
 blib/
 inc/
-jifty-plugin-authentication-ldap/
 pm_to_blib

commit 05dad7fd1d25c2ea3013cc666f4188c5c90a8f7b
Author: Stanislav Sinyagin <ssinyagin at k-open.com>
Date:   Tue Sep 14 17:16:52 2010 +0200

    minor bugfix

diff --git a/lib/Jifty/Plugin/Authentication/Ldap.pm b/lib/Jifty/Plugin/Authentication/Ldap.pm
index 215765f..70afc32 100644
--- a/lib/Jifty/Plugin/Authentication/Ldap.pm
+++ b/lib/Jifty/Plugin/Authentication/Ldap.pm
@@ -230,10 +230,7 @@ sub init {
 
     $params{'Hostname'} = $args{LDAPhost};
     $params{'bind_template'} = $args{LDAPBindTemplate};
-    $params{'base'}     = $args{LDAPbase};
-    $params{'bind_template'} or $params{'base'} or
-        die "Need LDAPbase or LDAPBindTemplate in plugin config";
-        
+    $params{'base'}     = $args{LDAPbase} or die "Need LDAPbase in plugin config";
     $params{'uid'}      = $args{LDAPuid}     || "uid";
     $params{'email'}    = $args{LDAPMail}    || "";
     $params{'name'}     = $args{LDAPName}    || "cn";

commit 8a5a4cf2a8781bea9e27411151d6cdf0fa701a4b
Author: Stanislav Sinyagin <ssinyagin at k-open.com>
Date:   Tue Sep 14 17:20:34 2010 +0200

    documentation update

diff --git a/lib/Jifty/Plugin/Authentication/Ldap.pm b/lib/Jifty/Plugin/Authentication/Ldap.pm
index 70afc32..aef999d 100644
--- a/lib/Jifty/Plugin/Authentication/Ldap.pm
+++ b/lib/Jifty/Plugin/Authentication/Ldap.pm
@@ -119,7 +119,8 @@ Your LDAP server.
 
 =item C<LDAPbase>
 
-The base object where your users live.
+[Mandatory] The base object where your users live. If C<LDAPBindTemplate> is
+defined, C<LDAPbase> is only used for user search.
 
 =item C<LDAPBindTemplate>
 

commit fb309dd907b8b79936c1b9406388a5feed976a53
Author: Yves Agostini <agostini at univ-metz.fr>
Date:   Wed Sep 15 12:41:16 2010 +0200

    *bump version number copyright year *update changes *add Sinyagin as author

diff --git a/Changes b/Changes
index 1e8b0e7..a6fbb66 100644
--- a/Changes
+++ b/Changes
@@ -1,5 +1,9 @@
 Revision history for Perl module Jifty::Plugin::Authentication::Ldap
 
+1.01 Wed, 15 Sep 2010 12:36:08 +0200
+    - Active Directory style binding (ssinyagin)
+    - hooks login (ssinyagin)
+
 1.00 Wed, 10 Jun 2009 11:49:12 +0200
     - bump version number to avoid conflict with debian
 
diff --git a/README b/README
new file mode 100644
index 0000000..f246a9d
--- /dev/null
+++ b/README
@@ -0,0 +1,191 @@
+NAME
+    Jifty::Plugin::Authentication::Ldap - LDAP Authentication Plugin for
+    Jifty
+
+DESCRIPTION
+    CAUTION: This plugin is experimental.
+
+    This may be combined with the User Mixin to provide user accounts and
+    ldap password authentication to your application.
+
+    When a new user authenticates using this plugin, a new User object will
+    be created automatically. The "name" and "email" fields will be
+    automatically populated with LDAP data.
+
+    in etc/config.yml
+
+      Plugins: 
+        - Authentication::Ldap: 
+           LDAPhost: ldap.univ.fr           # ldap server
+           LDAPbase: ou=people,dc=.....     # base ldap
+           LDAPName: displayname            # name to be displayed (cn givenname)
+           LDAPMail: mailLocalAddress       # email used optional
+           LDAPuid: uid                     # optional
+
+    Then create a user model
+
+      jifty model --name=User
+
+    and edit lib/App/Model/User.pm to look something like this:
+
+      use strict;
+      use warnings;
+      
+  package Venice::Model::User;
+      
+  use Jifty::DBI::Schema;
+      use Venice::Record schema {
+            # More app-specific user columns go here
+      };
+      
+  use Jifty::Plugin::User::Mixin::Model::User;
+      use Jifty::Plugin::Authentication::Ldap::Mixin::Model::User;
+      
+  sub current_user_can {
+          my $self = shift;
+          my $type = shift;
+          my %args = (@_);
+          
+    return 1 if
+              $self->current_user->is_superuser;
+        
+    # all logged in users can read this table
+        return 1
+            if ($type eq 'read' && $self->current_user->id);
+        
+    return $self->SUPER::current_user_can($type, @_);
+      };
+      
+  1;
+
+  ACTIONS
+    This plugin will add the following actions to your application. For
+    testing you can access these from the Admin plugin.
+
+    Jifty::Plugin::Authentication::Ldap::Action::LDAPLogin
+        The login path is "/ldaplogin".
+
+    Jifty::Plugin::Authentication::Ldap::Action::LDAPLogout
+        The logout path is "/ldaplogout".
+
+  METHODS
+  prereq_plugins
+    This plugin depends on the User Mixin.
+
+  Configuration
+    The following options are available in your "config.yml" under the
+    Authentication::Ldap Plugins section.
+
+    "LDAPhost"
+        Your LDAP server.
+
+    "LDAPbase"
+        [Mandatory] The base object where your users live. If
+        "LDAPBindTemplate" is defined, "LDAPbase" is only used for user
+        search.
+
+    "LDAPBindTemplate"
+        Alternatively to "LDAPbase", you can specify here the whole DN
+        string, with *%u* as a placeholder for UID.
+
+    "LDAPMail"
+        The DN that your organization uses to store Email addresses. This
+        gets copied into the User object as the "email".
+
+    "LDAPName"
+        The DN that your organization uses to store Real Name. This gets
+        copied into the User object as the "name".
+
+    "LDAPuid"
+        The DN that your organization uses to store the user ID. Usually
+        "cn". This gets copied into the User object as the "ldap_id".
+
+    "LDAPOptions"
+        These options get passed through to Net::LDAP.
+
+        Default Options :
+
+         debug   => 0
+         onerror => undef
+         async   => 1
+
+        Other options you may want :
+
+         timeout => 30
+
+        See "Net::LDAP" for a full list. You can overwrite the defaults
+        selectively or not at all.
+
+    "LDAPLoginHooks"
+        Optional list of Perl functions that would be called after a
+        successful login and after a corresponding User object is loaded and
+        updated. The function is called with a hash array arguments, as
+        follows:
+
+          username => string
+          user_object => User object
+          ldap => Net::LDAP object
+          infos => User attributes as returned by get_infos
+
+    "LDAPFetchUserAttr"
+        Optional list of LDAP user attributes fetched by get_infos. The
+        values are returned to the login hook as arrayrefs.
+
+  Example
+    The following example authenticates the application against a MS Active
+    Directory server for the domain MYDOMAIN. Each user entry has the
+    attribute 'department' which is used for authorization. "LDAPbase" is
+    used for user searching, and binding is done in a Microsoft way. The
+    login hook checks if the user belongs to specific departments and
+    updates the user record.
+
+     ######
+     #   etc/config.yml:  
+      Plugins: 
+        - User: {}
+        - Authentication::Ldap:
+           LDAPhost: ldap1.mydomain.com
+           LDAPbase: 'DC=mydomain,DC=com'
+           LDAPBindTemplate: 'MYDOMAIN\%u'
+           LDAPName: displayName
+           LDAPMail: mail
+           LDAPuid: cn
+           LDAPFetchUserAttr:
+             - department
+           LDAPLoginHooks:
+             - 'Myapp::Model::User::ldap_login_hook'
+
+      ######
+      #  package Myapp::Model::User;
+      sub ldap_login_hook
+      {
+          my %args = @_;
+
+          my $u = $args{'user_object'};    
+          my $department = $args{'infos'}->{'department'}[0];
+
+          my $editor = 0;
+          if( $department eq 'NOC' or
+              $department eq 'ENGINEERING' )
+          {
+              $editor = 1;
+          }
+
+          $u->__set( column => 'is_content_editor', value => $editor );
+      }
+
+SEE ALSO
+    Jifty::Manual::AccessControl, Jifty::Plugin::User::Mixin::Model::User,
+    Net::LDAP
+
+AUTHORS
+    Yves Agostini, <yvesago at cpan.org>, Stanislav Sinyagin
+
+    and others authors from Jifty (maxbaker, clkao, sartak, alexmv)
+
+LICENSE
+    Copyright 2007-2010 Yves Agostini. All Rights Reserved.
+
+    This program is free software and may be modified and distributed under
+    the same terms as Perl itself.
+
diff --git a/lib/Jifty/Plugin/Authentication/Ldap.pm b/lib/Jifty/Plugin/Authentication/Ldap.pm
index aef999d..bbc4574 100644
--- a/lib/Jifty/Plugin/Authentication/Ldap.pm
+++ b/lib/Jifty/Plugin/Authentication/Ldap.pm
@@ -4,7 +4,7 @@ use warnings;
 package Jifty::Plugin::Authentication::Ldap;
 use base qw/Jifty::Plugin/;
 
-our $VERSION = '1.00';
+our $VERSION = '1.01';
 
 =head1 NAME
 
@@ -317,13 +317,13 @@ L<Jifty::Manual::AccessControl>, L<Jifty::Plugin::User::Mixin::Model::User>, L<N
 
 =head1 AUTHORS
 
-Yves Agostini, <yvesago at cpan.org>
+Yves Agostini, <yvesago at cpan.org>, Stanislav Sinyagin
 
 and others authors from Jifty (maxbaker, clkao, sartak, alexmv)
 
 =head1 LICENSE
 
-Copyright 2007-2009 Yves Agostini. All Rights Reserved.
+Copyright 2007-2010 Yves Agostini. All Rights Reserved.
 
 This program is free software and may be modified and distributed under the same terms as Perl itself.
 

commit 210b8bb80046caea23788bdfbd2b8ce0f8a4fb2e
Author: Stanislav Sinyagin <ssinyagin at k-open.com>
Date:   Thu Sep 16 16:03:03 2010 +0200

    under FastCGI or mod_perl, LDAP connection times out and has to be re-established

diff --git a/lib/Jifty/Plugin/Authentication/Ldap.pm b/lib/Jifty/Plugin/Authentication/Ldap.pm
index bbc4574..e463716 100644
--- a/lib/Jifty/Plugin/Authentication/Ldap.pm
+++ b/lib/Jifty/Plugin/Authentication/Ldap.pm
@@ -249,15 +249,21 @@ sub init {
     $opts->{'onerror'} = 'undef' unless defined $opts->{'onerror'};
     $opts->{'async'}   = 1       unless defined $opts->{'async'};
     $params{'opts'}    = $opts;
-
-    $LDAP = Net::LDAP->new($params{Hostname},%{$opts})
-        or die "Can't connect to LDAP server ",$params{Hostname};
 }
 
 sub LDAP {
+    if( not defined $LDAP ) {
+        $LDAP = Net::LDAP->new($params{Hostname},%{$params{'opts'}})
+            or die "Can't connect to LDAP server ",$params{Hostname};
+    }
     return $LDAP;
 }
 
+sub disconnect {
+    $LDAP->disconnect();
+    undef $LDAP;
+}
+
 sub bind_template {
     return $params{'bind_template'};
 }
diff --git a/lib/Jifty/Plugin/Authentication/Ldap/Action/LDAPLogin.pm b/lib/Jifty/Plugin/Authentication/Ldap/Action/LDAPLogin.pm
index 9c4cd1d..bd90ce4 100644
--- a/lib/Jifty/Plugin/Authentication/Ldap/Action/LDAPLogin.pm
+++ b/lib/Jifty/Plugin/Authentication/Ldap/Action/LDAPLogin.pm
@@ -141,6 +141,17 @@ sub take_action {
     return 1;
 };
 
+
+=head2 cleanup
+
+=cut
+
+
+sub cleanup {
+    my ($plugin)  = Jifty->find_plugin('Jifty::Plugin::Authentication::Ldap');
+    $plugin->disconnect();
+}
+
 =head2 report_success
 
 =cut

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


More information about the Jifty-commit mailing list