diff --git a/lib/Kolab/FreeBusy/HTTPAuth.php b/lib/Kolab/FreeBusy/HTTPAuth.php index 1cbbce3..f8073cc 100644 --- a/lib/Kolab/FreeBusy/HTTPAuth.php +++ b/lib/Kolab/FreeBusy/HTTPAuth.php @@ -1,186 +1,185 @@ * * 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 \Kolab\Config; 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'); // First try token authentication if enabled and user/token detected in the URL if (!empty($_SERVER['FREEBUSY_URI']) && Config::boolean($config['allow_token']) - && preg_match('|([^@/]+@[^@/]+)/([a-f0-9]{32})$|', $_SERVER['FREEBUSY_URI'], $matches) + && preg_match('|([^@/]+@[^@/]+)/([a-f0-9]{32})/|', $_SERVER['FREEBUSY_URI'], $matches) && self::checkToken($config, $matches[1], $matches[2]) ) { return true; } // 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($config['host']), 'port' => $host['port'] ?: 389, '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; } /** * Validate user token and credentials from freebusy_auth cache */ private static function checkToken($config, $user, $token) { // See 'ready' hook handler in kolab_auth plugin // for details on how the token auth (cache) entries are created // load the Roundcube framework with its autoloader require_once KOLAB_FREEBUSY_ROOT . '/lib/Roundcube/bootstrap.php'; $rcube = \rcube::get_instance(\rcube::INIT_WITH_DB | \rcube::INIT_WITH_PLUGINS); $ip = \rcube_utils::remote_addr(); $key = md5("$token:$ip:$user"); $valid = false; $rcube->config->set('freebusy_auth_cache', 'db'); $cache = $rcube->get_cache_shared('freebusy_auth', false); if ($cache && ($deadline = $cache->get($key))) { $now = new \DateTime('now', new \DateTimeZone('UTC')); $deadline = new \DateTime($deadline); if ($deadline >= $now) { $valid = true; } } - $_SERVER['FREEBUSY_USER'] = $user; $status = $valid ? 'SUCCESS' : 'FAILURE'; Logger::get('httpauth')->addInfo("Token: authenticating user $user/$token/$ip: $status"); 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