Yet another updated patch.
I reworked it completely and group membership checks are now integrated with the "require
group" directive.
--- /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