Projet

Général

Profil

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

root / drupal7 / sites / all / modules / ldap / ldap_user / ldap_user.module @ 91af538d

1
<?php
2

    
3
/**
4
 * @file
5
 * Module for the LDAP User Entity.
6
 */
7

    
8
define('LDAP_USER_DRUPAL_HELP_URL', 'http://drupal.org/node/997082');
9

    
10
// Configurable drupal acct provision triggers.
11
define('LDAP_USER_DRUPAL_USER_PROV_ON_USER_UPDATE_CREATE', 1);
12
define('LDAP_USER_DRUPAL_USER_PROV_ON_AUTHENTICATE', 2);
13
define('LDAP_USER_DRUPAL_USER_PROV_ON_ALLOW_MANUAL_CREATE', 3);
14

    
15
// Configurable ldap entry provision triggers.
16
define('LDAP_USER_LDAP_ENTRY_PROV_ON_USER_UPDATE_CREATE', 6);
17
define('LDAP_USER_LDAP_ENTRY_PROV_ON_AUTHENTICATE', 7);
18
define('LDAP_USER_LDAP_ENTRY_DELETE_ON_USER_DELETE', 8);
19

    
20
// Provisioning events (events are triggered by triggers)
21
define('LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER', 1);
22
define('LDAP_USER_EVENT_CREATE_DRUPAL_USER', 2);
23
define('LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY', 3);
24
define('LDAP_USER_EVENT_CREATE_LDAP_ENTRY', 4);
25
define('LDAP_USER_EVENT_LDAP_ASSOCIATE_DRUPAL_ACCT', 5);
26

    
27
// Results of ldap entry provisioning.
28
define('LDAP_USER_PROVISION_LDAP_ENTRY_EXISTS', 1);
29
define('LDAP_USER_PROVISION_LDAP_ENTRY_CREATE_FAILED', 2);
30
define('LDAP_USER_PROVISION_LDAP_ENTRY_SYNCH_FAILED', 3);
31

    
32
// Options for what to do when existing non ldap associated Drupal account conflicts with ldap account.
33
define('LDAP_USER_CONFLICT_LOG', 1);
34
define('LDAP_USER_CONFLICT_RESOLVE', 2);
35
define('LDAP_USER_CONFLICT_RESOLVE_DEFAULT', 2);
36

    
37
// Options for what to do if another Drupal account has the same email address.
38
define('LDAP_USER_ACCOUNTS_WITH_SAME_EMAIL_DISABLED', 0);
39
define('LDAP_USER_ACCOUNTS_WITH_SAME_EMAIL_ENABLED', 1);
40

    
41
// Options for dealing with manual account creation that conflict with ldap entries.
42
define('LDAP_USER_MANUAL_ACCT_CONFLICT_REJECT', 1);
43
define('LDAP_USER_MANUAL_ACCT_CONFLICT_LDAP_ASSOCIATE', 2);
44
define('LDAP_USER_MANUAL_ACCT_CONFLICT_SHOW_OPTION_ON_FORM', 3);
45
define('LDAP_USER_MANUAL_ACCT_CONFLICT_NO_LDAP_ASSOCIATE', 4);
46

    
47
// Options for account creation behavior.
48
define('LDAP_USER_ACCT_CREATION_LDAP_BEHAVIOR', 4);
49
define('LDAP_USER_ACCT_CREATION_USER_SETTINGS_FOR_LDAP', 1);
50
define('LDAP_USER_ACCT_CREATION_LDAP_BEHAVIOR_DEFAULT', 4);
51

    
52
// Provision directions.
53
define('LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER', 1);
54
define('LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY', 2);
55
define('LDAP_USER_PROV_DIRECTION_NONE', 3);
56
define('LDAP_USER_PROV_DIRECTION_ALL', 4);
57

    
58
define('LDAP_USER_PROV_RESULT_NO_ERROR', 0);
59
define('LDAP_USER_PROV_RESULT_NO_PWD', 1);
60
define('LDAP_USER_PROV_RESULT_BAD_PARAMS', 2);
61

    
62
// Need to avoid conflicting with server ids.
63
define('LDAP_USER_NO_SERVER_SID', 0);
64
define('LDAP_USER_TEST_FORM_PATH', 'admin/config/people/ldap/user/test');
65
define('LDAP_USER_WS_USER_PATH', 'ldap/user/ws');
66

    
67
// Machine name for the setting to provision from last authentication server.
68
define('LDAP_USER_AUTH_SERVER_SID', 'ldap_last_authserv');
69
define('LDAP_USER_SESSION_PROV_SID', 'ldap_user_session_prov_sid');
70

    
71
/**
72
 * Implements hook_menu().
73
 */
74
function ldap_user_menu() {
75
  $items = [];
76

    
77
  $items['admin/config/people/ldap/user'] = [
78
    'title' => '3. User',
79
    'description' => 'Settings related to user provisioning and data synching between ldap and drupal users.',
80
    'page callback' => 'drupal_get_form',
81
    'page arguments' => ['ldap_user_admin_form'],
82
    'access arguments' => ['administer site configuration'],
83
    'type' => MENU_LOCAL_TASK,
84
    'weight' => 2,
85
    'file' => 'ldap_user.admin.inc',
86
  ];
87

    
88
  $items[LDAP_USER_TEST_FORM_PATH] = [
89
    'title' => 'Test LDAP User Functionality for a given user.',
90
    'description' => '',
91
    'page callback' => 'drupal_get_form',
92
    'page arguments' => ['ldap_user_test_form'],
93
    'access arguments' => ['administer site configuration'],
94
    'file' => 'ldap_user.test_form.inc',
95
    'type' => MENU_LOCAL_ACTION,
96
  ];
97
  return $items;
98
}
99

    
100
/**
101
 * Implements hook_init().
102
 */
103
function ldap_user_init() {
104
  // Reset for simpletest page load behavior.
105
  ldap_user_ldap_provision_semaphore(NULL, NULL, NULL, TRUE);
106
}
107

    
108
/**
109
 * Implements hook_theme().
110
 */
111
function ldap_user_theme() {
112
  return [
113
    'ldap_user_conf_form' => [
114
      'render element' => 'form',
115
      'file' => 'ldap_user.theme.inc',
116
    ],
117
  ];
118
}
119

    
120
/**
121
 * Implements hook_cron().
122
 */
123
function ldap_user_cron() {
124
  $ldap_user_conf = ldap_user_conf();
125
  if ($ldap_user_conf->orphanedDrupalAcctBehavior != 'ldap_user_orphan_do_not_check') {
126
    module_load_include('inc', 'ldap_user', 'ldap_user.cron');
127
    $result = _ldap_user_orphans($ldap_user_conf);
128
    if ($result !== TRUE) {
129
      watchdog('ldap_user', 'LDAP User check for orphaned ldap provisioned Drupal accounts failed', [], WATCHDOG_ERROR);
130
    }
131
  }
132
}
133

    
134
/**
135
 * Implements hook_mail().
136
 */
