LDAP Plugin - Best way to pass errors back to login page

@Damian,

I took the LDAP plugin code some people here contributed to the forums (sorry guys, I forgot who all worked on it) and made some modifications. I fixed a couple of bugs and I resolved an issue with the original code that occurs if someone changes the local password. (The original code would fail, with this updated code it will continue to work).

If anything - anywhere in the process fails - including authentication errors - I want to make sure the login page displays again with the error highlighted similar to how it works without the plugin.

What is the best way to get error codes back into that page? As you can see from the code below, I am doing a redirect back with the error code as part of the query string, but I don't like that all. Is there a more graceful way to populate that error message?

Looking forward to your reply.

GM


<?php

class LDAP extends PluginAbstract
{
public $name = 'LDAP Plugin';
public $description = 'LDAP Authentication';
public $author = 'various';
public $url = 'http://www.cumulusclips.org';
public $version = '1.0.0';

public function load()
{
// Plugin::attachEvent('login.end', array(__class__, 'LDAPCode'));
Plugin::attachEvent('login.end', array($this, 'LDAPCode'));
}

private function handleException($errorMessage)
{
$config = Registry::get('config');
$baseUrl = $config->baseUrl;

$view = View::getInstance();

$errorMessage = urlencode($errorMessage);

header('Location: ' . $baseUrl . '/login?error=' . $errorMessage);
exit;
}

public function LDAPCode()
{
$view = View::getInstance();

if ((isset($_POST['submitted_login'])) && (!(empty($view->vars->username))) && (!(empty($view->vars->password))))
{
$username = $view->vars->username;
$password = $view->vars->password;

$userMapper = new UserMapper();
$userService = new UserService();

// To trust selfsigned SSL certs add "TLS_REQCERT never" to /etc/openldap/ldap.conf
$ldapurl = "ldaps://server.mydomain.org:636";
$basedn = "DC=mydomain,DC=org";
$filter = "(sAMAccountName=[username])";
$userdn = $filter;

$ldaprdn = $username . "@mydomain.org";
$ldappass = $view->vars->password;

if ($userService->loginCheck())
{
exit;
}

$ldapconn = ldap_connect($ldapurl) or LDAP::handleException("ERROR: Incorrect LDAP Settings");
ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);

// Enable tracing...
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);

if ($ldapconn)
{
$ldapbind = ldap_bind($ldapconn, $ldaprdn, $ldappass) or LDAP::handleException("ERROR: Inccorect username or password");
}

$search = str_replace("[username]", $username, $userdn);

if (!preg_match('/\((.)*=(.)*\)/',$search))
{
throw new Exception("Failed: search has been used but '$search' is NOT a filter.");
}

$result = ldap_search($ldapconn,$basedn,$search) or LDAP::handleException("ERROR: Could not log you in, please try again.");
$entries = ldap_get_entries($ldapconn, $result);
$binddn = $entries[0]["dn"];
$ldapbind = ldap_bind($ldapconn, $binddn, $view->vars->password);

if ($ldapbind)
{
if ($entries)
{
$_SESSION['user'] = $username;
$_SESSION['loggedInUserId'] = $username;
$_SESSION['name'] = $entries[0]["cn"][0];
$_SESSION['email'] = $entries[0]['mail'][0];
}

// Creation of local user account if one does not exist
if (!$userMapper->getUserByUsername($username))
{
//Code to create the new user
$user = new User();
$user->username = $username;
$user->password = md5(SECRET_KEY.'PASSWORD');
$user->email = $_SESSION['email'];
$newUser = $userService->create($user);

//Local user activation
$newUser->status = 'active';
$newuser->lastLogin = date(DATE_FORMAT);
$userMapper->save($newUser);
}

$user = $userMapper->getUserByCustom(array(
'username' => $username,
'status' => 'active'
));

if ($user)
{
$_SESSION['loggedInUserId'] = $user->userId;
$user->lastLogin = date(DATE_FORMAT);
$userMapper->save($user);
$url = ($view->vars->redirect) ? $view->vars->redirect : HOST . '/account/';
$url = Plugin::triggerFilter('login_redirect', $url);
header('Location: ' . $url);
}
else
{
LDAP::handleException("ERROR: Login Failed");
}
}
ldap_close($ldapconn);
}
}
}
?>

Comments

  • edited October 2016
    Unfortunately we're not passing the view instance directly to the plugin hook on the login page. We can fix that during the next release.

    In the mean time you can hijack the "message" and "message_type" variables in the View.
  • Updated login.end hook in 2.5
  • Cool I see $view being passed now.

    Within the LDAP code I have a function to handle error messages in which I am setting the vars->message and vars->message_type.

    But how do I re-render the login page? If I do a redirect, I obviously lose the vars->message and vars->message_type I am setting ... so I am guessing I just need to redisplay the login page?
  • I'm a little confused. You are doing a redirect but want to still display the login page?
  • Ha! Sorry. So if the login fails (login.end), I am invoking the LDAP plugin and the LDAP code will attempt to authenticate against LDAP. If that fails however, I want to display the login page again with an error saying "login failed". I just don't know how to re-show the login page and pass that error message to it. Makes sense?
  • edited March 28
    Got it. The thing is, if the original login fails, the page will still try to render with the original error message. Unless you're preventing this behavior, there shouldn't be anything special you need to do.

    You should be able to grab the $view object passed to the plugin hook and override the message and message_type values from within your plugin.
This discussion has been closed.