summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>2011-12-01 13:37:39 (GMT)
committerJeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>2011-12-01 13:37:39 (GMT)
commit98562ba546ef3a378363679055132c134ca4e4d2 (patch)
tree1aced18bde2d0e10bb868b6b514e75dbb5eeed6a
parentb263e1c0557adf721f8f344b289d882d0415a577 (diff)
downloadkolab-wap-98562ba546ef3a378363679055132c134ca4e4d2.tar.gz
Add initial stab at some API work
-rw-r--r--lib/Auth.php122
-rw-r--r--lib/Auth/LDAP.php719
-rw-r--r--lib/Conf.php86
-rw-r--r--lib/SQL.php55
-rw-r--r--lib/Session.php51
-rw-r--r--lib/User.php73
-rw-r--r--lib/actions/domains_list.php32
-rw-r--r--lib/actions/system_login.php5
-rw-r--r--lib/actions/user_add.php71
-rw-r--r--lib/actions/user_types_list.php23
-rw-r--r--lib/actions/users_list.php11
-rw-r--r--lib/functions.php56
-rw-r--r--public_html/.htaccess11
-rw-r--r--public_html/add_user_test.html5
-rw-r--r--public_html/add_user_test.php44
-rw-r--r--public_html/api/index.php16
16 files changed, 1380 insertions, 0 deletions
diff --git a/lib/Auth.php b/lib/Auth.php
new file mode 100644
index 0000000..97c2364
--- /dev/null
+++ b/lib/Auth.php
@@ -0,0 +1,122 @@
+<?php
+ require_once('Conf.php');
+
+ class Auth {
+ static private $instance = Array();
+
+ private $_auth = Array();
+ private $conf;
+ private $domains = Array();
+
+ 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);
+ }
+
+ public function authenticate($username, $password) {
+ error_log("Authentication request for $username");
+ if (strpos($username, '@')) {
+ $user_domain = explode('@', $username);
+ $user_domain = $user_domain[1];
+
+ if (isset($this->_auth[$user_domain])) {
+ $domain = $user_domain;
+ } else {
+ $associated_domain = $this->primary_for_valid_domain($user_domain);
+ if ($associated_domain) {
+ $domain = $user_domain;
+ } else {
+ $domain = FALSE;
+ }
+ }
+ } else {
+ $domain = $this->conf->get('primary_domain');
+ }
+
+ if ($this->domain == $domain) {
+ error_log("using the current $domain auth thingy");
+ $result = $this->_auth[$domain]->authenticate($username, $password);
+ } else {
+ error_log("creating a new $domain auth thingy");
+ $result = Auth::get_instance($domain)->authenticate($username, $password);
+ }
+ return $result;
+ }
+
+ public function connect($domain = NULL) {
+ $auth_method = strtoupper($this->conf->get('kolab', 'auth_mechanism'));
+
+ if ($domain === NULL) {
+ $domain = $this->conf->get('primary_domain');
+ }
+
+ if (!isset($this->_auth[$domain])) {
+ require_once('Auth/' . $auth_method . '.php');
+ $this->_auth[$domain] = new $auth_method($domain);
+ }
+
+ }
+
+ public function list_domains() {
+ $this->connect();
+ return $this->_auth[$this->domain]->list_domains();
+ }
+
+ public function list_users($domain = NULL) {
+ $this->connect($domain);
+ if ($domain === NULL) {
+ $domain = $this->conf->get('primary_domain');
+ }
+
+ $users = $this->_auth[$domain]->list_users();
+
+ return $users;
+ }
+
+ 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;
+ } elseif (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;
+ }
+ }
+ }
+?>
diff --git a/lib/Auth/LDAP.php b/lib/Auth/LDAP.php
new file mode 100644
index 0000000..a207a41
--- /dev/null
+++ b/lib/Auth/LDAP.php
@@ -0,0 +1,719 @@
+<?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();
+
+ if ($domain === NULL) {
+ $this->domain = $this->conf->get('primary_domain');
+ } else {
+ $this->domain = $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->_from_domain_to_rootdn($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();
+ $_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);
+
+ 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 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');
+ return $this->search($this->conf->get($section, 'domain_base_dn'), $this->conf->get($section, 'kolab_domain_filter'));
+ }
+
+ public function llist($base_dn, $filter)
+ {
+ return $this->_list($base_dn, $filter);
+ }
+
+ public function list_domains() {
+ return $this->domains_list();
+ }
+
+ public function list_users() {
+ return $this->users_list();
+ }
+
+ 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;
+ }
+
+ public function users_list() {
+ return $this->search("ou=People,dc=klab,dc=cc", "(objectClass=kolabinetorgperson)", Array("uid"));
+ }
+
+ 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 _from_domain_to_rootdn($domain = '')
+ {
+ // Issue deprecation warning
+ return $this->domain_root_dn($domain);
+ }
+
+ 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 )
+ {
+ if ( is_array($value) )
+ $attributes_filter[] = $key;
+ else
+ $attributes_filter[] = $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)
+ {
+ if ( ( $add_result = ldap_add($this->_connection, $entry_dn, $attributes) ) == FALSE )
+ {
+ // Issue warning
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+ }
+
+ /*
+ Shortcut to ldap_bind()
+ */
+
+ private function _bind($dn, $pw)
+ {
+ $this->_connect();
+
+ 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 )
+ {
+ 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;
+ error_log("Not connected: " . ldap_err2str() . "(no.) " . ldap_errno());
+ }
+ else
+ {
+ $this->_connection = $connection;
+ }
+ error_log("Connected!");
+ }
+ else {
+ error_log("Already connected");
+ }
+ }
+
+ /*
+ Shortcut to ldap_disconnect()
+ */
+
+ private function _disconnect()
+ {
+ if ( ( $this->_connection ) == FALSE )
+ {
+ return TRUE;
+ }
+ else
+ {
+ if ( ( $result = ldap_close($this->_connection) ) == TRUE )
+ {
+ $this->_connection = FALSE;
+ return TRUE;
+ }
+ else
+ {
+ // 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) ) == TRUE )
+ {
+ if ( ( $err2str = @ldap_err2str($errno) ) == TRUE )
+ {
+ return $err2str;
+ }
+ else
+ {
+ // Issue warning
+ return NULL;
+ }
+ }
+ else
+ {
+ // 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('*'))
+ {
+ $this->_connect();
+ $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;
+ }
+ else
+ {
+ if ( ( $entries = ldap_get_entries($this->_connection, $search_results) ) == FALSE )
+ {
+ #message("Could not get the results of the search: " . $this->_errstr());
+ return FALSE;
+ }
+ else
+ {
+ 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 ) == TRUE )
+ {
+ 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'.
+
+ Returns a 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_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 ) == TRUE )
+ {
+ #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;
+ else
+ $user_dn = ldap_get_dn($this->_connection, $first_entry);
+
+ return $user_dn;
+ }
+
+
+ public function _get_email_address()
+ {
+ return "kanarip@kanarip.com";
+ }
+
+ }
+?>
+
diff --git a/lib/Conf.php b/lib/Conf.php
new file mode 100644
index 0000000..afd9687
--- /dev/null
+++ b/lib/Conf.php
@@ -0,0 +1,86 @@
+<?php
+
+ class Conf {
+ static private $instance;
+
+ /**
+ * This implements the 'singleton' design pattern
+ *
+ * @return Conf The one and only instance
+ */
+ static function get_instance()
+ {
+ if (!self::$instance) {
+ self::$instance = new Conf();
+ }
+
+ return self::$instance;
+ }
+
+ public function __construct()
+ {
+ // Do some magic configuration loading here.
+ if (file_exists('/etc/kolab/kolab.conf'))
+ {
+ $_ini_raw = file('/etc/kolab/kolab.conf');
+
+ $this->_conf = Array();
+
+ foreach ($_ini_raw as $_line) {
+ if (preg_match('/^\[([a-z0-9-_\.]+)\]/', $_line, $matches)) {
+ $_cur_section = $matches[1];
+ $this->_conf[$_cur_section] = Array();
+ unset($_cur_key);
+ }
+
+ if (preg_match('/^;/', $_line, $matches)) {
+ }
+
+ if (preg_match('/^([a-z0-9\.-_]+)\s*=\s*(.*)/', $_line, $matches)) {
+ if (isset($_cur_section) && !empty($_cur_section)) {
+ $_cur_key = $matches[1];
+ $this->_conf[$_cur_section][$matches[1]] = isset($matches[2]) ? $matches[2] : '';
+
+ }
+ }
+
+ if (preg_match('/^\s+(.*)$/', $_line, $matches)) {
+ if (isset($_cur_key) && !empty($_cur_key)) {
+ $this->_conf[$_cur_section][$_cur_key] .= $matches[1];
+ }
+ }
+ }
+ }
+ }
+
+ public function get($key1, $key2 = NULL) {
+ if (isset($this->_conf[$key1])) {
+ if ($key2) {
+ if (isset($this->_conf[$key1][$key2])) {
+ return $this->_conf[$key1][$key2];
+ } elseif (isset($this->_conf['kolab'][$key2])) {
+ return $this->_conf['kolab'][$key2];
+ }
+ } else {
+ return $this->_conf[$key1];
+ }
+ }
+
+ // Simple (global) settings may be obtained by calling the key and omitting
+ // the section. This goes for sections 'kolab', and whatever is the equivalent
+ // of 'kolab', 'auth_mechanism'.
+# echo "<pre>";
+# print_r($this->_conf);
+# echo "</pre>";
+
+ if (isset($this->_conf['kolab'][$key1])) {
+ return $this->_conf['kolab'][$key1];
+ } elseif (isset($this->_conf[$this->_conf['kolab']['auth_mechanism']][$key1])) {
+ return $this->_conf[$this->_conf['kolab']['auth_mechanism']][$key1];
+ }
+
+ }
+
+ }
+
+?>
diff --git a/lib/SQL.php b/lib/SQL.php
new file mode 100644
index 0000000..44cd600
--- /dev/null
+++ b/lib/SQL.php
@@ -0,0 +1,55 @@
+<?php
+
+ class SQL {
+ static private $instance = Array();
+
+ private $sql_uri = "mysql://username:password@hostname/database";
+
+ /* Placeholder for the existing MySQL connection */
+ private $conn = FALSE;
+
+ /**
+ * This implements the 'singleton' design pattern
+ *
+ * @return SQL The one and only instance associated with $_conn
+ */
+ static function get_instance($_conn = 'kolab_wap')
+ {
+ if (!isset(self::$instance[$_conn])) {
+ self::$instance[$_conn] = new SQL($_conn);
+ }
+
+ return self::$instance[$_conn];
+ }
+
+ public function __construct($_conn = 'kolab_wap') {
+ $this->name = $_conn;
+ $conf = Conf::get_instance();
+ $this->sql_uri = $conf->get($_conn, 'sql_uri');
+ }
+
+ public function query($query) {
+ if (!$this->conn) {
+ $this->_connect();
+ }
+
+ $result = mysql_query($query);
+ return $result;
+ }
+
+ private function _connect() {
+ if (!$this->conn) {
+ $_uri = parse_url($this->sql_uri);
+ $this->_username = $_uri['user'];
+ $this->_password = $_uri['pass'];
+ $this->_hostname = $_uri['host'];
+ $this->_database = str_replace('/','',$_uri['path']);
+
+ $this->conn = mysql_connect($this->_hostname, $this->_username, $this->_password);
+ mysql_select_db($this->_database, $this->conn);
+ }
+ }
+
+ }
+
+?>
diff --git a/lib/Session.php b/lib/Session.php
new file mode 100644
index 0000000..e73af26
--- /dev/null
+++ b/lib/Session.php
@@ -0,0 +1,51 @@
+<?php
+
+ require_once("User.php");
+
+ session_start();
+
+ if ( isset($_COOKIE['PHPSESSID']) )
+ {
+ define("PHPSESSID",$_COOKIE['PHPSESSID']);
+ }
+ elseif ( session_id() )
+ {
+ $sid = explode("=",SID);
+ define("PHPSESSID",$sid[1]);
+ }
+
+ if ( !isset($_SESSION['session_id']) )
+ $_SESSION['session_id'] = session_id();
+
+ // We attempt to find the user credentials and use them for authentication.
+ // TODO: Attempt to figure out the authentication tech. and realm from;
+ //
+ // - the configuration,
+ // - the credentials supplied,
+ // - etc.
+ require_once('User.php');
+
+ if ( $_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['username']) && isset($_POST['password']) )
+ {
+ $_SESSION['user'] = new User();
+ return $_SESSION['user']->authenticate($_POST['username'], $_POST['password']);
+ }
+
+ function append_sid($url)
+ {
+ if ( defined('PHPSESSID') && !preg_match('#sid=#', $url) )
+ {
+ $url .= ( strpos($url,'?') != FALSE ) ? '&sid=' . PHPSESSID : '?sid=' . PHPSESSID;
+ }
+
+ return $url;
+ }
+
+ if ( isset($_GET['new_template']) )
+ {
+ $_SESSION['template'] = $_GET['new_template'];
+ }
+
+ output_add_rewrite_var('sid',PHPSESSID);
+?>
+
diff --git a/lib/User.php b/lib/User.php
new file mode 100644
index 0000000..ec82797
--- /dev/null
+++ b/lib/User.php
@@ -0,0 +1,73 @@
+<?php
+// @require_once($_SERVER["DOCUMENT_ROOT"] . "../bin/lib/User/Type.php");
+// @require_once($_SERVER["DOCUMENT_ROOT"] . "../bin/lib/User/LDAP.php");
+// @require_once($_SERVER["DOCUMENT_ROOT"] . "../bin/lib/User/SQL.php");
+
+ require_once('Auth.php');
+
+ class User
+ {
+
+ public $_authenticated = FALSE;
+
+ private $username = NULL;
+ private $password = NULL;
+
+ private $bind_dn = NULL;
+ private $bind_pw = NULL;
+
+ public $user_bind_dn = NULL;
+ public $user_bind_pw = NULL;
+
+ function User($username = NULL, $password = NULL)
+ {
+ if ( ( $username ) == FALSE || ( $password ) == FALSE )
+ {
+ $result = FALSE;
+ }
+ else
+ {
+ $this->username = $username;
+ $this->password = $password;
+
+ $result = $this->authenticate($username, $password);
+ }
+
+ return $result;
+ }
+
+ public function _get_username()
+ {
+ // Who's asking?
+ return $this->username;
+ }
+
+ public function _get_information()
+ {
+ // Return an array of information about this user. For one, the auth method.
+ $user['information'] = Array(
+ 'email_address' => $this->_auth_method->_get_email_address(),
+ 'username' => $this->username,
+ 'password' => $this->password,
+ );
+ }
+
+ public function authenticate($username, $password, $method = FALSE)
+ {
+ $auth = Auth::get_instance();
+ $result = $auth->authenticate($username, $password);
+
+ if ( $result )
+ {
+ $this->_authenticated = TRUE;
+ $this->username = $username;
+ $this->password = $password;
+ }
+
+ return $this->_authenticated;
+ }
+
+ }
+
+?>
+
diff --git a/lib/actions/domains_list.php b/lib/actions/domains_list.php
new file mode 100644
index 0000000..587cf68
--- /dev/null
+++ b/lib/actions/domains_list.php
@@ -0,0 +1,32 @@
+<?php
+
+ require_once(dirname(__FILE__) . "/../functions.php");
+
+ $auth = Auth::get_instance();
+ $conf = Conf::get_instance();
+
+ $domains = $auth->list_domains();
+ $domains = LDAP::normalize_result($domains);
+
+ if (isset($_GET['rest']) && !empty($_GET['rest'])) {
+ $search_key = str_replace('/','',$_GET['rest']);
+
+ $section = $conf->get('kolab', 'auth_mechanism');
+ $domain_name_attr = $conf->get($section, 'domain_name_attribute');
+
+ foreach ($domains as $id => $attributes) {
+
+ if (is_array($attributes['associateddomain'])) {
+ if (in_array($_GET['rest'], $attributes['associateddomain'])) {
+ print json_encode($attributes);
+ }
+ } elseif ($attributes['associateddomain'] == $search_key) {
+ print json_encode($attributes);
+ }
+ }
+
+ } else {
+ print json_encode($domains);
+ }
+
+?>
diff --git a/lib/actions/system_login.php b/lib/actions/system_login.php
new file mode 100644
index 0000000..7457f43
--- /dev/null
+++ b/lib/actions/system_login.php
@@ -0,0 +1,5 @@
+<?php
+ if (!$_SERVER["REQUEST_METHOD"] == "POST") {
+ throw new Exception("You are not posting any information you twat!");
+ }
+?>
diff --git a/lib/actions/user_add.php b/lib/actions/user_add.php
new file mode 100644
index 0000000..9986fde
--- /dev/null
+++ b/lib/actions/user_add.php
@@ -0,0 +1,71 @@
+<?php
+ $type = 'kolab';
+
+ $user_type = mysql_fetch_assoc(query("SELECT attributes FROM user_types WHERE id = '" . $_GET['user_type_id'] ."'"));
+
+ $user_type_attributes = json_decode(base64_decode($user_type['attributes']));
+
+# echo "<pre>";
+# print_r($_POST);
+# echo "</pre>";
+
+ $user = Array();
+
+ #chars = ['Ä', 'Ü', 'Ö', 'ä', 'ü', 'ö', 'ß']
+ #simple = ['Ae', 'Ue', 'Oe', 'ae', 'ue', 'oe', 'ss']
+
+ $needles = Array(
+ ' ',
+ 'ö',
+ 'ü',
+ );
+
+ $replaces = Array(
+ '',
+ 'oe',
+ 'ue',
+ );
+
+ foreach ($user_type_attributes as $level => $attributes) {
+ echo "<li>$level:<pre>";
+ print_r($attributes);
+ echo "</pre>";
+ if ($level == "mandatory") {
+ foreach ($attributes as $key => $value) {
+ if (isset($_POST[strtolower($key)])) {
+# print $level . " key " . $key . " found\n";
+ $user[$key] = $_POST[strtolower($key)];
+ } elseif (isset($_POST[strtolower($value)])) {
+# print $level . " value for " . $value . " found\n";
+ $user[$value] = $_POST[strtolower($value)];
+ } else {
+ $user[$key] = $value;
+ }
+ }
+ }
+ if ($level == "auto_generated") {
+ // Only contains a list of attribute names...
+ foreach ($attributes as $num => $attribute) {
+ if ($attribute == "alias") {
+ // Apply secondary mail routine
+ }
+
+ if ($attribute == "uid") {
+ // Apply normalization
+ $user['uid'] = strtolower(str_replace($needles, $replaces, $user['sn']));
+ }
+
+ if ($attribute == "cn") {
+ $user['cn'] = $user['givenName'] . " " . $user['sn'];
+ }
+
+ if ($attribute == "displayName") {
+ $user['displayName'] = $user['sn'] . ", " . $user['givenName'];
+ }
+ }
+ }
+ }
+
+ print_r($user);
+
+?>
diff --git a/lib/actions/user_types_list.php b/lib/actions/user_types_list.php
new file mode 100644
index 0000000..a504c72
--- /dev/null
+++ b/lib/actions/user_types_list.php
@@ -0,0 +1,23 @@
+<?php
+ $result = query("SELECT * FROM user_types");
+
+ $user_types = Array();
+
+ while ($row = mysql_fetch_assoc($result)) {
+ $user_types[$row['id']] = Array();
+
+ foreach ($row as $key => $value) {
+ if ($key != "id") {
+ if ($key == "attributes") {
+ $user_types[$row['id']][$key] = json_decode(base64_decode($value));
+ } else {
+ $user_types[$row['id']][$key] = $value;
+ }
+ }
+ }
+ }
+
+ #print base64_encode(json_encode($user_types));
+ print json_encode($user_types);
+
+?>
diff --git a/lib/actions/users_list.php b/lib/actions/users_list.php
new file mode 100644
index 0000000..66903e0
--- /dev/null
+++ b/lib/actions/users_list.php
@@ -0,0 +1,11 @@
+<?php
+ require_once(dirname(__FILE__) . "/../functions.php");
+
+ require_once('Auth.php');
+
+ $auth = Auth::get_instance();
+ $users = $auth->list_users();
+ $users = $auth->normalize_result($users);
+
+ print json_encode($users);
+?>
diff --git a/lib/functions.php b/lib/functions.php
new file mode 100644
index 0000000..09cf3a4
--- /dev/null
+++ b/lib/functions.php
@@ -0,0 +1,56 @@
+<?php
+ ini_set('include_path', dirname(__FILE__) . PATH_SEPARATOR . ini_get('include_path'));
+
+ // These are just here for some statistics.
+ list($usec, $sec) = explode(' ',microtime());
+
+ $GLOBALS['parse_start'] = ((float)$usec + (float)$sec);
+
+ // Initialize some runtime variables
+ $ldap = Array();
+ $sql = Array();
+ $messages = Array();
+
+ $sql_stats = Array(
+ 'queries' => 0,
+ 'query_time' => 0,
+ 'connections' => 0
+ );
+
+ require_once('Session.php');
+ require_once('Conf.php');
+
+ function query($query, $_conn = 'kolab_wap') {
+ require_once('SQL.php');
+
+ $sql = SQL::get_instance($_conn);
+
+ return $sql->query($query);
+ }
+
+ function valid_login() {
+ // The $_SESSION variable is controlled through lib/User.php's
+ // _authenticate()
+ //
+ if ( isset($_SESSION['user']->_authenticated) ) {
+ error_log("Logged in proper");
+ return $_SESSION['user']->_authenticated;
+ } else {
+ error_log("Not logged in!");
+ return FALSE;
+ }
+
+ }
+
+ function need_login() {
+ print "You are not logged in<br/>";
+ print '<form method="post">';
+ print '<input type="text" name="username" /><br/>';
+ print '<input type="password" name="password" /><br/>';
+ print '<input type="submit" name="submit" value="Log in"/></form>';
+ echo "<pre>"; print_r($_SESSION); echo "</pre>";
+ exit;
+ }
+
+
+?>
diff --git a/public_html/.htaccess b/public_html/.htaccess
new file mode 100644
index 0000000..ebc5438
--- /dev/null
+++ b/public_html/.htaccess
@@ -0,0 +1,11 @@
+<IfModule mod_rewrite.c>
+ RewriteEngine on
+
+ RewriteBase /~vanmeeuwen/kolab-wap/public_html
+
+ # Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteCond %{REQUEST_URI} !=/favicon.ico
+ RewriteRule ^api/([a-z0-9-_]+)/([a-z0-9-_]+)(.*)$ api/index.php?object=$1&action=$2&rest=$3 [L,QSA]
+</IfModule>
diff --git a/public_html/add_user_test.html b/public_html/add_user_test.html
new file mode 100644
index 0000000..8e893ae
--- /dev/null
+++ b/public_html/add_user_test.html
@@ -0,0 +1,5 @@
+<form method="post" action="/~vanmeeuwen/kolab-wap/public_html/api/user/add?user_type_id=1">
+<input name="sn" type="text" value="van Meeuwen" />
+<input name="givenname" type="text" value="Jeroen" />
+<input name="submit" type="submit" value="Add User" />
+</form>
diff --git a/public_html/add_user_test.php b/public_html/add_user_test.php
new file mode 100644
index 0000000..ced1a13
--- /dev/null
+++ b/public_html/add_user_test.php
@@ -0,0 +1,44 @@
+<?php
+ require_once( dirname(__FILE__) . '/../lib/functions.php');
+
+ if (!valid_login())
+ need_login();
+
+ #echo "<pre>"; print_r($_SERVER); echo "</pre>";
+
+ if (array_key_exists('HTTPS', $_SERVER) && !empty($_SERVER['HTTPS'])) {
+ $proto = 'https://';
+ } else {
+ $proto = 'http://';
+ }
+
+ define('API_ROOT', $proto . $_SERVER['HTTP_HOST'] . dirname($_SERVER["REQUEST_URI"]) . "/api/");
+
+ #$user_types = json_decode(base64_decode(implode('',file( API_ROOT . 'user_types/list'))));
+ $user_types = (array)(json_decode(implode('',file( API_ROOT . 'user_types/list'))));
+ #echo "<pre>"; print_r($user_types); echo "</pre>";
+
+ print '<form method="post">';
+ print '<table>';
+ print '<tr><td>User Type:</td><td><select name="user_type_id" onchange="javascript:update_user_type_form_elements(this.value);">';
+ foreach ($user_types as $id => $attrs) {
+ $attrs = (array)($attrs);
+ print '<option value="' . $id . '">' . $attrs['name'] . '</option>';
+ }
+ print '</select></td></tr>';
+ foreach ($user_types as $id => $attrs) {
+ $attrs = (array)($attrs);
+ $attrs['attributes'] = (array)($attrs['attributes']);
+ foreach ($attrs['attributes']['mandatory'] as $attribute_name => $attribute) {
+ if (!is_array($attribute)) {
+ print '<tr><td>' . $attribute . '</td><td><input type="text" name="' . $attribute . '" /></td></tr>';
+ } else {
+ print '<tr><td>' . $attribute_name . '</td><td>' . implode('<br />', $attribute) . '</td></tr>';
+ }
+ }
+ }
+
+ print '<tr><td colspan="2" align="center"><input type="submit" name="submit" value="Whatever is the localized equivalent of \'Add User\'" /></td></tr>';
+ print '</table>';
+ print '</form>';
+?>
diff --git a/public_html/api/index.php b/public_html/api/index.php
new file mode 100644
index 0000000..5146e3d
--- /dev/null
+++ b/public_html/api/index.php
@@ -0,0 +1,16 @@
+<?php
+ require_once( dirname(__FILE__) . "/../../lib/functions.php");
+
+ if (!valid_login()) {
+ need_login();
+ }
+
+ if (!empty($_GET['object']) && !empty($_GET['action'])) {
+ if (function_exists($_GET['object'] . '_' . $_GET['action'])) {
+ call_user_func_array($_GET['object'] . '_' . $_GET['action']);
+ } elseif (file_exists(dirname(__FILE__) . "/../../lib/actions/" . $_GET['object'] . '_' . $_GET['action'] . ".php")) {
+ require_once(dirname(__FILE__) . "/../../lib/actions/" . $_GET['object'] . '_' . $_GET['action'] . ".php");
+ }
+ }
+
+?>