diff --git a/lib/Kolab/FreeBusy/DirectoryLDAP.php b/lib/Kolab/FreeBusy/DirectoryLDAP.php index e3704fa..9e6366a 100644 --- a/lib/Kolab/FreeBusy/DirectoryLDAP.php +++ b/lib/Kolab/FreeBusy/DirectoryLDAP.php @@ -1,168 +1,168 @@ * * Copyright (C) 2013, Kolab Systems AG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ namespace Kolab\FreeBusy; // PEAR modules operate in global namespace use \Net_LDAP3; use \Kolab\Config; use \Monolog\Logger as Monolog; /** * Implementation of an address lookup using an LDAP directory */ class DirectoryLDAP extends Directory { private $ldap; private $logger; private $ready = false; /** * Default constructor loading directory configuration */ public function __construct($config) { $this->config = $config; $host = parse_url($config['host']); $ldap_config = array( - 'hosts' => array($host['host']), + 'hosts' => array($config['host']), 'port' => $host['port'] ?: 389, - 'use_tls' => $host['scheme'] == 'tls' || $host['scheme'] == 'ldaps', + 'use_tls' => $host['scheme'] == 'tls', 'root_dn' => $config['root_dn'] ?: $config['base_dn'], 'log_hook' => array($this, 'log'), ) + $config; // instantiate Net_LDAP3 and connect with logger $this->logger = Logger::get('ldap', intval($config['loglevel'])); $this->ldap = new Net_LDAP3($ldap_config); // connect + bind to LDAP server if ($this->ldap->connect()) { $this->ready = $this->ldap->bind($config['bind_dn'], $config['bind_pw']); } if ($this->ready) { $this->logger->addInfo("Connected to $config[host] with '$config[bind_dn]'"); } else { $this->logger->addWarning("Connectiion to $config[host] with '$config[bind_dn]' failed!"); } } /** * Callback for Net_LDAP3 logging */ public function log($level, $msg) { // map PHP log levels to Monolog levels static $loglevels = array( LOG_DEBUG => Monolog::DEBUG, LOG_NOTICE => Monolog::NOTICE, LOG_INFO => Monolog::INFO, LOG_WARNING => Monolog::WARNING, LOG_ERR => Monolog::ERROR, LOG_CRIT => Monolog::CRITICAL, LOG_ALERT => Monolog::ALERT, LOG_EMERG => Monolog::EMERGENCY, ); $msg = is_array($msg) ? join('; ', $msg) : strval($msg); $this->logger->addRecord($loglevels[$level], $msg); } /** * @see Directory::resolve() */ public function resolve($user) { $result = array('s' => $user); if ($this->ready) { // extract domain name list($u, $d) = explode('@', $user); if (empty($d)) $d = $this->config['primary_domain']; // resolve domain root dn if (!empty($this->config['domain_filter'])) { $dc = $this->ldap->domain_root_dn($d); } else { $dc = 'dc=' . str_replace('.', ',dc=', $d); } // search with configured base_dn and filter $replaces = array('%dc' => $dc, '%u' => $u); $base_dn = strtr($this->config['base_dn'], $replaces); $filter = str_replace('%s', Net_LDAP3::quote_string($user), strtr($this->config['filter'], $replaces)); $ldapresult = $this->ldap->search($base_dn, $filter, 'sub', Config::convert($this->config['attributes'], Config::ARR)); // got a valid result if ($ldapresult && $ldapresult->count()) { $ldapresult->rewind(); $entry = Net_LDAP3::normalize_entry($ldapresult->current()); // get the first entry $this->logger->addInfo("Found " . $ldapresult->count() . " entries for $filter", $entry); // convert entry attributes to strings and add them to the final result hash array $result += self::_compact_entry($entry); // resolve DN attribute into the actual record if (!empty($this->config['resolve_dn']) && array_key_exists($this->config['resolve_dn'], $result)) { $k = $this->config['resolve_dn']; $member_attr = $this->config['resolve_attribute'] ?: 'mail'; foreach ((array)$result[$k] as $i => $member_dn) { if ($member_rec = $this->ldap->get_entry($member_dn, array($member_attr))) { $member_rec = self::_compact_entry(Net_LDAP3::normalize_entry($member_rec)); $result[$k][$i] = $member_rec[$member_attr]; } } } return $result; } $this->logger->addInfo("No entry found for $filter"); } return false; } /** * Helper method to convert entry attributes to simple values */ private static function _compact_entry($entry) { $result = array(); foreach ($entry as $k => $v) { if (is_array($v) && count($v) > 1) { $result[$k] = array_map('strval', $v); } else if (!empty($v)) { $result[$k] = strval(is_array($v) ? $v[0] : $v); } } return $result; } } diff --git a/lib/Kolab/FreeBusy/HTTPAuth.php b/lib/Kolab/FreeBusy/HTTPAuth.php index 4be5be4..368aa72 100644 --- a/lib/Kolab/FreeBusy/HTTPAuth.php +++ b/lib/Kolab/FreeBusy/HTTPAuth.php @@ -1,141 +1,141 @@ * * Copyright (C) 2013, Kolab Systems AG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ namespace Kolab\FreeBusy; use \Net_LDAP3; use \Monolog\Logger as Monolog; /** * Static class to process HTTP authentication to this service */ class HTTPAuth { private static $logger; /** * Validate HTTP basic auth against the configured backend */ public static function check($config) { $logger = Logger::get('httpauth'); // no http auth submitted, abort! if (empty($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) { $logger->addDebug('No HTTP auth submitted'); return false; } switch ($config['type']) { case 'static': return self::checkStatic($config, $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); case 'ldap': return self::checkLDAP($config, $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); default: $logger->addWarning('Unsupported auth type ' . $config['type']); break; } return false; } /** * Validate static user credentials from config */ private static function checkStatic($config, $user, $pass) { $valid = $user == $config['username'] && $pass == $config['password']; Logger::get('httpauth')->addInfo("Static: authenticating user '$user': " . ($valid ? 'SUCCESS' : 'FAILURE')); return $valid; } /** * Validate user credentials against the configured LDAP backend */ private static function checkLDAP($config, $user, $pass) { self::$logger = Logger::get('httpauth', intval($config['loglevel'])); list($u, $d) = explode('@', $user); $replaces = array('%dc' => 'dc=' . str_replace('.', ',dc=', $d), '%u' => $u); $config['base_dn'] = strtr($config['base_dn'], $replaces); $config['filter'] = strtr($config['filter'], $replaces); $host = parse_url($config['host']); $ldap_config = array( - 'hosts' => array($host['host']), + 'hosts' => array($config['host']), 'port' => $host['port'] ?: 389, - 'use_tls' => $host['scheme'] == 'tls' || $host['scheme'] == 'ldaps', + 'use_tls' => $host['scheme'] == 'tls', 'root_dn' => $config['base_dn'], 'filter' => $config['filter'], 'service_bind_dn' => $config['bind_dn'], 'service_bind_pw' => $config['bind_pw'], 'log_hook' => 'Kolab\FreeBusy\HTTPAuth::ldapLog', ); // instantiate Net_LDAP3 and connect with logger $ldap = new Net_LDAP3($ldap_config); // connect + bind to LDAP server if ($ldap->connect()) { self::$logger->addDebug("LDAP: connected to $config[host] with '$config[bind_dn]'"); // extract domain part from base_dn $dn_domain = ldap_explode_dn($config['base_dn'], 1); unset($dn_domain['count']); $domain = join('.', $dn_domain); $valid = (bool)$ldap->login($user, $pass, $domain); } else { self::$logger->addWarning("LDAP: connectiion to $config[host] with '$config[bind_dn]' failed!"); } self::$logger->addInfo("LDAP: authenticating user '$user': " . ($valid ? 'SUCCESS' : 'FAILURE')); return $valid; } /** * Callback for Net_LDAP3 logging */ public static function ldapLog($level, $msg) { // map PHP log levels to Monolog levels static $loglevels = array( LOG_DEBUG => Monolog::DEBUG, LOG_NOTICE => Monolog::NOTICE, LOG_INFO => Monolog::INFO, LOG_WARNING => Monolog::WARNING, LOG_ERR => Monolog::ERROR, LOG_CRIT => Monolog::CRITICAL, LOG_ALERT => Monolog::ALERT, LOG_EMERG => Monolog::EMERGENCY, ); $msg = is_array($msg) ? join('; ', $msg) : strval($msg); self::$logger->addRecord($loglevels[$level], $msg); } } \ No newline at end of file