From: Daniel Tarbuck Date: Tue, 17 Jan 2006 11:14:59 +0000 (+0100) Subject: mod_auth_ldap, non-anon binding and openxchange support X-Git-Tag: 0.7.1~106 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=77d53c7d27865772028df4c45ee81b38ac13f0e7;p=contagged mod_auth_ldap, non-anon binding and openxchange support The attached patch builds on your work in the following ways: 1. adds support for non-anonymous binding. Leaving the extra config variables empty results in an anonymous bind. I haven't fully tested this (I cannot test the anonymous case), but any problems should be apparent immediately. 2. adds support for httpd authentication. I use mod_auth_ldap to authenticate access to the site. This prevents the user having to login twice. 3. adds support for parts of the openxchange schema (http://www.openxchange.org). Only the parts I found useful are added. The openxchange.schema is not included as the user that enables this is expected to have already installed openxchange. darcs-hash:20060117111459-bb1f7-cc6f1f6e943f5c6ffa8f393f68c32500505dae67.gz --- diff --git a/README b/README index a69db64..60af64c 100644 --- a/README +++ b/README @@ -2,7 +2,7 @@ LDAPab is a webbased address book for small companies. It features a public address book which is writable for all company staff and a personal address -book for each staff member. LDAPab require an already setup LDAP server to +book for each staff member. LDAPab requires an already setup LDAP server to authenticate users. === REQUIREMENTS === @@ -18,11 +18,14 @@ with LDAP support (compiled in or as extension) Copy the contents of the .tgz file to a directory below your webserver document root. Make sure the webserver is able to write to the cache directory which is -used for the template engines cache files. A 'chmod 777 cache' will do. +used for the template engine's cache files. A 'chmod 777 cache' will do. Open the config.php file in your favourite editor and edit the options according to your needs. Some knowlege about LDAP may come in handy. +If HTTP auth is wanted have a look at the provided _htaccess file, edit it as +needed and rename it back to .htaccess + === SETUP THE LDAP SERVER === The following only describes what to do for open-ldap 2.0! If you use any diff --git a/_htaccess b/_htaccess new file mode 100644 index 0000000..dbb247d --- /dev/null +++ b/_htaccess @@ -0,0 +1,27 @@ +# +# Example .htaccess to use with mod_authldap +# + +AuthName "LDAPab" +AuthType basic + +AuthLDAPURL "ldap://ldap/ou=people,o=cosmocode,c=de?uid?one" + +### LDAP Bind information +#AuthLDAPBindDN cn=NonAnon,o=cosmocode,c=de +#AuthLDAPBindPassword secret + +### For LDAP group authentication +#AuthLDAPGroupAttribute memberUid +#AuthLDAPGroupAttributeIsDN off +#require group cn=Users,ou=Groups,o=cosmocode,c=de + +### Authorize users individually +#require user myusername + +### Authorize any authenticated user +require valid-user + +### Require SSL for access +#SSLRequireSSL + diff --git a/config.php b/config.php index 31419dc..d269fe7 100644 --- a/config.php +++ b/config.php @@ -3,6 +3,9 @@ // Which LDAP Server to use? $conf[ldapserver] = 'ldap'; + // Which LDAP Port Server to use? (389 is standard, 636 for ssl) + $conf[ldapport] = 389; + // What is the root dn on this Server? $conf[ldaprootdn] = 'o=cosmocode, c=de'; @@ -12,6 +15,10 @@ // How to match users? %u is replaced by the given login $conf[userfilter] = '(&(uid=%u)(objectClass=posixAccount))'; + // Use these values to bind to the ldap directory when not logged in (leave blank for anonymous bind) + $conf[anonbinddn] = ''; + $conf[anonbindpw] = ''; + // Which language to use (see lang directory) $conf[lang] = 'de'; @@ -21,6 +28,17 @@ // Where to store private contacts (relative to $conf[usertree]) $conf[privatebook] = 'ou=contacts'; + // Should the additional schema ldapab.schema be used? (0|1) + // Note: openxchange and extended are currently exclusive, do not use both at the same time! + $conf[extended] = 0; + + // Should we use some parts of the openxchange.schema? (0|1) + // Note: openxchange and extended are currently exclusive, do not use both at the same time! + $conf[openxchange] = 1; + + // Should we try to login using the username and password provided by httpd? (0|1) + $conf[httpd_auth] = 1; + // Should the additional schema ldapab.schema be used? (0|1) $conf[extended] = 1; @@ -31,4 +49,5 @@ // Force recompilation of smarty templates? $conf[smartycompile] = 0; + ?> diff --git a/entry.php b/entry.php index a855053..594e1eb 100644 --- a/entry.php +++ b/entry.php @@ -41,6 +41,9 @@ tpl_std(); tpl_orgs(); tpl_markers(); + tpl_categories(); + tpl_timezone(); + tpl_country(); //display templates if($_REQUEST[mode]=='vcf'){ $entry = $smarty->get_template_vars('entry'); @@ -132,6 +135,10 @@ print '';*/ if($conf[extended]){ ldap_store_objectclasses($dn,array('inetOrgPerson','contactPerson')); } + // in openxchange mode we have to make sure the right classes are set + if ($conf[openxchange]){ + ldap_store_objectclasses($dn,array('inetOrgPerson','OXUserObject')); + } //modify entry (touches only our attributes) foreach (array_keys($entries) as $key){ if($key == 'dn'){ diff --git a/functions.php b/functions.php index e8ac472..2c74c1f 100644 --- a/functions.php +++ b/functions.php @@ -13,6 +13,7 @@ function smarty_std(){ * If it fails it redirects to login.php */ function ldap_login(){ + global $conf; if(!empty($_SESSION[ldapab][username])){ //existing session! Check if valid if($_COOKIE[ldapabconid] != $_SESSION[ldapab][conid]){ @@ -20,6 +21,9 @@ function ldap_login(){ header('Location: login.php?username='); exit; } + } elseif ($conf[httpd_auth] && !empty($_SERVER[PHP_AUTH_USER])) { + $_SESSION[ldapab][username] = $_SERVER[PHP_AUTH_USER]; + $_SESSION[ldapab][password] = $_SERVER[PHP_AUTH_PW]; } if(!do_ldap_bind($_SESSION[ldapab][username], @@ -39,7 +43,7 @@ function do_ldap_bind($user,$pass,$dn=""){ //create global connection to LDAP if nessessary if(!$LDAP_CON){ - $LDAP_CON = ldap_connect($conf[ldapserver]); + $LDAP_CON = ldap_connect($conf[ldapserver],$conf[ldapport]); if(!$LDAP_CON){ die("couldn't connect to LDAP server"); } @@ -47,7 +51,8 @@ function do_ldap_bind($user,$pass,$dn=""){ if(empty($dn)){ //anonymous bind to lookup users - if(!ldap_bind($LDAP_CON)){ + //blank binddn or blank bindpw will result in anonymous bind + if(!ldap_bind($LDAP_CON,$conf[anonbinddn],$conf[anonbindpw])){ die("can not bind anonymously"); } @@ -152,6 +157,17 @@ function namedentries($flip=false){ if($conf[extended]){ $entries[anniversary] = 'anniversary'; } + if($conf[openxchange]){ + $entries[mailDomain] = 'domain'; + $entries[userCountry] = 'country'; + $entries[birthDay] = 'birthday'; + $entries[IPPhone] = 'ipphone'; + $entries[OXUserCategories] = 'categories'; + $entries[OXUserInstantMessenger] = 'instantmessenger'; + $entries[OXTimeZone] = 'timezone'; + $entries[OXUserPosition] = 'position'; + $entries[relClientCert] = 'certificate'; + } if($flip){ $entries = array_reverse($entries); @@ -190,6 +206,9 @@ function prepare_ldap_entry($in){ if($conf[extended]){ $out[objectclass][] = 'contactPerson'; } + if($conf[openxchange]){ + $out[objectclass][] = 'OXUserObject'; + } utf8_encode_array($out); diff --git a/index.php b/index.php index 7ff0f07..f797e5e 100644 --- a/index.php +++ b/index.php @@ -42,6 +42,9 @@ //prepare templates tpl_std(); tpl_markers(); + tpl_categories(); + tpl_timezone(); + tpl_country(); $smarty->assign('list',$list); $smarty->assign('filter',$_REQUEST['filter']); $smarty->assign('marker',$_REQUEST['marker']); @@ -84,12 +87,16 @@ $search = $_REQUEST['search']; $org = $_REQUEST['org']; $marker = $_REQUEST['marker']; + $categories = $_REQUEST['categories']; $_SESSION[ldapab][filter] = $filter; if(empty($filter)) $filter='a'; if(!empty($marker)){ $marker = utf8_encode($marker); $ldapfilter = "(&(objectClass=contactPerson)(marker=$marker))"; + }elseif(!empty($categories)){ + $categories = utf8_encode($categories); + $ldapfilter = "(&(objectClass=OXUserObject)(OXUserCategories=$categories))"; }elseif(!empty($search)){ $search = trim($search); $words=preg_split('/\s+/',$search); diff --git a/lang/en.php b/lang/en.php index 1a16c6a..18b0b65 100644 --- a/lang/en.php +++ b/lang/en.php @@ -2,7 +2,7 @@ $lang[ldapab] = 'The LDAP address book'; -$lang[name] = 'Name'; +$lang[name] = 'Last Name'; $lang[givenname] = 'First Name'; $lang[title] = 'Title'; $lang[organization] = 'Company'; @@ -66,4 +66,16 @@ $lang[msg_uploadvcf] = 'Upload VCard File'; $lang[err_noentries] = 'No entries'; $lang[err_ldap] = 'The LDAP server returned the following errors'; + +$lang[openxchange] = 'Xchange Information'; +$lang[moreopenxchange] = 'Xchange Information Cont\'d'; +$lang[instantmessenger] = 'Inst Msg'; +$lang[categories] = 'Categories'; +$lang[birthday] = 'Birthday'; +$lang[domain] = 'Mail Domain'; +$lang[country] = 'Country'; +$lang[certificate] = 'x.509 Cert'; +$lang[timezone] = 'Time Zone'; +$lang[position] = 'Position'; +$lang[ipphone] = 'IP Phone'; ?> diff --git a/template.php b/template.php index 7448a24..dbe4b5e 100644 --- a/template.php +++ b/template.php @@ -58,6 +58,10 @@ function tpl_entry($in){ //handle marker special in extended mode $out['marker'] = $in['marker']; } + if ($conf[openxchange]){ + //handle categories special in openxchange mode + $out['categories'] = $in['OXUserCategories']; + } //decode array utf8_decode_array($out); @@ -160,4 +164,121 @@ function tpl_orgs(){ $smarty->assign('orgs',$orgs); } +/** + * assigns all categories to the template + */ +function tpl_categories(){ + global $conf; + global $LDAP_CON; + global $smarty; + + if(!$conf[openxchange]) return; + + $categories = array(); + + $sr = ldap_list($LDAP_CON,$conf[publicbook],"ObjectClass=OXUserObject",array("OXUserCategories")); + $result1 = ldap_get_binentries($LDAP_CON, $sr); + //check users private addressbook + if(!empty($_SESSION[ldapab][binddn])){ + $sr = @ldap_list($LDAP_CON, + $conf[privatebook].','.$_SESSION[ldapab][binddn], + "ObjectClass=OXUserObject",array("OXUserCategories")); + $result2 = ldap_get_binentries($LDAP_CON, $sr); + } + $result = array_merge($result1,$result2); + + if(count($result)){ + foreach ($result as $entry){ + if(count($entry['OXUserCategories'])){ + foreach($entry['OXUserCategories'] as $category){ + array_push($categories, $category); + } + } + } + } + $categories = array_unique($categories); + sort($categories,SORT_STRING); + + utf8_decode_array($categories); + $smarty->assign('categories',$categories); +} + +/** + * assigns all timezones to the template + */ +function tpl_timezone(){ + global $conf; + global $LDAP_CON; + global $smarty; + + if(!$conf[openxchange]) return; + + $timezone = array(); + + $sr = ldap_list($LDAP_CON,$conf[publicbook],"ObjectClass=OXUserObject",array("OXTimeZone")); + $result1 = ldap_get_binentries($LDAP_CON, $sr); + //check users private addressbook + if(!empty($_SESSION[ldapab][binddn])){ + $sr = @ldap_list($LDAP_CON, + $conf[privatebook].','.$_SESSION[ldapab][binddn], + "ObjectClass=OXUserObject",array("OXTimeZone")); + $result2 = ldap_get_binentries($LDAP_CON, $sr); + } + $result = array_merge($result1,$result2); + + if(count($result)){ + foreach ($result as $entry){ + if(count($entry['OXTimeZone'])){ + foreach($entry['OXTimeZone'] as $tz){ + array_push($timezone, $tz); + } + } + } + } + $timezone = array_unique($timezone); + sort($timezone,SORT_STRING); + + utf8_decode_array($timezone); + $smarty->assign('timezone',$timezone); +} + +/** + * assigns all countries to the template + */ +function tpl_country(){ + global $conf; + global $LDAP_CON; + global $smarty; + + if(!$conf[openxchange]) return; + + $country = array(); + + $sr = ldap_list($LDAP_CON,$conf[publicbook],"ObjectClass=OXUserObject",array("userCountry")); + $result1 = ldap_get_binentries($LDAP_CON, $sr); + //check users private addressbook + if(!empty($_SESSION[ldapab][binddn])){ + $sr = @ldap_list($LDAP_CON, + $conf[privatebook].','.$_SESSION[ldapab][binddn], + "ObjectClass=OXUserObject",array("userCountry")); + $result2 = ldap_get_binentries($LDAP_CON, $sr); + } + $result = array_merge($result1,$result2); + + if(count($result)){ + foreach ($result as $entry){ + if(count($entry['userCountry'])){ + foreach($entry['userCountry'] as $c){ + array_push($country, $c); + } + } + } + } + $country = array_unique($country); + sort($country,SORT_STRING); + + utf8_decode_array($country); + $smarty->assign('country',$country); +} + ?> diff --git a/templates/entry_edit.tpl b/templates/entry_edit.tpl index de2283d..be8f3a9 100644 --- a/templates/entry_edit.tpl +++ b/templates/entry_edit.tpl @@ -169,6 +169,9 @@ {/if} + {if $conf.openxchange} + {include file="openxchange_edit.tpl"} + {/if}
diff --git a/templates/entry_show.tpl b/templates/entry_show.tpl index b87a69e..da5f391 100644 --- a/templates/entry_show.tpl +++ b/templates/entry_show.tpl @@ -116,5 +116,8 @@ + {if $conf.openxchange} + {include file="openxchange_show.tpl"} + {/if}


