Subversion Repositories Applications.papyrus

Rev

Rev 1173 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1173 Rev 1713
1
<?php
1
<?php
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
3
 
3
 
4
/**
4
/**
5
 * Storage driver for use against an LDAP server
5
 * Storage driver for use against an LDAP server
6
 *
6
 *
7
 * PHP versions 4 and 5
7
 * PHP versions 4 and 5
8
 *
8
 *
9
 * LICENSE: This source file is subject to version 3.01 of the PHP license
9
 * LICENSE: This source file is subject to version 3.01 of the PHP license
10
 * that is available through the world-wide-web at the following URI:
10
 * that is available through the world-wide-web at the following URI:
11
 * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
11
 * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
12
 * the PHP License and are unable to obtain it through the web, please
12
 * the PHP License and are unable to obtain it through the web, please
13
 * send a note to license@php.net so we can mail you a copy immediately.
13
 * send a note to license@php.net so we can mail you a copy immediately.
14
 *
14
 *
15
 * @category   Authentication
15
 * @category   Authentication
16
 * @package    Auth
16
 * @package    Auth
17
 * @author     Jan Wagner <wagner@netsols.de> 
17
 * @author     Jan Wagner <wagner@netsols.de>
18
 * @author     Adam Ashley <aashley@php.net>
18
 * @author     Adam Ashley <aashley@php.net>
19
 * @author     Hugues Peeters <hugues.peeters@claroline.net>
19
 * @author     Hugues Peeters <hugues.peeters@claroline.net>
20
 * @copyright  2001-2006 The PHP Group
20
 * @copyright  2001-2006 The PHP Group
21
 * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
21
 * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
22
 * @version    CVS: $Id: LDAP.php,v 1.2 2006-12-14 15:04:28 jp_milcent Exp $
22
 * @version    CVS: $Id: LDAP.php,v 1.3 2007-11-19 15:11:00 jp_milcent Exp $
23
 * @link       http://pear.php.net/package/Auth
23
 * @link       http://pear.php.net/package/Auth
24
 */
24
 */
25
 
25
 
26
/**
26
/**
27
 * Include Auth_Container base class
27
 * Include Auth_Container base class
28
 */
28
 */
29
require_once "Auth/Container.php";
29
require_once "Auth/Container.php";
30
/**
30
/**
31
 * Include PEAR package for error handling
31
 * Include PEAR package for error handling
32
 */
32
 */
33
require_once "PEAR.php";
33
require_once "PEAR.php";
34
 
34
 
