Projet

Général

Profil

Paste
Télécharger (42 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ldap / ldap_user / LdapUserConfAdmin.class.php @ 91af538d

1
<?php
2

    
3
/**
4
 * @file
5
 * This classextends by LdapUserConf for configuration and other admin functions.
6
 */
7

    
8
module_load_include('php', 'ldap_user', 'LdapUserConf.class');
9
module_load_include('inc', 'user', 'user.pages');
10
/**
11
 *
12
 */
13
class LdapUserConfAdmin extends LdapUserConf {
14

    
15
  /**
16
   * Basic settings.
17
   */
18

    
19
  protected $drupalAcctProvisionServerDescription;
20
  protected $drupalAcctProvisionServerOptions = [];
21
  protected $ldapEntryProvisionServerOptions = [];
22

    
23
  protected $drupalAccountProvisionEventsDescription;
24
  protected $drupalAccountProvisionEventsOptions = [];
25

    
26
  protected $ldapEntryProvisionTriggersDescription;
27
  protected $ldapEntryProvisionTriggersOptions = [];
28

    
29
  protected $synchFormRow = 0;
30

    
31
  /**
32
   * 3. Drupal Account Provisioning and Syncing.
33
   */
34

    
35
  public $userConflictResolveDescription;
36
  public $userConflictResolveDefault = LDAP_USER_CONFLICT_RESOLVE_DEFAULT;
37
  public $userConflictOptions;
38

    
39
  public $accountsWithSameEmailDescription;
40
  public $accountsWithSameEmailOptions;
41

    
42
  public $acctCreationDescription = '';
43
  public $acctCreationDefault = LDAP_USER_ACCT_CREATION_LDAP_BEHAVIOR_DEFAULT;
44
  public $acctCreationOptions;
45

    
46

    
47
  public $errorMsg = NULL;
48
  public $hasError = FALSE;
49
  public $errorName = NULL;
50

    
51
  /**
52
   *
53
   */
54
  public function clearError() {
55
    $this->hasError = FALSE;
56
    $this->errorMsg = NULL;
57
    $this->errorName = NULL;
58
  }
59

    
60
  /**
61
   *
62
   */
63
  public function save() {
64
    foreach ($this->saveable as $property) {
65
      $save[$property] = $this->{$property};
66
    }
67
    variable_set('ldap_user_conf', $save);
68
    ldap_user_conf_cache_clear();
69
  }
70

    
71
  /**
72
   *
73
   */
74
  public static function uninstall() {
75
    variable_del('ldap_user_conf');
76
  }
77

    
78
  /**
79
   *
80
   */
81
  public function __construct() {
82
    parent::__construct();
83
    $this->setTranslatableProperties();
84

    
85
    if ($servers = ldap_servers_get_servers(NULL, 'enabled')) {
86
      $this->drupalAcctProvisionServerOptions[LDAP_USER_AUTH_SERVER_SID] = t('Use server which performed the authentication. Useful for multi-domain environments.');
87
      foreach ($servers as $sid => $ldap_server) {
88
        $enabled = ($ldap_server->status) ? 'Enabled' : 'Disabled';
89
        $this->drupalAcctProvisionServerOptions[$sid] = $ldap_server->name . ' (' . $ldap_server->address . ') Status: ' . $enabled;
90
        $this->ldapEntryProvisionServerOptions[$sid] = $ldap_server->name . ' (' . $ldap_server->address . ') Status: ' . $enabled;
91
      }
92
    }
93
    $this->drupalAcctProvisionServerOptions['none'] = t('None');
94
    $this->ldapEntryProvisionServerOptions['none'] = t('None');
95

    
96
  }
97

    
98
  /**
99
   * Generate admin form for ldapUserConf object.
100
   *
101
   * @return array $form as drupal form api form array
102
   */
103
  public function drupalForm() {
104
    if (count($this->drupalAcctProvisionServerOptions) == 0) {
105
      $message = ldap_servers_no_enabled_servers_msg('configure LDAP User');
106
      $form['intro'] = [
107
        '#type' => 'item',
108
        '#markup' => t('<h1>LDAP User Settings</h1>') . $message,
109
      ];
110
      return $form;
111
    }
112
    $form['#storage'] = [];
113
    $form['#theme'] = 'ldap_user_conf_form';
114

    
115
    $form['intro'] = [
116
      '#type' => 'item',
117
      '#markup' => t('<h1>LDAP User Settings</h1>'),
118
    ];
119

    
120
    $form['manual_drupal_account_editing'] = [
121
      '#type' => 'fieldset',
122
      '#title' => t('Manual Drupal Account Creation and Updates'),
123
      '#collapsible' => TRUE,
124
      '#collapsed' => FALSE,
125
    ];
126

    
127
    $form['manual_drupal_account_editing']['manualAccountConflict'] = [
128
      '#type' => 'radios',
129
      '#options' => $this->manualAccountConflictOptions,
130
      '#title' => t('How to resolve LDAP conflicts with manually  created Drupal accounts.'),
131
      '#description' => t('This applies only to accounts created manually through admin/people/create
132
        for which an LDAP entry can be found on the LDAP server selected in "LDAP Servers Providing Provisioning Data"'),
133
      '#default_value' => $this->manualAccountConflict,
134
    ];
135

    
136
    $form['basic_to_drupal'] = [
137
      '#type' => 'fieldset',
138
      '#title' => t('Basic Provisioning to Drupal Account Settings'),
139
      '#collapsible' => TRUE,
140
      '#collapsed' => FALSE,
141
    ];
142

    
143
    $default_value = ($this->drupalAcctProvisionServer) ? $this->drupalAcctProvisionServer : 'none';
144
    $form['basic_to_drupal']['drupalAcctProvisionServer'] = [
145
      '#type' => 'radios',
146
      '#title' => t('LDAP Servers Providing Provisioning Data'),
147
      '#required' => 1,
148
      '#default_value' => $default_value,
149
      '#options' => $this->drupalAcctProvisionServerOptions,
150
      '#description' => $this->drupalAcctProvisionServerDescription,
151
      '#states' => [
152
        'enabled' => [
153
          ':input[name=drupalAcctProvisionTriggers]' => ['value' => LDAP_USER_DRUPAL_USER_PROV_ON_AUTHENTICATE],
154
        ],
155
      ],
156
    ];
157

    
158
    $form['basic_to_drupal']['drupalAcctProvisionTriggers'] = [
159
      '#type' => 'checkboxes',
160
      '#title' => t('Drupal Account Provisioning Events'),
161
      '#required' => FALSE,
162
      '#default_value' => $this->drupalAcctProvisionTriggers,
163
      '#options' => $this->drupalAccountProvisionEventsOptions,
164
      '#description' => $this->drupalAccountProvisionEventsDescription,
165
    ];
166

    
167
    $form['basic_to_drupal']['disableAdminPasswordField'] = [
168
      '#type' => 'checkbox',
169
      '#title' => t('Disable the password fields at /admin/create/people since the password is going to be randomly generated anyway. This is useful if you are synching data to Drupal from LDAP, and not bringing the user password from LDAP.'),
170
      '#default_value' => $this->disableAdminPasswordField,
171
    ];
172

    
173
    $form['basic_to_drupal']['userConflictResolve'] = [
174
      '#type' => 'radios',
175
      '#title' => t('Existing Drupal User Account Conflict'),
176
      '#required' => 1,
177
      '#default_value' => $this->userConflictResolve,
178
      '#options' => $this->userConflictOptions,
179
      '#description' => t($this->userConflictResolveDescription),
180
    ];
181

    
182
    $form['basic_to_drupal']['accountsWithSameEmail'] = [
183
      '#type' => 'radios',
184
      '#title' => t('Existing Account with Same Email Address'),
185
      '#default_value' => $this->accountsWithSameEmail,
186
      '#options' => $this->accountsWithSameEmailOptions,
187
      '#description' => t($this->accountsWithSameEmailDescription),
188
      '#disabled' => (module_exists('sharedemail') === FALSE),
189
    ];
190

    
191
    $form['basic_to_drupal']['acctCreation'] = [
192
      '#type' => 'radios',
193
      '#title' => t('Application of Drupal Account settings to LDAP Authenticated Users'),
194
      '#required' => 1,
195
      '#default_value' => $this->acctCreation,
196
      '#options' => $this->acctCreationOptions,
197
      '#description' => t($this->acctCreationDescription),
198
    ];
199

    
200
    $account_options = [];
201
    $account_options['ldap_user_orphan_do_not_check'] = t('Do not check for orphaned Drupal accounts.');
202
    $account_options['ldap_user_orphan_email'] = t('Perform no action, but email list of orphaned accounts. (All the other options will send email summaries also.)');
203
    foreach (user_cancel_methods() as $option_name => $option) {
204
      $account_options[$option_name] = $option['#title'];
205
    }
206

    
207
    // @todo these 2 options are removed until this feature is better tested in
208
    // actual production environments; it has potentially disastrous effects
209
    unset($account_options['user_cancel_reassign']);
210
    unset($account_options['user_cancel_delete']);
211

    
212
    $form['basic_to_drupal']['orphanedDrupalAcctBehavior'] = [
213
      '#type' => 'radios',
214
      '#title' => t('Action to perform on Drupal account that no longer have a
215
        corresponding LDAP entry'),
216
      '#required' => 0,
217
      '#default_value' => $this->orphanedDrupalAcctBehavior,
218
      '#options' => $account_options,
219
      '#description' => t($this->orphanedDrupalAcctBehaviorDescription),
220
    ];
221

    
222
    $form['basic_to_drupal']['orphanedCheckQty'] = [
223
      '#type' => 'textfield',
224
      '#size' => 10,
225
      '#title' => t('Number of users to check each cron run.'),
226
      '#description' => t(''),
227
      '#default_value' => $this->orphanedCheckQty,
228
      '#required' => FALSE,
229
    ];
230

    
231
    $form['basic_to_ldap'] = [
232
      '#type' => 'fieldset',
233
      '#title' => t('Basic Provisioning to LDAP Settings'),
234
      '#collapsible' => TRUE,
235
      '#collapsed' => !($this->ldapEntryProvisionServer),
236
    ];
237

    
238
    $default_value = ($this->ldapEntryProvisionServer) ? $this->ldapEntryProvisionServer : 'none';
239
    $form['basic_to_ldap']['ldapEntryProvisionServer'] = [
240
      '#type' => 'radios',
241
      '#title' => t('LDAP Servers to Provision LDAP Entries on'),
242
      '#required' => 1,
243
      '#default_value' => $default_value,
244
      '#options' => $this->ldapEntryProvisionServerOptions,
245
      '#description' => $this->ldapEntryProvisionServerDescription,
246
    ];
247

    
248
    $form['basic_to_ldap']['ldapEntryProvisionTriggers'] = [
249
      '#type' => 'checkboxes',
250
      '#title' => t('LDAP Entry Provisioning Events'),
251
      '#required' => FALSE,
252
      '#default_value' => $this->ldapEntryProvisionTriggers,
253
      '#options' => $this->ldapEntryProvisionTriggersOptions,
254
      '#description' => $this->ldapEntryProvisionTriggersDescription,
255
    ];
256

    
257
    $form['basic_to_drupal']['server_mapping_preamble'] = [
258
      '#type' => 'markup',
259
      '#markup' => t('
260
The relationship between a Drupal user and an LDAP entry is defined within the LDAP server configurations.
261

262

263
The mappings below are for user fields, properties, and profile2 data that are not automatically mapped elsewhere.
264
Mappings such as username or email address that are configured elsewhere are shown at the top for clarity.
265
When more than one ldap server is enabled for provisioning data (or simply more than one configuration for the same ldap server),
266
mappings need to be setup for each server.  If no tables are listed below, you have not enabled any provisioning servers at
267
the top of this form.
268
'),
269
    ];
270

    
271
    foreach ([LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER, LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY] as $direction) {
272
      $sid = $this->provisionSidFromDirection[$direction];
273
      $ldap_server = ($sid) ? ldap_servers_get_servers($sid, NULL, TRUE) : FALSE;
274
      $ldap_server_selected = (boolean) $ldap_server;
275

    
276
      if ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) {
277
        $parent_fieldset = 'basic_to_drupal';
278
        $description = t('Provisioning from LDAP to Drupal Mappings:');
279
      }
280
      elseif ($direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
281
        $parent_fieldset = 'basic_to_ldap';
282
        $description = t('Provisioning from Drupal to LDAP Mappings:');
283
      }
284

    
285
      $form[$parent_fieldset]['mappings__' . $direction] = [
286
        '#type' => 'fieldset',
287
        '#title' => $description,
288
        '#collapsible' => TRUE,
289
        '#collapsed' => FALSE,
290
        '#description' => '',
291
        'table__' . $direction => [
292
          '#type' => 'markup',
293
          '#markup' => '[replace_with_table__' . $direction . ']',
294
        ],
295
      ];
296

    
297
      $password_notes = '<h3>' . t('Password Tokens') . '</h3><ul>' .
298
      '<li>' . t('Pwd: Random -- Uses a random Drupal generated password') . '</li>' .
299
      '<li>' . t('Pwd: User or Random -- Uses password supplied on user forms.
300
  If none available uses random password.') . '</li></ul>' .
301
      '<h3>' . t('Password Concerns') . '</h3>' .
302
      '<ul>' .
303
      '<li>' . t('Provisioning passwords to LDAP means passwords must meet the LDAP\'s
304
password requirements.  Password Policy module can be used to add requirements.') . '</li>' .
305
      '<li>' . t('Some LDAPs require a user to reset their password if it has been changed
306
by someone other that user.  Consider this when provisioning LDAP passwords.') . '</li>' .
307
      '</ul></p>';
308

    
309
      $source_drupal_token_notes = <<<EOT
310
<p>Examples in form: Source Drupal User token => Target LDAP Token (notes)</p>
311
<ul>
312
<li>Source Drupal User token => Target LDAP Token</li>
313
<li>cn=[property.name],ou=test,dc=ad,dc=mycollege,dc=edu => [dn] (example of token and constants)</li>
314
<li>top => [objectclass:0] (example of constants mapped to multivalued attribute)</li>
315
<li>person => [objectclass:1] (example of constants mapped to multivalued attribute)</li>
316
<li>organizationalPerson => [objectclass:2] (example of constants mapped to multivalued attribute)</li>
317
<li>user => [objectclass:3] (example of constants mapped to multivalued attribute)</li>
318
<li>Drupal Provisioned LDAP Account => [description] (example of constant)</li>
319
<li>[field.field_lname] => [sn]</li>
320

321
</ul>
322
EOT;
323

    
324
      // Add some password notes.
325
      if ($direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
326
        $form[$parent_fieldset]['password_notes'] = [
327
          '#type' => 'fieldset',
328
          '#title' => t('Password Notes'),
329
          '#collapsible' => TRUE,
330
          '#collapsed' => TRUE,
331
          'directions' => [
332
            '#type' => 'markup',
333
            '#markup' => $password_notes,
334
          ],
335
        ];
336
        $form[$parent_fieldset]['source_drupal_token_notes'] = [
337
          '#type' => 'fieldset',
338
          '#title' => t('Source Drupal User Tokens and Corresponding Target LDAP Tokens'),
339
          '#collapsible' => TRUE,
340
          '#collapsed' => TRUE,
341
          'directions' => [
342
            '#type' => 'markup',
343
            '#markup' => $source_drupal_token_notes,
344
          ],
345
        ];
346
      }
347
      $this->addServerMappingFields($form, $direction);
348
    }
349

    
350
    foreach (['orphanedCheckQty', 'orphanedDrupalAcctBehavior', 'acctCreation', 'userConflictResolve', 'accountsWithSameEmail', 'drupalAcctProvisionTriggers', 'mappings__' . LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER] as $input_name) {
351
      $form['basic_to_drupal'][$input_name]['#states']['invisible'] =
352
        [
353
          ':input[name=drupalAcctProvisionServer]' => ['value' => 'none'],
354
        ];
355
    }
356

    
357
    foreach (['ldapEntryProvisionTriggers', 'password_notes', 'source_drupal_token_notes', 'mappings__' . LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY] as $input_name) {
358
      $form['basic_to_ldap'][$input_name]['#states']['invisible'] =
359
        [
360
          ':input[name=ldapEntryProvisionServer]' => ['value' => 'none'],
361
        ];
362
    }
363

    
364
    $form['submit'] = [
365
      '#type' => 'submit',
366
      '#value' => 'Save',
367
    ];
368

    
369
    return $form;
370
  }
371

    
372
  /**
373
   * @param $sid
374
   * @param $orphan_handling
375
   */
376
  private function checkPuidOrphans($sid, $orphan_handling) {
377
    $ldap_server = ldap_servers_get_servers($sid, NULL, TRUE);
378
    if ($ldap_server && empty($ldap_server->unique_persistent_attr)
379
      && $orphan_handling != 'ldap_user_orphan_do_not_check') {
380
      drupal_set_message(t('You\'ve configured the orphan check but are missing the required persistent user ID property.'), 'error');
381
    }
382
  }
383

    
384
  /**
385
   * Validate submitted form.
386
   *
387
   * @param array $values
388
   *   as $form_state['values'] from drupal form api.
389
   * @param array $storage
390
   *   as $form_state['storage'] from drupal form api.
391
   *
392
   * @return array in form array($errors, $warnings)to be thrown by form api
393
   */
394
  public function drupalFormValidate($values, $storage) {
395
    $this->populateFromDrupalForm($values, $storage);
396
    list($errors, $warnings) = $this->validate($values);
397

    
398
    $this->checkPuidOrphans($values['drupalAcctProvisionServer'], $values['orphanedDrupalAcctBehavior']);
399

    
400
    // Since failed mapping rows in form, don't populate ->ldapUserSynchMappings, need to validate these from values.
401
    foreach ($values as $field => $value) {
402
      $parts = explode('__', $field);
403
      // Since synch mapping fields are in n-tuples, process entire n-tuple at once (on field == configurable_to_drupal)
404
      if (count($parts) != 4 || $parts[1] !== 'sm' || $parts[2] != 'configurable_to_drupal') {
405
        continue;
406
      }
407
      list($direction, $discard, $column_name, $i) = $parts;
408
      $action = $storage['synch_mapping_fields'][$direction][$i]['action'];
409
      $tokens = [];
410
      $row_mappings = [];
411
      foreach (['remove', 'configurable_to_drupal', 'configurable_to_ldap', 'convert', 'direction', 'ldap_attr', 'user_attr', 'user_tokens'] as $column_name) {
412
        $input_name = join('__', ['sm', $column_name, $i]);
413
        $row_mappings[$column_name] = isset($values[$input_name]) ? $values[$input_name] : NULL;
414
      }
415

    
416
      $has_values = $row_mappings['ldap_attr'] || $row_mappings['user_attr'];
417
      if ($has_values) {
418
        $tokens['%ldap_attr'] = $row_mappings['ldap_attr'];
419
        $row_descriptor = t("server %sid row mapping to ldap attribute %ldap_attr", $tokens);
420
        $tokens['!row_descriptor'] = $row_descriptor;
421
        if (!$row_mappings['direction']) {
422
          $input_name = join('__', ['sm', 'direction', $i]);
423
          $errors[$input_name] = t('No mapping direction given in !row_descriptor', $tokens);
424
        }
425
        if ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER && $row_mappings['user_attr'] == 'user_tokens') {
426
          $input_name = join('__', ['sm', 'user_attr', $i]);
427
          $errors[$input_name] = t('User tokens not allowed when mapping to Drupal user.  Location: !row_descriptor', $tokens);
428
        }
429
        if (!$row_mappings['ldap_attr']) {
430
          $input_name = join('__', ['sm', 'ldap_attr', $i]);
431
          $errors[$input_name] = t('No ldap attribute given in !row_descriptor', $tokens);
432
        }
433
        if (!$row_mappings['user_attr']) {
434
          $input_name = join('__', ['sm', 'user_attr', $i]);
435
          $errors[$input_name] = t('No user attribute given in !row_descriptor', $tokens);
436
        }
437
      }
438

    
439
    }
440
    return [$errors, $warnings];
441
  }
442

    
443
  /**
444
   * Validate object, not form.
445
   *
446
   * @param array $values
447
   *   as $form_state['values'] from drupal form api.
448
   *
449
   * @return array in form array($errors, $warnings)to be thrown by form api
450
   *
451
   * @todo validate that a user field exists, such as field.field_user_lname
452
   */
453
  public function validate($values) {
454
    $errors = [];
455
    $warnings = [];
456
    $tokens = [];
457

    
458
    $has_drupal_acct_prov_servers = (boolean) ($this->drupalAcctProvisionServer);
459
    $has_drupal_acct_prov_settings_options = (count(array_filter($this->drupalAcctProvisionTriggers)) > 0);
460

    
461
    if (!$has_drupal_acct_prov_servers && $has_drupal_acct_prov_settings_options) {
462
      $warnings['drupalAcctProvisionServer'] = t('No Servers are enabled to provide provisioning to Drupal, but Drupal Account Provisioning Options are selected.', $tokens);
463
    }
464
    if ($has_drupal_acct_prov_servers && !$has_drupal_acct_prov_settings_options) {
465
      $warnings['drupalAcctProvisionTriggers'] = t('Servers are enabled to provide provisioning to Drupal, but no Drupal Account Provisioning Options are selected.  This will result in no synching happening.', $tokens);
466
    }
467

    
468
    $has_ldap_prov_servers = (boolean) ($this->ldapEntryProvisionServer);
469
    $has_ldap_prov_settings_options = (count(array_filter($this->ldapEntryProvisionTriggers)) > 0);
470
    if (!$has_ldap_prov_servers && $has_ldap_prov_settings_options) {
471
      $warnings['ldapEntryProvisionServer'] = t('No Servers are enabled to provide provisioning to ldap, but LDAP Entry Options are selected.', $tokens);
472
    }
473
    if ($has_ldap_prov_servers && !$has_ldap_prov_settings_options) {
474
      $warnings['ldapEntryProvisionTriggers'] = t('Servers are enabled to provide provisioning to ldap, but no LDAP Entry Options are selected.  This will result in no synching happening.', $tokens);
475
    }
476

    
477
    if (isset($this->ldapUserSynchMappings)) {
478
      $to_ldap_entries_mappings_exist = FALSE;
479
      foreach ($this->ldapUserSynchMappings as $synch_direction => $mappings) {
480
        $map_index = [];
481
        // Format ['%sid' => $sid].
482
        $tokens = [];
483
        $to_drupal_user_mappings_exist = FALSE;
484
        $to_ldap_entries_mappings_exist = FALSE;
485

    
486
        foreach ($mappings as $target_attr => $mapping) {
487
          if ($mapping['direction'] == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) {
488
            $attr_value = $mapping['user_attr'];
489
            $attr_name = 'user_attr';
490
          }
491
          if ($mapping['direction'] == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
492
            $attr_value = $mapping['ldap_attr'];
493
            $attr_name = 'ldap_attr';
494
          }
495
          foreach ($values as $field => $value) {
496
            $parts = explode('__', $field);
497
            if (count($parts) == 4 && $parts[2] == $attr_name && $value == $attr_value) {
498
              $map_index[$attr_value] = $parts[3];
499
            }
500
          }
501
        }
502

    
503
        foreach ($mappings as $target_attr => $mapping) {
504
          foreach ($mapping as $key => $value) {
505
            if (is_scalar($value)) {
506
              $tokens['%' . $key] = $value;
507
            }
508
          }
509
          $row_descriptor = t("server %sid row mapping to ldap attribute %ldap_attr", $tokens);
510
          $tokens['!row_descriptor'] = $row_descriptor;
511
          $ldap_attribute_maps_in_token = [];
512
          ldap_servers_token_extract_attributes($ldap_attribute_maps_in_token, $mapping['ldap_attr']);
513

    
514
          if ($mapping['direction'] == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) {
515
            $row_id = $map_index[$mapping['user_attr']];
516
            $to_drupal_user_mappings_exist = TRUE;
517
          }
518
          if ($mapping['direction'] == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
519
            $row_id = $map_index[$mapping['ldap_attr']];
520
            $to_ldap_entries_mappings_exist = TRUE;
521

    
522
            if (count(array_keys($ldap_attribute_maps_in_token)) != 1) {
523
              $token_field_id = join('__', ['sm', 'user_tokens', $row_id]);
524
              $errors[$token_field_id] = t('When provisioning to ldap, ldap attribute column must be singular token such as [cn]. %ldap_attr is not.
525
                Do not use compound tokens such as "[displayName] [sn]" or literals such as "physics". Location: !row_descriptor', $tokens);
526
            }
527

    
528
          }
529
          $ldap_attr_field_id = join('__', ['sm', 'ldap_attr', $row_id]);
530
          $user_attr_field_id = join('__', ['sm', 'user_attr', $row_id]);
531
          $first_context_field_id = join('__', ['sm', 1, $row_id]);
532
          $user_tokens_field_id = join('__', ['sm', 'user_tokens', $row_id]);
533

    
534
          if (!$mapping['ldap_attr']) {
535
            $errors[$ldap_attr_field_id] = t('No LDAP Attribute given in !row_descriptor', $tokens);
536
          }
537
          if ($mapping['user_attr'] == 'user_tokens' && !$mapping['user_tokens']) {
538
            $errors[$user_tokens_field_id] = t('User tokens selected in !row_descriptor, but user tokens column empty.', $tokens);
539
          }
540

    
541
          if (isset($mapping['prov_events']) && count($mapping['prov_events']) == 0) {
542
            $warnings[$first_context_field_id] = t('No synchronization events checked in !row_descriptor.
543
              This field will not be synchronized until some are checked.', $tokens);
544
          }
545
        }
546
      }
547
      if ($to_ldap_entries_mappings_exist && !isset($mappings['[dn]'])) {
548
        $errors['mappings__' . $synch_direction] = t('Mapping rows exist for provisioning to ldap, but no ldap attribute is targetted for [dn].
549
          One row must map to [dn].  This row will have a user token like cn=[property.name],ou=users,dc=ldap,dc=mycompany,dc=com');
550
      }
551
    }
552
    return [$errors, $warnings];
553
  }
554

    
555
  /**
556
   * Populate object with data from form values.
557
   *
558
   * @param array $values
559
   *   as $form_state['values'] from drupal form api.
560
   * @param array $storage
561
   *   as $form_state['storage'] from drupal form api.
562
   */
563
  protected function populateFromDrupalForm($values, $storage) {
564
    $this->drupalAcctProvisionServer = ($values['drupalAcctProvisionServer'] == 'none') ? 0 : $values['drupalAcctProvisionServer'];
565
    $this->ldapEntryProvisionServer = ($values['ldapEntryProvisionServer'] == 'none') ? 0 : $values['ldapEntryProvisionServer'];
566

    
567
    $this->drupalAcctProvisionTriggers = $values['drupalAcctProvisionTriggers'];
568
    $this->ldapEntryProvisionTriggers = $values['ldapEntryProvisionTriggers'];
569
    $this->orphanedDrupalAcctBehavior = $values['orphanedDrupalAcctBehavior'];
570
    $this->orphanedCheckQty = $values['orphanedCheckQty'];
571

    
572
    $this->manualAccountConflict = $values['manualAccountConflict'];
573
    $this->userConflictResolve = ($values['userConflictResolve']) ? (int) $values['userConflictResolve'] : NULL;
574
    $this->accountsWithSameEmail = ($values['accountsWithSameEmail']) ? (int) $values['accountsWithSameEmail'] : NULL;
575
    $this->acctCreation = ($values['acctCreation']) ? (int) $values['acctCreation'] : NULL;
576
    $this->disableAdminPasswordField = $values['disableAdminPasswordField'];
577

    
578
    $this->ldapUserSynchMappings = $this->synchMappingsFromForm($values, $storage);
579

    
580
  }
581

    
582
  /**
583
   * Extract synch mappings array from mapping table in admin form.
584
   *
585
   * @param array $values
586
   *   as $form_state['values'] from drupal form api.
587
   * @param array $storage
588
   *   as $form_state['storage'] from drupal form api
589
   *
590
   *   $values input names in form:
591
   *   1__sm__configurable__5,
592
   *   1__sm__remove__5,
593
   *   1__sm__ldap_attr__5,
594
   *   1__sm__convert__5,
595
   *   1__sm__direction__5,
596
   *   1__sm__user_attr__5,
597
   *   1__sm__user_tokens__5
598
   *   1__sm__1__5,
599
   *   1__sm__2__5,
600
   *   ...where
601
   *   -- first arg is direction, eg 1 or 2 LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER or LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY
602
   *   -- second arg is discarded ('sm')
603
   *   -- third part is field, e.g. user_attr
604
   *   -- fourth is the row in the configuration form, e.g. 5
605
   *
606
   *   where additiond data is in $form['#storage'][<direction>]['synch_mapping_fields'][N]
607
   *   $form['#storage']['synch_mapping_fields'][<direction>][N] = array(
608
   *   'sid' => $sid,
609
   *   'action' => 'add',
610
   *   );.
611
   */
612
  private function synchMappingsFromForm($values, $storage) {
613

    
614
    $mappings = [];
615
    foreach ($values as $field => $value) {
616

    
617
      $parts = explode('__', $field);
618
      // Since synch mapping fields are in n-tuples, process entire n-tuple at once.
619
      if (count($parts) != 4 || $parts[1] !== 'sm') {
620
        continue;
621
      }
622

    
623
      list($direction, $discard, $column_name, $i) = $parts;
624
      $action = $storage['synch_mapping_fields'][$direction][$i]['action'];
625

    
626
      $row_mappings = [];
627
      foreach (['remove', 'configurable_to_drupal', 'configurable_to_ldap', 'convert', 'ldap_attr', 'user_attr', 'user_tokens'] as $column_name) {
628
        $input_name = join('__', [$direction, 'sm', $column_name, $i]);
629
        $row_mappings[$column_name] = isset($values[$input_name]) ? $values[$input_name] : NULL;
630
      }
631

    
632
      if ($row_mappings['remove']) {
633
        continue;
634
      }
635

    
636
      $key = ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) ? $row_mappings['user_attr'] : $row_mappings['ldap_attr'];
637
      if ($row_mappings['configurable_to_drupal'] && $row_mappings['ldap_attr'] && $row_mappings['user_attr']) {
638
        $mappings[$direction][$key] = [
639
          'ldap_attr' => $row_mappings['ldap_attr'],
640
          'user_attr' => $row_mappings['user_attr'],
641
          'convert' => $row_mappings['convert'],
642
          'direction' => $direction,
643
          'user_tokens' => $row_mappings['user_tokens'],
644
          'config_module' => 'ldap_user',
645
          'prov_module' => 'ldap_user',
646
          'enabled' => 1,
647
        ];
648

    
649
        $synchEvents = ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) ? $this->provisionsDrupalEvents : $this->provisionsLdapEvents;
650
        foreach ($synchEvents as $prov_event => $discard) {
651
          $input_name = join('__', [$direction, 'sm', $prov_event, $i]);
652
          if (isset($values[$input_name]) && $values[$input_name]) {
653
            $mappings[$direction][$key]['prov_events'][] = $prov_event;
654
          }
655
        }
656
      }
657
    }
658

    
659
    return $mappings;
660
  }
661

    
662
  /**
663
   * Method to respond to successfully validated form submit.
664
   *
665
   * @param array $values
666
   *   as $form_state['values'] from drupal form api.
667
   * @param array $storage
668
   *   as $form_state['storage'] from drupal form api.
669
   *
670
   * @return by reference to $form array
671
   */
672
  public function drupalFormSubmit($values, $storage) {
673

    
674
    $this->populateFromDrupalForm($values, $storage);
675

    
676
    try {
677
      $save_result = $this->save();
678
    }
679
    catch (Exception $e) {
680
      $this->errorName = 'Save Error';
681
      $this->errorMsg = t('Failed to save object.  Your form data was not saved.');
682
      $this->hasError = TRUE;
683
    }
684

    
685
  }
686

    
687
  /**
688
   * Add existing mappings to ldap user provisioning mapping admin form table.
689
   *
690
   * @param drupal form array $form
691
   * @param enum $direction
692
   *   LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER or LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY.
693
   *
694
   * @return by reference to $form array
695
   */
696
  private function addServerMappingFields(&$form, $direction) {
697

    
698
    if ($direction == LDAP_USER_PROV_DIRECTION_NONE) {
699
      return;
700
    }
701

    
702
    $text = ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) ? 'target' : 'source';
703
    $user_attr_options = ['0' => t('Select') . ' ' . $text];
704

    
705
    if (!empty($this->synchMapping[$direction])) {
706
      foreach ($this->synchMapping[$direction] as $target_id => $mapping) {
707
        if (!isset($mapping['name']) || isset($mapping['exclude_from_mapping_ui']) && $mapping['exclude_from_mapping_ui']) {
708
          continue;
709
        }
710
        if (
711
          (isset($mapping['configurable_to_drupal']) && $mapping['configurable_to_drupal'] && $direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER)
712
          ||
713
          (isset($mapping['configurable_to_ldap']) && $mapping['configurable_to_ldap']  && $direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY)
714
          ) {
715
          $user_attr_options[$target_id] = substr($target_id, 1, -1);
716
        }
717
      }
718
    }
719

    
720
    if ($direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
721
      $user_attr_options['user_tokens'] = '-- user tokens --';
722
    }
723

    
724
    $row = 0;
725

    
726
    // 1. non configurable mapping rows.
727
    foreach ($this->synchMapping[$direction] as $target_id => $mapping) {
728
      if (isset($mapping['exclude_from_mapping_ui']) && $mapping['exclude_from_mapping_ui']) {
729
        continue;
730
      }
731
      // Is configurable by ldap_user module (not direction to ldap_user)
732
      if (!$this->isMappingConfigurable($mapping, 'ldap_user') && ($mapping['direction'] == $direction || $mapping['direction'] == LDAP_USER_PROV_DIRECTION_ALL)) {
733
        $this->addSynchFormRow($form, 'nonconfigurable', $direction, $mapping, $user_attr_options, $row);
734
        $row++;
735
      }
736
    }
737

    
738
    // 2. existing configurable mappings rows.
739
    if (!empty($this->ldapUserSynchMappings[$direction])) {
740
      // Key could be ldap attribute name or user attribute name.
741
      foreach ($this->ldapUserSynchMappings[$direction] as $target_attr_token => $mapping) {
742
        if (isset($mapping['enabled']) && $mapping['enabled'] && $this->isMappingConfigurable($this->synchMapping[$direction][$target_attr_token], 'ldap_user')) {
743
          $this->addSynchFormRow($form, 'update', $direction, $mapping, $user_attr_options, $row);
744
          $row++;
745
        }
746
      }
747
    }
748

    
749
    // 3. leave 4 rows for adding more mappings.
750
    for ($i = 0; $i < 4; $i++) {
751
      $this->addSynchFormRow($form, 'add', $direction, NULL, $user_attr_options, $row);
752
      $row++;
753
    }
754

    
755
  }
756

    
757
  /**
758
   * Add mapping form row to ldap user provisioning mapping admin form table.
759
   *
760
   * @param drupal form array $form
761
   * @param string $action
762
   *   is 'add', 'update', or 'nonconfigurable'.
763
   * @param enum $direction
764
   *   LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER or LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY.
765
   * @param array $mapping
766
   *   is current setting for updates or nonconfigurable items.
767
   * @param array $user_attr_options
768
   *   of drupal user target options.
769
   * @param int $row
770
   *   is current row in table.
771
   *
772
   * @return by reference to $form
773
   */
774
  private function addSynchFormRow(&$form, $action, $direction, $mapping, $user_attr_options, $row) {
775

    
776
    $id_prefix = $direction . '__';
777

    
778
    $id = $id_prefix . 'sm__remove__' . $row;
779
    $form[$id] = [
780
      '#id' => $id,
781
      '#row' => $row,
782
      '#col' => 0,
783
      '#type' => 'checkbox',
784
      '#default_value' => NULL,
785
      '#disabled' => ($action == 'add' || $action == 'nonconfigurable'),
786
    ];
787

    
788
    $id = $id_prefix . 'sm__convert__' . $row;
789
    $form[$id] = [
790
      '#id' => $id,
791
      '#row' => $row,
792
      '#col' => ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) ? 2 : 3,
793
      '#type' => 'checkbox',
794
      '#default_value' => isset($mapping['convert']) ? $mapping['convert'] : '',
795
      '#disabled' => ($action == 'nonconfigurable'),
796
      '#attributes' => ['class' => ['convert']],
797
    ];
798

    
799
    $id = $id_prefix . 'sm__ldap_attr__' . $row;
800
    $col = ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) ? 1 : 4;
801
    if ($action == 'nonconfigurable') {
802
      $form[$id] = [
803
        '#id' => $id,
804
        '#row' => $row,
805
        '#col' => $col,
806
        '#type' => 'item',
807
        '#markup' => isset($mapping['source']) ? $mapping['source'] : '?',
808
        '#attributes' => ['class' => ['source']],
809
      ];
810
    }
811
    else {
812
      $form[$id] = [
813
        '#id' => $id,
814
        '#row' => $row,
815
        '#col' => $col,
816
        '#type' => 'textfield',
817
        '#default_value' => isset($mapping['ldap_attr']) ? $mapping['ldap_attr'] : '',
818
        '#size' => 20,
819
        '#maxlength' => 255,
820
        '#attributes' => ['class' => ['ldap-attr']],
821
      ];
822
    }
823

    
824
    $user_attr_input_id = $id_prefix . 'sm__user_attr__' . $row;
825
    $col = ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) ? 3 : 1;
826
    if ($action == 'nonconfigurable') {
827
      $form[$user_attr_input_id] = [
828
        '#id' => $user_attr_input_id,
829
        '#row' => $row,
830
        '#col' => $col,
831
        '#type' => 'item',
832
        '#markup' => isset($mapping['name']) ? $mapping['name'] : '?',
833
      ];
834
    }
835
    else {
836
      $form[$user_attr_input_id] = [
837
        '#id' => $user_attr_input_id,
838
        '#row' => $row,
839
        '#col' => $col,
840
        '#type' => 'select',
841
        '#default_value' => isset($mapping['user_attr']) ? $mapping['user_attr'] : '',
842
        '#options' => $user_attr_options,
843
      ];
844
    }
845

    
846
    if ($direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) {
847
      $id = $id_prefix . 'sm__user_tokens__' . $row;
848
      $form[$id] = [
849
        '#id' => $id,
850
        '#row' => $row,
851
        '#col' => 2,
852
        '#type' => 'textfield',
853
        '#default_value' => isset($mapping['user_tokens']) ? $mapping['user_tokens'] : '',
854
        '#size' => 40,
855
        '#maxlength' => 255,
856
        '#disabled' => ($action == 'nonconfigurable'),
857
        '#states' => [
858
          'visible' => [
859
            ':input[name="' . $user_attr_input_id . '"]' => ['value' => 'user_tokens'],
860
          ],
861
        ],
862
        '#attributes' => ['class' => ['tokens']],
863
      ];
864
    }
865

    
866
    $form['#storage']['synch_mapping_fields'][$direction][$row] = [
867
      'action' => $action,
868
      'direction' => $direction,
869
    ];
870

    
871
    $id = $id_prefix . 'sm__configurable_to_drupal__' . $row;
872
    $form[$id] = [
873
      '#id' => $id,
874
      '#type' => 'hidden',
875
      '#default_value' => ($action != 'nonconfigurable'),
876
    ];
877

    
878
    $col = ($direction == LDAP_USER_PROV_DIRECTION_TO_LDAP_ENTRY) ? 5 : 4;
879
    $synchEvents = ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) ? $this->provisionsDrupalEvents : $this->provisionsLdapEvents;
880

    
881
    foreach ($synchEvents as $prov_event => $prov_event_name) {
882
      $col++;
883
      $id = $id_prefix . join('__', ['sm', $prov_event, $row]);
884
      $form[$id] = [
885
        '#id' => $id ,
886
        '#type' => 'checkbox',
887
        '#default_value' => isset($mapping['prov_events']) ? (int) (in_array($prov_event, $mapping['prov_events'])) : '',
888
        '#row' => $row,
889
        '#col' => $col,
890
        '#disabled' => (!$this->provisionEventConfigurable($prov_event, $mapping) || ($action == 'nonconfigurable')),
891
        '#attributes' => ['class' => ['synch-method']],
892
      ];
893
    }
894
  }
895

    
896
  /**
897
   * Is a mapping configurable by a given module?
898
   *
899
   * @param array $mapping
900
   *   as mapping configuration for field, attribute, property, etc.
901
   * @param string $module
902
   *   machine name such as ldap_user.
903
   *
904
   * @return bool
905
   */
906
  private function isMappingConfigurable($mapping = NULL, $module = 'ldap_user') {
907
    $configurable = (
908
      (
909
        (!isset($mapping['configurable_to_drupal']) && !isset($mapping['configurable_to_ldap'])) ||
910
        (isset($mapping['configurable_to_drupal']) && $mapping['configurable_to_drupal']) ||
911
        (isset($mapping['configurable_to_ldap']) && $mapping['configurable_to_ldap'])
912
      )
913
      &&
914
      (
915
        !isset($mapping['config_module']) ||
916
        (isset($mapping['config_module']) && $mapping['config_module'] == $module)
917
      )
918
    );
919
    return $configurable;
920
  }
921

    
922
  /**
923
   * Is a particular synch method viable for a given mapping?
924
   * That is, Can it be enabled in the UI by admins?
925
   *
926
   * @param int $prov_event
927
   * @param array $mapping
928
   *   is array of mapping configuration.
929
   *
930
   * @return bool
931
   */
932
  private function provisionEventConfigurable($prov_event, $mapping = NULL) {
933

    
934
    if ($mapping) {
935
      if ($prov_event == LDAP_USER_EVENT_CREATE_LDAP_ENTRY || $prov_event == LDAP_USER_EVENT_SYNCH_TO_LDAP_ENTRY) {
936
        $configurable = (boolean) (!isset($mapping['configurable_to_ldap']) || $mapping['configurable_to_ldap']);
937
      }
938
      elseif ($prov_event == LDAP_USER_EVENT_CREATE_DRUPAL_USER || $prov_event == LDAP_USER_EVENT_SYNCH_TO_DRUPAL_USER) {
939
        $configurable = (boolean) (!isset($mapping['configurable_to_drupal']) || $mapping['configurable_to_drupal']);
940
      }
941
    }
942
    else {
943
      $configurable = TRUE;
944
    }
945

    
946
    return $configurable;
947
  }
948

    
949
  /**
950
   *
951
   */
952
  protected function setTranslatableProperties() {
953

    
954
    $values['drupalAcctProvisionServerDescription'] = t('Check ONE LDAP server configuration to use
955
      in provisioning Drupal users and their user fields.');
956
    $values['ldapEntryProvisionServerDescription'] = t('Check ONE LDAP server configuration to create ldap entries on.');
957

    
958
    $values['drupalAccountProvisionEventsDescription'] = t('Which user fields and properties are synched on create or synch is determined in the
959
      "Provisioning from LDAP to Drupal mappings" table below in the right two columns. If you are synching only from LDAP to Drupal, and not 
960
      retrieving the user password from LDAP into their Drupal account, a 20 character random password will be generated automatically for
961
      the user\'s Drupal account since Drupal requires a password for the "users" table. Check the watchdog at /admin/reports/dblog to
962
      confirm that a random password was generated when the user account was created.');
963

    
964
    $values['drupalAccountProvisionEventsOptions'] = [
965
      LDAP_USER_DRUPAL_USER_PROV_ON_AUTHENTICATE => t('Create or Synch to Drupal user on successful authentication with LDAP
966
        credentials. (Requires LDAP Authentication module).'),
967
      LDAP_USER_DRUPAL_USER_PROV_ON_USER_UPDATE_CREATE => t('Create or Synch to Drupal user anytime a Drupal user account
968
        is created or updated. Requires a server with binding method of "Service Account Bind" or "Anonymous Bind".'),
969
    ];
970

    
971
    $values['ldapEntryProvisionTriggersDescription'] = t('Which LDAP attributes are synched on create or synch is determined in the
972
      "Provisioning from Drupal to LDAP mappings" table below in the right two columns.');
973

    
974
    $values['ldapEntryProvisionTriggersOptions'] = [
975
      LDAP_USER_LDAP_ENTRY_PROV_ON_USER_UPDATE_CREATE => t('Create or Synch to LDAP entry when a Drupal account is created or updated.
976
        Only applied to accounts with a status of approved.'),
977
      LDAP_USER_LDAP_ENTRY_PROV_ON_AUTHENTICATE => t('Create or Synch to LDAP entry when a user authenticates.'),
978
      LDAP_USER_LDAP_ENTRY_DELETE_ON_USER_DELETE => t('Delete 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.'),
979
      LDAP_USER_DRUPAL_USER_PROV_ON_ALLOW_MANUAL_CREATE => t('Provide option on admin/people/create to create corresponding LDAP Entry.'),
980

    
981
    ];
982

    
983
    $values['orphanedDrupalAcctBehaviorDescription'] = t('It is highly recommended to use the "Perform no action, but email list of orphaned accounts" for some time before considering switching to "Disable the account" options.');
984

    
985
    $values['manualAccountConflictOptions'] = [
986
      LDAP_USER_MANUAL_ACCT_CONFLICT_REJECT => t('Reject manual creation of Drupal accounts that conflict with LDAP Accounts. This only applies to accounts created on user logon;  Account conflicts can still be generated by manually creating users that conflict with ldap users and these users will have their data synched with LDAP data.'),
987
      LDAP_USER_MANUAL_ACCT_CONFLICT_LDAP_ASSOCIATE => t('Associate manually created Drupal accounts with related LDAP Account if one exists.'),
988
      LDAP_USER_MANUAL_ACCT_CONFLICT_SHOW_OPTION_ON_FORM => t('Show option on user create form to determine how account conflict is resolved.'),
989
    ];
990

    
991
    /**
992
    *  Drupal Account Provisioning and Synching
993
    */
994
    $values['userConflictResolveDescription'] = t('What should be done if a local Drupal or other external
995
      user account already exists with the same login name.');
996
    $values['userConflictOptions'] = [
997
      LDAP_USER_CONFLICT_LOG => t('Don\'t associate Drupal account with LDAP.  Require user to use Drupal password. Log the conflict'),
998
      LDAP_USER_CONFLICT_RESOLVE => t('Associate Drupal account with the LDAP entry.  This option
999
      is useful for creating accounts and assigning roles before an LDAP user authenticates.'),
1000
    ];
1001
    $values['accountsWithSameEmailDescription'] = t('Allows provisioning a Drupal user account from LDAP regardless of whether another Drupal user account has the same email address. This setting depends on the "sharedemail" contrib module being enabled. ');
1002
    if (!module_exists('sharedemail')) {
1003
      $values['accountsWithSameEmailDescription'] .= t('The module is not currently enabled; you must install/enable it if you want to use this setting.');
1004
    }
1005
    $values['accountsWithSameEmailOptions'] = [
1006
      LDAP_USER_ACCOUNTS_WITH_SAME_EMAIL_DISABLED => t('Prevent provisioning a user account if an existing account has the same email address.'),
1007
      LDAP_USER_ACCOUNTS_WITH_SAME_EMAIL_ENABLED => t('Allow provisioning a user account that has the same email address as another user account.'),
1008
    ];
1009
    $values['acctCreationOptions'] = [
1010
      LDAP_USER_ACCT_CREATION_LDAP_BEHAVIOR => t('Account creation settings at
1011
        /admin/config/people/accounts/settings do not affect "LDAP Associated" Drupal accounts.'),
1012
      LDAP_USER_ACCT_CREATION_USER_SETTINGS_FOR_LDAP => t('Account creation policy
1013
         at /admin/config/people/accounts/settings applies to both Drupal and LDAP Authenticated users.
1014
         "Visitors" option automatically creates and account when they successfully LDAP authenticate.
1015
         "Admin" and "Admin with approval" do not allow user to authenticate until the account is approved.'),
1016

    
1017
    ];
1018

    
1019
    foreach ($values as $property => $default_value) {
1020
      $this->$property = $default_value;
1021
    }
1022
  }
1023

    
1024
}