137
function ldap_user_mail($key, &$message, $params) {
138
  switch ($key) {
139
    case 'orphaned_accounts':
140
      $message['subject'] = variable_get('site_name') . ' ' . t('Orphaned LDAP Users');
141
      $message['body'][] = t('The following !count Drupal users no longer have
142
        corresponding LDAP Entries.  Perhaps they have been removed from the LDAP
143
        and should be removed:', ['!count' => count($params['accounts'])])
144
        . "\n\n" . t('username,mail,edit url') . "\n" .
145
        join("\n", $params['accounts']);
146
      break;
147
  }
148
}
149

    
150
/**
151
 * Implements hook_ldap_derived_user_name_alter().
152
 */
153
function ldap_user_ldap_derived_user_name_alter(&$name, $ldap_user) {
154
  // Alter $name in some way here.
155
}
156

    
157
/**
158
 *
159
 */
160
function ldap_user_conf_cache_clear() {
161
  $discard = ldap_user_conf('admin', TRUE);
162
  $discard = ldap_user_conf(NULL, TRUE);
163
  ldap_user_ldap_provision_semaphore(NULL, NULL, NULL, TRUE);
164
}
165

    
166
/**
167
 * Get ldapUserConf or ldapUserConfAdmin object.
168
 *
169
 * @param enum $type
170
 *   is 'admin' for ldapUserConfAdmin object or NULL for ldapUserConf object.
171
 * @param bool $resect
172
 *   clear static cache of object.
173
 *
174
 * @return \LdapUserConf|\LdapUserConfAdmin
175
 */
176
function ldap_user_conf($type = NULL, $reset = FALSE) {
177
  static $ldap_user_conf;
178
  static $ldap_user_conf_admin;
179

    
180
  if ($type == 'admin' && ($reset || !is_object($ldap_user_conf_admin))) {
181
    ldap_servers_module_load_include('php', 'ldap_user', 'LdapUserConfAdmin.class');
182
    $ldap_user_conf_admin = new LdapUserConfAdmin();
183
  }
184
  elseif ($type != 'admin' && ($reset || !is_object($ldap_user_conf))) {
185
    ldap_servers_module_load_include('php', 'ldap_user', 'LdapUserConf.class');
186
    $ldap_user_conf = new LdapUserConf();
187
  }
188

    
189
  return ($type == 'admin') ? $ldap_user_conf_admin : $ldap_user_conf;
190
}
191

    
192
/**
193
 * Implements hook_ldap_attributes_needed_alter().
194
 */
195
function ldap_user_ldap_attributes_needed_alter(&$attributes, $params) {
196

    
197
  // Puid attributes are server specific.
198
  if (isset($params['sid']) && $params['sid']) {
199
    if (is_scalar($params['sid'])) {
200
      $ldap_server = ldap_servers_get_servers($params['sid'], 'enabled', TRUE);
201
    }
202
    else {
203
      $ldap_server = $params['sid'];
204
    }
205

    
206
    // Failed to find enabled server.
207
    if ($ldap_server === FALSE) {
208
      return;
209
    }
210

    
211
    $ldap_user_conf = ldap_user_conf();
212
    if (!isset($attributes['dn'])) {
213
      $attributes['dn'] = [];
214
    }
215
    // Force dn "attribute" to exist.
216
    $attributes['dn'] = ldap_servers_set_attribute_map($attributes['dn']);
217
    // Add the attributes required by the user configuration when provisioning drupal users.
218
    switch ($params['ldap_context']) {
219
      case 'ldap_user_insert_drupal_user':
220
      case 'ldap_user_update_drupal_user':
221
      case 'ldap_user_ldap_associate':
222
      case 'all':
223
        $attributes[$ldap_server->user_attr] = ldap_servers_set_attribute_map(@$attributes[$ldap_server->user_attr]);
224
        $attributes[$ldap_server->mail_attr] = ldap_servers_set_attribute_map(@$attributes[$ldap_server->mail_attr]);
225
        if ($ldap_server->picture_attr) {
226
          $attributes[$ldap_server->picture_attr] = ldap_servers_set_attribute_map(@$attributes[$ldap_server->picture_attr]);
227
        }
228
        if ($ldap_server->unique_persistent_attr) {
229
          $attributes[$ldap_server->unique_persistent_attr] = ldap_servers_set_attribute_map(@$attributes[$ldap_server->unique_persistent_attr]);
230
        }
231
        if ($ldap_server->mail_template) {
232
          ldap_servers_token_extract_attributes($attributes, $ldap_server->mail_template);
233
        }
234
        break;
235
    }
236

    
237
    $ldap_context = empty($params['ldap_context']) ? NULL : $params['ldap_context'];
238
    $direction = empty($params['direction']) ? $ldap_user_conf->ldapContextToProvDirection($ldap_context) : $params['direction'];
239
    $attributes_required_by_user_module_mappings = $ldap_user_conf->getLdapUserRequiredAttributes($direction, $ldap_context);
240
    $attributes = array_merge($attributes_required_by_user_module_mappings, $attributes);
241

    
242
  }
243
}
244

    
245
/**
246
 * Implements hook_ldap_user_attrs_list_alter().
247
 */
248
function ldap_user_ldap_user_attrs_list_alter(&$available_user_attrs, &$params) {
249

    
250
  $sid = (isset($params['ldap_server']) && is_object($params['ldap_server'])) ? $params['ldap_server']->sid : LDAP_USER_NO_SERVER_SID;
251

    
252
  $ldap_user_conf = $params['ldap_user_conf'];
253
  $direction = isset($params['direction']) ? $params['direction'] : LDAP_USER_PROV_DIRECTION_NONE;
254

    
255
  if ($direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
256
    $available_user_attrs['[property.name]'] = [
257
      'name' => 'Property: Username',
258
      'source' => '',
259
      'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY,
260
      'enabled' => TRUE,
261
      'prov_events' => [LDAP_USER_EVENT_CREATE_LDAP_ENTRY, LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY],
262
      'config_module' => 'ldap_user',
263
      'prov_module' => 'ldap_user',
264
      'configurable_to_ldap' => TRUE,
265
    ];
266

    
267
    $available_user_attrs['[property.mail]'] = [
268
      'name' => 'Property: Email',
269
      'source' => '',
270
      'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY,
271
      'enabled' => TRUE,
272
      'prov_events' => [LDAP_USER_EVENT_CREATE_LDAP_ENTRY, LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY],
273
      'config_module' => 'ldap_user',
274
      'prov_module' => 'ldap_user',
275
      'configurable_to_ldap' => TRUE,
276
    ];
277

    
278
    $available_user_attrs['[property.picture]'] = [
279
      'name' => 'Property: picture',
280
      'source' => '',
281
      'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY,
282
      'enabled' => TRUE,
283
      'prov_events' => [LDAP_USER_EVENT_CREATE_LDAP_ENTRY, LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY],
284
      'config_module' => 'ldap_user',
285
      'prov_module' => 'ldap_user',
286
      'configurable_to_ldap' => TRUE,
287
    ];
288

    
289
    $available_user_attrs['[property.uid]'] = [
290
      'name' => 'Property: Drupal User Id (uid)',
291
      'source' => '',
292
      'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY,
293
      'enabled' => TRUE,
294
      'prov_events' => [LDAP_USER_EVENT_CREATE_LDAP_ENTRY, LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY],
295
      'config_module' => 'ldap_user',
296
      'prov_module' => 'ldap_user',
297
      'configurable_to_ldap' => TRUE,
298
    ];
299

    
300
  }
301

    
302
  // 1. Drupal user properties
303
  // 1.a make sure empty array are present so array + function works.
304
  foreach (['property.status', 'property.timezone', 'property.signature'] as $i => $property_id) {
305
    $property_token = '[' . $property_id . ']';
306
    if (!isset($available_user_attrs[$property_token]) || !is_array($available_user_attrs[$property_token])) {
307
      $available_user_attrs[$property_token] = [];
308
    }
309
  }
310
  // @todo make these merges so they don't override saved values such as 'enabled'
311
  $available_user_attrs['[property.status]'] = $available_user_attrs['[property.status]'] + [
312
    'name' => 'Property: Acount Status',
313
    'configurable_to_drupal' => 1,
314
    'configurable_to_ldap' => 1,
315
    'user_tokens' => '1=enabled, 0=blocked.',
316
    'enabled' => FALSE,
317
    'config_module' => 'ldap_user',
318
    'prov_module' => 'ldap_user',
319
  ];
320

    
321
  $available_user_attrs['[property.timezone]'] = $available_user_attrs['[property.timezone]'] + [
322
    'name' => 'Property: User Timezone',
323
    'configurable_to_drupal' => 1,
324
    'configurable_to_ldap' => 1,
325
    'enabled' => FALSE,
326
    'config_module' => 'ldap_user',
327
    'prov_module' => 'ldap_user',
328
  ];
329

    
330
  $available_user_attrs['[property.signature]'] = $available_user_attrs['[property.signature]'] + [
331
    'name' => 'Property: User Signature',
332
    'configurable_to_drupal' => 1,
333
    'configurable_to_ldap' => 1,
334
    'enabled' => FALSE,
335
    'config_module' => 'ldap_user',
336
    'prov_module' => 'ldap_user',
337
  ];
338

    
339
  // 2. Drupal user fields.
340
  $user_fields = field_info_instances('user', 'user');
341
  foreach ($user_fields as $field_name => $field_instance) {
342
    $field_id = "[field.$field_name]";
343
    if (!isset($available_user_attrs[$field_id]) || !is_array($available_user_attrs[$field_id])) {
344
      $available_user_attrs[$field_id] = [];
345
    }
346

    
347
    $available_user_attrs[$field_id] = $available_user_attrs[$field_id] + [
348
      'name' => t('Field') . ': ' . $field_instance['label'],
349
      'configurable_to_drupal' => 1,
350
      'configurable_to_ldap' => 1,
351
      'enabled' => FALSE,
352
      'config_module' => 'ldap_user',
353
      'prov_module' => 'ldap_user',
354
    ];
355
  }
356

    
357
  if (!$ldap_user_conf->provisionsDrupalAccountsFromLdap) {
358
    $available_user_attrs['[property.mail]']['config_module'] = 'ldap_user';
359
    $available_user_attrs['[property.name]']['config_module'] = 'ldap_user';
360
    $available_user_attrs['[property.picture]']['config_module'] = 'ldap_user';
361
  }
362

    
363
  if ($direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
364
    $available_user_attrs['[password.random]'] = [
365
      'name' => 'Pwd: Random',
366
      'source' => '',
367
      'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY,
368
      'enabled' => TRUE,
369
      'prov_events' => [LDAP_USER_EVENT_CREATE_LDAP_ENTRY, LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY],
370
      'config_module' => 'ldap_user',
371
      'prov_module' => 'ldap_user',
372
      'configurable_to_ldap' => TRUE,
373
    ];
374

    
375
    // Use user password when available fall back to random pwd.
376
    $available_user_attrs['[password.user-random]'] = [
377
      'name' => 'Pwd: User or Random',
378
      'source' => '',
379
      'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY,
380
      'enabled' => TRUE,
381
      'prov_events' => [LDAP_USER_EVENT_CREATE_LDAP_ENTRY, LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY],
382
      'config_module' => 'ldap_user',
383
      'prov_module' => 'ldap_user',
384
      'configurable_to_ldap' => TRUE,
385
    ];
386

    
387
    // Use user password, do not modify if unavailable.
388
    $available_user_attrs['[password.user-only]'] = [
389
      'name' => 'Pwd: User Only',
390
      'source' => '',
391
      'direction' => LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY,
392
      'enabled' => TRUE,
393
      'prov_events' => [LDAP_USER_EVENT_CREATE_LDAP_ENTRY, LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY],
394
      'config_module' => 'ldap_user',
395
      'prov_module' => 'ldap_user',
396
      'configurable_to_ldap' => TRUE,
397
    ];
398

    
399
  }
400

    
401
  // This is where need to be added to arrays.
402
  if (!empty($ldap_user_conf->ldapUserSynchMappings[$direction])) {
403

    
404
    foreach ($ldap_user_conf->ldapUserSynchMappings[$direction] as $target_token => $mapping) {
405
      if ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER && isset($mapping['user_attr'])) {
406
        $key = $mapping['user_attr'];
407
      }
408
      elseif ($direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY && isset($mapping['ldap_attr'])) {
409
        $key = $mapping['ldap_attr'];
410
      }
411
      else {
412
        continue;
413
      }
414

    
415
      foreach (['ldap_attr', 'user_attr', 'convert', 'direction', 'enabled', 'prov_events'] as $k) {
416
        if (isset($mapping[$k])) {
417
          $available_user_attrs[$key][$k] = $mapping[$k];
418
        }
419
        else {
420
          $available_user_attrs[$key][$k] = NULL;
421
        }
422
        $available_user_attrs[$key]['config_module'] = 'ldap_user';
423
        $available_user_attrs[$key]['prov_module'] = 'ldap_user';
424
      }
425
      if ($mapping['user_attr'] == 'user_tokens') {
426
        $available_user_attrs['user_attr'] = $mapping['user_tokens'];
427
      }
428

    
429
    }
430

    
431
  }
432

    
433
  // 3. profile2 fields
434
  // 4. $user->data array.   will need to be added manually.  perhaps better not to implement this at all?
435
}
436

    
437
/**
438
 * Implements hook_help().
439
 */