35
/**
35
/**
36
 * Storage driver for fetching login data from LDAP
36
 * Storage driver for fetching login data from LDAP
37
 *
37
 *
38
 * This class is heavily based on the DB and File containers. By default it
38
 * This class is heavily based on the DB and File containers. By default it
39
 * connects to localhost:389 and searches for uid=$username with the scope
39
 * connects to localhost:389 and searches for uid=$username with the scope
40
 * "sub". If no search base is specified, it will try to determine it via
40
 * "sub". If no search base is specified, it will try to determine it via
41
 * the namingContexts attribute. It takes its parameters in a hash, connects
41
 * the namingContexts attribute. It takes its parameters in a hash, connects
42
 * to the ldap server, binds anonymously, searches for the user, and tries
42
 * to the ldap server, binds anonymously, searches for the user, and tries
43
 * to bind as the user with the supplied password. When a group was set, it
43
 * to bind as the user with the supplied password. When a group was set, it
44
 * will look for group membership of the authenticated user. If all goes
44
 * will look for group membership of the authenticated user. If all goes
45
 * well the authentication was successful.
45
 * well the authentication was successful.
46
 *
46
 *
47
 * Parameters:
47
 * Parameters:
48
 *
48
 *
49
 * host:        localhost (default), ldap.netsols.de or 127.0.0.1
49
 * host:        localhost (default), ldap.netsols.de or 127.0.0.1
50
 * port:        389 (default) or 636 or whereever your server runs
50
 * port:        389 (default) or 636 or whereever your server runs
51
 * url:         ldap://localhost:389/
51
 * url:         ldap://localhost:389/
52
 *              useful for ldaps://, works only with openldap2 ?
52
 *              useful for ldaps://, works only with openldap2 ?
53
 *              it will be preferred over host and port
53
 *              it will be preferred over host and port
54
 * version:     LDAP version to use, ususally 2 (default) or 3,
54
 * version:     LDAP version to use, ususally 2 (default) or 3,
55
 *              must be an integer!
55
 *              must be an integer!
56
 * referrals:   If set, determines whether the LDAP library automatically
56
 * referrals:   If set, determines whether the LDAP library automatically
57
 *              follows referrals returned by LDAP servers or not. Possible
57
 *              follows referrals returned by LDAP servers or not. Possible
58
 *              values are true (default) or false.
58
 *              values are true (default) or false.
59
 * binddn:      If set, searching for user will be done after binding
59
 * binddn:      If set, searching for user will be done after binding
60
 *              as this user, if not set the bind will be anonymous.
60
 *              as this user, if not set the bind will be anonymous.
61
 *              This is reported to make the container work with MS
61
 *              This is reported to make the container work with MS
62
 *              Active Directory, but should work with any server that
62
 *              Active Directory, but should work with any server that
63
 *              is configured this way.
63
 *              is configured this way.
64
 *              This has to be a complete dn for now (basedn and
64
 *              This has to be a complete dn for now (basedn and
65
 *              userdn will not be appended).
65
 *              userdn will not be appended).
66
 * bindpw:      The password to use for binding with binddn
66
 * bindpw:      The password to use for binding with binddn
67
 * basedn:      the base dn of your server
67
 * basedn:      the base dn of your server
68
 * userdn:      gets prepended to basedn when searching for user
68
 * userdn:      gets prepended to basedn when searching for user
69
 * userscope:   Scope for user searching: one, sub (default), or base
69
 * userscope:   Scope for user searching: one, sub (default), or base
70
 * userattr:    the user attribute to search for (default: uid)
70
 * userattr:    the user attribute to search for (default: uid)
71
 * userfilter:  filter that will be added to the search filter
71
 * userfilter:  filter that will be added to the search filter
72
 *              this way: (&(userattr=username)(userfilter))
72
 *              this way: (&(userattr=username)(userfilter))
73
 *              default: (objectClass=posixAccount)
73
 *              default: (objectClass=posixAccount)
74
 * attributes:  array of additional attributes to fetch from entry.
74
 * attributes:  array of additional attributes to fetch from entry.
75
 *              these will added to auth data and can be retrieved via
75
 *              these will added to auth data and can be retrieved via
76
 *              Auth::getAuthData(). An empty array will fetch all attributes,
76
 *              Auth::getAuthData(). An empty array will fetch all attributes,
77
 *              array('') will fetch no attributes at all (default)
77
 *              array('') will fetch no attributes at all (default)
78
 *              If you add 'dn' as a value to this array, the users DN that was
78
 *              If you add 'dn' as a value to this array, the users DN that was
79
 *              used for binding will be added to auth data as well.
79
 *              used for binding will be added to auth data as well.
80
 * attrformat:  The returned format of the additional data defined in the
80
 * attrformat:  The returned format of the additional data defined in the
81
 *              'attributes' option. Two formats are available.
81
 *              'attributes' option. Two formats are available.
82
 *              LDAP returns data formatted in a
82
 *              LDAP returns data formatted in a
83
 *              multidimensional array where each array starts with a
83
 *              multidimensional array where each array starts with a
84
 *              'count' element providing the number of attributes in the
84
 *              'count' element providing the number of attributes in the
85
 *              entry, or the number of values for attributes. When set
85
 *              entry, or the number of values for attributes. When set
86
 *              to this format, the only way to retrieve data from the
86
 *              to this format, the only way to retrieve data from the
87
 *              Auth object is by calling getAuthData('attributes').
87
 *              Auth object is by calling getAuthData('attributes').
88
 *              AUTH returns data formatted in a
88
 *              AUTH returns data formatted in a
89
 *              structure more compliant with other Auth Containers,
89
 *              structure more compliant with other Auth Containers,
90
 *              where each attribute element can be directly called by
90
 *              where each attribute element can be directly called by
91
 *              getAuthData() method from Auth.
91
 *              getAuthData() method from Auth.
92
 *              For compatibily with previous LDAP container versions,
92
 *              For compatibily with previous LDAP container versions,
93
 *              the default format is LDAP.
93
 *              the default format is LDAP.
94
 * groupdn:     gets prepended to basedn when searching for group
94
 * groupdn:     gets prepended to basedn when searching for group
95
 * groupattr:   the group attribute to search for (default: cn)
95
 * groupattr:   the group attribute to search for (default: cn)
96
 * groupfilter: filter that will be added to the search filter when
96
 * groupfilter: filter that will be added to the search filter when
97
 *              searching for a group:
97
 *              searching for a group:
98
 *              (&(groupattr=group)(memberattr=username)(groupfilter))
98
 *              (&(groupattr=group)(memberattr=username)(groupfilter))
99
 *              default: (objectClass=groupOfUniqueNames)
99
 *              default: (objectClass=groupOfUniqueNames)
100
 * memberattr : the attribute of the group object where the user dn
100
 * memberattr : the attribute of the group object where the user dn
101
 *              may be found (default: uniqueMember)
101
 *              may be found (default: uniqueMember)
102
 * memberisdn:  whether the memberattr is the dn of the user (default)
102
 * memberisdn:  whether the memberattr is the dn of the user (default)
103
 *              or the value of userattr (usually uid)
103
 *              or the value of userattr (usually uid)
104
 * group:       the name of group to search for
104
 * group:       the name of group to search for
105
 * groupscope:  Scope for group searching: one, sub (default), or base
105
 * groupscope:  Scope for group searching: one, sub (default), or base
106
 * start_tls:   enable/disable the use of START_TLS encrypted connection 
106
 * start_tls:   enable/disable the use of START_TLS encrypted connection
107
 *              (default: false)
107
 *              (default: false)
108
 * debug:       Enable/Disable debugging output (default: false)
108
 * debug:       Enable/Disable debugging output (default: false)
109
 * try_all:     Whether to try all user accounts returned from the search
109
 * try_all:     Whether to try all user accounts returned from the search
110
 *              or just the first one. (default: false)
110
 *              or just the first one. (default: false)
111
 *
111
 *
112
 * To use this storage container, you have to use the following syntax:
112
 * To use this storage container, you have to use the following syntax:
113
 *
113
 *
114
 * <?php
114
 * <?php
115
 * ...
115
 * ...
116
 *
116
 *
117
 * $a1 = new Auth("LDAP", array(
117
 * $a1 = new Auth("LDAP", array(
118
 *       'host' => 'localhost',
118
 *       'host' => 'localhost',
119
 *       'port' => '389',
119
 *       'port' => '389',
120
 *       'version' => 3,
120
 *       'version' => 3,
121
 *       'basedn' => 'o=netsols,c=de',
121
 *       'basedn' => 'o=netsols,c=de',
122
 *       'userattr' => 'uid'
122
 *       'userattr' => 'uid'
123
 *       'binddn' => 'cn=admin,o=netsols,c=de',
123
 *       'binddn' => 'cn=admin,o=netsols,c=de',
124
 *       'bindpw' => 'password'));
124
 *       'bindpw' => 'password'));
125
 *
125
 *
126
 * $a2 = new Auth('LDAP', array(
126
 * $a2 = new Auth('LDAP', array(
127
 *       'url' => 'ldaps://ldap.netsols.de',
127
 *       'url' => 'ldaps://ldap.netsols.de',
128
 *       'basedn' => 'o=netsols,c=de',
128
 *       'basedn' => 'o=netsols,c=de',
129
 *       'userscope' => 'one',
129
 *       'userscope' => 'one',
130
 *       'userdn' => 'ou=People',
130
 *       'userdn' => 'ou=People',
131
 *       'groupdn' => 'ou=Groups',
131
 *       'groupdn' => 'ou=Groups',
132
 *       'groupfilter' => '(objectClass=posixGroup)',
132
 *       'groupfilter' => '(objectClass=posixGroup)',
133
 *       'memberattr' => 'memberUid',
133
 *       'memberattr' => 'memberUid',
134
 *       'memberisdn' => false,
134
 *       'memberisdn' => false,
135
 *       'group' => 'admin'
135
 *       'group' => 'admin'
136
 *       ));
136
 *       ));
137
 *
137
 *
138
 * $a3 = new Auth('LDAP', array(
138
 * $a3 = new Auth('LDAP', array(
139
 *       'host' => 'ldap.netsols.de',
139
 *       'host' => 'ldap.netsols.de',
140
 *       'port' => 389,
140
 *       'port' => 389,
141
 *       'version' => 3,
141
 *       'version' => 3,
142
 *       'referrals' => false,
142
 *       'referrals' => false,
143
 *       'basedn' => 'dc=netsols,dc=de',
143
 *       'basedn' => 'dc=netsols,dc=de',
144
 *       'binddn' => 'cn=Jan Wagner,cn=Users,dc=netsols,dc=de',
144
 *       'binddn' => 'cn=Jan Wagner,cn=Users,dc=netsols,dc=de',
145
 *       'bindpw' => 'password',
145
 *       'bindpw' => 'password',
146
 *       'userattr' => 'samAccountName',
146
 *       'userattr' => 'samAccountName',
147
 *       'userfilter' => '(objectClass=user)',
147
 *       'userfilter' => '(objectClass=user)',
148
 *       'attributes' => array(''),
148
 *       'attributes' => array(''),
149
 *       'group' => 'testing',
149
 *       'group' => 'testing',
150
 *       'groupattr' => 'samAccountName',
150
 *       'groupattr' => 'samAccountName',
151
 *       'groupfilter' => '(objectClass=group)',
151
 *       'groupfilter' => '(objectClass=group)',
152
 *       'memberattr' => 'member',
152
 *       'memberattr' => 'member',
153
 *       'memberisdn' => true,
153
 *       'memberisdn' => true,
154
 *       'groupdn' => 'cn=Users',
154
 *       'groupdn' => 'cn=Users',
155
 *       'groupscope' => 'one',
155
 *       'groupscope' => 'one',
156
 *       'debug' => true);
156
 *       'debug' => true);
157
 *
157
 *
158
 * The parameter values have to correspond
158
 * The parameter values have to correspond
159
 * to the ones for your LDAP server of course.
159
 * to the ones for your LDAP server of course.
160
 *
160
 *
161
 * When talking to a Microsoft ActiveDirectory server you have to
161
 * When talking to a Microsoft ActiveDirectory server you have to
162
 * use 'samaccountname' as the 'userattr' and follow special rules
162
 * use 'samaccountname' as the 'userattr' and follow special rules
163
 * to translate the ActiveDirectory directory names into 'basedn'.
163
 * to translate the ActiveDirectory directory names into 'basedn'.
164
 * The 'basedn' for the default 'Users' folder on an ActiveDirectory
164
 * The 'basedn' for the default 'Users' folder on an ActiveDirectory
165
 * server for the ActiveDirectory Domain (which is not related to
165
 * server for the ActiveDirectory Domain (which is not related to
166
 * its DNS name) "win2000.example.org" would be:
166
 * its DNS name) "win2000.example.org" would be:
167
 * "CN=Users, DC=win2000, DC=example, DC=org'
167
 * "CN=Users, DC=win2000, DC=example, DC=org'
168
 * where every component of the domain name becomes a DC attribute
168
 * where every component of the domain name becomes a DC attribute
169
 * of its own. If you want to use a custom users folder you have to
169
 * of its own. If you want to use a custom users folder you have to
170
 * replace "CN=Users" with a sequence of "OU" attributes that specify
170
 * replace "CN=Users" with a sequence of "OU" attributes that specify
171
 * the path to your custom folder in reverse order.
171
 * the path to your custom folder in reverse order.
172
 * So the ActiveDirectory folder
172
 * So the ActiveDirectory folder
173
 *   "win2000.example.org\Custom\Accounts"
173
 *   "win2000.example.org\Custom\Accounts"
174
 * would become
174
 * would become
175
 *   "OU=Accounts, OU=Custom, DC=win2000, DC=example, DC=org'
175
 *   "OU=Accounts, OU=Custom, DC=win2000, DC=example, DC=org'
176
 *
176
 *
177
 * It seems that binding anonymously to an Active Directory
177
 * It seems that binding anonymously to an Active Directory
178
 * is not allowed, so you have to set binddn and bindpw for
178
 * is not allowed, so you have to set binddn and bindpw for
179
 * user searching.
179
 * user searching.
180
 * 
180
 *
181
 * LDAP Referrals need to be set to false for AD to work sometimes.
181
 * LDAP Referrals need to be set to false for AD to work sometimes.
182
 *
182
 *
183
 * Example a3 shows a full blown and tested example for connection to 
183
 * Example a3 shows a full blown and tested example for connection to
184
 * Windows 2000 Active Directory with group mebership checking
184
 * Windows 2000 Active Directory with group mebership checking
185
 *
185
 *
186
 * Note also that if you want an encrypted connection to an MS LDAP 
186
 * Note also that if you want an encrypted connection to an MS LDAP
187
 * server, then, on your webserver, you must specify 
187
 * server, then, on your webserver, you must specify
188
 *        TLS_REQCERT never
188
 *        TLS_REQCERT never
189
 * in /etc/ldap/ldap.conf or in the webserver user's ~/.ldaprc (which
189
 * in /etc/ldap/ldap.conf or in the webserver user's ~/.ldaprc (which
190
 * may or may not be read depending on your configuration).
190
 * may or may not be read depending on your configuration).
191
 *
191
 *
192
 *
192
 *
193
 * @category   Authentication
193
 * @category   Authentication
194
 * @package    Auth
194
 * @package    Auth
195
 * @author     Jan Wagner <wagner@netsols.de>
195
 * @author     Jan Wagner <wagner@netsols.de>
196
 * @author     Adam Ashley <aashley@php.net>
196
 * @author     Adam Ashley <aashley@php.net>
197
 * @author     Hugues Peeters <hugues.peeters@claroline.net>
197
 * @author     Hugues Peeters <hugues.peeters@claroline.net>
198
 * @copyright  2001-2006 The PHP Group
198
 * @copyright  2001-2006 The PHP Group
199
 * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
199
 * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
200
 * @version    Release: 1.4.3  File: $Revision: 1.2 $
200
 * @version    Release: 1.5.4  File: $Revision: 1.3 $
201
 * @link       http://pear.php.net/package/Auth
201
 * @link       http://pear.php.net/package/Auth
202
 */