diff --git a/templates/list_filter.tpl b/templates/list_filter.tpl index 1cecd92..e5c2ab5 100644 --- a/templates/list_filter.tpl +++ b/templates/list_filter.tpl @@ -30,6 +30,17 @@ # * +{if $conf.openxchange} + +
+ + +
+ +{/if} {if $conf.extended}
diff --git a/templates/openxchange_edit.tpl b/templates/openxchange_edit.tpl new file mode 100644 index 0000000..0856a4f --- /dev/null +++ b/templates/openxchange_edit.tpl @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$lang.openxchange}
{$lang.birthday}:
{$lang.ipphone}:
{$lang.instantmessenger}:
{$lang.domain}:
{$lang.certificate}: + +
+ +
+ + + + + + + + + + + + + + + + + + + +
{$lang.moreopenxchange}
{$lang.country}: +
+
+
{$lang.timezone}: +
+
+
{$lang.categories}: +
+
+
+
+ + diff --git a/templates/openxchange_show.tpl b/templates/openxchange_show.tpl new file mode 100644 index 0000000..6f50348 --- /dev/null +++ b/templates/openxchange_show.tpl @@ -0,0 +1,72 @@ + + + + + +
+ {$lang.openxchange} +
+ + {if $entry.birthday} + + + + + {/if} + {if $entry.ipphone} + + + + + {/if} + {if $entry.instantmessenger} + + + + + {/if} + {if $entry.domain} + + + + + {/if} + {if $entry.certificate} + + + + + {/if} +
{$lang.birthday}:{$entry.birthday}
{$lang.ipphone}:{$entry.ipphone}
{$lang.instantmessenger}:{$entry.instantmessenger}
{$lang.domain}:{$entry.domain}
{$lang.certificate}: + +
+
+
+ {$lang.moreopenxchange} +
+ + {if $entry.country} + + + + + {/if} + {if $entry.timezone} + + + + + {/if} + {if $entry.categories} + + + + + {/if} +
{$lang.country}:{$entry.country}
{$lang.timezone}:{$entry.timezone}
{$lang.categories}: + {foreach from=$entry.categories item=categories} + {$categories}
+ {/foreach} +
+
+