440
function ldap_user_help($path, $arg) {
441

    
442
  $ldap_user_help = t('LDAP user configuration determines how and when
443
    Drupal accounts are created based on LDAP data and which user fields
444
    are derived and synched to and from LDAP. See !helplink.',
445
    [
446
      '!helplink' => l(LDAP_USER_DRUPAL_HELP_URL, LDAP_USER_DRUPAL_HELP_URL),
447
    ]);
448

    
449
  switch ($path) {
450
    case 'admin/config/people/ldap/user':
451
      $output = '<p>' . $ldap_user_help . '</p>';
452
      return $output;
453

    
454
    case 'admin/help#ldap_user':
455
      $output = '<p>' . $ldap_user_help . '</p>';
456
      return $output;
457
  }
458
}
459

    
460
/**
461
 * Implements hook_form_FORM_ID_alter(). for user_login_block.
462
 */
463
function ldap_user_form_user_login_block_alter(&$form, &$form_state) {
464
  array_unshift($form['#validate'], 'ldap_user_grab_password_validate');
465
}
466

    
467
/**
468
 * Implements hook_form_FORM_ID_alter(). for user_login_form.
469
 */
470
function ldap_user_form_user_login_alter(&$form, $form_state) {
471
  array_unshift($form['#validate'], 'ldap_user_grab_password_validate');
472
}
473

    
474
/**
475
 * Implements hook_form_FORM_ID_alter(). for user_register_form.
476
 */
477
function ldap_user_form_user_profile_form_alter(&$form, $form_state) {
478
  array_unshift($form['#submit'], 'ldap_user_grab_password_validate');
479
}
480

    
481
/**
482
 * Implements hook_form_FORM_ID_alter(). for password_policy_password_tab.
483
 */
