LDAP authentication - Gallery Codex
Personal tools

LDAP authentication

From Gallery Codex

LDAP authentication in Gallery2 ...

Setup instructions

...

Forum discussions


Example Code

Note this code is an example from a user and not the developers of Gallery. It is my interpretation and works well enough for our use. In my opinion this should not be so difficult --Jkuter 06:25, 27 November 2007 (PST)

index.php embed script with ldap authentication

  • This code is for passwordless login
  • SESSION is unset in logout.inc
  • login.php is another small file with an input that posts to the index.php
<?php
// look for a user id in the session, if its not there start the session so we can make one
if (!isset($_SESSION['emAppUserId'])) {
	session_name('GalleryOnInside'); // Choose session name
	session_set_cookie_params(1209600);
	session_start(); // Initialize a session
}
// triggers embed classes for gallery so the below will work
require_once('embed.php');

// pull in gallery content and trigger user functions
$data = runGallery();

// set page title
$data['title'] = (isset($data['title']) && !empty($data['title'])) ? $data['title'] : 'Gallery';
//set up page html
if (isset($data['bodyHtml'])) {
	print <<<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>{$data['title']}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
{$data['javascript']}
{$data['css']}
</head>

<body>
{$data['bodyHtml']}
</body>
</html>
EOF;
}
// Close Gallery Connection
GalleryEmbed::done();

function runGallery() {
	// required configuration of embed vars	
	$embedUri = '/phpapps/gallery2/index.php';
	$g2Uri = '/phpapps/gallery2/main.php';
	$loginRedirect = '/phpapps/gallery2/login.php';
	// see if this is an initial login and set username
	$username = isset($_POST['username']) ? $_POST['username'] : "";
	if ($username != "") {
		// try and authenticate posted name
		$auth = authenticateLogin($username);
		if ($auth['ErrorCode'] == "Username and Password validated") {
			//set config vars from LDAP
			$_SESSION['emAppUserId'] = $auth['uid'];
			$emAppUserLogin = $auth['cn'];
			$emAppUserName = $auth['fullname'];
			$emAppUserEmail = $auth['email'];
		} else {
			die('Authentication Failed: ' . $auth['ErrorCode']);
		}
	}

	if (isset($_SESSION['emAppUserId'])) {
		// if user is logged in, set user ID to emApp's session user_id
		$emAppUserId = $_SESSION['emAppUserId'];
	} else {
		// if anonymous user, set g2 activeUser to ''
		$emAppUserId = '';
	}
	
	// actually get gallery going passing all needed config
	$ret = GalleryEmbed::init(array('embedUri' => $embedUri, 'g2Uri' => $g2Uri, 'fullInit' => true, 'loginRedirect' => $loginRedirect, 'activeUserId' => $emAppUserId));

	// Display login link with our credentials from $loginRedirect
	GalleryCapabilities::set('login', true);

	if ($ret) {
		// Did we get an error because the user doesn't exist in g2 yet?
		$ret2 = GalleryEmbed::isExternalIdMapped($emAppUserId, 'GalleryUser');
		if ($ret2 && $ret2->getErrorCode() & ERROR_MISSING_OBJECT) {
			// The user does not exist in G2 yet. Create in now on-the-fly
			$ret = GalleryEmbed::createUser($emAppUserId, array ( 'username' => $emAppUserLogin, 'email' => $emAppUserEmail, 'fullname' => $emAppUserName));
			if ($ret) {
				// An error during user creation. Not good, print an error or do whatever is appropriate
				print "An error occurred during the on-the-fly user creation <br>";
				print $ret->getAsHtml();
				exit;
			}
		} else {
			// The error we got wasn't due to a missing user, it was a real error
			if ($ret2) {
				print "An error occurred while checking if a user already exists<br>";
				print $ret2->getAsHtml();
			}
			print "An error occurred while trying to initialize G2<br>";
			print $ret->getAsHtml();
			exit;
		}
	}

	// At this point we know that either the user either existed already before or that it was just created
	$g2moddata = GalleryEmbed::handleRequest();

	// show error message if isDone is not defined
	if (!isset($g2moddata['isDone'])) {
		$data['bodyHtml'] = 'isDone is not defined, something very bad must have happened.';
		return $data;
	}

	// exit if it was an immediate view / request (G2 already outputted some data)
	if ($g2moddata['isDone']) {
		exit;
	}

	// put the body html
	$data['bodyHtml'] = isset($g2moddata['bodyHtml']) ? $g2moddata['bodyHtml'] : '';

	// get the page title, javascript and css links from the <head> html from G2
	$title = ''; $javascript = array();	$css = array();

	if (isset($g2moddata['headHtml'])) {
		list($data['title'], $css, $javascript) = GalleryEmbed::parseHead($g2moddata['headHtml']);
		$data['headHtml'] = $g2moddata['headHtml'];
	}


	// Add G2 javascript
	$data['javascript'] = '';
	if (!empty($javascript)) {
		foreach ($javascript as $script) {
			$data['javascript'] .= "\n".$script;
		}
	}

	// Add G2 css
	$data['css'] = '';
	if (!empty($css)) {
		foreach ($css as $style) {
			$data['css'] .= "\n".$style;
		}
	}

	return $data;
}

