b9ddb2d5 |
1 | <?php |
2 | |
3 | /** |
4 | * @author Martin Dougiamas |
5 | * @license http://www.gnu.org/copyleft/gpl.html GNU Public License |
6 | * @package moodle multiauth |
7 | * |
8 | * Authentication Plugin: LDAP Authentication |
9 | * |
10 | * Authentication using LDAP (Lightweight Directory Access Protocol). |
11 | * |
12 | * 2006-08-28 File created. |
13 | */ |
14 | |
139ebfdb |
15 | if (!defined('MOODLE_INTERNAL')) { |
16 | die('Direct access to this script is forbidden.'); /// It must be included from a Moodle page |
b9ddb2d5 |
17 | } |
18 | |
6bc1e5d5 |
19 | require_once($CFG->libdir.'/authlib.php'); |
20 | |
b9ddb2d5 |
21 | /** |
22 | * LDAP authentication plugin. |
23 | */ |
6bc1e5d5 |
24 | class auth_plugin_ldap extends auth_plugin_base { |
b9ddb2d5 |
25 | |
26 | /** |
139ebfdb |
27 | * Constructor with initialisation. |
b9ddb2d5 |
28 | */ |
29 | function auth_plugin_ldap() { |
6bc1e5d5 |
30 | $this->authtype = 'ldap'; |
b9ddb2d5 |
31 | $this->config = get_config('auth/ldap'); |
139ebfdb |
32 | if (empty($this->config->ldapencoding)) { |
33 | $this->config->ldapencoding = 'utf-8'; |
34 | } |
35 | if (empty($this->config->user_type)) { |
36 | $this->config->user_type = 'default'; |
37 | } |
38 | |
39 | $default = $this->ldap_getdefaults(); |
40 | |
41 | //use defaults if values not given |
42 | foreach ($default as $key => $value) { |
43 | // watch out - 0, false are correct values too |
44 | if (!isset($this->config->{$key}) or $this->config->{$key} == '') { |
45 | $this->config->{$key} = $value[$this->config->user_type]; |
46 | } |
47 | } |
48 | //hack prefix to objectclass |
430759a5 |
49 | if (empty($this->config->objectclass)) { // Can't send empty filter |
50 | $this->config->objectclass='objectClass=*'; |
51 | } else if (strpos($this->config->objectclass, 'objectClass=') !== 0) { |
52 | $this->config->objectclass = 'objectClass='.$this->config->objectclass; |
139ebfdb |
53 | } |
430759a5 |
54 | |
b9ddb2d5 |
55 | } |
56 | |
57 | /** |
58 | * Returns true if the username and password work and false if they are |
59 | * wrong or don't exist. |
60 | * |
139ebfdb |
61 | * @param string $username The username (with system magic quotes) |
62 | * @param string $password The password (with system magic quotes) |
63 | * |
64 | * @return bool Authentication success or failure. |
b9ddb2d5 |
65 | */ |
66 | function user_login($username, $password) { |
b7b50143 |
67 | if (! function_exists('ldap_bind')) { |
43c6650b |
68 | print_error('auth_ldapnotinstalled','auth'); |
b7b50143 |
69 | return false; |
70 | } |
b9ddb2d5 |
71 | |
b9ddb2d5 |
72 | if (!$username or !$password) { // Don't allow blank usernames or passwords |
73 | return false; |
74 | } |
139ebfdb |
75 | |
76 | $textlib = textlib_get_instance(); |
77 | $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); |
78 | $extpassword = $textlib->convert(stripslashes($password), 'utf-8', $this->config->ldapencoding); |
b9ddb2d5 |
79 | |
80 | $ldapconnection = $this->ldap_connect(); |
81 | |
82 | if ($ldapconnection) { |
139ebfdb |
83 | $ldap_user_dn = $this->ldap_find_userdn($ldapconnection, $extusername); |
84 | |
b9ddb2d5 |
85 | //if ldap_user_dn is empty, user does not exist |
86 | if (!$ldap_user_dn) { |
87 | ldap_close($ldapconnection); |
88 | return false; |
89 | } |
90 | |
91 | // Try to bind with current username and password |
139ebfdb |
92 | $ldap_login = @ldap_bind($ldapconnection, $ldap_user_dn, $extpassword); |
b9ddb2d5 |
93 | ldap_close($ldapconnection); |
94 | if ($ldap_login) { |
95 | return true; |
96 | } |
97 | } |
98 | else { |
99 | @ldap_close($ldapconnection); |
e8b9d76a |
100 | print_error('auth_ldap_noconnect','auth',$this->config->host_url); |
b9ddb2d5 |
101 | } |
102 | return false; |
103 | } |
104 | |
105 | /** |
106 | * reads userinformation from ldap and return it in array() |
107 | * |
108 | * Read user information from external database and returns it as array(). |
109 | * Function should return all information available. If you are saving |
110 | * this information to moodle user-table you should honor syncronization flags |
111 | * |
139ebfdb |
112 | * @param string $username username (with system magic quotes) |
113 | * |
114 | * @return mixed array with no magic quotes or false on error |
b9ddb2d5 |
115 | */ |
116 | function get_userinfo($username) { |
139ebfdb |
117 | $textlib = textlib_get_instance(); |
118 | $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); |
119 | |
b9ddb2d5 |
120 | $ldapconnection = $this->ldap_connect(); |
b9ddb2d5 |
121 | $attrmap = $this->ldap_attributes(); |
139ebfdb |
122 | |
b9ddb2d5 |
123 | $result = array(); |
124 | $search_attribs = array(); |
139ebfdb |
125 | |
b9ddb2d5 |
126 | foreach ($attrmap as $key=>$values) { |
127 | if (!is_array($values)) { |
128 | $values = array($values); |
129 | } |
130 | foreach ($values as $value) { |
131 | if (!in_array($value, $search_attribs)) { |
132 | array_push($search_attribs, $value); |
139ebfdb |
133 | } |
b9ddb2d5 |
134 | } |
135 | } |
136 | |
139ebfdb |
137 | $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername); |
b9ddb2d5 |
138 | |
139ebfdb |
139 | if (!$user_info_result = ldap_read($ldapconnection, $user_dn, $this->config->objectclass, $search_attribs)) { |
140 | return false; // error! |
141 | } |
142 | $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result); |
143 | if (empty($user_entry)) { |
144 | return false; // entry not found |
145 | } |
146 | |
147 | foreach ($attrmap as $key=>$values) { |
148 | if (!is_array($values)) { |
149 | $values = array($values); |
150 | } |
151 | $ldapval = NULL; |
152 | foreach ($values as $value) { |
a8d58c58 |
153 | if ($value == 'dn') { |
154 | $result[$key] = $user_dn; |
155 | } |
139ebfdb |
156 | if (!array_key_exists($value, $user_entry[0])) { |
157 | continue; // wrong data mapping! |
b9ddb2d5 |
158 | } |
139ebfdb |
159 | if (is_array($user_entry[0][$value])) { |
160 | $newval = $textlib->convert($user_entry[0][$value][0], $this->config->ldapencoding, 'utf-8'); |
161 | } else { |
162 | $newval = $textlib->convert($user_entry[0][$value], $this->config->ldapencoding, 'utf-8'); |
b9ddb2d5 |
163 | } |
139ebfdb |
164 | if (!empty($newval)) { // favour ldap entries that are set |
165 | $ldapval = $newval; |
b9ddb2d5 |
166 | } |
167 | } |
139ebfdb |
168 | if (!is_null($ldapval)) { |
169 | $result[$key] = $ldapval; |
170 | } |
b9ddb2d5 |
171 | } |
172 | |
173 | @ldap_close($ldapconnection); |
b9ddb2d5 |
174 | return $result; |
175 | } |
176 | |
177 | /** |
178 | * reads userinformation from ldap and return it in an object |
179 | * |
139ebfdb |
180 | * @param string $username username (with system magic quotes) |
181 | * @return mixed object or false on error |
b9ddb2d5 |
182 | */ |
183 | function get_userinfo_asobj($username) { |
139ebfdb |
184 | $user_array = $this->get_userinfo($username); |
185 | if ($user_array == false) { |
186 | return false; //error or not found |
187 | } |
188 | $user_array = truncate_userinfo($user_array); |
189 | $user = new object(); |
b9ddb2d5 |
190 | foreach ($user_array as $key=>$value) { |
191 | $user->{$key} = $value; |
192 | } |
193 | return $user; |
194 | } |
195 | |
196 | /** |
197 | * returns all usernames from external database |
198 | * |
199 | * get_userlist returns all usernames from external database |
200 | * |
139ebfdb |
201 | * @return array |
b9ddb2d5 |
202 | */ |
203 | function get_userlist() { |
b9ddb2d5 |
204 | return $this->ldap_get_userlist("({$this->config->user_attribute}=*)"); |
205 | } |
206 | |
207 | /** |
208 | * checks if user exists on external db |
139ebfdb |
209 | * |
210 | * @param string $username (with system magic quotes) |
b9ddb2d5 |
211 | */ |
212 | function user_exists($username) { |
139ebfdb |
213 | |
214 | $textlib = textlib_get_instance(); |
215 | $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); |
216 | |
217 | //returns true if given username exist on ldap |
218 | $users = $this->ldap_get_userlist("({$this->config->user_attribute}=".$this->filter_addslashes($extusername).")"); |
219 | return count($users); |
b9ddb2d5 |
220 | } |
221 | |
222 | /** |
139ebfdb |
223 | * Creates a new user on external database. |
b9ddb2d5 |
224 | * By using information in userobject |
225 | * Use user_exists to prevent dublicate usernames |
226 | * |
139ebfdb |
227 | * @param mixed $userobject Moodle userobject (with system magic quotes) |
228 | * @param mixed $plainpass Plaintext password (with system magic quotes) |
b9ddb2d5 |
229 | */ |
230 | function user_create($userobject, $plainpass) { |
139ebfdb |
231 | $textlib = textlib_get_instance(); |
232 | $extusername = $textlib->convert(stripslashes($userobject->username), 'utf-8', $this->config->ldapencoding); |
233 | $extpassword = $textlib->convert(stripslashes($plainpass), 'utf-8', $this->config->ldapencoding); |
234 | |
344514fc |
235 | switch ($this->config->passtype) { |
236 | case 'md5': |
237 | $extpassword = '{MD5}' . base64_encode(pack('H*', md5($extpassword))); |
238 | break; |
239 | case 'sha1': |
240 | $extpassword = '{SHA}' . base64_encode(pack('H*', sha1($extpassword))); |
241 | break; |
242 | case 'plaintext': |
243 | default: |
244 | break; // plaintext |
245 | } |
246 | |
b9ddb2d5 |
247 | $ldapconnection = $this->ldap_connect(); |
248 | $attrmap = $this->ldap_attributes(); |
139ebfdb |
249 | |
b9ddb2d5 |
250 | $newuser = array(); |
139ebfdb |
251 | |
b9ddb2d5 |
252 | foreach ($attrmap as $key => $values) { |
253 | if (!is_array($values)) { |
254 | $values = array($values); |
255 | } |
256 | foreach ($values as $value) { |
257 | if (!empty($userobject->$key) ) { |
139ebfdb |
258 | $newuser[$value] = $textlib->convert(stripslashes($userobject->$key), 'utf-8', $this->config->ldapencoding); |
b9ddb2d5 |
259 | } |
260 | } |
261 | } |
139ebfdb |
262 | |
b9ddb2d5 |
263 | //Following sets all mandatory and other forced attribute values |
264 | //User should be creted as login disabled untill email confirmation is processed |
139ebfdb |
265 | //Feel free to add your user type and send patches to paca@sci.fi to add them |
b9ddb2d5 |
266 | //Moodle distribution |
267 | |
268 | switch ($this->config->user_type) { |
269 | case 'edir': |
139ebfdb |
270 | $newuser['objectClass'] = array("inetOrgPerson","organizationalPerson","person","top"); |
271 | $newuser['uniqueId'] = $extusername; |
272 | $newuser['logindisabled'] = "TRUE"; |
273 | $newuser['userpassword'] = $extpassword; |
b9ddb2d5 |
274 | break; |
275 | default: |
e8b9d76a |
276 | print_error('auth_ldap_unsupportedusertype','auth',$this->config->user_type); |
b9ddb2d5 |
277 | } |
139ebfdb |
278 | $uadd = $this->ldap_add($ldapconnection, $this->config->user_attribute.'="'.$this->ldap_addslashes($userobject->username).','.$this->config->create_context.'"', $newuser); |
b9ddb2d5 |
279 | ldap_close($ldapconnection); |
280 | return $uadd; |
b9ddb2d5 |
281 | |
b9ddb2d5 |
282 | } |
283 | |
284 | /** |
285 | * return number of days to user password expires |
286 | * |
287 | * If userpassword does not expire it should return 0. If password is already expired |
288 | * it should return negative value. |
289 | * |
6bc1e5d5 |
290 | * @param mixed $username username (with system magic quotes) |
b9ddb2d5 |
291 | * @return integer |
292 | */ |
293 | function password_expire($username) { |
2cef74f9 |
294 | $result = 0; |
139ebfdb |
295 | |
296 | $textlib = textlib_get_instance(); |
297 | $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); |
298 | |
b9ddb2d5 |
299 | $ldapconnection = $this->ldap_connect(); |
139ebfdb |
300 | $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername); |
b9ddb2d5 |
301 | $search_attribs = array($this->config->expireattr); |
302 | $sr = ldap_read($ldapconnection, $user_dn, 'objectclass=*', $search_attribs); |
303 | if ($sr) { |
139ebfdb |
304 | $info = $this->ldap_get_entries($ldapconnection, $sr); |
2cef74f9 |
305 | if (!empty ($info) and !empty($info[0][$this->config->expireattr][0])) { |
306 | $expiretime = $this->ldap_expirationtime2unix($info[0][$this->config->expireattr][0], $ldapconnection, $user_dn); |
307 | if ($expiretime != 0) { |
308 | $now = time(); |
309 | if ($expiretime > $now) { |
310 | $result = ceil(($expiretime - $now) / DAYSECS); |
311 | } |
312 | else { |
313 | $result = floor(($expiretime - $now) / DAYSECS); |
314 | } |
139ebfdb |
315 | } |
b9ddb2d5 |
316 | } |
139ebfdb |
317 | } else { |
b9ddb2d5 |
318 | error_log("ldap: password_expire did't find expiration time."); |
319 | } |
320 | |
321 | //error_log("ldap: password_expire user $user_dn expires in $result days!"); |
322 | return $result; |
323 | } |
324 | |
325 | /** |
326 | * syncronizes user fron external db to moodle user table |
327 | * |
139ebfdb |
328 | * Sync is now using username attribute. |
329 | * |
330 | * Syncing users removes or suspends users that dont exists anymore in external db. |
331 | * Creates new users and updates coursecreator status of users. |
332 | * |
333 | * @param int $bulk_insert_records will insert $bulkinsert_records per insert statement |
334 | * valid only with $unsafe. increase to a couple thousand for |
335 | * blinding fast inserts -- but test it: you may hit mysqld's |
336 | * max_allowed_packet limit. |
337 | * @param bool $do_updates will do pull in data updates from ldap if relevant |
b9ddb2d5 |
338 | */ |
139ebfdb |
339 | function sync_users ($bulk_insert_records = 1000, $do_updates = true) { |
b9ddb2d5 |
340 | |
fa96bfaa |
341 | global $CFG; |
342 | |
139ebfdb |
343 | $textlib = textlib_get_instance(); |
344 | |
fa96bfaa |
345 | $droptablesql = array(); /// sql commands to drop the table (because session scope could be a problem for |
346 | /// some persistent drivers like ODBTP (mssql) or if this function is invoked |
347 | /// from within a PHP application using persistent connections |
b9ddb2d5 |
348 | |
139ebfdb |
349 | // configure a temp table |
350 | print "Configuring temp table\n"; |
fa96bfaa |
351 | switch (strtolower($CFG->dbfamily)) { |
352 | case 'mysql': |
353 | $temptable = $CFG->prefix . 'extuser'; |
354 | $droptablesql[] = 'DROP TEMPORARY TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) |
355 | execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later |
356 | echo "Creating temp table $temptable\n"; |
139ebfdb |
357 | execute_sql('CREATE TEMPORARY TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username)) TYPE=MyISAM', false); |
fa96bfaa |
358 | break; |
359 | case 'postgres': |
360 | $temptable = $CFG->prefix . 'extuser'; |
361 | $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) |
362 | execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later |
363 | echo "Creating temp table $temptable\n"; |
364 | $bulk_insert_records = 1; // no support for multiple sets of values |
139ebfdb |
365 | execute_sql('CREATE TEMPORARY TABLE '. $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false); |
fa96bfaa |
366 | break; |
367 | case 'mssql': |
368 | $temptable = '#'.$CFG->prefix . 'extuser'; /// MSSQL temp tables begin with # |
369 | $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) |
370 | execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later |
371 | echo "Creating temp table $temptable\n"; |
372 | $bulk_insert_records = 1; // no support for multiple sets of values |
139ebfdb |
373 | execute_sql('CREATE TABLE ' . $temptable . ' (username VARCHAR(64), PRIMARY KEY (username))', false); |
fa96bfaa |
374 | break; |
375 | case 'oracle': |
376 | $temptable = $CFG->prefix . 'extuser'; |
377 | $droptablesql[] = 'TRUNCATE TABLE ' . $temptable; // oracle requires truncate before being able to drop a temp table |
378 | $droptablesql[] = 'DROP TABLE ' . $temptable; // sql command to drop the table (because session scope could be a problem) |
379 | execute_sql_arr($droptablesql, true, false); /// Drop temp table to avoid persistence problems later |
380 | echo "Creating temp table $temptable\n"; |
381 | $bulk_insert_records = 1; // no support for multiple sets of values |
139ebfdb |
382 | execute_sql('CREATE GLOBAL TEMPORARY TABLE '.$temptable.' (username VARCHAR(64), PRIMARY KEY (username)) ON COMMIT PRESERVE ROWS', false); |
fa96bfaa |
383 | break; |
b9ddb2d5 |
384 | } |
385 | |
139ebfdb |
386 | print "Connecting to ldap...\n"; |
b9ddb2d5 |
387 | $ldapconnection = $this->ldap_connect(); |
388 | |
389 | if (!$ldapconnection) { |
390 | @ldap_close($ldapconnection); |
139ebfdb |
391 | print get_string('auth_ldap_noconnect','auth',$this->config->host_url); |
392 | exit; |
b9ddb2d5 |
393 | } |
394 | |
395 | //// |
396 | //// get user's list from ldap to sql in a scalable fashion |
397 | //// |
398 | // prepare some data we'll need |
b9ddb2d5 |
399 | $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))"; |
400 | |
401 | $contexts = explode(";",$this->config->contexts); |
139ebfdb |
402 | |
b9ddb2d5 |
403 | if (!empty($this->config->create_context)) { |
404 | array_push($contexts, $this->config->create_context); |
405 | } |
406 | |
407 | $fresult = array(); |
b9ddb2d5 |
408 | foreach ($contexts as $context) { |
409 | $context = trim($context); |
410 | if (empty($context)) { |
411 | continue; |
412 | } |
413 | begin_sql(); |
414 | if ($this->config->search_sub) { |
415 | //use ldap_search to find first user from subtree |
416 | $ldap_result = ldap_search($ldapconnection, $context, |
417 | $filter, |
418 | array($this->config->user_attribute)); |
139ebfdb |
419 | } else { |
b9ddb2d5 |
420 | //search only in this context |
421 | $ldap_result = ldap_list($ldapconnection, $context, |
422 | $filter, |
423 | array($this->config->user_attribute)); |
424 | } |
425 | |
426 | if ($entry = ldap_first_entry($ldapconnection, $ldap_result)) { |
427 | do { |
139ebfdb |
428 | $value = ldap_get_values_len($ldapconnection, $entry, $this->config->user_attribute); |
429 | $value = $textlib->convert($value[0], $this->config->ldapencoding, 'utf-8'); |
b9ddb2d5 |
430 | array_push($fresult, $value); |
431 | if (count($fresult) >= $bulk_insert_records) { |
fa96bfaa |
432 | $this->ldap_bulk_insert($fresult, $temptable); |
139ebfdb |
433 | $fresult = array(); |
434 | } |
435 | } while ($entry = ldap_next_entry($ldapconnection, $entry)); |
b9ddb2d5 |
436 | } |
139ebfdb |
437 | unset($ldap_result); // free mem |
b9ddb2d5 |
438 | |
439 | // insert any remaining users and release mem |
440 | if (count($fresult)) { |
fa96bfaa |
441 | $this->ldap_bulk_insert($fresult, $temptable); |
139ebfdb |
442 | $fresult = array(); |
b9ddb2d5 |
443 | } |
444 | commit_sql(); |
445 | } |
b9ddb2d5 |
446 | |
447 | /// preserve our user database |
448 | /// if the temp table is empty, it probably means that something went wrong, exit |
449 | /// so as to avoid mass deletion of users; which is hard to undo |
139ebfdb |
450 | $count = get_record_sql('SELECT COUNT(username) AS count, 1 FROM ' . $temptable); |
b9ddb2d5 |
451 | $count = $count->{'count'}; |
452 | if ($count < 1) { |
453 | print "Did not get any users from LDAP -- error? -- exiting\n"; |
454 | exit; |
fa96bfaa |
455 | } else { |
139ebfdb |
456 | print "Got $count records from LDAP\n\n"; |
b9ddb2d5 |
457 | } |
458 | |
b9ddb2d5 |
459 | |
139ebfdb |
460 | /// User removal |
461 | // find users in DB that aren't in ldap -- to be removed! |
462 | // this is still not as scalable (but how often do we mass delete?) |
463 | if (!empty($this->config->removeuser)) { |
464 | $sql = "SELECT u.id, u.username, u.email |
465 | FROM {$CFG->prefix}user u |
466 | LEFT JOIN $temptable e ON u.username = e.username |
467 | WHERE u.auth='ldap' |
468 | AND u.deleted=0 |
469 | AND e.username IS NULL"; |
470 | $remove_users = get_records_sql($sql); |
471 | |
472 | if (!empty($remove_users)) { |
473 | print "User entries to remove: ". count($remove_users) . "\n"; |
474 | |
475 | begin_sql(); |
476 | foreach ($remove_users as $user) { |
477 | if ($this->config->removeuser == 2) { |
478 | //following is copy pasted from admin/user.php |
479 | //maybe this should moved to function in lib/datalib.php |
480 | $updateuser = new object(); |
481 | $updateuser->id = $user->id; |
482 | $updateuser->deleted = 1; |
483 | $updateuser->username = addslashes("$user->email.".time()); // Remember it just in case |
484 | $updateuser->email = ''; // Clear this field to free it up |
485 | $updateuser->idnumber = ''; // Clear this field to free it up |
486 | $updateuser->timemodified = time(); |
487 | if (update_record('user', $updateuser)) { |
488 | delete_records('role_assignments', 'userid', $user->id); // unassign all roles |
489 | //copy pasted part ends |
490 | echo "\t"; print_string('auth_dbdeleteuser', 'auth', array($user->username, $user->id)); echo "\n"; |
491 | } else { |
492 | echo "\t"; print_string('auth_dbdeleteusererror', 'auth', $user->username); echo "\n"; |
493 | } |
494 | } else if ($this->config->removeuser == 1) { |
495 | $updateuser = new object(); |
496 | $updateuser->id = $user->id; |
497 | $updateuser->auth = 'nologin'; |
498 | if (update_record('user', $updateuser)) { |
499 | echo "\t"; print_string('auth_dbsuspenduser', 'auth', array($user->username, $user->id)); echo "\n"; |
500 | } else { |
501 | echo "\t"; print_string('auth_dbsuspendusererror', 'auth', $user->username); echo "\n"; |
502 | } |
503 | } |
b9ddb2d5 |
504 | } |
139ebfdb |
505 | commit_sql(); |
506 | } else { |
507 | print "No user entries to be removed\n"; |
508 | } |
509 | unset($remove_users); // free mem! |
510 | } |
511 | |
512 | /// Revive suspended users |
513 | if (!empty($this->config->removeuser) and $this->config->removeuser == 1) { |
514 | $sql = "SELECT u.id, u.username |
515 | FROM $temptable e, {$CFG->prefix}user u |
516 | WHERE e.username=u.username |
517 | AND u.auth='nologin'"; |
518 | $revive_users = get_records_sql($sql); |
519 | |
520 | if (!empty($revive_users)) { |
521 | print "User entries to be revived: ". count($revive_users) . "\n"; |
522 | |
523 | begin_sql(); |
524 | foreach ($revive_users as $user) { |
525 | $updateuser = new object(); |
526 | $updateuser->id = $user->id; |
527 | $updateuser->auth = 'ldap'; |
528 | if (update_record('user', $updateuser)) { |
529 | echo "\t"; print_string('auth_dbreviveser', 'auth', array($user->username, $user->id)); echo "\n"; |
530 | } else { |
531 | echo "\t"; print_string('auth_dbreviveusererror', 'auth', $user->username); echo "\n"; |
532 | } |
b9ddb2d5 |
533 | } |
139ebfdb |
534 | commit_sql(); |
535 | } else { |
536 | print "No user entries to be revived\n"; |
537 | } |
538 | |
539 | unset($revive_users); |
fa96bfaa |
540 | } |
b9ddb2d5 |
541 | |
139ebfdb |
542 | |
543 | /// User Updates - time-consuming (optional) |
b9ddb2d5 |
544 | if ($do_updates) { |
545 | // narrow down what fields we need to update |
546 | $all_keys = array_keys(get_object_vars($this->config)); |
547 | $updatekeys = array(); |
548 | foreach ($all_keys as $key) { |
549 | if (preg_match('/^field_updatelocal_(.+)$/',$key, $match)) { |
550 | // if we have a field to update it from |
139ebfdb |
551 | // and it must be updated 'onlogin' we |
b9ddb2d5 |
552 | // update it on cron |
553 | if ( !empty($this->config->{'field_map_'.$match[1]}) |
139ebfdb |
554 | and $this->config->{$match[0]} === 'onlogin') { |
b9ddb2d5 |
555 | array_push($updatekeys, $match[1]); // the actual key name |
556 | } |
557 | } |
558 | } |
559 | // print_r($all_keys); print_r($updatekeys); |
560 | unset($all_keys); unset($key); |
139ebfdb |
561 | |
fa96bfaa |
562 | } else { |
563 | print "No updates to be done\n"; |
b9ddb2d5 |
564 | } |
139ebfdb |
565 | if ( $do_updates and !empty($updatekeys) ) { // run updates only if relevant |
566 | $users = get_records_sql("SELECT u.username, u.id |
567 | FROM {$CFG->prefix}user u |
568 | WHERE u.deleted=0 AND u.auth='ldap'"); |
b9ddb2d5 |
569 | if (!empty($users)) { |
570 | print "User entries to update: ". count($users). "\n"; |
139ebfdb |
571 | |
b9ddb2d5 |
572 | $sitecontext = get_context_instance(CONTEXT_SYSTEM); |
139ebfdb |
573 | if (!empty($this->config->creators) and !empty($this->config->memberattribute) |
574 | and $roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { |
575 | $creatorrole = array_shift($roles); // We can only use one, let's use the first one |
576 | } else { |
577 | $creatorrole = false; |
578 | } |
b9ddb2d5 |
579 | |
139ebfdb |
580 | begin_sql(); |
581 | $xcount = 0; |
582 | $maxxcount = 100; |
b9ddb2d5 |
583 | |
139ebfdb |
584 | foreach ($users as $user) { |
585 | echo "\t"; print_string('auth_dbupdatinguser', 'auth', array($user->username, $user->id)); |
586 | if (!$this->update_user_record(addslashes($user->username), $updatekeys)) { |
587 | echo " - ".get_string('skipped'); |
588 | } |
589 | echo "\n"; |
590 | $xcount++; |
591 | |
592 | // update course creators if needed |
593 | if ($creatorrole !== false) { |
594 | if ($this->iscreator($user->username)) { |
595 | role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap'); |
596 | } else { |
6bc1e5d5 |
597 | role_unassign($creatorrole->id, $user->id, 0, $sitecontext->id, 'ldap'); |
b9ddb2d5 |
598 | } |
139ebfdb |
599 | } |
600 | |
601 | if ($xcount++ > $maxxcount) { |
602 | commit_sql(); |
603 | begin_sql(); |
604 | $xcount = 0; |
605 | } |
b9ddb2d5 |
606 | } |
139ebfdb |
607 | commit_sql(); |
608 | unset($users); // free mem |
b9ddb2d5 |
609 | } |
fa96bfaa |
610 | } else { // end do updates |
611 | print "No updates to be done\n"; |
612 | } |
139ebfdb |
613 | |
614 | /// User Additions |
b9ddb2d5 |
615 | // find users missing in DB that are in LDAP |
616 | // note that get_records_sql wants at least 2 fields returned, |
617 | // and gives me a nifty object I don't want. |
139ebfdb |
618 | // note: we do not care about deleted accounts anymore, this feature was replaced by suspending to nologin auth plugin |
619 | $sql = "SELECT e.username, e.username |
620 | FROM $temptable e LEFT JOIN {$CFG->prefix}user u ON e.username = u.username |
621 | WHERE u.id IS NULL"; |
622 | $add_users = get_records_sql($sql); // get rid of the fat |
623 | |
b9ddb2d5 |
624 | if (!empty($add_users)) { |
625 | print "User entries to add: ". count($add_users). "\n"; |
626 | |
139ebfdb |
627 | $sitecontext = get_context_instance(CONTEXT_SYSTEM); |
628 | if (!empty($this->config->creators) and !empty($this->config->memberattribute) |
629 | and $roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { |
b9ddb2d5 |
630 | $creatorrole = array_shift($roles); // We can only use one, let's use the first one |
139ebfdb |
631 | } else { |
632 | $creatorrole = false; |
b9ddb2d5 |
633 | } |
634 | |
635 | begin_sql(); |
636 | foreach ($add_users as $user) { |
139ebfdb |
637 | $user = $this->get_userinfo_asobj(addslashes($user->username)); |
638 | |
b9ddb2d5 |
639 | // prep a few params |
b7b50143 |
640 | $user->modified = time(); |
641 | $user->confirmed = 1; |
139ebfdb |
642 | $user->auth = 'ldap'; |
b7b50143 |
643 | $user->mnethostid = $CFG->mnet_localhost_id; |
139ebfdb |
644 | if (empty($user->lang)) { |
645 | $user->lang = $CFG->lang; |
b9ddb2d5 |
646 | } |
139ebfdb |
647 | |
648 | $user = addslashes_recursive($user); |
649 | |
650 | if ($id = insert_record('user',$user)) { |
651 | echo "\t"; print_string('auth_dbinsertuser', 'auth', array(stripslashes($user->username), $id)); echo "\n"; |
652 | $userobj = $this->update_user_record($user->username); |
653 | if (!empty($this->config->forcechangepassword)) { |
654 | set_user_preference('auth_forcepasswordchange', 1, $userobj->id); |
b9ddb2d5 |
655 | } |
139ebfdb |
656 | } else { |
657 | echo "\t"; print_string('auth_dbinsertusererror', 'auth', $user->username); echo "\n"; |
658 | } |
659 | |
660 | // add course creators if needed |
661 | if ($creatorrole !== false and $this->iscreator(stripslashes($user->username))) { |
662 | role_assign($creatorrole->id, $user->id, 0, $sitecontext->id, 0, 0, 0, 'ldap'); |
b9ddb2d5 |
663 | } |
664 | } |
665 | commit_sql(); |
666 | unset($add_users); // free mem |
fa96bfaa |
667 | } else { |
668 | print "No users to be added\n"; |
b9ddb2d5 |
669 | } |
670 | return true; |
671 | } |
672 | |
139ebfdb |
673 | /** |
674 | * Update a local user record from an external source. |
675 | * This is a lighter version of the one in moodlelib -- won't do |
b9ddb2d5 |
676 | * expensive ops such as enrolment. |
677 | * |
139ebfdb |
678 | * If you don't pass $updatekeys, there is a performance hit and |
679 | * values removed from LDAP won't be removed from moodle. |
680 | * |
681 | * @param string $username username (with system magic quotes) |
b9ddb2d5 |
682 | */ |
683 | function update_user_record($username, $updatekeys = false) { |
b9ddb2d5 |
684 | global $CFG; |
685 | |
686 | //just in case check text case |
687 | $username = trim(moodle_strtolower($username)); |
139ebfdb |
688 | |
b9ddb2d5 |
689 | // get the current user record |
b7b50143 |
690 | $user = get_record('user', 'username', $username, 'mnethostid', $CFG->mnet_localhost_id); |
b9ddb2d5 |
691 | if (empty($user)) { // trouble |
139ebfdb |
692 | error_log("Cannot update non-existent user: ".stripslashes($username)); |
693 | print_error('auth_dbusernotexist','auth',$username); |
b9ddb2d5 |
694 | die; |
695 | } |
696 | |
b7b50143 |
697 | // Protect the userid from being overwritten |
698 | $userid = $user->id; |
699 | |
139ebfdb |
700 | if ($newinfo = $this->get_userinfo($username)) { |
701 | $newinfo = truncate_userinfo($newinfo); |
702 | |
703 | if (empty($updatekeys)) { // all keys? this does not support removing values |
704 | $updatekeys = array_keys($newinfo); |
705 | } |
706 | |
707 | foreach ($updatekeys as $key) { |
708 | if (isset($newinfo[$key])) { |
709 | $value = $newinfo[$key]; |
710 | } else { |
711 | $value = ''; |
b9ddb2d5 |
712 | } |
139ebfdb |
713 | |
714 | if (!empty($this->config->{'field_updatelocal_' . $key})) { |
715 | if ($user->{$key} != $value) { // only update if it's changed |
716 | set_field('user', $key, addslashes($value), 'id', $userid); |
b9ddb2d5 |
717 | } |
718 | } |
719 | } |
139ebfdb |
720 | } else { |
721 | return false; |
b9ddb2d5 |
722 | } |
139ebfdb |
723 | return get_record_select('user', "id = $userid AND deleted = 0"); |
b9ddb2d5 |
724 | } |
725 | |
139ebfdb |
726 | /** |
727 | * Bulk insert in SQL's temp table |
728 | * @param array $users is an array of usernames |
729 | */ |
fa96bfaa |
730 | function ldap_bulk_insert($users, $temptable) { |
731 | |
b9ddb2d5 |
732 | // bulk insert -- superfast with $bulk_insert_records |
139ebfdb |
733 | $sql = 'INSERT INTO ' . $temptable . ' (username) VALUES '; |
b9ddb2d5 |
734 | // make those values safe |
139ebfdb |
735 | $users = addslashes_recursive($users); |
b9ddb2d5 |
736 | // join and quote the whole lot |
139ebfdb |
737 | $sql = $sql . "('" . implode("'),('", $users) . "')"; |
738 | print "\t+ " . count($users) . " users\n"; |
739 | execute_sql($sql, false); |
b9ddb2d5 |
740 | } |
741 | |
742 | |
139ebfdb |
743 | /** |
b9ddb2d5 |
744 | * Activates (enables) user in external db so user can login to external db |
745 | * |
139ebfdb |
746 | * @param mixed $username username (with system magic quotes) |
b9ddb2d5 |
747 | * @return boolen result |
748 | */ |
749 | function user_activate($username) { |
139ebfdb |
750 | $textlib = textlib_get_instance(); |
751 | $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); |
752 | |
b9ddb2d5 |
753 | $ldapconnection = $this->ldap_connect(); |
754 | |
139ebfdb |
755 | $userdn = $this->ldap_find_userdn($ldapconnection, $extusername); |
b9ddb2d5 |
756 | switch ($this->config->user_type) { |
757 | case 'edir': |
758 | $newinfo['loginDisabled']="FALSE"; |
759 | break; |
760 | default: |
139ebfdb |
761 | error ('auth: ldap user_activate() does not support selected usertype:"'.$this->config->user_type.'" (..yet)'); |
762 | } |
b9ddb2d5 |
763 | $result = ldap_modify($ldapconnection, $userdn, $newinfo); |
764 | ldap_close($ldapconnection); |
765 | return $result; |
766 | } |
767 | |
139ebfdb |
768 | /** |
b9ddb2d5 |
769 | * Disables user in external db so user can't login to external db |
770 | * |
771 | * @param mixed $username username |
772 | * @return boolean result |
773 | */ |
139ebfdb |
774 | /* function user_disable($username) { |
775 | $textlib = textlib_get_instance(); |
776 | $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); |
b9ddb2d5 |
777 | |
778 | $ldapconnection = $this->ldap_connect(); |
779 | |
139ebfdb |
780 | $userdn = $this->ldap_find_userdn($ldapconnection, $extusername); |
b9ddb2d5 |
781 | switch ($this->config->user_type) { |
782 | case 'edir': |
783 | $newinfo['loginDisabled']="TRUE"; |
784 | break; |
785 | default: |
139ebfdb |
786 | error ('auth: ldap user_disable() does not support selected usertype (..yet)'); |
787 | } |
b9ddb2d5 |
788 | $result = ldap_modify($ldapconnection, $userdn, $newinfo); |
789 | ldap_close($ldapconnection); |
790 | return $result; |
139ebfdb |
791 | }*/ |
b9ddb2d5 |
792 | |
139ebfdb |
793 | /** |
b9ddb2d5 |
794 | * Returns true if user should be coursecreator. |
795 | * |
6bc1e5d5 |
796 | * @param mixed $username username (without system magic quotes) |
b9ddb2d5 |
797 | * @return boolean result |
798 | */ |
6bc1e5d5 |
799 | function iscreator($username) { |
139ebfdb |
800 | if (empty($this->config->creators) or empty($this->config->memberattribute)) { |
6bc1e5d5 |
801 | return null; |
b9ddb2d5 |
802 | } |
139ebfdb |
803 | |
804 | $textlib = textlib_get_instance(); |
805 | $extusername = $textlib->convert($username, 'utf-8', $this->config->ldapencoding); |
806 | |
6bc1e5d5 |
807 | return (boolean)$this->ldap_isgroupmember($extusername, $this->config->creators); |
b9ddb2d5 |
808 | } |
809 | |
139ebfdb |
810 | /** |
b9ddb2d5 |
811 | * Called when the user record is updated. |
139ebfdb |
812 | * Modifies user in external database. It takes olduser (before changes) and newuser (after changes) |
b9ddb2d5 |
813 | * conpares information saved modified information to external db. |
814 | * |
139ebfdb |
815 | * @param mixed $olduser Userobject before modifications (without system magic quotes) |
816 | * @param mixed $newuser Userobject new modified userobject (without system magic quotes) |
b9ddb2d5 |
817 | * @return boolean result |
818 | * |
819 | */ |
820 | function user_update($olduser, $newuser) { |
821 | |
139ebfdb |
822 | global $USER; |
823 | |
824 | if (isset($olduser->username) and isset($newuser->username) and $olduser->username != $newuser->username) { |
825 | error_log("ERROR:User renaming not allowed in LDAP"); |
826 | return false; |
827 | } |
828 | |
6bc1e5d5 |
829 | if (isset($olduser->auth) and $olduser->auth != 'ldap') { |
139ebfdb |
830 | return true; // just change auth and skip update |
831 | } |
832 | |
833 | $textlib = textlib_get_instance(); |
834 | $extoldusername = $textlib->convert($olduser->username, 'utf-8', $this->config->ldapencoding); |
b9ddb2d5 |
835 | |
836 | $ldapconnection = $this->ldap_connect(); |
139ebfdb |
837 | |
b9ddb2d5 |
838 | $search_attribs = array(); |
839 | |
139ebfdb |
840 | $attrmap = $this->ldap_attributes(); |
b9ddb2d5 |
841 | foreach ($attrmap as $key => $values) { |
842 | if (!is_array($values)) { |
843 | $values = array($values); |
844 | } |
845 | foreach ($values as $value) { |
846 | if (!in_array($value, $search_attribs)) { |
847 | array_push($search_attribs, $value); |
848 | } |
139ebfdb |
849 | } |
b9ddb2d5 |
850 | } |
851 | |
139ebfdb |
852 | $user_dn = $this->ldap_find_userdn($ldapconnection, $extoldusername); |
b9ddb2d5 |
853 | |
854 | $user_info_result = ldap_read($ldapconnection, $user_dn, |
855 | $this->config->objectclass, $search_attribs); |
856 | |
857 | if ($user_info_result) { |
858 | |
859 | $user_entry = $this->ldap_get_entries($ldapconnection, $user_info_result); |
139ebfdb |
860 | if (empty($user_entry)) { |
861 | return false; // old user not found! |
862 | } else if (count($user_entry) > 1) { |
b9ddb2d5 |
863 | trigger_error("ldap: Strange! More than one user record found in ldap. Only using the first one."); |
139ebfdb |
864 | return false; |
b9ddb2d5 |
865 | } |
866 | $user_entry = $user_entry[0]; |
867 | |
868 | //error_log(var_export($user_entry) . 'fpp' ); |
b9ddb2d5 |
869 | |
139ebfdb |
870 | foreach ($attrmap as $key => $ldapkeys) { |
b9ddb2d5 |
871 | // only process if the moodle field ($key) has changed and we |
872 | // are set to update LDAP with it |
139ebfdb |
873 | if (isset($olduser->$key) and isset($newuser->$key) |
874 | and $olduser->$key !== $newuser->$key |
875 | and !empty($this->config->{'field_updateremote_'. $key})) { |
876 | // for ldap values that could be in more than one |
877 | // ldap key, we will do our best to match |
b9ddb2d5 |
878 | // where they came from |
879 | $ambiguous = true; |
880 | $changed = false; |
881 | if (!is_array($ldapkeys)) { |
882 | $ldapkeys = array($ldapkeys); |
883 | } |
884 | if (count($ldapkeys) < 2) { |
885 | $ambiguous = false; |
886 | } |
139ebfdb |
887 | |
888 | $nuvalue = $textlib->convert($newuser->$key, 'utf-8', $this->config->ldapencoding); |
889 | $ouvalue = $textlib->convert($olduser->$key, 'utf-8', $this->config->ldapencoding); |
890 | |
b9ddb2d5 |
891 | foreach ($ldapkeys as $ldapkey) { |
139ebfdb |
892 | $ldapkey = $ldapkey; |
b9ddb2d5 |
893 | $ldapvalue = $user_entry[$ldapkey][0]; |
894 | if (!$ambiguous) { |
895 | // skip update if the values already match |
139ebfdb |
896 | if ($nuvalue !== $ldapvalue) { |
897 | //this might fail due to schema validation |
898 | if (@ldap_modify($ldapconnection, $user_dn, array($ldapkey => $nuvalue))) { |
899 | continue; |
900 | } else { |
901 | error_log('Error updating LDAP record. Error code: ' |
902 | . ldap_errno($ldapconnection) . '; Error string : ' |
903 | . ldap_err2str(ldap_errno($ldapconnection)) |
904 | . "\nKey ($key) - old moodle value: '$ouvalue' new value: '$nuvalue'"); |
905 | continue; |
906 | } |
b9ddb2d5 |
907 | } |
139ebfdb |
908 | } else { |
b9ddb2d5 |
909 | // ambiguous |
910 | // value empty before in Moodle (and LDAP) - use 1st ldap candidate field |
911 | // no need to guess |
139ebfdb |
912 | if ($ouvalue === '') { // value empty before - use 1st ldap candidate |
913 | //this might fail due to schema validation |
914 | if (@ldap_modify($ldapconnection, $user_dn, array($ldapkey => $nuvalue))) { |
b9ddb2d5 |
915 | $changed = true; |
139ebfdb |
916 | continue; |
917 | } else { |
918 | error_log('Error updating LDAP record. Error code: ' |
919 | . ldap_errno($ldapconnection) . '; Error string : ' |
920 | . ldap_err2str(ldap_errno($ldapconnection)) |
921 | . "\nKey ($key) - old moodle value: '$ouvalue' new value: '$nuvalue'"); |
922 | continue; |
b9ddb2d5 |
923 | } |
924 | } |
925 | |
139ebfdb |
926 | // we found which ldap key to update! |
927 | if ($ouvalue !== '' and $ouvalue === $ldapvalue ) { |
928 | //this might fail due to schema validation |
929 | if (@ldap_modify($ldapconnection, $user_dn, array($ldapkey => $nuvalue))) { |
b9ddb2d5 |
930 | $changed = true; |
139ebfdb |
931 | continue; |
932 | } else { |
933 | error_log('Error updating LDAP record. Error code: ' |
b9ddb2d5 |
934 | . ldap_errno($ldapconnection) . '; Error string : ' |
139ebfdb |
935 | . ldap_err2str(ldap_errno($ldapconnection)) |
936 | . "\nKey ($key) - old moodle value: '$ouvalue' new value: '$nuvalue'"); |
937 | continue; |
b9ddb2d5 |
938 | } |
939 | } |
940 | } |
941 | } |
139ebfdb |
942 | |
b9ddb2d5 |
943 | if ($ambiguous and !$changed) { |
139ebfdb |
944 | error_log("Failed to update LDAP with ambiguous field $key". |
945 | " old moodle value: '" . $ouvalue . |
946 | "' new value '" . $nuvalue ); |
b9ddb2d5 |
947 | } |
948 | } |
949 | } |
139ebfdb |
950 | } else { |
b9ddb2d5 |
951 | error_log("ERROR:No user found in LDAP"); |
952 | @ldap_close($ldapconnection); |
953 | return false; |
954 | } |
955 | |
956 | @ldap_close($ldapconnection); |
139ebfdb |
957 | |
b9ddb2d5 |
958 | return true; |
959 | |
960 | } |
961 | |
fb5c7739 |
962 | /** |
b9ddb2d5 |
963 | * changes userpassword in external db |
964 | * |
965 | * called when the user password is updated. |
966 | * changes userpassword in external db |
967 | * |
139ebfdb |
968 | * @param object $user User table object (with system magic quotes) |
969 | * @param string $newpassword Plaintext password (with system magic quotes) |
b9ddb2d5 |
970 | * @return boolean result |
971 | * |
972 | */ |
b9ddb2d5 |
973 | function user_update_password($user, $newpassword) { |
974 | /// called when the user password is updated -- it assumes it is called by an admin |
975 | /// or that you've otherwise checked the user's credentials |
976 | /// IMPORTANT: $newpassword must be cleartext, not crypted/md5'ed |
977 | |
139ebfdb |
978 | global $USER; |
b9ddb2d5 |
979 | $result = false; |
980 | $username = $user->username; |
139ebfdb |
981 | |
982 | $textlib = textlib_get_instance(); |
983 | $extusername = $textlib->convert(stripslashes($username), 'utf-8', $this->config->ldapencoding); |
984 | $extpassword = $textlib->convert(stripslashes($newpassword), 'utf-8', $this->config->ldapencoding); |
985 | |
344514fc |
986 | switch ($this->config->passtype) { |
987 | case 'md5': |
988 | $extpassword = '{MD5}' . base64_encode(pack('H*', md5($extpassword))); |
989 | break; |
990 | case 'sha1': |
991 | $extpassword = '{SHA}' . base64_encode(pack('H*', sha1($extpassword))); |
992 | break; |
993 | case 'plaintext': |
994 | default: |
995 | break; // plaintext |
996 | } |
997 | |
b9ddb2d5 |
998 | $ldapconnection = $this->ldap_connect(); |
999 | |
139ebfdb |
1000 | $user_dn = $this->ldap_find_userdn($ldapconnection, $extusername); |
1001 | |
b9ddb2d5 |
1002 | if (!$user_dn) { |
139ebfdb |
1003 | error_log('LDAP Error in user_update_password(). No DN for: ' . stripslashes($user->username)); |
b9ddb2d5 |
1004 | return false; |
1005 | } |
1006 | |
1007 | switch ($this->config->user_type) { |
1008 | case 'edir': |
1009 | //Change password |
139ebfdb |
1010 | $result = ldap_modify($ldapconnection, $user_dn, array('userPassword' => $extpassword)); |
b9ddb2d5 |
1011 | if (!$result) { |
1012 | error_log('LDAP Error in user_update_password(). Error code: ' |
1013 | . ldap_errno($ldapconnection) . '; Error string : ' |
1014 | . ldap_err2str(ldap_errno($ldapconnection))); |
1015 | } |
1016 | //Update password expiration time, grace logins count |
1017 | $search_attribs = array($this->config->expireattr, 'passwordExpirationInterval','loginGraceLimit' ); |
1018 | $sr = ldap_read($ldapconnection, $user_dn, 'objectclass=*', $search_attribs); |
1019 | if ($sr) { |
1020 | $info=$this->ldap_get_entries($ldapconnection, $sr); |
1021 | $newattrs = array(); |
1022 | if (!empty($info[0][$this->config->expireattr][0])) { |
1023 | //Set expiration time only if passwordExpirationInterval is defined |
1024 | if (!empty($info[0]['passwordExpirationInterval'][0])) { |
139ebfdb |
1025 | $expirationtime = time() + $info[0]['passwordExpirationInterval'][0]; |
b9ddb2d5 |
1026 | $ldapexpirationtime = $this->ldap_unix2expirationtime($expirationtime); |
1027 | $newattrs['passwordExpirationTime'] = $ldapexpirationtime; |
139ebfdb |
1028 | } |
b9ddb2d5 |
1029 | |
1030 | //set gracelogin count |
1031 | if (!empty($info[0]['loginGraceLimit'][0])) { |
139ebfdb |
1032 | $newattrs['loginGraceRemaining']= $info[0]['loginGraceLimit'][0]; |
b9ddb2d5 |
1033 | } |
139ebfdb |
1034 | |
b9ddb2d5 |
1035 | //Store attribute changes to ldap |
1036 | $result = ldap_modify($ldapconnection, $user_dn, $newattrs); |
1037 | if (!$result) { |
1038 | error_log('LDAP Error in user_update_password() when modifying expirationtime and/or gracelogins. Error code: ' |
1039 | . ldap_errno($ldapconnection) . '; Error string : ' |
1040 | . ldap_err2str(ldap_errno($ldapconnection))); |
1041 | } |
1042 | } |
1043 | } |
1044 | else { |
1045 | error_log('LDAP Error in user_update_password() when reading password expiration time. Error code: ' |
1046 | . ldap_errno($ldapconnection) . '; Error string : ' |
1047 | . ldap_err2str(ldap_errno($ldapconnection))); |
d0e84e1b |
1048 | } |
1049 | break; |
1050 | |
1051 | case 'ad': |
1052 | // Passwords in Active Directory must be encoded as Unicode |
1053 | // strings (UCS-2 Little Endian format) and surrounded with |
1054 | // double quotes. See http://support.microsoft.com/?kbid=269190 |
1055 | if (!function_exists('mb_convert_encoding')) { |
1056 | error_log ('You need the mbstring extension to change passwords in Active Directory'); |
1057 | return false; |
1058 | } |
1059 | $extpassword = mb_convert_encoding('"'.$extpassword.'"', "UCS-2LE", $this->config->ldapencoding); |
1060 | $result = ldap_modify($ldapconnection, $user_dn, array('unicodePwd' => $extpassword)); |
1061 | if (!$result) { |
1062 | error_log('LDAP Error in user_update_password(). Error code: ' |
1063 | . ldap_errno($ldapconnection) . '; Error string : ' |
1064 | . ldap_err2str(ldap_errno($ldapconnection))); |
139ebfdb |
1065 | } |
b9ddb2d5 |
1066 | break; |
139ebfdb |
1067 | |
b9ddb2d5 |
1068 | default: |
1069 | $usedconnection = &$ldapconnection; |
1070 | // send ldap the password in cleartext, it will md5 it itself |
139ebfdb |
1071 | $result = ldap_modify($ldapconnection, $user_dn, array('userPassword' => $extpassword)); |
b9ddb2d5 |
1072 | if (!$result) { |
139ebfdb |
1073 | error_log('LDAP Error in user_update_password(). Error code: ' |
b9ddb2d5 |
1074 | . ldap_errno($ldapconnection) . '; Error string : ' |
1075 | . ldap_err2str(ldap_errno($ldapconnection))); |
1076 | } |
139ebfdb |
1077 | |
b9ddb2d5 |
1078 | } |
1079 | |
1080 | @ldap_close($ldapconnection); |
1081 | return $result; |
1082 | } |
1083 | |
1084 | //PRIVATE FUNCTIONS starts |
1085 | //private functions are named as ldap_* |
1086 | |
1087 | /** |
1088 | * returns predefined usertypes |
1089 | * |
1090 | * @return array of predefined usertypes |
1091 | */ |
b9ddb2d5 |
1092 | function ldap_suppported_usertypes() { |
139ebfdb |
1093 | $types = array(); |
b9ddb2d5 |
1094 | $types['edir']='Novell Edirectory'; |
1095 | $types['rfc2307']='posixAccount (rfc2307)'; |
1096 | $types['rfc2307bis']='posixAccount (rfc2307bis)'; |
1097 | $types['samba']='sambaSamAccount (v.3.0.7)'; |
139ebfdb |
1098 | $types['ad']='MS ActiveDirectory'; |
1099 | $types['default']=get_string('default'); |
b9ddb2d5 |
1100 | return $types; |
139ebfdb |
1101 | } |
1102 | |
b9ddb2d5 |
1103 | |
b9ddb2d5 |
1104 | /** |
139ebfdb |
1105 | * Initializes needed variables for ldap-module |
b9ddb2d5 |
1106 | * |
1107 | * Uses names defined in ldap_supported_usertypes. |
1108 | * $default is first defined as: |
1109 | * $default['pseudoname'] = array( |
1110 | * 'typename1' => 'value', |
1111 | * 'typename2' => 'value' |
1112 | * .... |
1113 | * ); |
1114 | * |
1115 | * @return array of default values |
1116 | */ |
1117 | function ldap_getdefaults() { |
1118 | $default['objectclass'] = array( |
1119 | 'edir' => 'User', |
139ebfdb |
1120 | 'rfc2307' => 'posixAccount', |
1121 | 'rfc2307bis' => 'posixAccount', |
b9ddb2d5 |
1122 | 'samba' => 'sambaSamAccount', |
1123 | 'ad' => 'user', |
1124 | 'default' => '*' |
1125 | ); |
1126 | $default['user_attribute'] = array( |
1127 | 'edir' => 'cn', |
1128 | 'rfc2307' => 'uid', |
1129 | 'rfc2307bis' => 'uid', |
1130 | 'samba' => 'uid', |
1131 | 'ad' => 'cn', |
1132 | 'default' => 'cn' |
1133 | ); |
1134 | $default['memberattribute'] = array( |
1135 | 'edir' => 'member', |
1136 | 'rfc2307' => 'member', |
1137 | 'rfc2307bis' => 'member', |
1138 | 'samba' => 'member', |
139ebfdb |
1139 | 'ad' => 'member', |
b9ddb2d5 |
1140 | 'default' => 'member' |
1141 | ); |
1142 | $default['memberattribute_isdn'] = array( |
1143 | 'edir' => '1', |
1144 | 'rfc2307' => '0', |
1145 | 'rfc2307bis' => '1', |
1146 | 'samba' => '0', //is this right? |
1147 | 'ad' => '1', |
1148 | 'default' => '0' |
1149 | ); |
1150 | $default['expireattr'] = array ( |
1151 | 'edir' => 'passwordExpirationTime', |
1152 | 'rfc2307' => 'shadowExpire', |
1153 | 'rfc2307bis' => 'shadowExpire', |
1154 | 'samba' => '', //No support yet |
1155 | 'ad' => '', //No support yet |
1156 | 'default' => '' |
1157 | ); |
139ebfdb |
1158 | return $default; |
b9ddb2d5 |
1159 | } |
1160 | |
1161 | /** |
1162 | * return binaryfields of selected usertype |
1163 | * |
1164 | * |
1165 | * @return array |
1166 | */ |
1167 | function ldap_getbinaryfields () { |
b9ddb2d5 |
1168 | $binaryfields = array ( |
1169 | 'edir' => array('guid'), |
139ebfdb |
1170 | 'rfc2307' => array(), |
1171 | 'rfc2307bis' => array(), |
b9ddb2d5 |
1172 | 'samba' => array(), |
1173 | 'ad' => array(), |
139ebfdb |
1174 | 'default' => array() |
b9ddb2d5 |
1175 | ); |
1176 | if (!empty($this->config->user_type)) { |
139ebfdb |
1177 | return $binaryfields[$this->config->user_type]; |
b9ddb2d5 |
1178 | } |
1179 | else { |
1180 | return $binaryfields['default']; |
139ebfdb |
1181 | } |
b9ddb2d5 |
1182 | } |
1183 | |
1184 | function ldap_isbinary ($field) { |
139ebfdb |
1185 | if (empty($field)) { |
1186 | return false; |
b9ddb2d5 |
1187 | } |
139ebfdb |
1188 | return array_search($field, $this->ldap_getbinaryfields()); |
b9ddb2d5 |
1189 | } |
1190 | |
1191 | /** |
1192 | * take expirationtime and return it as unixseconds |
139ebfdb |
1193 | * |
b9ddb2d5 |
1194 | * takes expriration timestamp as readed from ldap |
1195 | * returns it as unix seconds |
139ebfdb |
1196 | * depends on $this->config->user_type variable |
b9ddb2d5 |
1197 | * |
1198 | * @param mixed time Time stamp readed from ldap as it is. |
1199 | * @return timestamp |
1200 | */ |
1201 | function ldap_expirationtime2unix ($time) { |
b9ddb2d5 |
1202 | $result = false; |
1203 | switch ($this->config->user_type) { |
1204 | case 'edir': |
1205 | $yr=substr($time,0,4); |
1206 | $mo=substr($time,4,2); |
1207 | $dt=substr($time,6,2); |
1208 | $hr=substr($time,8,2); |
1209 | $min=substr($time,10,2); |
1210 | $sec=substr($time,12,2); |
139ebfdb |
1211 | $result = mktime($hr,$min,$sec,$mo,$dt,$yr); |
b9ddb2d5 |
1212 | break; |
1213 | case 'posix': |
1214 | $result = $time * DAYSECS; //The shadowExpire contains the number of DAYS between 01/01/1970 and the actual expiration date |
1215 | break; |
139ebfdb |
1216 | default: |
e8b9d76a |
1217 | print_error('auth_ldap_usertypeundefined', 'auth'); |
b9ddb2d5 |
1218 | } |
1219 | return $result; |
1220 | } |
1221 | |
1222 | /** |
1223 | * takes unixtime and return it formated for storing in ldap |
1224 | * |
1225 | * @param integer unix time stamp |
1226 | */ |
1227 | function ldap_unix2expirationtime($time) { |
b9ddb2d5 |
1228 | $result = false; |
1229 | switch ($this->config->user_type) { |
1230 | case 'edir': |
139ebfdb |
1231 | $result=date('YmdHis', $time).'Z'; |
b9ddb2d5 |
1232 | break; |
1233 | case 'posix': |
1234 | $result = $time ; //Already in correct format |
1235 | break; |
139ebfdb |
1236 | default: |
e8b9d76a |
1237 | print_error('auth_ldap_usertypeundefined2', 'auth'); |
139ebfdb |
1238 | } |
b9ddb2d5 |
1239 | return $result; |
1240 | |
1241 | } |
1242 | |
139ebfdb |
1243 | /** |
b9ddb2d5 |
1244 | * checks if user belong to specific group(s) |
1245 | * |
1246 | * Returns true if user belongs group in grupdns string. |
1247 | * |
1248 | * @param mixed $username username |
1249 | * @param mixed $groupdns string of group dn separated by ; |
1250 | * |
1251 | */ |
139ebfdb |
1252 | function ldap_isgroupmember($extusername='', $groupdns='') { |
b9ddb2d5 |
1253 | // Takes username and groupdn(s) , separated by ; |
1254 | // Returns true if user is member of any given groups |
1255 | |
b9ddb2d5 |
1256 | $ldapconnection = $this->ldap_connect(); |
139ebfdb |
1257 | |
cd874e21 |
1258 | if (empty($extusername) or empty($groupdns)) { |
1259 | return false; |
b9ddb2d5 |
1260 | } |
1261 | |
1262 | if ($this->config->memberattribute_isdn) { |
cd874e21 |
1263 | $memberuser = $this->ldap_find_userdn($ldapconnection, $extusername); |
1264 | } else { |
1265 | $memberuser = $extusername; |
b9ddb2d5 |
1266 | } |
cd874e21 |
1267 | |
1268 | if (empty($memberuser)) { |
1269 | return false; |
b9ddb2d5 |
1270 | } |
1271 | |
1272 | $groups = explode(";",$groupdns); |
139ebfdb |
1273 | |
cd874e21 |
1274 | $result = false; |
b9ddb2d5 |
1275 | foreach ($groups as $group) { |
1276 | $group = trim($group); |
1277 | if (empty($group)) { |
1278 | continue; |
1279 | } |
1280 | //echo "Checking group $group for member $username\n"; |
cd874e21 |
1281 | $search = ldap_read($ldapconnection, $group, '('.$this->config->memberattribute.'='.$this->filter_addslashes($memberuser).')', array($this->config->memberattribute)); |
1282 | if (!empty($search) and ldap_count_entries($ldapconnection, $search)) { |
1283 | $info = $this->ldap_get_entries($ldapconnection, $search); |
139ebfdb |
1284 | |
b9ddb2d5 |
1285 | if (count($info) > 0 ) { |
1286 | // user is member of group |
1287 | $result = true; |
1288 | break; |
1289 | } |
cd874e21 |
1290 | } |
b9ddb2d5 |
1291 | } |
b9ddb2d5 |
1292 | |
1293 | return $result; |
1294 | |
1295 | } |
1296 | |
1297 | /** |
1298 | * connects to ldap server |
1299 | * |
1300 | * Tries connect to specified ldap servers. |
1301 | * Returns connection result or error. |
1302 | * |
1303 | * @return connection result |
1304 | */ |
1305 | function ldap_connect($binddn='',$bindpwd='') { |
b9ddb2d5 |
1306 | //Select bind password, With empty values use |
1307 | //ldap_bind_* variables or anonymous bind if ldap_bind_* are empty |
1308 | if ($binddn == '' and $bindpwd == '') { |
1309 | if (!empty($this->config->bind_dn)) { |
1310 | $binddn = $this->config->bind_dn; |
1311 | } |
1312 | if (!empty($this->config->bind_pw)) { |
1313 | $bindpwd = $this->config->bind_pw; |
1314 | } |
1315 | } |
139ebfdb |
1316 | |
b9ddb2d5 |
1317 | $urls = explode(";",$this->config->host_url); |
139ebfdb |
1318 | |
b9ddb2d5 |
1319 | foreach ($urls as $server) { |
1320 | $server = trim($server); |
1321 | if (empty($server)) { |
1322 | continue; |
1323 | } |
1324 | |
1325 | $connresult = ldap_connect($server); |
1326 | //ldap_connect returns ALWAYS true |
139ebfdb |
1327 | |
b9ddb2d5 |
1328 | if (!empty($this->config->version)) { |
1329 | ldap_set_option($connresult, LDAP_OPT_PROTOCOL_VERSION, $this->config->version); |
1330 | } |
1331 | |
1332 | if (!empty($binddn)) { |
1333 | //bind with search-user |
139ebfdb |
1334 | //$debuginfo .= 'Using bind user'.$binddn.'and password:'.$bindpwd; |
b9ddb2d5 |
1335 | $bindresult=ldap_bind($connresult, $binddn,$bindpwd); |
1336 | } |
1337 | else { |
139ebfdb |
1338 | //bind anonymously |
b9ddb2d5 |
1339 | $bindresult=@ldap_bind($connresult); |
139ebfdb |
1340 | } |
1341 | |
b9ddb2d5 |
1342 | if (!empty($this->config->opt_deref)) { |
1343 | ldap_set_option($connresult, LDAP_OPT_DEREF, $this->config->opt_deref); |
1344 | } |
1345 | |
1346 | if ($bindresult) { |
1347 | return $connresult; |
1348 | } |
139ebfdb |
1349 | |
b9ddb2d5 |
1350 | $debuginfo .= "<br/>Server: '$server' <br/> Connection: '$connresult'<br/> Bind result: '$bindresult'</br>"; |
1351 | } |
1352 | |
1353 | //If any of servers are alive we have already returned connection |
e8b9d76a |
1354 | print_error('auth_ldap_noconnect_all','auth',$this->config->user_type); |
b9ddb2d5 |
1355 | return false; |
1356 | } |
1357 | |
1358 | /** |
1359 | * retuns dn of username |
1360 | * |
1361 | * Search specified contexts for username and return user dn |
1362 | * like: cn=username,ou=suborg,o=org |
1363 | * |
1364 | * @param mixed $ldapconnection $ldapconnection result |
139ebfdb |
1365 | * @param mixed $username username (external encoding no slashes) |
b9ddb2d5 |
1366 | * |
1367 | */ |
1368 | |
139ebfdb |
1369 | function ldap_find_userdn ($ldapconnection, $extusername) { |
b9ddb2d5 |
1370 | |
1371 | //default return value |
1372 | $ldap_user_dn = FALSE; |
1373 | |
1374 | //get all contexts and look for first matching user |
1375 | $ldap_contexts = explode(";",$this->config->contexts); |
139ebfdb |
1376 | |
b9ddb2d5 |
1377 | if (!empty($this->config->create_context)) { |
1378 | array_push($ldap_contexts, $this->config->create_context); |
1379 | } |
139ebfdb |
1380 | |
b9ddb2d5 |
1381 | foreach ($ldap_contexts as $context) { |
1382 | |
1383 | $context = trim($context); |
1384 | if (empty($context)) { |
1385 | continue; |
1386 | } |
1387 | |
1388 | if ($this->config->search_sub) { |
1389 | //use ldap_search to find first user from subtree |
139ebfdb |
1390 | $ldap_result = ldap_search($ldapconnection, $context, "(".$this->config->user_attribute."=".$this->filter_addslashes($extusername).")",array($this->config->user_attribute)); |
b9ddb2d5 |
1391 | |
1392 | } |
1393 | else { |
1394 | //search only in this context |
139ebfdb |
1395 | $ldap_result = ldap_list($ldapconnection, $context, "(".$this->config->user_attribute."=".$this->filter_addslashes($extusername).")",array($this->config->user_attribute)); |
b9ddb2d5 |
1396 | } |
139ebfdb |
1397 | |
b9ddb2d5 |
1398 | $entry = ldap_first_entry($ldapconnection,$ldap_result); |
1399 | |
1400 | if ($entry) { |
1401 | $ldap_user_dn = ldap_get_dn($ldapconnection, $entry); |
1402 | break ; |
1403 | } |
1404 | } |
1405 | |
1406 | return $ldap_user_dn; |
1407 | } |
1408 | |
1409 | /** |
1410 | * retuns user attribute mappings between moodle and ldap |
1411 | * |
1412 | * @return array |
1413 | */ |
1414 | |
1415 | function ldap_attributes () { |
139ebfdb |
1416 | $fields = array("firstname", "lastname", "email", "phone1", "phone2", |
1417 | "department", "address", "city", "country", "description", |
b9ddb2d5 |
1418 | "idnumber", "lang" ); |
1419 | $moodleattributes = array(); |
1420 | foreach ($fields as $field) { |
1421 | if (!empty($this->config->{"field_map_$field"})) { |
1422 | $moodleattributes[$field] = $this->config->{"field_map_$field"}; |
1423 | if (preg_match('/,/',$moodleattributes[$field])) { |
1424 | $moodleattributes[$field] = explode(',', $moodleattributes[$field]); // split ? |
1425 | } |
1426 | } |
1427 | } |
1428 | $moodleattributes['username'] = $this->config->user_attribute; |
1429 | return $moodleattributes; |
1430 | } |
1431 | |
1432 | /** |
1433 | * return all usernames from ldap |
1434 | * |
1435 | * @return array |
1436 | */ |
1437 | |
1438 | function ldap_get_userlist($filter="*") { |
1439 | /// returns all users from ldap servers |
b9ddb2d5 |
1440 | $fresult = array(); |
1441 | |
1442 | $ldapconnection = $this->ldap_connect(); |
1443 | |
1444 | if ($filter=="*") { |
1445 | $filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))"; |
1446 | } |
1447 | |
1448 | $contexts = explode(";",$this->config->contexts); |
139ebfdb |
1449 | |
b9ddb2d5 |
1450 | if (!empty($this->config->create_context)) { |
1451 | array_push($contexts, $this->config->create_context); |
1452 | } |
1453 | |
1454 | foreach ($contexts as $context) { |
1455 | |
1456 | $context = trim($context); |
1457 | if (empty($context)) { |
1458 | continue; |
1459 | } |
1460 | |
1461 | if ($this->config->search_sub) { |
1462 | //use ldap_search to find first user from subtree |
1463 | $ldap_result = ldap_search($ldapconnection, $context,$filter,array($this->config->user_attribute)); |
1464 | } |
1465 | else { |
1466 | //search only in this context |
1467 | $ldap_result = ldap_list($ldapconnection, $context, |
1468 | $filter, |
1469 | array($this->config->user_attribute)); |
1470 | } |
139ebfdb |
1471 | |
b9ddb2d5 |
1472 | $users = $this->ldap_get_entries($ldapconnection, $ldap_result); |
1473 | |
1474 | //add found users to list |
1475 | for ($i=0;$i<count($users);$i++) { |
1476 | array_push($fresult, ($users[$i][$this->config->user_attribute][0]) ); |
1477 | } |
1478 | } |
139ebfdb |
1479 | |
b9ddb2d5 |
1480 | return $fresult; |
1481 | } |
1482 | |
1483 | /** |
1484 | * return entries from ldap |
1485 | * |
1486 | * Returns values like ldap_get_entries but is |
1487 | * binary compatible and return all attributes as array |
1488 | * |
1489 | * @return array ldap-entries |
1490 | */ |
139ebfdb |
1491 | |
b9ddb2d5 |
1492 | function ldap_get_entries($conn, $searchresult) { |
1493 | //Returns values like ldap_get_entries but is |
1494 | //binary compatible |
1495 | $i=0; |
1496 | $fresult=array(); |
1497 | $entry = ldap_first_entry($conn, $searchresult); |
1498 | do { |
1499 | $attributes = @ldap_get_attributes($conn, $entry); |
1500 | for ($j=0; $j<$attributes['count']; $j++) { |
1501 | $values = ldap_get_values_len($conn, $entry,$attributes[$j]); |
1502 | if (is_array($values)) { |
1503 | $fresult[$i][$attributes[$j]] = $values; |
1504 | } |
1505 | else { |
1506 | $fresult[$i][$attributes[$j]] = array($values); |
1507 | } |
139ebfdb |
1508 | } |
1509 | $i++; |
b9ddb2d5 |
1510 | } |
1511 | while ($entry = @ldap_next_entry($conn, $entry)); |
1512 | //were done |
1513 | return ($fresult); |
1514 | } |
1515 | |
1516 | /** |
1517 | * Returns true if this authentication plugin is 'internal'. |
1518 | * |
139ebfdb |
1519 | * @return bool |
b9ddb2d5 |
1520 | */ |
1521 | function is_internal() { |
1522 | return false; |
1523 | } |
1524 | |
1525 | /** |
1526 | * Returns true if this authentication plugin can change the user's |
1527 | * password. |
1528 | * |
139ebfdb |
1529 | * @return bool |
b9ddb2d5 |
1530 | */ |
1531 | function can_change_password() { |
430759a5 |
1532 | return !empty($this->config->stdchangepassword) or !empty($this->config->changepasswordurl); |
b9ddb2d5 |
1533 | } |
139ebfdb |
1534 | |
b9ddb2d5 |
1535 | /** |
430759a5 |
1536 | * Returns the URL for changing the user's pw, or empty if the default can |
b9ddb2d5 |
1537 | * be used. |
1538 | * |
139ebfdb |
1539 | * @return string url |
b9ddb2d5 |
1540 | */ |
1541 | function change_password_url() { |
139ebfdb |
1542 | if (empty($this->config->stdchangepassword)) { |
1543 | return $this->config->changepasswordurl; |
1544 | } else { |
430759a5 |
1545 | return ''; |
139ebfdb |
1546 | } |
b9ddb2d5 |
1547 | } |
139ebfdb |
1548 | |
6bc1e5d5 |
1549 | /** |
1550 | * Sync roles for this user |
1551 | * |
1552 | * @param $user object user object (without system magic quotes) |
1553 | */ |
1554 | function sync_roles($user) { |
1555 | $iscreator = $this->iscreator($user->username); |
1556 | if ($iscreator === null) { |
1557 | return; //nothing to sync - creators not configured |
1558 | } |
1559 | |
1560 | if ($roles = get_roles_with_capability('moodle/legacy:coursecreator', CAP_ALLOW)) { |
1561 | $creatorrole = array_shift($roles); // We can only use one, let's use the first one |
1562 | $systemcontext = get_context_instance(CONTEXT_SYSTEM); |
1563 | |
1564 | if ($iscreator) { // Following calls will not create duplicates |
1565 | role_assign($creatorrole->id, $user->id, 0, $systemcontext->id, 0, 0, 0, 'ldap'); |
1566 | } else { |
1567 | //unassign only if previously assigned by this plugin! |
1568 | role_unassign($creatorrole->id, $user->id, 0, $systemcontext->id, 'ldap'); |
1569 | } |
1570 | } |
1571 | } |
1572 | |
b9ddb2d5 |
1573 | /** |
1574 | * Prints a form for configuring this authentication plugin. |
1575 | * |
1576 | * This function is called from admin/auth.php, and outputs a full page with |
1577 | * a form for configuring this plugin. |
1578 | * |
1579 | * @param array $page An object containing all the data for this page. |
1580 | */ |
139ebfdb |
1581 | function config_form($config, $err, $user_fields) { |
1582 | include 'config.html'; |
b9ddb2d5 |
1583 | } |
1584 | |
1585 | /** |
1586 | * Processes and stores configuration data for this authentication plugin. |
1587 | */ |
1588 | function process_config($config) { |
1589 | // set to defaults if undefined |
139ebfdb |
1590 | if (!isset($config->host_url)) |
b9ddb2d5 |
1591 | { $config->host_url = ''; } |
139ebfdb |
1592 | if (empty($config->ldapencoding)) |
1593 | { $config->ldapencoding = 'utf-8'; } |
1594 | if (!isset($config->contexts)) |
b9ddb2d5 |
1595 | { $config->contexts = ''; } |
139ebfdb |
1596 | if (!isset($config->user_type)) |
1597 | { $config->user_type = 'default'; } |
1598 | if (!isset($config->user_attribute)) |
b9ddb2d5 |
1599 | { $config->user_attribute = ''; } |
139ebfdb |
1600 | if (!isset($config->search_sub)) |
b9ddb2d5 |
1601 | { $config->search_sub = ''; } |
139ebfdb |
1602 | if (!isset($config->opt_deref)) |
b9ddb2d5 |
1603 | { $config->opt_deref = ''; } |
139ebfdb |
1604 | if (!isset($config->preventpassindb)) |
1605 | { $config->preventpassindb = 0; } |
1606 | if (!isset($config->bind_dn)) |
b9ddb2d5 |
1607 | {$config->bind_dn = ''; } |
139ebfdb |
1608 | if (!isset($config->bind_pw)) |
b9ddb2d5 |
1609 | {$config->bind_pw = ''; } |
139ebfdb |
1610 | if (!isset($config->version)) |
b9ddb2d5 |
1611 | {$config->version = '2'; } |
139ebfdb |
1612 | if (!isset($config->objectclass)) |
b9ddb2d5 |
1613 | {$config->objectclass = ''; } |
139ebfdb |
1614 | if (!isset($config->memberattribute)) |
b9ddb2d5 |
1615 | {$config->memberattribute = ''; } |
cd874e21 |
1616 | if (!isset($config->memberattribute_isdn)) |
1617 | {$config->memberattribute_isdn = ''; } |
139ebfdb |
1618 | if (!isset($config->creators)) |
b9ddb2d5 |
1619 | {$config->creators = ''; } |
139ebfdb |
1620 | if (!isset($config->create_context)) |
b9ddb2d5 |
1621 | {$config->create_context = ''; } |
139ebfdb |
1622 | if (!isset($config->expiration)) |
b9ddb2d5 |
1623 | {$config->expiration = ''; } |
139ebfdb |
1624 | if (!isset($config->expiration_warning)) |
b9ddb2d5 |
1625 | {$config->expiration_warning = '10'; } |
139ebfdb |
1626 | if (!isset($config->expireattr)) |
b9ddb2d5 |
1627 | {$config->expireattr = ''; } |
139ebfdb |
1628 | if (!isset($config->gracelogins)) |
b9ddb2d5 |
1629 | {$config->gracelogins = ''; } |
139ebfdb |
1630 | if (!isset($config->graceattr)) |
b9ddb2d5 |
1631 | {$config->graceattr = ''; } |
139ebfdb |
1632 | if (!isset($config->auth_user_create)) |
b9ddb2d5 |
1633 | {$config->auth_user_create = ''; } |
139ebfdb |
1634 | if (!isset($config->forcechangepassword)) |
1635 | {$config->forcechangepassword = 0; } |
b9ddb2d5 |
1636 | if (!isset($config->stdchangepassword)) |
344514fc |
1637 | {$config->forcechangepassword = 0; } |
1638 | if (!isset($config->passtype)) |
1639 | {$config->passtype = 'plaintext'; } |
b9ddb2d5 |
1640 | if (!isset($config->changepasswordurl)) |
1641 | {$config->changepasswordurl = ''; } |
139ebfdb |
1642 | if (!isset($config->removeuser)) |
1643 | {$config->removeuser = 0; } |
b9ddb2d5 |
1644 | |
1645 | // save settings |
1646 | set_config('host_url', $config->host_url, 'auth/ldap'); |
139ebfdb |
1647 | set_config('ldapencoding', $config->ldapencoding, 'auth/ldap'); |
1648 | set_config('host_url', $config->host_url, 'auth/ldap'); |
b9ddb2d5 |
1649 | set_config('contexts', $config->contexts, 'auth/ldap'); |
1650 | set_config('user_type', $config->user_type, 'auth/ldap'); |
1651 | set_config('user_attribute', $config->user_attribute, 'auth/ldap'); |
1652 | set_config('search_sub', $config->search_sub, 'auth/ldap'); |
1653 | set_config('opt_deref', $config->opt_deref, 'auth/ldap'); |
1654 | set_config('preventpassindb', $config->preventpassindb, 'auth/ldap'); |
1655 | set_config('bind_dn', $config->bind_dn, 'auth/ldap'); |
1656 | set_config('bind_pw', $config->bind_pw, 'auth/ldap'); |
1657 | set_config('version', $config->version, 'auth/ldap'); |
1658 | set_config('objectclass', $config->objectclass, 'auth/ldap'); |
1659 | set_config('memberattribute', $config->memberattribute, 'auth/ldap'); |
cd874e21 |
1660 | set_config('memberattribute_isdn', $config->memberattribute_isdn, 'auth/ldap'); |
b9ddb2d5 |
1661 | set_config('creators', $config->creators, 'auth/ldap'); |
1662 | set_config('create_context', $config->create_context, 'auth/ldap'); |
1663 | set_config('expiration', $config->expiration, 'auth/ldap'); |
1664 | set_config('expiration_warning', $config->expiration_warning, 'auth/ldap'); |
1665 | set_config('expireattr', $config->expireattr, 'auth/ldap'); |
1666 | set_config('gracelogins', $config->gracelogins, 'auth/ldap'); |
1667 | set_config('graceattr', $config->graceattr, 'auth/ldap'); |
1668 | set_config('auth_user_create', $config->auth_user_create, 'auth/ldap'); |
1669 | set_config('forcechangepassword', $config->forcechangepassword, 'auth/ldap'); |
1670 | set_config('stdchangepassword', $config->stdchangepassword, 'auth/ldap'); |
344514fc |
1671 | set_config('passtype', $config->passtype, 'auth/ldap'); |
b9ddb2d5 |
1672 | set_config('changepasswordurl', $config->changepasswordurl, 'auth/ldap'); |
139ebfdb |
1673 | set_config('removeuser', $config->removeuser, 'auth/ldap'); |
b9ddb2d5 |
1674 | |
1675 | return true; |
1676 | } |
1677 | |
139ebfdb |
1678 | /** |
1679 | * Quote control characters in texts used in ldap filters - see rfc2254.txt |
1680 | * |
1681 | * @param string |
1682 | */ |
1683 | function filter_addslashes($text) { |
1684 | $text = str_replace('\\', '\\5c', $text); |
1685 | $text = str_replace(array('*', '(', ')', "\0"), |
1686 | array('\\2a', '\\28', '\\29', '\\00'), $text); |
1687 | return $text; |
1688 | } |
1689 | |
1690 | /** |
1691 | * Quote control characters in quoted "texts" used in ldap |
1692 | * |
1693 | * @param string |
1694 | */ |
1695 | function ldap_addslashes($text) { |
1696 | $text = str_replace('\\', '\\\\', $text); |
1697 | $text = str_replace(array('"', "\0"), |
1698 | array('\\"', '\\00'), $text); |
1699 | return $text; |
1700 | } |
b9ddb2d5 |
1701 | } |
1702 | |
1703 | ?> |