484
function ldap_user_form_password_policy_password_tab_alter(&$form, &$form_state) {
485
  array_unshift($form['#validate'], 'ldap_user_grab_password_validate');
486
}
487

    
488
/**
489
 * Implements hook_form_FORM_ID_alter(). for user-pass-reset form. Useful for
490
 * sites where this is the form ID for a user to intially set their password
491
 * (user clicks an emailed registration link, is prompted to set their password).
492
 */
493
function ldap_user_form_user_pass_reset_alter(&$form, &$form_state) {
494
  array_unshift($form['#validate'], 'ldap_user_grab_password_validate');
495
}
496

    
497
/**
498
 * Store password from logon forms in ldap_user_ldap_provision_pwd static variable
499
 * for use in provisioning to ldap.
500
 */
501
function ldap_user_grab_password_validate($form, &$form_state) {
502

    
503
  // This is not a login form but profile form and user is inserting password to update email.
504
  if (!empty($form_state['values']['current_pass_required_values'])) {
505
    if (!empty($form_state['values']['current_pass']) && empty($form_state['values']['pass'])) {
506
      ldap_user_ldap_provision_pwd('set', $form_state['values']['current_pass']);
507
    }
508
    // Or this is a profile form where the user is updating their own password.
509
    elseif (!empty($form_state['values']['pass'])) {
510
      ldap_user_ldap_provision_pwd('set', $form_state['values']['pass']);
511
    }
512
  }
513
  // Otherwise a logon form.
514
  elseif (!empty($form_state['values']['pass'])) {
515
    ldap_user_ldap_provision_pwd('set', $form_state['values']['pass']);
516
  }
517

    
518
}
519

    
520
/**
521
 * Implements hook_form_FORM_ID_alter(). for user_register_form.
522
 */