function authenticateLogin($username) {
	// ldap config
	$server="ldap://myldap.server.com:389";
	$basedn="dc=ad,dc=domainname,dc=com";
	$filter="(&(objectclass=user)(cn=$username)(!(userAccountControl=66050))(!(objectclass=computer)))";
	// try and connect
	if (!($connect = ldap_connect($server))) {
		$loginError = 'Could not connect to LDAP server';
	} else {
		// Logged in - Override some options
		ldap_set_option($connect, LDAP_OPT_REFERRALS, 0);
		ldap_set_option($connect,LDAP_OPT_PROTOCOL_VERSION,3);
		$bind = ldap_bind($connect);
		// Search for the user to get the DN
		$sr = ldap_search($connect,$basedn,$filter);
		$info = ldap_get_entries($connect, $sr);
		// set basic user info
		$fullname=$info[0]["displayname"][0];
		$cn=$info[0]["cn"][0];
		$uid=$info[0]["uidnumber"][0];
		$email=$info[0]["userprincipalname"][0];
		$dn=$info[0]["dn"];

		// Store key user information in an array to be returned
		$result['fullname'] = $fullname;
		$result['uid'] = $uid;
		$result['cn'] = $cn;
		$result['email'] = $email;
		if ($dn != "") {
			$loginError = 'Username and Password validated';
		} else {
			$loginError = "Bind Failed for $dn";
		}
	}
	// set results of bind
	$result['ErrorCode'] = $loginError;
	
	return $result;
}
?>

LDAP UserLogin for Gallery 2.3

None of the given contributions met my needs for ldap authentication ... most of them didn't work or just seemed to work but also with wrong passwords!

I modified modules\core\UserLogin.inc to authenticate against an ActiveDirectory and it works perfectly for me.

I don't know a lot about error handling but I tried to use it correctly.

--W.stoettinger 10:18, 30 September 2009 (UTC)

Functionality

A User is first authenticated against the LDAP. If it does not exist, it is created in Gallery2, so no need for additional administration here. If the user does not exist in LDAP it is checked against the Gallery2 database so it's also possible to create Gallery-only users.

Installation

Place the code found below in your modules\core\UserLogin.inc and replace the settings to connect to you LDAP server (in Line 229 in the function ldapAuthentication).

Code

Replace your modules\core\UserLogin.inc with the following code:

<?php
/*
 * Gallery - a web based photo album viewer and editor
 * Copyright (C) 2000-2007 Bharat Mediratta
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
 */

/**
 * This controller will handle a user logging in to Gallery
 * @package GalleryCore
 * @subpackage UserInterface
 * @author Bharat Mediratta <bharat@menalto.com>
 * @version $Revision: 15955 $
 */
class UserLoginController extends GalleryController {

    /**
     * ValidationPlugin instances to use when handling this request.  Only used by test code.
     *
     * @var array $_plugins (array of GalleryValidationPlugin)
     * @access private
     */
    var $_pluginInstances;

    /**
     * Tests can use this method to hardwire a specific set of plugin instances to use.
     * This avoids situations where some of the option instances will do unpredictable
     * things and derail the tests.
     *
     * @param array $pluginInstances of GalleryValidationPlugin
     */
    function setPluginInstances($pluginInstances) {
	$this->_pluginInstances = $pluginInstances;
    }

    /**
     * @see GalleryController::isAllowedInMaintenance
     */
    function isAllowedInMaintenance() {
	return true;
    }

