| 94 | jpm | 1 | <?php
 | 
        
           |  |  | 2 | //
 | 
        
           |  |  | 3 | // +----------------------------------------------------------------------+
 | 
        
           |  |  | 4 | // | PHP Version 4                                                        |
 | 
        
           |  |  | 5 | // +----------------------------------------------------------------------+
 | 
        
           |  |  | 6 | // | Copyright (c) 1997-2003 The PHP Group                                |
 | 
        
           |  |  | 7 | // +----------------------------------------------------------------------+
 | 
        
           |  |  | 8 | // | This source file is subject to version 2.02 of the PHP license,      |
 | 
        
           |  |  | 9 | // | that is bundled with this package in the file LICENSE, and is        |
 | 
        
           |  |  | 10 | // | available at through the world-wide-web at                           |
 | 
        
           |  |  | 11 | // | http://www.php.net/license/2_02.txt.                                 |
 | 
        
           |  |  | 12 | // | If you did not receive a copy of the PHP license and are unable to   |
 | 
        
           |  |  | 13 | // | obtain it through the world-wide-web, please send a note to          |
 | 
        
           |  |  | 14 | // | license@php.net so we can mail you a copy immediately.               |
 | 
        
           |  |  | 15 | // +----------------------------------------------------------------------+
 | 
        
           |  |  | 16 | // | Authors: Jan Wagner <wagner@netsols.de>                              |
 | 
        
           |  |  | 17 | // +----------------------------------------------------------------------+
 | 
        
           |  |  | 18 | //
 | 
        
           |  |  | 19 | // $Id: LDAP.php,v 1.14 2003/06/02 16:55:10 mj Exp $
 | 
        
           |  |  | 20 | //
 | 
        
           |  |  | 21 |   | 
        
           |  |  | 22 | require_once "Auth/Container.php";
 | 
        
           |  |  | 23 | require_once "PEAR.php";
 | 
        
           |  |  | 24 |   | 
        
           |  |  | 25 | /**
 | 
        
           |  |  | 26 |  * Storage driver for fetching login data from LDAP
 | 
        
           |  |  | 27 |  *
 | 
        
           |  |  | 28 |  * This class is heavily based on the DB and File containers. By default it
 | 
        
           |  |  | 29 |  * connects to localhost:389 and searches for uid=$username with the scope
 | 
        
           |  |  | 30 |  * "sub". If no search base is specified, it will try to determine it via
 | 
        
           |  |  | 31 |  * the namingContexts attribute. It takes its parameters in a hash, connects
 | 
        
           |  |  | 32 |  * to the ldap server, binds anonymously, searches for the user, and tries
 | 
        
           |  |  | 33 |  * to bind as the user with the supplied password. When a group was set, it
 | 
        
           |  |  | 34 |  * will look for group membership of the authenticated user. If all goes
 | 
        
           |  |  | 35 |  * well the authentication was successful.
 | 
        
           |  |  | 36 |  *
 | 
        
           |  |  | 37 |  * Parameters:
 | 
        
           |  |  | 38 |  *
 | 
        
           |  |  | 39 |  * host:        localhost (default), ldap.netsols.de or 127.0.0.1
 | 
        
           |  |  | 40 |  * port:        389 (default) or 636 or whereever your server runs
 | 
        
           |  |  | 41 |  * url:         ldap://localhost:389/
 | 
        
           |  |  | 42 |  *              useful for ldaps://, works only with openldap2 ?
 | 
        
           |  |  | 43 |  *              it will be preferred over host and port
 | 
        
           |  |  | 44 |  * binddn:      If set, searching for user will be done after binding
 | 
        
           |  |  | 45 |  *              as this user, if not set the bind will be anonymous.
 | 
        
           |  |  | 46 |  *              This is reported to make the container work with MS
 | 
        
           |  |  | 47 |  *              Active Directory, but should work with any server that
 | 
        
           |  |  | 48 |  *              is configured this way.
 | 
        
           |  |  | 49 |  *              This has to be a complete dn for now (basedn and
 | 
        
           |  |  | 50 |  *              userdn will not be appended).
 | 
        
           |  |  | 51 |  * bindpw:      The password to use for binding with binddn
 | 
        
           |  |  | 52 |  * scope:       one, sub (default), or base
 | 
        
           |  |  | 53 |  * basedn:      the base dn of your server
 | 
        
           |  |  | 54 |  * userdn:      gets prepended to basedn when searching for user
 | 
        
           |  |  | 55 |  * userattr:    the user attribute to search for (default: uid)
 | 
        
           |  |  | 56 |  * useroc:      objectclass of user (for the search filter)
 | 
        
           |  |  | 57 |  *              (default: posixAccount)
 | 
        
           |  |  | 58 |  * groupdn:     gets prepended to basedn when searching for group
 | 
        
           |  |  | 59 |  * groupattr  : the group attribute to search for (default: cn)
 | 
        
           |  |  | 60 |  * groupoc    : objectclass of group (for the search filter)
 | 
        
           |  |  | 61 |  *              (default: groupOfUniqueNames)
 | 
        
           |  |  | 62 |  * memberattr : the attribute of the group object where the user dn
 | 
        
           |  |  | 63 |  *              may be found (default: uniqueMember)
 | 
        
           |  |  | 64 |  * memberisdn:  whether the memberattr is the dn of the user (default)
 | 
        
           |  |  | 65 |  *              or the value of userattr (usually uid)
 | 
        
           |  |  | 66 |  * group:       the name of group to search for
 | 
        
           |  |  | 67 |  * debug:       Enable/Disable debugging output (default: false)
 | 
        
           |  |  | 68 |  *
 | 
        
           |  |  | 69 |  * To use this storage container, you have to use the following syntax:
 | 
        
           |  |  | 70 |  *
 | 
        
           |  |  | 71 |  * <?php
 | 
        
           |  |  | 72 |  * ...
 | 
        
           |  |  | 73 |  *
 | 
        
           |  |  | 74 |  * $a = new Auth("LDAP", array(
 | 
        
           |  |  | 75 |  *       'host' => 'localhost',
 | 
        
           |  |  | 76 |  *       'port' => '389',
 | 
        
           |  |  | 77 |  *       'basedn' => 'o=netsols,c=de',
 | 
        
           |  |  | 78 |  *       'userattr' => 'uid'
 | 
        
           |  |  | 79 |  *       'binddn' => 'cn=admin,o=netsols,c=de',
 | 
        
           |  |  | 80 |  *       'bindpw' => 'password'));
 | 
        
           |  |  | 81 |  *
 | 
        
           |  |  | 82 |  * $a2 = new Auth('LDAP', array(
 | 
        
           |  |  | 83 |  *       'url' => 'ldaps://ldap.netsols.de',
 | 
        
           |  |  | 84 |  *       'basedn' => 'o=netsols,c=de',
 | 
        
           |  |  | 85 |  *       'scope' => 'one',
 | 
        
           |  |  | 86 |  *       'userdn' => 'ou=People',
 | 
        
           |  |  | 87 |  *       'groupdn' => 'ou=Groups',
 | 
        
           |  |  | 88 |  *       'groupoc' => 'posixGroup',
 | 
        
           |  |  | 89 |  *       'memberattr' => 'memberUid',
 | 
        
           |  |  | 90 |  *       'memberisdn' => false,
 | 
        
           |  |  | 91 |  *       'group' => 'admin'
 | 
        
           |  |  | 92 |  *       ));
 | 
        
           |  |  | 93 |  *
 | 
        
           |  |  | 94 |  * $a3 = new Auth('LDAP', array(
 | 
        
           |  |  | 95 |  *         'host' => 'ad.netsols.de',
 | 
        
           |  |  | 96 |  *         'basedn' => 'dc=netsols,dc=de',
 | 
        
           |  |  | 97 |  *         'userdn' => 'ou=Users',
 | 
        
           |  |  | 98 |  *         'binddn' => 'cn=Jan Wagner,ou=Users,dc=netsols,dc=de',
 | 
        
           |  |  | 99 |  *         'bindpw' => '*******',
 | 
        
           |  |  | 100 |  *         'userattr' => 'samAccountName',
 | 
        
           |  |  | 101 |  *         'useroc' => 'user',
 | 
        
           |  |  | 102 |  *          'debug' => true
 | 
        
           |  |  | 103 |  *         ));
 | 
        
           |  |  | 104 |  *
 | 
        
           |  |  | 105 |  * The parameter values have to correspond
 | 
        
           |  |  | 106 |  * to the ones for your LDAP server of course.
 | 
        
           |  |  | 107 |  *
 | 
        
           |  |  | 108 |  * When talking to a Microsoft ActiveDirectory server you have to
 | 
        
           |  |  | 109 |  * use 'samaccountname' as the 'userattr' and follow special rules
 | 
        
           |  |  | 110 |  * to translate the ActiveDirectory directory names into 'basedn'.
 | 
        
           |  |  | 111 |  * The 'basedn' for the default 'Users' folder on an ActiveDirectory
 | 
        
           |  |  | 112 |  * server for the ActiveDirectory Domain (which is not related to
 | 
        
           |  |  | 113 |  * its DNS name) "win2000.example.org" would be:
 | 
        
           |  |  | 114 |  * "CN=Users, DC=win2000, DC=example, DC=org'
 | 
        
           |  |  | 115 |  * where every component of the domain name becomes a DC attribute
 | 
        
           |  |  | 116 |  * of its own. If you want to use a custom users folder you have to
 | 
        
           |  |  | 117 |  * replace "CN=Users" with a sequence of "OU" attributes that specify
 | 
        
           |  |  | 118 |  * the path to your custom folder in reverse order.
 | 
        
           |  |  | 119 |  * So the ActiveDirectory folder
 | 
        
           |  |  | 120 |  *   "win2000.example.org\Custom\Accounts"
 | 
        
           |  |  | 121 |  * would become
 | 
        
           |  |  | 122 |  *   "OU=Accounts, OU=Custom, DC=win2000, DC=example, DC=org'
 | 
        
           |  |  | 123 |  *
 | 
        
           |  |  | 124 |  * It seems that binding anonymously to an Active Directory
 | 
        
           |  |  | 125 |  * is not allowed, so you have to set binddn and bindpw for
 | 
        
           |  |  | 126 |  * user searching,
 | 
        
           |  |  | 127 |  *
 | 
        
           |  |  | 128 |  * Example a3 shows a tested example for connenction to Windows 2000
 | 
        
           |  |  | 129 |  * Active Directory
 | 
        
           |  |  | 130 |  *
 | 
        
           |  |  | 131 |  * @author   Jan Wagner <wagner@netsols.de>
 | 
        
           |  |  | 132 |  * @package  Auth
 | 
        
           |  |  | 133 |  * @version  $Revision: 1.14 $
 | 
        
           |  |  | 134 |  */
 | 
        
           |  |  | 135 | class Auth_Container_LDAP extends Auth_Container
 | 
        
           |  |  | 136 | {
 | 
        
           |  |  | 137 |     /**
 | 
        
           |  |  | 138 |      * Options for the class
 | 
        
           |  |  | 139 |      * @var array
 | 
        
           |  |  | 140 |      */
 | 
        
           |  |  | 141 |     var $options = array();
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 |     /**
 | 
        
           |  |  | 144 |      * Connection ID of LDAP Link
 | 
        
           |  |  | 145 |      * @var string
 | 
        
           |  |  | 146 |      */
 | 
        
           |  |  | 147 |     var $conn_id = false;
 | 
        
           |  |  | 148 |   | 
        
           |  |  | 149 |     /**
 | 
        
           |  |  | 150 |      * LDAP search function to use
 | 
        
           |  |  | 151 |      * @var string
 | 
        
           |  |  | 152 |      */
 | 
        
           |  |  | 153 |     var $ldap_search_func;
 | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 |     /**
 | 
        
           |  |  | 156 |      * Constructor of the container class
 | 
        
           |  |  | 157 |      *
 | 
        
           |  |  | 158 |      * @param  $params, associative hash with host,port,basedn and userattr key
 | 
        
           |  |  | 159 |      * @return object Returns an error object if something went wrong
 | 
        
           |  |  | 160 |      */
 | 
        
           |  |  | 161 |     function Auth_Container_LDAP($params)
 | 
        
           |  |  | 162 |     {
 | 
        
           |  |  | 163 |         $this->_setDefaults();
 | 
        
           |  |  | 164 |   | 
        
           |  |  | 165 |         if (is_array($params)) {
 | 
        
           |  |  | 166 |             $this->_parseOptions($params);
 | 
        
           |  |  | 167 |         }
 | 
        
           |  |  | 168 |     }
 | 
        
           |  |  | 169 |   | 
        
           |  |  | 170 |     // }}}
 | 
        
           |  |  | 171 |     // {{{ _connect()
 | 
        
           |  |  | 172 |   | 
        
           |  |  | 173 |     /**
 | 
        
           |  |  | 174 |      * Connect to the LDAP server using the global options
 | 
        
           |  |  | 175 |      *
 | 
        
           |  |  | 176 |      * @access private
 | 
        
           |  |  | 177 |      * @return object  Returns a PEAR error object if an error occurs.
 | 
        
           |  |  | 178 |      */
 | 
        
           |  |  | 179 |     function _connect()
 | 
        
           |  |  | 180 |     {
 | 
        
           |  |  | 181 |         // connect
 | 
        
           |  |  | 182 |         if (isset($this->options['url']) && $this->options['url'] != '') {
 | 
        
           |  |  | 183 |             $this->_debug('Connecting with URL', __LINE__);
 | 
        
           |  |  | 184 |             $conn_params = array($this->options['url']);
 | 
        
           |  |  | 185 |         } else {
 | 
        
           |  |  | 186 |             $this->_debug('Connecting with host:port', __LINE__);
 | 
        
           |  |  | 187 |             $conn_params = array($this->options['host'], $this->options['port']);
 | 
        
           |  |  | 188 |         }
 | 
        
           |  |  | 189 |   | 
        
           |  |  | 190 |         if(($this->conn_id = @call_user_func_array('ldap_connect', $conn_params)) === false) {
 | 
        
           |  |  | 191 |             return PEAR::raiseError('Auth_Container_LDAP: Could not connect to server.', 41, PEAR_ERROR_DIE);
 | 
        
           |  |  | 192 |         }
 | 
        
           |  |  | 193 |         $this->_debug('Successfully connected to server', __LINE__);
 | 
        
           |  |  | 194 |   | 
        
           |  |  | 195 |         // try switchig to LDAPv3
 | 
        
           |  |  | 196 |         $ver = 0;
 | 
        
           |  |  | 197 |         if(@ldap_get_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, $ver) && $ver >= 2) {
 | 
        
           |  |  | 198 |             $this->_debug('Switching to LDAPv3', __LINE__);
 | 
        
           |  |  | 199 |             @ldap_set_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, 3);
 | 
        
           |  |  | 200 |         }
 | 
        
           |  |  | 201 |   | 
        
           |  |  | 202 |         // bind with credentials or anonymously
 | 
        
           |  |  | 203 |         if($this->options['binddn'] && $this->options['bindpw']) {
 | 
        
           |  |  | 204 |             $this->_debug('Binding with credentials', __LINE__);
 | 
        
           |  |  | 205 |             $bind_params = array($this->conn_id, $this->options['binddn'], $this->options['bindpw']);
 | 
        
           |  |  | 206 |         } else {
 | 
        
           |  |  | 207 |             $this->_debug('Binding anonymously', __LINE__);
 | 
        
           |  |  | 208 |             $bind_params = array($this->conn_id);
 | 
        
           |  |  | 209 |         }
 | 
        
           |  |  | 210 |   | 
        
           |  |  | 211 |         // bind for searching
 | 
        
           |  |  | 212 |         if ((@call_user_func_array('ldap_bind', $bind_params)) == false) {
 | 
        
           |  |  | 213 |             $this->_debug();
 | 
        
           |  |  | 214 |             $this->_disconnect();
 | 
        
           |  |  | 215 |             return PEAR::raiseError("Auth_Container_LDAP: Could not bind to LDAP server.", 41, PEAR_ERROR_DIE);
 | 
        
           |  |  | 216 |         }
 | 
        
           |  |  | 217 |         $this->_debug('Binding was successful', __LINE__);
 | 
        
           |  |  | 218 |     }
 | 
        
           |  |  | 219 |   | 
        
           |  |  | 220 |     /**
 | 
        
           |  |  | 221 |      * Disconnects (unbinds) from ldap server
 | 
        
           |  |  | 222 |      *
 | 
        
           |  |  | 223 |      * @access private
 | 
        
           |  |  | 224 |      */
 | 
        
           |  |  | 225 |     function _disconnect()
 | 
        
           |  |  | 226 |     {
 | 
        
           |  |  | 227 |         if($this->_isValidLink()) {
 | 
        
           |  |  | 228 |             $this->_debug('disconnecting from server');
 | 
        
           |  |  | 229 |             @ldap_unbind($this->conn_id);
 | 
        
           |  |  | 230 |         }
 | 
        
           |  |  | 231 |     }
 | 
        
           |  |  | 232 |   | 
        
           |  |  | 233 |     /**
 | 
        
           |  |  | 234 |      * Tries to find Basedn via namingContext Attribute
 | 
        
           |  |  | 235 |      *
 | 
        
           |  |  | 236 |      * @access private
 | 
        
           |  |  | 237 |      */
 | 
        
           |  |  | 238 |     function _getBaseDN()
 | 
        
           |  |  | 239 |     {
 | 
        
           |  |  | 240 |         if ($this->options['basedn'] == "" && $this->_isValidLink()) {
 | 
        
           |  |  | 241 |             $this->_debug("basedn not set, searching via namingContexts.", __LINE__);
 | 
        
           |  |  | 242 |   | 
        
           |  |  | 243 |             $result_id = @ldap_read($this->conn_id, "", "(objectclass=*)", array("namingContexts"));
 | 
        
           |  |  | 244 |   | 
        
           |  |  | 245 |             if (ldap_count_entries($this->conn_id, $result_id) == 1) {
 | 
        
           |  |  | 246 |   | 
        
           |  |  | 247 |                 $this->_debug("got result for namingContexts", __LINE__);
 | 
        
           |  |  | 248 |   | 
        
           |  |  | 249 |                 $entry_id = ldap_first_entry($this->conn_id, $result_id);
 | 
        
           |  |  | 250 |                 $attrs = ldap_get_attributes($this->conn_id, $entry_id);
 | 
        
           |  |  | 251 |                 $basedn = $attrs['namingContexts'][0];
 | 
        
           |  |  | 252 |   | 
        
           |  |  | 253 |                 if ($basedn != "") {
 | 
        
           |  |  | 254 |                     $this->_debug("result for namingContexts was $basedn", __LINE__);
 | 
        
           |  |  | 255 |                     $this->options['basedn'] = $basedn;
 | 
        
           |  |  | 256 |                 }
 | 
        
           |  |  | 257 |             }
 | 
        
           |  |  | 258 |             ldap_free_result($result_id);
 | 
        
           |  |  | 259 |         }
 | 
        
           |  |  | 260 |   | 
        
           |  |  | 261 |         // if base ist still not set, raise error
 | 
        
           |  |  | 262 |         if ($this->options['basedn'] == "") {
 | 
        
           |  |  | 263 |             return PEAR::raiseError("Auth_Container_LDAP: LDAP search base not specified!", 41, PEAR_ERROR_DIE);
 | 
        
           |  |  | 264 |         }
 | 
        
           |  |  | 265 |         return true;
 | 
        
           |  |  | 266 |     }
 | 
        
           |  |  | 267 |   | 
        
           |  |  | 268 |     /**
 | 
        
           |  |  | 269 |      * determines whether there is a valid ldap conenction or not
 | 
        
           |  |  | 270 |      *
 | 
        
           |  |  | 271 |      * @accessd private
 | 
        
           |  |  | 272 |      * @return boolean
 | 
        
           |  |  | 273 |      */
 | 
        
           |  |  | 274 |     function _isValidLink()
 | 
        
           |  |  | 275 |     {
 | 
        
           |  |  | 276 |         if(is_resource($this->conn_id)) {
 | 
        
           |  |  | 277 |             if(get_resource_type($this->conn_id) == 'ldap link') {
 | 
        
           |  |  | 278 |                 return true;
 | 
        
           |  |  | 279 |             }
 | 
        
           |  |  | 280 |         }
 | 
        
           |  |  | 281 |         return false;
 | 
        
           |  |  | 282 |     }
 | 
        
           |  |  | 283 |   | 
        
           |  |  | 284 |     /**
 | 
        
           |  |  | 285 |      * Set some default options
 | 
        
           |  |  | 286 |      *
 | 
        
           |  |  | 287 |      * @access private
 | 
        
           |  |  | 288 |      */
 | 
        
           |  |  | 289 |     function _setDefaults()
 | 
        
           |  |  | 290 |     {
 | 
        
           |  |  | 291 |         $this->options['host']        = 'localhost';
 | 
        
           |  |  | 292 |         $this->options['port']        = '389';
 | 
        
           |  |  | 293 |         $this->options['binddn']      = '';
 | 
        
           |  |  | 294 |         $this->options['bindpw']      = '';
 | 
        
           |  |  | 295 |         $this->options['scope']       = 'sub';
 | 
        
           |  |  | 296 |         $this->options['basedn']      = '';
 | 
        
           |  |  | 297 |         $this->options['userdn']      = '';
 | 
        
           |  |  | 298 |         $this->options['userattr']    = "uid";
 | 
        
           |  |  | 299 |         $this->options['useroc']      = 'posixAccount';
 | 
        
           |  |  | 300 |         $this->options['groupdn']     = '';
 | 
        
           |  |  | 301 |         $this->options['groupattr']   = 'cn';
 | 
        
           |  |  | 302 |         $this->options['groupoc']     = 'groupOfUniqueNames';
 | 
        
           |  |  | 303 |         $this->options['memberattr']  = 'uniqueMember';
 | 
        
           |  |  | 304 |         $this->options['memberisdn']  = true;
 | 
        
           |  |  | 305 |         $this->options['debug']       = false;
 | 
        
           |  |  | 306 |     }
 | 
        
           |  |  | 307 |   | 
        
           |  |  | 308 |     /**
 | 
        
           |  |  | 309 |      * Parse options passed to the container class
 | 
        
           |  |  | 310 |      *
 | 
        
           |  |  | 311 |      * @access private
 | 
        
           |  |  | 312 |      * @param  array
 | 
        
           |  |  | 313 |      */
 | 
        
           |  |  | 314 |     function _parseOptions($array)
 | 
        
           |  |  | 315 |     {
 | 
        
           |  |  | 316 |         foreach ($array as $key => $value) {
 | 
        
           |  |  | 317 |             $this->options[$key] = $value;
 | 
        
           |  |  | 318 |         }
 | 
        
           |  |  | 319 |   | 
        
           |  |  | 320 |         // get the according search function for selected scope
 | 
        
           |  |  | 321 |         switch($this->options['scope']) {
 | 
        
           |  |  | 322 |         case 'one':
 | 
        
           |  |  | 323 |             $this->ldap_search_func = 'ldap_list';
 | 
        
           |  |  | 324 |             break;
 | 
        
           |  |  | 325 |         case 'base':
 | 
        
           |  |  | 326 |             $this->ldap_search_func = 'ldap_read';
 | 
        
           |  |  | 327 |             break;
 | 
        
           |  |  | 328 |         default:
 | 
        
           |  |  | 329 |             $this->ldap_search_func = 'ldap_search';
 | 
        
           |  |  | 330 |             break;
 | 
        
           |  |  | 331 |         }
 | 
        
           |  |  | 332 |         $this->_debug("LDAP search function will be: {$this->ldap_search_func}", __LINE__);
 | 
        
           |  |  | 333 |     }
 | 
        
           |  |  | 334 |   | 
        
           |  |  | 335 |     /**
 | 
        
           |  |  | 336 |      * Fetch data from LDAP server
 | 
        
           |  |  | 337 |      *
 | 
        
           |  |  | 338 |      * Searches the LDAP server for the given username/password
 | 
        
           |  |  | 339 |      * combination.
 | 
        
           |  |  | 340 |      *
 | 
        
           |  |  | 341 |      * @param  string Username
 | 
        
           |  |  | 342 |      * @param  string Password
 | 
        
           |  |  | 343 |      * @return boolean
 | 
        
           |  |  | 344 |      */
 | 
        
           |  |  | 345 |     function fetchData($username, $password)
 | 
        
           |  |  | 346 |     {
 | 
        
           |  |  | 347 |   | 
        
           |  |  | 348 |         $this->_connect();
 | 
        
           |  |  | 349 |         $this->_getBaseDN();
 | 
        
           |  |  | 350 |   | 
        
           |  |  | 351 |         // make search filter
 | 
        
           |  |  | 352 |         $filter = sprintf('(&(objectClass=%s)(%s=%s))', $this->options['useroc'], $this->options['userattr'], $username);
 | 
        
           |  |  | 353 |   | 
        
           |  |  | 354 |         // make search base dn
 | 
        
           |  |  | 355 |         $search_basedn = $this->options['userdn'];
 | 
        
           |  |  | 356 |         if ($search_basedn != '' && substr($search_basedn, -1) != ',') {
 | 
        
           |  |  | 357 |             $search_basedn .= ',';
 | 
        
           |  |  | 358 |         }
 | 
        
           |  |  | 359 |         $search_basedn .= $this->options['basedn'];
 | 
        
           |  |  | 360 |   | 
        
           |  |  | 361 |         // make functions params array
 | 
        
           |  |  | 362 |         $func_params = array($this->conn_id, $search_basedn, $filter, array($this->options['userattr']));
 | 
        
           |  |  | 363 |   | 
        
           |  |  | 364 |         $this->_debug("Searching with $filter in $search_basedn", __LINE__);
 | 
        
           |  |  | 365 |   | 
        
           |  |  | 366 |         // search
 | 
        
           |  |  | 367 |         if (($result_id = @call_user_func_array($this->ldap_search_func, $func_params)) == false) {
 | 
        
           |  |  | 368 |             $this->_debug('User not found', __LINE__);
 | 
        
           |  |  | 369 |         } elseif (ldap_count_entries($this->conn_id, $result_id) == 1) { // did we get just one entry?
 | 
        
           |  |  | 370 |   | 
        
           |  |  | 371 |             $this->_debug('User was found', __LINE__);
 | 
        
           |  |  | 372 |   | 
        
           |  |  | 373 |             // then get the user dn
 | 
        
           |  |  | 374 |             $entry_id = ldap_first_entry($this->conn_id, $result_id);
 | 
        
           |  |  | 375 |             $user_dn  = ldap_get_dn($this->conn_id, $entry_id);
 | 
        
           |  |  | 376 |   | 
        
           |  |  | 377 |             ldap_free_result($result_id);
 | 
        
           |  |  | 378 |   | 
        
           |  |  | 379 |             // need to catch an empty password as openldap seems to return TRUE
 | 
        
           |  |  | 380 |             // if anonymous binding is allowed
 | 
        
           |  |  | 381 |             if ($password != "") {
 | 
        
           |  |  | 382 |                 $this->_debug("Bind as $user_dn", __LINE__);
 | 
        
           |  |  | 383 |   | 
        
           |  |  | 384 |                 // try binding as this user with the supplied password
 | 
        
           |  |  | 385 |                 if (@ldap_bind($this->conn_id, $user_dn, $password)) {
 | 
        
           |  |  | 386 |                     $this->_debug('Bind successful', __LINE__);
 | 
        
           |  |  | 387 |   | 
        
           |  |  | 388 |                     // check group if appropiate
 | 
        
           |  |  | 389 |                     if(isset($this->options['group'])) {
 | 
        
           |  |  | 390 |                         // decide whether memberattr value is a dn or the username
 | 
        
           |  |  | 391 |                         $this->_debug('Checking group membership', __LINE__);
 | 
        
           |  |  | 392 |                         return $this->checkGroup(($this->options['memberisdn']) ? $user_dn : $username);
 | 
        
           |  |  | 393 |                     } else {
 | 
        
           |  |  | 394 |                         $this->_debug('Authenticated', __LINE__);
 | 
        
           |  |  | 395 |                         $this->_disconnect();
 | 
        
           |  |  | 396 |                         return true; // user authenticated
 | 
        
           |  |  | 397 |                     } // checkGroup
 | 
        
           |  |  | 398 |                 } // bind
 | 
        
           |  |  | 399 |             } // non-empty password
 | 
        
           |  |  | 400 |         } // one entry
 | 
        
           |  |  | 401 |         // default
 | 
        
           |  |  | 402 |         $this->_debug('NOT authenticated!', __LINE__);
 | 
        
           |  |  | 403 |         $this->_disconnect();
 | 
        
           |  |  | 404 |         return false;
 | 
        
           |  |  | 405 |     }
 | 
        
           |  |  | 406 |   | 
        
           |  |  | 407 |     /**
 | 
        
           |  |  | 408 |      * Validate group membership
 | 
        
           |  |  | 409 |      *
 | 
        
           |  |  | 410 |      * Searches the LDAP server for group membership of the
 | 
        
           |  |  | 411 |      * authenticated user
 | 
        
           |  |  | 412 |      *
 | 
        
           |  |  | 413 |      * @param  string Distinguished Name of the authenticated User
 | 
        
           |  |  | 414 |      * @return boolean
 | 
        
           |  |  | 415 |      */
 | 
        
           |  |  | 416 |     function checkGroup($user)
 | 
        
           |  |  | 417 |     {
 | 
        
           |  |  | 418 |         // make filter
 | 
        
           |  |  | 419 |         $filter = sprintf('(&(%s=%s)(objectClass=%s)(%s=%s))',
 | 
        
           |  |  | 420 |                           $this->options['groupattr'],
 | 
        
           |  |  | 421 |                           $this->options['group'],
 | 
        
           |  |  | 422 |                           $this->options['groupoc'],
 | 
        
           |  |  | 423 |                           $this->options['memberattr'],
 | 
        
           |  |  | 424 |                           $user
 | 
        
           |  |  | 425 |                           );
 | 
        
           |  |  | 426 |   | 
        
           |  |  | 427 |         // make search base dn
 | 
        
           |  |  | 428 |         $search_basedn = $this->options['groupdn'];
 | 
        
           |  |  | 429 |         if($search_basedn != '' && substr($search_basedn, -1) != ',') {
 | 
        
           |  |  | 430 |             $search_basedn .= ',';
 | 
        
           |  |  | 431 |         }
 | 
        
           |  |  | 432 |         $search_basedn .= $this->options['basedn'];
 | 
        
           |  |  | 433 |   | 
        
           |  |  | 434 |         $func_params = array($this->conn_id, $search_basedn, $filter, array($this->options['memberattr']));
 | 
        
           |  |  | 435 |   | 
        
           |  |  | 436 |         $this->_debug("Searching with $filter in $search_basedn", __LINE__);
 | 
        
           |  |  | 437 |   | 
        
           |  |  | 438 |         // search
 | 
        
           |  |  | 439 |         if(($result_id = @call_user_func_array($this->ldap_search_func, $func_params)) != false) {
 | 
        
           |  |  | 440 |             if(ldap_count_entries($this->conn_id, $result_id) == 1) {
 | 
        
           |  |  | 441 |                 ldap_free_result($result_id);
 | 
        
           |  |  | 442 |                 $this->_debug('User is member of group', __LINE__);
 | 
        
           |  |  | 443 |                 $this->_disconnect();
 | 
        
           |  |  | 444 |                 return true;
 | 
        
           |  |  | 445 |             }
 | 
        
           |  |  | 446 |         }
 | 
        
           |  |  | 447 |   | 
        
           |  |  | 448 |         // default
 | 
        
           |  |  | 449 |         $this->_debug('User is NOT member of group', __LINE__);
 | 
        
           |  |  | 450 |         $this->_disconnect();
 | 
        
           |  |  | 451 |         return false;
 | 
        
           |  |  | 452 |     }
 | 
        
           |  |  | 453 |   | 
        
           |  |  | 454 |     /**
 | 
        
           |  |  | 455 |      * Outputs debugging messages
 | 
        
           |  |  | 456 |      *
 | 
        
           |  |  | 457 |      * @access private
 | 
        
           |  |  | 458 |      * @param string Debugging Message
 | 
        
           |  |  | 459 |      * @param integer Line number
 | 
        
           |  |  | 460 |      */
 | 
        
           |  |  | 461 |     function _debug($msg = '', $line = 0)
 | 
        
           |  |  | 462 |     {
 | 
        
           |  |  | 463 |         if($this->options['debug'] === true) {
 | 
        
           |  |  | 464 |             if($msg == '' && $this->_isValidLink()) {
 | 
        
           |  |  | 465 |                 $msg = 'LDAP_Error: ' . @ldap_err2str(@ldap_errno($this->_conn_id));
 | 
        
           |  |  | 466 |             }
 | 
        
           |  |  | 467 |             print("$line: $msg <br />");
 | 
        
           |  |  | 468 |         }
 | 
        
           |  |  | 469 |     }
 | 
        
           |  |  | 470 | }
 | 
        
           |  |  | 471 |   | 
        
           |  |  | 472 | ?>
 |