523
function ldap_user_form_user_register_form_alter(&$form, $form_state) {
524

    
525
  array_unshift($form['#submit'], 'ldap_user_grab_password_validate');
526

    
527
  if (!user_access('administer users')) {
528
    return;
529
  }
530
  $ldap_user_conf = ldap_user_conf();
531
  if ($ldap_user_conf->disableAdminPasswordField == TRUE) {
532
    $form['account']['pass']['#type'] = 'value';
533
    $form['account']['pass']['#value'] = user_password(20);
534
    $form['account']['pass_disabled']['#type'] = 'fieldset';
535
    $form['account']['pass_disabled']['#title'] = t('Password');
536
    $form['account']['pass_disabled'][]['#markup'] = t('An LDAP setting at /admin/config/people/ldap/user has disabled the password fields. Drupal will store a 20 character random password in the Drupal "users" table, and the user will login with their LDAP password.');
537
  }
538

    
539
  $ldap_fieldset = [];
540
  $options = [
541
    LDAP_USER_MANUAL_ACCT_CONFLICT_LDAP_ASSOCIATE => t('Make this an LDAP Associated account.  If a related LDAP account can not be found, a validation error will appear and the account will not be created.'),
542
    LDAP_USER_MANUAL_ACCT_CONFLICT_NO_LDAP_ASSOCIATE => t('Do not make this an LDAP Associated account.'),
543
  ];
544
  $ldap_fieldset['ldap_user_association'] = [
545
    '#type' => 'radios',
546
    '#options' => $options,
547
    '#required' => FALSE,
548
    '#title' => t('LDAP Entry Association.'),
549
  ];
550

    
551
  if ($ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY, LDAP_USER_DRUPAL_USER_PROV_ON_USER_UPDATE_CREATE)) {
552
    $ldap_fieldset['ldap_user_association']['#disabled'] = TRUE;
553
    $ldap_fieldset['ldap_user_association']['#description'] = t('Since "Create
554
      or Synch to Drupal user anytime a Drupal user account is created or updated"
555
      is selected at admin/config/people/ldap/user, this option will have no
556
      effect so its disabled.');
557
  }
558
  elseif ($ldap_user_conf->manualAccountConflict != LDAP_USER_MANUAL_ACCT_CONFLICT_SHOW_OPTION_ON_FORM) {
559
    $ldap_fieldset['ldap_user_association']['#disabled'] = TRUE;
560
    $ldap_fieldset['ldap_user_association']['#description'] = t('To enable
561
      this an LDAP server must be selected for provisioning to Drupal in
562
      admin/config/people/ldap/user and "Show option on user create form..." must be selected.');
563
  }
564

    
565
  $ldap_fieldset['ldap_user_create_ldap_acct'] = [
566
    '#type' => 'checkbox',
567
    '#title' => t('Create corresponding LDAP entry.'),
568
  ];
569
  if (!$ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY, LDAP_USER_DRUPAL_USER_PROV_ON_ALLOW_MANUAL_CREATE)) {
570
    $ldap_fieldset['ldap_user_create_ldap_acct']['#disabled'] = TRUE;
571
    $ldap_fieldset['ldap_user_create_ldap_acct']['#description'] = t('To enable
572
      this an LDAP server must be selected for provisioning to Drupal in
573
      admin/config/people/ldap/user and manual creation of LDAP accounts
574
      must be enabled also.');
575
  }
576

    
577
  if (count($ldap_fieldset) > 0) {
578
    $form['ldap_user_fields'] = $ldap_fieldset;
579
    $form['ldap_user_fields']['#type'] = 'fieldset';
580
    $form['ldap_user_fields']['#title'] = t('LDAP Options');
581
    $form['ldap_user_fields']['#collapsible'] = TRUE;
582
    $form['ldap_user_fields']['#collapsed'] = FALSE;
583
  }
584

    
585
  $form['#validate'][] = 'ldap_user_form_register_form_validate';
586
  $form['#submit'][] = 'ldap_user_form_register_form_submit2';
587

    
588
}
589

    
590
/**
591
 *
592
 */
593
function ldap_user_form_register_form_validate($form, &$form_state) {
594

    
595
  $values = $form_state['values'];
596
  $user_ldap_entry = NULL;
597
  $drupal_username = $form_state['values']['name'];
598

    
599
  if ($values['ldap_user_association'] == LDAP_USER_MANUAL_ACCT_CONFLICT_NO_LDAP_ASSOCIATE) {
600
    $form_state['values']['ldap_user_ldap_exclude'][LANGUAGE_NONE][0]['value'] = 1;
601
  }
602

    
603
  // If corresponding ldap account doesn't exist and provision not selected and make ldap associated is selected, throw error.
604
  if (!@$values['ldap_user_create_ldap_acct'] && @$values['ldap_user_association'] == LDAP_USER_MANUAL_ACCT_CONFLICT_LDAP_ASSOCIATE) {
605
    $ldap_user_conf = ldap_user_conf();
606
    $ldap_user = ldap_servers_get_user_ldap_data($drupal_username, $ldap_user_conf->ldapEntryProvisionServer, 'ldap_user_prov_to_drupal');
607
    if (!$ldap_user) {
608

    
609
      form_set_error('ldap_user_association', t('User %name does not have a corresponding LDAP Entry (dn).
610
        Under LDAP options, you may NOT select "Make this an LDAP Associated Account"', ['%name' => $drupal_username]));
611
    }
612
  }
613

    
614
  // If trying to provision and ldap account and one already exists, throw error.
615
  if (@$values['ldap_user_create_ldap_acct']) {
616
    $ldap_user_conf = ldap_user_conf();
617
    $ldap_user = ldap_servers_get_user_ldap_data($drupal_username, $ldap_user_conf->ldapEntryProvisionServer, 'ldap_user_prov_to_ldap');
618
    if ($ldap_user) {
619
      $tokens = ['%dn' => $ldap_user['dn'], '%name' => $drupal_username];
620
      form_set_error('ldap_user_create_ldap_acct', t('User %name already has a corresponding LDAP Entry (%dn).
621
        Uncheck "Create corresponding LDAP entry" to allow this Drupal user to be created.  Select
622
        "Make this an LDAP associated account" to associate this account with the ldap entry.', $tokens));
623
    }
624
  }
625
}
626

    
627
/**
628
 * Called after user_register_form_submit .**/
629
function ldap_user_form_register_form_submit2($form, &$form_state) {
630

    
631
  $values = $form_state['values'];
632
  $ldap_user_association_set = FALSE;
633

    
634
  if (@$values['ldap_user_create_ldap_acct']) {
635
    if ($account = user_load_by_name($values['name'])) {
636
      $ldap_user_conf = ldap_user_conf();
637
      $ldap_provision_entry = $ldap_user_conf->getProvisionRelatedLdapEntry($account);
638
      if (!$ldap_provision_entry) {
639
        $provision_result = $ldap_user_conf->provisionLdapEntry($account);
640
      }
641
      else {
642
        $ldap_user_association_set = TRUE;
643
      }
644
    }
645
    else {
646
      // don't do anything here.  If account is not created, other user module warnings will exist.
647
    }
648
  }
649

    
650
  if ($ldap_user_association_set || @$values['ldap_user_association'] == LDAP_USER_MANUAL_ACCT_CONFLICT_LDAP_ASSOCIATE) {
651
    $ldap_user_conf = ldap_user_conf();
652
    $ldap_user_conf->ldapAssociateDrupalAccount($form_state['values']['name']);
653
  }
654

    
655
}
656

    
657
/**
658
 * @param object $account
659
 *   as drupal user object.
660
 * @param array $edit
661
 *   is a drupal user edit array.
662
 * @param enum int $direction
663
 *   indicating which directions to test for association.
664
 *
665
 *
666
 * @return boolean TRUE if user should be excluded from ldap provision/synching
667
 */
668
function ldap_user_ldap_exclude($account = NULL, $edit = NULL, $direction = LDAP_USER_PROV_DIRECTION_ALL) {
669
  // Always exclude user 1.
670
  if (is_object($account) && isset($account->uid) && $account->uid == 1) {
671
    return TRUE;
672
  }
673

    
674
  // Exclude users who have the field ldap_user_ldap_exclude set to 1.
675
  if (is_object($account) && isset($account->ldap_user_ldap_exclude[LANGUAGE_NONE][0]['value'])
676
    && $account->ldap_user_ldap_exclude[LANGUAGE_NONE][0]['value'] == 1) {
677
    return TRUE;
678
  }
679

    
680
  // Exclude new users who have the value set to 1 in their $edit array.
681
  if (is_array($edit) && isset($edit['ldap_user_ldap_exclude'][LANGUAGE_NONE][0]['value'])
682
    && $edit['ldap_user_ldap_exclude'][LANGUAGE_NONE][0]['value'] == 1) {
683
    return TRUE;
684
  }
685

    
686
  // Everyone else is fine.
687
  return FALSE;
688

    
689
}
690

    
691
/**
692
 * @param object $account
693
 *   as drupal user object.
694
 * @param enum int $direction
695
 *   indicating which directions to test for association
696
 *   LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER signifies test if drupal account has been provisioned or synched from ldap
697
 *   LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY signifies test if ldap account has been provisioned or synched from drupal
698
 *   NULL signifies check for either direction.
699
 *
700
 * @return boolean if user is ldap associated
701
 */
702
function ldap_user_is_ldap_associated($account, $direction = NULL) {
703

    
704
  $to_drupal_user = FALSE;
705
  $to_ldap_entry = FALSE;
706

    
707
  if ($direction === NULL || $direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) {
708

    
709
    if (property_exists($account, 'ldap_user_current_dn') && !empty($account->ldap_user_current_dn[LANGUAGE_NONE][0]['value'])) {
710
      $to_drupal_user = TRUE;
711
    }
712
    elseif (isset($account->uid)) {
713
      $authname = ldap_user_get_authname($account);
714
      $to_drupal_user = (boolean) $authname;
715
    }
716
  }
717

    
718
  if ($direction === NULL || $direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
719
    if (property_exists($account, 'ldap_user_prov_entries') && !empty($account->ldap_user_prov_entries[LANGUAGE_NONE][0]['value'])) {
720
      $to_ldap_entry = TRUE;
721
    }
722
  }
723

    
724
  if ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) {
725
    return $to_drupal_user;
726
  }
727
  elseif ($direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
728
    return $to_ldap_entry;
729
  }
730
  else {
731
    return ($to_ldap_entry || $to_drupal_user);
732
  }
733

    
734
}
735

    
736
/**
737
 * Api function for synching
738
 * note: does no checking if synching is enabled or configured for a given context.
739
 */
740
function ldap_user_synch_to_drupal($username, $prov_event = LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER, $ldap_user = NULL) {
741

    
742
  $ldap_user_conf = ldap_user_conf();
743
  $account = user_load_by_name($username);
744
  $user_edit = [];
745
  $ldap_user_conf->synchToDrupalAccount($account, $user_edit, $prov_event, $ldap_user, TRUE);
746

    
747
}
748

    
749
/**
750
 * Api function for ldap associated user provisioning
751
 * note: does no checking if synching is enabled or configured for a given context.
752
 */
753
function ldap_user_provision_to_drupal($ldap_user, $user_edit = []) {
754

    
755
  $sid = $ldap_user['sid'];
756
  $ldap_user_conf = ldap_user_conf();
757
  $account = NULL;
758
  $ldap_user_conf->provisionDrupalAccount($account, $user_edit, $ldap_user, TRUE);
759

    
760
}
761

    
762
/**
763
 * Function to:
764
 *   -- store user entered password during pageload
765
 *   and protect unencrypted user password from other modules.
766
 *
767
 * @param enum string $action
768
 *   'get' | 'set'.
769
 * @param string | FALSE $value
770
 *   as user entered password.
771
 */
772
function ldap_user_ldap_provision_pwd($action, $value = NULL, $reset = FALSE) {
773

    
774
  static $current_user_pass;
775

    
776
  if ($reset) {
777
    $current_user_pass = NULL;
778
  }
779

    
780
  if ($action == 'set') {
781
    $current_user_pass = $value;
782
  }
783
  elseif ($action == 'get' && $current_user_pass) {
784
    return $current_user_pass;
785
  }
786
  else {
787
    return FALSE;
788
  }
789

    
790
}
791

    
792
/**
793
 * Function to avoid multiple synch or provision in same page load (if desired)
794
 *
795
 * @param enum string $action
796
 *   'synch' | 'provision' | 'set_page_load_key' | NULL.
797
 * @param enum string $op
798
 *   = 'set' or 'get'.
799
 *
800
 * @value mixed value associate with $op.
801
 *
802
 * @return bool|void
803
 */
804
function ldap_user_ldap_provision_semaphore($action, $op, $value = NULL, $reset = FALSE) {
805

    
806
  $calling_function = FALSE;
807
  // {.
808
  if (function_exists('debug_backtrace') && $backtrace = debug_backtrace()) {
809
    $calling_function = $backtrace[1]['function'];
810
  }
811

    
812
  static $ldap_accts;
813
  static $intialized;
814

    
815
  if ($reset || !$intialized) {
816
    $ldap_accts = [];
817
    $intialized = TRUE;
818
  }
819

    
820
  // Mark that the given drupal user has had ldap entry synched or provisioned on this page load.
821
  if ($op == 'set') {
822
    if ($action && $value) {
823
      $ldap_accts[$action][$value] = TRUE;
824
    }
825
    return;
826
  }
827

    
828
  // Has the given drupal user x action (synch or provision) been executed.
829
  if ($op == 'get') {
830
    if ($action && $value && isset($ldap_accts[$action][$value])) {
831
      return $ldap_accts[$action][$value];
832
    }
833
    else {
834
      return FALSE;
835
    }
836
  }
837

    
838
}
839

    
840
/**
841
 * Implements hook_user_login().
842
 */
843
function ldap_user_user_login(&$edit, $account) {
844

    
845
  if (ldap_user_ldap_exclude($account, $edit)) {
846
    return;
847
  }
848
  $ldap_user_conf = ldap_user_conf();
849
  $user_edit = [];
850

    
851
  ldap_user_reset_provision_server($ldap_user_conf, $account);
852

    
853
  // Provision or synch to ldap, not both.
854
  $provision_result = ['status' => 'none'];
855

    
856
  // Provision to ldap
857
  // Check for first time user.
858
  if (
859
      $ldap_user_conf->provisionsLdapEntriesFromDrupalUsers
860
      && ldap_user_ldap_provision_semaphore('provision', 'get', $account->name) === FALSE
861
      && !$ldap_user_conf->getProvisionRelatedLdapEntry($account)
862
      && $ldap_user_conf->ldapEntryProvisionServer
863
      && $ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY, LDAP_USER_LDAP_ENTRY_PROV_ON_AUTHENTICATE)
864
      ) {
865
    $provision_result = $ldap_user_conf->provisionLdapEntry($account);
866
    if ($provision_result['status'] == 'success') {
867
      ldap_user_ldap_provision_semaphore('provision', 'set', $account->name);
868
    }
869
  }
870
  // don't synch if just provisioned.
871
  if (
872
    $ldap_user_conf->provisionsLdapEntriesFromDrupalUsers
873
    && ldap_user_ldap_provision_semaphore('synch', 'get', $account->name) === FALSE
874
    && $provision_result['status'] != 'success'
875
    && $ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY, LDAP_USER_LDAP_ENTRY_PROV_ON_AUTHENTICATE)
876
    ) {
877
    $bool_result = $ldap_user_conf->synchToLdapEntry($account, $user_edit);
878
    if ($bool_result) {
879
      ldap_user_ldap_provision_semaphore('synch', 'set', $account->name);
880
    }
881
  }
882

    
883
  $prov_enabled = $ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, LDAP_USER_LDAP_ENTRY_PROV_ON_AUTHENTICATE);
884

    
885
  // Provision from LDAP if a new account was not just provisioned from LDAP.
886
  if (ldap_user_ldap_provision_semaphore('drupal_created', 'get', $account->name) === FALSE) {
887
    if ($ldap_user_conf->provisionsDrupalAccountsFromLdap && in_array(LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER, array_keys($ldap_user_conf->provisionsDrupalEvents))) {
888
      $ldap_user = ldap_servers_get_user_ldap_data($account->name, $ldap_user_conf->drupalAcctProvisionServer, 'ldap_user_prov_to_drupal');
889
      if ($ldap_user) {
890
        $ldap_server = ldap_servers_get_servers($ldap_user_conf->drupalAcctProvisionServer, NULL, TRUE);
891
        $ldap_user_conf->entryToUserEdit($ldap_user, $user_edit, $ldap_server, LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, [LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER]);
892
        // See #1973352 and #935592.
893
        if (empty($account->picture->fid)) {
894
          $account2 = user_load($account->uid);
895
          $account->picture = $account2->picture;
896
        }
897
        $account = user_save($account, $user_edit, 'ldap_user');
898
      }
899
    }
900
  }
901

    
902
}
903

    
904
/**
905
 * Implements hook_user_insert().
906
 */
907
function ldap_user_user_insert(&$user_edit, $account, $category) {
908

    
909
  global $user;
910
  $not_associated = ldap_user_ldap_exclude($account, $user_edit);
911
  // Check for first time user.
912
  $new_account_request = (boolean) ($user->uid == 0 && $account->access == 0 && $account->login == 0);
913
  $already_provisioned_to_ldap = ldap_user_ldap_provision_semaphore('provision', 'get', $account->name);
914
  $already_synched_to_ldap = ldap_user_ldap_provision_semaphore('synch', 'user_action_query', $account->name);
915
  if ($not_associated || $already_synched_to_ldap || $already_synched_to_ldap || $new_account_request) {
916
    return;
917
  }
918

    
919
  $ldap_user_conf = ldap_user_conf();
920
  /**
921
   * in hook_user_insert, account is already created, so never call provisionDrupalAccount(), just
922
   * synchToDrupalAccount(), even if action is 'provision'
923
   */
924
  $empty_user_edit = [];
925
  if ($account->status && $ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, LDAP_USER_DRUPAL_USER_PROV_ON_USER_UPDATE_CREATE)) {
926
    $ldap_user_conf->synchToDrupalAccount($account, $empty_user_edit, LDAP_USER_EVENT_CREATE_DRUPAL_USER, NULL, TRUE);
927
  }
928

    
929
  if ($ldap_user_conf->provisionsLdapEntriesFromDrupalUsers) {
930
    $prov_enabled = $ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY, LDAP_USER_LDAP_ENTRY_PROV_ON_USER_UPDATE_CREATE);
931
    if ($prov_enabled) {
932
      $ldap_provision_entry = $ldap_user_conf->getProvisionRelatedLdapEntry($account);
933
      if (!$ldap_provision_entry) {
934
        $provision_result = $ldap_user_conf->provisionLdapEntry($account);
935
        if ($provision_result['status'] == 'success') {
936
          ldap_user_ldap_provision_semaphore('provision', 'set', $account->name);
937
        }
938
      }
939
      elseif ($ldap_provision_entry) {
940
        $bool_result = $ldap_user_conf->synchToLdapEntry($account, $user_edit);
941
        if ($bool_result) {
942
          ldap_user_ldap_provision_semaphore('synch', 'set', $account->name);
943
        }
944
      }
945
    }
946
  }