    /**
     * @see GalleryController::handleRequest
     */
    function handleRequest($form) {
	global $gallery;

	$results = array();
	$error = array();
	if (isset($form['action']['login'])) {
	    if (empty($form['username'])) {
		$error[] = 'form[error][username][missing]';
	    }

	    if (empty($form['password'])) {
		$error[] = 'form[error][password][missing]';
	    }

	    if (empty($error)) {
		list ($ret, $isDisabled) = GalleryCoreApi::isDisabledUsername($form['username']);
		if ($ret) {
		    return array($ret, null);
		}
		if ($isDisabled) {
		    $error[] = 'form[error][username][disabled]';
		}
	    }

	    if (empty($error)) {
		list ($ret, $user) = GalleryCoreApi::fetchUserByUsername($form['username']);
		if ($ret && !($ret->getErrorCode() & ERROR_MISSING_OBJECT)) {
		    return array($ret, null);
		}		
		/* LDAP Code begin */
		
		$ldapRet = $this->ldapAuthentication($form['username'],$form['password']);
		if ($ldapRet && !is_array($ldapRet))  {
			// any error with LDAP connection.
			$error[] = "form[error]$ldapRet";
		}
		else if(is_array($ldapRet)){ // User found:
			// At first login, create new User
			if (!isset($user)) { 
				list ($ret, $user) = GalleryCoreApi::newFactoryInstance('GalleryEntity', 'GalleryUser');
				if ($ret) {
					return array($ret, null);
				}
				if (!isset($user)) {
					return array(GalleryCoreApi::error(ERROR_MISSING_OBJECT), null);
				}
				
				$ret = $user->create($username);
				if ($ret) { // this should never happen:
					if (!($ret->getErrorCode() & ERROR_COLLISION)) {
						return array($ret, null);
					}
					// Set our error status and fall back to the view
					$error[] = 'form[error][userName][exists]';
				} 
			}
			// set the users properties and save them:
			$user->setEmail($ldapRet['email']);
			$user->setFullName($ldapRet['fullName']);
			$user->changePassword($ldapRet['password']);
			
			GalleryCoreApi::acquireWriteLock($user->getId());
			$ret = $user->save();
			GalleryCoreApi::releaseLocks($user->getId());
			
			if ($ret) {
				return array($ret, null);
			}
		}
		else { 
			// User not found in LDAP should not be a problem: normal user autentication
		}
		/* LDAP Code end */
		GalleryUtilities::unsanitizeInputValues($form['password'], false);
		$isCorrect = (isset($user) && $user->isCorrectPassword($form['password']));

		/* Prepare for validation */
		$options = array('pass' => $isCorrect);
		list ($ret, $options['level']) =
		    GalleryCoreApi::getPluginParameter('module', 'core', 'validation.level');
		if ($ret) {
		    return array($ret, null);
		}
		if ($options['level'] == 'MEDIUM') {
		    $options['key'] = 'core.UserLogin.' . $form['username'];
		}
		if ($options['level'] == 'OFF') {
		    $pluginInstances = array();
		} else if (isset($this->_pluginInstances)) {
		    $pluginInstances = $this->_pluginInstances;
		} else {
		    list ($ret, $pluginInstances) =
			GalleryCoreApi::getAllFactoryImplementationIds('GalleryValidationPlugin');
		    if ($ret) {
			return array($ret, null);
		    }

		    foreach (array_keys($pluginInstances) as $pluginId) {
			list ($ret, $pluginInstances[$pluginId]) =
			    GalleryCoreApi::newFactoryInstanceById('GalleryValidationPlugin',
								   $pluginId);
			if ($ret) {
			    return array($ret, null);
			}
		    }
		}

		/* Let each plugin do its verification */
		foreach ($pluginInstances as $plugin) {
		    list ($ret, $pluginErrors, $continue) =
			$plugin->performValidation($form, $options);
		    if ($ret) {
			return array($ret, null);
		    }

		    $error = array_merge($error, $pluginErrors);
		    if (!$continue) {
			break;
		    }
		}
	    }

	    if (empty($error)) {
		if ($isCorrect) {
		    $gallery->setActiveUser($user);

		    $event = GalleryCoreApi::newEvent('Gallery::Login');
		    $event->setEntity($user);
		    list ($ret, $redirect) = GalleryCoreApi::postEvent($event);
		    if ($ret) {
			return array($ret, null);
		    }

		    /* Redirect if requested by event listener, otherwise return */
		    if (!empty($redirect)) {
			$results['redirect'] = array_shift($redirect);
		    } else {
			$results['return'] = 1;
		    }
		} else {
		    $error[] = 'form[error][invalidPassword]';
		}
	    }

	    if (!empty($error)) {
		if (!empty($form['username'])) {
		    $event = GalleryCoreApi::newEvent('Gallery::FailedLogin');
		    $event->setData(array('userName' => $form['username']));
		    list ($ret, $ignored) = GalleryCoreApi::postEvent($event);
		    if ($ret) {
			return array($ret, null);
		    }
		}
	    }

	} else if (isset($form['action']['cancel'])) {
	    $results['return'] = 1;
	}

	if (!empty($error)) {
	    $results['delegate']['view'] = 'core.UserAdmin';
	    $results['delegate']['subView'] = 'core.UserLogin';
	}
	$results['status'] = array();
	$results['error'] = $error;

	return array(null, $results);
    }
    /* LDAP Code begin */
    public function ldapAuthentication($username, $password) {
    	$ldap      = array('ldaphost' => 'ldap://ldap.domain.com',
			'domain'   => 'domain.com',
			'dn'       => 'ou=Users,dc=domain,dc=com',
			'binduser' => 'CN=Proxy,ou=Users,dc=domain,dc=com',
			'bindpass' => 'proxypassword'
    	);
    	
		// Open LDAP connection to server
		$ldapconn  = ldap_connect($ldap['ldaphost']);
		ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
		ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);

