Projet

Général

Profil

Paste
Télécharger (14,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ldap / ldap_test / LdapServerTest.class.php @ 32700c57

1
<?php
2

    
3
/**
4
 * @file
5
 * Simpletest ldapServer class for testing without an actual ldap server.
6
 */
7

    
8
/**
9
 * LDAP Server Class.
10
 *
11
 *  This class is used to create, work with, and eventually destroy ldap_server
12
 * objects.
13
 *
14
 * @todo make bindpw protected
15
 */
16

    
17
ldap_servers_module_load_include('php', 'ldap_servers', 'LdapServer.class');
18
/**
19
 *
20
 */
21
class LdapServerTest extends LdapServer {
22

    
23
  public $entries;
24
  public $methodResponses;
25
  public $searchResults;
26
  /**
27
   * Default to an anonymous bind.
28
   */
29
  public $binddn = FALSE;
30
  /**
31
   * Default to an anonymous bind.
32
   */
33
  public $bindpw = FALSE;
34

    
35
  /**
36
   * Constructor Method.
37
   *
38
   * Can take array of form property_name => property_value
39
   * or $sid, where sid is used to derive the include file.
40
   */
41
  public function __construct($sid) {
42
    if (!is_scalar($sid)) {
43
      $test_data = $sid;
44
      $sid = $test_data['sid'];
45
    }
46
    else {
47
      $test_data = variable_get('ldap_test_server__' . $sid, []);
48
    }
49

    
50
    $bindpw = (isset($test_data['bindpw'])) ? $test_data['bindpw'] : 'goodpwd';
51
    $this->sid = $sid;
52
    $this->refreshFakeData();
53
    $this->initDerivedProperties($bindpw);
54
  }
55

    
56
  /**
57
   *
58
   */
59
  public function refreshFakeData() {
60
    $test_data = variable_get('ldap_test_server__' . $this->sid, []);
61
    $this->methodResponses = (is_array($test_data) && isset($test_data['methodResponses'])) ? $test_data['methodResponses'] : [];
62
    $this->entries = (is_array($test_data) && isset($test_data['ldap'])) ? $test_data['ldap'] : [];
63
    $this->searchResults = (isset($test_data['search_results'])) ? $test_data['search_results'] : [];
64
    $this->detailedWatchdogLog = variable_get('ldap_help_watchdog_detail', 0);
65
    foreach ($test_data['properties'] as $property_name => $property_value) {
66
      $this->{$property_name} = $property_value;
67
    }
68
    if (isset($test_data['bindpw']) && $test_data['bindpw'] != '') {
69
      $this->bindpw = ldap_servers_decrypt($this->bindpw);
70
    }
71
  }
72

    
73
  /**
74
   * Destructor Method.
75
   */
76
  public function __destruct() {
77
    // If alterations to server configuration must be maintained throughout
78
    // simpletest, Call:
79
    // variable_set('ldap_authorization_test_server__'. $sid, []);.
80
  }
81

    
82
  /**
83
   * Connect Method.
84
   */
85
  public function connect() {
86
    return $this->methodResponses['connect'];
87
  }
88

    
89
  /**
90
   *
91
   */
92
  public function bind($userdn = NULL, $pass = NULL, $anon_bind = FALSE) {
93
    $userdn = ($userdn != NULL) ? $userdn : $this->binddn;
94
    $pass = ($pass != NULL) ? $pass : $this->bindpw;
95

    
96
    if (!isset($this->entries[$userdn])) {
97
      // 0x20 or 32.
98
      $ldap_errno = LDAP_NO_SUCH_OBJECT;
99
      if (function_exists('ldap_err2str')) {
100
        $ldap_error = ldap_err2str($ldap_errno);
101
      }
102
      else {
103
        $ldap_error = "Failed to find $userdn in LdapServerTest.class.php";
104
      }
105
    }
106
    elseif (isset($this->entries[$userdn]['password'][0]) && $this->entries[$userdn]['password'][0] == $pass && $pass) {
107
      return LDAP_SUCCESS;
108
    }
109
    else {
110
      if (!$pass) {
111
        debug("Simpletest failure for $userdn.  No password submitted");
112
      }
113
      if (!isset($this->entries[$userdn]['password'][0])) {
114
        debug("Simpletest failure for $userdn.  No password in entry to test for bind"); debug($this->entries[$userdn]);
115
      }
116
      $ldap_errno = LDAP_INVALID_CREDENTIALS;
117
      if (function_exists('ldap_err2str')) {
118
        $ldap_error = ldap_err2str($ldap_errno);
119
      }
120
      else {
121
        $ldap_error = "Credentials for $userdn failed in LdapServerTest.class.php";
122
      }
123
    }
124

    
125
    $watchdog_tokens = ['%user' => $userdn, '%errno' => $ldap_errno, '%error' => $ldap_error];
126
    watchdog('ldap_servers', "LDAP bind failure for user %user. Error %errno: %error", $watchdog_tokens);
127
    return $ldap_errno;
128

    
129
  }
130

    
131
  /**
132
   * Disconnect (unbind) from an active LDAP server.
133
   */
134
  public function disconnect() {
135

    
136
  }
137

    
138
  /**
139
   * Perform an LDAP search.
140
   *
141
   * @param string $filter
142
   *   The search filter. such as sAMAccountName=jbarclay.
143
   * @param string $basedn
144
   *   The search base. If NULL, we use $this->basedn.
145
   * @param array $attributes
146
   *   List of desired attributes. If omitted, we only return "dn".
147
   *
148
   * @return
149
   *   An array of matching entries->attributes, or FALSE if the search is
150
   *   empty.
151
   */
152
  public function search($base_dn = NULL, $filter, $attributes = [], $attrsonly = 0, $sizelimit = 0, $timelimit = 0, $deref = LDAP_DEREF_NEVER, $scope = LDAP_SCOPE_SUBTREE) {
153

    
154
    $lcase_attribute = [];
155
    foreach ($attributes as $i => $attribute_name) {
156
      $lcase_attribute[] = drupal_strtolower($attribute_name);
157
    }
158
    $attributes = $lcase_attribute;
159

    
160
    // For test matching simplicity remove line breaks and tab spacing.
161
    $filter = trim(str_replace(["\n", "  "], ['', ''], $filter));
162

    
163
    if ($base_dn == NULL) {
164
      if (count($this->basedn) == 1) {
165
        $base_dn = $this->basedn[0];
166
      }
167
      else {
168
        return FALSE;
169
      }
170
    }
171

    
172
    /**
173
     * Search CASE 1: for some mock ldap servers, a set of fixed ldap filters
174
     * are prepolulated in test data
175
     */
176
    if (isset($this->searchResults[$filter][$base_dn])) {
177
      $results = $this->searchResults[$filter][$base_dn];
178
      foreach ($results as $i => $entry) {
179
        if (is_array($entry) && isset($entry['FULLENTRY'])) {
180
          unset($results[$i]['FULLENTRY']);
181
          $dn = $results[$i]['dn'];
182
          $results[$i] = $this->entries[$dn];
183
          $results[$i]['dn'] = $dn;
184
        }
185
      }
186
      return $results;
187
    }
188

    
189
    /**
190
     * Search CASE 2: attempt to programmatically evaluate ldap filter
191
     * by looping through fake ldap entries
192
     */
193
    $base_dn = drupal_strtolower($base_dn);
194
    $filter = trim($filter, "()");
195
    $subqueries = [];
196
    $operand = FALSE;
197

    
198
    if (strpos($filter, '&') === 0) {
199
      /**
200
     * case 2.A.: filter of form (&(<attribute>=<value>)(<attribute>=<value>)(<attribute>=<value>))
201
     *  such as (&(samaccountname=hpotter)(samaccountname=hpotter)(samaccountname=hpotter))
202
     */
203
      $operand = '&';
204
      $filter = substr($filter, 1);
205
      $filter = trim($filter, "()");
206
      $parts = explode(')(', $filter);
207
      foreach ($parts as $i => $pair) {
208
        $subqueries[] = explode('=', $pair);
209
      }
210
    }
211
    elseif (strpos($filter, '|') === 0) {
212
      /**
213
     * case 2.B: filter of form (|(<attribute>=<value>)(<attribute>=<value>)(<attribute>=<value>))
214
     *  such as (|(samaccountname=hpotter)(samaccountname=hpotter)(samaccountname=hpotter))
215
     */
216
      $operand = '|';
217
      $filter = substr($filter, 1);
218
      $filter = trim($filter, "()");
219
      $parts = explode(')(', $filter);
220
      $parts = explode(')(', $filter);
221
      foreach ($parts as $i => $pair) {
222
        $subqueries[] = explode('=', $pair);
223
      }
224
    }
225
    elseif (count(explode('=', $filter)) == 2) {
226
      /**
227
     * case 2.C.: filter of form (<attribute>=<value>)
228
     *  such as (samaccountname=hpotter)
229
     */
230
      $operand = '|';
231
      $subqueries[] = explode('=', $filter);
232
    }
233
    else {
234
      return FALSE;
235
    }
236

    
237
    // Need to perform feaux ldap search here with data in.
238
    $results = [];
239

    
240
    if ($operand == '|') {
241
      foreach ($subqueries as $i => $subquery) {
242
        $filter_attribute = drupal_strtolower($subquery[0]);
243
        $filter_value = $subquery[1];
244
        foreach ($this->entries as $dn => $entry) {
245
          $dn_lcase = drupal_strtolower($dn);
246

    
247
          // If not in basedn, skip
248
          // eg. basedn ou=campus accounts,dc=ad,dc=myuniversity,dc=edu
249
          // should be leftmost string in:
250
          // cn=jdoe,ou=campus accounts,dc=ad,dc=myuniversity,dc=edu.
251
          $substring = strrev(substr(strrev($dn_lcase), 0, strlen($base_dn)));
252
          $cascmp = strcasecmp($base_dn, $substring);
253
          if ($cascmp !== 0) {
254

    
255
            // Not in basedn.
256
            continue;
257
          }
258
          // If doesn't filter attribute has no data, continue.
259
          $attr_value_to_compare = FALSE;
260
          foreach ($entry as $attr_name => $attr_value) {
261
            if (drupal_strtolower($attr_name) == $filter_attribute) {
262
              $attr_value_to_compare = $attr_value;
263
              break;
264
            }
265
          }
266
          if (!$attr_value_to_compare || drupal_strtolower($attr_value_to_compare[0]) != $filter_value) {
267
            continue;
268
          }
269

    
270
          // match!
271
          $entry['dn'] = $dn;
272
          if ($attributes) {
273
            $selected_data = [];
274
            foreach ($attributes as $i => $attr_name) {
275
              $selected_data[$attr_name] = (isset($entry[$attr_name])) ? $entry[$attr_name] : NULL;
276
            }
277
            $results[] = $selected_data;
278
          }
279
          else {
280
            $results[] = $entry;
281
          }
282
        }
283
      }
284
    }
285
    // Reverse the loops.
286
    elseif ($operand == '&') {
287
      foreach ($this->entries as $dn => $entry) {
288
        $dn_lcase = drupal_strtolower($dn);
289
        // Until 1 subquery fails.
290
        $match = TRUE;
291
        foreach ($subqueries as $i => $subquery) {
292
          $filter_attribute = drupal_strtolower($subquery[0]);
293
          $filter_value = $subquery[1];
294

    
295
          $substring = strrev(substr(strrev($dn_lcase), 0, strlen($base_dn)));
296
          $cascmp = strcasecmp($base_dn, $substring);
297
          if ($cascmp !== 0) {
298
            $match = FALSE;
299
            // Not in basedn.
300
            break;
301
          }
302
          // If doesn't filter attribute has no data, continue.
303
          $attr_value_to_compare = FALSE;
304
          foreach ($entry as $attr_name => $attr_value) {
305
            if (drupal_strtolower($attr_name) == $filter_attribute) {
306
              $attr_value_to_compare = $attr_value;
307
              break;
308
            }
309
          }
310
          if (!$attr_value_to_compare || drupal_strtolower($attr_value_to_compare[0]) != $filter_value) {
311
            $match = FALSE;
312
            // Not in basedn.
313
            break;
314
          }
315

    
316
        }
317
        if ($match === TRUE) {
318
          $entry['dn'] = $dn;
319
          if ($attributes) {
320
            $selected_data = [];
321
            foreach ($attributes as $i => $attr_name) {
322
              $selected_data[$attr_name] = (isset($entry[$attr_name])) ? $entry[$attr_name] : NULL;
323
            }
324
            $results[] = $selected_data;
325
          }
326
          else {
327
            $results[] = $entry;
328
          }
329
        }
330
      }
331
    }
332

    
333
    $results['count'] = count($results);
334
    return $results;
335
  }
336

    
337
  /**
338
   * Does dn exist for this server?
339
   *
340
   * @param string $dn
341
   * @param enum $return
342
   *   = 'boolean' or 'ldap_entry'.
343
   *
344
   * @param return FALSE or ldap entry array
345
   */
346
  public function dnExists($find_dn, $return = 'boolean', $attributes = ['objectclass']) {
347
    $this->refreshFakeData();
348
    $test_data = variable_get('ldap_test_server__' . $this->sid, []);
349
    foreach ($this->entries as $entry_dn => $entry) {
350
      $match = (strcasecmp($entry_dn, $find_dn) == 0);
351

    
352
      if ($match) {
353
        return ($return == 'boolean') ? TRUE : $entry;
354
      }
355
    }
356
    // Not match found in loop.
357
    return FALSE;
358

    
359
  }
360

    
361
  /**
362
   *
363
   */
364
  public function countEntries($ldap_result) {
365
    return ldap_count_entries($this->connection, $ldap_result);
366
  }
367

    
368
  /**
369
   *
370
   */
371
  public static function getLdapServerObjects($sid = NULL, $type = NULL, $flatten = FALSE) {
372
    $servers = [];
373
    if ($sid) {
374
      $servers[$sid] = new LdapServerTest($sid);
375
    }
376
    else {
377
      $server_ids = variable_get('ldap_test_servers', []);
378
      foreach ($server_ids as $sid => $_sid) {
379
        $servers[$sid] = new LdapServerTest($sid);
380
      }
381
    }
382

    
383
    if ($flatten && $sid) {
384
      return $servers[$sid];
385
    }
386
    else {
387
      return $servers;
388
    }
389
  }
390

    
391
  /**
392
   * Create ldap entry.
393
   *
394
   * @param array $ldap_entry
395
   *   should follow the structure of ldap_add functions
396
   *   entry array: http://us.php.net/manual/en/function.ldap-add.php
397
   *   $attributes["attribute1"] = "value";
398
   *   $attributes["attribute2"][0] = "value1";
399
   *   $attributes["attribute2"][1] = "value2";.
400
   *
401
   * @return boolean result
402
   */
403
  public function createLdapEntry($ldap_entry, $dn = NULL) {
404
    $result = FALSE;
405
    $test_data = variable_get('ldap_test_server__' . $this->sid, []);
406

    
407
    if (isset($ldap_entry['dn'])) {
408
      $dn = $ldap_entry['dn'];
409
      unset($ldap_entry['dn']);
410
    }
411

    
412
    if ($dn && !isset($test_data['entries'][$dn])) {
413
      $test_data['entries'][$dn] = $ldap_entry;
414
      $test_data['ldap'][$dn] = $ldap_entry;
415
      variable_set('ldap_test_server__' . $this->sid, $test_data);
416
      $this->refreshFakeData();
417
      $result = TRUE;
418
    }
419
    return $result;
420
  }
421

    
422
  /**
423
   *
424
   */
425
  public function modifyLdapEntry($dn, $attributes = NULL, $old_attributes = FALSE) {
426
    if (!$attributes) {
427
      $attributes = [];
428
    }
429
    $test_data = variable_get('ldap_test_server__' . $this->sid, []);
430
    if (!isset($test_data['entries'][$dn])) {
431
      return FALSE;
432
    }
433
    $ldap_entry = $test_data['entries'][$dn];
434

    
435
    foreach ($attributes as $key => $cur_val) {
436
      if ($cur_val == '') {
437
        unset($ldap_entry[$key]);
438
      }
439
      elseif (is_array($cur_val)) {
440
        foreach ($cur_val as $mv_key => $mv_cur_val) {
441
          if ($mv_cur_val == '') {
442
            unset($ldap_entry[$key][$mv_key]);
443
          }
444
          else {
445
            if (is_array($mv_cur_val)) {
446
              $ldap_entry[$key][$mv_key] = $mv_cur_val;
447
            }
448
            else {
449
              $ldap_entry[$key][$mv_key][] = $mv_cur_val;
450
            }
451
          }
452
        }
453
        unset($ldap_entry[$key]['count']);
454
        $ldap_entry[$key]['count'] = count($ldap_entry[$key]);
455
      }
456
      else {
457
        $ldap_entry[$key][0] = $cur_val;
458
        $ldap_entry[$key]['count'] = count($ldap_entry[$key]);
459
      }
460
    }
461

    
462
    $test_data['entries'][$dn] = $ldap_entry;
463
    $test_data['ldap'][$dn] = $ldap_entry;
464
    variable_set('ldap_test_server__' . $this->sid, $test_data);
465
    $this->refreshFakeData();
466
    return TRUE;
467

    
468
  }
469

    
470
  /**
471
   * Perform an LDAP delete.
472
   *
473
   * @param string $dn
474
   *
475
   * @return boolean result per ldap_delete
476
   */
477
  public function delete($dn) {
478

    
479
    $test_data = variable_get('ldap_test_server__' . $this->sid, []);
480
    $deleted = FALSE;
481
    foreach (['entries', 'users', 'groups', 'ldap'] as $test_data_sub_array) {
482
      if (isset($test_data[$test_data_sub_array][$dn])) {
483
        unset($test_data[$test_data_sub_array][$dn]);
484
        $deleted = TRUE;
485
      }
486
    }
487
    if ($deleted) {
488
      variable_set('ldap_test_server__' . $this->sid, $test_data);
489
      $this->refreshFakeData();
490
      return TRUE;
491
    }
492
    else {
493
      return FALSE;
494
    }
495

    
496
  }
497

    
498
}