947
}
948

    
949
/**
950
 * Implements hook_user_update()
951
 */
952
function ldap_user_user_update(&$user_edit, $account, $category) {
953
  if (ldap_user_ldap_exclude($account, $user_edit)) {
954
    return;
955
  }
956

    
957
  $ldap_user_conf = ldap_user_conf();
958
  // Check for provisioning to LDAP; this will normally occur on hook_user_insert or other event when drupal user is created.
959
  if ($ldap_user_conf->provisionsLdapEntriesFromDrupalUsers &&
960
      $ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY, LDAP_USER_LDAP_ENTRY_PROV_ON_USER_UPDATE_CREATE)) {
961

    
962
    $already_provisioned_to_ldap = ldap_user_ldap_provision_semaphore('provision', 'get', $account->name);
963
    $already_synched_to_ldap = ldap_user_ldap_provision_semaphore('synch', 'get', $account->name);
964
    if ($already_provisioned_to_ldap || $already_synched_to_ldap) {
965
      return;
966
    }
967

    
968
    $provision_result = ['status' => 'none'];
969
    // Always check if provisioning to ldap has already occurred this page load.
970
    $ldap_entry = $ldap_user_conf->getProvisionRelatedLdapEntry($account);
971
    // {.
972
    if (!$ldap_entry) {
973
      $provision_result = $ldap_user_conf->provisionLdapEntry($account);
974
      if ($provision_result['status'] == 'success') {
975
        ldap_user_ldap_provision_semaphore('provision', 'set', $account->name);
976
      }
977
    }
978
    // Synch if not just provisioned and enabled.
979
    if ($provision_result['status'] != 'success') {
980
      // Always check if provisioing to ldap has already occurred this page load.
981
      $provision_enabled = $ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY, LDAP_USER_LDAP_ENTRY_PROV_ON_USER_UPDATE_CREATE);
982
      $ldap_entry = $ldap_user_conf->getProvisionRelatedLdapEntry($account);
983
      if ($provision_enabled && $ldap_entry) {
984
        $bool_result = $ldap_user_conf->synchToLdapEntry($account, $user_edit);
985
        if ($bool_result) {
986
          ldap_user_ldap_provision_semaphore('synch', 'set', $account->name);
987
        }
988
      }
989
    }
