Modified LDAP connections to support ldaps and ldapi authentication. Additionally modified some of the labels and hoverhelp within the LDAPLink edit screen to better explain and make them less confusing.

This commit is contained in:
Frank Dillon 2008-10-20 20:25:09 +00:00
parent 921ee1ab96
commit d7d9eb946f
4 changed files with 229 additions and 189 deletions

View file

@ -40,83 +40,82 @@ i.e., it does not validate their username or ensure their account is active.
=cut
sub _isValidLDAPUser {
my $self = shift;
my ($uri, $error, $ldap, $search, $auth, $connectDN, $username, $password);
my $i18n = WebGUI::International->new($self->session);
my $connection = $self->getLDAPConnection;
my $self = shift;
my ($error, $ldap, $search, $auth, $connectDN);
my $i18n = WebGUI::International->new($self->session);
$username = $self->session->form->get("authLDAP_ldapId") || $self->session->form->get("username");
$password = $self->session->form->get("authLDAP_identifier") || $self->session->form->get("identifier");
$uri = URI->new($connection->{ldapUrl}) or $error = '<li>'.$i18n->get(2,'AuthLDAP').'</li>';
if($error ne ""){
$self->error($error);
return 0;
}
# Create an LDAP object
if ($ldap = Net::LDAP->new($uri->host, (port=>$uri->port))) {
my $connection = $self->getLDAPConnection;
#Check to see that the LDAP Link is valid
my $ldapLink = $self->getLDAPLink;
unless ($ldapLink) {
$self->error('<li>'.$i18n->get(2,'AuthLDAP').'</li>');
return 0;
}
# Bind as a proxy user to search for the user trying to login
if($connection->{connectDn}) {
$auth = $ldap->bind(dn=>$connection->{connectDn}, password=>$connection->{identifier});
}
else { # No proxy user specified, try to bind anonymously for the search
$auth = $ldap->bind;
}
# If we were able to bind
if ($auth) {
# Search for the user trying to login
$search = $ldap->search(base=>$uri->dn, filter=>$connection->{ldapIdentity}.'='.$username);
my $username = $self->session->form->get("authLDAP_ldapId") || $self->session->form->get("username");
my $password = $self->session->form->get("authLDAP_identifier") || $self->session->form->get("identifier");
# Create an LDAP object
if ($ldap = $ldapLink->connectToLDAP) {
my $uri = $ldapLink->getURI;
# Bind as a proxy user to search for the user trying to login
if($connection->{connectDn}) {
$auth = $ldap->bind(dn=>$connection->{connectDn}, password=>$connection->{identifier});
}
else { # No proxy user specified, try to bind anonymously for the search
$auth = $ldap->bind;
}
# If we were able to bind
if ($auth) {
# Search for the user trying to login
$search = $ldap->search(base=>$uri->dn, filter=>$connection->{ldapIdentity}.'='.$username);
# If we found a match
if (defined $search->entry(0)) {
# If we found a match
if (defined $search->entry(0)) {
# Determine the users distinguished name using dn
if ($connection->{ldapUserRDN} eq 'dn') {
$connectDN = $search->entry(0)->dn;
}
else { # or... use a releative distinguished name instead
$connectDN = $search->entry(0)->get_value($connection->{ldapUserRDN});
}
# Determine the users distinguished name using dn
if ($connection->{ldapUserRDN} eq 'dn') {
$connectDN = $search->entry(0)->dn;
}
else { # or... use a releative distinguished name instead
$connectDN = $search->entry(0)->get_value($connection->{ldapUserRDN});
}
# Remember the users DN so we can use it later.
$self->setConnectDN($connectDN);
$ldap->unbind;
# Remember the users DN so we can use it later.
$self->setConnectDN($connectDN);
$ldap->unbind;
# Create a new LDAP object
$ldap = Net::LDAP->new($uri->host, (port=>$uri->port)) or $error .= $i18n->get(2,'AuthLDAP');
# Create a new LDAP object
$ldap = $ldapLink->connectToLDAP or $error .= $i18n->get(2,'AuthLDAP');
# Try to bind to the directory using the users dn and password
$auth = $ldap->bind(dn=>$connectDN, password=>$password);
#Try to bind to the directory using the users dn and password
$auth = $ldap->bind(dn=>$connectDN, password=>$password);
# Invalid login credentials, directory did not authenticate the user
if ($auth->code == 48 || $auth->code == 49) {
$error .= '<li>'.$i18n->get(68).'</li>';
$self->session->errorHandler->warn("Invalid LDAP information for registration of LDAP ID: ".$self->session->form->process('authLDAP_ldapId'));
# Invalid login credentials, directory did not authenticate the user
if ($auth->code == 48 || $auth->code == 49) {
$error .= '<li>'.$i18n->get(68).'</li>';
$self->session->errorHandler->warn("Invalid LDAP information for registration of LDAP ID: ".$self->session->form->process('authLDAP_ldapId'));
}
elsif ($auth->code > 0) { # Some other LDAP error occured
$error .= '<li>LDAP error "'.$self->ldapStatusCode($auth->code).'" occured. '.$i18n->get(69).'</li>';
$self->session->errorHandler->error("LDAP error: ".$self->ldapStatusCode($auth->code));
}
$ldap->unbind;
}
elsif ($auth->code > 0) { # Some other LDAP error occured
$error .= '<li>LDAP error "'.$self->ldapStatusCode($auth->code).'" occured. '.$i18n->get(69).'</li>';
$self->session->errorHandler->error("LDAP error: ".$self->ldapStatusCode($auth->code));
else { # Could not find the user in the directory to build a DN
$error .= '<li>'.$i18n->get(68).'</li>';
$self->session->errorHandler->warn("Invalid LDAP information for registration of LDAP ID: ".$self->session->form->process("authLDAP_ldapId"));
}
$ldap->unbind;
}
else { # Could not find the user in the directory to build a DN
$error .= '<li>'.$i18n->get(68).'</li>';
$self->session->errorHandler->warn("Invalid LDAP information for registration of LDAP ID: ".$self->session->form->process("authLDAP_ldapId"));
}
}
else { # Unable to bind with proxy user credentials or anonymously for our search
$error = '<li>'.$i18n->get(2,'AuthLDAP').'</li>';
$self->session->errorHandler->error("Couldn't bind to LDAP server: ".$connection->{ldapUrl});
}
}
else { # Unable to bind with proxy user credentials or anonymously for our search
$error = '<li>'.$i18n->get(2,'AuthLDAP').'</li>';
$self->session->errorHandler->error("Couldn't bind to LDAP server: ".$connection->{ldapUrl});
}
}
else { # Could not create our LDAP object
$error = '<li>'.$i18n->get(2,'AuthLDAP').'</li>';
$self->session->errorHandler->error("Couldn't create LDAP object: ".$uri->host);
$self->session->errorHandler->error("Couldn't create LDAP object: ".$connection->{ldapUrl});
}
$self->error($error);
@ -141,78 +140,79 @@ Returns 1 on success.
=cut
sub authenticate {
my $self = shift;
my ($uri, $ldap, $auth, $result, $error);
my $i18n = WebGUI::International->new($self->session);
return 0 if !$self->SUPER::authenticate($_[0]); #see that the username entered actually exists and is active in webgui
my $self = shift;
my ($uri, $ldap, $auth, $result, $error);
my $i18n = WebGUI::International->new($self->session);
return 0 if !$self->SUPER::authenticate($_[0]); #see that the username entered actually exists and is active in webgui
my $userId = $self->userId;
my $identifier = $_[1];
my $userData = $self->getParams;
my $userId = $self->userId;
my $identifier = $_[1];
my $userData = $self->getParams;
$error .= '<li>'.$i18n->get(12,'AuthLDAP').'</li>' if ($userData->{ldapUrl} eq "");
$error .= '<li>'.$i18n->get(11,'AuthLDAP').'</li>' if ($userData->{connectDN} eq "");
$self->error($error);
$error .= '<li>'.$i18n->get(12,'AuthLDAP').'</li>' if ($userData->{ldapUrl} eq "");
$error .= '<li>'.$i18n->get(11,'AuthLDAP').'</li>' if ($userData->{connectDN} eq "");
$self->error($error);
if($error ne ""){
$self->user(WebGUI::User->new($self->session,1));
return 0 ;
}
if($error ne ""){
$self->user(WebGUI::User->new($self->session,1));
return 0 ;
}
if($uri = URI->new($userData->{ldapUrl})) {
if($uri = URI->new($userData->{ldapUrl})) {
# Create an LDAP object
$ldap = Net::LDAP->new($uri->host, (port=>$uri->port)) or $error .= '<li>'.$i18n->get(2,'AuthLDAP').'</li>';
# Create an LDAP object
$ldap = Net::LDAP->new($uri->host, (port=>$uri->port, scheme=>$uri->scheme)) or $error .= '<li>'.$i18n->get(2,'AuthLDAP').'</li>';
if($error ne ""){
$self->user(WebGUI::User->new($self->session,1));
return 0 ;
}
if($error ne ""){
$self->user(WebGUI::User->new($self->session,1));
return 0 ;
}
# Try to bind using the users dn and password
$auth = $ldap->bind(dn=>$userData->{connectDN}, password=>$identifier);
# Authentication failed
if ($auth->code == 48 || $auth->code == 49){
$error .= '<li>'.$i18n->get(68).'</li>';
}
elsif ($auth->code > 0) { # Some other LDAP error happened
$error .= '<li>LDAP error "'.$self->ldapStatusCode($auth->code).'" occured.'.$i18n->get(69).'</li>';
$self->session->errorHandler->error("LDAP error: ".$self->ldapStatusCode($auth->code));
}
# Try to bind using the users dn and password
$auth = $ldap->bind(dn=>$userData->{connectDN}, password=>$identifier);
# Authentication failed
if ($auth->code == 48 || $auth->code == 49){
$error .= '<li>'.$i18n->get(68).'</li>';
}
elsif ($auth->code > 0) { # Some other LDAP error happened
$error .= '<li>LDAP error "'.$self->ldapStatusCode($auth->code).'" occured.'.$i18n->get(69).'</li>';
$self->session->errorHandler->error("LDAP error: ".$self->ldapStatusCode($auth->code));
}
$ldap->unbind;
}
else {
$error .= '<li>'.$i18n->get(13,'AuthLDAP').'</li>';
$self->session->errorHandler->error("Could not process this LDAP URL: ".$userData->{ldapUrl});
}
$ldap->unbind;
}
else {
$error .= '<li>'.$i18n->get(13,'AuthLDAP').'</li>';
$self->session->errorHandler->error("Could not process this LDAP URL: ".$userData->{ldapUrl});
}
if($error ne ""){
$self->error($error);
$self->user(WebGUI::User->new($self->session,1));
}
if($error ne ""){
$self->error($error);
$self->user(WebGUI::User->new($self->session,1));
}
return $error eq "";
return $error eq "";
}
#-------------------------------------------------------------------
sub connectToLDAP {
# This method needs to do some excpetion handling when we try to create an LDAPLink object
# Lot's to do though because then everything calling connectToLDAP must also handle exceptions on up
#
# Problem is that $connectionId may not have a value or the object creation may fail for other reasons.
# Quick fix for now is to ensure the ldapConnection setting is set in the settings table with the id of
# the default ldap connection.
# This method needs to do some excpetion handling when we try to create an LDAPLink object
# Lot's to do though because then everything calling connectToLDAP must also handle exceptions on up
#
# Problem is that $connectionId may not have a value or the object creation may fail for other reasons.
# Quick fix for now is to ensure the ldapConnection setting is set in the settings table with the id of
# the default ldap connection.
my $self = shift;
my $connectionId = $self->session->form->process("connection") || $self->session->setting->get("ldapConnection");
my $ldapLink = WebGUI::LDAPLink->new($self->session,$connectionId);
my $connection = $ldapLink->get;
my $self = shift;
my $connectionId = $self->session->form->process("connection") || $self->session->setting->get("ldapConnection");
my $ldapLink = WebGUI::LDAPLink->new($self->session,$connectionId);
my $connection = $ldapLink->get;
$self->{_connection} = $connection;
return $connection;
$self->{'_ldapLink' } = $ldapLink;
$self->{'_connection'} = $connection;
return $connection;
}
#-------------------------------------------------------------------
@ -274,46 +274,50 @@ sub createAccountSave {
return $self->createAccount("<h1>".$i18n->get(70)."</h1>".$self->error);
}
my $connection = $self->getLDAPConnection;
#Get connectDN from settings
my $uri = URI->new($connection->{ldapUrl});
my $ldap = Net::LDAP->new($uri->host, (port=>$uri->port));
my $auth;
if($connection->{connectDn}) {
$auth = $ldap->bind(dn=>$connection->{connectDn}, password=>$connection->{identifier});
}else{
$auth = $ldap->bind;
}
#$ldap->bind;
my $search = $ldap->search (base => $uri->dn, filter=>$connection->{ldapIdentity}."=".$username);
my $connectDN = "";
if (defined $search->entry(0)) {
if ($connection->{ldapUserRDN} eq 'dn') {
$connectDN = $search->entry(0)->dn;
} else {
$connectDN = $search->entry(0)->get_value($connection->{ldapUserRDN});
}
}
$ldap->unbind;
#Check that username is valid and not a duplicate in the system.
$error .= $self->error if(!$self->validUsername($username));
#Validate profile data.
my ($profile, $temp, $warning) = WebGUI::Operation::Profile::validateProfileData($self->session);
$error .= $temp;
return $self->createAccount("<li>".$error."</li1>") unless ($error eq "");
#If Email address is not unique, a warning is displayed
if($warning ne "" && !$self->session->form->process("confirm")){
return $self->createAccount('<li>'.$i18n->get(1078).'</li>', 1);
}
my $properties;
$properties->{connectDN} = $connectDN;
$properties->{ldapUrl} = $connection->{ldapUrl};
$properties->{ldapConnection} = $connection->{ldapLinkId};
my $connection = $self->getLDAPConnection;
my $ldapLink = $self->getLDAPLink;
return $self->SUPER::createAccountSave($username,$properties,$password,$profile);
#Get connectDN from settings
my $ldap = $ldapLink->connectToLDAP;
my $uri = $ldapLink->getURI;
my $auth;
if($connection->{connectDn}) {
$auth = $ldap->bind(dn=>$connection->{connectDn}, password=>$connection->{identifier});
}
else{
$auth = $ldap->bind;
}
#$ldap->bind;
my $search = $ldap->search (base => $uri->dn, filter=>$connection->{ldapIdentity}."=".$username);
my $connectDN = "";
if (defined $search->entry(0)) {
if ($connection->{ldapUserRDN} eq 'dn') {
$connectDN = $search->entry(0)->dn;
}
else {
$connectDN = $search->entry(0)->get_value($connection->{ldapUserRDN});
}
}
$ldap->unbind;
#Check that username is valid and not a duplicate in the system.
$error .= $self->error if(!$self->validUsername($username));
#Validate profile data.
my ($profile, $temp, $warning) = WebGUI::Operation::Profile::validateProfileData($self->session);
$error .= $temp;
return $self->createAccount("<li>".$error."</li1>") unless ($error eq "");
#If Email address is not unique, a warning is displayed
if($warning ne "" && !$self->session->form->process("confirm")){
return $self->createAccount('<li>'.$i18n->get(1078).'</li>', 1);
}
my $properties;
$properties->{connectDN} = $connectDN;
$properties->{ldapUrl} = $connection->{ldapUrl};
$properties->{ldapConnection} = $connection->{ldapLinkId};
return $self->SUPER::createAccountSave($username,$properties,$password,$profile);
}
#-------------------------------------------------------------------
@ -489,6 +493,13 @@ sub getLDAPConnection {
return $self->connectToLDAP;
}
#-------------------------------------------------------------------
sub getLDAPLink {
my $self = shift;
return $self->{_ldapLink};
}
#-------------------------------------------------------------------
sub getLoginTemplateId {
my $self = shift;

View file

@ -56,14 +56,14 @@ cannot be established
sub bind {
my $self = shift;
my ($uri, $ldap, $auth, $result, $error);
my ($uri, $auth, $result, $error);
if (defined $self->{_connection}) {
return $self->{_connection};
}
my $ldapUrl = $self->{_ldapLink}->{ldapUrl};
my $connectDn = $self->{_ldapLink}->{connectDn};
my $ldapUrl = $self->{_ldapLink}->{ldapUrl};
my $connectDn = $self->{_ldapLink}->{connectDn};
my $identifier = $self->{_ldapLink}->{identifier};
if ($ldapUrl eq "") {
@ -71,25 +71,52 @@ sub bind {
return 0;
}
if ($uri = URI->new($ldapUrl)) {
unless ($ldap = Net::LDAP->new($uri->host, (port=>($uri->port || 389)))) {
$self->{_error} = 103;
return 0;
}
my $ldap = $self->connectToLDAP($ldapUrl);
return 0 unless ($ldap);
$auth = $ldap->bind(dn=>$connectDn, password=>$identifier);
if ($auth->code == 48 || $auth->code == 49) {
$self->{_error} = 104;
} elsif($auth->code > 0) {
$self->{_error} = $auth->code;
}
$self->{_uri } = $uri;
$self->{_connection} = $ldap;
} else {
$self->{_error} = 105;
return 0;
}
return $self->{_connection};
$auth = $ldap->bind(dn=>$connectDn, password=>$identifier);
if ($auth->code == 48 || $auth->code == 49) {
$self->{_error} = 104;
} elsif($auth->code > 0) {
$self->{_error} = $auth->code;
}
return $ldap;
}
#-------------------------------------------------------------------
=head2 connectToLDAP ( )
Attempts to bind to an LDAP server returning the Net::LDAP object if successful
=cut
sub connectToLDAP {
my $self = shift;
my $ldapUrl = shift || $self->getValue("ldapUrl");
my $uri = URI->new($ldapUrl);
unless ($uri) {
$self->{_error} = 105;
return undef;
}
$self->{_uri} = $uri;
my $ldap = Net::LDAP->new($uri->host,
port => $uri->port, #Port will default to 389 or 636
scheme => $uri->scheme
);
unless($ldap) {
$self->{_error} = 103;
return undef;
}
$self->{_connection} = $ldap;
return $ldap;
}
#-------------------------------------------------------------------

View file

@ -159,7 +159,6 @@ sub www_deleteLDAPLink {
my $session = shift;
return $session->privilege->insufficient unless canView($session);
$session->db->write("delete from ldapLink where ldapLinkId=".$session->db->quote($session->form->process("llid")));
$session->form->process("op") = "listLDAPLinks";
return www_listLDAPLinks($session);
}

View file

@ -140,7 +140,7 @@ our $I18N = {
},
'9' => {
message => q|User RDN|,
message => q|Authentication Attribute|,
lastUpdated => 1053777552
},
@ -546,28 +546,31 @@ our $I18N = {
},
'LDAPLink_993 description' => {
message => q|The URL used to connect to the LDAP server.|,
message => q|<p>The URL used to connect to the LDAP server. LDAP url should look like:</p>
<p>ldap://ldap.mycompany.com/baseDN</p><p>baseDN is the node on your LDAP server that WebGUI should use to initialize user searches. Typically this looks like dc=mycompany,dc=com.</p>
<p>ldap://ldap.mycompany.com/dc=mycompany,dc=com</p>|,
lastUpdated => 1120164594,
},
'LDAPLink_994 description' => {
message => q|<p>DN = Distinguished Name. A DN is a unique path to a particular object within an LDAP
directory. In this case, the "Connect DN" is the DN that points to the user account
record. Usually that will look something like:</p>
record for authenticating against this LDAP server at a permission level that has full read and write access to all of the users and groups on your LDAP server.
Usually that will look something like:</p>
<p>cn=Joe Shmoe,ou=people,dc=example,dc=com</p>|,
lastUpdated => 1146630168,
},
'LDAPLink_995 description' => {
message => q|The password for the LDAP connection|,
message => q|The password for the account entered in the "Connect DN" field|,
lastUpdated => 1120164594,
},
'9 description' => {
message => q|<p>RDN is a relative distinguished name. It means that we're looking at only part of the
path. In this case, the "User RDN" is the path to where user records can be found.
Usually the RDN looks something like:</p>
<p>ou=people,dc=example,dc=com</p>|,
message => q|<p>Enter the attribute that should be used for each record in LDAP to uniquely identify a user.
This field is used for auto creating user accounts for users already in your LDAP repository when they attempt to log in and
for finding users who sign up for the site via the anonymous registration feature if it is enabled. In almost all cases this attrubute is 'dn'
and should be entered as such.</p>|,
lastUpdated => 1146630220,
},