202
 */
203
class Auth_Container_LDAP extends Auth_Container
203
class Auth_Container_LDAP extends Auth_Container
204
{
204
{
205
 
205
 
206
    // {{{ properties
206
    // {{{ properties
207
 
207
 
208
    /**
208
    /**
209
     * Options for the class
209
     * Options for the class
210
     * @var array
210
     * @var array
211
     */
211
     */
212
    var $options = array();
212
    var $options = array();
213
 
213
 
214
    /**
214
    /**
215
     * Connection ID of LDAP Link
215
     * Connection ID of LDAP Link
216
     * @var string
216
     * @var string
217
     */
217
     */
218
    var $conn_id = false;
218
    var $conn_id = false;
219
 
219
 
220
    // }}}
220
    // }}}
221
 
221
 
222
    // {{{ Auth_Container_LDAP() [constructor]
222
    // {{{ Auth_Container_LDAP() [constructor]
223
 
223
 
224
    /**
224
    /**
225
     * Constructor of the container class
225
     * Constructor of the container class
226
     *
226
     *
227
     * @param  $params, associative hash with host,port,basedn and userattr key
227
     * @param  $params, associative hash with host,port,basedn and userattr key
228
     * @return object Returns an error object if something went wrong
228
     * @return object Returns an error object if something went wrong
229
     */
229
     */
230
    function Auth_Container_LDAP($params)
230
    function Auth_Container_LDAP($params)
231
    {
231
    {
232
        if (false === extension_loaded('ldap')) {
232
        if (false === extension_loaded('ldap')) {
233
            return PEAR::raiseError('Auth_Container_LDAP: LDAP Extension not loaded',
233
            return PEAR::raiseError('Auth_Container_LDAP: LDAP Extension not loaded',
234
                    41, PEAR_ERROR_DIE);
234
                    41, PEAR_ERROR_DIE);
235
        }
235
        }
236
 
236
 
237
        $this->_setDefaults();
237
        $this->_setDefaults();
238
 
238
 
239
        if (is_array($params)) {
239
        if (is_array($params)) {
240
            $this->_parseOptions($params);
240
            $this->_parseOptions($params);
241
        }
241
        }
242
    }
242
    }
243
 
243
 
244
    // }}}
244
    // }}}
245
    // {{{ _prepare()
245
    // {{{ _prepare()
246
 
246
 
247
    /**
247
    /**
248
     * Prepare LDAP connection
248
     * Prepare LDAP connection
249
     *
249
     *
250
     * This function checks if we have already opened a connection to
250
     * This function checks if we have already opened a connection to
251
     * the LDAP server. If that's not the case, a new connection is opened.
251
     * the LDAP server. If that's not the case, a new connection is opened.
252
     *
252
     *
253
     * @access private
253
     * @access private
254
     * @return mixed True or a PEAR error object.
254
     * @return mixed True or a PEAR error object.
255
     */
255
     */
256
    function _prepare()
256
    function _prepare()
257
    {
257
    {
258
        if (!$this->_isValidLink()) {
258
        if (!$this->_isValidLink()) {
259
            $res = $this->_connect();
259
            $res = $this->_connect();
260
            if (PEAR::isError($res)) {
260
            if (PEAR::isError($res)) {
261
                return $res;
261
                return $res;
262
            }
262
            }
263
        }
263
        }
264
        return true;
264
        return true;
265
    }
265
    }
266
 
266
 
267
    // }}}
267
    // }}}
268
    // {{{ _connect()
268
    // {{{ _connect()
269
 
269
 
270
    /**
270
    /**
271
     * Connect to the LDAP server using the global options
271
     * Connect to the LDAP server using the global options
272
     *
272
     *
273
     * @access private
273
     * @access private
274
     * @return object  Returns a PEAR error object if an error occurs.
274
     * @return object  Returns a PEAR error object if an error occurs.
275
     */
275
     */
276
    function _connect()
276
    function _connect()
277
    {
277
    {
-
 
278
        $this->log('Auth_Container_LDAP::_connect() called.', AUTH_LOG_DEBUG);
278
        // connect
279
        // connect
279
        if (isset($this->options['url']) && $this->options['url'] != '') {
280
        if (isset($this->options['url']) && $this->options['url'] != '') {
280
            $this->_debug('Connecting with URL', __LINE__);
281
            $this->log('Connecting with URL', AUTH_LOG_DEBUG);
281
            $conn_params = array($this->options['url']);
282
            $conn_params = array($this->options['url']);
282
        } else {
283
        } else {
283
            $this->_debug('Connecting with host:port', __LINE__);
284
            $this->log('Connecting with host:port', AUTH_LOG_DEBUG);
284
            $conn_params = array($this->options['host'], $this->options['port']);
285
            $conn_params = array($this->options['host'], $this->options['port']);
285
        }
286
        }
286
 
287
 
287
        if (($this->conn_id = @call_user_func_array('ldap_connect', $conn_params)) === false) {
288
        if (($this->conn_id = @call_user_func_array('ldap_connect', $conn_params)) === false) {
-
 
289
            $this->log('Connection to server failed.', AUTH_LOG_DEBUG);
-
 
290
            $this->log('LDAP ERROR: '.ldap_errno($this->conn_id).': '.ldap_error($this->conn_id), AUTH_LOG_DEBUG);
288
            return PEAR::raiseError('Auth_Container_LDAP: Could not connect to server.', 41);
291
            return PEAR::raiseError('Auth_Container_LDAP: Could not connect to server.', 41);
289
        }
292
        }
290
        $this->_debug('Successfully connected to server', __LINE__);
293
        $this->log('Successfully connected to server', AUTH_LOG_DEBUG);
291
 
294
 
292
        // switch LDAP version
295
        // switch LDAP version
293
        if (is_numeric($this->options['version']) && $this->options['version'] > 2) {
296
        if (is_numeric($this->options['version']) && $this->options['version'] > 2) {
294
            $this->_debug("Switching to LDAP version {$this->options['version']}", __LINE__);
297
            $this->log("Switching to LDAP version {$this->options['version']}", AUTH_LOG_DEBUG);
295
            @ldap_set_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, $this->options['version']);
298
            @ldap_set_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, $this->options['version']);
296
        
299
 
297
            // start TLS if available
300
            // start TLS if available
298
            if (isset($this->options['start_tls']) && $this->options['start_tls']) {           
301
            if (isset($this->options['start_tls']) && $this->options['start_tls']) {
299
                $this->_debug("Starting TLS session", __LINE__);
302
                $this->log("Starting TLS session", AUTH_LOG_DEBUG);
300
                if (@ldap_start_tls($this->conn_id) === false) {
303
                if (@ldap_start_tls($this->conn_id) === false) {
-
 
304
                    $this->log('Could not start TLS session', AUTH_LOG_DEBUG);
-
 
305
                    $this->log('LDAP ERROR: '.ldap_errno($this->conn_id).': '.ldap_error($this->conn_id), AUTH_LOG_DEBUG);
301
                    return PEAR::raiseError('Auth_Container_LDAP: Could not start tls.', 41);
306
                    return PEAR::raiseError('Auth_Container_LDAP: Could not start tls.', 41);
302
                }
307
                }
303
            }
308
            }
304
        }
309
        }
305
 
310
 
306
        // switch LDAP referrals
311
        // switch LDAP referrals
307
        if (is_bool($this->options['referrals'])) {
312
        if (is_bool($this->options['referrals'])) {
308
          $this->_debug("Switching LDAP referrals to " . (($this->options['referrals']) ? 'true' : 'false'), __LINE__);
313
            $this->log("Switching LDAP referrals to " . (($this->options['referrals']) ? 'true' : 'false'), AUTH_LOG_DEBUG);
309
          @ldap_set_option($this->conn_id, LDAP_OPT_REFERRALS, $this->options['referrals']);
314
            if (@ldap_set_option($this->conn_id, LDAP_OPT_REFERRALS, $this->options['referrals']) === false) {
-
 
315
                $this->log('Could not change LDAP referrals options', AUTH_LOG_DEBUG);
-
 
316
                $this->log('LDAP ERROR: '.ldap_errno($this->conn_id).': '.ldap_error($this->conn_id), AUTH_LOG_DEBUG);
-
 
317
            }
310
        }
318
        }
311
 
319
 
312
        // bind with credentials or anonymously
320
        // bind with credentials or anonymously
313
        if (strlen($this->options['binddn']) && strlen($this->options['bindpw'])) {
321
        if (strlen($this->options['binddn']) && strlen($this->options['bindpw'])) {
314
            $this->_debug('Binding with credentials', __LINE__);
322
            $this->log('Binding with credentials', AUTH_LOG_DEBUG);
315
            $bind_params = array($this->conn_id, $this->options['binddn'], $this->options['bindpw']);
323
            $bind_params = array($this->conn_id, $this->options['binddn'], $this->options['bindpw']);
316
        } else {
324
        } else {
317
            $this->_debug('Binding anonymously', __LINE__);
325
            $this->log('Binding anonymously', AUTH_LOG_DEBUG);
318
            $bind_params = array($this->conn_id);
326
            $bind_params = array($this->conn_id);
319
        }
327
        }
320
 
328
 
321
        // bind for searching
329
        // bind for searching
322
        if ((@call_user_func_array('ldap_bind', $bind_params)) === false) {
330
        if ((@call_user_func_array('ldap_bind', $bind_params)) === false) {
323
            $this->_debug();
331
            $this->log('Bind failed', AUTH_LOG_DEBUG);
-
 
332
            $this->log('LDAP ERROR: '.ldap_errno($this->conn_id).': '.ldap_error($this->conn_id), AUTH_LOG_DEBUG);
324
            $this->_disconnect();
333
            $this->_disconnect();
325
            return PEAR::raiseError("Auth_Container_LDAP: Could not bind to LDAP server.", 41);
334
            return PEAR::raiseError("Auth_Container_LDAP: Could not bind to LDAP server.", 41);
326
        }
335
        }
327
        $this->_debug('Binding was successful', __LINE__);
336
        $this->log('Binding was successful', AUTH_LOG_DEBUG);
328
 
337
 
329
        return true;
338
        return true;
330
    }
339
    }