990
  }
991

    
992
}
993

    
994
/**
995
 * Implements hook_user_presave()
996
 */
997
function ldap_user_user_presave(&$user_edit, $account, $category) {
998

    
999
  if (ldap_user_ldap_exclude($account, $user_edit)) {
1000
    return;
1001
  }
1002
  if (isset($account->name)) {
1003
    $drupal_username = $account->name;
1004
  }
1005
  elseif (!empty($user_edit['name'])) {
1006
    $drupal_username = $user_edit['name'];
1007
  }
1008
  else {
1009
    return;
1010
  }
1011
  $ldap_user_conf = ldap_user_conf();
1012

    
1013
  ldap_user_reset_provision_server($ldap_user_conf, $account);
1014

    
1015
  // Check for provisioning to drupal and override synched user fields/props
1016
  // Provision from LDAP if a new account was not just provisioned from LDAP.
1017
  if (ldap_user_ldap_provision_semaphore('drupal_created', 'get', $drupal_username) === FALSE) {
1018
    if ($ldap_user_conf->provisionsDrupalAccountsFromLdap && in_array(LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER, array_keys($ldap_user_conf->provisionsDrupalEvents))) {
1019
      if ($ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, LDAP_USER_DRUPAL_USER_PROV_ON_USER_UPDATE_CREATE)) {
1020
        if (ldap_user_is_ldap_associated($account, LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER)) {
1021
          $ldap_user = ldap_servers_get_user_ldap_data($drupal_username, $ldap_user_conf->drupalAcctProvisionServer, 'ldap_user_prov_to_drupal');
1022
          if ($ldap_user) {
1023
            $ldap_server = ldap_servers_get_servers($ldap_user_conf->drupalAcctProvisionServer, NULL, TRUE);
1024
            $ldap_user_conf->entryToUserEdit($ldap_user, $user_edit, $ldap_server, LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, [LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER]);
1025
          }
1026
        }
1027
      }
1028
    }
1029
  }
1030

    
1031
}
1032

    
1033
/**
1034
 * Implements hook_user_delete().
1035
 */
1036
function ldap_user_user_delete($account) {
1037
  // Drupal user account is about to be deleted.
1038
  $ldap_user_conf = ldap_user_conf();
1039
  if (
1040
      $ldap_user_conf->provisionsLdapEntriesFromDrupalUsers
1041
      && $ldap_user_conf->provisionEnabled(LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY, LDAP_USER_LDAP_ENTRY_DELETE_ON_USER_DELETE)
1042
      ) {
1043
    $boolean_result = $ldap_user_conf->deleteProvisionedLdapEntries($account);
1044
    // No need to watchdog here, because fail in deleteProvisionedLdapEntries provides watchdog entry.
1045
  }
1046
}
1047

    
1048
/**
1049
 * Implements hook_field_widget_info().
1050
 * to provide field type for LDAP fields.
1051
 */
1052
function ldap_user_field_widget_info() {
1053
  return [
1054
    'ldap_user_hidden' => [
1055
      'label' => t('Hidden Text Field'),
1056
      'field types' => ['text'],
1057
      'settings' => [],
1058
    ],
1059
  ];
1060
}
1061

    
1062
/**
1063
 * Implements hook_field_widget_settings_form().
1064
 */
1065
function ldap_user_field_widget_settings_form($field, $instance) {
1066
  return [];
1067
}
1068

    
1069
/**
1070
 * Implements hook_field_widget_form().
1071
 */
1072
function ldap_user_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
1073

    
1074
  $main_widget = [];
1075

    
1076
  switch ($instance['widget']['type']) {
1077
    case 'ldap_user_hidden':
1078
      $element['value'] = $element + [
1079
        '#type' => 'value',
1080
        '#value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL,
1081
        '#attached' => [
1082
          'css' => [
1083
            drupal_get_path('module', 'ldap_user') . '/ldap_user.css',
1084
          ],
1085
        ],
1086
      ];
1087
      break;
1088
  }
1089

    
1090
  return $element;
1091
}
1092

    
1093
/**
1094
 *
1095
 */
1096
function ldap_user_synch_triggers_key_values() {
1097

    
1098
  return [
1099
    LDAP_USER_DRUPAL_USER_PROV_ON_USER_UPDATE_CREATE => t('On synch to Drupal user create or update. Requires a server with binding method of "Service Account Bind" or "Anonymous Bind".'),
1100
    LDAP_USER_DRUPAL_USER_PROV_ON_AUTHENTICATE => t('On create or synch to Drupal user when successfully authenticated with LDAP credentials. (Requires LDAP Authentication module).'),
1101
    LDAP_USER_DRUPAL_USER_PROV_ON_ALLOW_MANUAL_CREATE => t('On manual creation of Drupal user from admin/people/create and "Create corresponding LDAP entry" is checked'),
1102
    LDAP_USER_LDAP_ENTRY_PROV_ON_USER_UPDATE_CREATE => t('On creation or synch of an LDAP entry when a Drupal account is created or updated. Only applied to accounts with a status of approved.'),
1103
    LDAP_USER_LDAP_ENTRY_PROV_ON_AUTHENTICATE => t('On creation or synch of an LDAP entry when a user authenticates.'),
1104
    LDAP_USER_LDAP_ENTRY_DELETE_ON_USER_DELETE => t('On deletion of an LDAP entry when the corresponding Drupal Account is deleted.  This only applies when the LDAP entry was provisioned by Drupal by the LDAP User module.'),
1105
  ];
1106

    
1107
}
1108

    
1109
/**
1110
 *
1111
 */
1112
function ldap_user_all_events() {
1113
  return [
1114
    LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER,
1115
    LDAP_USER_EVENT_CREATE_DRUPAL_USER,
1116
    LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY,
1117
    LDAP_USER_EVENT_CREATE_LDAP_ENTRY,
1118
    LDAP_USER_EVENT_LDAP_ASSOCIATE_DRUPAL_ACCT,
1119
  ];
1120

    
1121
}
1122

    
1123
/**
1124
 * @param array $account
1125
 * @param string $text
1126
 * @return string text with tokens replaced
1127
 */
