Projet

Général

Profil

Paste
Télécharger (43,6 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ldap / ldap_servers / LdapServerAdmin.class.php @ be58a50c

1
<?php
2

    
3
/**
4
 * @file
5
 * LDAP Server Admin Class
6
 *
7
 *
8
 */
9

    
10
module_load_include('php', 'ldap_servers', 'LdapServer.class');
11

    
12
class LdapServerAdmin extends LdapServer {
13

    
14
  public $bindpw_new = FALSE;
15
  public $bindpw_clear = FALSE;
16

    
17
  /**
18
   * @param $type = 'all', 'enabled'
19
   */
20
  public static function getLdapServerObjects($sid = NULL, $type = NULL, $class = 'LdapServer', $reset = FALSE) {
21
    $servers = array();
22
    if (module_exists('ctools')) {
23
      ctools_include('export');
24
      if ($reset) {
25
        ctools_export_load_object_reset('ldap_servers');
26
      }
27
      $select = ctools_export_load_object('ldap_servers', 'all');
28
    }
29
    else {
30
      try {
31
        $select = db_select('ldap_servers', 'ldap_servers')
32
          ->fields('ldap_servers')
33
          ->execute();
34
      }
35
      catch (Exception $e) {
36
        drupal_set_message(t('server index query failed. Message = %message, query= %query',
37
          array('%message' => $e->getMessage(), '%query' => $e->query_string)), 'error');
38
        return array();
39
      }
40
    }
41
    foreach ($select as $result) {
42
      $servers[$result->sid] = ($class == 'LdapServer') ? new LdapServer($result->sid) : new LdapServerAdmin($result->sid);
43
    }
44
    return $servers;
45

    
46
  }
47

    
48
  function __construct($sid) {
49
    parent::__construct($sid);
50
  }
51

    
52
  protected function populateFromDrupalForm($op, $values) {
53
    $this->inDatabase = ($op == 'edit');
54
    $this->sid = trim($values['sid']);
55
    $this->name = trim($values['name']);
56
    $this->status = ($values['status']) ? 1 : 0;
57
    $this->ldap_type = trim($values['ldap_type']);
58
    $this->address = trim($values['address']);
59
    $this->port = trim($values['port']);
60
    $this->tls = trim($values['tls']);
61
    $this->followrefs = trim($values['followrefs']);
62
    $this->bind_method = trim($values['bind_method']);
63
    $this->binddn = trim($values['binddn']);
64
    if (trim($values['bindpw'])) {
65
      $this->bindpw_new = trim($values['bindpw']);
66
    }
67
    $this->user_dn_expression = trim($values['user_dn_expression']);
68
    $this->basedn = $this->linesToArray(trim($values['basedn']));
69
    $this->user_attr = drupal_strtolower(trim($values['user_attr']));
70
    $this->picture_attr = drupal_strtolower(trim($values['picture_attr']));
71
    $this->account_name_attr = drupal_strtolower(trim($values['account_name_attr']));
72
    $this->mail_attr = drupal_strtolower(trim($values['mail_attr']));
73
    $this->mail_template = trim($values['mail_template']);
74
    $this->unique_persistent_attr = drupal_strtolower(trim($values['unique_persistent_attr']));
75
    $this->unique_persistent_attr_binary = trim($values['unique_persistent_attr_binary']);
76
    $this->ldapToDrupalUserPhp = $values['ldap_to_drupal_user'];
77
    $this->testingDrupalUsername = trim($values['testing_drupal_username']);
78
    $this->testingDrupalUserDn = trim($values['testing_drupal_user_dn']);
79
    $this->groupFunctionalityUnused = $values['grp_unused'];
80
    $this->groupObjectClass = drupal_strtolower(trim($values['grp_object_cat']));
81
    $this->groupNested = trim($values['grp_nested']);
82

    
83
    $this->groupUserMembershipsAttrExists = trim($values['grp_user_memb_attr_exists']);
84
    $this->groupUserMembershipsAttr =  drupal_strtolower(trim($values['grp_user_memb_attr']));
85

    
86
    $this->groupMembershipsAttr = drupal_strtolower(trim($values['grp_memb_attr']));
87

    
88
    $this->groupMembershipsAttrMatchingUserAttr =  drupal_strtolower(trim($values['grp_memb_attr_match_user_attr']));
89

    
90
    $this->groupDeriveFromDn = trim($values['grp_derive_from_dn']);
91
    $this->groupDeriveFromDnAttr = drupal_strtolower(trim($values['grp_derive_from_dn_attr']));
92
    $this->groupTestGroupDn = trim($values['grp_test_grp_dn']);
93
    $this->groupTestGroupDnWriteable = trim($values['grp_test_grp_dn_writeable']);
94

    
95

    
96
    $this->searchPagination = ($values['search_pagination']) ? 1 : 0;
97
    $this->searchPageSize = trim($values['search_page_size']);
98

    
99
  }
100

    
101
  /**
102
   * @param string enum $op 'add', 'update'
103
   */
104

    
105
  public function save($op) {
106

    
107
    $values = new stdClass();
108

    
109
    foreach ($this->field_to_properties_map() as $field_name => $property_name) {
110
      $field_name_lcase = drupal_strtolower($field_name);
111
      $values->{$field_name_lcase} = $this->{$property_name};
112
    }
113
    if (isset($this->bindpw) && $this->bindpw) {
114
      $values->bindpw = ldap_servers_encrypt($this->bindpw);
115
    }
116
    if ($this->bindpw_new) {
117
      $values->bindpw = ldap_servers_encrypt($this->bindpw_new);
118
    }
119
    elseif ($this->bindpw_clear) {
120
      $values->bindpw = NULL;
121
    }
122

    
123
    $values->tls = (int)$this->tls;
124
    $values->followrefs = (int)$this->followrefs;
125

    
126
    if (module_exists('ctools')) {
127
      ctools_include('export');
128
      // Populate our object with ctool's properties
129
      $object = ctools_export_crud_new('ldap_servers');
130

    
131
      foreach ($object as $property => $value) {
132
        $property_lcase = drupal_strtolower($property);
133
        if (!isset($values->$property) || !isset($values->$property_lcase)) {
134
          $values->$property_lcase = $value;
135
        }
136
      }
137

    
138
      try {
139
        $values->export_type = NULL;
140
        $result = ctools_export_crud_save('ldap_servers', $values);
141
      } catch (Exception $e) {
142
        $values->export_type = EXPORT_IN_DATABASE;
143
        $result = ctools_export_crud_save('ldap_servers', $values);
144
      }
145
      
146
      ctools_export_load_object_reset('ldap_servers'); // ctools_export_crud_save doesn't invalidate cache
147

    
148
    }
149
    else { // directly via db
150
      unset($values->numeric_sid);
151
      if ($op == 'add') {
152
        $result = drupal_write_record('ldap_servers', $values);
153
      }
154
      else {
155
        $result = drupal_write_record('ldap_servers', $values, 'sid');
156
      }
157
      ldap_servers_cache_clear();
158

    
159
    }
160

    
161
  //  debug("values sent to save op=$op, ctools=". (int)module_exists('ctools')); debug($values);
162
    if ($result) {
163
      $this->inDatabase = TRUE;
164
    }
165
    else {
166
      drupal_set_message(t('Failed to write LDAP Server to the database.'));
167
    }
168
  }
169

    
170
  public function delete($sid) {
171
    if ($sid == $this->sid) {
172
      $result = db_delete('ldap_servers')->condition('sid', $sid)->execute();
173
      if (module_exists('ctools')) {
174
        ctools_include('export');
175
        ctools_export_load_object_reset('ldap_servers'); // invalidate cache
176
      }
177
      $this->inDatabase = FALSE;
178
      return $result;
179
    }
180
    else {
181
      return FALSE;
182
    }
183
  }
184
  public function getLdapServerActions() {
185
    $switch = ($this->status ) ? 'disable' : 'enable';
186
    $actions = array();
187
    $actions[] =  l(t('edit'), LDAP_SERVERS_MENU_BASE_PATH . '/servers/edit/' . $this->sid);
188
    if (property_exists($this, 'type')) {
189
      if ($this->type == 'Overridden') {
190
          $actions[] = l(t('revert'), LDAP_SERVERS_MENU_BASE_PATH . '/servers/delete/' . $this->sid);
191
      }
192
      if ($this->type == 'Normal') {
193
          $actions[] = l(t('delete'), LDAP_SERVERS_MENU_BASE_PATH . '/servers/delete/' . $this->sid);
194
      }
195
    }
196
    else {
197
        $actions[] = l(t('delete'), LDAP_SERVERS_MENU_BASE_PATH . '/servers/delete/' . $this->sid);
198
    }
199
    $actions[] = l(t('test'), LDAP_SERVERS_MENU_BASE_PATH . '/servers/test/' . $this->sid);
200
    $actions[] = l($switch, LDAP_SERVERS_MENU_BASE_PATH . '/servers/' . $switch . '/' . $this->sid);
201
    return $actions;
202
  }
203

    
204
  public function drupalForm($op) {
205

    
206
  $form['server'] = array(
207
    '#type' => 'fieldset',
208
    '#title' => t('Connection settings'),
209
    '#collapsible' => TRUE,
210
    '#collapsed' => TRUE,
211
  );
212

    
213
  $form['bind_method'] = array(
214
    '#type' => 'fieldset',
215
    '#title' => t('Binding Method'),
216
    '#description' => t('How the Drupal system is authenticated by the LDAP server.'),
217
    '#collapsible' => TRUE,
218
    '#collapsed' => TRUE,
219
  );
220

    
221
  $form['users'] = array(
222
    '#type' => 'fieldset',
223
    '#title' => t('LDAP User to Drupal User Relationship'),
224
    '#description' => t('How are LDAP user entries found based on Drupal username or email?  And vice-versa?
225
       Needed for LDAP Authentication and Authorization functionality.'),
226
    '#collapsible' => TRUE,
227
    '#collapsed' => TRUE,
228
  );
229

    
230
  $form['groups'] = array(
231
    '#type' => 'fieldset',
232
    '#title' => t('LDAP Group Configuration'),
233
    '#description' => t('How are groups defined on your LDAP server?  This varies slightly from one LDAP implementation to another
234
      such as Active Directory, Novell, OpenLDAP, etc. Check everything that is true and enter all the values you know.'),
235
    '#collapsible' => TRUE,
236
    '#collapsed' => TRUE,
237
  );
238

    
239
  $supports = (ldap_servers_php_supports_pagination()) ? t('support pagination!') : t('NOT support pagination.');
240
  $form['pagination'] = array(
241
    '#type' => 'fieldset',
242
    '#title' => t('LDAP Pagination'),
243
    '#description' => t('In PHP 5.4, pagination is supported in ldap queries.
244
      A patch to earlier versions of PHP also supports this.')
245
      . ' <strong>' . t('This PHP installation appears to') . ' ' . $supports . '</strong> '
246
      . '<p>' . t('The advantage to pagination support is that if an ldap server is setup to return only
247
      1000 entries at a time,
248
      you can use page through 1000 records at a time;
249
      without pagination you would never see more than the first 1000 entries.
250
      Pagination is most useful when large queries for batch creating or
251
      synching accounts are used.  If you are not using this server for such
252
      tasks, its recommended to leave pagination disabled.') . '</p>',
253
    '#collapsible' => TRUE,
254
    '#collapsed' => !ldap_servers_php_supports_pagination(),
255
  );
256

    
257

    
258
  $field_to_prop_maps = $this->field_to_properties_map();
259
  foreach ($this->fields() as $field_id => $field) {
260
    if (isset($field['form'])) {
261

    
262
      if (!isset($field['form']['required']) && isset($field['schema']['not null']) && $field['form']['#type'] != 'checkbox') {
263
        $field['form']['#required'] = (boolean)$field['schema']['not null'];
264
      }
265
      if (isset($field['schema']['length']) && !isset($field['form']['#maxlength'])) {
266
        $field['form']['#maxlength'] = $field['schema']['length'];
267
      }
268
      if (isset($field_to_prop_maps[$field_id])) {
269
        $field['form']['#default_value'] = $this->{$field_to_prop_maps[$field_id]};
270
      }
271
      $fieldset = @$field['form']['fieldset'];
272
      if ($fieldset) {
273
        unset($field['form']['fieldset']);
274
        $form[$fieldset][$field_id] = $field['form'];
275
      }
276
      else {
277
        $form[$field_id] = $field['form'];
278
      }
279
    }
280
  }
281

    
282
  $form['server']['sid']['#disabled'] = ($op == 'edit');
283

    
284
  if (!function_exists('ldap_set_rebind_proc')) {
285
    $form['server']['followrefs']['#disabled'] = TRUE;
286
    $form['server']['followrefs']['#description'] =  t('This functionality is disabled because the function ldap_set_rebind_proc can not be found on this server.  Perhaps your version of php does not have this function.  See php.net/manual/en/function.ldap-set-rebind-proc.php') . $form['server']['followrefs']['#description'];
287
  }
288

    
289
  $form['server']['tls']['#required'] = FALSE;
290
  $form['server']['followrefs']['#required'] = FALSE;
291
  $form['bind_method']['bind_method']['#default_value'] = ($this->bind_method) ? $this->bind_method : LDAP_SERVERS_BIND_METHOD_DEFAULT;
292
  $form['users']['basedn']['#default_value'] = $this->arrayToLines($this->basedn);
293

    
294
  if ($this->bindpw) {
295
    $pwd_directions = t('You currently have a password stored in the database.
296
      Leave password field empty to leave password unchanged.  Enter a new password
297
      to replace the current password.  Check the checkbox below to simply
298
      remove it from the database.');
299
    $pwd_class = 'ldap-pwd-present';
300
  }
301
  else {
302
    $pwd_directions = t('No password is currently stored in the database.
303
      If you are using a service account, enter one.');
304
    if ($this->bind_method == LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT) {
305
      $pwd_class = 'ldap-pwd-abscent';
306
    }
307
    else {
308
      $pwd_class = 'ldap-pwd-not-applicable';
309
    }
310
  }
311

    
312
  $action = ($op == 'add') ? 'Add' : 'Update';
313
  $form['submit'] = array(
314
    '#type' => 'submit',
315
    '#value' => $action,
316
    '#weight' => 100,
317
  );
318

    
319
  return $form;
320

    
321
  }
322

    
323

    
324
  public function drupalFormValidate($op, $values)  {
325
    $errors = array();
326

    
327
    if ($op == 'delete') {
328
      if (!$this->sid) {
329
        $errors['server_id_missing'] = 'Server id missing from delete form.';
330
      }
331
      $warnings = module_invoke_all('ldap_server_in_use', $this->sid, $this->name);
332
      if (count($warnings)) {
333
        $errors['status'] = join("<br/>", array_values($warnings));
334
      }
335

    
336

    
337
    }
338
    else {
339
      $this->populateFromDrupalForm($op, $values);
340
      $errors = $this->validate($op);
341
    }
342
    return $errors;
343
  }
344

    
345
  protected function validate($op) {
346
    $errors = array();
347
    if ($op == 'add') {
348
      $ldap_servers = $this->getLdapServerObjects(NULL, 'all');
349
      if (count($ldap_servers)) {
350
        foreach ($ldap_servers as $sid => $ldap_server) {
351
          if ($this->name == $ldap_server->name) {
352
            $errors['name'] = t('An LDAP server configuration with the  name %name already exists.', array('%name' => $this->name));
353
          }
354
          elseif ($this->sid == $ldap_server->sid) {
355
            $errors['sid'] = t('An LDAP server configuration with the  id %sid  already exists.', array('%sid' => $this->sid));
356
          }
357
        }
358
      }
359
    }
360

    
361
    if ($this->status == 0) { // check that no modules use this server
362
      $warnings = module_invoke_all('ldap_server_in_use', $this->sid, $this->name);
363
      if (count($warnings)) {
364
        $errors['status'] = join("<br/>", array_values($warnings));
365
      }
366
    }
367

    
368

    
369
    if (!is_numeric($this->port)) {
370
      $errors['port'] =  t('The TCP/IP port must be an integer.');
371
    }
372

    
373
    if ($this->bind_method == LDAP_SERVERS_BIND_METHOD_USER && !$this->user_dn_expression) {
374
      $errors['user_dn_expression'] =  t('When using "Bind with Users Credentials", Expression for user DN is required');
375
    }
376

    
377
    if ($this->mail_attr && $this->mail_template) {
378
      $errors['mail_attr'] =  t('Mail attribute or Mail Template may be used.  Not both.');
379
    }
380

    
381
    if ($this->bind_method == LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT && !$this->binddn) {
382
      $errors['binddn'] =  t('When using "Bind with Service Account", Bind DN is required.');
383
    }
384
    if ($op == 'add') {
385
      if ($this->bind_method == LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT &&
386
        (($op == 'add' && !$this->bindpw_new) || ($op != 'add' && !$this->bindpw))
387
      ) {
388
        $errors['bindpw'] =  t('When using "Bind with Service Account", Bind password is required.');
389
      }
390
    }
391

    
392
    return $errors;
393
  }
394

    
395
public function drupalFormWarnings($op, $values, $has_errors = NULL)  {
396
    $errors = array();
397

    
398
    if ($op == 'delete') {
399
      if (!$this->sid) {
400
        $errors['server_id_missing'] = t('Server id missing from delete form.');
401
      }
402
    }
403
    else {
404
      $this->populateFromDrupalForm($op, $values);
405
      $warnings = $this->warnings($op, $has_errors);
406
    }
407
    return $warnings;
408
  }
409

    
410

    
411
protected function warnings($op, $has_errors = NULL) {
412

    
413
    $warnings = array();
414
    if ($this->ldap_type) {
415
      $defaults = ldap_servers_ldaps_option_array();
416
      if (isset($defaults['user']['user_attr']) && ($this->user_attr != $defaults['user']['user_attr'])) {
417
        $tokens = array('%name' => $defaults['name'], '%default' => $defaults['user']['user_attr'], '%user_attr' => $this->user_attr);
418
        $warnings['user_attr'] =  t('The standard UserName attribute in %name is %default.  You have %user_attr. This may be correct
419
          for your particular LDAP.', $tokens);
420
      }
421

    
422
      if (isset($defaults['user']['mail_attr']) && $this->mail_attr && ($this->mail_attr != $defaults['user']['mail_attr'])) {
423
        $tokens = array('%name' => $defaults['name'], '%default' => $defaults['user']['mail_attr'], '%mail_attr' => $this->mail_attr);
424
        $warnings['mail_attr'] =  t('The standard mail attribute in %name is %default.  You have %mail_attr.  This may be correct
425
          for your particular LDAP.', $tokens);
426
      }
427
    }
428
  //  if (!$this->status && $has_errors != TRUE) {
429
    //  $warnings['status'] =  t('This server configuration is currently disabled.');
430
   // }
431

    
432
    if (!$this->mail_attr && !$this->mail_template) {
433
      $warnings['mail_attr'] =  t('Mail attribute or Mail Template should be used for most user account functionality.');
434
    }
435

    
436
   // commented out validation because too many false positives present usability errors.
437
   // if ($this->bind_method == LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT) { // Only for service account
438
     // $result = ldap_baddn($this->binddn, t('Service Account DN'));
439
     // if ($result['boolean'] == FALSE) {
440
     //   $warnings['binddn'] =  $result['text'];
441
     // }
442
   // }
443

    
444
   // foreach ($this->basedn as $basedn) {
445
    //  $result = ldap_baddn($basedn, t('User Base DN'));
446
     // if ($result['boolean'] == FALSE) {
447
     //   $warnings['basedn'] =  $result['text'];
448
    //  }
449
   // }
450

    
451
   // $result = ldap_badattr($this->user_attr, t('User attribute'));
452
   // if ($result['boolean'] == FALSE) {
453
    //  $warnings['user_attr'] =  $result['text'];
454
   // }
455

    
456
   // if ($this->mail_attr) {
457
  //    $result = ldap_badattr($this->mail_attr, t('Mail attribute'));
458
   //   if ($result['boolean'] == FALSE) {
459
    //    $warnings['mail_attr'] =  $result['text'];
460
   //   }
461
  //  }
462

    
463
   // $result = ldap_badattr($this->unique_persistent_attr, t('Unique Persistent Attribute'));
464
   // if ($result['boolean'] == FALSE) {
465
    //  $warnings['unique_persistent_attr'] =  $result['text'];
466
   // }
467

    
468
    return $warnings;
469
  }
470

    
471
public function drupalFormSubmit($op, $values) {
472

    
473
  $this->populateFromDrupalForm($op, $values);
474

    
475
  if ($values['clear_bindpw']) {
476
    $this->bindpw_clear = TRUE;
477
  }
478

    
479
  if ($op == 'delete') {
480
    $this->delete($this);
481
  }
482
  else { // add or edit
483
    try {
484
      $save_result = $this->save($op);
485
    }
486
    catch (Exception $e) {
487
      $this->setError('Save Error',
488
        t('Failed to save object.  Your form data was not saved.'));
489
    }
490
  }
491
}
492

    
493

    
494

    
495
  protected function arrayToLines($array) {
496
    $lines = "";
497
    if (is_array($array)) {
498
      $lines = join("\n", $array);
499
    }
500
    elseif (is_array(@unserialize($array))) {
501
      $lines = join("\n", unserialize($array));
502
    }
503
    return $lines;
504
  }
505

    
506
  protected function linesToArray($lines) {
507
    $lines = trim($lines);
508

    
509
    if ($lines) {
510
      $array = preg_split('/[\n\r]+/', $lines);
511
      foreach ($array as $i => $value) {
512
        $array[$i] = trim($value);
513
      }
514
    }
515
    else {
516
      $array = array();
517
    }
518
    return $array;
519
  }
520

    
521

    
522
  public static function fields() {
523

    
524
     /**
525
     * consumer_type is tag (unique alphanumeric id) of consuming authorization such as
526
     *   drupal_roles, og_groups, civicrm_memberships
527
     */
528
    $fields = array(
529

    
530
      'sid' => array(
531
        'form' => array(
532
          'fieldset' => 'server',
533
          '#type' => 'textfield',
534
          '#size' => 20,
535
          '#title' => t('Machine name for this server configuration.'),
536
          '#description' => t('May only contain alphanumeric characters (a-z, A-Z, 0-9, and _)'),
537
          '#required' => TRUE,
538
        ),
539
        'schema' => array(
540
          'type' => 'varchar',
541
          'length' => 20,
542
          'not null' => TRUE,
543
        )
544
      ),
545

    
546
     'numeric_sid' => array(
547
        'schema' => array(
548
          'type' => 'serial',
549
          'unsigned' => TRUE,
550
          'not null' => TRUE,
551
          'description' => 'Primary ID field for the table.  Only used internally.',
552
          'no export' => TRUE,
553
        ),
554
      ),
555

    
556
      'name' => array(
557
        'form' => array(
558
          'fieldset' => 'server',
559
          '#type' => 'textfield',
560
          '#size' => 50,
561
          '#title' => 'Name',
562
          '#description' => t('Choose a <em><strong>unique</strong></em> name for this server configuration.'),
563
        ),
564
        'schema' => array(
565
          'type' => 'varchar',
566
          'length' => 255,
567
          'not null' => FALSE,
568
        ),
569
      ),
570

    
571
      'status' => array(
572
        'form' => array(
573
          'fieldset' => 'server',
574
          '#type' => 'checkbox',
575
          '#title' => t('Enabled'),
576
          '#description' => t('Disable in order to keep configuration without having it active.'),
577
          '#required' => FALSE,
578
        ),
579
        'schema' => array(
580
          'type' => 'int',
581
          'size' => 'tiny',
582
          'not null' => FALSE,
583
          'default' => 0,
584
        ),
585
      ),
586

    
587
      'ldap_type' =>  array(
588
        'form' => array(
589
          'fieldset' => 'server',
590
          '#type' => 'select',
591
          '#options' =>  ldap_servers_ldaps_option_array(),
592
          '#title' => t('LDAP Server Type'),
593
          '#description' => t('This field is informative.  It\'s purpose is to assist with default values and give validation warnings.'),
594
        ),
595
        'schema' => array(
596
          'type' => 'varchar',
597
          'length' => 20,
598
          'not null' => FALSE,
599
        ),
600
      ),
601

    
602
      'address' => array(
603
        'form' => array(
604
          'fieldset' => 'server',
605
          '#type' => 'textfield',
606
          '#title' => t('LDAP server'),
607
          '#description' => t('The domain name or IP address of your LDAP Server such as "ad.unm.edu". For SSL
608
        use the form ldaps://DOMAIN such as "ldaps://ad.unm.edu"'),
609
          '#size' => 50,
610
        ),
611
        'schema' => array(
612
          'type' => 'varchar',
613
          'length' => 255,
614
          'not null' => FALSE,
615
        ),
616
      ),
617

    
618
      'port' => array(
619
        'form' => array(
620
          'fieldset' => 'server',
621
          '#type' => 'textfield',
622
          '#title' => t('LDAP port'),
623
          '#size' => 5,
624
          '#description' => t('The TCP/IP port on the above server which accepts LDAP connections. Must be an integer.'),
625
        ),
626
        'schema' => array(
627
          'type' => 'int',
628
          'not null' => FALSE,
629
          'default' => 389,
630
        ),
631
      ),
632

    
633
      'tls' => array(
634
        'form' => array(
635
          'fieldset' => 'server',
636
          '#type' => 'checkbox',
637
          '#title' => t('Use Start-TLS'),
638
          '#description' => t('Secure the connection between the Drupal and the LDAP servers using TLS.<br /><em>Note: To use START-TLS, you must set the LDAP Port to 389.</em>'),
639
        ),
640
        'schema' => array(
641
          'type' => 'int',
642
          'size' => 'tiny',
643
          'not null' => FALSE,
644
          'default' => 0,
645
        ),
646
      ),
647

    
648
      'followrefs' => array(
649
        'form' => array(
650
           'fieldset' => 'server',
651
           '#type' => 'checkbox',
652
           '#title' => t('Follow LDAP Referrals'),
653
           '#description' => t('Makes the LDAP client follow referrals (in the responses from the LDAP server) to other LDAP servers. This requires that the Bind Settings you give, is ALSO valid on these other servers.'),
654
          ),
655
        'schema' => array(
656
           'type' => 'int',
657
           'size' => 'tiny',
658
           'not null' => FALSE,
659
           'default' => 0,
660
        ),
661
      ),
662

    
663
      'bind_method' => array(
664
        'form' => array(
665
          'fieldset' => 'bind_method',
666
          '#type' => 'radios',
667
          '#title' => t('Binding Method for Searches (such as finding user object or their group memberships)'),
668
          '#options' => array(
669
            LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT => t('Service Account Bind: Use credentials in the
670
            <strong>Service Account</strong> field to bind to LDAP.  <em>This option is usually a best practice.</em>'),
671

    
672
            LDAP_SERVERS_BIND_METHOD_USER => t('Bind with Users Credentials: Use user\'s entered credentials
673
            to bind to LDAP.<br/> This is only useful for modules that execute during user logon such
674
            as LDAP Authentication and LDAP Authorization.  <em>This option is not a best practice in most cases.</em>
675
            This option skips the initial anonymous bind and anonymous search to determine the LDAP user DN, but you
676
            can only use this option if your user DNs follow a consistent pattern, for example all of them being of
677
            the form "cn=[username],[base dn]", or all of them being of the form "uid=[username],ou=accounts,[base dn]".
678
            You specify the pattern under "Expression for user DN" in the next configuration block below.'),
679

    
680
            LDAP_SERVERS_BIND_METHOD_ANON_USER => t('Anonymous Bind for search, then Bind with Users Credentials:
681
            Searches for user dn then uses user\'s entered credentials to bind to LDAP.<br/> This is only useful for
682
            modules that work during user logon such as LDAP Authentication and LDAP Authorization.
683
            The user\'s dn must be discovered by an anonymous search for this option to work.'),
684

    
685
            LDAP_SERVERS_BIND_METHOD_ANON => t('Anonymous Bind: Use no credentials to bind to LDAP server.<br/>
686
            <em>This option will not work on most LDAPS connections.</em>'),
687
          ),
688
        ),
689
        'schema' => array(
690
          'type' => 'int',
691
          'size' => 'small',
692
          'not null' => FALSE,
693
          'default' => 0,
694
          'boolean' => FALSE,
695
        ),
696
      ),
697

    
698
    'binding_service_acct' => array(
699
      'form' => array(
700
        'fieldset' => 'bind_method',
701
        '#type' => 'markup',
702
        '#markup' => t('<label>Service Account</label> Some LDAP configurations
703
          prohibit or restrict the results of anonymous searches. These LDAPs require a DN//password pair
704
          for binding. For security reasons, this pair should belong to an
705
          LDAP account with stripped down permissions.
706
          This is also required for provisioning LDAP accounts and groups!'),
707
        ),
708
      ),
709

    
710

    
711
      'binddn' => array(
712
        'form' => array(
713
          'fieldset' => 'bind_method',
714
          '#type' => 'textfield',
715
          '#title' => t('DN for non-anonymous search'),
716
          '#size' => 80,
717
          '#states' => array(
718
             'enabled' => array(   // action to take.
719
               ':input[name=bind_method]' => array('value' => (string)LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT),
720
              ),
721
            ),
722
        ),
723
        'schema' => array(
724
          'type' => 'varchar',
725
          'length' => 511,
726
        ),
727
      ),
728

    
729
      'bindpw' => array(
730
        'form' => array(
731
          'fieldset' => 'bind_method',
732
          '#type' => 'password',
733
          '#title' => t('Password for non-anonymous search'),
734
          '#size' => 20,
735
          '#states' => array(
736
             'enabled' => array(   // action to take.
737
               ':input[name=bind_method]' => array('value' => (string)LDAP_SERVERS_BIND_METHOD_SERVICE_ACCT),
738
              ),
739
            ),
740
        ),
741
        'schema' => array(
742
          'type' => 'varchar',
743
          'length' => 255,
744
        ),
745
      ),
746

    
747
      'clear_bindpw' => array(
748
        'form' => array(
749
          'fieldset' => 'bind_method',
750
          '#type' => 'checkbox',
751
          '#title' => t('Clear existing password from database.  Check this when switching away from Service Account Binding.'),
752
          '#default_value' => 0,
753
        ),
754
      ),
755

    
756
      'basedn' => array(
757
        'form' => array(
758
          'fieldset' => 'users',
759
          '#type' => 'textarea',
760
          '#cols' => 50,
761
          '#rows' => 6,
762
          '#title' => t('Base DNs for LDAP users, groups, and other entries.'),
763
          '#description' => '<div>' . t('What DNs have entries relavant to this configuration?
764
            e.g. <code>ou=campus accounts,dc=ad,dc=uiuc,dc=edu</code>
765
            Keep in mind that every additional basedn likely doubles the number of queries.  Place the
766
            more heavily used one first and consider using one higher base DN rather than 2 or more lower base DNs.
767
            Enter one per line in case if you need more than one.') . '</div>',
768
        ),
769
        'schema' => array(
770
          'type' => 'text',
771
          'serialize' => TRUE,
772
        ),
773
      ),
774

    
775
      'user_attr' => array(
776
        'form' => array(
777
          'fieldset' => 'users',
778
          '#type' => 'textfield',
779
          '#size' => 30,
780
          '#title' => t('AuthName attribute'),
781
          '#description' => t('The attribute that holds the users\' login name. (eg. <code>cn</code> for eDir or <code>sAMAccountName</code> for Active Directory).'),
782
        ),
783
        'schema' => array(
784
          'type' => 'varchar',
785
          'length' => 255,
786
          'not null' => FALSE,
787
        ),
788
      ),
789

    
790
      'account_name_attr' => array(
791
        'form' => array(
792
          'fieldset' => 'users',
793
          '#type' => 'textfield',
794
          '#size' => 30,
795
          '#title' => t('AccountName attribute'),
796
          '#description' => t('The attribute that holds the unique account name. Defaults to the same as the AuthName attribute.'),
797
        ),
798
        'schema' => array(
799
          'type' => 'varchar',
800
          'length' => 255,
801
          'not null' => FALSE,
802
          'default' => '',
803
        ),
804
      ),
805

    
806
      'mail_attr' => array(
807
        'form' => array(
808
          'fieldset' => 'users',
809
          '#type' => 'textfield',
810
          '#size' => 30,
811
          '#title' => t('Email attribute'),
812
          '#description' => t('The attribute that holds the users\' email address. (eg. <code>mail</code>). Leave empty if no such attribute exists'),
813
        ),
814
        'schema' => array(
815
          'type' => 'varchar',
816
          'length' => 255,
817
          'not null' => FALSE,
818
        ),
819
      ),
820

    
821
      'mail_template' => array(
822
        'form' => array(
823
          'fieldset' => 'users',
824
          '#type' => 'textfield',
825
          '#size' => 30,
826
          '#title' => t('Email template'),
827
          '#description' => t('If no attribute contains the user\'s email address, but it can be derived from other attributes,
828
            enter an email "template" here.
829
            Templates should have the user\'s attribute name in form such as [cn], [uin], etc.
830
            such as <code>[cn]@mycompany.com</code>.
831
            See http://drupal.org/node/997082 for additional documentation on ldap tokens.
832
            '),
833
        ),
834
        'schema' => array(
835
          'type' => 'varchar',
836
          'length' => 255,
837
          'not null' => FALSE,
838
        ),
839
      ),
840

    
841
    'picture_attr' => array(
842
                      'form' => array(
843
                                      'fieldset' => 'users',
844
                                      '#type' => 'textfield',
845
                                      '#size' => 30,
846
                                      '#title' => t('Thumbnail attribute'),
847
                                      '#description' => t('The attribute that holds the users\' thumnail image. (eg. <code>thumbnailPhoto</code>). Leave empty if no such attribute exists'),
848
                      ),
849
                      'schema' => array(
850
                                      'type' => 'varchar',
851
                                      'length' => 255,
852
                                      'not null' => FALSE,
853
                      ),
854
      ),
855
  
856
      'unique_persistent_attr' => array(
857
        'form' => array(
858
          'fieldset' => 'users',
859
          '#type' => 'textfield',
860
          '#size' => 30,
861
          '#title' => t('Persistent and Unique User ID Attribute'),
862
          '#description' => t('In some LDAPs, a user\'s DN, CN, or mail value may
863
            change when a user\'s name changes or for other reasons.
864
            In order to avoid creation of multiple accounts for that user or other ambiguities,
865
            enter a unique and persistent ldap attribute for users.  In cases
866
            where DN does not change, enter "dn" here.
867
            If no such attribute exists, leave this blank.'
868
            ),
869
        ),
870
        'schema' => array(
871
          'type' => 'varchar',
872
          'length' => 64,
873
          'not null' => FALSE,
874
        ),
875
      ),
876

    
877
      'unique_persistent_attr_binary' => array(
878
        'form' => array(
879
          'fieldset' => 'users',
880
          '#type' => 'checkbox',
881
          '#title' => t('Does the <em>Persistent and Unique User ID
882
            Attribute</em> hold a binary value?'),
883
          '#description' => t('You need to set this if you are using a binary
884
             attribute such as objectSid in ActiveDirectory for the PUID.<br>
885
             If you don\'t want this consider switching to another attribute,
886
             such as samaccountname.'),
887
        ),
888
        'schema' => array(
889
          'type' => 'int',
890
          'size' => 'tiny',
891
          'not null' => FALSE,
892
          'default' => 0,
893
        ),
894
      ),
895

    
896
      'user_dn_expression' => array(
897
        'form' => array(
898
          'fieldset' => 'users',
899
          '#type' => 'textfield',
900
          '#size' => 80,
901
          '#title' => t('Expression for user DN. Required when "Bind with Users Credentials" method selected.'),
902
          '#description' => t('%username and %basedn are valid tokens in the expression.
903
            Typically it will be:<br/> <code>cn=%username,%basedn</code>
904
             which might evaluate to <code>cn=jdoe,ou=campus accounts,dc=ad,dc=mycampus,dc=edu</code>
905
             Base DNs are entered above.'),
906
        ),
907
        'schema' => array(
908
          'type' => 'varchar',
909
          'length' => 255,
910
          'not null' => FALSE,
911
        ),
912
      ),
913

    
914
      'ldap_to_drupal_user' =>  array(
915
        'form' => array(
916
          'fieldset' => 'users',
917
          '#disabled' => (!module_exists('php')),
918
          '#type' => 'textarea',
919
          '#cols' => 25,
920
          '#rows' => 5,
921
          '#title' => t('PHP to transform Drupal login username to LDAP UserName attribute.'),
922
          '#description' => t('This will appear as disabled unless the "PHP filter" core module is enabled. Enter PHP to transform Drupal username to the value of the UserName attribute.
923
            The code should print the UserName attribute.
924
            PHP filter module must be enabled for this to work.
925
            The variable $name is available and is the user\'s login username.
926
            Careful, bad PHP code here will break your site. If left empty, no name transformation will be done.
927
            <br/>Example:<br/>Given the user will logon with jdoe@xyz.com and you want the ldap UserName attribute to be
928
            jdoe.<br/><code>$parts = explode(\'@\', $name); if (count($parts) == 2) {print $parts[0]};</code>'),
929
          ),
930
        'schema' => array(
931
          'type' => 'varchar',
932
          'length' => 1024,
933
          'not null' => FALSE,
934
        ),
935
      ),
936

    
937
     'testing_drupal_username' =>  array(
938
        'form' => array(
939
          'fieldset' => 'users',
940
          '#type' => 'textfield',
941
          '#size' => 30,
942
          '#title' => t('Testing Drupal Username'),
943
          '#description' => t('This is optional and used for testing this server\'s configuration against an actual username.  The user need not exist in Drupal and testing will not affect the user\'s LDAP or Drupal Account.'),
944
        ),
945
        'schema' => array(
946
          'type' => 'varchar',
947
          'length' => 255,
948
          'not null' => FALSE,
949
        ),
950
      ),
951

    
952
     'testing_drupal_user_dn' =>  array(
953
        'form' => array(
954
          'fieldset' => 'users',
955
          '#type' => 'textfield',
956
          '#size' => 120,
957
          '#title' => t('DN of testing username, e.g. cn=hpotter,ou=people,dc=hogwarts,dc=edu'),
958
          '#description' => t('This is optional and used for testing this server\'s configuration against an actual username.  The user need not exist in Drupal and testing will not affect the user\'s LDAP or Drupal Account.'),
959
        ),
960
        'schema' => array(
961
          'type' => 'varchar',
962
          'length' => 255,
963
          'not null' => FALSE,
964
        ),
965
      ),
966

    
967
      'grp_unused' => array(
968
        'form' => array(
969
          'fieldset' => 'groups',
970
          '#type' => 'checkbox',
971
          '#title' => t('Groups are not relevant to this Drupal site.  This is generally true if LDAP Groups, LDAP Authorization, etc are not it use.'),
972
          '#disabled' => FALSE,
973
        ),
974
        'schema' => array(
975
          'type' => 'int',
976
          'size' => 'tiny',
977
          'not null' => FALSE,
978
          'default' => 0,
979
        ),
980
      ),
981

    
982
     'grp_object_cat' =>  array(
983
        'form' => array(
984
          'fieldset' => 'groups',
985
          '#type' => 'textfield',
986
          '#size' => 30,
987
          '#title' => t('Name of Group Object Class'),
988
          '#description' => t('e.g. groupOfNames, groupOfUniqueNames, group.'),
989
          '#states' => array(
990
              'visible' => array(   // action to take.
991
                ':input[name=grp_unused]' => array('checked' => FALSE),
992
              ),
993
            ),
994
        ),
995
        'schema' => array(
996
          'type' => 'varchar',
997
          'length' => 64,
998
          'not null' => FALSE,
999
        ),
1000
      ),
1001

    
1002
      'grp_nested' => array(
1003
        'form' => array(
1004
          'fieldset' => 'groups',
1005
          '#type' => 'checkbox',
1006
          '#title' => t('Nested groups are used in my LDAP'),
1007
          '#disabled' => FALSE,
1008
          '#description' => t('If a user is a member of group A and group A is a member of group B,
1009
             user should be considered to be in group A and B.  If your LDAP has nested groups, but you
1010
             want to ignore nesting, leave this unchecked.'),
1011
          '#states' => array(
1012
              'visible' => array(   // action to take.
1013
                ':input[name=grp_unused]' => array('checked' => FALSE),
1014
              ),
1015
            ),
1016
        ),
1017
        'schema' => array(
1018
          'type' => 'int',
1019
          'size' => 'tiny',
1020
          'not null' => FALSE,
1021
          'default' => 0,
1022
        ),
1023
      ),
1024

    
1025
      'grp_user_memb_attr_exists' => array(
1026
        'form' => array(
1027
          'fieldset' => 'groups',
1028
          '#type' => 'checkbox',
1029
          '#title' => t('A user LDAP attribute such as <code>memberOf</code> exists that contains a list of their groups.
1030
            Active Directory and openLdap with memberOf overlay fit this model.'),
1031
          '#disabled' => FALSE,
1032
          '#states' => array(
1033
             'visible' => array(   // action to take.
1034
               ':input[name=grp_unused]' => array('checked' => FALSE),
1035
              ),
1036
            ),
1037
        ),
1038
        'schema' => array(
1039
          'type' => 'int',
1040
          'size' => 'tiny',
1041
          'not null' => FALSE,
1042
          'default' => 0,
1043
        ),
1044
      ),
1045

    
1046
      'grp_user_memb_attr' =>  array(
1047
        'form' => array(
1048
          'fieldset' => 'groups',
1049
          '#type' => 'textfield',
1050
          '#size' => 30,
1051
          '#title' => t('Attribute in User Entry Containing Groups'),
1052
          '#description' => t('e.g. memberOf'),
1053
          '#states' => array(
1054
            'enabled' => array(   // action to take.
1055
              ':input[name=grp_user_memb_attr_exists]' => array('checked' => TRUE),
1056
            ),
1057
              'visible' => array(   // action to take.
1058
              ':input[name=grp_unused]' => array('checked' => FALSE),
1059
            ),
1060
          ),
1061
        ),
1062
        'schema' => array(
1063
          'type' => 'varchar',
1064
          'length' => 255,
1065
          'not null' => FALSE,
1066
        ),
1067
      ),
1068

    
1069
      'grp_memb_attr' =>  array(
1070
        'form' => array(
1071
          'fieldset' => 'groups',
1072
          '#type' => 'textfield',
1073
          '#size' => 30,
1074
          '#title' => t('LDAP Group Entry Attribute Holding User\'s DN, CN, etc.'),
1075
          '#description' => t('e.g uniquemember, memberUid'),
1076
          '#states' => array(
1077
              'visible' => array(   // action to take.
1078
                ':input[name=grp_unused]' => array('checked' => FALSE),
1079
              ),
1080
            ),
1081
        ),
1082
        'schema' => array(
1083
          'type' => 'varchar',
1084
          'length' => 255,
1085
          'not null' => FALSE,
1086
        ),
1087
      ),
1088

    
1089
      'grp_memb_attr_match_user_attr' =>  array(
1090
        'form' => array(
1091
          'fieldset' => 'groups',
1092
          '#type' => 'textfield',
1093
          '#size' => 30,
1094
          '#title' => t('User attribute held in "LDAP Group Entry Attribute Holding..."'),
1095
          '#description' => t('This is almost always "dn" (which technically isn\'t an attribute).  Sometimes its "cn".'),
1096
          '#states' => array(
1097
              'visible' => array(   // action to take.
1098
                ':input[name=grp_unused]' => array('checked' => FALSE),
1099
              ),
1100
            ),
1101
        ),
1102
        'schema' => array(
1103
          'type' => 'varchar',
1104
          'length' => 255,
1105
          'not null' => FALSE,
1106
        ),
1107
      ),
1108

    
1109
      'grp_derive_from_dn' => array(
1110
        'form' => array(
1111
          'fieldset' => 'groups',
1112
          '#type' => 'checkbox',
1113
          '#title' => t('Groups are derived from user\'s LDAP entry DN.') . '<em>' .
1114
            t('This
1115
            group definition has very limited functionality and most modules will
1116
            not take this into account.  LDAP Authorization will.') . '</em>',
1117
          '#disabled' => FALSE,
1118
          '#states' => array(
1119
              'visible' => array(   // action to take.
1120
                ':input[name=grp_unused]' => array('checked' => FALSE),
1121
              ),
1122
            ),
1123
        ),
1124
        'schema' => array(
1125
          'type' => 'int',
1126
          'size' => 'tiny',
1127
          'not null' => FALSE,
1128
          'default' => 0,
1129
        ),
1130
      ),
1131

    
1132
      'grp_derive_from_dn_attr' =>  array(
1133
        'form' => array(
1134
          'fieldset' => 'groups',
1135
          '#type' => 'textfield',
1136
          '#size' => 30,
1137
          '#title' => t('Attribute of the User\'s LDAP Entry DN which contains the group'),
1138
          '#description' => t('e.g. ou'),
1139
          '#states' => array(
1140
            'enabled' => array(   // action to take.
1141
              ':input[name=grp_derive_from_dn]' => array('checked' => TRUE),
1142
            ),
1143
              'visible' => array(   // action to take.
1144
              ':input[name=grp_unused]' => array('checked' => FALSE),
1145
            ),
1146
          ),
1147
        ),
1148
        'schema' => array(
1149
          'type' => 'varchar',
1150
          'length' => 255,
1151
          'not null' => FALSE,
1152
        ),
1153
      ),
1154

    
1155
     'grp_test_grp_dn' =>  array(
1156
        'form' => array(
1157
          'fieldset' => 'groups',
1158
          '#type' => 'textfield',
1159
          '#size' => 120,
1160
          '#title' => t('Testing LDAP Group DN'),
1161
          '#description' => t('This is optional and can be useful for debugging and validating forms.'),
1162
          '#states' => array(
1163
              'visible' => array(   // action to take.
1164
                ':input[name=grp_unused]' => array('checked' => FALSE),
1165
              ),
1166
            ),
1167
        ),
1168
        'schema' => array(
1169
          'type' => 'varchar',
1170
          'length' => 255,
1171
          'not null' => FALSE,
1172
        ),
1173
      ),
1174

    
1175
     'grp_test_grp_dn_writeable' =>  array(
1176
        'form' => array(
1177
          'fieldset' => 'groups',
1178
          '#type' => 'textfield',
1179
          '#size' => 120,
1180
          '#title' => t('Testing LDAP Group DN that is writable.  WARNING the test script for the server will create, delete, and add members to this group!'),
1181
          '#description' => t('This is optional and can be useful for debugging and validating forms.'),
1182
          '#states' => array(
1183
              'visible' => array(   // action to take.
1184
                ':input[name=grp_unused]' => array('checked' => FALSE),
1185
              ),
1186
            ),
1187
        ),
1188
        'schema' => array(
1189
          'type' => 'varchar',
1190
          'length' => 255,
1191
          'not null' => FALSE,
1192
        ),
1193
      ),
1194

    
1195
      'search_pagination' => array(
1196
        'form' => array(
1197
          'fieldset' => 'pagination',
1198
          '#type' => 'checkbox',
1199
          '#title' => t('Use LDAP Pagination.'),
1200
          '#disabled' => !ldap_servers_php_supports_pagination(),
1201
        ),
1202
        'schema' => array(
1203
          'type' => 'int',
1204
          'size' => 'tiny',
1205
          'not null' => FALSE,
1206
          'default' => 0,
1207
        ),
1208
      ),
1209

    
1210
     'search_page_size' =>  array(
1211
        'form' => array(
1212
          'fieldset' => 'pagination',
1213
          '#type' => 'textfield',
1214
          '#size' => 10,
1215
          '#disabled' => !ldap_servers_php_supports_pagination(),
1216
          '#title' => t('Pagination size limit.'),
1217
          '#description' => t('This should be equal to or smaller than the max
1218
            number of entries returned at a time by your ldap server.
1219
            1000 is a good guess when unsure. Other modules such as LDAP Query
1220
            or LDAP Feeds will be allowed to set a smaller page size, but not
1221
            a larger one.'),
1222
          '#states' => array(
1223
            'visible' => array(   // action to take.
1224
              ':input[name="search_pagination"]' => array('checked' => TRUE),
1225
            ),
1226
      ),
1227
        ),
1228
        'schema' => array(
1229
          'type' => 'int',
1230
          'size' => 'medium',
1231
          'not null' => FALSE,
1232
          'default' => 1000,
1233
        ),
1234
      ),
1235

    
1236
      'weight' =>  array(
1237
        'schema' => array(
1238
          'type' => 'int',
1239
          'not null' => FALSE,
1240
          'default' => 0,
1241
        ),
1242
      ),
1243

    
1244
    );
1245

    
1246
  return $fields;
1247

    
1248
  }
1249
}