331
 
340
 
332
    // }}}
341
    // }}}
333
    // {{{ _disconnect()
342
    // {{{ _disconnect()
334
 
343
 
335
    /**
344
    /**
336
     * Disconnects (unbinds) from ldap server
345
     * Disconnects (unbinds) from ldap server
337
     *
346
     *
338
     * @access private
347
     * @access private
339
     */
348
     */
340
    function _disconnect()
349
    function _disconnect()
341
    {
350
    {
-
 
351
        $this->log('Auth_Container_LDAP::_disconnect() called.', AUTH_LOG_DEBUG);
342
        if ($this->_isValidLink()) {
352
        if ($this->_isValidLink()) {
343
            $this->_debug('disconnecting from server');
353
            $this->log('disconnecting from server');
344
            @ldap_unbind($this->conn_id);
354
            @ldap_unbind($this->conn_id);
345
        }
355
        }
346
    }
356
    }
347
 
357
 
348
    // }}}
358
    // }}}
349
    // {{{ _getBaseDN()
359
    // {{{ _getBaseDN()
350
 
360
 
351
    /**
361
    /**
352
     * Tries to find Basedn via namingContext Attribute
362
     * Tries to find Basedn via namingContext Attribute
353
     *
363
     *
354
     * @access private
364
     * @access private
355
     */
