Projet

Général

Profil

Paste
Télécharger (50,7 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ldap / ldap_user / LdapUserConf.class.php @ b42754b9

1 85ad3d82 Assos Assos
<?php
2
3
/**
4
 * @file
5
 * This class represents a ldap_user module's configuration
6
 * It is extended by LdapUserConfAdmin for configuration and other admin functions
7
 */
8
9
require_once('ldap_user.module');
10
11
class LdapUserConf {
12
13
  /**
14
   * server providing Drupal account provisioning
15
   *
16
   * @var string
17
   *
18
   * @see LdapServer::sid
19
   */
20
  public $drupalAcctProvisionServer = LDAP_USER_NO_SERVER_SID;
21
22
  /**
23
   * server providing LDAP entry provisioning
24
   *
25
   * @var string
26
   *
27
   * @see LdapServer::sid
28
   */
29
  public $ldapEntryProvisionServer = LDAP_USER_NO_SERVER_SID;
30
31
  /**
32
   * Associative array mapping synch directions to ldap server instances.
33
   *
34
   * @var array
35
   */
36
  public $provisionSidFromDirection = array(
37
    LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER => LDAP_USER_NO_SERVER_SID,
38
    LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY => LDAP_USER_NO_SERVER_SID,
39
  );
40
41
  /**
42
   * Array of events that trigger provisioning of Drupal Accounts
43
   * Valid constants are:
44
   *   LDAP_USER_DRUPAL_USER_PROV_ON_AUTHENTICATE
45
   *   LDAP_USER_DRUPAL_USER_PROV_ON_USER_UPDATE_CREATE
46
   *   LDAP_USER_DRUPAL_USER_PROV_ON_ALLOW_MANUAL_CREATE
47
   *
48
   * @var array
49
   */
50
  public $drupalAcctProvisionTriggers = array(LDAP_USER_DRUPAL_USER_PROV_ON_AUTHENTICATE, LDAP_USER_DRUPAL_USER_PROV_ON_USER_UPDATE_CREATE, LDAP_USER_DRUPAL_USER_PROV_ON_ALLOW_MANUAL_CREATE);
51
52
  /**
53
   * Array of events that trigger provisioning of LDAP Entries
54
   * Valid constants are:
55
   *   LDAP_USER_LDAP_ENTRY_PROV_ON_USER_UPDATE_CREATE
56
   *   LDAP_USER_LDAP_ENTRY_PROV_ON_AUTHENTICATE
57
   *   LDAP_USER_LDAP_ENTRY_DELETE_ON_USER_DELETE
58
   *
59
   * @var array
60
   */
61
  public $ldapEntryProvisionTriggers = array();
62
63
  /**
64
   * server providing LDAP entry provisioning
65
   *
66
   * @var string
67
   *
68
   * @see LdapServer::sid
69
   */
70
  public $userConflictResolve = LDAP_USER_CONFLICT_RESOLVE_DEFAULT;
71
72 b42754b9 Assos Assos
  /**
73
   * Whether to allow/disallow provisioning accounts that have the same email.
74
   * Depending on whether the "sharedemail" module is enabled, this variable
75
   * will (by default) be set accordingly.  It can be overridden by an admin.
76
   *
77
   * @var int
78
   *    LDAP_USER_ACCOUNTS_WITH_SAME_EMAIL_DISABLED (0)
79
   *    LDAP_USER_ACCOUNTS_WITH_SAME_EMAIL_ENABLED (1)
80
   */
81
  public $accountsWithSameEmail = LDAP_USER_ACCOUNTS_WITH_SAME_EMAIL_DISABLED;
82
83 85ad3d82 Assos Assos
  /**
84
   * drupal account creation model
85
   *
86
   * @var int
87
   *   LDAP_USER_ACCT_CREATION_LDAP_BEHAVIOR   /admin/config/people/accounts/settings do not affect "LDAP Associated" Drupal accounts.
88
   *   LDAP_USER_ACCT_CREATION_USER_SETTINGS_FOR_LDAP  use Account creation settings at /admin/config/people/accounts/settings
89
   */
90
  public $acctCreation = LDAP_USER_ACCT_CREATION_LDAP_BEHAVIOR_DEFAULT;
91
92
  /**
93
   * has current object been saved to the database?
94
   *
95
   * @var boolean
96
   *
97
   */
98
  public $inDatabase = FALSE;
99
100
  /**
101
   * what to do when an ldap provisioned username conflicts with existing drupal user?
102
   *
103
   * @var int
104
   *   LDAP_USER_CONFLICT_LOG - log the conflict
105
   *   LDAP_USER_CONFLICT_RESOLVE - LDAP associate the existing drupal user
106
   *
107
   */
108
  public $manualAccountConflict = LDAP_USER_MANUAL_ACCT_CONFLICT_REJECT;
109
110
  public $setsLdapPassword = TRUE; // @todo default to FALSE and check for mapping to set to true
111
112
  public $loginConflictResolve = FALSE;
113
114
  public $disableAdminPasswordField = FALSE;
115
  /**
116
   * array of field synch mappings provided by all modules (via hook_ldap_user_attrs_list_alter())
117
   * array of the form: array(
118
   * LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER | LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY => array(
119
   *   <server_id> => array(
120
   *     'sid' => <server_id> (redundant)
121
   *     'ldap_attr' => e.g. [sn]
122
   *     'user_attr'  => e.g. [field.field_user_lname] (when this value is set to 'user_tokens', 'user_tokens' value is used.)
123
   *     'user_tokens' => e.g. [field.field_user_lname], [field.field_user_fname]
124
   *     'convert' => 1|0 boolean indicating need to covert from binary
125
   *     'direction' => LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER | LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY (redundant)
126
   *     'config_module' => 'ldap_user'
127
   *     'prov_module' => 'ldap_user'
128
   *     'enabled' => 1|0 boolean
129
   *      prov_events' => array( of LDAP_USER_EVENT_* constants indicating during which synch actions field should be synched)
130
   *         - four permutations available
131
   *            to ldap:   LDAP_USER_EVENT_CREATE_LDAP_ENTRY,  LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY,
132
   *            to drupal: LDAP_USER_EVENT_CREATE_DRUPAL_USER, LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER
133
   *    )
134
   *  )
135
   */
136
  public $synchMapping = NULL; // array of field synching directions for each operation.  should include ldapUserSynchMappings
137
  // keyed on direction => property, ldap, or field token such as '[field.field_lname] with brackets in them.
138
139
  /**
140
  * synch mappings configured in ldap user module (not in other modules)
141
  *   array of the form: array(
142
    LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER | LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY => array(
143
      'sid' => <server_id> (redundant)
144
      'ldap_attr' => e.g. [sn]
145
      'user_attr'  => e.g. [field.field_user_lname] (when this value is set to 'user_tokens', 'user_tokens' value is used.)
146
      'user_tokens' => e.g. [field.field_user_lname], [field.field_user_fname]
147
      'convert' => 1|0 boolean indicating need to covert from binary
148
      'direction' => LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER | LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY (redundant)
149
      'config_module' => 'ldap_user'
150
      'prov_module' => 'ldap_user'
151
      'enabled' => 1|0 boolean
152
       prov_events' => array( of LDAP_USER_EVENT_* constants indicating during which synch actions field should be synched)
153
          - four permutations available
154
             to ldap:   LDAP_USER_EVENT_CREATE_LDAP_ENTRY,  LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY,
155
             to drupal: LDAP_USER_EVENT_CREATE_DRUPAL_USER, LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER
156
      )
157
    )
158
  )
159
  */
160
  public $ldapUserSynchMappings = NULL;  //
161
  // keyed on property, ldap, or field token such as '[field.field_lname] with brackets in them.
162
  public $detailedWatchdog = FALSE;
163
  public $provisionsDrupalAccountsFromLdap = FALSE;
164
  public $provisionsLdapEntriesFromDrupalUsers = FALSE;
165
166
  // what should be done with ldap provisioned accounts that no longer have associated drupal accounts.
167
  public $orphanedDrupalAcctBehavior = 'ldap_user_orphan_email';
168
   /** options are partially derived from user module account cancel options:
169
    *
170
    'ldap_user_orphan_do_not_check' => Do not check for orphaned Drupal accounts.)
171
    'ldap_user_orphan_email' => Perform no action, but email list of orphaned accounts. (All the other options will send email summaries also.)
172
    'user_cancel_block' => Disable the account and keep its content.
173
    'user_cancel_block_unpublish' => Disable the account and unpublish its content.
174
    'user_cancel_reassign' => Delete the account and make its content belong to the Anonymous user.
175
    'user_cancel_delete' => Delete the account and its content.
176
    */
177
178
  public $orphanedCheckQty = 100;
179
180
// public $wsKey = NULL;
181
//  public $wsEnabled = 0;
182
//  public $wsUserIps = array();
183
184
  public $provisionsLdapEvents = array();
185
  public $provisionsDrupalEvents = array();
186
187
  public $saveable = array(
188
    'drupalAcctProvisionServer',
189
    'ldapEntryProvisionServer',
190
    'drupalAcctProvisionTriggers',
191
    'ldapEntryProvisionTriggers',
192
    'orphanedDrupalAcctBehavior',
193
    'orphanedCheckQty',
194
    'userConflictResolve',
195 b42754b9 Assos Assos
    'accountsWithSameEmail',
196 85ad3d82 Assos Assos
    'manualAccountConflict',
197
    'acctCreation',
198
    'ldapUserSynchMappings',
199
    'disableAdminPasswordField',
200
  );
201
// 'wsKey','wsEnabled','wsUserIps',
202
  function __construct() {
203
    $this->load();
204
205
    $this->provisionSidFromDirection[LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER] = $this->drupalAcctProvisionServer;
206
    $this->provisionSidFromDirection[LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY] = $this->ldapEntryProvisionServer;
207
208
    $this->provisionsLdapEvents = array(
209
      LDAP_USER_EVENT_CREATE_LDAP_ENTRY => t('On LDAP Entry Creation'),
210
      LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY => t('On Synch to LDAP Entry'),
211
      );
212
213
    $this->provisionsDrupalEvents = array(
214
      LDAP_USER_EVENT_CREATE_DRUPAL_USER => t('On Drupal User Creation'),
215
      LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER => t('On Synch to Drupal User'),
216
      );
217
218
    $this->provisionsDrupalAccountsFromLdap = (
219
      $this->drupalAcctProvisionServer &&
220
      $this->drupalAcctProvisionServer &&
221
      (count(array_filter(array_values($this->drupalAcctProvisionTriggers))) > 0)
222
    );
223
224
    $this->provisionsLdapEntriesFromDrupalUsers = (
225
      $this->ldapEntryProvisionServer
226
      && $this->ldapEntryProvisionServer
227
      && (count(array_filter(array_values($this->ldapEntryProvisionTriggers))) > 0)
228
      );
229
230
    $this->setSynchMapping(TRUE);
231
    $this->detailedWatchdog = variable_get('ldap_help_watchdog_detail', 0);
232
  }
233
234
  function load() {
235
236
    if ($saved = variable_get("ldap_user_conf", FALSE)) {
237
      $this->inDatabase = TRUE;
238
      foreach ($this->saveable as $property) {
239
        if (isset($saved[$property])) {
240
          $this->{$property} = $saved[$property];
241
        }
242
      }
243
    }
244
    else {
245
      $this->inDatabase = FALSE;
246 b42754b9 Assos Assos
      // By default this variable should be 0 if the "sharedemail" module
247
      // is not enabled, or 1 if the module is.
248
      $this->accountsWithSameEmail = (int)module_exists('sharedemail');
249 85ad3d82 Assos Assos
    }
250
    // determine account creation configuration
251
    $user_register = variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
252
    if ($this->acctCreation == LDAP_USER_ACCT_CREATION_LDAP_BEHAVIOR_DEFAULT || $user_register == USER_REGISTER_VISITORS) {
253
      $this->createLDAPAccounts = TRUE;
254
      $this->createLDAPAccountsAdminApproval = FALSE;
255
    }
256
    elseif ($user_register == USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) {
257
      $this->createLDAPAccounts = FALSE;
258
      $this->createLDAPAccountsAdminApproval = TRUE;
259
    }
260
    else {
261
      $this->createLDAPAccounts = FALSE;
262
      $this->createLDAPAccountsAdminApproval = FALSE;
263
    }
264
  }
265
266
  /**
267
   * Destructor Method
268
   */
269
  function __destruct() { }
270
271
272
  /**
273
   * Util to fetch mappings for a given direction
274
   *
275
   * @param string $sid
276
   *   The server id
277
   * @param string $direction LDAP_USER_PROV_DIRECTION_* constant
278
   * @param array $prov_events
279
   *
280
   * @return array/bool
281
   *   Array of mappings (may be empty array)
282
  */
283
  public function getSynchMappings($direction = LDAP_USER_PROV_DIRECTION_ALL, $prov_events = NULL) {
284
    if (!$prov_events) {
285
      $prov_events = ldap_user_all_events();
286
    }
287
288
    $mappings = array();
289
    if ($direction == LDAP_USER_PROV_DIRECTION_ALL) {
290
      $directions = array(LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY);
291
    }
292
    else {
293
      $directions = array($direction);
294
    }
295
    foreach ($directions as $direction) {
296
      if (!empty($this->ldapUserSynchMappings[$direction])) {
297
        foreach ($this->ldapUserSynchMappings[$direction] as $attribute => $mapping) {
298
          if (!empty($mapping['prov_events'])) {
299
            $result = count(array_intersect($prov_events, $mapping['prov_events']));
300
            if ($result) {
301
              $mappings[$attribute] = $mapping;
302
            }
303
          }
304
        }
305
      }
306
    }
307
    return $mappings;
308
  }
309
310
  public function isDrupalAcctProvisionServer($sid) {
311
    if (!$sid || !$this->drupalAcctProvisionServer) {
312
      return FALSE;
313
    }
314
    elseif ($this->ldapEntryProvisionServer == $sid) {
315
      return TRUE;
316
    }
317
    else {
318
      return FALSE;
319
    }
320
  }
321
322
  public function isLdapEntryProvisionServer($sid) {
323
    if (!$sid || !$this->ldapEntryProvisionServer) {
324
      return FALSE;
325
    }
326
    elseif ($this->ldapEntryProvisionServer == $sid) {
327
      return TRUE;
328
    }
329
    else {
330
      return FALSE;
331
    }
332
  }
333
334
  /**
335
   * Util to fetch attributes required for this user conf, not other modules.
336
   *
337
   * @param enum $direction LDAP_USER_PROV_DIRECTION_* constants
338
   * @param string $ldap_context
339
   *
340
  */
341
  public function getLdapUserRequiredAttributes($direction = LDAP_USER_PROV_DIRECTION_ALL, $ldap_context = NULL) {
342
343
    $attributes_map = array();
344
    $required_attributes = array();
345
    if ($this->drupalAcctProvisionServer) {
346
      $prov_events = $this->ldapContextToProvEvents($ldap_context);
347
      $attributes_map = $this->getSynchMappings($direction, $prov_events);
348
      $required_attributes = array();
349
      foreach ($attributes_map as $detail) {
350
        if (count(array_intersect($prov_events, $detail['prov_events']))) {
351
          // Add the attribute to our array.
352
          if ($detail['ldap_attr']) {
353
            ldap_servers_token_extract_attributes($required_attributes,  $detail['ldap_attr']);
354
          }
355
        }
356
      }
357
    }
358
    return $required_attributes;
359
  }
360
361
/**
362
 * converts the more general ldap_context string to its associated ldap user event
363
 */
364
365
  public function ldapContextToProvEvents($ldap_context = NULL) {
366
367
    switch ($ldap_context) {
368
369
      case 'ldap_user_prov_to_drupal':
370
        $result = array(LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER, LDAP_USER_EVENT_CREATE_DRUPAL_USER, LDAP_USER_EVENT_LDAP_ASSOCIATE_DRUPAL_ACCT);
371
        break;
372
373
      case 'ldap_user_prov_to_ldap':
374
        $result = array(LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY, LDAP_USER_EVENT_CREATE_LDAP_ENTRY);
375
        break;
376
377
      default:
378
        $result = ldap_user_all_events();
379
380
    }
381
382
    return $result;
383
384
  }
385
386
387
/**
388
 * converts the more general ldap_context string to its associated ldap user prov direction
389
 */
390
391
  public function ldapContextToProvDirection($ldap_context = NULL) {
392
393
    switch ($ldap_context) {
394
395
      case 'ldap_user_prov_to_drupal':
396
        $result = LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER;
397
        break;
398
399
      case 'ldap_user_prov_to_ldap':
400
      case 'ldap_user_delete_drupal_user':
401
        $result = LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY;
402
        break;
403
404
      // provisioning is can hapen in both directions in most contexts
405
      case 'ldap_user_insert_drupal_user':
406
      case 'ldap_user_update_drupal_user':
407
      case 'ldap_authentication_authenticate':
408
      case 'ldap_user_insert_drupal_user':
409
      case 'ldap_user_disable_drupal_user':
410
        $result = LDAP_USER_PROV_DIRECTION_ALL;
411
        break;
412
413
      default:
414
        $result = LDAP_USER_PROV_DIRECTION_ALL;
415
416
    }
417
418
    return $result;
419
  }
420
421
  /**
422
    derive mapping array from ldap user configuration and other configurations.
423
    if this becomes a resource hungry function should be moved to ldap_user functions
424
    and stored with static variable. should be cached also.
425

426
    this should be cached and modules implementing ldap_user_synch_mapping_alter
427
    should know when to invalidate cache.
428

429
   */
430
431
  function setSynchMapping($reset = TRUE) {  // @todo change default to false after development
432
    $synch_mapping_cache = cache_get('ldap_user_synch_mapping');
433
    if (!$reset && $synch_mapping_cache) {
434
      $this->synchMapping = $synch_mapping_cache->data;
435
    }
436
    else {
437
      $available_user_attrs = array();
438
      foreach (array(LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) as $direction) {
439
        $sid = $this->provisionSidFromDirection[$direction];
440
        $available_user_attrs[$direction] = array();
441
        $ldap_server = ($sid) ? ldap_servers_get_servers($sid, NULL, TRUE) : FALSE;
442
443
        $params = array(
444
          'ldap_server' => $ldap_server,
445
          'ldap_user_conf' => $this,
446
          'direction' => $direction,
447
        );
448
449
        drupal_alter('ldap_user_attrs_list', $available_user_attrs[$direction], $params);
450
      }
451
    }
452
    $this->synchMapping = $available_user_attrs;
453
454
    cache_set('ldap_user_synch_mapping',  $this->synchMapping);
455
  }
456
457
  /**
458
   * given a $prov_event determine if ldap user configuration supports it.
459
   *   this is overall, not per field synching configuration
460
   *
461
   * @param enum $direction LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER or LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY
462
   *
463
   * @param enum $prov_event
464
   *   LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER, LDAP_USER_EVENT_CREATE_DRUPAL_USER
465
   *   LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY LDAP_USER_EVENT_CREATE_LDAP_ENTRY
466
   *   LDAP_USER_EVENT_LDAP_ASSOCIATE_DRUPAL_ACCT
467
   *   LDAP_USER_EVENT_ALL
468
   *
469
   * @param enum $action 'synch', 'provision', 'delete_ldap_entry', 'delete_drupal_entry', 'cancel_drupal_entry'
470
   * @return boolean
471
   */
472
473
  public function provisionEnabled($direction, $provision_trigger) {
474
    $result = FALSE;
475
476
    if ($direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
477
478
      if (!$this->ldapEntryProvisionServer) {
479
        $result = FALSE;
480
      }
481
      else {
482
        $result = in_array($provision_trigger, $this->ldapEntryProvisionTriggers);
483
      }
484
485
    }
486
    elseif ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) {
487
      if (!$this->drupalAcctProvisionServer) {
488
        $result = FALSE;
489
      }
490
      else {
491
        $result = in_array($provision_trigger, $this->drupalAcctProvisionTriggers);
492
      }
493
    }
494
495
    return $result;
496
  }
497
498
 /**
499
   * given a drupal account, provision an ldap entry if none exists.  if one exists do nothing
500
   *
501
   * @param object $account drupal account object with minimum of name property
502
   * @param array $ldap_user as prepopulated ldap entry.  usually not provided
503
   *
504
   * @return array of form:
505
   *     array('status' => 'success', 'fail', or 'conflict'),
506
   *     array('ldap_server' => ldap server object),
507
   *     array('proposed' => proposed ldap entry),
508
   *     array('existing' => existing ldap entry),
509
   *     array('description' = > blah blah)
510
   *
511
   */
512
513
  public function provisionLdapEntry($account, $ldap_user = NULL, $test_query = FALSE) {
514
    $watchdog_tokens = array();
515
    $result = array(
516
      'status' => NULL,
517
      'ldap_server' => NULL,
518
      'proposed' => NULL,
519
      'existing' => NULL,
520
      'description' => NULL,
521
    );
522
523
    if (is_scalar($account)) {
524
      $username = $account;
525
      $account = new stdClass();
526 be58a50c Assos Assos
      $account->name = $username;
527 85ad3d82 Assos Assos
    }
528
529
    list($account, $user_entity) = ldap_user_load_user_acct_and_entity($account->name);
530
531
    if (is_object($account) && property_exists($account, 'uid') && $account->uid == 1) {
532
      $result['status'] = 'fail';
533
      $result['error_description'] = 'can not provision drupal user 1';
534
      return $result; // do not provision or synch user 1
535
    }
536
537
    if ($account == FALSE || $account->uid == 0) {
538
      $result['status'] = 'fail';
539
      $result['error_description'] = 'can not provision ldap user unless corresponding drupal account exists first.';
540
      return $result;
541
    }
542
543
    if (!$this->ldapEntryProvisionServer || !$this->ldapEntryProvisionServer) {
544
      $result['status'] = 'fail';
545
      $result['error_description'] = 'no provisioning server enabled';
546
      return $result;
547
    }
548
549
    $ldap_server = ldap_servers_get_servers($this->ldapEntryProvisionServer, NULL, TRUE);
550
    $params = array(
551
      'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY,
552
      'prov_events' => array(LDAP_USER_EVENT_CREATE_LDAP_ENTRY),
553
      'module' => 'ldap_user',
554
      'function' => 'provisionLdapEntry',
555
      'include_count' => FALSE,
556
    );
557
558
    list($proposed_ldap_entry, $error) = $this->drupalUserToLdapEntry($account, $ldap_server, $params, $ldap_user);
559
    $proposed_dn = (is_array($proposed_ldap_entry) && isset($proposed_ldap_entry['dn']) && $proposed_ldap_entry['dn']) ? $proposed_ldap_entry['dn'] : NULL;
560
    $proposed_dn_lcase = drupal_strtolower($proposed_dn);
561
    $existing_ldap_entry = ($proposed_dn) ? $ldap_server->dnExists($proposed_dn, 'ldap_entry') : NULL;
562
563
    if ($error == LDAP_USER_PROV_RESULT_NO_PWD) {
564
      $result['status'] = 'fail';
565
      $result['description'] = 'Can not provision ldap account without user provided password.';
566
      $result['existing'] = $existing_ldap_entry;
567
      $result['proposed'] = $proposed_ldap_entry;
568
      $result['ldap_server'] = $ldap_server;
569
    }
570
    elseif (!$proposed_dn) {
571
      $result['status'] = 'fail';
572
      $result['description'] = t('failed to derive dn and or mappings');
573
      return $result;
574
    }
575
    elseif ($existing_ldap_entry) {
576
      $result['status'] = 'conflict';
577
      $result['description'] = 'can not provision ldap entry because exists already';
578
      $result['existing'] = $existing_ldap_entry;
579
      $result['proposed'] = $proposed_ldap_entry;
580
      $result['ldap_server'] = $ldap_server;
581
    }
582
    elseif ($test_query) {
583
      $result['status'] = 'fail';
584
      $result['description'] = 'not created because flagged as test query';
585
      $result['proposed'] = $proposed_ldap_entry;
586
      $result['ldap_server'] = $ldap_server;
587
    }
588
    else {
589
      // stick $proposed_ldap_entry in $ldap_entries array for drupal_alter call
590
      $ldap_entries = array($proposed_dn_lcase => $proposed_ldap_entry);
591
      $context = array(
592
        'action' => 'add',
593
        'corresponding_drupal_data' => array($proposed_dn_lcase => $account),
594
        'corresponding_drupal_data_type' => 'user',
595
      );
596
      drupal_alter('ldap_entry_pre_provision', $ldap_entries, $ldap_server, $context);
597
      // remove altered $proposed_ldap_entry from $ldap_entries array
598
      $proposed_ldap_entry = $ldap_entries[$proposed_dn_lcase];
599
600
      $ldap_entry_created = $ldap_server->createLdapEntry($proposed_ldap_entry, $proposed_dn);
601
      if ($ldap_entry_created) {
602
        module_invoke_all('ldap_entry_post_provision', $ldap_entries, $ldap_server, $context);
603
        $result['status'] = 'success';
604
        $result['description'] = 'ldap account created';
605
        $result['proposed'] = $proposed_ldap_entry;
606
        $result['created'] = $ldap_entry_created;
607
        $result['ldap_server'] = $ldap_server;
608
609
        // need to store <sid>|<dn> in ldap_user_prov_entries field, which may contain more than one
610
        $ldap_user_prov_entry = $ldap_server->sid . '|' . $proposed_ldap_entry['dn'];
611 7547bb19 Assos Assos
        if (!isset($user_entity->ldap_user_prov_entries[LANGUAGE_NONE])) {
612
          $user_entity->ldap_user_prov_entries = array(LANGUAGE_NONE => array());
613 85ad3d82 Assos Assos
        }
614
        $ldap_user_prov_entry_exists = FALSE;
615 7547bb19 Assos Assos
        foreach ($user_entity->ldap_user_prov_entries[LANGUAGE_NONE] as $i => $field_value_instance) {
616 85ad3d82 Assos Assos
          if ($field_value_instance == $ldap_user_prov_entry) {
617
            $ldap_user_prov_entry_exists = TRUE;
618
          }
619
        }
620
        if (!$ldap_user_prov_entry_exists) {
621 7547bb19 Assos Assos
          $user_entity->ldap_user_prov_entries[LANGUAGE_NONE][] = array(
622 85ad3d82 Assos Assos
            'value' =>  $ldap_user_prov_entry,
623
          );
624 5136ce55 Assos Assos
625
          // Save the field without calling user_save()
626
          field_attach_presave('user', $user_entity);
627
          field_attach_update('user', $user_entity);
628 85ad3d82 Assos Assos
        }
629
630
      }
631
      else {
632
        $result['status'] = 'fail';
633
        $result['proposed'] = $proposed_ldap_entry;
634
        $result['created'] = $ldap_entry_created;
635
        $result['ldap_server'] = $ldap_server;
636
        $result['existing'] = NULL;
637
      }
638
    }
639
640
    $tokens = array(
641
      '%dn' => isset($result['proposed']['dn']) ? $result['proposed']['dn'] : NULL,
642
      '%sid' => (isset($result['ldap_server']) && $result['ldap_server']) ? $result['ldap_server']->sid : 0,
643
      '%username' => @$account->name,
644
      '%uid' => @$account->uid,
645
      '%description' => @$result['description'],
646
    );
647
    if (!$test_query && isset($result['status'])) {
648
      if ($result['status'] == 'success') {
649
        if ($this->detailedWatchdog) {
650
          watchdog('ldap_user', 'LDAP entry on server %sid created dn=%dn.  %description. username=%username, uid=%uid', $tokens, WATCHDOG_INFO);
651
        }
652
      }
653
      elseif ($result['status'] == 'conflict') {
654
        if ($this->detailedWatchdog) {
655
          watchdog('ldap_user', 'LDAP entry on server %sid not created because of existing ldap entry. %description. username=%username, uid=%uid', $tokens, WATCHDOG_WARNING);
656
        }
657
      }
658
      elseif ($result['status'] == 'fail') {
659
        watchdog('ldap_user', 'LDAP entry on server %sid not created because error.  %description. username=%username, uid=%uid', $tokens, WATCHDOG_ERROR);
660
      }
661
    }
662
    return $result;
663
  }
664
665
666
  /**
667
   * given a drupal account, synch to related ldap entry
668
   *
669
   * @param drupal user object $account.  Drupal user object
670
   * @param array $user_edit.  Edit array for user_save.  generally null unless user account is being created or modified in same synching
671
   * @param array $ldap_user.  current ldap data of user. @see README.developers.txt for structure
672
   *
673
   * @return TRUE on success or FALSE on fail.
674
   */
675
676
  public function synchToLdapEntry($account, $user_edit = NULL, $ldap_user =  array(), $test_query = FALSE) {
677
678
    if (is_object($account) && property_exists($account, 'uid') && $account->uid == 1) {
679
      return FALSE; // do not provision or synch user 1
680
    }
681
682
    $watchdog_tokens = array();
683
    $result = FALSE;
684
    $proposed_ldap_entry = FALSE;
685
686
    if ($this->ldapEntryProvisionServer) {
687
      $ldap_server = ldap_servers_get_servers($this->ldapEntryProvisionServer, NULL, TRUE);
688
689
      $params = array(
690
        'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY,
691
        'prov_events' => array(LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY),
692
        'module' => 'ldap_user',
693
        'function' => 'synchToLdapEntry',
694
        'include_count' => FALSE,
695
      );
696
697
      list($proposed_ldap_entry, $error) = $this->drupalUserToLdapEntry($account, $ldap_server, $params, $ldap_user);
698
      if ($error != LDAP_USER_PROV_RESULT_NO_ERROR) {
699
        $result = FALSE;
700
      }
701
      elseif (is_array($proposed_ldap_entry) && isset($proposed_ldap_entry['dn'])) {
702
        $existing_ldap_entry = $ldap_server->dnExists($proposed_ldap_entry['dn'], 'ldap_entry');
703
        $attributes = array(); // this array represents attributes to be modified; not comprehensive list of attributes
704
        foreach ($proposed_ldap_entry as $attr_name => $attr_values) {
705
          if ($attr_name != 'dn') {
706
            if (isset($attr_values['count'])) {
707
              unset($attr_values['count']);
708
            }
709
            if (count($attr_values) == 1) {
710
              $attributes[$attr_name] = $attr_values[0];
711
            }
712
            else {
713
              $attributes[$attr_name] = $attr_values;
714
            }
715
          }
716
        }
717
718
        if ($test_query) {
719
          $proposed_ldap_entry = $attributes;
720
          $result = array(
721
            'proposed' => $proposed_ldap_entry,
722
            'server' => $ldap_server,
723
          );
724
        }
725
        else {
726 59ae487e Assos Assos
          // stick $proposed_ldap_entry in $ldap_entries array for drupal_alter call
727 85ad3d82 Assos Assos
          $proposed_dn_lcase = drupal_strtolower($proposed_ldap_entry['dn']);
728
          $ldap_entries = array($proposed_dn_lcase => $attributes);
729
          $context = array(
730
            'action' => 'update',
731
            'corresponding_drupal_data' => array($proposed_dn_lcase => $attributes),
732
            'corresponding_drupal_data_type' => 'user',
733
          );
734
          drupal_alter('ldap_entry_pre_provision', $ldap_entries, $ldap_server, $context);
735
          // remove altered $proposed_ldap_entry from $ldap_entries array
736
          $attributes = $ldap_entries[$proposed_dn_lcase];
737
          $result = $ldap_server->modifyLdapEntry($proposed_ldap_entry['dn'], $attributes);
738
          if ($result) { // success
739
            module_invoke_all('ldap_entry_post_provision', $ldap_entries, $ldap_server, $context);
740
          }
741
        }
742
      }
743
      else { // failed to get acceptable proposed ldap entry
744
        $result = FALSE;
745
      }
746
    }
747
748
    $tokens = array(
749
      '%dn' => isset($proposed_ldap_entry['dn']) ? $proposed_ldap_entry['dn'] : NULL,
750
      '%sid' => $this->ldapEntryProvisionServer,
751
      '%username' => $account->name,
752
      '%uid' => ($test_query || !property_exists($account, 'uid')) ? '' : $account->uid,
753
    );
754
755
    if ($result) {
756
      watchdog('ldap_user', 'LDAP entry on server %sid synched dn=%dn. username=%username, uid=%uid', $tokens, WATCHDOG_INFO);
757
    }
758
    else {
759
      watchdog('ldap_user', 'LDAP entry on server %sid not synched because error. username=%username, uid=%uid', $tokens, WATCHDOG_ERROR);
760
    }
761
762
    return $result;
763
764
  }
765
766
  /**
767
   * given a drupal account, query ldap and get all user fields and create user account
768
   *
769
   * @param array $account drupal account array with minimum of name
770
   * @param array $user_edit drupal edit array in form user_save($account, $user_edit) would take,
771
   *   generally empty unless overriding synchToDrupalAccount derived values
772
   * @param array $ldap_user as user's ldap entry.  passed to avoid requerying ldap in cases where already present
773
   * @param boolean $save indicating if drupal user should be saved.  generally depends on where function is called from.
774
   *
775
   * @return result of user_save() function is $save is true, otherwise return TRUE
776
   *   $user_edit data returned by reference
777
   *
778
   */
779
  public function synchToDrupalAccount($drupal_user, &$user_edit, $prov_event = LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER, $ldap_user = NULL,  $save = FALSE) {
780 dd54aff9 Assos Assos
    
781 85ad3d82 Assos Assos
    $debug = array(
782
      'account' => $drupal_user,
783
      'user_edit' => $user_edit,
784
      'ldap_user' => $ldap_user,
785
    );
786
787
    if (
788
        (!$ldap_user  && !isset($drupal_user->name)) ||
789
        (!$drupal_user && $save) ||
790
        ($ldap_user && !isset($ldap_user['sid']))
791
    ) {
792
       // should throw watchdog error also
793
      return FALSE;
794
    }
795
796
    if (!$ldap_user && $this->drupalAcctProvisionServer) {
797
      $ldap_user = ldap_servers_get_user_ldap_data($drupal_user->name, $this->drupalAcctProvisionServer, 'ldap_user_prov_to_drupal');
798
    }
799
800
    if (!$ldap_user) {
801
      return FALSE;
802
    }
803
804
    if ($this->drupalAcctProvisionServer) {
805
      $ldap_server = ldap_servers_get_servers($this->drupalAcctProvisionServer, NULL, TRUE);
806
      $this->entryToUserEdit($ldap_user, $user_edit, $ldap_server, LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, array($prov_event));
807
    }
808
809
    if ($save) {
810
      $account = user_load($drupal_user->uid);
811
      $result = user_save($account, $user_edit, 'ldap_user');
812
      return $result;
813
    }
814
    else {
815
      return TRUE;
816
    }
817
  }
818
819
820
  /**
821
   * given a drupal account, delete user account
822
   *
823
   * @param string $username drupal account name
824
   * @return TRUE or FALSE.  FALSE indicates failed or action not enabled in ldap user configuration
825
   */
826
  public function deleteDrupalAccount($username) {
827
    $user = user_load_by_name($username);
828
    if (is_object($user)) {
829
      user_delete($user->uid);
830
      return TRUE;
831
    }
832
    else {
833
      return FALSE;
834
    }
835
  }
836
837
  /**
838
   * given a drupal account, find the related ldap entry.
839
   *
840
   * @param drupal user object $account
841
   *
842
   * @return FALSE or ldap entry
843
   */
844
  public function getProvisionRelatedLdapEntry($account, $prov_events = NULL) {
845
    if (!$prov_events) {
846
      $prov_events = ldap_user_all_events();
847
    }
848
    $sid = $this->ldapEntryProvisionServer; //
849
    if (!$sid) {
850
      return FALSE;
851
    }
852
    // $user_entity->ldap_user_prov_entries,
853
    $ldap_server = ldap_servers_get_servers($sid, NULL, TRUE);
854
    $params = array(
855
      'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY,
856
      'prov_events' => $prov_events,
857
      'module' => 'ldap_user',
858
      'function' => 'getProvisionRelatedLdapEntry',
859
      'include_count' => FALSE,
860
      );
861
    list($proposed_ldap_entry, $error) = $this->drupalUserToLdapEntry($account, $ldap_server, $params);
862
    if (!(is_array($proposed_ldap_entry) && isset($proposed_ldap_entry['dn']) && $proposed_ldap_entry['dn'])) {
863
      return FALSE;
864
    }
865
    $ldap_entry = $ldap_server->dnExists($proposed_ldap_entry['dn'], 'ldap_entry', array());
866
    return $ldap_entry;
867
868
  }
869
870
  /**
871
   * given a drupal account, delete ldap entry that was provisioned based on it
872
   *   normally this will be 0 or 1 entry, but the ldap_user_provisioned_ldap_entries
873
   *   field attached to the user entity track each ldap entry provisioned
874
   *
875
   * @param object $account drupal account
876
   * @return TRUE or FALSE.  FALSE indicates failed or action not enabled in ldap user configuration
877
   */
878
  public function deleteProvisionedLdapEntries($account) {
879
    // determine server that is associated with user
880
881
    $boolean_result = FALSE;
882 be58a50c Assos Assos
    if (isset($account->ldap_user_prov_entries[LANGUAGE_NONE][0])) {
883
      foreach ($account->ldap_user_prov_entries[LANGUAGE_NONE] as $i => $field_instance) {
884 85ad3d82 Assos Assos
        $parts = explode('|', $field_instance['value']);
885
        if (count($parts) == 2) {
886
887
          list($sid, $dn) = $parts;
888
          $ldap_server = ldap_servers_get_servers($sid, NULL, TRUE);
889
          if (is_object($ldap_server) && $dn) {
890
            $boolean_result = $ldap_server->delete($dn);
891
            $tokens = array('%sid' => $sid, '%dn' => $dn, '%username' => $account->name, '%uid' => $account->uid);
892
            if ($boolean_result) {
893
              watchdog('ldap_user', 'LDAP entry on server %sid deleted dn=%dn. username=%username, uid=%uid', $tokens, WATCHDOG_INFO);
894
            }
895
            else {
896
              watchdog('ldap_user', 'LDAP entry on server %sid not deleted because error. username=%username, uid=%uid', $tokens, WATCHDOG_ERROR);
897
            }
898
          }
899
          else {
900
            $boolean_result = FALSE;
901
          }
902
        }
903
      }
904
    }
905
    return $boolean_result;
906
907
  }
908
909
/**
910
  *  populate ldap entry array for provisioning
911
  *
912
  * @param array $account drupal account
913
  * @param object $ldap_server
914
  * @param array $ldap_user ldap entry of user, returned by reference
915
  * @param array $params with the following key values:
916
  *    'ldap_context' =>
917
       'module' => module calling function, e.g. 'ldap_user'
918
       'function' => function calling function, e.g. 'provisionLdapEntry'
919
       'include_count' => should 'count' array key be included
920
       'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY || LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER
921
  *
922
  * @return array(ldap entry, $result) in ldap extension array format.!THIS IS NOT THE ACTUAL LDAP ENTRY
923
  */
924
925
  function drupalUserToLdapEntry($account, $ldap_server, $params, $ldap_user_entry = NULL) {
926
    $provision = (isset($params['function']) && $params['function'] == 'provisionLdapEntry');
927
    $result = LDAP_USER_PROV_RESULT_NO_ERROR;
928
    if (!$ldap_user_entry) {
929
      $ldap_user_entry = array();
930
    }
931
932
    if (!is_object($account) || !is_object($ldap_server)) {
933
      return array(NULL, LDAP_USER_PROV_RESULT_BAD_PARAMS);
934
    }
935
    $watchdog_tokens = array(
936
      '%drupal_username' => $account->name,
937
    );
938
    $include_count = (isset($params['include_count']) && $params['include_count']);
939
940
    $direction = isset($params['direction']) ? $params['direction'] : LDAP_USER_PROV_DIRECTION_ALL;
941
    $prov_events = empty($params['prov_events']) ? ldap_user_all_events() : $params['prov_events'];
942
943
    $mappings = $this->getSynchMappings($direction, $prov_events);
944
    foreach ($mappings as $field_key => $field_detail) {
945
      list($ldap_attr_name, $ordinal, $conversion) = ldap_servers_token_extract_parts($field_key, TRUE);  //trim($field_key, '[]');
946
      $ordinal = (!$ordinal) ? 0 : $ordinal;
947
      if ($ldap_user_entry && isset($ldap_user_entry[$ldap_attr_name]) && is_array($ldap_user_entry[$ldap_attr_name]) && isset($ldap_user_entry[$ldap_attr_name][$ordinal]) ) {
948
        continue; // don't override values passed in;
949
      }
950
951
      $synched = $this->isSynched($field_key, $params['prov_events'], LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY);
952
      if ($synched) {
953
        $token = ($field_detail['user_attr'] == 'user_tokens') ? $field_detail['user_tokens'] : $field_detail['user_attr'];
954
        $value = ldap_servers_token_replace($account, $token, 'user_account');
955
956
        if (substr($token, 0, 10) == '[password.' && (!$value || $value == $token)) { // deal with empty/unresolved password
957
          if (!$provision) {
958
            continue; //don't overwrite password on synch if no value provided
959
          }
960
        }
961
962
        if ($ldap_attr_name == 'dn' && $value) {
963
          $ldap_user_entry['dn'] = $value;
964
        }
965
        elseif ($value) {
966
          if (!isset($ldap_user_entry[$ldap_attr_name]) || !is_array($ldap_user_entry[$ldap_attr_name])) {
967
            $ldap_user_entry[$ldap_attr_name] = array();
968
          }
969
          $ldap_user_entry[$ldap_attr_name][$ordinal] = $value;
970
          if ($include_count) {
971
            $ldap_user_entry[$ldap_attr_name]['count'] = count($ldap_user_entry[$ldap_attr_name]);
972
          }
973
974
        }
975
976
      }
977
978
    }
979
980
    /**
981
     * 4. call drupal_alter() to allow other modules to alter $ldap_user
982
     */
983
984
    drupal_alter('ldap_entry', $ldap_user_entry, $params);
985
986
    return array($ldap_user_entry, $result);
987
988
  }
989
990
991
992
   /**
993
   * given a drupal account, query ldap and get all user fields and save user account
994
   * (note: parameters are in odd order to match synchDrupalAccount handle)
995
   *
996
   * @param array $account drupal account object or null
997
   * @param array $user_edit drupal edit array in form user_save($account, $user_edit) would take.
998
   * @param array $ldap_user as user's ldap entry.  passed to avoid requerying ldap in cases where already present
999
   * @param boolean $save indicating if drupal user should be saved.  generally depends on where function is called from and if the
1000
   *
1001
   * @return result of user_save() function is $save is true, otherwise return TRUE on success or FALSE on any problem
1002
   *   $user_edit data returned by reference
1003
   *
1004
   */
1005
1006
  public function provisionDrupalAccount($account = FALSE, &$user_edit, $ldap_user = NULL, $save = TRUE) {
1007
1008
    $watchdog_tokens = array();
1009
    /**
1010
     * @todo
1011
     * -- add error catching for conflicts, conflicts should be checked before calling this function.
1012
     *
1013
     */
1014
1015
    if (!$account) {
1016
      $account = new stdClass();
1017
    }
1018
    $account->is_new = TRUE;
1019
1020
    if (!$ldap_user && !isset($user_edit['name'])) {
1021
      return FALSE;
1022
    }
1023
1024
    if (!$ldap_user) {
1025
      $watchdog_tokens['%username'] = $user_edit['name'];
1026
      if ($this->drupalAcctProvisionServer) {
1027
        $ldap_user = ldap_servers_get_user_ldap_data($user_edit['name'], $this->drupalAcctProvisionServer, 'ldap_user_prov_to_drupal');
1028
      }
1029
      if (!$ldap_user) {
1030
        if ($this->detailedWatchdog) {
1031
          watchdog('ldap_user', '%username : failed to find associated ldap entry for username in provision.', $watchdog_tokens, WATCHDOG_DEBUG);
1032
        }
1033
        return FALSE;
1034
      }
1035
    }
1036 59ae487e Assos Assos
1037 85ad3d82 Assos Assos
    if (!isset($user_edit['name']) && isset($account->name)) {
1038
      $user_edit['name'] = $account->name;
1039
      $watchdog_tokens['%username'] = $user_edit['name'];
1040
    }
1041 dd54aff9 Assos Assos
    //When using the multi-domain last authentication option
1042
    //$ldap_server breaks beacause $this->drupalAcctProvisionServer is set on LDAP_USER_AUTH_SERVER_SID
1043
    //So we need to check it's not the case before using ldap_servers_get_servers
1044
    if ($this->drupalAcctProvisionServer && $this->drupalAcctProvisionServer != LDAP_USER_AUTH_SERVER_SID) {
1045 85ad3d82 Assos Assos
1046
      $ldap_server = ldap_servers_get_servers($this->drupalAcctProvisionServer, 'enabled', TRUE);  // $ldap_user['sid']
1047
1048
      $params = array(
1049
        'account' => $account,
1050
        'user_edit' => $user_edit,
1051
        'prov_event' => LDAP_USER_EVENT_CREATE_DRUPAL_USER,
1052
        'module' => 'ldap_user',
1053
        'function' => 'provisionDrupalAccount',
1054
        'direction' => LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER,
1055
      );
1056
1057
      drupal_alter('ldap_entry', $ldap_user, $params);
1058
1059
      // look for existing drupal account with same puid.  if so update username and attempt to synch in current context
1060
      $puid = $ldap_server->userPuidFromLdapEntry($ldap_user['attr']);
1061
      $account2 = ($puid) ? $ldap_server->userUserEntityFromPuid($puid) : FALSE;
1062
1063
      if ($account2) { // synch drupal account, since drupal account exists
1064
        // 1. correct username and authmap
1065
        $this->entryToUserEdit($ldap_user, $user_edit, $ldap_server, LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, array(LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER));
1066
        $account = user_save($account2, $user_edit, 'ldap_user');
1067
        user_set_authmaps($account, array("authname_ldap_user" => $user_edit['name']));
1068
        // 2. attempt synch if appropriate for current context
1069
        if ($account) {
1070
          $account = $this->synchToDrupalAccount($account, $user_edit, LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER, $ldap_user, TRUE);
1071
        }
1072
        return $account;
1073
      }
1074
      else { // create drupal account
1075
        $this->entryToUserEdit($ldap_user, $user_edit, $ldap_server, LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, array(LDAP_USER_EVENT_CREATE_DRUPAL_USER));
1076
        if ($save) {
1077
          $watchdog_tokens = array('%drupal_username' =>  $user_edit['name']);
1078
          if (empty($user_edit['name'])) {
1079
            drupal_set_message(t('User account creation failed because of invalid, empty derived Drupal username.'), 'error');
1080
            watchdog('ldap_user',
1081
              'Failed to create Drupal account %drupal_username because drupal username could not be derived.',
1082
              $watchdog_tokens,
1083
              WATCHDOG_ERROR
1084
            );
1085
            return FALSE;
1086
          }
1087
          if (!isset($user_edit['mail']) || !$user_edit['mail']) {
1088
            drupal_set_message(t('User account creation failed because of invalid, empty derived email address.'), 'error');
1089
            watchdog('ldap_user',
1090
              'Failed to create Drupal account %drupal_username because email address could not be derived by LDAP User module',
1091
              $watchdog_tokens,
1092
              WATCHDOG_ERROR
1093
            );
1094
            return FALSE;
1095
          }
1096 b42754b9 Assos Assos
          if(($this->accountsWithSameEmail == LDAP_USER_ACCOUNTS_WITH_SAME_EMAIL_DISABLED) && ($account_with_same_email = user_load_by_mail($user_edit['mail']))) {
1097 85ad3d82 Assos Assos
            $watchdog_tokens['%email'] = $user_edit['mail'];
1098
            $watchdog_tokens['%duplicate_name'] = $account_with_same_email->name;
1099
            watchdog('ldap_user', 'LDAP user %drupal_username has email address
1100
              (%email) conflict with a drupal user %duplicate_name', $watchdog_tokens, WATCHDOG_ERROR);
1101
            drupal_set_message(t('Another user already exists in the system with the same email address. You should contact the system administrator in order to solve this conflict.'), 'error');
1102
            return FALSE;
1103
          }
1104
          $account = user_save(NULL, $user_edit, 'ldap_user');
1105
          if (!$account) {
1106
            drupal_set_message(t('User account creation failed because of system problems.'), 'error');
1107
          }
1108
          else {
1109
            user_set_authmaps($account, array('authname_ldap_user' => $account->name));
1110
            ldap_user_ldap_provision_semaphore('drupal_created', 'set', $account->name);
1111
          }
1112
          return $account;
1113
        }
1114
        return TRUE;
1115
      }
1116
    }
1117
  }
1118
1119
  /**
1120
   * set ldap associations of a drupal account by altering user fields
1121
   *
1122
   * @param string $drupal_username
1123
   *
1124
   * @return boolean TRUE on success, FALSE on error or failure because of invalid user or ldap accounts
1125
   *
1126
   */
1127
  function ldapAssociateDrupalAccount($drupal_username) {
1128
1129
    if ($this->drupalAcctProvisionServer) {
1130
      $prov_events = array(LDAP_USER_EVENT_LDAP_ASSOCIATE_DRUPAL_ACCT);
1131
      $ldap_server = ldap_servers_get_servers($this->drupalAcctProvisionServer, 'enabled', TRUE);  // $ldap_user['sid']
1132
      $account = user_load_by_name($drupal_username);
1133
      $ldap_user = ldap_servers_get_user_ldap_data($drupal_username, $this->drupalAcctProvisionServer, 'ldap_user_prov_to_drupal');
1134
      if (!$account) {
1135
        watchdog(
1136
          'ldap_user',
1137
          'Failed to LDAP associate drupal account %drupal_username because account not found',
1138
          array('%drupal_username' => $drupal_username),
1139
          WATCHDOG_ERROR
1140
        );
1141
        return FALSE;
1142
      }
1143
      elseif (!$ldap_user) {
1144
        watchdog(
1145
          'ldap_user',
1146
          'Failed to LDAP associate drupal account %drupal_username because corresponding LDAP entry not found',
1147
          array('%drupal_username' => $drupal_username),
1148
          WATCHDOG_ERROR
1149
        );
1150
        return FALSE;
1151
      }
1152
      else {
1153
        $user_edit = array();
1154
        $user_edit['data']['ldap_user']['init'] = array(
1155
          'sid'  => $ldap_user['sid'],
1156
          'dn'   => $ldap_user['dn'],
1157
          'mail'   => $account->mail,
1158
        );
1159
        $ldap_user_puid = $ldap_server->userPuidFromLdapEntry($ldap_user['attr']);
1160
        if ($ldap_user_puid) {
1161
          $user_edit['ldap_user_puid'][LANGUAGE_NONE][0]['value'] = $ldap_user_puid; //
1162
        }
1163
        $user_edit['ldap_user_puid_property'][LANGUAGE_NONE][0]['value'] = $ldap_server->unique_persistent_attr;
1164
        $user_edit['ldap_user_puid_sid'][LANGUAGE_NONE][0]['value'] = $ldap_server->sid;
1165
        $user_edit['ldap_user_current_dn'][LANGUAGE_NONE][0]['value'] = $ldap_user['dn'];
1166
        $account = user_save($account, $user_edit, 'ldap_user');
1167
        return (boolean)$account;
1168
      }
1169
    }
1170
    else {
1171
      return FALSE;
1172
    }
1173
  }
1174
1175
  /** populate $user edit array (used in hook_user_save, hook_user_update, etc)
1176
   * ... should not assume all attribues are present in ldap entry
1177
   *
1178
   * @param array ldap entry $ldap_user
1179
   * @param array $edit see hook_user_save, hook_user_update, etc
1180
   * @param object $ldap_server
1181
   * @param enum $direction
1182
   * @param array $prov_events
1183
   *
1184
   */
1185
1186
  function entryToUserEdit($ldap_user, &$edit, $ldap_server, $direction = LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, $prov_events = NULL) {
1187
1188
    // need array of user fields and which direction and when they should be synched.
1189
    if (!$prov_events) {
1190
      $prov_events = ldap_user_all_events();
1191
    }
1192
    $mail_synched = $this->isSynched('[property.mail]', $prov_events, $direction);
1193
    if (!isset($edit['mail']) && $mail_synched) {
1194
      $derived_mail = $ldap_server->userEmailFromLdapEntry($ldap_user['attr']);
1195
      if ($derived_mail) {
1196
        $edit['mail'] = $derived_mail;
1197
      }
1198
    }
1199
1200
    $drupal_username = $ldap_server->userUsernameFromLdapEntry($ldap_user['attr']);
1201
                if ($this->isSynched('[property.picture]', $prov_events, $direction)){
1202
1203
                        $picture = $ldap_server->userPictureFromLdapEntry($ldap_user['attr'], $drupal_username);
1204
1205
                        if ($picture){
1206
                                $edit['picture'] = $picture;
1207
                                if(isset($picture->md5Sum)){
1208
                                        $edit['data']['ldap_user']['init']['thumb5md'] = $picture->md5Sum;
1209
                                }
1210
                        }
1211
                }
1212
1213
    if ($this->isSynched('[property.name]', $prov_events, $direction) && !isset($edit['name']) && $drupal_username) {
1214
      $edit['name'] = $drupal_username;
1215
    }
1216
1217
    if ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER && in_array(LDAP_USER_EVENT_CREATE_DRUPAL_USER, $prov_events)) {
1218
      $edit['mail'] = isset($edit['mail']) ? $edit['mail'] : $ldap_user['mail'];
1219
      if (!isset($edit['pass'])) {
1220
        $edit['pass'] = user_password(20);
1221
        watchdog('ldap_user', '20 character random password generated for the %username account that has been created.', array('%username' => $drupal_username), WATCHDOG_INFO);
1222
      }
1223
      $edit['init'] = isset($edit['init']) ? $edit['init'] : $edit['mail'];
1224
      $edit['status'] = isset($edit['status']) ? $edit['status'] : 1;
1225
      $edit['signature'] = isset($edit['signature']) ? $edit['signature'] : '';
1226
1227
      $edit['data']['ldap_user']['init'] = array(
1228
        'sid'  => $ldap_user['sid'],
1229
        'dn'   => $ldap_user['dn'],
1230
        'mail' => $edit['mail'],
1231
      );
1232
    }
1233
1234
    /*
1235
     * Make sure the user account has the latest ldap_user settings
1236
     * when syncing the profile.
1237
     */
1238
    if ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER && in_array(LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER, $prov_events)) {
1239
       $edit['data']['ldap_user']['init'] = array(
1240
        'sid'  => $ldap_user['sid'],
1241
        'dn'   => $ldap_user['dn'],
1242
        'mail' => isset($edit['mail']) && !empty($edit['mail']) ? $edit['mail'] : $ldap_user['mail'],
1243
      );
1244
    }
1245
1246
    /**
1247
     * basic $user ldap fields
1248
     */
1249
    if ($this->isSynched('[field.ldap_user_puid]', $prov_events, $direction)) {
1250
      $ldap_user_puid = $ldap_server->userPuidFromLdapEntry($ldap_user['attr']);
1251
      if ($ldap_user_puid) {
1252
        $edit['ldap_user_puid'][LANGUAGE_NONE][0]['value'] = $ldap_user_puid; //
1253
      }
1254
    }
1255
    if ($this->isSynched('[field.ldap_user_puid_property]', $prov_events, $direction)) {
1256
      $edit['ldap_user_puid_property'][LANGUAGE_NONE][0]['value'] = $ldap_server->unique_persistent_attr;
1257
    }
1258
    if ($this->isSynched('[field.ldap_user_puid_sid]', $prov_events, $direction)) {
1259
      $edit['ldap_user_puid_sid'][LANGUAGE_NONE][0]['value'] = $ldap_server->sid;
1260
    }
1261
    if ($this->isSynched('[field.ldap_user_current_dn]', $prov_events, $direction)) {
1262
      $edit['ldap_user_current_dn'][LANGUAGE_NONE][0]['value'] = $ldap_user['dn'];
1263
    }
1264
1265
    // Get any additional mappings.
1266
    $mappings = $this->getSynchMappings($direction, $prov_events);
1267
1268
     // Loop over the mappings.
1269
    foreach ($mappings as $user_attr_key => $field_detail) {
1270
1271
       // Make sure this mapping is relevant to the sync context.
1272
      if (!$this->isSynched($user_attr_key, $prov_events, $direction)) {
1273
        continue;
1274
      }
1275
       /**
1276
        * if "convert from binary is selected" and no particular method is in token,
1277
        * default to ldap_servers_binary() function
1278
        */
1279
      if ($field_detail['convert'] && strpos($field_detail['ldap_attr'], ';') === FALSE) {
1280
        $field_detail['ldap_attr'] = str_replace(']', ';binary]', $field_detail['ldap_attr']);
1281
      }
1282
      $value = ldap_servers_token_replace($ldap_user['attr'], $field_detail['ldap_attr'], 'ldap_entry');
1283
      list($value_type, $value_name, $value_instance) = ldap_servers_parse_user_attr_name($user_attr_key);
1284
1285
      // $value_instance not used, may have future use case
1286
1287
      // Are we dealing with a field?
1288
      if ($value_type == 'field') {
1289
        // Field api field - first we get the field.
1290
        $field = field_info_field($value_name);
1291
        // Then the columns for the field in the schema.
1292
        $columns = array_keys($field['columns']);
1293
        // Then we convert the value into an array if it's scalar.
1294
        $values = $field['cardinality'] == 1 ? array($value) : (array) $value;
1295
1296
        $items = array();
1297
        // Loop over the values and set them in our $items array.
1298
        foreach ($values as $delta => $value) {
1299
          if (isset($value)) {
1300
            // We set the first column value only, this is consistent with
1301
            // the Entity Api (@see entity_metadata_field_property_set).
1302
            $items[$delta][$columns[0]] = $value;
1303
          }
1304
        }
1305
        // Add them to our edited item.
1306
        $edit[$value_name][LANGUAGE_NONE] = $items;
1307
      }
1308
      elseif ($value_type == 'property') {
1309
        // Straight property.
1310
        $edit[$value_name] = $value;
1311
      }
1312
    }
1313
1314
    // Allow other modules to have a say.
1315
1316
    drupal_alter('ldap_user_edit_user', $edit, $ldap_user, $ldap_server, $prov_events);
1317
    if (isset($edit['name']) && $edit['name'] == '') {  // don't let empty 'name' value pass for user
1318
      unset($edit['name']);
1319
    }
1320
1321
  }
1322
  /**
1323
   * given configuration of synching, determine is a given synch should occur
1324
   *
1325
   * @param string $attr_token e.g. [property.mail], [field.ldap_user_puid_property]
1326
   * @param object $ldap_server
1327
   * @param array $prov_events e.g. array(LDAP_USER_EVENT_CREATE_DRUPAL_USER).  typically array with 1 element
1328
   * @param scalar $direction LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER or LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY
1329
   */
1330
1331
  public function isSynched($attr_token, $prov_events, $direction) {
1332
    $result = (boolean)(
1333
      isset($this->synchMapping[$direction][$attr_token]['prov_events']) &&
1334
      count(array_intersect($prov_events, $this->synchMapping[$direction][$attr_token]['prov_events']))
1335
    );
1336
    if (!$result) {
1337
      if (isset($this->synchMapping[$direction][$attr_token])) {
1338
      }
1339
      else {
1340
      }
1341
    }
1342
    return $result;
1343
  }
1344
1345 59ae487e Assos Assos
}