Page MenuHomePhorge

No OneTemporary

Size
12 KB
Referenced Files
None
Subscribers
None
diff --git a/config/config.ini.sample b/config/config.ini.sample
index 5eb6607..3dfe7cf 100644
--- a/config/config.ini.sample
+++ b/config/config.ini.sample
@@ -1,53 +1,53 @@
;; Kolab Free/Busy Service configuration
;; Require HTTP authentication to access this service
[httpauth]
;; Example for static auth credentials
; type = static
; username = "<user>"
; password = "<pass>"
;; Example for LDAP-based authentication
; type = ldap
; host = ldap://localhost:389
; bind_dn = "uid=kolab-service,ou=Special Users,dc=yourdomain,dc=com"
; bind_pw = "<service-bind-pw>"
; base_dn = "dc=yourdomain,dc=com"
; filter = "(&(|(mail=%s)(alias=%s)(uid=%s))(objectclass=inetorgperson))" ; optional, %s is replaced by the username
;; Allow privileged access from these IPs
[trustednetworks]
allow[] = 127.0.0.1
allow[] = 192.168.0.0/16
allow[] = 10.10.*
allow[] = ::1
;; Logging configuration
[log]
driver = file ; supported drivers: file, syslog
path = ./log
name = freebusy
level = 300 ; (100 = Debug, 200 = Info, 300 = Warn, 400 = Error, 500 = Critical)
;; Directories to resolve email addresses and their f/b source locations
;; try local filesystem first
[directory "local"]
type = static
filter = "@yourdomain"
-fbsource = file:/var/lib/kolab-freebusy/%u.ifb
+fbsource = file:/var/lib/kolab-freebusy/%s.ifb
;; local Kolab directory server
[directory "kolab-ldap"]
type = ldap
host = ldap://localhost:389
bind_dn = "uid=kolab-service,ou=Special Users,dc=yourdomain,dc=com"
bind_pw = "<service-bind-pw>"
base_dn = "dc=yourdomain,dc=com"
-filter = "(&(objectClass=kolabInetOrgPerson)(|(uid=%u)(mail=%u)(alias=%u)))"
+filter = "(&(objectClass=kolabInetOrgPerson)(|(uid=%s)(mail=%s)(alias=%s)))"
attributes[] = mail
fbsource = file:/www/kolab-freebusy/data/%mail.ifb
loglevel = 100 ; Debug
diff --git a/lib/Kolab/FreeBusy/DirectoryLDAP.php b/lib/Kolab/FreeBusy/DirectoryLDAP.php
index 54709f2..55a59df 100644
--- a/lib/Kolab/FreeBusy/DirectoryLDAP.php
+++ b/lib/Kolab/FreeBusy/DirectoryLDAP.php
@@ -1,111 +1,111 @@
<?php
namespace Kolab\FreeBusy;
// PEAR modules operate in global namespace
use \Net_LDAP3;
use \Monolog\Logger as Monolog;
/**
*
*/
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']),
'port' => $host['port'] ?: 389,
'use_tls' => $host['scheme'] == 'tls' || $host['scheme'] == 'ldaps',
'root_dn' => $config['base_dn'],
'return_attributes' => (array)$config['attributes'],
'sizelimit' => 0,
'timelimit' => 0,
) + $config;
// instantiate Net_LDAP3 and connect with logger
$this->logger = Logger::get('ldap', intval($config['loglevel']));
$this->ldap = new Net_LDAP3($ldap_config);
$this->ldap->config_set('log_hook', array($this, 'log'));
$this->ldap->config_set('return_attributes', (array)$config['attributes']);
// 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('u' => $user);
+ $result = array('s' => $user);
if ($this->ready) {
// search with configured filter
- $filter = preg_replace('/%u/i', $user, $this->config['filter']);
+ $filter = preg_replace('/%s/i', $user, $this->config['filter']);
$ldapresult = $this->ldap->search($this->config['base_dn'], $filter, 'sub');
// 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
foreach ($entry as $k => $v) {
if (!empty($v)) {
$result[$k] = strval(is_array($v) ? $v[0] : $v);
}
}
return $result;
}
$this->logger->addInfo("No entry found for $filter");
}
return false;
}
}
diff --git a/lib/Kolab/FreeBusy/DirectoryStatic.php b/lib/Kolab/FreeBusy/DirectoryStatic.php
index ff55e0e..8424332 100644
--- a/lib/Kolab/FreeBusy/DirectoryStatic.php
+++ b/lib/Kolab/FreeBusy/DirectoryStatic.php
@@ -1,38 +1,38 @@
<?php
namespace Kolab\FreeBusy;
/**
* Implementation of a static address directory for Free/Busy user lookups.
*
* This directory basically pipes the username through with an optional check
* whether it matches the configured filter rule
*/
class DirectoryStatic extends Directory
{
/**
* Default constructor loading directory configuration
*/
public function __construct($config)
{
$this->config = $config;
}
/**
* @see Directory::resolve()
*/
public function resolve($user)
{
- $result = array('u' => $user);
+ $result = array('s' => $user);
// check if user matches the filter property (if configured)
if (!empty($this->config['filter'])) {
if (!preg_match('!'.$this->config['filter'].'!i', $user))
$result = false;
}
return $result;
}
}
diff --git a/lib/Kolab/FreeBusy/Source.php b/lib/Kolab/FreeBusy/Source.php
index 2d12ebc..96bb547 100644
--- a/lib/Kolab/FreeBusy/Source.php
+++ b/lib/Kolab/FreeBusy/Source.php
@@ -1,66 +1,67 @@
<?php
namespace Kolab\FreeBusy;
/**
* Abstract class to fetch free/busy data from a specific source
*/
abstract class Source
{
protected $config = array();
/**
* Factory method creating an instace of Source according to config
*
* @param array Hash array with config
*/
public static function factory($url)
{
$config = parse_url($url);
$config['url'] = $url;
switch ($config['scheme']) {
case 'file': return new SourceFile($config);
- case 'imap': return new SourceIMAP($config);
+ case 'imap':
+ case 'imaps': return new SourceIMAP($config);
case 'http':
case 'https': return new SourceURL($config);
}
Logger::get('source')->addError("Invalid source configuration: " . $url);
return null;
}
/**
* Default constructor
*/
public function __construct($config)
{
$this->config = $config;
}
/**
* Retrieve free/busy data for the given user
*
* @param array Hash array with user attributes
*/
abstract public function getFreeBusyData($user, $extended);
/**
* Replace all %varname strings in config with values from $user
*/
protected function getUserConfig($user)
{
$config = array();
foreach ($this->config as $k => $val) {
if (is_string($val) && strpos($val, '%') !== false) {
$val = preg_replace_callback(
'/%\{?([a-z0-9]+)\}?/',
function($m) use ($user) { return $user[$m[1]]; },
$val);
}
$config[$k] = $val;
}
return $config;
}
}
\ No newline at end of file
diff --git a/web/index.php b/web/index.php
index 93115f2..9d7cc37 100644
--- a/web/index.php
+++ b/web/index.php
@@ -1,128 +1,128 @@
<?php
/**
* Kolab Server Free/Busy Service Endpoint
*
* This is the public API to provide Free/Busy information for Kolab users.
*
* @version 0.1.0
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2013, Kolab Systems AG <contact@kolabsys.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
define('KOLAB_FREEBUSY_ROOT', realpath('../'));
// suppress error notices
ini_set('error_reporting', E_ALL &~ E_NOTICE);
// use composer's autoloader for both dependencies and local lib
require_once KOLAB_FREEBUSY_ROOT . '/vendor/autoload.php';
use Kolab\FreeBusy\Utils;
use Kolab\FreeBusy\Config;
use Kolab\FreeBusy\Logger;
use Kolab\FreeBusy\Directory;
use Kolab\FreeBusy\HTTPAuth;
// load config
$config = Config::getInstance(KOLAB_FREEBUSY_ROOT . '/config');
if ($config->isValid()) {
// check for trusted IP first
$remote_ip = Utils::remoteIP();
$trusted_ip = $config->trustednetworks ? Utils::checkIPRange($remote_ip, $config->trustednetworks['allow']) : false;
$log = Logger::get('web');
$log->addDebug('Request: ' . $_SERVER['REDIRECT_URL'], array('ip' => $remote_ip, 'trusted' => $trusted_ip));
// check HTTP authentication
if (!$trusted_ip && $config->httpauth) {
if (!HTTPAuth::check($config->httpauth)) {
$log->addDebug("Abort with 401 Unauthorized");
header('WWW-Authenticate: Basic realm="Kolab Free/Busy Service"');
header($_SERVER['SERVER_PROTOCOL'] . " 401 Unauthorized", true);
exit;
}
}
#header('Content-type: text/calendar; charset=utf-8', true);
- header('Content-type: text/plain', true);
+ header('Content-type: text/plain; charset=utf-8', true);
// analyse request
$url = array_filter(explode('/', $_SERVER['REDIRECT_URL']));
$user = strtolower(array_pop($url));
$action = strtolower(array_pop($url));
$extended = false;
// remove file extension
if (preg_match('/^(.+)\.([ipx]fb)$/i', $user, $m)) {
$user = $m[1];
$extended = $m[2] == 'xfb';
}
// iterate over directories
foreach ($config->directories as $key => $dirconfig) {
$log->addDebug("Trying directory $key", $dirconfig);
$directory = Directory::factory($dirconfig);
if ($directory && ($fbdata = $directory->getFreeBusyData($user, $extended))) {
$log->addInfo("Found valid data for user $user in directory $key");
echo $fbdata;
exit;
}
}
// return 404 if request was sent from a trusted IP
if ($trusted_ip) {
$log->addDebug("Returning '404 Not Found' for user $user");
header($_SERVER['SERVER_PROTOCOL'] . " 404 Not found", true);
}
else {
$log->addInfo("Returning empty Free/Busy list for user $user");
$now = time();
$dtformat = 'Ymd\THis\Z';
// NOTE: The following settings should probably correspond with
// whatever period of time kolab-freebusyd thinks it should use.
// Should probably be a setting. For now, do 8 weeks in the past
$start = $now - (60 * 60 * 24 * 7 * 8);
// Should probably be a setting. For now, do 16 weeks into the future
$end = $now + (60 * 60 * 24 * 7 * 16);
// Return an apparent empty Free/Busy list.
print "BEGIN:VCALENDAR\n";
print "VERSION:2.0\n";
print "PRODID:-//kolab.org//NONSGML Kolab Server 3//EN\n";
print "METHOD:PUBLISH\n";
print "BEGIN:VFREEBUSY\n";
print "ORGANIZER:MAILTO:" . $user . ".ifb\n";
print "DTSTAMP:" . gmdate($dtformat) . "\n";
print "DTSTART:" . gmdate($dtformat, $start) . "\n";
print "DTEND:" . gmdate($dtformat, $end) . "\n";
print "COMMENT:This is a dummy vfreebusy that indicates an empty calendar\n";
print "FREEBUSY:19700101T000000Z/19700101T000000Z\n";
print "END:VFREEBUSY\n";
print "END:VCALENDAR\n";
}
}
// exit with error
# header($_SERVER['SERVER_PROTOCOL'] . " 500 Internal Server Error", true);

File Metadata

Mime Type
text/x-diff
Expires
Sun, Feb 1, 5:07 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
426633
Default Alt Text
(12 KB)

Event Timeline