365
     */
356
    function _getBaseDN()
366
    function _getBaseDN()
357
    {
367
    {
-
 
368
        $this->log('Auth_Container_LDAP::_getBaseDN() called.', AUTH_LOG_DEBUG);
358
        $err = $this->_prepare();
369
        $err = $this->_prepare();
359
        if ($err !== true) {
370
        if ($err !== true) {
360
            return PEAR::raiseError($err->getMessage(), $err->getCode());
371
            return PEAR::raiseError($err->getMessage(), $err->getCode());
361
        }
372
        }
362
 
373
 
363
        if ($this->options['basedn'] == "" && $this->_isValidLink()) {
374
        if ($this->options['basedn'] == "" && $this->_isValidLink()) {
364
            $this->_debug("basedn not set, searching via namingContexts.", __LINE__);
375
            $this->log("basedn not set, searching via namingContexts.", AUTH_LOG_DEBUG);
365
 
376
 
366
            $result_id = @ldap_read($this->conn_id, "", "(objectclass=*)", array("namingContexts"));
377
            $result_id = @ldap_read($this->conn_id, "", "(objectclass=*)", array("namingContexts"));
367
 
378
 
368
            if (@ldap_count_entries($this->conn_id, $result_id) == 1) {
379
            if (@ldap_count_entries($this->conn_id, $result_id) == 1) {
369
 
380
 
370
                $this->_debug("got result for namingContexts", __LINE__);
381
                $this->log("got result for namingContexts", AUTH_LOG_DEBUG);
371
 
382
 
372
                $entry_id = @ldap_first_entry($this->conn_id, $result_id);
383
                $entry_id = @ldap_first_entry($this->conn_id, $result_id);
373
                $attrs = @ldap_get_attributes($this->conn_id, $entry_id);
384
                $attrs = @ldap_get_attributes($this->conn_id, $entry_id);
374
                $basedn = $attrs['namingContexts'][0];
385
                $basedn = $attrs['namingContexts'][0];
375
 
386
 
376
                if ($basedn != "") {
387
                if ($basedn != "") {
377
                    $this->_debug("result for namingContexts was $basedn", __LINE__);
388
                    $this->log("result for namingContexts was $basedn", AUTH_LOG_DEBUG);
378
                    $this->options['basedn'] = $basedn;
389
                    $this->options['basedn'] = $basedn;
379
                }
390
                }
380
            }
391
            }
381
            @ldap_free_result($result_id);
392
            @ldap_free_result($result_id);
382
        }
393
        }
383
 
394
 
384
        // if base ist still not set, raise error
395
        // if base ist still not set, raise error
385
        if ($this->options['basedn'] == "") {
396
        if ($this->options['basedn'] == "") {
386
            return PEAR::raiseError("Auth_Container_LDAP: LDAP search base not specified!", 41);
397
            return PEAR::raiseError("Auth_Container_LDAP: LDAP search base not specified!", 41);
387
        }
398
        }
388
        return true;
399
        return true;
389
    }
400
    }
390
 
401
 
391
    // }}}
402
    // }}}
392
    // {{{ _isValidLink()
403
    // {{{ _isValidLink()
393
 
404
 
394
    /**
405
    /**
395
     * determines whether there is a valid ldap conenction or not
406
     * determines whether there is a valid ldap conenction or not
396
     *
407
     *
397
     * @accessd private
408
     * @accessd private
398
     * @return boolean
409
     * @return boolean
399
     */
410
     */
400
    function _isValidLink()
411
    function _isValidLink()
401
    {
412
    {
402
        if (is_resource($this->conn_id)) {
413
        if (is_resource($this->conn_id)) {
403
            if (get_resource_type($this->conn_id) == 'ldap link') {
414
            if (get_resource_type($this->conn_id) == 'ldap link') {
404
                return true;
415
                return true;
405
            }
416
            }
406
        }
417
        }
407
        return false;
418
        return false;
408
    }
419
    }
409
 
420
 
410
    // }}}
421
    // }}}
411
    // {{{ _setDefaults()
422
    // {{{ _setDefaults()
412
 
423
 
413
    /**
424
    /**
414
     * Set some default options
425
     * Set some default options
415
     *
426
     *
416
     * @access private
427
     * @access private
417
     */
428
     */
418
    function _setDefaults()
429
    function _setDefaults()
419
    {
430
    {
420
        $this->options['url']         = '';
431
        $this->options['url']         = '';
421
        $this->options['host']        = 'localhost';
432
        $this->options['host']        = 'localhost';
422
        $this->options['port']        = '389';
433
        $this->options['port']        = '389';
423
        $this->options['version']     = 2;
434
        $this->options['version']     = 2;
424
        $this->options['referrals']   = true;
435
        $this->options['referrals']   = true;
425
        $this->options['binddn']      = '';
436
        $this->options['binddn']      = '';
426
        $this->options['bindpw']      = '';
437
        $this->options['bindpw']      = '';
427
        $this->options['basedn']      = '';
438
        $this->options['basedn']      = '';
428
        $this->options['userdn']      = '';
439
        $this->options['userdn']      = '';
429
        $this->options['userscope']   = 'sub';
440
        $this->options['userscope']   = 'sub';
430
        $this->options['userattr']    = 'uid';
441
        $this->options['userattr']    = 'uid';
431
        $this->options['userfilter']  = '(objectClass=posixAccount)';
442
        $this->options['userfilter']  = '(objectClass=posixAccount)';
432
        $this->options['attributes']  = array(''); // no attributes
443
        $this->options['attributes']  = array(''); // no attributes
433
     // $this->options['attrformat']  = 'LDAP'; // returns attribute array as PHP LDAP functions return it
-
 
434
        $this->options['attrformat']  = 'AUTH'; // returns attribute like other Auth containers
444
        $this->options['attrformat']  = 'AUTH'; // returns attribute like other Auth containers
435
        $this->options['group']       = '';
445
        $this->options['group']       = '';
436
        $this->options['groupdn']     = '';
446
        $this->options['groupdn']     = '';
437
        $this->options['groupscope']  = 'sub';
447
        $this->options['groupscope']  = 'sub';
438
        $this->options['groupattr']   = 'cn';
448
        $this->options['groupattr']   = 'cn';
439
        $this->options['groupfilter'] = '(objectClass=groupOfUniqueNames)';
449
        $this->options['groupfilter'] = '(objectClass=groupOfUniqueNames)';
440
        $this->options['memberattr']  = 'uniqueMember';
450
        $this->options['memberattr']  = 'uniqueMember';
441
        $this->options['memberisdn']  = true;
451
        $this->options['memberisdn']  = true;
442
        $this->options['start_tls']   = false;
452
        $this->options['start_tls']   = false;
443
        $this->options['debug']       = false;
453
        $this->options['debug']       = false;
444
        $this->options['try_all']     = false; // Try all user ids returned not just the first one
454
        $this->options['try_all']     = false; // Try all user ids returned not just the first one
445
    }
455
    }
446
 
456
 
447
    // }}}
457
    // }}}
448
    // {{{ _parseOptions()
458
    // {{{ _parseOptions()
449
 
459
 
450
    /**
460
    /**
451
     * Parse options passed to the container class
461
     * Parse options passed to the container class
452
     *
462
     *
453
     * @access private
463
     * @access private
454
     * @param  array
464
     * @param  array
455
     */
465
     */
456
    function _parseOptions($array)
466
    function _parseOptions($array)
