]> git.sur5r.net Git - contagged/commitdiff
mod_auth_ldap, non-anon binding and openxchange support
authorDaniel Tarbuck <tarbuck@futurewest.ca>
Tue, 17 Jan 2006 11:14:59 +0000 (12:14 +0100)
committerDaniel Tarbuck <tarbuck@futurewest.ca>
Tue, 17 Jan 2006 11:14:59 +0000 (12:14 +0100)
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

13 files changed:
README
_htaccess [new file with mode: 0644]
config.php
entry.php
functions.php
index.php
lang/en.php
template.php
templates/entry_edit.tpl
templates/entry_show.tpl
templates/list_filter.tpl
templates/openxchange_edit.tpl [new file with mode: 0644]
templates/openxchange_show.tpl [new file with mode: 0644]

diff --git a/README b/README
index a69db6459a751255cb8fe0d5712fa68d4dddaff5..60af64cc04ff82e0a1ff2cf00512a4805b31a7ab 100644 (file)
--- 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 (file)
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
+
index 31419dca562e9e1c8557404811ee1cad5ef44d3b..d269fe752f493469b24c3ee83478fef11aa41e9d 100644 (file)
@@ -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';
 
   // 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';
 
   // 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;
+
 ?>
index a8550534f7a76ae47b86bc91c8c3d786e3431239..594e1eb2b95fb54d8b9e1474eb4e3749413816ee 100644 (file)
--- 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 '</pre>';*/
       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'){
index e8ac472488987ad535af3cbd5278081979d0d50e..2c74c1f606e1089b0997b569b34c049383207c70 100644 (file)
@@ -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);
 
index 7ff0f0761287e736a7700499ea5eadf1648de527..f797e5e0637952272bb77ffe56f1260fc8c85073 100644 (file)
--- 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']);
     $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);
index 1a16c6a8ee01fb20992643c94a8043ec93a1b8fc..18b0b65fd8ea0ab919af475f800cf5f30df979a3 100644 (file)
@@ -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';
 ?>
index 7448a2424db58020ab41a35fd127b330e49e7362..dbe4b5ec5fa0e66d72be17804137dde849e8b2c7 100644 (file)
@@ -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);
+}
+
 ?>
index de2283dddc973ec96f8309940565bced496807e1..be8f3a90603f0599a30b1481e48dfbd73954d00f 100644 (file)
     </td>
   </tr>
   {/if}
+  {if $conf.openxchange}
+    {include file="openxchange_edit.tpl"}
+  {/if}
   <tr>
     <td colspan="2" align="center"><br><input type="submit" class="input" value="{$lang.submit}"></td>
   </tr>
index b87a69efefe63c00b0c1acb7786e634f77ae61cc..da5f3914687b152af445c7c357f8712dd6393561 100644 (file)
     </td>
   </tr>
 </table>
+      {if $conf.openxchange}
+        {include file="openxchange_show.tpl"}
+      {/if}
 <br><br><br>
 
index 1cecd9263e792b6831e6d57f523c44836ce377fb..e5c2ab57a47c2954e2872a583ddbad55a7905910 100644 (file)
   <a href="index.php?filter=other">#</a>
   <a href="index.php?filter=*">*</a>
 </td>
+{if $conf.openxchange}
+<td class="filterrow" align="right">
+  <form method="get" action="index.php" style="display:inline">
+    <select name="categories" class="searchfield">
+      <option value="">--- {$lang.categories} ---</option>
+      {html_options values=$categories output=$categories selected=$smarty.request.categories}
+    </select>
+    <input type="submit" value="{$lang.search}" class="searchbutton">
+  </form>
+</td>
+{/if}
 {if $conf.extended}
 <td class="filterrow" align="right">
   <form method="get" action="index.php" style="display:inline">