		// Bind with binduser as proxy to do the search
		$proxyBind         = ldap_bind($ldapconn, $ldap['binduser'], $ldap['bindpass']);
		
		if (!$proxyBind) {
			return "[invalidLDAPProxy]";
		}
		
		// search for the supplied username in the base DN
		$ldapSearchResult = ldap_search($ldapconn, $ldap['dn'], "(sAMAccountName=".$username.")" , array( "*" ));
		$ldapEntries      = ldap_get_entries($ldapconn, $ldapSearchResult);

		if ($ldapEntries["count"] < 1) {
			return null;
		}
		
		$userdn = $ldapEntries[0]["dn"];
		//use the found DN to bind again
		$userBind = ldap_bind($ldapconn, $userdn, $password);
		
    	if (!$userBind) {
			return "[invalidPassword]";
		}

		$user_info = array();
		$user_info['fullName'] = $ldapEntries[0]["givenname"][0]." ".$ldapEntries[0]["sn"][0];
		$user_info['email']    = $ldapEntries[0]["mail"][0];
		$user_info['password'] = $password;
		
		ldap_unbind($ldapconn);
		
		return $user_info;
    }
    /* LDAP Code end */
    
}

/**
 * This view prompts for login information
 */
class UserLoginView extends GalleryView {

    /**
     * @see GalleryView::loadTemplate
     */
    function loadTemplate(&$template, &$form) {
	global $gallery;

	/* Check if the default login view URL has been overridden and redirect appropriately */
	$loginRedirect = $gallery->getConfig('loginRedirect');
	if (!(isset($loginRedirect['subView']) && $loginRedirect['subView'] == 'core.UserLogin')
		&& !empty($loginRedirect)) {
	    /* Do not redirect if we are logged in already */
	    list ($ret, $isGuest) = GalleryCoreApi::isAnonymousUser();
	    if ($ret) {
		return array($ret, null);
	    }

	    $phpVm = $gallery->getPhpVm();
	    $urlGenerator =& $gallery->getUrlGenerator();
	    if ($isGuest && !$phpVm->headers_sent()) {
		$redirectUrl = $urlGenerator->generateUrl($loginRedirect,
							  array('forceSessionId' => false,
							  	'forceFullUrl' => true));
		$phpVm->header("Location: $redirectUrl");
		$phpVm->exit_();
	    }
	}

	if ($form['formName'] != 'UserLogin') {
	    $form['formName'] = 'UserLogin';
	    $form['username'] = '';

	    /*
	     * When logging in we don't have a session yet, thus no navigation history / a place
	     * to store the returnUrl. Thus store the returnUrl in the login form
	     */
	    $returnUrl = GalleryUtilities::getRequestVariables('return');
	    $form['returnUrl'] = !empty($returnUrl) ? $returnUrl : '';
	}

	$template->setVariable('controller', 'core.UserLogin');
	return array(null, array('body' => 'modules/core/templates/UserLogin.tpl'));
    }
}
?>

A note for those stuck with PHP4.x, "public function ldapAuthentication" will probably need to be just "function ldapAuthentication," and "$ret = $user->create($username);" didn't work until I changed it to "$ret = $user->create($form['username']);"

If your AD server is running in secure mode, change these lines:

#change ldap://ldap.domain.com to ldaps://ldap.domain.com
$ldap      = array('ldaphost' => 'ldap://ldap.domain.com',
			'domain'   => 'domain.com',
			##ADD THIS NEW LINE BELOW
			'ldapport' => '123', #or whatever
			'dn'       => 'ou=Users,dc=domain,dc=com',
			'binduser' => 'CN=Proxy,ou=Users,dc=domain,dc=com',
			'bindpass' => 'proxypassword'
    	);

And change this:

$ldapconn  = ldap_connect($ldap['ldaphost']);

To this:

$ldapconn  = ldap_connect($ldap['ldaphost'],$ldap['ldapport']);