~ubuntu-branches/ubuntu/saucy/mediawiki-extensions/saucy

« back to all changes in this revision

Viewing changes to extensions/LdapAuthentication.php

  • Committer: Bazaar Package Importer
  • Author(s): Romain Beauxis
  • Date: 2010-05-04 15:13:35 UTC
  • mfrom: (0.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20100504151335-54qeucg3ec108q28
Tags: 2.2
* Added Replaces:/Conflicts: to allow a proper upgrade.
Closes: #580066
* Fixed package descriptions.
Closes: #579667
* Patched mediawiki-extensions-fckeditor to make it work with
  php 5.3. The fix may not be perfect but at least it work.
  Not closing the bug (#579822) for now..

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?php
2
 
# Copyright (C) 2004 Ryan Lane <http://www.mediawiki.org/wiki/User:Ryan_lane>
3
 
#
4
 
# This program is free software; you can redistribute it and/or modify
5
 
# it under the terms of the GNU General Public License as published by
6
 
# the Free Software Foundation; either version 2 of the License, or
7
 
# (at your option) any later version.
8
 
#
9
 
# This program is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
 
# GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License along
15
 
# with this program; if not, write to the Free Software Foundation, Inc.,
16
 
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
 
# http://www.gnu.org/copyleft/gpl.html
18
 
 
19
 
/**
20
 
 * LdapAuthentication plugin.
21
 
 *
22
 
 * Password authentication, and Smartcard Authentication support are currently
23
 
 * available. All forms of authentication, current and future, should support
24
 
 * group, and attribute based restrictions; preference pulling; and group
25
 
 * syncronization. All forms of authentication should have basic support for 
26
 
 * adding users, changing passwords, and updating preferences in LDAP.
27
 
 *
28
 
 * Password authentication has a number of configurations, including straight binds,
29
 
 * proxy based authentication, and anonymous-search based authentication.
30
 
 *
31
 
 * @package MediaWiki
32
 
 */
33
 
 
34
 
#
35
 
# LdapAuthentication.php
36
 
#
37
 
# Info available at http://www.mediawiki.org/wiki/Extension:LDAP_Authentication
38
 
# and at http://www.mediawiki.org/wiki/Extension:LDAP_Authentication/Configuration_Examples
39
 
# and at http://www.mediawiki.org/wiki/Extension:LDAP_Authentication/Smartcard_Configuration_Examples
40
 
#
41
 
# Support is available at http://www.mediawiki.org/wiki/Extension_talk:LDAP_Authentication 
42
 
#
43
 
 
44
 
/**
45
 
 * Add extension information to Special:Version
46
 
 */
47
 
$wgExtensionCredits['other'][] = array(
48
 
        'name' => 'LDAP Authentication Plugin',
49
 
        'version' => '1.2b (alpha)',
50
 
        'author' => 'Ryan Lane',
51
 
        'description' => 'LDAP Authentication plugin with support for multiple LDAP authentication methods',
52
 
        'url' => 'http://www.mediawiki.org/wiki/Extension:LDAP_Authentication',
53
 
        );
54
 
 
55
 
//constants for search base
56
 
define("GROUPDN", 0);
57
 
define("USERDN", 1);
58
 
define("DEFAULTDN", 2);
59
 
 
60
 
//constants for error reporting
61
 
define("NONSENSITIVE", 1);
62
 
define("SENSITIVE", 2);
63
 
define("HIGHLYSENSITIVE", 3);
64
 
 
65
 
class LdapAuthenticationPlugin extends AuthPlugin {
66
 
 
67
 
        //ldap connection resource
68
 
        var $ldapconn;
69
 
 
70
 
        //preferences
71
 
        var $email, $lang, $realname, $nickname, $externalid;
72
 
 
73
 
        //username pulled from ldap
74
 
        var $LDAPUsername;
75
 
 
76
 
        //userdn pulled from ldap
77
 
        var $userdn;
78
 
 
79
 
        //groups pulled from ldap
80
 
        var $userLDAPGroups;
81
 
        var $allLDAPGroups;
82
 
 
83
 
        //boolean to test for failed auth
84
 
        var $authFailed;
85
 
 
86
 
        //boolean to test for fetched user info
87
 
        var $fetchedUserInfo;
88
 
 
89
 
        //the user's entry and all attributes
90
 
        var $userInfo;
91
 
 
92
 
        function LdapAuthenticationPlugin() {
93
 
        }
94
 
 
95
 
        /**
96
 
         * Check whether there exists a user account with the given name.
97
 
         * The name will be normalized to MediaWiki's requirements, so
98
 
         * you might need to munge it (for instance, for lowercase initial
99
 
         * letters).
100
 
         *
101
 
         * @param string $username
102
 
         * @return bool
103
 
         * @access public
104
 
         */
105
 
        function userExists( $username ) {
106
 
                global $wgLDAPAddLDAPUsers;
107
 
 
108
 
                $this->printDebug( "Entering userExists", NONSENSITIVE );
109
 
 
110
 
                //If we can't add LDAP users, we don't really need to check
111
 
                //if the user exists, the authenticate method will do this for
112
 
                //us. This will decrease hits to the LDAP server.
113
 
                //We do however, need to use this if we are using auto authentication.
114
 
                if ( ( !isset( $wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) || !$wgLDAPAddLDAPUsers[$_SESSION['wsDomain']]) && !$this->useAutoAuth() ) {
115
 
                        return true;
116
 
                }
117
 
 
118
 
                $this->ldapconn = $this->connect();
119
 
                if ( $this->ldapconn ) {
120
 
                        $this->printDebug( "Successfully connected", NONSENSITIVE );
121
 
 
122
 
                        $searchstring = $this->getSearchString( $this->ldapconn, $username );
123
 
 
124
 
                        //If we are using auto authentication, and we got
125
 
                        //anything back, then the user exists.
126
 
                        if ( $this->useAutoAuth() && $searchstring != '' ) {
127
 
                                //getSearchString is going to bind, but will not unbind
128
 
                                //Let's clean up
129
 
                                @ldap_unbind();
130
 
                                return true;
131
 
                        }
132
 
 
133
 
                        //Search for the entry.
134
 
                        $entry = @ldap_read( $this->ldapconn, $searchstring, "objectclass=*" );
135
 
 
136
 
                        //getSearchString is going to bind, but will not unbind
137
 
                        //Let's clean up
138
 
                        @ldap_unbind();
139
 
                        if ( !$entry ) {
140
 
                                $this->printDebug( "Did not find a matching user in LDAP", NONSENSITIVE );
141
 
                                return false;
142
 
                        } else {
143
 
                                $this->printDebug( "Found a matching user in LDAP", NONSENSITIVE );
144
 
                                return true;
145
 
                        }
146
 
                } else {
147
 
                        $this->printDebug( "Failed to connect", NONSENSITIVE );
148
 
                        return false;
149
 
                }
150
 
                
151
 
        }
152
 
 
153
 
        /**
154
 
         * Connect to LDAP
155
 
         *
156
 
         * @access private
157
 
         */
158
 
        function connect() {
159
 
                global $wgLDAPServerNames;
160
 
                global $wgLDAPEncryptionType;
161
 
                global $wgLDAPOptions;
162
 
 
163
 
                $this->printDebug( "Entering Connect", NONSENSITIVE );
164
 
 
165
 
                if ( !function_exists( 'ldap_connect' ) ) {
166
 
                        $this->printDebug( "It looks like you are issing LDAP support; please ensure you have either compiled LDAP support in, or have enabled the module. If the authentication is working for you, the plugin isn't properly detecting the LDAP module, and you can safely ignore this message.", NONSENSITIVE );
167
 
                        return false;
168
 
                }
169
 
 
170
 
                //If the admin didn't set an encryption type, we default to tls
171
 
                if ( isset( $wgLDAPEncryptionType[$_SESSION['wsDomain']] ) ) {
172
 
                        $encryptionType = $wgLDAPEncryptionType[$_SESSION['wsDomain']];
173
 
                } else {
174
 
                        $encryptionType = "tls";
175
 
                }
176
 
 
177
 
                //Set the server string depending on whether we use ssl or not
178
 
                switch( $encryptionType ) {
179
 
                        case "ldapi":
180
 
                                # this is a really dirty place to put this,
181
 
                                # but it is easy and avoids another config option.
182
 
                                $this->printDebug( "Using ldapi", SENSITIVE );
183
 
                                $serverpre = "ldapi://";
184
 
                                break;
185
 
                        case "ssl":
186
 
                                $this->printDebug( "Using SSL", SENSITIVE );
187
 
                                $serverpre = "ldaps://";
188
 
                                break;
189
 
                        default:
190
 
                                $this->printDebug( "Using TLS or not using encryption.", SENSITIVE );
191
 
                                $serverpre = "ldap://";
192
 
                }
193
 
 
194
 
                //Make a space separated list of server strings with the ldap:// or ldaps://
195
 
                //string added.
196
 
                $servers = "";
197
 
                $tmpservers = $wgLDAPServerNames[$_SESSION['wsDomain']];
198
 
                $tok = strtok( $tmpservers, " " );
199
 
                while ( $tok ) {
200
 
                        $servers = $servers . " " . $serverpre . $tok;
201
 
                        $tok = strtok( " " );
202
 
                }
203
 
                $servers = rtrim($servers);
204
 
 
205
 
                $this->printDebug( "Using servers: $servers", SENSITIVE );
206
 
 
207
 
                //Connect and set options
208
 
                $this->ldapconn = @ldap_connect( $servers );
209
 
                ldap_set_option( $this->ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
210
 
                ldap_set_option( $this->ldapconn, LDAP_OPT_REFERRALS, 0);
211
 
 
212
 
                if ( isset( $wgLDAPOptions[$_SESSION['wsDomain']] ) ) {
213
 
                        $options = $wgLDAPOptions[$_SESSION['wsDomain']];
214
 
                        foreach ( $options as $key => $value ) {
215
 
                                if ( !ldap_set_option( $this->ldapconn, constant( $key ), $value ) ) {
216
 
                                        $this->printDebug( "Can't set option to LDAP! Option code and value: " . $key . "=" . $value, 1 );
217
 
                                }
218
 
                        }
219
 
                }
220
 
 
221
 
                //TLS needs to be started after the connection is made
222
 
                if ( $encryptionType == "tls" ) {
223
 
                        $this->printDebug( "Using TLS", SENSITIVE );
224
 
                        if ( !ldap_start_tls( $this->ldapconn ) ) {
225
 
                                $this->printDebug( "Failed to start TLS.", SENSITIVE );
226
 
                                return;
227
 
                        }
228
 
                }
229
 
        }
230
 
 
231
 
        /**
232
 
         * Check if a username+password pair is a valid login, or if the username
233
 
         * is allowed access to the wiki.
234
 
         * The name will be normalized to MediaWiki's requirements, so
235
 
         * you might need to munge it (for instance, for lowercase initial
236
 
         * letters).
237
 
         *
238
 
         * @param string $username
239
 
         * @param string $password
240
 
         * @return bool
241
 
         * @access public
242
 
         */
243
 
        function authenticate( $username, $password='' ) {
244
 
                global $wgLDAPAuthAttribute;
245
 
                global $wgLDAPAutoAuthUsername;
246
 
                global $wgLDAPLowerCaseUsername;
247
 
                global $wgLDAPSearchStrings;
248
 
 
249
 
                $this->printDebug( "Entering authenticate", NONSENSITIVE );
250
 
 
251
 
                //We don't handle local authentication
252
 
                if ( 'local' == $_SESSION['wsDomain'] ) {
253
 
                        $this->printDebug( "User is using a local domain", SENSITIVE );
254
 
                        return false;
255
 
                }
256
 
 
257
 
                //If the user is using auto authentication, we need to ensure
258
 
                //that he/she isn't trying to fool us by sending a username other
259
 
                //than the one the web server got from the auto-authentication method.
260
 
                if ( $this->useAutoAuth() && $wgLDAPAutoAuthUsername != $username ) {
261
 
                        $this->printDebug( "The username provided ($username) doesn't match the username provided by the webserver ($wgLDAPAutoAuthUsername). The user is probably trying to log in to the auto-authentication domain with password authentication via the wiki. Denying access.", SENSITIVE );
262
 
                        return false;
263
 
                }
264
 
 
265
 
                //We need to ensure that if we require a password, that it is
266
 
                //not blank. We don't allow blank passwords, so we are being
267
 
                //tricked if someone is supplying one when using password auth.
268
 
                //Smartcard authentication uses a pin, and does not require
269
 
                //a password to be given; a blank password here is wanted.
270
 
                if ( '' == $password && !$this->useAutoAuth() ) {
271
 
                        $this->printDebug( "User used a blank password", NONSENSITIVE );
272
 
                        return false;
273
 
                }
274
 
 
275
 
                $this->connect();
276
 
                if ( $this->ldapconn ) {
277
 
                        $this->printDebug( "Connected successfully", NONSENSITIVE );
278
 
 
279
 
                        //Mediawiki munges the username before authenticate is called,
280
 
                        //this can mess with authentication, group pulling/restriction,
281
 
                        //preference pulling, etc. Let's allow the admin to use
282
 
                        //a lowercased username if needed.
283
 
                        if ( isset( $wgLDAPLowerCaseUsername[$_SESSION['wsDomain']] ) && $wgLDAPLowerCaseUsername[$_SESSION['wsDomain']] ) {
284
 
                                $this->printDebug( "Lowercasing the username: $username", NONSENSITIVE );
285
 
                                $username = strtolower( $username );
286
 
                        }
287
 
 
288
 
                        $this->userdn = $this->getSearchString( $username );
289
 
 
290
 
                        //It is possible that getSearchString will return an
291
 
                        //empty string; if this happens, the bind will ALWAYS
292
 
                        //return true, and will let anyone in!
293
 
                        if ( '' == $this->userdn ) {
294
 
                                $this->printDebug( "User DN is blank", NONSENSITIVE );
295
 
                                @ldap_unbind();
296
 
                                $this->markAuthFailed();
297
 
                                return false;
298
 
                        }
299
 
 
300
 
                        //If we are using password authentication, we need to bind as the
301
 
                        //user to make sure the password is correct.
302
 
                        if ( !$this->useAutoAuth() ) {
303
 
                                $this->printDebug( "Binding as the user", NONSENSITIVE );
304
 
 
305
 
                                //Let's see if the user can authenticate.
306
 
                                $bind = $this->bindAs( $this->userdn, $password );
307
 
                                if ( !$bind ) {
308
 
                                        $this->markAuthFailed();
309
 
                                        return false;
310
 
                                }
311
 
 
312
 
                                $this->printDebug( "Bound successfully", NONSENSITIVE );
313
 
 
314
 
                                if ( isset( $wgLDAPSearchStrings[$_SESSION['wsDomain']] ) ) { 
315
 
                                        $ss = $wgLDAPSearchStrings[$_SESSION['wsDomain']];
316
 
                                        if ( strstr( $ss, "@" ) || strstr( $ss, '\\' ) ) {
317
 
                                                //We are most likely configured using USER-NAME@DOMAIN, or
318
 
                                                //DOMAIN\\USER-NAME.
319
 
                                                //Get the user's full DN so we can search for groups and such.
320
 
                                                $this->userdn = $this->getUserDN( $username );
321
 
                                                $this->printDebug( "Pulled the user's DN: $this->userdn", NONSENSITIVE );
322
 
                                        }
323
 
                                }
324
 
 
325
 
                                if ( isset( $wgLDAPAuthAttribute[$_SESSION['wsDomain']] ) ) {
326
 
 
327
 
                                        $this->printDebug( "Checking for auth attributes", NONSENSITIVE );
328
 
 
329
 
                                        $filter = "(" . $wgLDAPAuthAttribute[$_SESSION['wsDomain']] . ")";
330
 
                                        $attributes = array( "dn" );
331
 
 
332
 
                                        $entry = ldap_read( $this->ldapconn, $this->userdn, $filter, $attributes );
333
 
                                        $info = ldap_get_entries( $this->ldapconn, $entry );
334
 
 
335
 
                                        if ( $info["count"] < 1 ) {
336
 
                                                $this->printDebug( "Failed auth attribute check", NONSENSITIVE );
337
 
                                                @ldap_unbind();
338
 
                                                $this->markAuthFailed();
339
 
                                                return false;
340
 
                                        }
341
 
                                }
342
 
                        }
343
 
 
344
 
                        $this->getGroups( $username );
345
 
 
346
 
                        if ( !$this->checkGroups( $username ) ) {
347
 
                                @ldap_unbind();
348
 
                                $this->markAuthFailed();
349
 
                                return false;
350
 
                        }
351
 
 
352
 
                        $this->getPreferences();
353
 
 
354
 
                        if ( !$this->synchUsername( $username ) ) {
355
 
                                @ldap_unbind();
356
 
                                $this->markAuthFailed();
357
 
                                return false;
358
 
                        }
359
 
 
360
 
                        @ldap_unbind();
361
 
                } else {
362
 
                        $this->printDebug( "Failed to connect", NONSENSITIVE );
363
 
                        $this->markAuthFailed();
364
 
                        return false;
365
 
                }
366
 
                $this->printDebug( "Authentication passed", NONSENSITIVE );
367
 
 
368
 
                //We made it this far; the user authenticated and didn't fail any checks, so he/she gets in.
369
 
                return true;
370
 
        }
371
 
 
372
 
        function markAuthFailed() {
373
 
                $this->authFailed = true;
374
 
        }
375
 
 
376
 
        /**
377
 
         * Modify options in the login template.
378
 
         *
379
 
         * @param UserLoginTemplate $template
380
 
         * @access public
381
 
         */
382
 
        function modifyUITemplate( &$template ) {
383
 
                global $wgLDAPDomainNames, $wgLDAPUseLocal;
384
 
                global $wgLDAPAddLDAPUsers;
385
 
                global $wgLDAPAutoAuthDomain;
386
 
 
387
 
                $this->printDebug( "Entering modifyUITemplate", NONSENSITIVE );
388
 
 
389
 
                if ( !isset( $wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) || !$wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) {
390
 
                        $template->set( 'create', false );
391
 
                }
392
 
 
393
 
                $template->set( 'usedomain', true );
394
 
                $template->set( 'useemail', false );
395
 
 
396
 
                $tempDomArr = $wgLDAPDomainNames;
397
 
                if ( $wgLDAPUseLocal ) {
398
 
                        $this->printDebug( "Allowing the local domain, adding it to the list.", NONSENSITIVE );
399
 
                        array_push( $tempDomArr, 'local' );
400
 
                }
401
 
 
402
 
                if ( isset( $wgLDAPAutoAuthDomain ) ) {
403
 
                        $this->printDebug( "Allowing auto-authentication login, removing the domain from the list.", NONSENSITIVE );
404
 
 
405
 
                        //There is no reason for people to log in directly to the wiki if the are using an
406
 
                        //auto-authentication domain. If they try to, they are probably up to something fishy.
407
 
                        unset( $tempDomArr[array_search( $wgLDAPAutoAuthDomain, $tempDomArr )] );
408
 
                }
409
 
 
410
 
                $template->set( 'domainnames', $tempDomArr );
411
 
        }
412
 
 
413
 
        /**
414
 
         * Return true if the wiki should create a new local account automatically
415
 
         * when asked to login a user who doesn't exist locally but does in the
416
 
         * external auth database.
417
 
         *
418
 
         * This is just a question, and shouldn't perform any actions.
419
 
         *
420
 
         * @return bool
421
 
         * @access public
422
 
         */
423
 
        function autoCreate() {
424
 
                global $wgLDAPDisableAutoCreate;
425
 
 
426
 
                if ( isset( $wgLDAPDisableAutoCreate[$_SESSION['wsDomain']] ) && $wgLDAPDisableAutoCreate[$_SESSION['wsDomain']] ) {
427
 
                        return false;
428
 
                } else {
429
 
                        return true;
430
 
                }
431
 
        }
432
 
 
433
 
        /**
434
 
         * Set the given password in LDAP.
435
 
         * Return true if successful.
436
 
         *
437
 
         * @param User $user
438
 
         * @param string $password
439
 
         * @return bool
440
 
         * @access public
441
 
         */
442
 
        function setPassword( $user, &$password ) {
443
 
                global $wgLDAPUpdateLDAP, $wgLDAPWriterDN, $wgLDAPWriterPassword;
444
 
 
445
 
                $this->printDebug( "Entering setPassword", NONSENSITIVE );
446
 
 
447
 
                if ( $_SESSION['wsDomain'] == 'local' ) {
448
 
                        $this->printDebug( "User is using a local domain", NONSENSITIVE );
449
 
 
450
 
                        //We don't set local passwords, but we don't want the wiki
451
 
                        //to send the user a failure.           
452
 
                        return true;
453
 
                } else if ( !isset( $wgLDAPUpdateLDAP[$_SESSION['wsDomain']] ) || !$wgLDAPUpdateLDAP[$_SESSION['wsDomain']] ) {
454
 
                        $this->printDebug( "Wiki is set to not allow updates", NONSENSITIVE );
455
 
 
456
 
                        //We aren't allowing the user to change his/her own password
457
 
                        return false;
458
 
                }
459
 
 
460
 
                if ( !isset( $wgLDAPWriterDN[$_SESSION['wsDomain']] ) ) {
461
 
                        $this->printDebug( "Wiki doesn't have wgLDAPWriterDN set", NONSENSITIVE );
462
 
 
463
 
                        //We can't change a user's password without an account that is
464
 
                        //allowed to do it.
465
 
                        return false;
466
 
                }
467
 
 
468
 
                $pass = $this->getPasswordHash( $password );
469
 
 
470
 
                $this->connect();
471
 
                if ( $this->ldapconn ) {
472
 
                        $this->printDebug( "Connected successfully", NONSENSITIVE );
473
 
                        $this->userdn = $this->getSearchString( $user->getName() );
474
 
 
475
 
                        $this->printDebug( "Binding as the writerDN", NONSENSITIVE );
476
 
                        $bind = $this->bindAs( $wgLDAPWriterDN[$_SESSION['wsDomain']], $wgLDAPWriterPassword[$_SESSION['wsDomain']] );
477
 
                        if ( !$bind ) {
478
 
                                return false;
479
 
                        }
480
 
 
481
 
                        $values["userpassword"] = $pass;
482
 
 
483
 
                        //Blank out the password in the database. We don't want to save
484
 
                        //domain credentials for security reasons.
485
 
                        $password = '';
486
 
 
487
 
                        $success = @ldap_modify( $this->ldapconn, $this->userdn, $values );
488
 
 
489
 
                        //Let's clean up
490
 
                        @ldap_unbind();
491
 
                        if ( $success ) {
492
 
                                $this->printDebug( "Successfully modified the user's password", NONSENSITIVE );
493
 
                                return true;
494
 
                        } else {
495
 
                                $this->printDebug( "Failed to modify the user's password", NONSENSITIVE );
496
 
                                return false;
497
 
                        }
498
 
                } else {
499
 
                        $this->printDebug( "Failed to connect", NONSENSITIVE );
500
 
                        return false;
501
 
                }
502
 
        }
503
 
 
504
 
        /**
505
 
         * Update user information in LDAP
506
 
         * Return true if successful.
507
 
         *
508
 
         * @param User $user
509
 
         * @return bool
510
 
         * @access public
511
 
         */     
512
 
        function updateExternalDB( $user ) {
513
 
                global $wgLDAPUpdateLDAP;
514
 
                global $wgLDAPWriterDN, $wgLDAPWriterPassword;
515
 
 
516
 
                $this->printDebug( "Entering updateExternalDB", NONSENSITIVE );
517
 
 
518
 
                if ( ( !isset( $wgLDAPUpdateLDAP[$_SESSION['wsDomain']] ) || !$wgLDAPUpdateLDAP[$_SESSION['wsDomain']] ) ||
519
 
                        $_SESSION['wsDomain'] == 'local' ) {
520
 
                        $this->printDebug( "Either the user is using a local domain, or the wiki isn't allowing updates", NONSENSITIVE );
521
 
 
522
 
                        //We don't handle local preferences, but we don't want the
523
 
                        //wiki to return an error.
524
 
                        return true;
525
 
                }
526
 
 
527
 
                if ( !isset( $wgLDAPWriterDN[$_SESSION['wsDomain']] ) ) {
528
 
                        $this->printDebug( "The wiki doesn't have wgLDAPWriterDN set", NONSENSITIVE );
529
 
 
530
 
                        //We can't modify LDAP preferences if we don't have a user
531
 
                        //capable of editing LDAP attributes.
532
 
                        return false;
533
 
                }
534
 
 
535
 
                $this->email = $user->getEmail();
536
 
                $this->realname = $user->getRealName();
537
 
                $this->nickname = $user->getOption( 'nickname' );
538
 
                $this->language = $user->getOption( 'language' );
539
 
 
540
 
                $this->connect();
541
 
                if ( $this->ldapconn ) {
542
 
                        $this->printDebug( "Connected successfully", NONSENSITIVE );
543
 
                        $this->userdn = $this->getSearchString( $user->getName() );
544
 
 
545
 
                        $this->printDebug( "Binding as the writerDN", NONSENSITIVE );
546
 
                        $bind = $this->bindAs( $wgLDAPWriterDN[$_SESSION['wsDomain']], $wgLDAPWriterPassword[$_SESSION['wsDomain']] );
547
 
                        if ( !$bind ) {
548
 
                                return false;
549
 
                        }
550
 
 
551
 
                        if ( '' != $this->email ) { $values["mail"] = $this->email; }
552
 
                        if ( '' != $this->nickname ) { $values["displayname"] = $this->nickname; }
553
 
                        if ( '' != $this->realname ) { $values["cn"] = $this->realname; }
554
 
                        if ( '' != $this->language ) { $values["preferredlanguage"] = $this->language; }
555
 
 
556
 
                        if ( 0 != sizeof( $values ) && @ldap_modify( $this->ldapconn, $this->userdn, $values ) ) {
557
 
                                $this->printDebug( "Successfully modified the user's attributes", NONSENSITIVE );
558
 
                                @ldap_unbind();
559
 
                                return true;
560
 
                        } else {
561
 
                                $this->printDebug( "Failed to modify the user's attributes", NONSENSITIVE );
562
 
                                @ldap_unbind();
563
 
                                return false;
564
 
                        }
565
 
                } else {
566
 
                        $this->printDebug( "Failed to Connect", NONSENSITIVE );
567
 
                        return false;
568
 
                }
569
 
        }
570
 
 
571
 
        /**
572
 
         * Can the wiki create accounts in LDAP?
573
 
         * Return true if yes.
574
 
         *
575
 
         * @return bool
576
 
         * @access public
577
 
         */     
578
 
        function canCreateAccounts() {
579
 
                global $wgLDAPAddLDAPUsers;
580
 
 
581
 
                if ( isset( $wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) && $wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) {
582
 
                        return true;
583
 
                } else {
584
 
                        return false;
585
 
                }
586
 
        }
587
 
 
588
 
        /**
589
 
         * Can the wiki change passwords in LDAP, or can the user
590
 
         * change passwords locally?
591
 
         * Return true if yes.
592
 
         *
593
 
         * @return bool
594
 
         * @access public
595
 
         */     
596
 
        function allowPasswordChange() {
597
 
                global $wgLDAPUpdateLDAP, $wgLDAPMailPassword;
598
 
                global $wgLDAPUseLocal;
599
 
 
600
 
                $this->printDebug( "Entering allowPasswordChange", NONSENSITIVE );
601
 
 
602
 
                $retval = false;
603
 
 
604
 
                // Local domains need to be able to change passwords
605
 
                if ( (isset($wgLDAPUseLocal) && $wgLDAPUseLocal) && 'local' == $_SESSION['wsDomain'] ) {
606
 
                        $retval = true;
607
 
                }
608
 
 
609
 
                if ( isset( $wgLDAPUpdateLDAP[$_SESSION['wsDomain']] ) && $wgLDAPUpdateLDAP[$_SESSION['wsDomain']] ) {
610
 
                        $retval = true;
611
 
                }
612
 
 
613
 
                if ( isset( $wgLDAPMailPassword[$_SESSION['wsDomain']] ) && $wgLDAPMailPassword[$_SESSION['wsDomain']] ) {
614
 
                        $retval = true;
615
 
                }
616
 
 
617
 
                return $retval;
618
 
        }
619
 
 
620
 
        /**
621
 
         * Add a user to LDAP.
622
 
         * Return true if successful.
623
 
         *
624
 
         * @param User $user
625
 
         * @param string $password
626
 
         * @return bool
627
 
         * @access public
628
 
         */
629
 
        function addUser( $user, $password ) {
630
 
                global $wgLDAPAddLDAPUsers, $wgLDAPWriterDN, $wgLDAPWriterPassword;
631
 
                global $wgLDAPSearchAttributes;
632
 
                global $wgLDAPWriteLocation;
633
 
                global $wgLDAPRequiredGroups, $wgLDAPGroupDN;
634
 
                global $wgLDAPAuthAttribute;
635
 
 
636
 
                $this->printDebug( "Entering addUser", NONSENSITIVE );
637
 
 
638
 
                if ( ( !isset( $wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) || !$wgLDAPAddLDAPUsers[$_SESSION['wsDomain']] ) ||
639
 
                        'local' == $_SESSION['wsDomain'] ) {
640
 
                        $this->printDebug( "Either the user is using a local domain, or the wiki isn't allowing users to be added to LDAP", NONSENSITIVE );
641
 
 
642
 
                        //Tell the wiki not to return an error.
643
 
                        return true;
644
 
                }
645
 
 
646
 
                if ( $wgLDAPRequiredGroups || $wgLDAPGroupDN ) {
647
 
                        $this->printDebug( "The wiki is requiring users to be in specific groups, and cannot add users as this would be a security hole.", NONSENSITIVE );
648
 
                        //It is possible that later we can add users into
649
 
                        //groups, but since we don't support it, we don't want
650
 
                        //to open holes!
651
 
                        return false;
652
 
                }
653
 
 
654
 
                if ( !isset( $wgLDAPWriterDN[$_SESSION['wsDomain']] ) ) {
655
 
                        $this->printDebug( "The wiki doesn't have wgLDAPWriterDN set", NONSENSITIVE );
656
 
 
657
 
                        //We can't add users without an LDAP account capable of doing so.
658
 
                        return false;
659
 
                }
660
 
 
661
 
                $this->email = $user->getEmail();
662
 
                $this->realname = $user->getRealName();
663
 
                $username = $user->getName();
664
 
 
665
 
                $pass = $this->getPasswordHash( $password );
666
 
 
667
 
                $this->connect();
668
 
                if ( $this->ldapconn ) {
669
 
                        $this->printDebug( "Successfully connected", NONSENSITIVE );
670
 
 
671
 
                        $this->userdn = $this->getSearchString( $username );
672
 
                        if ( '' == $this->userdn ) {
673
 
                                $this->printDebug( "$this->userdn is blank, attempting to use wgLDAPWriteLocation", NONSENSITIVE );
674
 
                                if ( isset( $wgLDAPWriteLocation[$_SESSION['wsDomain']] ) ) {
675
 
                                        $this->printDebug( "wgLDAPWriteLocation is set, using that", NONSENSITIVE );
676
 
                                        $this->userdn = $wgLDAPSearchAttributes[$_SESSION['wsDomain']] . "=" .
677
 
                                                $username . "," . $wgLDAPWriteLocation[$_SESSION['wsDomain']];
678
 
                                } else {
679
 
                                        $this->printDebug( "wgLDAPWriteLocation is not set, failing", NONSENSITIVE );
680
 
                                        //getSearchString will bind, but will not unbind
681
 
                                        @ldap_unbind();
682
 
                                        return false;
683
 
                                }
684
 
                        }
685
 
 
686
 
                        $this->printDebug( "Binding as the writerDN", NONSENSITIVE );
687
 
 
688
 
                        $bind = $this->bindAs( $wgLDAPWriterDN[$_SESSION['wsDomain']], $wgLDAPWriterPassword[$_SESSION['wsDomain']] );
689
 
                        if ( !$bind ) {
690
 
                                $this->printDebug( "Failed to bind as the writerDN; add failed", NONSENSITIVE );
691
 
                                return false;
692
 
                        }
693
 
 
694
 
                        //Set up LDAP attributes
695
 
                        $values["uid"] = $username;
696
 
                        //sn is required for objectclass inetorgperson
697
 
                        $values["sn"] = $username;
698
 
                        if ( '' != $this->email ) { $values["mail"] = $this->email; }
699
 
                        if ( '' != $this->realname ) {$values["cn"] = $this->realname; }
700
 
                                else { $values["cn"] = $username; }
701
 
                        $values["userpassword"] = $pass;
702
 
                        $values["objectclass"] = "inetorgperson";
703
 
 
704
 
                        if ( isset ( $wgLDAPAuthAttribute[$_SESSION['wsDomain']] ) ) {
705
 
                                $values[$wgLDAPAuthAttribute[$_SESSION['wsDomain']]] = "true";
706
 
                        }
707
 
 
708
 
                        $this->printDebug( "Adding user", NONSENSITIVE );
709
 
                        if ( @ldap_add( $this->ldapconn, $this->userdn, $values ) ) {
710
 
                                $this->printDebug( "Successfully added user", NONSENSITIVE );
711
 
                                @ldap_unbind();
712
 
                                return true;
713
 
                        } else {
714
 
                                $this->printDebug( "Failed to add user", NONSENSITIVE );
715
 
                                @ldap_unbind();
716
 
                                return false;
717
 
                        }
718
 
                } else {
719
 
                        $this->printDebug( "Failed to connect; add failed", NONSENSITIVE );
720
 
                        return false;
721
 
                }
722
 
        }
723
 
 
724
 
        /**
725
 
         * Set the domain this plugin is supposed to use when authenticating.
726
 
         *
727
 
         * @param string $domain
728
 
         * @access public       
729
 
         */
730
 
        function setDomain( $domain ) {
731
 
                $this->printDebug( "Setting domain as: $domain", NONSENSITIVE );
732
 
                $_SESSION['wsDomain'] = $domain;
733
 
        }
734
 
 
735
 
        /**
736
 
         * Check to see if the specific domain is a valid domain.
737
 
         * Return true if the domain is valid.
738
 
         *
739
 
         * @param string $domain
740
 
         * @return bool
741
 
         * @access public
742
 
         */
743
 
        function validDomain( $domain ) {
744
 
                global $wgLDAPDomainNames, $wgLDAPUseLocal;
745
 
 
746
 
                $this->printDebug( "Entering validDomain", NONSENSITIVE );
747
 
 
748
 
                if ( in_array( $domain, $wgLDAPDomainNames ) || ( $wgLDAPUseLocal && 'local' == $domain ) ) {
749
 
                        $this->printDebug( "User is using a valid domain.", NONSENSITIVE );
750
 
                        return true;
751
 
                } else {
752
 
                        $this->printDebug( "User is not using a valid domain.", NONSENSITIVE );
753
 
                        return false;
754
 
                }
755
 
        }
756
 
 
757
 
        /**
758
 
         * When a user logs in, update user with information from LDAP.
759
 
         *
760
 
         * @param User $user
761
 
         * @access public
762
 
         * TODO: fix the setExternalID stuff
763
 
         */
764
 
        function updateUser( &$user ) {
765
 
                global $wgLDAPRetrievePrefs, $wgLDAPPreferences;
766
 
                global $wgLDAPUseLDAPGroups;
767
 
                global $wgLDAPUniqueBlockLogin, $wgLDAPUniqueRenameUser;
768
 
 
769
 
                $this->printDebug( "Entering updateUser", NONSENSITIVE );
770
 
 
771
 
                if ($this->authFailed) {
772
 
                        $this->printDebug( "User didn't successfully authenticate, exiting.", NONSENSITIVE );
773
 
                        return;
774
 
                }
775
 
 
776
 
                $saveSettings = false;
777
 
 
778
 
                //If we aren't pulling preferences, we don't want to accidentally
779
 
                //overwrite anything.
780
 
                if ( ( isset( $wgLDAPRetrievePrefs[$_SESSION['wsDomain']] ) && $wgLDAPRetrievePrefs[$_SESSION['wsDomain']] )
781
 
                        || isset( $wgLDAPPreferences[$_SESSION['wsDomain']] ) ) {
782
 
                        $this->printDebug( "Setting user preferences.", NONSENSITIVE );
783
 
 
784
 
                        if ( '' != $this->lang ) {
785
 
                                $this->printDebug( "Setting language.", NONSENSITIVE );
786
 
                                $user->setOption( 'language', $this->lang );
787
 
                        }
788
 
                        if ( '' != $this->nickname ) {
789
 
                                $this->printDebug( "Setting nickname.", NONSENSITIVE );
790
 
                                $user->setOption( 'nickname', $this->nickname );
791
 
                        }
792
 
                        if ( '' != $this->realname ) {
793
 
                                $this->printDebug( "Setting realname.", NONSENSITIVE );
794
 
                                $user->setRealName( $this->realname );
795
 
                        }
796
 
                        if ( '' != $this->email ) {
797
 
                                $this->printDebug( "Setting email.", NONSENSITIVE );
798
 
                                $user->setEmail( $this->email );
799
 
                                $user->confirmEmail();
800
 
                        }
801
 
                        if ( ( isset( $wgLDAPUniqueBlockLogin[$_SESSION['wsDomain']] ) && $wgLDAPUniqueBlockLogin[$_SESSION['wsDomain']] )
802
 
                                || ( isset( $wgLDAPUniqueRenameUser[$_SESSION['wsDomain']] ) && $wgLDAPUniqueRenameUser[$_SESSION['wsDomain']] ) ) {
803
 
 
804
 
                                if ( '' != $this->externalid ) {
805
 
                                        $user->setExternalID( $this->externalid );
806
 
                                }
807
 
                        }
808
 
 
809
 
                        $saveSettings = true;
810
 
                }
811
 
 
812
 
                if ( isset( $wgLDAPUseLDAPGroups[$_SESSION['wsDomain']] ) && $wgLDAPUseLDAPGroups[$_SESSION['wsDomain']] ) {
813
 
                        $this->printDebug( "Setting user groups.", NONSENSITIVE );
814
 
                        $this->setGroups( $user );
815
 
 
816
 
                        $saveSettings = true;
817
 
                }
818
 
 
819
 
                if ( $saveSettings ) {
820
 
                        $this->printDebug( "Saving user settings.", NONSENSITIVE );
821
 
                        $user->saveSettings();
822
 
                }
823
 
        }
824
 
 
825
 
        /**
826
 
         * When creating a user account, initialize user with information from LDAP.
827
 
         *
828
 
         * @param User $user
829
 
         * @access public
830
 
         * TODO: fix setExternalID stuff
831
 
         */
832
 
        function initUser( &$user ) {
833
 
                global $wgLDAPUseLDAPGroups;
834
 
 
835
 
                $this->printDebug( "Entering initUser", NONSENSITIVE );
836
 
 
837
 
                if ($this->authFailed) {
838
 
                        $this->printDebug( "User didn't successfully authenticate, exiting.", NONSENSITIVE );
839
 
                        return;
840
 
                }
841
 
 
842
 
                if ( 'local' == $_SESSION['wsDomain'] ) {
843
 
                        $this->printDebug( "User is using a local domain", NONSENSITIVE );
844
 
                        return;
845
 
                }
846
 
 
847
 
                //We are creating an LDAP user, it is very important that we do
848
 
                //NOT set a local password because it could compromise the
849
 
                //security of our domain.
850
 
                $user->mPassword = '';
851
 
 
852
 
                //The update user function does everything else we need done.
853
 
                $this->updateUser($user);
854
 
 
855
 
                //updateUser() won't definately save the user's settings
856
 
                $user->saveSettings();
857
 
        }
858
 
 
859
 
        /**
860
 
         * Return true to prevent logins that don't authenticate here from being
861
 
         * checked against the local database's password fields.
862
 
         *
863
 
         * This is just a question, and shouldn't perform any actions.
864
 
         *
865
 
         * @return bool
866
 
         * @access public
867
 
         */
868
 
        function strict() {
869
 
                global $wgLDAPUseLocal, $wgLDAPMailPassword;
870
 
 
871
 
                $this->printDebug( "Entering strict.", NONSENSITIVE );
872
 
 
873
 
                if ( $wgLDAPUseLocal || $wgLDAPMailPassword ) {
874
 
                        $this->printDebug( "Returning false in strict().", NONSENSITIVE );
875
 
                        return false;
876
 
                } else {
877
 
                        $this->printDebug( "Returning true in strict().", NONSENSITIVE );
878
 
                        return true;
879
 
                }
880
 
        }
881
 
 
882
 
        /**
883
 
         * Munge the username to always have a form of uppercase for the first letter,
884
 
         * and lowercase for the rest of the letters.
885
 
         *
886
 
         * @param string $username
887
 
         * @return string
888
 
         * @access public
889
 
         */
890
 
        function getCanonicalName( $username ) {
891
 
                global $wgLDAPUseLocal;
892
 
                $this->printDebug( "Entering getCanonicalName", NONSENSITIVE );
893
 
 
894
 
                if ( $username != '' ) {
895
 
                        $this->printDebug( "Username isn't empty.", NONSENSITIVE );
896
 
 
897
 
                        //We want to use the username returned by LDAP
898
 
                        //if it exists
899
 
                        if ( $this->LDAPUsername != '' ) {
900
 
                                $this->printDebug( "Using LDAPUsername.", NONSENSITIVE );
901
 
                                $username = $this->LDAPUsername;
902
 
                        }
903
 
 
904
 
                        if ( isset($_SESSION['wsDomain']) && 'local' != $_SESSION['wsDomain']) {
905
 
                                //Change username to lowercase so that multiple user accounts
906
 
                                //won't be created for the same user.
907
 
                                //But don't do it for the local domain!
908
 
                                $username = strtolower( $username );
909
 
                        }
910
 
 
911
 
                        //The wiki considers an all lowercase name to be invalid; need to
912
 
                        //uppercase the first letter
913
 
                        $username[0] = strtoupper( $username[0] );
914
 
                }
915
 
 
916
 
                $this->printDebug( "Munged username: $username", NONSENSITIVE );
917
 
 
918
 
                return $username;
919
 
        }
920
 
 
921
 
        /**
922
 
         * Configures the authentication plugin for use with auto-authentication
923
 
         * plugins.
924
 
         *
925
 
         * @access public
926
 
         */
927
 
        function autoAuthSetup() {
928
 
                global $wgLDAPAutoAuthDomain;
929
 
 
930
 
                $this->setDomain( $wgLDAPAutoAuthDomain );
931
 
        }
932
 
 
933
 
        /**
934
 
         * Gets the searchstring for a user based upon settings for the domain.
935
 
         * Returns a full DN for a user.
936
 
         *
937
 
         * @param string $username
938
 
         * @return string
939
 
         * @access private
940
 
         */
941
 
        function getSearchString( $username ) {
942
 
                global $wgLDAPSearchStrings;
943
 
                global $wgLDAPProxyAgent, $wgLDAPProxyAgentPassword;
944
 
 
945
 
                $this->printDebug( "Entering getSearchString", NONSENSITIVE );
946
 
 
947
 
                if ( isset( $wgLDAPSearchStrings[$_SESSION['wsDomain']] ) ) {
948
 
                        //This is a straight bind
949
 
                        $this->printDebug( "Doing a straight bind", NONSENSITIVE );
950
 
 
951
 
                        $tmpuserdn = $wgLDAPSearchStrings[$_SESSION['wsDomain']];
952
 
                        $userdn = str_replace( "USER-NAME", $username, $tmpuserdn );
953
 
                } else {
954
 
                        //This is a proxy bind, or an anonymous bind with a search
955
 
                        if ( isset( $wgLDAPProxyAgent[$_SESSION['wsDomain']] ) ) {
956
 
                                //This is a proxy bind
957
 
                                $this->printDebug( "Doing a proxy bind", NONSENSITIVE );
958
 
                                $bind = $this->bindAs( $wgLDAPProxyAgent[$_SESSION['wsDomain']], $wgLDAPProxyAgentPassword[$_SESSION['wsDomain']] );
959
 
                        } else {
960
 
                                //This is an anonymous bind
961
 
                                $this->printDebug( "Doing an anonymous bind", NONSENSITIVE );
962
 
                                $bind = $this->bindAs();
963
 
                        }
964
 
        
965
 
                        if ( !$bind ) {
966
 
                                $this->printDebug( "Failed to bind", NONSENSITIVE );
967
 
                                return '';
968
 
                        }
969
 
 
970
 
                        $userdn = $this->getUserDN( $username );
971
 
                }
972
 
                $this->printDebug( "userdn is: $userdn", SENSITIVE );
973
 
                return $userdn;
974
 
        }
975
 
 
976
 
        /**
977
 
         * Gets the DN of a user based upon settings for the domain.
978
 
         * This function will set $this->LDAPUsername
979
 
         * You must bind to the server before calling this.
980
 
         *
981
 
         * @param string $username
982
 
         * @return string
983
 
         * @access private
984
 
         */
985
 
        function getUserDN( $username ) {
986
 
                global $wgLDAPSearchAttributes;
987
 
                global $wgLDAPAuthAttribute;
988
 
 
989
 
                $this->printDebug("Entering getUserDN", NONSENSITIVE);
990
 
 
991
 
                //we need to do a subbase search for the entry
992
 
 
993
 
                //Auto auth needs to check LDAP for required attributes.
994
 
                if ( ( isset( $wgLDAPAuthAttribute[$_SESSION['wsDomain']] ) )
995
 
                        && $this->useAutoAuth() ) {
996
 
                        $auth_filter = "(" . $wgLDAPAuthAttribute[$_SESSION['wsDomain']] . ")";
997
 
                        $srch_filter = "(" . $wgLDAPSearchAttributes[$_SESSION['wsDomain']] . "=" . $this->getLdapEscapedString( $username ) . ")";
998
 
                        $filter = "(&" . $srch_filter . $auth_filter . ")";
999
 
                        $this->printDebug( "Created an auth attribute filter: $filter", SENSITIVE );
1000
 
                } else {
1001
 
                        $filter = "(" . $wgLDAPSearchAttributes[$_SESSION['wsDomain']] . "=" . $this->getLdapEscapedString( $username ) . ")";
1002
 
                        $this->printDebug( "Created a regular filter: $filter", SENSITIVE );
1003
 
                }
1004
 
 
1005
 
                $attributes = array( "*" );
1006
 
                $base = $this->getBaseDN( USERDN );
1007
 
 
1008
 
                $this->printDebug( "Using base: $base", SENSITIVE );
1009
 
 
1010
 
                $entry = @ldap_search( $this->ldapconn, $base, $filter, $attributes );
1011
 
                if ( !$entry ) {
1012
 
                        $this->printDebug( "Couldn't find an entry", NONSENSITIVE );
1013
 
                        $this->fetchedUserInfo = false;
1014
 
                        return '';
1015
 
                }
1016
 
 
1017
 
                $this->userInfo = @ldap_get_entries( $this->ldapconn, $entry );
1018
 
                $this->fetchedUserInfo = true;
1019
 
 
1020
 
                //This is a pretty useful thing to have for auto authentication,
1021
 
                //group checking, and pulling preferences.
1022
 
                wfRunHooks( 'SetUsernameAttributeFromLDAP', array( &$this->LDAPUsername, $this->userInfo ) );
1023
 
                if ( !is_string( $this->LDAPUsername ) ) {
1024
 
                        $this->printDebug( "Fetched username is not a string (check your hook code...). This message can be safely ignored if you do not have the SetUsernameAttributeFromLDAP hook defined.", NONSENSITIVE );
1025
 
                        $this->LDAPUsername = '';
1026
 
                }
1027
 
 
1028
 
                $userdn = $this->userInfo[0]["dn"];
1029
 
                return $userdn;
1030
 
        }
1031
 
 
1032
 
        function getUserInfo() {
1033
 
                //Don't fetch the same data more than once
1034
 
                if ( $this->fetchedUserInfo ) {
1035
 
                        return $this->userInfo;
1036
 
                }
1037
 
 
1038
 
                $entry = @ldap_read( $this->ldapconn, $this->userdn, "objectclass=*" );
1039
 
                $userInfo = @ldap_get_entries( $this->ldapconn, $entry );
1040
 
                if ( $userInfo["count"] < 1 ) {
1041
 
                        $this->fetchedUserInfo = false;
1042
 
                        return;
1043
 
                } else {
1044
 
                        $this->fetchedUserInfo = true;
1045
 
                        return $userInfo;
1046
 
                }
1047
 
        }
1048
 
 
1049
 
        /**
1050
 
         * Retrieve user preferences from LDAP
1051
 
         *
1052
 
         * @param string $userDN
1053
 
         * @access private
1054
 
         */
1055
 
        function getPreferences() {
1056
 
                global $wgLDAPPreferences;
1057
 
                global $wgLDAPRetrievePrefs;
1058
 
 
1059
 
                $this->printDebug("Entering getPreferences", NONSENSITIVE);
1060
 
 
1061
 
                $this->userInfo = $this->getUserInfo();
1062
 
                if ( is_null( $this->userInfo ) ) {
1063
 
                        $this->printDebug("Failed to get preferences", NONSENSITIVE);
1064
 
                }
1065
 
 
1066
 
                //Retrieve preferences
1067
 
                if ( isset( $wgLDAPPreferences[$_SESSION['wsDomain']] ) ) {
1068
 
                        $this->printDebug( "Retrieving preferences", NONSENSITIVE );
1069
 
                        $prefs = $wgLDAPPreferences[$_SESSION['wsDomain']];
1070
 
                        foreach ( array_keys( $prefs ) as $key ) {
1071
 
                                switch ( $key ) {
1072
 
                                        case "email":
1073
 
                                                if ( isset( $this->userInfo[0]["$prefs[$key]"] ) ) {
1074
 
                                                        $this->email = $this->userInfo[0]["$prefs[$key]"][0];
1075
 
                                                        $this->printDebug( "Retrieved email ($this->email) using attribute ($prefs[$key])", NONSENSITIVE );
1076
 
                                                }
1077
 
                                                break;
1078
 
                                        case "language":
1079
 
                                                if ( isset( $this->userInfo[0]["$prefs[$key]"] ) ) {
1080
 
                                                        $this->lang = $this->userInfo[0][$prefs[$key]][0];
1081
 
                                                        $this->printDebug( "Retrieved language ($this->lang) using attribute ($prefs[$key])", NONSENSITIVE );
1082
 
                                                }
1083
 
                                                break;
1084
 
                                        case "nickname":
1085
 
                                                if ( isset( $this->userInfo[0]["$prefs[$key]"] ) ) {
1086
 
                                                        $this->nickname = $this->userInfo[0]["$prefs[$key]"][0];
1087
 
                                                        $this->printDebug( "Retrieved nickname ($this->nickname) using attribute ($prefs[$key])", NONSENSITIVE );
1088
 
                                                }
1089
 
                                                break;
1090
 
                                        case "realname":
1091
 
                                                if ( isset( $this->userInfo[0]["$prefs[$key]"] ) ) {
1092
 
                                                        $this->realname = $this->userInfo[0]["$prefs[$key]"][0];
1093
 
                                                        $this->printDebug( "Retrieved realname ($this->realname) using attribute ($prefs[$key])", NONSENSITIVE );
1094
 
                                                }
1095
 
                                                break;
1096
 
                                }
1097
 
                        }
1098
 
                } else if ( isset( $wgLDAPRetrievePrefs[$_SESSION['wsDomain']] ) && $wgLDAPRetrievePrefs[$_SESSION['wsDomain']] ) {
1099
 
                        //DEPRECATED. Kept for backwards compatibility.
1100
 
                        $this->printDebug( "Retrieving preferences", NONSENSITIVE );
1101
 
                        $this->printDebug( '$wgLDAPRetrievePrefs is a DEPRECATED option, please use $wgLDAPPreferences.', NONSENSITIVE );
1102
 
 
1103
 
                        if (isset($this->userInfo[0]["mail"])) {
1104
 
                                $this->email = $this->userInfo[0]["mail"][0];
1105
 
                        }
1106
 
                        if (isset($this->userInfo[0]["preferredlanguage"])) {
1107
 
                                $this->lang = $this->userInfo[0]["preferredlanguage"][0];
1108
 
                        }
1109
 
                        if (isset($this->userInfo[0]["displayname"])) {
1110
 
                                $this->nickname = $this->userInfo[0]["displayname"][0];
1111
 
                        }
1112
 
                        if (isset($this->userInfo[0]["cn"])) {
1113
 
                                $this->realname = $this->userInfo[0]["cn"][0];
1114
 
                        }
1115
 
 
1116
 
                        $this->printDebug( "Retrieved: $this->email, $this->lang, $this->nickname, $this->realname", SENSITIVE );
1117
 
                }
1118
 
        }
1119
 
 
1120
 
        function synchUsername( $username ) {
1121
 
                global $wgLDAPUniqueBlockLogin, $wgLDAPUniqueRenameUser;
1122
 
                global $wgLDAPUniqueAttribute;
1123
 
 
1124
 
                $this->printDebug("Entering synchUsername", NONSENSITIVE);
1125
 
 
1126
 
                $this->userInfo = $this->getUserInfo();
1127
 
                if ( is_null( $this->userInfo ) ) {
1128
 
                        $this->printDebug("Failed to get preferences", NONSENSITIVE);
1129
 
                }
1130
 
 
1131
 
                // Are we blocking login/renaming users on unique external ID mismatches?
1132
 
                //     *** WARNING ***
1133
 
                //     This needs to be fixed before use! This probably does not work correctly
1134
 
                //     with all options. It is probably a good idea to refactor the username stuff
1135
 
                //     in general (as it is currently somewhat of a kludge). Also, MediaWiki does
1136
 
                //     not currently have support for this.
1137
 
                //     *** WARNING ***
1138
 
                if ( ( isset( $wgLDAPUniqueBlockLogin[$_SESSION['wsDomain']] ) && $wgLDAPUniqueBlockLogin[$_SESSION['wsDomain']] )
1139
 
                        || ( isset( $wgLDAPUniqueRenameUser[$_SESSION['wsDomain']] ) && $wgLDAPUniqueRenameUser[$_SESSION['wsDomain']] ) ) {
1140
 
 
1141
 
                        $this->printDebug( "Checking for username change in LDAP.", SENSITIVE );
1142
 
 
1143
 
                        //Get the user's unique attribute from LDAP
1144
 
                        if ( isset( $wgLDAPUniqueAttribute[$_SESSION['wsDomain']] ) ) {
1145
 
                                $ldapuniqueattr = $wgLDAPUniqueAttribute[$_SESSION['wsDomain']];
1146
 
                                $this->externalid = $this->info[0][$ldapuniqueattr][0];
1147
 
                        } else {
1148
 
                                return false;
1149
 
                        }
1150
 
 
1151
 
                        $this->printDebug( "Retrieved external id: $this->externalid", SENSITIVE );
1152
 
 
1153
 
                        $retrievedusername = User::whoIsExternalID( "$this->externalid" );
1154
 
 
1155
 
                        $this->printDebug( "Username (in MediaWiki database) of fetched external id: $retrievedusername", SENSITIVE );
1156
 
 
1157
 
                        // See if the username returned from the database matches the username given
1158
 
                        if ( $retrievedusername != '' && ( $username != $retrievedusername ) ) {
1159
 
                                if ( isset( $wgLDAPUniqueBlockLogin[$_SESSION['wsDomain']] )
1160
 
                                        && $wgLDAPUniqueBlockLogin[$_SESSION['wsDomain']] ) {
1161
 
 
1162
 
                                        $this->printDebug( "Usernames do not match, blocking login.", SENSITIVE );
1163
 
                                        return false;
1164
 
                                } else if ( isset( $wgLDAPUniqueRenameUser[$_SESSION['wsDomain']] )
1165
 
                                        && $wgLDAPUniqueRenameUser[$_SESSION['wsDomain']] ) {
1166
 
 
1167
 
                                        $this->printDebug( "Usernames do not match, renaming user in database.", SENSITIVE );
1168
 
 
1169
 
                                        global $wgVersion;
1170
 
                                        if ( version_compare( $wgVersion, '1.7.0', '<' ) ) {
1171
 
                                                $this->printDebug( "Renaming users is only supported in MediaWiki 1.7+, please upgrade.", SENSITIVE );
1172
 
                                                $this->markAuthFailed();
1173
 
                                                return false;
1174
 
                                        }
1175
 
 
1176
 
                                        $olduser = User::newFromName( $retrievedusername );
1177
 
                                        $uid = $olduser->idForName();
1178
 
 
1179
 
                                        // Ensure we don't require the same class twice
1180
 
                                        if ( !class_exists( 'RenameuserSQL' ) ) {
1181
 
                                                require( 'Renameuser/SpecialRenameuser_body.php' );
1182
 
                                        }
1183
 
 
1184
 
                                        // Make a new rename user object with: from, to, uid of from    
1185
 
                                        $rename = new RenameuserSQL( $retrievedusername, $username, $uid );
1186
 
                                        $rename->rename();
1187
 
 
1188
 
                                        // For the time being we can't just allow the user to log in
1189
 
                                        // as MediaWiki will try to create the user account after we
1190
 
                                        // do a rename. If we don't return false, the user will get
1191
 
                                        // a database error
1192
 
                                        return false;
1193
 
                                }
1194
 
                        }
1195
 
 
1196
 
                        $this->printDebug( "Usernames matched or the user doesn't exist in the database yet.", SENSITIVE );
1197
 
                }
1198
 
 
1199
 
                return true;
1200
 
        }
1201
 
 
1202
 
        /**
1203
 
         * Checks to see whether a user is in a required group.
1204
 
         *
1205
 
         * @param string $username
1206
 
         * @return bool
1207
 
         * @access private
1208
 
         */
1209
 
        function checkGroups( $username ) {
1210
 
                global $wgLDAPGroupDN;
1211
 
                global $wgLDAPRequiredGroups, $wgLDAPExcludedGroups;
1212
 
 
1213
 
                $this->printDebug("Entering checkGroups", NONSENSITIVE);
1214
 
 
1215
 
                //Old style groups, non-nestable and fairly limited on group type (full DN
1216
 
                //versus username). DEPRECATED
1217
 
                if ( $wgLDAPGroupDN ) {
1218
 
                        $this->printDebug( "Checking for (old style) group membership", NONSENSITIVE );
1219
 
                        //we need to do a subbase search for the entry
1220
 
                        $filter = "(member=" . $this->getLdapEscapedString( $this->userdn ) . ")";
1221
 
                        $info = @ldap_get_entries( $this->ldapconn, @ldap_search( $this->ldapconn, $wgLDAPGroupDN, $filter ) );
1222
 
 
1223
 
                        return ( $info["count"] >= 1 );
1224
 
                }
1225
 
 
1226
 
                if ( isset( $wgLDAPExcludedGroups[$_SESSION['wsDomain']] ) ) {
1227
 
                        $this->printDebug( "Checking for excluded group membership", NONSENSITIVE );
1228
 
                        $excgroups = $wgLDAPExcludedGroups[$_SESSION['wsDomain']];
1229
 
                        for ( $i = 0; $i < count( $excgroups ); $i++ ) {
1230
 
                                $excgroups[$i] = strtolower( $excgroups[$i] );
1231
 
                        }
1232
 
 
1233
 
                        $this->printDebug( "Excluded groups:", NONSENSITIVE, $excgroups );
1234
 
 
1235
 
                        foreach ( $this->userLDAPGroups["dn"] as $group ) {
1236
 
                                $this->printDebug( "Checking against: $group", NONSENSITIVE );
1237
 
                                if ( in_array( $group, $excgroups ) ) {
1238
 
                                        $this->printDebug( "Found user in an excluded group.", NONSENSITIVE );
1239
 
                                        return false;
1240
 
                                }
1241
 
                        }
1242
 
                }
1243
 
 
1244
 
                //New style group checking
1245
 
                if ( isset( $wgLDAPRequiredGroups[$_SESSION['wsDomain']] ) ) {
1246
 
                        $this->printDebug( "Checking for (new style) group membership", NONSENSITIVE );
1247
 
                        $reqgroups = $wgLDAPRequiredGroups[$_SESSION['wsDomain']];
1248
 
                        for ( $i = 0; $i < count( $reqgroups ); $i++ ) {
1249
 
                                $reqgroups[$i] = strtolower( $reqgroups[$i] );
1250
 
                        }
1251
 
 
1252
 
                        $this->printDebug( "Required groups:", NONSENSITIVE, $reqgroups );
1253
 
 
1254
 
                        foreach ( $this->userLDAPGroups["dn"] as $group ) {
1255
 
                                $this->printDebug( "Checking against: $group", NONSENSITIVE );
1256
 
                                if ( in_array( $group, $reqgroups ) ) {
1257
 
                                        $this->printDebug( "Found user in a group.", NONSENSITIVE );
1258
 
                                        return true;
1259
 
                                }
1260
 
                        }
1261
 
 
1262
 
                        $this->printDebug("Couldn't find the user in any groups.", NONSENSITIVE );
1263
 
                        return false;
1264
 
                }
1265
 
 
1266
 
                // Ensure we return true if we aren't checking groups.
1267
 
                return true;
1268
 
        }
1269
 
 
1270
 
        /**
1271
 
         * Function to get the user's groups.
1272
 
         *
1273
 
         * @access private
1274
 
         */
1275
 
        function getGroups( $username ) {
1276
 
                global $wgLDAPRequiredGroups, $wgLDAPUseLDAPGroups;
1277
 
                global $wgLDAPGroupUseFullDN, $wgLDAPGroupUseRetrievedUsername;
1278
 
                global $wgLDAPGroupSearchNestedGroups;
1279
 
                global $wgLDAPGroupsPrevail;
1280
 
                global $wgLDAPGroupsUseMemberOf;
1281
 
 
1282
 
                $this->printDebug("Entering getGroups", NONSENSITIVE);
1283
 
 
1284
 
                //Find groups
1285
 
                if ( isset( $wgLDAPRequiredGroups[$_SESSION['wsDomain']] ) || ( isset( $wgLDAPUseLDAPGroups[$_SESSION['wsDomain']] ) && $wgLDAPUseLDAPGroups[$_SESSION['wsDomain']] ) ) {
1286
 
                        $this->printDebug( "Retrieving LDAP group membership", NONSENSITIVE );
1287
 
 
1288
 
                        //Let's figure out what we should be searching for
1289
 
                        if ( isset( $wgLDAPGroupUseFullDN[$_SESSION['wsDomain']] ) && $wgLDAPGroupUseFullDN[$_SESSION['wsDomain']] ) {
1290
 
                                $usertopass = $this->userdn;
1291
 
                        } else {
1292
 
                                if ( ( isset( $wgLDAPGroupUseRetrievedUsername[$_SESSION['wsDomain']] ) && $wgLDAPGroupUseRetrievedUsername[$_SESSION['wsDomain']] )
1293
 
                                        && $this->LDAPUsername != '' ) {
1294
 
 
1295
 
                                        $usertopass = $this->LDAPUsername;
1296
 
                                } else {
1297
 
                                        $usertopass = $username;
1298
 
                                }
1299
 
                        }
1300
 
 
1301
 
                        if ( isset( $wgLDAPGroupsUseMemberOf[$_SESSION['wsDomain']] ) && $wgLDAPGroupsUseMemberOf[$_SESSION['wsDomain']] ) {
1302
 
                                $this->printDebug( "Using memberOf", NONSENSITIVE );
1303
 
                                $this->userInfo = $this->getUserInfo();
1304
 
                                if ( is_null( $this->userInfo ) ) {
1305
 
                                        $this->printDebug("Failed to get memberOf attribute", NONSENSITIVE);
1306
 
                                }
1307
 
                                if ( isset( $this->userInfo[0]["memberof"] ) ) {
1308
 
                                        # The first entry is always a count
1309
 
                                        $memberOfMembers = $this->userInfo[0]["memberof"];
1310
 
                                        array_shift( $memberOfMembers );
1311
 
                                        $groups = array( "dn"=> array(), "short"=>array() );
1312
 
                                        foreach( $memberOfMembers as $mem ) {
1313
 
                                                array_push( $groups["dn"], strtolower( $mem ) );
1314
 
                                        }
1315
 
                                        $this->userLDAPGroups = $groups;
1316
 
                                }
1317
 
                        } else {
1318
 
                                $this->printDebug( "Searching for the groups", NONSENSITIVE );
1319
 
                                $this->userLDAPGroups = $this->searchGroups( $usertopass );
1320
 
 
1321
 
                                if ( isset( $wgLDAPGroupSearchNestedGroups[$_SESSION['wsDomain']] ) && $wgLDAPGroupSearchNestedGroups[$_SESSION['wsDomain']] ) {
1322
 
                                        $this->userLDAPGroups = $this->searchNestedGroups( $this->userLDAPGroups );
1323
 
                                        $this->printDebug( "Got the following nested groups:", SENSITIVE, $this->userLDAPGroups["dn"] );
1324
 
                                }
1325
 
                        }
1326
 
 
1327
 
                        //Only find all groups if the user has any groups; otherwise, we are
1328
 
                        //just wasting a search.
1329
 
                        if ( ( isset( $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) && $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) && count( $this->userLDAPGroups ) != 0 ) {
1330
 
                                $this->allLDAPGroups = $this->searchGroups( '*' );
1331
 
                        }
1332
 
                }
1333
 
        }
1334
 
 
1335
 
        /**
1336
 
         * Function to return an array of nested groups when given a group or list of groups.
1337
 
         * $searchedgroups is used for tail recursion and shouldn't be provided
1338
 
         * when called externally.
1339
 
         *
1340
 
         * @param string $userDN
1341
 
         * @param array $searchedgroups
1342
 
         * @return bool
1343
 
         * @access private
1344
 
         */
1345
 
        function searchNestedGroups( $groups, $searchedgroups = array( "dn" => Array(), "short" => Array() ) ) {
1346
 
                $this->printDebug( "Entering searchNestedGroups", NONSENSITIVE );
1347
 
 
1348
 
                //base case, no more groups left to check
1349
 
                if ( count( $groups["dn"] ) == 0 ) {
1350
 
                        $this->printDebug( "No more groups to search.", NONSENSITIVE );
1351
 
                        return $searchedgroups;
1352
 
                }
1353
 
 
1354
 
                $this->printDebug( "Searching groups:", SENSITIVE, $groups["dn"] );
1355
 
 
1356
 
                $groupstosearch = array( "short"=>array(), "dn"=>array() );
1357
 
                foreach ( $groups["dn"] as $group ) {
1358
 
                        $returnedgroups = $this->searchGroups( $group );
1359
 
                        $this->printDebug( "Group $group is in the following groups:", SENSITIVE, $returnedgroups["dn"] );
1360
 
                        foreach ( $returnedgroups["dn"] as $searchme ) {
1361
 
                                if ( in_array( $searchme, $searchedgroups["dn"] ) ) {
1362
 
                                        //We already searched this, move on
1363
 
                                        continue;
1364
 
                                } else {
1365
 
                                        //We'll need to search this group's members now
1366
 
                                        $this->printDebug( "Adding $searchme to the list of groups (1)", SENSITIVE );
1367
 
                                        $groupstosearch["dn"][] = $searchme;
1368
 
                                }
1369
 
                        }
1370
 
                        foreach ( $returnedgroups["short"] as $searchme ) {
1371
 
                                if ( in_array( $searchme, $searchedgroups["short"] ) ) {
1372
 
                                        //We already searched this, move on
1373
 
                                        continue;
1374
 
                                } else {
1375
 
                                        $this->printDebug( "Adding $searchme to the list of groups (2)", SENSITIVE );
1376
 
                                        //We'll need to search this group's members now
1377
 
                                        $groupstosearch["short"][] = $searchme;
1378
 
                                }
1379
 
                        }
1380
 
                }
1381
 
 
1382
 
                $searchedgroups = array_merge_recursive( $groups, $searchedgroups );
1383
 
 
1384
 
                //Mmmmmm. Tail recursion. Tasty.
1385
 
                return $this->searchNestedGroups( $groupstosearch, $searchedgroups ); 
1386
 
        }
1387
 
 
1388
 
        /**
1389
 
         * Search groups for the supplied DN
1390
 
         *
1391
 
         * @param string $dn
1392
 
         * @return array
1393
 
         * @access private
1394
 
         */
1395
 
        function searchGroups( $dn ) {
1396
 
                global $wgLDAPGroupObjectclass, $wgLDAPGroupAttribute, $wgLDAPGroupNameAttribute;
1397
 
                global $wgLDAPProxyAgent, $wgLDAPProxyAgentPassword;
1398
 
                global $wgUser;
1399
 
 
1400
 
                $this->printDebug( "Entering searchGroups", NONSENSITIVE );
1401
 
 
1402
 
                $base = $this->getBaseDN( GROUPDN );
1403
 
 
1404
 
                $objectclass = $wgLDAPGroupObjectclass[$_SESSION['wsDomain']];
1405
 
                $attribute = $wgLDAPGroupAttribute[$_SESSION['wsDomain']];
1406
 
                $nameattribute = $wgLDAPGroupNameAttribute[$_SESSION['wsDomain']];
1407
 
 
1408
 
                // We actually want to search for * not \2a
1409
 
                $value = $dn;
1410
 
                if ( $value != "*" )
1411
 
                        $value = $this->getLdapEscapedString( $value );
1412
 
 
1413
 
                $filter = "(&($attribute=$value)(objectclass=$objectclass))";
1414
 
 
1415
 
                $this->printDebug( "Search string: $filter", SENSITIVE );
1416
 
 
1417
 
                if ( isset( $wgLDAPProxyAgent[$_SESSION['wsDomain']] ) ) {
1418
 
                        //We'll try to bind as the proxyagent as the proxyagent should normally have more
1419
 
                        //rights than the user. If the proxyagent fails to bind, we will still be able
1420
 
                        //to search as the normal user (which is why we don't return on fail).
1421
 
                        $this->printDebug( "Binding as the proxyagent", NONSENSITIVE );
1422
 
                        $bind = $this->bindAs( $wgLDAPProxyAgent[$_SESSION['wsDomain']], $wgLDAPProxyAgentPassword[$_SESSION['wsDomain']] );
1423
 
                }
1424
 
 
1425
 
                $info = @ldap_search( $this->ldapconn, $base, $filter );
1426
 
                #if ( $info["count"] < 1 ) {
1427
 
                if ( !$info ) {
1428
 
                        $this->printDebug( "No entries returned from search.", SENSITIVE );
1429
 
 
1430
 
                        //Return an array so that other functions
1431
 
                        //don't error out.
1432
 
                        return array( "short"=>array(), "dn"=>array() );
1433
 
                }
1434
 
 
1435
 
                $entries = @ldap_get_entries( $this->ldapconn, $info );
1436
 
 
1437
 
                //We need to shift because the first entry will be a count
1438
 
                array_shift( $entries );
1439
 
 
1440
 
                //Let's get a list of both full dn groups and shortname groups
1441
 
                $groups = array( "short"=>array(), "dn"=>array() );
1442
 
                foreach ( $entries as $entry ) {
1443
 
                        $shortMember = strtolower( $entry[$nameattribute][0] );
1444
 
                        $dnMember = strtolower( $entry['dn'] );
1445
 
                        $groups["short"][] = $shortMember;
1446
 
                        $groups["dn"][] = $dnMember;
1447
 
                }
1448
 
 
1449
 
                $this->printDebug( "Returned groups:", SENSITIVE, $groups["dn"] );
1450
 
 
1451
 
                return $groups;
1452
 
        }
1453
 
 
1454
 
        /**
1455
 
         * Returns true if this group is in the list of the currently authenticated
1456
 
         * user's groups, else false.
1457
 
         *
1458
 
         * @param string $group
1459
 
         * @return bool
1460
 
         * @access private
1461
 
         */
1462
 
        function hasLDAPGroup( $group ) {
1463
 
                $this->printDebug( "Entering hasLDAPGroup", NONSENSITIVE );
1464
 
 
1465
 
                return in_array( strtolower( $group ), $this->userLDAPGroups["short"] );
1466
 
        }
1467
 
 
1468
 
        /**
1469
 
         * Returns true if an LDAP group with this name exists, else false.
1470
 
         *
1471
 
         * @param string $group
1472
 
         * @return bool
1473
 
         * @access private
1474
 
         */
1475
 
        function isLDAPGroup( $group ) {
1476
 
                $this->printDebug( "Entering isLDAPGroup", NONSENSITIVE );
1477
 
 
1478
 
                return in_array( strtolower( $group ), $this->allLDAPGroups["short"] );
1479
 
        }
1480
 
 
1481
 
        /**
1482
 
         * Helper function for updateUser() and initUser(). Adds users into MediaWiki security groups
1483
 
         * based upon groups retreived from LDAP.
1484
 
         *
1485
 
         * @param User $user
1486
 
         * @access private
1487
 
         */
1488
 
        function setGroups( &$user ) {
1489
 
                global $wgLDAPGroupsPrevail, $wgGroupPermissions;
1490
 
                global $wgLDAPLocallyManagedGroups;
1491
 
 
1492
 
                //TODO: this is *really* ugly code. clean it up!
1493
 
 
1494
 
                $this->printDebug( "Entering setGroups.", NONSENSITIVE );
1495
 
 
1496
 
                # add groups permissions
1497
 
                $localAvailGrps = $user->getAllGroups();
1498
 
                $localUserGrps = $user->getEffectiveGroups();
1499
 
                
1500
 
                $defaultLocallyManagedGrps = array( 'bot', 'sysop', 'bureaucrat' );
1501
 
 
1502
 
                if ( isset( $wgLDAPLocallyManagedGroups[$_SESSION['wsDomain']] ) ) {
1503
 
                        $locallyManagedGrps = $wgLDAPLocallyManagedGroups[$_SESSION['wsDomain']];
1504
 
                        $locallyManagedGrps = array_unique( array_merge( $defaultLocallyManagedGrps, $locallyManagedGrps ) );           
1505
 
                        $this->printDebug( "Locally managed groups: ", SENSITIVE, $locallyManagedGrps );
1506
 
                } else {
1507
 
                        $locallyManagedGrps = $defaultLocallyManagedGrps;
1508
 
                        $this->printDebug( "Locally managed groups is unset, using defaults: ", SENSITIVE, $locallyManagedGrps );
1509
 
                }
1510
 
                        
1511
 
 
1512
 
                # Add ldap groups as local groups
1513
 
                if ( isset( $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) && $wgLDAPGroupsPrevail[$_SESSION['wsDomain']] ) {
1514
 
                        $this->printDebug( "Adding all groups to wgGroupPermissions: ", SENSITIVE, $this->allLDAPGroups );
1515
 
                        foreach ( $this->allLDAPGroups["short"] as $ldapgroup )
1516
 
                                if ( !array_key_exists( $ldapgroup, $wgGroupPermissions ) )
1517
 
                                        $wgGroupPermissions[$ldapgroup] = array();
1518
 
                }
1519
 
 
1520
 
                $this->printDebug( "Available groups are: ", NONSENSITIVE, $localAvailGrps );
1521
 
                $this->printDebug( "Effective groups are: ", NONSENSITIVE, $localUserGrps );
1522
 
 
1523
 
                # note: $localUserGrps does not need to be updated with $cGroup added,
1524
 
                #       as $localAvailGrps contains $cGroup only once.
1525
 
                foreach ( $localAvailGrps as $cGroup ) {
1526
 
                        # did we once add the user to the group?
1527
 
                        if ( in_array( $cGroup,$localUserGrps ) ) {
1528
 
                                $this->printDebug( "Checking to see if we need to remove user from: $cGroup", NONSENSITIVE );
1529
 
                                if ( ( !$this->hasLDAPGroup( $cGroup ) ) && ( !in_array( $cGroup, $locallyManagedGrps ) ) ) {
1530
 
                                        $this->printDebug( "Removing user from: $cGroup", NONSENSITIVE );
1531
 
                                        # the ldap group overrides the local group
1532
 
                                        # so as the user is currently not a member of the ldap group, he shall be removed from the local group
1533
 
                                        $user->removeGroup( $cGroup );
1534
 
                                }
1535
 
                        } else { # no, but maybe the user has recently been added to the ldap group?
1536
 
                                $this->printDebug( "Checking to see if user is in: $cGroup", NONSENSITIVE );
1537
 
                                if ( $this->hasLDAPGroup( $cGroup ) ) {
1538
 
                                        $this->printDebug( "Adding user to: $cGroup", NONSENSITIVE );
1539
 
                                        $user->addGroup( $cGroup );
1540
 
                                }
1541
 
                        }
1542
 
                }
1543
 
        }
1544
 
 
1545
 
        /**
1546
 
         * Returns a password that is created via the configured hash settings.
1547
 
         *
1548
 
         * @param string $password
1549
 
         * @return string
1550
 
         * @access private
1551
 
         */
1552
 
        function getPasswordHash( $password ) {
1553
 
                global $wgLDAPPasswordHash;
1554
 
 
1555
 
                $this->printDebug( "Entering getPasswordHash", NONSENSITIVE );
1556
 
 
1557
 
                if ( isset( $wgLDAPPasswordHash[$_SESSION['wsDomain']] ) ) {
1558
 
                        $hashtouse = $wgLDAPPasswordHash[$_SESSION['wsDomain']];
1559
 
                } else {
1560
 
                        $hashtouse = '';
1561
 
                }
1562
 
 
1563
 
                //Set the password hashing based upon admin preference
1564
 
                switch ( $hashtouse ) {
1565
 
                        case 'crypt':
1566
 
                                $pass = '{CRYPT}' . crypt( $password );
1567
 
                                break;
1568
 
                        case 'clear':
1569
 
                                $pass = $password;
1570
 
                                break;
1571
 
                        default:
1572
 
                                $pwd_sha = base64_encode( pack( 'H*',sha1( $password ) ) );
1573
 
                                $pass = "{SHA}".$pwd_sha;
1574
 
                                break;
1575
 
                }
1576
 
 
1577
 
                $this->printDebug( "Password is $pass", HIGHLYSENSITIVE );
1578
 
                return $pass;
1579
 
        }
1580
 
 
1581
 
        /**
1582
 
         * Prints debugging information. $debugText is what you want to print, $debugVal
1583
 
         * is the level at which you want to print the information.
1584
 
         *
1585
 
         * @param string $debugText
1586
 
         * @param string $debugVal
1587
 
         * @access private
1588
 
         */
1589
 
        function printDebug( $debugText, $debugVal, $debugArr = null ) {
1590
 
                global $wgLDAPDebug;
1591
 
 
1592
 
                if ( isset( $debugArr ) ) {
1593
 
                        if ( $wgLDAPDebug > $debugVal ) {
1594
 
                                $text = $debugText . " " . implode( "::", $debugArr );
1595
 
                                wfDebugLog( 'ldap', $text, false );
1596
 
                        }
1597
 
                } else {
1598
 
                        if ( $wgLDAPDebug > $debugVal ) {
1599
 
                                wfDebugLog( 'ldap', $debugText, false );
1600
 
                        }
1601
 
                }
1602
 
        }
1603
 
 
1604
 
        /**
1605
 
         * Binds as $userdn with $password. This can be called with only the ldap
1606
 
         * connection resource for an anonymous bind.
1607
 
         *
1608
 
         * @param string $userdn
1609
 
         * @param string $password
1610
 
         * @return bool
1611
 
         * @access private
1612
 
         */
1613
 
        function bindAs( $userdn=null, $password=null ) {
1614
 
                //Let's see if the user can authenticate.
1615
 
                if ( $userdn == null || $password == null ) {
1616
 
                        $bind = @ldap_bind( $this->ldapconn );
1617
 
                } else {
1618
 
                        $bind = @ldap_bind( $this->ldapconn, $userdn, $password );
1619
 
                }
1620
 
                if ( !$bind ) {
1621
 
                        $this->printDebug( "Failed to bind as $userdn", NONSENSITIVE );
1622
 
                        $this->printDebug( "with password: $password", HIGHLYSENSITIVE );
1623
 
                        return false;
1624
 
                }
1625
 
                return true;
1626
 
        }
1627
 
 
1628
 
        /**
1629
 
         * Returns true if auto-authentication is allowed, and the user is
1630
 
         * authenticating using the auto-authentication domain.
1631
 
         *
1632
 
         * @return bool
1633
 
         * @access private
1634
 
         */
1635
 
        function useAutoAuth() {
1636
 
                global $wgLDAPAutoAuthDomain;
1637
 
 
1638
 
                $this->printDebug( "", NONSENSITIVE );
1639
 
                return isset( $wgLDAPAutoAuthDomain ) && $_SESSION['wsDomain'] == $wgLDAPAutoAuthDomain;
1640
 
        }
1641
 
 
1642
 
        /**
1643
 
         * Returns a string which has the chars *, (, ), \ & NUL escaped to LDAP compliant
1644
 
         * syntax as per RFC 2254
1645
 
         * Thanks and credit to Iain Colledge for the research and function.
1646
 
         * 
1647
 
         * @param string $string
1648
 
         * @return string
1649
 
         * @access private
1650
 
         */
1651
 
        function getLdapEscapedString ( $string ) {
1652
 
                // Make the string LDAP compliant by escaping *, (, ) , \ & NUL
1653
 
                return str_replace(
1654
 
                        array( "*", "(", ")", "\\", "\x00" ), //replace this
1655
 
                        array( "\\2a", "\\28", "\\29", "\\5c", "\\00" ), //with this
1656
 
                        $string //in this
1657
 
                        );
1658
 
        }
1659
 
 
1660
 
        /**
1661
 
         * Returns a basedn by the type of entry we are searching for.
1662
 
         * 
1663
 
         * @param int $type
1664
 
         * @return string
1665
 
         * @access private
1666
 
         */
1667
 
        function getBaseDN ( $type ) {
1668
 
                global $wgLDAPBaseDNs, $wgLDAPGroupBaseDNs, $wgLDAPUserBaseDNs;
1669
 
 
1670
 
                $this->printDebug( "Entering getBaseDN", NONSENSITIVE );
1671
 
 
1672
 
                $ret = '';
1673
 
                switch( $type ) {
1674
 
                        case USERDN:
1675
 
                                if ( isset( $wgLDAPUserBaseDNs[$_SESSION['wsDomain']] ) ) {
1676
 
                                        $ret = $wgLDAPUserBaseDNs[$_SESSION['wsDomain']];
1677
 
                                }
1678
 
                                break;
1679
 
                        case GROUPDN:
1680
 
                                if ( isset( $wgLDAPGroupBaseDNs[$_SESSION['wsDomain']] ) ) {
1681
 
                                        $ret =  $wgLDAPGroupBaseDNs[$_SESSION['wsDomain']];
1682
 
                                }
1683
 
                                break;
1684
 
                        case DEFAULTDN:
1685
 
                                if ( isset( $wgLDAPBaseDNs[$_SESSION['wsDomain']] ) ) {
1686
 
                                        $ret = $wgLDAPBaseDNs[$_SESSION['wsDomain']];
1687
 
                                        $this->printDebug( "basedn is $ret", NONSENSITIVE );
1688
 
                                        return $ret;
1689
 
                                } else {
1690
 
                                        $this->printDebug( "basedn is not set.", NONSENSITIVE );
1691
 
                                        return '';
1692
 
                                }
1693
 
                                break;
1694
 
                }
1695
 
 
1696
 
                if ( $ret == '' ) {
1697
 
                        $this->printDebug( "basedn is not set for this type of entry, trying to get the default basedn.", NONSENSITIVE );
1698
 
                        // We will never reach here if $type is self::DEFAULTDN, so to avoid code
1699
 
                        // code duplication, we'll get the default by re-calling the function.
1700
 
                        return $this->getBaseDN( DEFAULTDN );
1701
 
                } else {
1702
 
                        $this->printDebug( "basedn is $ret", NONSENSITIVE );
1703
 
                        return $ret;
1704
 
                }
1705
 
        }
1706
 
 
1707
 
}
1708
 
 
1709
 
// The following was derived from the SSL Authentication plugin
1710
 
// http://www.mediawiki.org/wiki/SSL_authentication
1711
 
 
1712
 
/**
1713
 
 * Sets up the SSL authentication piece of the LDAP plugin.
1714
 
 *
1715
 
 * @access public
1716
 
 */
1717
 
function AutoAuthSetup() {
1718
 
        global $wgLDAPAutoAuthUsername;
1719
 
        global $wgLDAPSSLUsername;
1720
 
        global $wgLDAPAutoAuthDomain;
1721
 
        global $wgLDAPSmartcardDomain;
1722
 
        global $wgHooks;
1723
 
        global $wgAuth;
1724
 
 
1725
 
        $wgAuth = new LdapAuthenticationPlugin();
1726
 
 
1727
 
        $wgAuth->printDebug( "Entering AutoAuthSetup.", NONSENSITIVE );
1728
 
 
1729
 
        //Set configuration options for backwards compatibility
1730
 
        if ( isset( $wgLDAPSSLUsername ) ) {
1731
 
                $wgAuth->printDebug( 'Setting $wgLDAPAutoAuthUsername to $wgLDAPSSLUsername; please change your configuration to fix this deprecated configuration variable.', NONSENSITIVE );
1732
 
                $wgLDAPAutoAuthUsername = $wgLDAPSSLUsername;
1733
 
        }
1734
 
        if ( isset( $wgLDAPSmartcardDomain ) ) {
1735
 
                $wgAuth->printDebug( 'Setting $wgLDAPAutoAuthDomain to $wgLDAPSmartcardDomain; please change your configuration to fix this deprecated configuration variable.', NONSENSITIVE );
1736
 
                $wgLDAPAutoAuthDomain = $wgLDAPSmartcardDomain;
1737
 
        }
1738
 
 
1739
 
        if( $wgLDAPAutoAuthUsername != null ) {
1740
 
                $wgAuth->printDebug( "wgLDAPAutoAuthUsername is not null, adding hooks.", NONSENSITIVE );
1741
 
                if ( version_compare( $wgVersion, '1.14.0', '<' ) ) {
1742
 
                        $wgHooks['UserLoadFromSession'][] = 'LdapAutoAuthentication::Authenticate';
1743
 
                } else {
1744
 
                        $wgHooks['UserLoadAfterLoadFromSession'][] = 'LdapAutoAuthentication::Authenticate';
1745
 
                }
1746
 
                $wgHooks['PersonalUrls'][] = 'LdapAutoAuthentication::NoLogout'; /* Disallow logout link */
1747
 
        }
1748
 
}