Apache-AuthzLDAP
view release on metacpan or search on metacpan
AuthzLDAP.pm view on Meta::CPAN
# security implications in a general environment where you
# might be using someone else's handlers upstream or
# downstream...
my $group_sent = $r->subprocess_env("REMOTE_GROUP") ||
$r->headers_in->{'REMOTE_GROUP'};
my $cache_result = $r->notes('AuthzCache');
if ($group_sent && $cache_result eq 'hit') {
$r->log->debug("handler: upstream cache hit for ",
"user=$username, group=$group_sent");
return OK;
# }
}
# Clear for paranoid security precautions
$r->subprocess_env(REMOTE_GROUP => undef);
undef($r->headers_in->{'REMOTE_GROUP'});
my $basedn = $r->dir_config('AuthzBaseDN');
my $groupattrtype = $r->dir_config('AuthzGroupAttrType') || 'cn';
my $authzldapserver = $r->dir_config('AuthzLDAPServer') || "localhost";
my $authzldapport = $r->dir_config('AuthzLDAPPort') || 389;
my $authenldapserver = $r->dir_config('AuthenLDAPServer') ||
$r->dir_config('AuthzLDAPServer') || "localhost";
my $authenldapport = $r->dir_config('AuthenLDAPPort') ||
$r->dir_config('AuthzLDAPPort') || 389;
my $memberattrtype = $r->dir_config('AuthzMemberAttrType') || 'member';
my $memberattrvalue = $r->dir_config('AuthzMemberAttrValue') || 'cn';
my $nestedattrtype = $r->dir_config('AuthzNestedAttrType') || 'member';
my $nested_groups = $r->dir_config('AuthzNestedGroups');
my $requirement = $r->dir_config('AuthzRequire') || 'inAGroup';
my $uidattrtype = $r->dir_config('AuthzUidAttrType') || 'uid';
my $userbasedn = $r->dir_config('AuthenBaseDN');
$requirement = REQUIRE_OPTS->{lc($requirement)} || 1;
$r->log->debug(join ", ", "AuthzBaseDN=$basedn",
"GroupAttrType=$groupattrtype",
"LDAPServer=$authzldapserver",
"MemberAttrType=$memberattrtype",
"MemberAttrValue=$memberattrvalue",
"NestedAttrType=$nestedattrtype",
"NestedGroups=$nested_groups",
"Requirement=$requirement",
"UserBaseDN=$userbasedn");
for my $req (@$requires) {
my ($require, $rest) = split /\s+/, $req->{requirement}, 2;
if ($require eq "user") { return OK
if grep $username eq $_, split /\s+/, $rest}
elsif ($require eq "valid-user") { return OK }
elsif ($require eq 'group') {
my $ld = undef;
# Connect to the server
unless ($ld = new Net::LDAP($authenldapserver,port => $authenldapport)) {
$r->note_basic_auth_failure;
$r->log_reason("user $username: Authen LDAP Connection Failed",$r->uri);
return SERVER_ERROR;
}
# Bind anonymously
my $msg = $ld->bind;
unless ($msg->code == LDAP_SUCCESS) {
$r->note_basic_auth_failure;
$r->log_reason("user $username: Authen LDAP Initial Bind Failed: " .
$msg->code . " " . $msg->error, $r->uri);
return SERVER_ERROR;
}
# Get user DN
$msg = $ld->search(base => $userbasedn,
filter => qq($uidattrtype=$username));
unless ($msg->code == LDAP_SUCCESS) {
$r->note_basic_auth_failure;
$r->log_reason("LDAP read failure " .
$msg->code . " " . $msg->error, $r->uri);
return SERVER_ERROR;
}
unless ($msg->count) {
$r->note_basic_auth_failure;
$r->log_reason("user ($uidattrtype) $username doesn't " .
"exist in LDAP " .
$msg->code . " " . $msg->error . $r->uri);
return AUTH_REQUIRED;
}
my $userinfo = undef;
if ($memberattrvalue eq 'dn') {
$userinfo = $msg->first_entry->dn;
} else {
$userinfo = ($msg->first_entry->get($memberattrvalue))[0];
}
$r->log->debug("handler: Userinfo is $userinfo ($memberattrvalue)");
$ld->unbind();
$ld = undef;
# Connect to the server
unless ($ld = new Net::LDAP($authzldapserver,port => $authzldapport)) {
$r->note_basic_auth_failure;
$r->log_reason("user $username: Authz LDAP Connection Failed",$r->uri);
return SERVER_ERROR;
}
# Bind anonymously
$msg = $ld->bind;
unless ($msg->code == LDAP_SUCCESS) {
$r->note_basic_auth_failure;
$r->log_reason("user $username: Authz LDAP Initial Bind Failed: " .
$msg->code . " " . $msg->error, $r->uri);
return SERVER_ERROR;
}
# Compare the username
my ($result, $group) = check_group($r, $ld, $basedn, $groupattrtype,
$memberattrtype, $userinfo, $rest,
$nestedattrtype, $nested_groups,
$requirement, 1);
return $result unless $result == OK;
# Everything's A-OK
$r->log->debug("Setting REMOTE_GROUP to $group");
$r->subprocess_env(REMOTE_GROUP => $group);
$r->headers_in->{'REMOTE_GROUP'} = $group;
return OK;
}
}
}
1;
__END__
# Documentation - try 'pod2text AuthzLDAP'
=head1 NAME
Apache::AuthzLDAP - mod_perl LDAP Authorization Module
=head1 SYNOPSIS
<Directory /foo/bar>
# Authorization Realm and Type (only Basic supported)
AuthName "Foo Bar Authentication"
AuthType Basic
# Any of the following variables can be set.
# Defaults are listed to the right.
PerlSetVar AuthenBaseDN o=Foo,c=Bar # Default: Empty String ("")
PerlSetVar AuthzBaseDN o=My Company # Default: none
PerlSetVar AuthzGroupAttrType gid # Default: cn
PerlSetVar AuthzLDAPServer ldap.foo.com # Default: localhost
PerlSetVar AuthzLDAPPort 389 # Default: 389
PerlSetVar AuthzMemberAttrType uniquemember # Default: member
PerlSetVar AuthzMemberAttrValue dn # Default: cn
PerlSetVar AuthzNestedAttrType uniquegroup # Default: member
PerlSetVar AuthzNestedGroups on # Default: off
PerlSetVar AuthzRequire inAllGroups # Default: inAGroup
PerlSetVar AuthzUidattrType userid # Default: uid
PerlAuthzHandler Apache::AuthzLDAP
require group "My Group" GroupA "Group B" # Authorize user against
# multiple groups
</Directory>
( run in 2.716 seconds using v1.01-cache-2.11-cpan-2398b32b56e )