Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
47 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/Auth.php b/lib/Auth.php
index ae7c206..dbb07bd 100644
--- a/lib/Auth.php
+++ b/lib/Auth.php
@@ -1,240 +1,240 @@
<?php
class Auth {
static private $instance = array();
private $_auth = array();
private $conf;
private $domains = array();
/**
* Return an instance of Auth, associated with $domain.
*
* If $domain is not specified, the 'kolab' 'primary_domain' is used.
*/
static function get_instance($domain = NULL)
{
$conf = Conf::get_instance();
if ($domain === NULL) {
$domain = $conf->get('primary_domain');
}
if (!isset(self::$instance[$domain])) {
self::$instance[$domain] = new Auth($domain);
}
return self::$instance[$domain];
}
public function __construct($domain = NULL)
{
if (!$this->conf) {
$this->conf = Conf::get_instance();
}
if ($domain === NULL) {
$domain = $conf->get('primary_domain');
}
$this->conf = Conf::get_instance();
$this->domain = $domain;
$this->connect($domain);
}
/**
* Authenticate $username with $password.
*
* The following forms for a username exist:
*
* - "cn=Directory Manager"
*
* This is considered a DN, as it succeeds to parse as such. The
* very name of this user may have already caused you to suspect
* that the user is not associated with one domain per-se. It is
* our intention this user does therefor not have a
* $_SESSION['user']->domain, but instead a
* $_SESSION['user']->working_domain. In any case, obtain the
* current domain for any user through
* $_SESSION['user']->get_domain().
*
* NOTE/TODO: For now, even cn=Directory Manager is set to the
* default domain. I wish there was more time...
*
* - "user@domain.tld"
*
* While it may seem obvious, this user is to be authenticated
* against the 'domain.tld' realm.
*
* - "user"
*
* This user is to be authenticated against the 'kolab'
* 'primary_domain'.
*/
public function authenticate($username, $password)
{
// TODO: Log authentication request.
// error_log("Authentication request for $username");
if (strpos($username, '@')) {
// Case-sensitivity does not matter for strstr() on '@', which
// has no case.
$user_domain = strstr($username, '@');
if (isset($this->_auth[$user_domain])) {
// We know this domain
$domain = $user_domain;
}
else {
// Attempt to find the primary domain name space for the
// domain used in the authentication request.
//
// This will enable john@example.org to login using 'alias'
// domains as well, such as 'john@example.ch'.
$associated_domain = $this->primary_for_valid_domain($user_domain);
if ($associated_domain) {
$domain = $user_domain;
}
else {
// It seems we do not know about this domain.
$domain = FALSE;
}
}
}
else {
$domain = $this->conf->get('primary_domain');
}
// TODO: Debug logging for the use of a current or the creation of
// a new authentication class instance.
if ($this->domain == $domain) {
$result = $this->_auth[$domain]->authenticate($username, $password);
}
else {
$result = Auth::get_instance($domain)->authenticate($username, $password);
}
return $result;
}
public function connect($domain = NULL)
{
if ($domain === NULL) {
$domain = $this->conf->get('primary_domain');
}
$auth_method = strtoupper($this->conf->get($domain, 'auth_mechanism'));
if (!$auth_method) {
// Use the default authentication technology
$auth_method = strtoupper($this->conf->get('kolab', 'auth_mechanism'));
}
if (!isset($this->_auth[$domain])) {
require_once 'Auth/' . $auth_method . '.php';
$this->_auth[$domain] = new $auth_method($domain);
}
}
public function find_user_groups($member_dn)
{
return $this->_auth[$_SESSION['user']->get_domain()]->find_user_groups($member_dn);
}
public function group_info($groupdata)
{
return $this->normalize_result($this->_auth[$_SESSION['user']->get_domain()]->group_info($groupdata));
}
public function group_members_list($groupdata)
{
return $this->_auth[$_SESSION['user']->get_domain()]->group_members_list($groupdata);
}
public function list_domains()
{
// TODO: Consider a normal user does not have privileges on
// the base_dn where domain names and configuration is stored.
$this->connect();
return $this->_auth[$this->domain]->list_domains();
}
public function list_users($domain = NULL, $attributes = array(), $search = array(), $params = array())
{
$this->connect($domain);
if ($domain === NULL) {
$domain = $this->conf->get('primary_domain');
}
$users = $this->_auth[$domain]->list_users($attributes, $search, $params);
return $users;
}
- public function list_groups($domain = NULL)
+ public function list_groups($domain = NULL, $attributes = array())
{
$this->connect($domain);
if ($domain === NULL) {
$domain = $this->conf->get('primary_domain');
}
- $groups = $this->_auth[$domain]->list_groups();
+ $groups = $this->_auth[$domain]->list_groups($attributes);
return $groups;
}
public function normalize_result($results)
{
return LDAP::normalize_result($results);
}
public function primary_for_valid_domain($domain)
{
$this->domains = $this->list_domains();
if (array_key_exists($domain, $this->domains)) {
return $domain;
}
else if (in_array($domain, $this->domains)) {
// We know it's not a key!
foreach ($this->domains as $parent_domain => $child_domains) {
if (in_array($domain, $child_domains)) {
return $parent_domain;
}
}
return FALSE;
}
else {
return FALSE;
}
}
public function search($attributes)
{
return $this->_auth[$_SESSION['user']->get_domain()]->search();
}
public function user_add($attributes, $type=NULL)
{
return $this->_auth[$_SESSION['user']->get_domain()]->user_add($attributes, $type);
}
public function user_delete($userdata)
{
return $this->_auth[$_SESSION['user']->get_domain()]->user_delete($userdata);
}
public function user_find_by_attribute($attribute)
{
return $this->_auth[$_SESSION['user']->get_domain()]->user_find_by_attribute($attribute);
}
public function user_info($userdata)
{
return $this->normalize_result($this->_auth[$_SESSION['user']->get_domain()]->user_info($userdata));
}
}
diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php
index 20805b8..9cc78b3 100644
--- a/lib/Auth/LDAP.php
+++ b/lib/Auth/LDAP.php
@@ -1,1117 +1,1122 @@
<?php
//
// Kolab LDAP handling abstraction class.
//
class LDAP
{
public $_name = "LDAP";
// Needs to be protected and not just private
protected $_connection = NULL;
protected $user_bind_dn;
protected $user_bind_pw;
// This is the default and should actually be set through Conf.
private $_ldap_uri = 'ldap://localhost:389/';
private $conf;
public function __construct($domain = NULL)
{
$this->conf = Conf::get_instance();
$this->domain = $domain ? $domain : $this->conf->get('primary_domain');
$this->_ldap_uri = $this->conf->get('uri');
$this->_ldap_server = parse_url($this->_ldap_uri, PHP_URL_HOST);
$this->_ldap_port = parse_url($this->_ldap_uri, PHP_URL_PORT);
$this->_ldap_scheme = parse_url($this->_ldap_uri, PHP_URL_SCHEME);
// Catch cases in which the ldap server port has not been explicitely defined
if (!$this->_ldap_port) {
if ($this->_ldap_scheme == "ldaps") {
$this->_ldap_port = 636;
}
else {
$this->_ldap_port = 389;
}
}
// We can also use the parse_url() to pass on the bind dn and pw:
//
// $ldap = new LDAP('ldap://uid=svc-kwap,ou=Services,ou=Accounts,dc=kanarip,dc=com:VerySecret@localhost/');
// and the following line uncommented:
//
// echo "<pre>"; print_r(parse_url($ldap_uri)); echo "</pre>";
//
// creates:
//
// array
// (
// [scheme] => ldap
// [host] => localhost
// [user] => uid=svc-kwap,ou=Services,ou=Accounts,dc=kanarip,dc=com
// [pass] => VerySecret
// [path] => /
// )
}
/*
Public functions
*/
public function add($dn, $attributes)
{
return $this->_add($dn, $attributes);
}
public function authenticate($username, $password)
{
error_log("LDAP authentication request for $username");
$this->_connect();
// Attempt to explode the username to see if it is in fact a DN,
// such as would be the case for 'cn=Directory Manager' or
// 'uid=admin'.
$is_dn = ldap_explode_dn($username, 1);
if (!$is_dn) {
error_log("Username is not a DN");
list($this->userid, $this->domain) = $this->_qualify_id($username);
$root_dn = $this->domain_root_dn($this->domain);
$user_dn = $this->_get_user_dn($root_dn, '(mail=' . $username . ')');
error_log("Found user DN: $user_dn for user: $username");
}
else {
$user_dn = $username;
$root_dn = "";
}
if (($bind_ok = $this->_bind($user_dn, $password)) == TRUE) {
$this->_unbind();
if (isset($_SESSION['user'])) {
$_SESSION['user']->user_root_dn = $root_dn;
$_SESSION['user']->user_bind_dn = $user_dn;
$_SESSION['user']->user_bind_pw = $password;
error_log("Successfully bound with User DN: " . $_SESSION['user']->user_bind_dn);
}
else {
error_log("Successfully bound with User DN: " . $user_dn . " but not saving it to the session");
}
return TRUE;
}
else {
error_log("LDAP Error: " . $this->_errstr());
return FALSE;
}
}
public function bind($bind_dn, $bind_pw)
{
// Apply some routines for access control to this function here.
return $this->_bind($bind_dn, $bind_pw);
}
public function connect()
{
// Apply some routines for access control to this function here.
return $this->_connect();
}
public function delete($dn)
{
return $this->_delete($dn);
}
public function domain_add($domain, $domain_alias = FALSE, $prepopulate = TRUE)
{
// Apply some routines for access control to this function here.
if ($domain_alias) {
return $this->_domain_add_alias($domain, $domain_alias);
}
else {
return $this->_domain_add_new($domain, $prepopulate);
}
}
public function domain_exists($domain)
{
return $this->_ldap->domain_exists($domain);
}
public function domain_list($rev_sort = FALSE)
{
return $this->_ldap->domain_list($rev_sort);
}
/*
Translate a domain name into it's corresponding root dn.
*/
public function domain_root_dn($domain = '')
{
$conf = Conf::get_instance();
if ($domain == '') {
return FALSE;
}
error_log("Searching for domain $domain");
$this->_connect();
error_log("From domain to root dn");
if (($this->_bind($conf->get('ldap', 'bind_dn'), $conf->get('ldap', 'bind_pw'))) == FALSE) {
error_log("WARNING: Invalid Service bind credentials supplied");
$this->_bind($conf->manager_bind_dn, $conf->manager_bind_pw);
}
if (($results = ldap_search($this->_connection, $conf->get('domain_base_dn'), '(associatedDomain=' . $domain . ')')) == FALSE) {
error_log("No results?");
return FALSE;
}
$domain = ldap_first_entry($this->_connection, $results);
$domain_info = ldap_get_attributes($this->_connection, $domain);
// echo "<pre>"; print_r($domain_info); echo "</pre>";
if (isset($domain_info['inetDomainBaseDN'][0])) {
$domain_rootdn = $domain_info['inetDomainBaseDN'][0];
}
else {
$domain_rootdn = $this->_standard_root_dn($domain_info['associatedDomain']);
}
$this->_unbind();
error_log("Using $domain_rootdn");
return $domain_rootdn;
}
public function domains_list()
{
$section = $this->conf->get('kolab', 'auth_mechanism');
$base_dn = $this->conf->get($section, 'domain_base_dn');
$filter = $this->conf->get($section, 'kolab_domain_filter');
return $this->search($base_dn, $filter);
}
public function find_user_groups($member_dn)
{
error_log(__FILE__ . "(" . __LINE__ . "): " . $member_dn);
$groups = array();
$root_dn = $this->domain_root_dn($this->domain);
$entries = $this->search($root_dn, "(|" .
"(&(objectclass=groupofnames)(member=$member_dn))" .
"(&(objectclass=groupofuniquenames)(uniquemember=$member_dn))" .
")");
$entries = $this->normalize_result($entries);
foreach ($entries as $entry_dn => $entry_attributes) {
$groups[] = $entry_dn;
}
return $groups;
}
public function group_info($group)
{
$is_dn = ldap_explode_dn($group, 1);
if (!$is_dn) {
$root_dn = $this->domain_root_dn($this->domain);
$group_dn = $this->_get_group_dn($root_dn, '(mail=' . $group . ')');
}
else {
$group_dn = $user;
}
if (!$group_dn) {
return FALSE;
}
return $this->search($group_dn);
}
public function group_members_list($group)
{
$is_dn = ldap_explode_dn($group, 1);
if (!$is_dn) {
$root_dn = $this->domain_root_dn($this->domain);
$group_dn = $this->_get_group_dn($root_dn, '(mail=' . $group . ')');
}
else {
$group_dn = $user;
}
if (!$group_dn) {
return FALSE;
}
return $this->_list_group_members($group_dn);
}
- public function groups_list()
+ public function groups_list($attributes = array())
{
- $filter = "(|"
+ if (empty($attributes)) {
+ $attributes = array('*');
+ }
+
+ $base_dn = "ou=Groups,dc=klab,dc=cc";
+ $filter = "(|"
."(objectClass=kolabgroupofnames)"
."(objectclass=kolabgroupofuniquenames)"
."(objectclass=kolabgroupofurls)"
.")";
- return $this->search("ou=Groups,dc=klab,dc=cc", $filter, array("cn"));
+ return $this->search($base_dn, $filter, $attributes);
}
public function llist($base_dn, $filter)
{
return $this->_list($base_dn, $filter);
}
public function list_domains()
{
$domains = $this->domains_list();
$domains = $this->normalize_result($domains);
return $domains;
}
- public function list_groups()
+ public function list_groups($attributes = array())
{
- $groups = $this->groups_list();
+ $groups = $this->groups_list($attributes);
$groups = $this->normalize_result($groups);
return $groups;
}
public function list_users($attributes = array(), $search = array(), $params = array())
{
if (!empty($params['sort_by'])) {
if (!in_array($params['sort_by'], $attributes)) {
$attributes[] = $params['sort_by'];
}
}
$users = $this->users_list($attributes, $search);
$users = $this->normalize_result($users);
if (!empty($params['sort_by'])) {
$this->sort_result_key = $params['sort_by'];
uasort($users, array($this, 'sort_result'));
if ($params['sort_order'] == 'DESC') {
$users = array_reverse($users, true);
}
}
return $users;
}
static function normalize_result($__result)
{
$conf = Conf::get_instance();
$result = array();
for ($x = 0; $x < $__result["count"]; $x++) {
$dn = $__result[$x]['dn'];
$result[$dn] = array();
for ($y = 0; $y < $__result[$x]["count"]; $y++) {
$attr = $__result[$x][$y];
if ($__result[$x][$attr]["count"] == 1) {
$result[$dn][$attr] = $__result[$x][$attr][0];
}
else {
$result[$dn][$attr] = array();
for ($z = 0; $z < $__result[$x][$attr]["count"]; $z++) {
if ($z == 0 && $attr == $conf->get($conf->get('kolab', 'auth_mechanism'), 'domain_name_attribute')) {
$result[$dn]['primary_domain'] = $__result[$x][$attr][$z];
}
$result[$dn][$attr][] = $__result[$x][$attr][$z];
}
}
}
}
return $result;
}
/**
* Result sorting callback for uasort()
*/
public function sort_result($a, $b)
{
$str1 = $a[$this->sort_result_key];
$str2 = $b[$this->sort_result_key];
return strcmp(mb_strtoupper($str1), mb_strtoupper($str2));
}
public function user_add($attrs, $type = NULL) {
if ($type == NULL) {
$type_str = 'user';
}
else {
$db = SQL::get_instance();
$_key = mysql_fetch_assoc($db->query("SELECT key FROM user_types WHERE id = ?", $type));
$type_str = $_key['key'];
}
$base_dn = $this->conf->get($this->domain, $type_str . "_user_base_dn");
if (!$base_dn) {
$base_dn = $this->conf->get('ldap', $type_str . "_user_base_dn");
}
// TODO: The rdn is configurable as well
$dn = "uid=" . $attrs['uid'] . "," . $base_dn;
return $this->add($dn, $attrs);
}
public function user_delete($user)
{
$is_dn = ldap_explode_dn($user, 1);
if (!$is_dn) {
list($this->userid, $this->domain) = $this->_qualify_id($user);
$root_dn = $this->domain_root_dn($this->domain);
$user_dn = $this->_get_user_dn($root_dn, '(mail=' . $user . ')');
}
else {
$user_dn = $user;
}
if (!$user_dn) {
return FALSE;
}
return $this->delete($user_dn);
}
public function user_find_by_attribute($attribute)
{
if (!is_array($attribute) || count($attribute) > 1) {
return FALSE;
}
$filter = "(&";
foreach ($attribute as $key => $value) {
$filter .= "(" . $key . "=" . $value . ")";
}
$filter .= ")";
$base_dn = $this->domain_root_dn($this->domain);
$result = $this->normalize_result($this->search($base_dn, $filter, array_keys($attribute)));
if (count($result) > 0) {
error_log("Results found: " . implode(', ', array_keys($result)));
return $result;
}
else {
error_log("No result");
return FALSE;
}
}
public function user_info($user)
{
$is_dn = ldap_explode_dn($user, 1);
if (!$is_dn) {
list($this->userid, $this->domain) = $this->_qualify_id($user);
$root_dn = $this->domain_root_dn($this->domain);
$user_dn = $this->_get_user_dn($root_dn, '(mail=' . $user . ')');
}
else {
$user_dn = $user;
}
if (!$user_dn) {
return FALSE;
}
return $this->search($user_dn);
}
public function users_list($attributes = array(), $search = array(), $params = array())
{
$base_dn = "ou=People,dc=klab,dc=cc";
$filter = "(objectClass=kolabinetorgperson)";
if (empty($attributes) || !is_array($attributes)) {
$attributes = array('*');
}
if (!empty($search) && is_array($search) && !empty($search['params'])) {
$s_filter = '';
foreach ((array) $search['params'] as $field => $param) {
$value = self::_quote_string($param['value']);
switch ((string)$param['type']) {
case 'prefix':
$prefix = '';
$suffix = '*';
break;
case 'suffix':
$prefix = '*';
$suffix = '';
break;
case 'exact':
$prefix = '';
$suffix = '';
break;
case 'both':
default:
$prefix = '*';
$suffix = '*';
break;
}
$s_filter .= "($field=$prefix" . $value . "$suffix)";
}
// join search parameters with specified operator ('OR' or 'AND')
if (count($search['params']) > 1) {
$s_filter = '(' . ($search['operator'] == 'AND' ? '&' : '|') . $s_filter . ')';
}
// join search filter with objectClass filter
$filter = '(&' . $filter . $s_filter . ')';
}
return $this->search($base_dn, $filter, $attributes);
}
public function search($base_dn, $search_filter = '(objectClass=*)', $attributes = array('*'))
{
error_log("Searching $base_dn with filter '$search_filter'");
return $this->_search($base_dn, $search_filter, $attributes);
}
public function setup()
{
return $this->_ldap->setup();
}
/*
Qualify a username.
Where username is 'kanarip@kanarip.com', the function will return an
array containing 'kanarip' and 'kanarip.com'. However, where the
username is 'kanarip', the domain name is to be assumed the
management domain name.
*/
public function _qualify_id($username)
{
$conf = Conf::get_instance();
$username_parts = explode('@', $username);
if (count($username_parts) == 1) {
$domain_name = $conf->get('primary_domain');
}
else {
$domain_name = array_pop($username_parts);
}
return array(implode('@', $username_parts), $domain_name);
}
/*
Deprecated, use domain_root_dn()
*/
public function user_type_attribute_filter($type = FALSE)
{
global $conf;
// If the user type does not exist, issue warning and continue with
// the "All attributes" array.
if (!isset($conf->user_types[$type])) {
return array('*');
}
$attributes_filter = array();
foreach ($conf->user_types[$type]['attributes'] as $key => $value) {
$attributes_filter[] = is_array($value) ? $key : $value;
}
echo "<li>"; print_r($attributes_filter);
return $attributes_filter;
}
public function user_type_search_filter($type = FALSE)
{
global $conf;
// TODO: If the user type has not been specified we should actually
// iterate and mix and match:
//
// (|(&(type1))(&(type2)))
// If the user type does not exist, issue warning and continue with
// the "All" search filter.
if (!isset($conf->user_types[$type])) {
return "(objectClass=*)";
}
$search_filter = "(&";
// We want from user_types[$type]['attributes']['objectClasses']
foreach ($conf->user_types[$type]['attributes']['objectClass'] as $key => $value) {
$search_filter .= "(objectClass=" . $value . ")";
}
$search_filter .= ")";
print "<li>" . $search_filter;
return $search_filter;
}
/*
Private functions
*/
private function _domain_add_alias($domain, $domain_alias)
{
$this->_ldap->_domain_add_alias($domain, $domain_alias);
}
private function _domain_add_new($domain, $populatedomain)
{
$this->connect();
$this->_ldap->_domain_add_new($domain, $populatedomain);
}
/*
Shortcut functions
*/
/*
Shortcut to ldap_add()
*/
private function _add($entry_dn, $attributes)
{
$this->_connect();
$this->bind($_SESSION['user']->user_bind_dn, $_SESSION['user']->user_bind_pw);
if (($add_result = ldap_add($this->_connection, $entry_dn, $attributes)) == FALSE) {
// Issue warning
return FALSE;
}
return TRUE;
}
/**
* Shortcut to ldap_bind()
*/
private function _bind($dn, $pw)
{
$this->_connect();
// TODO: Debug logging
error_log("->_bind() Binding with $dn");
if (!$dn || !$pw) {
return FALSE;
}
if (($bind_ok = ldap_bind($this->_connection, $dn, $pw)) == FALSE) {
error_log("LDAP Error: " . $this->_errstr());
// Issue error message
return FALSE;
}
else {
return TRUE;
}
}
/**
* Shortcut to ldap_connect()
*/
private function _connect()
{
if ($this->_connection == FALSE) {
// TODO: Debug logging
error_log("Connecting to " . $this->_ldap_server . " on port " . $this->_ldap_port);
$connection = ldap_connect($this->_ldap_server, $this->_ldap_port);
if ($connection == FALSE) {
$this->_connection = FALSE;
// TODO: Debug logging
error_log("Not connected: " . ldap_err2str() . "(no.) " . ldap_errno());
}
else {
$this->_connection = $connection;
}
// TODO: Debug logging
error_log("Connected!");
}
else {
error_log("Already connected");
}
}
/**
* Shortcut to ldap_delete()
*/
private function _delete($entry_dn)
{
$this->_connect();
$this->bind($_SESSION['user']->user_bind_dn, $_SESSION['user']->user_bind_pw);
if (($delete_result = ldap_delete($this->_connection, $entry_dn)) == FALSE) {
// Issue warning
return FALSE;
}
else {
return TRUE;
}
}
/**
* Shortcut to ldap_disconnect()
*/
private function _disconnect()
{
if ($this->_connection == FALSE) {
return TRUE;
}
if (($result = ldap_close($this->_connection)) == TRUE) {
$this->_connection = FALSE;
return TRUE;
}
// Issue a warning
$this->_connection = FALSE;
$this->_ldap = FALSE;
return FALSE;
}
/**
* Shortcut to ldap_err2str() over ldap_errno()
*/
private function _errstr()
{
if ($errno = @ldap_errno($this->_connection)) {
if ($err2str = @ldap_err2str($errno)) {
return $err2str;
}
}
// Issue warning
return NULL;
}
/**
* Shortcut to ldap_get_entries() over ldap_list()
*
* Takes a $base_dn and $filter like ldap_list(), and returns an
* array obtained through ldap_get_entries().
*/
private function _list($base_dn, $filter)
{
$ldap_entries = array( "count" => 0 );
if (($ldap_list = @ldap_list($this->_connection, $base_dn, $filter)) == FALSE) {
//message("LDAP Error: Could not search " . $base_dn . ": " . $this->_errstr() );
}
else {
if (($ldap_entries = @ldap_get_entries($this->_connection, $ldap_list)) == FALSE) {
//message("LDAP Error: No entries for " . $filter . " in " . $base_dn . ": " . $this->_errstr());
}
}
return $ldap_entries;
}
/**
* Shortcut to ldap_search()
*/
private function _search($base_dn, $search_filter = '(objectClass=*)', $attributes = array('*'))
{
error_log("Searching with user " . $_SESSION['user']->user_bind_dn);
$this->_bind($_SESSION['user']->user_bind_dn, $_SESSION['user']->user_bind_pw);
if (($search_results = @ldap_search($this->_connection, $base_dn, $search_filter, $attributes)) == FALSE) {
#message("Could not search in " . __METHOD__ . " in " . __FILE__ . " on line " . __LINE__ . ": " . $this->_errstr());
return FALSE;
}
if (($entries = ldap_get_entries($this->_connection, $search_results)) == FALSE) {
#message("Could not get the results of the search: " . $this->_errstr());
return FALSE;
}
return $entries;
}
/**
* Shortcut to ldap_unbind()
*/
private function _unbind($yes = FALSE, $really = FALSE)
{
if ($yes && $really) {
ldap_unbind($this->_connection);
$this->_connection = FALSE;
}
else {
// What?
//
// - attempt bind as anonymous
// - in case of fail, bind as user
}
return TRUE;
}
/*
Utility functions
*/
/**
* Probe the root dn with the user credentials.
*
* When a list of domains is retrieved, this does not mean the user
* actually has access. Given the root dn for each domain however, we
* can in fact attempt to list / search the root dn and see if we get
* any results. If we don't, maybe this user is not authorized for the
* domain at all?
*/
private function _probe_root_dn($entry_root_dn)
{
error_log("Running for entry root dn: " . $entry_root_dn);
if (($tmp_connection = ldap_connect($this->_ldap_server)) == FALSE) {
//message("LDAP Error: " . $this->_errstr());
return FALSE;
}
error_log("User DN: " . $_SESSION['user']->user_bind_dn);
if (($bind_success = ldap_bind($tmp_connection, $_SESSION['user']->user_bind_dn, $_SESSION['user']->user_bind_pw)) == FALSE) {
//message("LDAP Error: " . $this->_errstr());
return FALSE;
}
if (($list_success = ldap_list($tmp_connection, $entry_root_dn, '(objectClass=*)', array('*', 'aci'))) == FALSE) {
#message("LDAP Error: " . $this->_errstr());
return FALSE;
}
# print_r(ldap_get_entries($tmp_connection, $list_success));
/*
if (ldap_count_entries($tmp_connection, $list_success) == 0) {
echo "<li>Listed things, but got no results";
return FALSE;
}
*/
return TRUE;
}
/**
* From a domain name, such as 'kanarip.com', create a standard root
* dn, such as 'dc=kanarip,dc=com'.
*
* As the parameter $associatedDomains, either pass it an array (such
* as may have been returned by ldap_get_entries() or perhaps
* ldap_list()), where the function will assume the first value
* ($array[0]) to be the uber-level domain name, or pass it a string
* such as 'kanarip.nl'.
*
* @return string
*/
private function _standard_root_dn($associatedDomains)
{
if (is_array($associatedDomains)) {
// Usually, the associatedDomain in position 0 is the naming attribute associatedDomain
if ($associatedDomains['count'] > 1) {
// Issue a debug message here
$relevant_associatedDomain = $associatedDomains[0];
}
else {
$relevant_associatedDomain = $associatedDomains[0];
}
}
else {
$relevant_associatedDomain = $associatedDomains;
}
return "dc=" . implode(',dc=', explode('.', $relevant_associatedDomain));
}
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
################################################################################
public function _get_group_dn($root_dn, $search_filter)
{
error_log("Searching for a group dn in $root_dn, with search filter: $search_filter");
$this->_connect();
if (($this->_bind($this->conf->get('bind_dn'), $this->conf->get('bind_pw'))) == FALSE) {
$this->_bind($this->conf->get('manager_bind_dn'), $this->conf->get('manager_bind_pw'));
}
$search_results = ldap_search($this->_connection, $root_dn, $search_filter);
if (ldap_count_entries($this->_connection, $search_results) == 0) {
return FALSE;
}
if (($first_entry = ldap_first_entry($this->_connection, $search_results)) == FALSE) {
return FALSE;
}
$group_dn = ldap_get_dn($this->_connection, $first_entry);
return $group_dn;
}
public function _get_user_dn($root_dn, $search_filter)
{
error_log("Searching for a user dn in $root_dn, with search filter: $search_filter");
$this->_connect();
if (($this->_bind($this->conf->get('bind_dn'), $this->conf->get('bind_pw'))) == FALSE) {
//message("WARNING: Invalid Service bind credentials supplied");
$this->_bind($this->conf->get('manager_bind_dn'), $this->conf->get('manager_bind_pw'));
}
$search_results = ldap_search($this->_connection, $root_dn, $search_filter);
if (ldap_count_entries($this->_connection, $search_results) == 0) {
//message("No entries found for the user dn in " . __METHOD__);
return FALSE;
}
if (($first_entry = ldap_first_entry($this->_connection, $search_results)) == FALSE) {
return FALSE;
}
$user_dn = ldap_get_dn($this->_connection, $first_entry);
return $user_dn;
}
public function _get_email_address()
{
return "kanarip@kanarip.com";
}
private function _list_group_members($dn, $entry = null)
{
$group_members = array();
if (is_array($entry) && in_array('objectclass', $entry)) {
if (!in_array(array('groupofnames', 'groupofuniquenames', 'groupofurls'), $entry['objectclass'])) {
error_log("Called _list_groups_members on a non-group!");
}
else {
error_log("Called list_group_members(" . $dn . ")");
}
}
$entries = $this->normalize_result($this->search($dn));
foreach ($entries as $entry_dn => $entry) {
if (!isset($entry['objectclass'])) {
continue;
}
foreach ( $entry['objectclass'] as $num => $objectclass) {
switch ($objectclass) {
case "groupofnames":
$group_members = array_merge($group_members, $this->_list_group_member($entry_dn, $entry));
break;
case "groupofuniquenames":
$group_members = array_merge($group_members, $this->_list_group_uniquemember($entry_dn, $entry));
break;
case "groupofurls":
$group_members = array_merge($group_members, $this->_list_group_memberurl($entry_dn, $entry));
break;
}
}
}
return array_filter($group_members);
}
private function _list_group_member($dn, $entry)
{
error_log("Called _list_group_member(" . $dn . ")");
// Use the member attributes to return an array of member ldap objects
// NOTE that the member attribute is supposed to contain a DN
$group_members = array();
for ($i = 0; $i < (count($entry['member'])-1); $i++) {
$result = @ldap_read($this->_connection, $entry['member'][$i], '(objectclass=*)');
$members = @ldap_get_entries($this->_connection, $result);
// Nested groups
$group_group_members = $this->list_group_members($entry['member'][$i]);
$group_members[] = array_filter(array_merge($group_group_members, $members));
}
return array_filter($group_members);
}
private function _list_group_uniquemember($dn, $entry)
{
error_log("Called _list_group_uniquemember(" . $dn . ")");
// Use the member attributes to return an array of member ldap objects
// NOTE that the member attribute is supposed to contain a DN
$group_members = array();
if (!isset($entry['uniquemember'])) {
return $group_members;
}
for ($i = 0; $i < (count($entry['uniquemember'])-1); $i++) {
$result = @ldap_read($this->_connection, $entry['uniquemember'][$i], '(objectclass=*)');
$members = @ldap_get_entries($this->_connection, $result);
// Nested groups
$group_group_members = $this->list_group_members($entry['uniquemember'][$i]);
$group_members[] = array_filter(array_merge($group_group_members, $members));
}
return $group_members;
}
private function _list_group_memberurl($dn, $entry)
{
error_log("Called _list_group_memberurl(" . $dn . ")");
// Use the member attributes to return an array of member ldap objects
// NOTE that the member attribute is supposed to contain a DN
$group_members = array();
if (is_array($entry['memberurl'])) {
foreach ($entry['memberurl'] as $url) {
$ldap_uri_components = $this->_parse_memberurl($url);
$entries = $this->normalize_result($this->search($ldap_uri_components[3], $ldap_uri_components[6]));
foreach ($entries as $entry_dn => $_entry) {
error_log("Found " . $entry_dn);
$group_group_members = $this->_list_group_members($entry_dn);
if ($group_group_members) {
$group_members = array_merge($group_members, $group_group_members);
}
else {
$group_members[] = $entry_dn;
}
}
}
}
else {
$ldap_uri_components = $this->_parse_memberurl($entry['memberurl']);
$entries = $this->normalize_result($this->search($ldap_uri_components[3], $ldap_uri_components[6]));
foreach ($entries as $entry_dn => $_entry) {
error_log("Found " . $entry_dn);
$group_group_members = $this->_list_group_members($entry_dn);
if ($group_group_members) {
$group_members = array_merge($group_members, $group_group_members);
}
else {
$group_members[] = $entry_dn;
}
}
}
return array_filter($group_members);
}
private function _parse_memberurl($url)
{
error_log("Parsing URL: " . $url);
preg_match('/(.*):\/\/(.*)\/(.*)\?(.*)\?(.*)\?(.*)/', $url, $matches);
return $matches;
}
/**
* Quotes attribute value string
*
* @param string $str Attribute value
* @param bool $dn True if the attribute is a DN
*
* @return string Quoted string
*/
private static function _quote_string($str, $dn=false)
{
// take firt entry if array given
if (is_array($str)) {
$str = reset($str);
}
if ($dn) {
$replace = array(
',' => '\2c',
'=' => '\3d',
'+' => '\2b',
'<' => '\3c',
'>' => '\3e',
';' => '\3b',
"\\"=> '\5c',
'"' => '\22',
'#' => '\23'
);
}
else {
$replace = array(
'*' => '\2a',
'(' => '\28',
')' => '\29',
"\\" => '\5c',
'/' => '\2f'
);
}
return strtr($str, $replace);
}
}
diff --git a/lib/api/kolab_groups_actions.php b/lib/api/kolab_groups_actions.php
index eab2a04..0b2478f 100644
--- a/lib/api/kolab_groups_actions.php
+++ b/lib/api/kolab_groups_actions.php
@@ -1,37 +1,55 @@
<?php
/**
*
*/
class kolab_groups_actions extends kolab_api_service
{
+ public $list_attribs = array(
+ 'cn',
+ 'gidnumber',
+ 'objectclass',
+ 'mail',
+ );
+
public function capabilities($domain)
{
return array(
'list' => 'r',
);
}
public function groups_list($get, $post)
{
$auth = Auth::get_instance();
+ // returned attributes
+ if (!empty($post['attributes']) && is_array($post['attributes'])) {
+ // get only supported attributes
+ $attributes = array_intersect($this->list_attribs, $post['attributes']);
+ // need to fix array keys
+ $attributes = array_values($attributes);
+ }
+ if (empty($attributes)) {
+ $attributes = (array)$this->list_attribs[0];
+ }
+
$groups = $auth->list_groups();
$count = count($groups);
// pagination
if (!empty($post['page_size']) && $count) {
$size = (int) $post['page_size'];
$page = !empty($post['page']) ? $post['page'] : 1;
$page = max(1, (int) $page);
$offset = ($page - 1) * $size;
$groups = array_slice($groups, $offset, $size, true);
}
return array(
'list' => $groups,
'count' => $count,
);
}
}
diff --git a/lib/api/kolab_users_actions.php b/lib/api/kolab_users_actions.php
index 87ae5ac..ceb58e7 100644
--- a/lib/api/kolab_users_actions.php
+++ b/lib/api/kolab_users_actions.php
@@ -1,96 +1,100 @@
<?php
/**
*
*/
class kolab_users_actions extends kolab_api_service
{
public $list_attribs = array(
'uid',
'cn',
'displayname',
'sn',
'givenname',
'mail',
+ 'objectclass',
+ 'uidnumber',
+ 'gidnumber',
+ 'mailhost',
);
public function capabilities($domain)
{
return array(
'list' => 'r',
);
}
public function users_list($get, $post)
{
$auth = Auth::get_instance();
// returned attributes
if (!empty($post['attributes']) && is_array($post['attributes'])) {
// get only supported attributes
$attributes = array_intersect($this->list_attribs, $post['attributes']);
// need to fix array keys
$attributes = array_values($attributes);
}
if (empty($attributes)) {
$attributes = (array)$this->list_attribs[0];
}
$search = array();
$params = array();
// searching
if (!empty($post['search']) && is_array($post['search'])) {
$params = $post['search'];
foreach ($params as $idx => $param) {
// get only supported attributes
if (!in_array($idx, $this->list_attribs)) {
unset($params[$idx]);
continue;
}
// search string
if (empty($param['value'])) {
unset($params[$idx]);
continue;
}
}
$search['params'] = $params;
if (!empty($post['search_operator'])) {
$search['operator'] = $post['search_operator'];
}
}
if (!empty($post['sort_by'])) {
// check if sort attribute is supported
if (in_array($post['sort_by'], $this->list_attribs)) {
$params['sort_by'] = $post['sort_by'];
}
}
if (!empty($post['sort_order'])) {
$params['sort_order'] = $post['sort_order'] == 'DESC' ? 'DESC' : 'ASC';
}
$users = $auth->list_users(null, $attributes, $search, $params);
$count = count($users);
// pagination
if (!empty($post['page_size']) && $count) {
$size = (int) $post['page_size'];
$page = !empty($post['page']) ? $post['page'] : 1;
$page = max(1, (int) $page);
$offset = ($page - 1) * $size;
$users = array_slice($users, $offset, $size, true);
}
return array(
'list' => $users,
'count' => $count,
);
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Apr 4, 3:32 AM (1 d, 22 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18820473
Default Alt Text
(47 KB)

Event Timeline