457
    {
467
    {
458
        $array = $this->_setV12OptionsToV13($array);
468
        $array = $this->_setV12OptionsToV13($array);
459
 
469
 
460
        foreach ($array as $key => $value) {
470
        foreach ($array as $key => $value) {
461
            if (array_key_exists($key, $this->options)) {
471
            if (array_key_exists($key, $this->options)) {
462
                if ($key == 'attributes') {
472
                if ($key == 'attributes') {
463
                    if (is_array($value)) {
473
                    if (is_array($value)) {
464
                        $this->options[$key] = $value;
474
                        $this->options[$key] = $value;
465
                    } else {
475
                    } else {
466
                        $this->options[$key] = explode(',', $value);
476
                        $this->options[$key] = explode(',', $value);
467
                    }
477
                    }
468
                } else {
478
                } else {
469
                    $this->options[$key] = $value;
479
                    $this->options[$key] = $value;
470
                }
480
                }
471
            }
481
            }
472
        }
482
        }
473
    }
483
    }
474
 
484
 
475
    // }}}
485
    // }}}
476
    // {{{ _setV12OptionsToV13()
486
    // {{{ _setV12OptionsToV13()
477
 
487
 
478
    /**
488
    /**
479
     * Adapt deprecated options from Auth 1.2 LDAP to Auth 1.3 LDAP
489
     * Adapt deprecated options from Auth 1.2 LDAP to Auth 1.3 LDAP
480
     * 
490
     *
481
     * @author Hugues Peeters <hugues.peeters@claroline.net>
491
     * @author Hugues Peeters <hugues.peeters@claroline.net>
482
     * @access private
492
     * @access private
483
     * @param array
493
     * @param array
484
     * @return array
494
     * @return array
485
     */
495
     */
486
    function _setV12OptionsToV13($array)
496
    function _setV12OptionsToV13($array)
487
    {
497
    {
488
        if (isset($array['useroc']))
498
        if (isset($array['useroc']))
489
            $array['userfilter'] = "(objectClass=".$array['useroc'].")";
499
            $array['userfilter'] = "(objectClass=".$array['useroc'].")";
490
        if (isset($array['groupoc']))
500
        if (isset($array['groupoc']))
491
            $array['groupfilter'] = "(objectClass=".$array['groupoc'].")";
501
            $array['groupfilter'] = "(objectClass=".$array['groupoc'].")";
492
        if (isset($array['scope']))
502
        if (isset($array['scope']))
493
            $array['userscope'] = $array['scope'];
503
            $array['userscope'] = $array['scope'];
494
 
504
 
495
        return $array;
505
        return $array;
496
    }
506
    }
497
 
507
 
498
    // }}}
508
    // }}}
499
    // {{{ _scope2function()
509
    // {{{ _scope2function()
500
 
510
 
501
    /**
511
    /**
502
     * Get search function for scope
512
     * Get search function for scope
503
     *
513
     *
504
     * @param  string scope
514
     * @param  string scope
505
     * @return string ldap search function
515
     * @return string ldap search function
506
     */
516
     */
507
    function _scope2function($scope)
517
    function _scope2function($scope)
508
    {
518
    {
509
        switch($scope) {
519
        switch($scope) {
510
        case 'one':
520
        case 'one':
511
            $function = 'ldap_list';
521
            $function = 'ldap_list';
512
            break;
522
            break;
513
        case 'base':
523
        case 'base':
514
            $function = 'ldap_read';
524
            $function = 'ldap_read';
515
            break;
525
            break;
516
        default:
526
        default:
517
            $function = 'ldap_search';
527
            $function = 'ldap_search';
518
            break;
528
            break;
519
        }
529
        }
520
        return $function;
530
        return $function;
521
    }
531
    }
522
 
532
 
523
    // }}}
533
    // }}}
524
    // {{{ fetchData()
534
    // {{{ fetchData()
525
 
535
 
526
    /**
536
    /**
527
     * Fetch data from LDAP server
537
     * Fetch data from LDAP server
528
     *
538
     *
529
     * Searches the LDAP server for the given username/password
539
     * Searches the LDAP server for the given username/password
530
     * combination.  Escapes all LDAP meta characters in username
540
     * combination.  Escapes all LDAP meta characters in username
531
     * before performing the query.
541
     * before performing the query.
532
     *
542
     *
533
     * @param  string Username
543
     * @param  string Username
534
     * @param  string Password
544
     * @param  string Password
535
     * @return boolean
545
     * @return boolean
536
     */
546
     */
537
    function fetchData($username, $password)
547
    function fetchData($username, $password)