diff --git a/templates/openxchange_edit.tpl b/templates/openxchange_edit.tpl
new file mode 100644 (file)
index 0000000..0856a4f
--- /dev/null
@@ -0,0 +1,71 @@
+<tr>
+<td width="50%" valign="top" align="center">
+  <table>
+  <tr>
+    <td colspan="2"><b>{$lang.openxchange}</b></td>
+  </tr>
+  <tr>
+    <td align="right" valign="top">{$lang.birthday}:</td>
+    <td><input type="text" class="input" name="entry[birthday]" value="{$entry.birthday|escape}"></td>
+  </tr>
+  <tr>
+    <td align="right" valign="top">{$lang.ipphone}:</td>
+    <td><input type="text" class="input" name="entry[ipphone]" value="{$entry.ipphone|escape}"></td>
+  </tr>
+  <tr>
+    <td align="right" valign="top">{$lang.instantmessenger}:</td>
+    <td><input type="text" class="input" name="entry[instantmessenger]" value="{$entry.instantmessenger|escape}"></td>
+  </tr>
+  <tr>
+    <td align="right" valign="top">{$lang.domain}:</td>
+    <td><input type="text" class="input" name="entry[domain]" value="{$entry.domain|escape}"></td>
+  </tr>
+  <tr>
+    <td align="right" valign="top">{$lang.certificate}:</td>
+    <td>
+      <textarea name="entry[certificate]" rows=6 cols=28 onClick="this.form.elements['entry[certificate]'].select();">{$entry.certificate|escape}</textarea>
+      <br>
+      <input type=button name=clearCert value="Clear" onClick="if (confirm('Are you sure?')) this.form.elements['entry[certificate]'].value='';">
+    </td>
+  </tr>
+  </table>
+</td>
+<td width="50%" valign="top" align="center">
+  <table>
+  <tr>
+    <td colspan="2"><b>{$lang.moreopenxchange}</b></td>
+  </tr>
+  <tr>
+    <td align="right" valign="top">{$lang.country}:</td>
+    <td>
+      <select name="entry[country][]" class="input">
+        <option value="">--- {$lang.select} ---</option>
+        {html_options values=$country output=$country selected=$entry.country}
+      </select><br>
+      <input type="text" class="inputbr" name="entry[country][]"><br>
+    </td>
+  </tr>
+  <tr>
+    <td align="right" valign="top">{$lang.timezone}:</td>
+    <td>
+      <select name="entry[timezone][]" class="input">
+        <option value="">--- {$lang.select} ---</option>
+        {html_options values=$timezone output=$timezone selected=$entry.timezone}
+      </select><br>
+      <input type="text" class="inputbr" name="entry[timezone][]"><br>
+    </td>
+  </tr>
+  <tr>
+    <td align="right" valign="top">{$lang.categories}:</td>
+    <td>
+      <select name="entry[categories][]" size="5" class="input" multiple="multiple">
+        {html_options values=$categories output=$categories selected=$entry.categories}
+      </select><br>
+      <input type="text" class="inputbr" name="entry[categories][]"><br>
+      <input type="text" class="inputbr" name="entry[categories][]"><br>
+    </td>
+
+  </tr>
+</table>
+</td>
+</tr>
diff --git a/templates/openxchange_show.tpl b/templates/openxchange_show.tpl
new file mode 100644 (file)
index 0000000..6f50348
--- /dev/null
@@ -0,0 +1,72 @@
+<table width="100%">
+  <tr>
+      <td width="50%" valign="top">
+       <b>{$lang.openxchange}</b>
+<dl><dd>
+  <table>
+    {if $entry.birthday}
+    <tr>
+      <td align="right">{$lang.birthday}:</td>
+      <td>{$entry.birthday}</td>
+    </tr>
+    {/if}
+    {if $entry.ipphone}
+    <tr>
+      <td align="right">{$lang.ipphone}:</td>
+      <td>{$entry.ipphone}</td>
+    </tr>
+    {/if}
+    {if $entry.instantmessenger}
+    <tr>
+      <td align="right">{$lang.instantmessenger}:</td>
+      <td>{$entry.instantmessenger}</td>
+    </tr>
+    {/if}
+    {if $entry.domain}
+    <tr>
+      <td align="right">{$lang.domain}:</td>
+      <td>{$entry.domain}</td>
+    </tr>
+    {/if}
+    {if $entry.certificate}
+    <tr>
+      <td align="right">{$lang.certificate}:</td>
+      <td><form>
+        <textarea rows=3 cols=28 name='certificate' onClick='this.form.certificate.select();'>{$entry.certificate}</textarea>
+       </form></td>
+    </tr>
+    {/if}
+  </table>
+</dd></dl>
+</td>
+      <td width="50%" valign="top">
+       <b>{$lang.moreopenxchange}</b>
+<dl><dd>
+<table >
+    {if $entry.country}
+    <tr>
+      <td align="right">{$lang.country}:</td>
+      <td>{$entry.country}</td>
+    </tr>
+    {/if}
+    {if $entry.timezone}
+    <tr>
+      <td align="right">{$lang.timezone}:</td>
+      <td>{$entry.timezone}</td>
+    </tr>
+    {/if}
+    {if $entry.categories}
+    <tr>
+      <td valign="top" align="right">{$lang.categories}:</td>
+      <td>
+        {foreach from=$entry.categories item=categories}
+          {$categories}<br>
+        {/foreach}
+      </td>
+    </tr>
+    {/if}
+</table>
+</dd></dl>
+      </td>
+  </tr>
+</table>