Add LDAP Auth backend
This commit is contained in:
116
source/lib/SihnonFramework/Auth/Plugin/LDAP.class.php
Normal file
116
source/lib/SihnonFramework/Auth/Plugin/LDAP.class.php
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class SihnonFramework_Auth_Plugin_LDAP
|
||||||
|
extends Sihnon_PluginBase
|
||||||
|
implements Sihnon_Auth_IPlugin,
|
||||||
|
Sihnon_Auth_IPermissionable,
|
||||||
|
Sihnon_Auth_IFinelyPermissionable {
|
||||||
|
|
||||||
|
protected $config;
|
||||||
|
protected $ldap;
|
||||||
|
|
||||||
|
protected function __construct($config) {
|
||||||
|
$this->config = $config;
|
||||||
|
|
||||||
|
$this->initInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function initInstance() {
|
||||||
|
$this->ldap = ldap_connect($this->config->get('auth.LDAP.servers'), $this->config->get('auth.LDAP.port', 389));
|
||||||
|
if ( ! $this->ldap) {
|
||||||
|
throw new SihnonFramework_Exception_LDAPConnectionFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->config->get('auth.LDAP.start-tls', false)) {
|
||||||
|
if ( ! ldap_start_tls($this->ldap)) {
|
||||||
|
throw new Sihnon_Exception_LDAPSecureConnectionFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$search_dn = $this->config->get('auth.LDAP.search-dn', null);
|
||||||
|
$search_password = $this->config->get('auth.LDAP.search-password', null);
|
||||||
|
if ( ! ldap_bind($this->ldap, $search_dn, $search_password)) {
|
||||||
|
var_dump("Failed to bind as", $search_dn, $search_password);
|
||||||
|
throw new SihnonFramework_Exception_LDAPBindFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
Sihnon_Auth_Plugin_LDAP_User::init(
|
||||||
|
$this->ldap,
|
||||||
|
$this->config->get('auth.LDAP.user-base-dn'),
|
||||||
|
$this->config->get('auth.LDAP.group-base-dn'),
|
||||||
|
$this->config->get('auth.LDAP.recursive-search', false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IPlugin methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static function create(Sihnon_Config $config) {
|
||||||
|
return new self($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function userExists($username) {
|
||||||
|
return Sihnon_Auth_Plugin_LDAP_User::exists($username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listUsers() {
|
||||||
|
return Sihnon_Auth_Plugin_LDAP_User::all();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authenticate($username, $password) {
|
||||||
|
$user = Sihnon_Auth_Plugin_LDAP_User::load($username);
|
||||||
|
|
||||||
|
if ( ! $user->checkPassword($password)) {
|
||||||
|
throw new Sihnon_Exception_IncorrectPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authenticateSession($username) {
|
||||||
|
return Sihnon_Auth_Plugin_LDAP_User::load($username);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IPermissionable methods
|
||||||
|
*/
|
||||||
|
|
||||||
|
public function isAdministrator(Sihnon_Auth_IUser $user) {
|
||||||
|
return $user->isAdministrator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasPermission(Sihnon_Auth_IUser $user, $permission) {
|
||||||
|
return $user->hasPermission($permission);
|
||||||
|
}
|
||||||
|
public static function ldapEscape($input_str, $for_dn = false) {
|
||||||
|
// Taken from Douglas Davis at http://php.sihnon.net/manual/en/function.ldap-search.php#90158
|
||||||
|
// see:
|
||||||
|
// RFC2254
|
||||||
|
// http://msdn.microsoft.com/en-us/library/ms675768(VS.85).aspx
|
||||||
|
// http://www-03.ibm.com/systems/i/software/ldap/underdn.html
|
||||||
|
|
||||||
|
$str = $input_str;
|
||||||
|
if ( ! is_array($str)) {
|
||||||
|
$str = array($str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($for_dn) {
|
||||||
|
$metaChars = array(',', '=', '+', '<', '>', ';', '\\', '"', '#');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$metaChars = array('*', '(', ')', '\\', chr(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
$quotedMetaChars = array();
|
||||||
|
foreach ($metaChars as $key => $value) {
|
||||||
|
$quotedMetaChars[$key] = '\\'.str_pad(dechex(ord($value)), 2, '0');
|
||||||
|
}
|
||||||
|
$str = str_replace($metaChars,$quotedMetaChars,$str); //replace them
|
||||||
|
|
||||||
|
return is_array($input_str) ? $str : $str[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
139
source/lib/SihnonFramework/Auth/Plugin/LDAP/User.class.php
Normal file
139
source/lib/SihnonFramework/Auth/Plugin/LDAP/User.class.php
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class SihnonFramework_Auth_Plugin_LDAP_User implements Sihnon_Auth_IUser {
|
||||||
|
|
||||||
|
protected static $ldap;
|
||||||
|
protected static $user_base_dn;
|
||||||
|
protected static $group_base_dn;
|
||||||
|
protected static $recursive_search;
|
||||||
|
|
||||||
|
protected $groups = null;
|
||||||
|
|
||||||
|
protected $fullname;
|
||||||
|
protected $username;
|
||||||
|
|
||||||
|
public static function init($ldap, $user_base_dn, $group_base_dn, $recursive_search) {
|
||||||
|
static::$ldap = $ldap;
|
||||||
|
static::$user_base_dn = $user_base_dn;
|
||||||
|
static::$group_base_dn = $group_base_dn;
|
||||||
|
static::$recursive_search = $recursive_search;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function exists($username) {
|
||||||
|
$ldap_username = Sihnon_Auth_Plugin_LDAP::ldapEscape($username);
|
||||||
|
$filter = "(&(objectClass=posixAccount)(uid={$ldap_username}))";
|
||||||
|
|
||||||
|
$search = ldap_search(static::$ldap, static::$user_base_dn, $filter, array('uid'), 0, 1);
|
||||||
|
$result = ldap_get_entries(static::$ldap, $search);
|
||||||
|
|
||||||
|
return $result['count'] == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function fromLDAP($result) {
|
||||||
|
$user = new self();
|
||||||
|
$user->fullname = $result['cn'][0];
|
||||||
|
$user->username = $result['uid'][0];
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function load($username) {
|
||||||
|
$ldap_username = Sihnon_Auth_Plugin_LDAP::ldapEscape($username);
|
||||||
|
$filter = "(&(objectClass=posixAccount)(uid={$ldap_username}))";
|
||||||
|
|
||||||
|
$search = ldap_search(static::$ldap, static::$user_base_dn, $filter, array('cn', 'uid'), 0, 1);
|
||||||
|
$result = ldap_get_entries(static::$ldap, $search);
|
||||||
|
|
||||||
|
if ($result['count'] != 1) {
|
||||||
|
throw new Sihnon_Exception_UnknownUser($username);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::fromLDAP($result[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function all() {
|
||||||
|
$filter = "(objectClass=posixAccount)";
|
||||||
|
|
||||||
|
$search = null;
|
||||||
|
if (static::$recursive_search) {
|
||||||
|
$search = ldap_search(static::$ldap, static::$user_base_dn, $filter, array('cn', 'uid'), 0);
|
||||||
|
} else {
|
||||||
|
$search = ldap_list(static::$ldap, static::$user_base_dn, $filter, array('cn', 'uid'), 0);
|
||||||
|
}
|
||||||
|
$result = ldap_get_entries(static::$ldap, $search);
|
||||||
|
|
||||||
|
$users = array();
|
||||||
|
for ($i = 0, $l = $result['count']; $i < $l; ++$i) {
|
||||||
|
$users[] = static::fromLDAP($result[$i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function username() {
|
||||||
|
return $this->username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkPassword($password) {
|
||||||
|
$ldap_user_dn = Sihnon_Auth_Plugin_LDAP::ldapEscape($this->fullname, true);
|
||||||
|
return ldap_bind(static::$ldap, "cn={$ldap_user_dn},".static::$base_dn, $password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function changePassword($new_password) {
|
||||||
|
throw new Sihnon_Exception_NotImplemented();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isAdministrator() {
|
||||||
|
return $this->hasPermission('wheel');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasPermission($permission) {
|
||||||
|
return in_array($permission, $this->permissions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function permissions() {
|
||||||
|
if ($this->groups === null) {
|
||||||
|
$ldap_username = Sihnon_Auth_Plugin_LDAP::ldapEscape($this->username);
|
||||||
|
|
||||||
|
$filter = "(&(objectClass=posixGroup)(memberUid={$ldap_username}))";
|
||||||
|
|
||||||
|
$search = null;
|
||||||
|
if (static::$recursive_search) {
|
||||||
|
$search = ldap_search(static::$ldap, static::$group_base_dn, $filter, array('cn'), 0);
|
||||||
|
} else {
|
||||||
|
$search = ldap_list(static::$ldap, static::$group_base_dn, $filter, array('cn'), 0);
|
||||||
|
}
|
||||||
|
$result = ldap_get_entries(static::$ldap, $search);
|
||||||
|
|
||||||
|
$this->groups = array();
|
||||||
|
for ($i = 0, $l = $result['count']; $i < $l; ++$i) {
|
||||||
|
$this->groups[] = $result[$i]['cn'][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($name) {
|
||||||
|
switch ($name) {
|
||||||
|
case 'username': {
|
||||||
|
return $this->username;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'fullname': {
|
||||||
|
return $this->fullname;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
throw new Sihnon_Exception_InvalidProperty($name);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __set($name, $value) {
|
||||||
|
throw new Sihnon_Exception_NotImplemented();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -52,4 +52,9 @@ class SihnonFramework_Exception_DaemonException extends SihnonFramework_E
|
|||||||
class SihnonFramework_Exception_AlreadyRunning extends SihnonFramework_Exception_DaemonException {};
|
class SihnonFramework_Exception_AlreadyRunning extends SihnonFramework_Exception_DaemonException {};
|
||||||
class SihnonFramework_Exception_LockingFailed extends SihnonFramework_Exception_DaemonException {};
|
class SihnonFramework_Exception_LockingFailed extends SihnonFramework_Exception_DaemonException {};
|
||||||
|
|
||||||
|
class SihnonFramework_Exception_LDAPException extends SihnonFramework_Exception {};
|
||||||
|
class SihnonFramework_Exception_LDAPConnectionFailed extends SihnonFramework_Exception_LDAPException {};
|
||||||
|
class SihnonFramework_Exception_LDAPSecureConnectionFailed extends SihnonFramework_Exception_LDAPException {};
|
||||||
|
class SihnonFramework_Exception_LDAPBindFailed extends SihnonFramework_Exception_LDAPException {};
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
Reference in New Issue
Block a user