538
    {
548
    {
-
 
549
        $this->log('Auth_Container_LDAP::fetchData() called.', AUTH_LOG_DEBUG);
539
        $err = $this->_prepare();
550
        $err = $this->_prepare();
540
        if ($err !== true) {
551
        if ($err !== true) {
541
            return PEAR::raiseError($err->getMessage(), $err->getCode());
552
            return PEAR::raiseError($err->getMessage(), $err->getCode());
542
        }
553
        }
543
 
554
 
544
        $err = $this->_getBaseDN();
555
        $err = $this->_getBaseDN();
545
        if ($err !== true) {
556
        if ($err !== true) {
546
            return PEAR::raiseError($err->getMessage(), $err->getCode());
557
            return PEAR::raiseError($err->getMessage(), $err->getCode());
547
        }
558
        }
548
 
559
 
549
        // UTF8 Encode username for LDAPv3
560
        // UTF8 Encode username for LDAPv3
550
        if (@ldap_get_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, $ver) && $ver == 3) {
561
        if (@ldap_get_option($this->conn_id, LDAP_OPT_PROTOCOL_VERSION, $ver) && $ver == 3) {
551
            $this->_debug('UTF8 encoding username for LDAPv3', __LINE__);
562
            $this->log('UTF8 encoding username for LDAPv3', AUTH_LOG_DEBUG);
552
            $username = utf8_encode($username);
563
            $username = utf8_encode($username);
553
        }
564
        }
554
 
565
 
555
        // make search filter
566
        // make search filter
556
        $filter = sprintf('(&(%s=%s)%s)',
567
        $filter = sprintf('(&(%s=%s)%s)',
557
                          $this->options['userattr'],
568
                          $this->options['userattr'],
558
                          $this->_quoteFilterString($username),
569
                          $this->_quoteFilterString($username),
559
                          $this->options['userfilter']);
570
                          $this->options['userfilter']);
560
 
571
 
561
        // make search base dn
572
        // make search base dn
562
        $search_basedn = $this->options['userdn'];
573
        $search_basedn = $this->options['userdn'];
563
        if ($search_basedn != '' && substr($search_basedn, -1) != ',') {
574
        if ($search_basedn != '' && substr($search_basedn, -1) != ',') {
564
            $search_basedn .= ',';
575
            $search_basedn .= ',';
565
        }
576
        }
566
        $search_basedn .= $this->options['basedn'];
577
        $search_basedn .= $this->options['basedn'];
567
 
578
 
568
        // attributes
579
        // attributes
569
        $attributes = $this->options['attributes'];
580
        $searchAttributes = $this->options['attributes'];
570
 
581
 
571
        // make functions params array
582
        // make functions params array
572
        $func_params = array($this->conn_id, $search_basedn, $filter, $attributes);
583
        $func_params = array($this->conn_id, $search_basedn, $filter, $searchAttributes);
573
 
584
 
574
        // search function to use
585
        // search function to use
575
        $func_name = $this->_scope2function($this->options['userscope']);
586
        $func_name = $this->_scope2function($this->options['userscope']);
576
 
587
 
577
        $this->_debug("Searching with $func_name and filter $filter in $search_basedn", __LINE__);
588
        $this->log("Searching with $func_name and filter $filter in $search_basedn", AUTH_LOG_DEBUG);
578
 
589
 
579
        // search
590
        // search
580
        if (($result_id = @call_user_func_array($func_name, $func_params)) === false) {
591
        if (($result_id = @call_user_func_array($func_name, $func_params)) === false) {
581
            $this->_debug('User not found', __LINE__);
592
            $this->log('User not found', AUTH_LOG_DEBUG);
582
        } elseif (@ldap_count_entries($this->conn_id, $result_id) >= 1) { // did we get some possible results?
593
        } elseif (@ldap_count_entries($this->conn_id, $result_id) >= 1) { // did we get some possible results?
583
 
594
 
584
            $this->_debug('User(s) found', __LINE__);
595
            $this->log('User(s) found', AUTH_LOG_DEBUG);
585
 
596
 
586
            $first = true;
597
            $first = true;
587
            $entry_id = null;
598
            $entry_id = null;
588
 
599
 
589
            do {
600
            do {
590
                
601
 
591
                // then get the user dn
602
                // then get the user dn
592
                if ($first) {
603
                if ($first) {
593
                    $entry_id = @ldap_first_entry($this->conn_id, $result_id);
604
                    $entry_id = @ldap_first_entry($this->conn_id, $result_id);
594
                    $first = false;
605
                    $first = false;
595
                } else {
606
                } else {
596
                    $entry_id = @ldap_next_entry($this->conn_id, $entry_id);
607
                    $entry_id = @ldap_next_entry($this->conn_id, $entry_id);
597
                    if ($entry_id === false)
608
                    if ($entry_id === false)
598
                        break;
609
                        break;
599
                }
610
                }
600
                $user_dn  = @ldap_get_dn($this->conn_id, $entry_id);
611
                $user_dn  = @ldap_get_dn($this->conn_id, $entry_id);
601
 
612
 
602
                // as the dn is not fetched as an attribute, we save it anyway
613
                // as the dn is not fetched as an attribute, we save it anyway
603
                if (is_array($attributes) && in_array('dn', $attributes)) {
614
                if (is_array($searchAttributes) && in_array('dn', $searchAttributes)) {
604
                    $this->_debug('Saving DN to AuthData', __LINE__);
615
                    $this->log('Saving DN to AuthData', AUTH_LOG_DEBUG);
605
                    $this->_auth_obj->setAuthData('dn', $user_dn);
616
                    $this->_auth_obj->setAuthData('dn', $user_dn);
606
                }
617
                }
607
            
618
 
608
                // fetch attributes
619
                // fetch attributes
609
                if ($attributes = @ldap_get_attributes($this->conn_id, $entry_id)) {
620
                if ($attributes = @ldap_get_attributes($this->conn_id, $entry_id)) {
610
 
621
 
611
                    if (is_array($attributes) && isset($attributes['count']) &&
622
                    if (is_array($attributes) && isset($attributes['count']) &&
612
                         $attributes['count'] > 0) {
623
                         $attributes['count'] > 0) {
613
 
624
 
614
                        // ldap_get_attributes() returns a specific multi dimensional array
625
                        // ldap_get_attributes() returns a specific multi dimensional array
615
                        // format containing all the attributes and where each array starts
626
                        // format containing all the attributes and where each array starts
616
                        // with a 'count' element providing the number of attributes in the
627
                        // with a 'count' element providing the number of attributes in the
617
                        // entry, or the number of values for attribute. For compatibility
628
                        // entry, or the number of values for attribute. For compatibility
618
                        // reasons, it remains the default format returned by LDAP container
629
                        // reasons, it remains the default format returned by LDAP container
619
                        // setAuthData().
630
                        // setAuthData().
620
                        // The code below optionally returns attributes in another format,
631
                        // The code below optionally returns attributes in another format,
621
                        // more compliant with other Auth containers, where each attribute
632
                        // more compliant with other Auth containers, where each attribute
622
                        // element are directly set in the 'authData' list. This option is
633
                        // element are directly set in the 'authData' list. This option is
623
                        // enabled by setting 'attrformat' to
634
                        // enabled by setting 'attrformat' to
624
                        // 'AUTH' in the 'options' array.
635
                        // 'AUTH' in the 'options' array.
625
                        // eg. $this->options['attrformat'] = 'AUTH'
636
                        // eg. $this->options['attrformat'] = 'AUTH'
626
 
637
 
627
                        if ( strtoupper($this->options['attrformat']) == 'AUTH' ) {
638
                        if ( strtoupper($this->options['attrformat']) == 'AUTH' ) {
628
                            $this->_debug('Saving attributes to Auth data in AUTH format', __LINE__);
639
                            $this->log('Saving attributes to Auth data in AUTH format', AUTH_LOG_DEBUG);
629
                            unset ($attributes['count']);
640
                            unset ($attributes['count']);
630
                            foreach ($attributes as $attributeName => $attributeValue ) {
641
                            foreach ($attributes as $attributeName => $attributeValue ) {
631
                                if (is_int($attributeName)) continue;
642
                                if (is_int($attributeName)) continue;
632
                                if (is_array($attributeValue) && isset($attributeValue['count'])) {
643
                                if (is_array($attributeValue) && isset($attributeValue['count'])) {
633
                                    unset ($attributeValue['count']);
644
                                    unset ($attributeValue['count']);
634
                                }
645
                                }
635
                                if (count($attributeValue)<=1) $attributeValue = $attributeValue[0];
646
                                if (count($attributeValue)<=1) $attributeValue = $attributeValue[0];
-
 
647
                                $this->log('Storing additional field: '.$attributeName, AUTH_LOG_DEBUG);
636
                                $this->_auth_obj->setAuthData($attributeName, $attributeValue);
648
                                $this->_auth_obj->setAuthData($attributeName, $attributeValue);
637
                            }
649
                            }
638
                        }
650
                        }
639
                        else
651
                        else
640
                        {
652
                        {
641
                            $this->_debug('Saving attributes to Auth data in LDAP format', __LINE__);
653
                            $this->log('Saving attributes to Auth data in LDAP format', AUTH_LOG_DEBUG);
642
                            $this->_auth_obj->setAuthData('attributes', $attributes);
654
                            $this->_auth_obj->setAuthData('attributes', $attributes);
643
                        }
655
                        }
644
                    }
656
                    }
645
                }
657
                }
646
                @ldap_free_result($result_id);
658
                @ldap_free_result($result_id);
647
 
659
 
648
                // need to catch an empty password as openldap seems to return TRUE
660
                // need to catch an empty password as openldap seems to return TRUE
649
                // if anonymous binding is allowed
661
                // if anonymous binding is allowed
650
                if ($password != "") {
662
                if ($password != "") {
651
                    $this->_debug("Bind as $user_dn", __LINE__);
663
                    $this->log("Bind as $user_dn", AUTH_LOG_DEBUG);
652
 
664
 
653
                    // try binding as this user with the supplied password
665
                    // try binding as this user with the supplied password
654
                    if (@ldap_bind($this->conn_id, $user_dn, $password)) {
666
                    if (@ldap_bind($this->conn_id, $user_dn, $password)) {
655
                        $this->_debug('Bind successful', __LINE__);
667
                        $this->log('Bind successful', AUTH_LOG_DEBUG);
656
 
668
 
657
                        // check group if appropiate
669
                        // check group if appropiate
658
                        if (strlen($this->options['group'])) {
670
                        if (strlen($this->options['group'])) {
659
                            // decide whether memberattr value is a dn or the username
671
                            // decide whether memberattr value is a dn or the username
660
                            $this->_debug('Checking group membership', __LINE__);
672
                            $this->log('Checking group membership', AUTH_LOG_DEBUG);
661
                            $return = $this->checkGroup(($this->options['memberisdn']) ? $user_dn : $username);
673
                            $return = $this->checkGroup(($this->options['memberisdn']) ? $user_dn : $username);
662
                            $this->_disconnect();
674
                            $this->_disconnect();
663
                            return $return;
675
                            return $return;
664
                        } else {
676
                        } else {
665
                            $this->_debug('Authenticated', __LINE__);
677
                            $this->log('Authenticated', AUTH_LOG_DEBUG);
666
                            $this->_disconnect();
678
                            $this->_disconnect();
667
                            return true; // user authenticated
679
                            return true; // user authenticated
668
                        } // checkGroup
680
                        } // checkGroup
669
                    } // bind
681
                    } // bind
670
                } // non-empty password
682
                } // non-empty password
671
            } while ($this->options['try_all'] == true); // interate through entries
683
            } while ($this->options['try_all'] == true); // interate through entries
672
        } // get results
684
        } // get results
673
        // default
685
        // default
674
        $this->_debug('NOT authenticated!', __LINE__);
686
        $this->log('NOT authenticated!', AUTH_LOG_DEBUG);
675
        $this->_disconnect();
687
        $this->_disconnect();
676
        return false;
688
        return false;
677
    }