1128
function ldap_user_token_replace($token, $account, $entity = NULL) {
1129
  $desired_tokens = ldap_servers_token_tokens_needed_for_template($token);
1130
  $tokens = ldap_user_token_tokenize_entry($account, $desired_tokens, LDAP_SERVERS_TOKEN_PRE, LDAP_SERVERS_TOKEN_POST, $entity);
1131
  $result = str_replace(array_keys($tokens), array_values($tokens), $token);
1132
  return $result;
1133
}
1134

    
1135
/**
1136
 * Turn an ldap entry into a token array suitable for the t() function.
1137
 *
1138
 * @param drupal user object $account
1139
 * @param array $token_keys
1140
 *   as list of token/value pairs to generate.
1141
 * @param string prefix token prefix such as !,%,[
1142
 * @param string suffix token suffix such as ]
1143
 *
1144
 * @return token array suitable for t() functions of with lowercase keys as exemplified below
1145
 */
1146
function ldap_user_token_tokenize_entry($account, $token_keys, $pre = LDAP_SERVERS_TOKEN_PRE, $post = LDAP_SERVERS_TOKEN_POST, $user_entity = NULL) {
1147

    
1148
  $detailed_watchdog_log = variable_get('ldap_help_watchdog_detail', 0);
1149
  $tokens = [];
1150
  if (!$user_entity) {
1151
    list($discard, $user_entity) = ldap_user_load_user_acct_and_entity($account->uid, 'uid');
1152
  }
1153

    
1154
  foreach ($token_keys as $token_key) {
1155
    // Target id is of form field.lname, property.mail, field.dept:0, etc.
1156
    list($type, $attr_ordinal) = explode('.', $token_key);
1157
    $parts = explode(':', $attr_ordinal);
1158
    $attr = $parts[0];
1159
    $ordinal = (count($parts) > 1) ? $parts[1] : 0;
1160
    $token = $pre . $token_key . $post;
1161
    switch ($type) {
1162

    
1163
      case 'field':
1164
        if (isset($user_entity->{$attr}[LANGUAGE_NONE][$ordinal]['value'])) {
1165
          $tokens[$token] = $user_entity->{$attr}[LANGUAGE_NONE][$ordinal]['value'];
1166
        }
1167
        break;
1168

    
1169
      case 'property':
1170
        if (property_exists($account, $attr)) {
1171
          $tokens[$token] = $account->{$attr};
1172
        }
1173
        break;
1174

    
1175
      // @todo: 3. tokenize profile 2
1176
    }
1177

    
1178
  }
1179

    
1180
  return $tokens;
1181
}
1182

    
1183
/**
1184
 * Load user $account and $entity, given uid or $username.
1185
 *
1186
 * @param string $user_id
1187
 *   is username or uid.
1188
 * @param enum $user_id_type
1189
 *   is 'username' or 'uid'
1190
 *
1191
 *   return array $account and $user_entity.
1192
 */
1193
function ldap_user_load_user_acct_and_entity($user_id, $user_id_type = 'username') {
1194

    
1195
  if ($user_id_type == 'username') {
1196
    $account = user_load_by_name($user_id);
1197
  }
1198
  else {
1199
    $account = user_load($user_id);
1200
  }
1201
  if ($account) {
1202
    $user_entities = entity_load('user', [$account->uid]);
1203
    $user_entity = $user_entities[$account->uid];
1204
  }
1205
  else {
1206
    $user_entity = NULL;
1207
  }
1208

    
1209
  return [$account, $user_entity];
1210

    
1211
}
1212

    
1213
/**
1214
 * Implements hook_ldap_servers_username_to_ldapname_alter
1215
 * - Set ldap name to auth name.
1216
 */
1217
function ldap_user_ldap_servers_username_to_ldapname_alter(&$ldap_username, $drupal_username, $context) {
1218
  // Alter the name only if it has not been altered already, ie php eval code.
1219
  if ($ldap_username == $drupal_username) {
1220
    $authname = ldap_user_get_authname($ldap_username);
1221
    if (!empty($authname)) {
1222
      $ldap_username = $authname;
1223
    }
1224
  }
1225
}
1226

    
1227
/**
1228
 * Returns LDAP authname from the authmap table for a variant input.
1229
 *
1230
 * @param $data
1231
 *   A variant input. Allowed variable types:
1232
 *   - object: user account object
1233
 *   - string: username
1234
 *
1235
 * @return string|null
1236
 *   Returns the LDAP authname of the passed Drupal user.
1237
 */
1238
function ldap_user_get_authname($data) {
1239
  $cache = &drupal_static(__FUNCTION__, []);
1240

    
1241
  $authname = NULL;
1242
  $uid = NULL;
1243

    
1244
  if (is_object($data)) {
1245
    // Object - set uid if object has uid and uid > 0.
1246
    if (!empty($data->uid)) {
1247
      $uid = $data->uid;
1248
    }
1249
  }
1250
  else {
1251
    // String - load account and set uid if uid > 0.
1252
    $account = user_load_by_name($data);
1253
    if (!empty($account->uid)) {
1254
      $uid = $account->uid;
1255
    }
1256
  }
1257

    
1258
  // Exit if no uid found.
1259
  if (empty($uid)) {
1260
    return NULL;
1261
  }
1262

    
1263
  // Run query if uid is not statically cached.
1264
  if (!array_key_exists($uid, $cache)) {
1265
    $authname = db_query('SELECT authname FROM {authmap} WHERE uid = :uid AND module = :module', [
1266
      ':uid' => $uid,
1267
      ':module' => 'ldap_user',
1268
    ])->fetchField();
1269

    
1270
    $cache[$uid] = !empty($authname) ? $authname : NULL;
1271
  }
1272

    
1273
  return $cache[$uid];
1274
}
1275

    
1276
/**
1277
 * Resets the drupalAcctProvisionServer if needed.
1278
 *
1279
 * Used when handling multi-domain authentication to set the provisioning
1280
 * server to be the server that last successfully authenticated the user.
1281
 *
1282
 * @param LdapUserConf $ldap_user_conf
1283
 *   The LDAP User Configuration object.
1284
 *
1285
 * @param object $account
1286
 *   The Drupal user account.
1287
 */
1288
function ldap_user_reset_provision_server($ldap_user_conf, $account) {
1289
  // Reset the Provision Server sid to the server that last authenticated the user.
1290
  if ($ldap_user_conf->drupalAcctProvisionServer == LDAP_USER_AUTH_SERVER_SID) {
1291
    $sid = FALSE;
1292
    if (isset($account->data['ldap_user']['init']['sid'])) {
1293
      $sid = $account->data['ldap_user']['init']['sid'];
1294
    }
1295
    else {
1296
      // Provisioning Server sid is not in the account object,
1297
      // see if we have a session variable with it.
1298
      $sid = isset($_SESSION[LDAP_USER_SESSION_PROV_SID]) ? $_SESSION[LDAP_USER_SESSION_PROV_SID] : FALSE;
1299
    }
1300
    if ($sid) {
1301
      $ldap_user_conf->drupalAcctProvisionServer = $sid;
1302
    }
1303
  }
1304
}