Skip Menu |

This queue is for tickets about the Apache2-AuthNetLDAP CPAN distribution.

Report information
The Basics
Id: 65079
Status: open
Priority: 0/
Queue: Apache2-AuthNetLDAP

People
Owner: Nobody in particular
Requestors: reg.cpan [...] entropy.ch
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 0.01
Fixed in: (no value)



Subject: Patch to add group membership criteria
Subject: Apache2-AuthNetLDAP-groupquery.patch
--- /Users/local/Desktop/AuthNetLDAP.pm 2011-01-24 11:33:54.000000000 -0800 +++ /Library/Perl/5.10.0/Apache2/AuthNetLDAP.pm 2011-01-24 14:20:19.000000000 -0800 @@ -46,6 +46,8 @@ my $uidattr = $r->dir_config('UIDAttr') || "uid"; my $allowaltauth = $r->dir_config('AllowAlternateAuth') || "no"; my $ldapfilter = $r->dir_config('LDAPFilter') || ""; + my $groupquery_filter = $r->dir_config('LDAPGroupQueryFilter') || ""; + my $groupquery_basedn = $r->dir_config('LDAPGroupQueryBaseDN') || ""; my $start_TLS = $r->dir_config('UseStartTLS') || "no"; my $scope = $r->dir_config('SearchScope') || "sub"; my $pwattr = $r->dir_config('AlternatePWAttribute') || ""; @@ -104,6 +106,7 @@ my $filter = $ldapfilter ? "(&$ldapfilter($uidattr=$user))" : "($uidattr=$user)"; + $mesg = $ldap->search( base => $basedn, scope => $scope, @@ -160,6 +163,7 @@ } else { +warn("ldap auth via bind"); $mesg = $ldap->bind($entry->dn(),password=>$password); } @@ -173,6 +177,29 @@ my $dn = $entry->dn(); # $r->log_error("AUTHDEBUG user $dn:$password bind: $error",$r->uri); + + if ($groupquery_filter && $groupquery_basedn) { + $groupquery_filter =~ s/\$uid/$user/g; + + $mesg = $ldap->search( + base => $groupquery_basedn, + scope => 'sub', + filter => $groupquery_filter, + ); + + if (my $error = $mesg->code()) { + $r->note_basic_auth_failure; + $r->log_error("user $user: LDAP Connection Failed: $error",$r->uri); + return Apache2::Const::HTTP_UNAUTHORIZED; + } + + unless ($mesg->count()) { + $r->note_basic_auth_failure; + $r->log_error("user $user: LDAP group query '$groupquery_filter' returned no results, rejecting for " , $r->uri); + return Apache2::Const::HTTP_UNAUTHORIZED; + } + } + return Apache2::Const::OK; } # Autoload methods go after =cut, and are processed by the autosplit program. @@ -196,6 +223,13 @@ PerlSetVar LDAPPort 389 #PerlSetVar UIDAttr uid PerlSetVar UIDAttr mail + + # Use these two if you need to verify group membership in a separate group tree + # and your user entries don't have a memberOf attribute. The string $uid is replaced with + # the user id. + #PerlSetVar LDAPGroupQueryFilter "(&(|(cn=foo-bar-group)(cn=baz-group))(memberUid=$uid))" + #PerlSetVar LDAPGroupQueryBaseDN "cn=groups,dc=example,dc=com" + #PerlSetVar AlternatePWAttribute alternateAttribute #PerlSetVar SearchScope base | one | sub # default is sub #PerlSetVar LDAPFilter "(&(course=CSA)(class=A))" #optional @@ -296,6 +330,18 @@ depends on openssl. Of course, the LDAP server must support Start TLS also. +=item PerlSetVar LDAPGroupQueryFilter + +Optional, must be an LDAP search filter expression. A * character will +be replaced with the user id. This search query is run after a user has +been authenticated successfully to further restrict the allowed users to +members of particular groups. + +=item PerlSetVar LDAPGroupQueryBaseDN + +Mandatory if LDAPGroupQueryFilter is used. This is the search base DND for +the group query search. + =back =head2 Uses for UIDAttr
Updated patch. This patch adds the ability to check if a user is a member of one or more groups in a separate subtree.
Subject: Apache2-AuthNetLDAP-groupquery-1.patch
--- /Users/local/Desktop/AuthNetLDAP.pm 2011-01-24 11:33:54.000000000 -0800 +++ /Library/Perl/5.10.0/Apache2/AuthNetLDAP.pm 2011-01-24 14:20:19.000000000 -0800 @@ -46,6 +46,8 @@ my $uidattr = $r->dir_config('UIDAttr') || "uid"; my $allowaltauth = $r->dir_config('AllowAlternateAuth') || "no"; my $ldapfilter = $r->dir_config('LDAPFilter') || ""; + my $groupquery_filter = $r->dir_config('LDAPGroupQueryFilter') || ""; + my $groupquery_basedn = $r->dir_config('LDAPGroupQueryBaseDN') || ""; my $start_TLS = $r->dir_config('UseStartTLS') || "no"; my $scope = $r->dir_config('SearchScope') || "sub"; my $pwattr = $r->dir_config('AlternatePWAttribute') || ""; @@ -104,6 +106,7 @@ my $filter = $ldapfilter ? "(&$ldapfilter($uidattr=$user))" : "($uidattr=$user)"; + $mesg = $ldap->search( base => $basedn, scope => $scope, @@ -160,6 +163,7 @@ } else { +warn("ldap auth via bind"); $mesg = $ldap->bind($entry->dn(),password=>$password); } @@ -173,6 +177,29 @@ my $dn = $entry->dn(); # $r->log_error("AUTHDEBUG user $dn:$password bind: $error",$r->uri); + + if ($groupquery_filter && $groupquery_basedn) { + $groupquery_filter =~ s/\$uid/$user/g; + + $mesg = $ldap->search( + base => $groupquery_basedn, + scope => 'sub', + filter => $groupquery_filter, + ); + + if (my $error = $mesg->code()) { + $r->note_basic_auth_failure; + $r->log_error("user $user: LDAP Connection Failed: $error",$r->uri); + return Apache2::Const::HTTP_UNAUTHORIZED; + } + + unless ($mesg->count()) { + $r->note_basic_auth_failure; + $r->log_error("user $user: LDAP group query '$groupquery_filter' returned no results, rejecting for " , $r->uri); + return Apache2::Const::HTTP_UNAUTHORIZED; + } + } + return Apache2::Const::OK; } # Autoload methods go after =cut, and are processed by the autosplit program. @@ -196,6 +223,13 @@ PerlSetVar LDAPPort 389 #PerlSetVar UIDAttr uid PerlSetVar UIDAttr mail + + # Use these two if you need to verify group membership in a separate group tree + # and your user entries don't have a memberOf attribute. The string $uid is replaced with + # the user id. + #PerlSetVar LDAPGroupQueryFilter "(&(|(cn=foo-bar-group)(cn=baz-group))(memberUid=$uid))" + #PerlSetVar LDAPGroupQueryBaseDN "cn=groups,dc=example,dc=com" + #PerlSetVar AlternatePWAttribute alternateAttribute #PerlSetVar SearchScope base | one | sub # default is sub #PerlSetVar LDAPFilter "(&(course=CSA)(class=A))" #optional @@ -296,6 +330,18 @@ depends on openssl. Of course, the LDAP server must support Start TLS also. +=item PerlSetVar LDAPGroupQueryFilter + +Optional, must be an LDAP search filter expression. A * character will +be replaced with the user id. This search query is run after a user has +been authenticated successfully to further restrict the allowed users to +members of particular groups. + +=item PerlSetVar LDAPGroupQueryBaseDN + +Mandatory if LDAPGroupQueryFilter is used. This is the search base DND for +the group query search. + =back =head2 Uses for UIDAttr
Yet another updated patch. I reworked it completely and group membership checks are now integrated with the "require group" directive.
Subject: Apache2-AuthNetLDAP-groupquery.patch
--- /Users/local/Desktop/AuthNetLDAP.pm 2011-01-24 11:33:54.000000000 -0800 +++ /Library/Perl/5.10.0/Apache2/AuthNetLDAP.pm 2011-01-24 16:51:31.000000000 -0800 @@ -104,6 +104,7 @@ my $filter = $ldapfilter ? "(&$ldapfilter($uidattr=$user))" : "($uidattr=$user)"; + $mesg = $ldap->search( base => $basedn, scope => $scope, @@ -173,8 +174,72 @@ my $dn = $entry->dn(); # $r->log_error("AUTHDEBUG user $dn:$password bind: $error",$r->uri); + return check_group_requirements($r, $ldap, $user); + +} + + +sub check_group_requirements +{ + my ($r, $ldap, $user) = @_; + + my @required_groups = + grep {$_} + map {/(?:"(.+?)"|(\S+))/g} + map {/^group\s+(.+)/i} + map {$_->{requirement}} + @{$r->requires() || []}; + + return Apache2::Const::OK unless @required_groups; + + my $groupquery_filter = $r->dir_config('LDAPGroupQueryFilter') || ""; + my $groupquery_basedn = $r->dir_config('LDAPGroupQueryBaseDN') || ""; + my $groupquery_groupname_attribute = $r->dir_config('LDAPGroupQueryGroupNameAttribute') || "cn"; + my $groupquery_memberuid_attribute = $r->dir_config('LDAPGroupQueryMemberUidAttribute') || "memberUid"; + + my $groupfilter = $groupquery_filter + ? "(&$groupquery_filter($groupquery_memberuid_attribute=$user))" + : "($groupquery_memberuid_attribute=$user)"; + + my $mesg = $ldap->search( + base => $groupquery_basedn, + scope => 'sub', + filter => $groupfilter, + attrs => [$groupquery_groupname_attribute], + ); + + if (my $error = $mesg->code()) { + $r->note_basic_auth_failure; + $r->log_error("user $user: LDAP Connection Failed: $error",$r->uri); + return Apache2::Const::HTTP_UNAUTHORIZED; + } + + my @assigned_groups = + grep {$_} + map {$_->get_value($groupquery_groupname_attribute)} + $mesg->entries(); + + my $group_match; + foreach my $required_group (@required_groups) { + if (grep {$_ eq $required_group} @assigned_groups) { + $group_match = 1; +# warn("Group match for $user: $required_group"); + last; + } + } + + unless ($group_match) { + $r->note_basic_auth_failure; + my $groupstring = join(", ", @required_groups); + $r->log_error("user $user not in one of the required groups ($groupstring), rejecting for " , $r->uri); + return Apache2::Const::HTTP_UNAUTHORIZED; + } + return Apache2::Const::OK; + } + + # Autoload methods go after =cut, and are processed by the autosplit program. # Below is the stub of documentation for your module. You better edit it! @@ -196,6 +261,21 @@ PerlSetVar LDAPPort 389 #PerlSetVar UIDAttr uid PerlSetVar UIDAttr mail + + # The following are for looking up LDAP group names and making them available for use with the + # "require group" directive. + # Use these if you need to verify group membership in a separate group tree + # and your user entries don't have a memberOf attribute (in which case you could just use + # the LDAPFilter directive directly). + # You need to set at least LDAPGroupQueryBaseDN, the others might work with the default values + # (LDAPGroupQueryGroupNameAttribute and LDAPGroupQueryMemberUidAttribute have the default + # values shown below). + #PerlSetVar LDAPGroupQueryGroupNameAttribute cn + #PerlSetVar LDAPGroupQueryMemberUidAttribute memberUid + #PerlSetVar LDAPGroupQueryFilter "(objectClass=posixGroup)" + PerlSetVar LDAPGroupQueryBaseDN "cn=groups,dc=example,dc=com" + require group some-ldap-group another-ldap-group + #PerlSetVar AlternatePWAttribute alternateAttribute #PerlSetVar SearchScope base | one | sub # default is sub #PerlSetVar LDAPFilter "(&(course=CSA)(class=A))" #optional @@ -296,6 +376,31 @@ depends on openssl. Of course, the LDAP server must support Start TLS also. +=item PerlSetVar LDAPGroupQueryBaseDN + +Optional. If present, a search is performed in the given subtree for group objects with +a memberUid attribute value corresponding to the current user. This search is performed +after the user id itself is already authenticated. + +If objects are found, the group names (from the cn attribute) are compared to the values +of the "require group xxx" directive. If there's a match, the authentication succeeds. +If there is no "require group" directive, this directive is ignored. + +=item PerlSetVar LDAPGroupQueryGroupNameAttribute + +Optional, lets you change the group name attribute from the default "cn" when you use +LDAPGroupQueryBaseDN. + +=item PerlSetVar LDAPGroupQueryMemberUidAttribute + +Optional, lets you change the member name attribute from the default "memberUid" when you use +LDAPGroupQueryBaseDN. + +=item PerlSetVar LDAPGroupQueryFilter + +Optional, lets you restrict the set of loaded group objects when you use LDAPGroupQueryBaseDN. +If present, it is combined with the filter that compares the member uid attribute. + =back =head2 Uses for UIDAttr