689
    }
678
 
690
 
679
    // }}}
691
    // }}}
680
    // {{{ checkGroup()
692
    // {{{ checkGroup()
681
 
693
 
682
    /**
694
    /**
683
     * Validate group membership
695
     * Validate group membership
684
     *
696
     *
685
     * Searches the LDAP server for group membership of the
697
     * Searches the LDAP server for group membership of the
686
     * supplied username.  Quotes all LDAP filter meta characters in
698
     * supplied username.  Quotes all LDAP filter meta characters in
687
     * the user name before querying the LDAP server.
699
     * the user name before querying the LDAP server.
688
     *
700
     *
689
     * @param  string Distinguished Name of the authenticated User
701
     * @param  string Distinguished Name of the authenticated User
690
     * @return boolean
702
     * @return boolean
691
     */
703
     */
692
    function checkGroup($user)
704
    function checkGroup($user)
693
    {
705
    {
-
 
706
        $this->log('Auth_Container_LDAP::checkGroup() called.', AUTH_LOG_DEBUG);
694
        $err = $this->_prepare();
707
        $err = $this->_prepare();
695
        if ($err !== true) {
708
        if ($err !== true) {
696
            return PEAR::raiseError($err->getMessage(), $err->getCode());
709
            return PEAR::raiseError($err->getMessage(), $err->getCode());
697
        }
710
        }
698
 
711
 
699
        // make filter
712
        // make filter
700
        $filter = sprintf('(&(%s=%s)(%s=%s)%s)',
713
        $filter = sprintf('(&(%s=%s)(%s=%s)%s)',
701
                          $this->options['groupattr'],
714
                          $this->options['groupattr'],
702
                          $this->options['group'],
715
                          $this->options['group'],
703
                          $this->options['memberattr'],
716
                          $this->options['memberattr'],
704
                          $this->_quoteFilterString($user),
717
                          $this->_quoteFilterString($user),
705
                          $this->options['groupfilter']);
718
                          $this->options['groupfilter']);
706
 
719
 
707
        // make search base dn
720
        // make search base dn
708
        $search_basedn = $this->options['groupdn'];
721
        $search_basedn = $this->options['groupdn'];
709
        if ($search_basedn != '' && substr($search_basedn, -1) != ',') {
722
        if ($search_basedn != '' && substr($search_basedn, -1) != ',') {
710
            $search_basedn .= ',';
723
            $search_basedn .= ',';
711
        }
724
        }
712
        $search_basedn .= $this->options['basedn'];
725
        $search_basedn .= $this->options['basedn'];
713
 
726
 
714
        $func_params = array($this->conn_id, $search_basedn, $filter,
727
        $func_params = array($this->conn_id, $search_basedn, $filter,
715
                             array($this->options['memberattr']));
728
                             array($this->options['memberattr']));
716
        $func_name = $this->_scope2function($this->options['groupscope']);
729
        $func_name = $this->_scope2function($this->options['groupscope']);
717
 
730
 
718
        $this->_debug("Searching with $func_name and filter $filter in $search_basedn", __LINE__);
731
        $this->log("Searching with $func_name and filter $filter in $search_basedn", AUTH_LOG_DEBUG);
719
 
732
 
720
        // search
733
        // search
721
        if (($result_id = @call_user_func_array($func_name, $func_params)) != false) {
734
        if (($result_id = @call_user_func_array($func_name, $func_params)) != false) {
722
            if (@ldap_count_entries($this->conn_id, $result_id) == 1) {
735
            if (@ldap_count_entries($this->conn_id, $result_id) == 1) {
723
                @ldap_free_result($result_id);
736
                @ldap_free_result($result_id);
724
                $this->_debug('User is member of group', __LINE__);
737
                $this->log('User is member of group', AUTH_LOG_DEBUG);
725
                return true;
738
                return true;
726
            }
739
            }
727
        }
740
        }
728
        // default
741
        // default
729
        $this->_debug('User is NOT member of group', __LINE__);
742
        $this->log('User is NOT member of group', AUTH_LOG_DEBUG);
730
        return false;
743
        return false;
731
    }
744
    }
732
 
-
 
733
    // }}}
-
 
734
    // {{{ _debug()
-
 
735
 
-
 
736
    /**
-
 
737
     * Outputs debugging messages
-
 
738
     *
-
 
739
     * @access private
-
 
740
     * @param string Debugging Message
-
 
741
     * @param integer Line number
-
 
742
     */
-
 
743
    function _debug($msg = '', $line = 0)
-
 
744
    {
-
 
745
        if ($this->options['debug'] == true) {
-
 
746
            if ($msg == '' && $this->_isValidLink()) {
-
 
747
                $msg = 'LDAP_Error: ' . @ldap_err2str(@ldap_errno($this->_conn_id));
-
 
748
            }
-
 
749
            print("$line: $msg <br />");
-
 
750
        }
-
 
751
    }
-
 
752
 
745
 
753
    // }}}
746
    // }}}
754
    // {{{ _quoteFilterString()
747
    // {{{ _quoteFilterString()
755
 
748
 
756
    /**
749
    /**
757
     * Escapes LDAP filter special characters as defined in RFC 2254.
750
     * Escapes LDAP filter special characters as defined in RFC 2254.
758
     *
751
     *
759
     * @access private
752
     * @access private
760
     * @param string Filter String
753
     * @param string Filter String
761
     */
754
     */
762
    function _quoteFilterString($filter_str)
755
    function _quoteFilterString($filter_str)
763
    {
756
    {
764
        $metas        = array(  '\\',  '*',  '(',  ')',   "\x00");
757
        $metas        = array(  '\\',  '*',  '(',  ')',   "\x00");
765
        $quoted_metas = array('\\\\', '\*', '\(', '\)', "\\\x00");
758
        $quoted_metas = array('\\\\', '\*', '\(', '\)', "\\\x00");
766
        return str_replace($metas, $quoted_metas, $filter_str);
759
        return str_replace($metas, $quoted_metas, $filter_str);
767
    }
760
    }
768
 
761
 
769
    // }}}
762
    // }}}
770
 
763
 
771
}
764
}
772
 
765
 
773
?>
766
?>