Projet

Général

Profil

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

root / drupal7 / sites / all / modules / ldap / ldap_authorization / LdapAuthorizationConsumerAbstract.class.php @ 91af538d

1
<?php
2

    
3
/**
4
 * @file
5
 * Abstract class to represent an ldap_authorization consumer behavior
6
 * such as drupal_role, og_group, etc.  each authorization comsumer
7
 * will extend this class with its own class named
8
 * LdapAuthorizationConsumer<consumer type> such as LdapAuthorizationConsumerDrupalRole.
9
 */
10

    
11
/**
12
 *
13
 */
14
class LdapAuthorizationConsumerAbstract {
15

    
16
  /**
17
   * Machine name of consumer.  e.g. og_group, drupal_role, etc.
18
   */
19
  public $consumerType = NULL;
20

    
21
  /**
22
   * The following properties are generally populated from a
23
   * call to hook_ldap_authorization_consumer()
24
   */
25

    
26
  /**
27
   * User interface name of consumer. e.g.  drupal role, og group.
28
   */
29
  public $name;
30

    
31
  /**
32
   * User interface name of consumer. e.g. drupal roles, og groups.
33
   */
34
  public $namePlural;
35
  /**
36
   * User interface short name of consumer. e.g. role, group.
37
   */
38
  public $shortName;
39

    
40
  /**
41
   * User interface short name of consumer plural, e.g. roles, groups.
42
   */
43
  public $shortNamePlural;
44

    
45
  /**
46
   * E.g. roles, groups.
47
   */
48
  public $description;
49
  /**
50
   * Module providing consumer functionality e.g. ldap_authorization_drupal_roles.
51
   */
52
  public $consumerModule;
53

    
54
  /**
55
   * LDAPConsumerConf object class encapuslating admin form.
56
   */
57
  public $consumerConf;
58

    
59
  /**
60
   * Link to test this consumer.
61
   */
62
  public $testLink;
63

    
64
  /**
65
   * Link to configure this consumer.
66
   */
67
  public $editLink;
68

    
69
  public $emptyConsumer = [
70
    'exists' => TRUE,
71
    'value' => NULL,
72
    'name' => NULL,
73
    'map_to_string' => NULL,
74
  ];
75

    
76
  /**
77
   * @property boolean $allowConsumerObjectCreation
78
   *
79
   *  Does this consumer module support creating consumer objects
80
   * (drupal roles,  og groups, etc.)
81
   */
82

    
83
  public $allowConsumerObjectCreation = FALSE;
84

    
85
  /**
86
   * @property boolean $detailedWatchdogLog
87
   *
88
   *  should watchdog log be used for debugging, useful for non programmers
89
   *  who don't have php debugging enabled
90
   */
91
  public $detailedWatchdogLog = FALSE;
92

    
93

    
94
  /**
95
   * @property array $defaultConsumerConfProperties
96
   * default properties for consumer admin UI form
97
   */
98
  public $defaultConsumerConfProperties = [
99
    'onlyApplyToLdapAuthenticated' => TRUE,
100
    'useMappingsAsFilter' => TRUE,
101
    'synchOnLogon' => TRUE,
102
    'revokeLdapProvisioned' => TRUE,
103
    'regrantLdapProvisioned' => TRUE,
104
    'createConsumers' => TRUE,
105
  ];
106

    
107
  /**
108
   * Constructor Method.
109
   *
110
   * @param string $consumer_type
111
   *   e.g. drupal_role, og_group.
112
   * @param array $params
113
   *   as associative array of default properties.
114
   */
115
  public function __construct($consumer_type, $params) {
116
    $this->consumerType = $consumer_type;
117
    $this->name = $params['consumer_name'];
118
    $this->namePlural = $params['consumer_name_plural'];
119
    $this->shortName = $params['consumer_short_name'];
120
    $this->shortNamePlural = $params['consumer_short_name_plural'];
121
    $this->consumerModule = $params['consumer_module'];
122
    $this->mappingDirections = $params['consumer_mapping_directions'];
123
    $this->testLink = l(t('test') . ' ' . $this->name, LDAP_SERVERS_MENU_BASE_PATH . '/authorization/test/' . $this->consumerType);
124
    $this->editLink = l(t('edit') . ' ' . $this->name, LDAP_SERVERS_MENU_BASE_PATH . '/authorization/edit/' . $this->consumerType);
125
    ldap_servers_module_load_include('php', 'ldap_authorization', 'LdapAuthorizationConsumerConfAdmin.class');
126
    $this->consumerConf = new LdapAuthorizationConsumerConf($this);
127
  }
128

    
129
  /**
130
   * Function to normalize mappings.
131
   *
132
   * Should be overridden when mappings are not stored as map|authorization_id format
133
   * where authorization_id is the format returned by
134
   * LdapAuthorizationConsumerAbstract::usersAuthorizations()
135
   *
136
   * For example ldap_authorization_og may store mapping target as:
137
   * Campus Accounts|group-name=knitters,role-name=administrator member
138
   * normalized mappings are of form such as for organic groups:
139
   * [
140
   *   [
141
   *     'from' => 'students',
142
   *     'normalized' => 'node:21:1',
143
   *     'simplified' => 'node:students:member',
144
   *     'user_entered' => 'students'
145
   *     'valid' => TRUE,
146
   *     'error_message' => '',
147
   *   ],
148
   * ...
149
   * ]
150
   *
151
   * Or for Drupal role where rid 3 is moderator and rid 2 is admin:
152
   * [
153
   *   [
154
   *     'from' => 'students',
155
   *     'normalized' => '2',
156
   *     'simplified' => 'admin',
157
   *     'user_entered' => 'admin',
158
   *     'valid' => TRUE,
159
   *     'error_message' => '',
160
   *   ],
161
   * ...
162
   * ]
163
   *
164
   * Where 'normalized' is in id format and 'simplified' is user shorthand.
165
   */
166
  public function normalizeMappings($mappings) {
167
    return $mappings;
168
  }
169

    
170
  /**
171
   * Create authorization consumers.
172
   *
173
   * @param string (lowercase) $consumer_id
174
   * @param array $consumer
175
   *   as associative array with the following key/values
176
   *   'value' => NULL | mixed consumer such as drupal role name, og group entity, etc.
177
   *   'name' => name of consumer for UI, logging etc.
178
   *   'map_to_string' => string mapped to in ldap authorization.  mixed case string
179
   *   'exists' => TRUE indicates consumer is known to exist,
180
   *               FALSE indicates consumer is known to not exist,
181
   *               NULL indicate consumer's existance not checked yet.
182
   */
183
  public function createConsumer($consumer_id, $consumer) {
184
    // Method must be overridden.
185
  }
186

    
187
  /**
188
   * Populate consumer side of $consumers array.
189
   *
190
   * @param array $consumers
191
   *   as associative array keyed on $consumer_id with values
192
   *   of $consumer.  $consumer_id and $consumer have structure in LdapAuthorizationConsumerAbstractClass::createConsumer
193
   *   when values are $consumer['exists'] != TRUE need to be populated by consumer object.
194
   * @param bool $create_missing_consumers
195
   *   indicates if consumers (drupal roles, og groups, etc) should be created
196
   *   if values are NULL, object will be created if.
197
   *
198
   * @return $consumers by reference
199
   */
200
  public function populateConsumersFromConsumerIds(&$consumers, $create_missing_consumers = FALSE) {
201
    // Method must be overridden.
202
  }
203

    
204
  /**
205
   *
206
   */
207
  public function authorizationDiff($initial, $current) {
208
    return array_diff($initial, $current);
209
  }
210

    
211
  /**
212
   * Grant authorizations to a user.
213
   *
214
   * @param object $user
215
   *   drupal user object.
216
   * @param array $consumers
217
   *   in form of LdapAuthorizationConsumerAbstractClass::populateConsumersFromConsumerIds.
218
   * @param array $ldap_entry
219
   *   is ldap data from ldap entry which drupal user is mapped to.
220
   * @param bool $user_save
221
   *   should user object be saved by authorizationGrant method.
222
   *
223
   * @return array $results.  Array of form
224
   *   array(
225
   *    <authz consumer id1> => 1,
226
   *    <authz consumer id2> => 0,
227
   *   )
228
   *   where 1s and 0s represent success and failure to grant
229
   *
230
   *
231
   *   method may be desireable to override, if consumer benefits from adding grants as a group rather than one at a time
232
   */
233
  public function authorizationGrant(&$user, &$user_auth_data, $consumers, $ldap_entry = NULL, $user_save = TRUE) {
234
    $this->filterOffPastAuthorizationRecords($user, $user_auth_data);
235
    $this->grantsAndRevokes('grant', $user, $user_auth_data, $consumers, $ldap_entry, $user_save);
236
  }
237

    
238
  /**
239
   * Revoke authorizations to a user.
240
   *
241
   * @param object $user
242
   *   drupal user object.
243
   * @param array $consumers
244
   *   in form of LdapAuthorizationConsumerAbstractClass::populateConsumersFromConsumerIds.
245
   * @param array $ldap_entry
246
   *   is ldap data from ldap entry which drupal user is mapped to.
247
   * @param bool $user_save
248
   *   should user object be saved by authorizationGrant method.
249
   *
250
   * @return array $results.  Array of form
251
   *   array(
252
   *    <authz consumer id1> => 1,
253
   *    <authz consumer id2> => 0,
254
   *   )
255
   *   where 1s and 0s represent success and failure to revoke
256
   *   $user_auth_data is returned by reference
257
   *
258
   *   method may be desireable to override, if consumer benefits from revoking grants as a group rather than one at a time
259
   */
260
  public function authorizationRevoke(&$user, &$user_auth_data, $consumers, $ldap_entry, $user_save = TRUE) {
261
    $this->filterOffPastAuthorizationRecords($user, $user_auth_data);
262
    $this->grantsAndRevokes('revoke', $user, $user_auth_data, $consumers, $ldap_entry, $user_save);
263
  }
264

    
265
  /**
266
   * This is a function to clear off.
267
   */
268
  public function filterOffPastAuthorizationRecords(&$user, &$user_auth_data, $time = NULL) {
269
    if ($time != NULL || variable_get('ldap_help_user_data_clear', 0)) {
270
      $clear_time = ($time) ? $time : variable_get('ldap_help_user_data_clear_set_date', 0);
271
      if ($clear_time > 0 && $clear_time < time()) {
272
        foreach ($user_auth_data as $consumer_id => $entry) {
273
          if ($entry['date_granted'] < $clear_time) {
274
            unset($user_auth_data[$consumer_id]);
275
            if (isset($user->data['ldap_authorizations'][$this->consumerType][$consumer_id])) {
276
              unset($user->data['ldap_authorizations'][$this->consumerType][$consumer_id]);
277
            }
278
          }
279
        }
280
      }
281
    }
282
  }
283

    
284
  /**
285
   * Some authorization schemes such as organic groups, require a certain order.  implement this method
286
   * to sort consumer ids/authorization ids.
287
   *
288
   * @param string $op
289
   *   'grant' or 'revoke' signifying what to do with the $consumer_ids.
290
   * @param $consumers
291
   *   associative array in form of LdapAuthorizationConsumerAbstract::populateConsumersFromConsumerIds
292
   *
293
   *   alters $consumers by reference
294
   */
295
  public function sortConsumerIds($op, &$consumers) {}
296

    
297
  /**
298
   * Attempt to flush related caches.  This will be something like og_invalidate_cache($gids)
299
   *
300
   * @param $consumers
301
   *   associative array in form of LdapAuthorizationConsumerAbstract::populateConsumersFromConsumerIds
302
   */
303
  public function flushRelatedCaches($consumers = NULL) {}
304

    
305
  /**
306
   * @param string $op
307
   *   'grant' or 'revoke' signifying what to do with the $consumer_ids.
308
   * @param drupal user object $object
309
   * @param array $user_auth_data
310
   *   is array specific to this consumer_type.  Stored at $user->data['ldap_authorizations'][<consumer_type>].
311
   * @param $consumers
312
   *   as associative array in form of LdapAuthorizationConsumerAbstract::populateConsumersFromConsumerIds
313
   * @param array $ldap_entry,
314
   *   when available user's ldap entry.
315
   * @param bool $user_save
316
   *   indicates is user data array should be saved or not.  this depends on the implementation calling this function.
317
   */
318
  protected function grantsAndRevokes($op, &$user, &$user_auth_data, $consumers, &$ldap_entry = NULL, $user_save = TRUE) {
319

    
320
    if (!is_array($user_auth_data)) {
321
      $user_auth_data = [];
322
    }
323

    
324
    $detailed_watchdog_log = variable_get('ldap_help_watchdog_detail', 0);
325
    $this->sortConsumerIds($op, $consumers);
326
    $results = [];
327
    $watchdog_tokens = [];
328
    $watchdog_tokens['%username'] = $user->name;
329
    $watchdog_tokens['%action'] = $op;
330
    $watchdog_tokens['%user_save'] = $user_save;
331
    $consumer_ids_log = [];
332
    $users_authorization_ids = $this->usersAuthorizations($user);
333
    $watchdog_tokens['%users_authorization_ids'] = join(', ', $users_authorization_ids);
334
    if ($detailed_watchdog_log) {
335
      watchdog('ldap_authorization', "on call of grantsAndRevokes: user_auth_data=" . print_r($user_auth_data, TRUE), $watchdog_tokens, WATCHDOG_DEBUG);
336
    }
337

    
338
    foreach ($consumers as $consumer_id => $consumer) {
339
      if ($detailed_watchdog_log) {
340
        watchdog('ldap_authorization', "consumer_id=$consumer_id, user_save=$user_save, op=$op", $watchdog_tokens, WATCHDOG_DEBUG);
341
      }
342
      $log = "consumer_id=$consumer_id, op=$op,";
343
      $user_has_authorization = in_array($consumer_id, $users_authorization_ids);
344
      $user_has_authorization_recorded = isset($user_auth_data[$consumer_id]);
345

    
346
      /** grants **/
347
      if ($op == 'grant') {
348
        if ($user_has_authorization && !$user_has_authorization_recorded) {
349
          // Grant case 1: authorization id already exists for user, but is not ldap provisioned.  mark as ldap provisioned, but don't regrant.
350
          $results[$consumer_id] = TRUE;
351
          $user_auth_data[$consumer_id] = [
352
            'date_granted' => time(),
353
            'consumer_id_mixed_case' => $consumer_id,
354
          ];
355
        }
356
        elseif (!$user_has_authorization && $consumer['exists']) {
357
          // Grant case 2: consumer exists, but user is not member. grant authorization
358
          // allow consuming module to add additional data to $user_auth_data.
359
          $results[$consumer_id] = $this->grantSingleAuthorization($user, $consumer_id, $consumer, $user_auth_data, $user_save);
360
          $existing = empty($user_auth_data[$consumer_id]) ? [] : $user_auth_data[$consumer_id];
361
          $user_auth_data[$consumer_id] = $existing + [
362
            'date_granted' => time(),
363
            'consumer_id_mixed_case' => $consumer_id,
364
          ];
365
        }
366
        elseif ($consumer['exists'] !== TRUE) {
367
          // Grant case 3: something is wrong. consumers should have been created before calling grantsAndRevokes.
368
          $results[$consumer_id] = FALSE;
369
        }
370
        elseif ($consumer['exists'] === TRUE) {
371
          // Grant case 4: consumer exists and user has authorization recorded. do nothing.
372
          $results[$consumer_id] = TRUE;
373
        }
374
        else {
375
          // Grant case 5: $consumer['exists'] has not been properly set before calling function.
376
          $results[$consumer_id] = FALSE;
377
          watchdog('ldap_authorization', "grantsAndRevokes consumer[exists] not properly set. consumer_id=$consumer_id, op=$op, username=%username", $watchdog_tokens, WATCHDOG_ERROR);
378
        }
379
      }
380
      /** revokes **/
381
      elseif ($op == 'revoke') {
382

    
383
        $log .= "revoking existing consumer object, ";
384
        if ($user_has_authorization) {
385
          // Revoke case 1: user has authorization, revoke it.  revokeSingleAuthorization will remove $user_auth_data[$consumer_id]
386
          // defer to default for $user_save param.
387
          $results[$consumer_id] = $this->revokeSingleAuthorization($user, $consumer_id, $consumer, $user_auth_data, $user_save);
388
          $log .= t(',result=') . (boolean) ($results[$consumer_id]);
389
        }
390
        elseif ($user_has_authorization_recorded) {
391
          // Revoke case 2: user does not have authorization, but has record of it. remove record of it.
392
          unset($user_auth_data[$consumer_id]);
393
          $results[$consumer_id] = TRUE;
394
        }
395
        else {
396
          // Revoke case 3: trying to revoke something that isn't there.
397
          $results[$consumer_id] = TRUE;
398
        }
399

    
400
      }
401
      $consumer_ids_log[] = $log;
402
      if ($detailed_watchdog_log) {
403
        watchdog('ldap_authorization', "user_auth_data after consumer $consumer_id" . print_r($user_auth_data, TRUE), $watchdog_tokens, WATCHDOG_DEBUG);
404
      }
405

    
406
    }
407
    $watchdog_tokens['%consumer_ids_log'] = (count($consumer_ids_log)) ? join('<hr/>', $consumer_ids_log) : t('no actions');
408

    
409
    if ($user_save) {
410
      $user = user_load($user->uid, TRUE);
411
      $user_edit = $user->data;
412
      $user_edit['data']['ldap_authorizations'][$this->consumerType] = $user_auth_data;
413
      $user = user_save($user, $user_edit);
414
      // Reload this.
415
      $user_auth_data = $user->data['ldap_authorizations'][$this->consumerType];
416
    }
417
    $this->flushRelatedCaches($consumers);
418

    
419
    if ($detailed_watchdog_log) {
420
      watchdog('ldap_authorization', '%username:
421
        <hr/>LdapAuthorizationConsumerAbstract grantsAndRevokes() method log.  action=%action:<br/> %consumer_ids_log
422
        ',
423
        $watchdog_tokens, WATCHDOG_DEBUG);
424
    }
425

    
426
  }
427

    
428
  /**
429
   * @param drupal user object $user
430
   *   to have $consumer_id revoked.
431
   * @param string lower case $consumer_id
432
   *   $consumer_id such as drupal role name, og group name, etc.
433
   * @param mixed $consumer
434
   *   depends on type of consumer.  Drupal roles are strings, og groups are ??
435
   * @param array $user_auth_data
436
   *   array of $user data specific to this consumer type.
437
   *   stored in $user->data['ldap_authorizations'][<consumer_type>] array.
438
   * @param bool $reset
439
   *   signifying if caches associated with $consumer_id should be invalidated.
440
   *
441
   *   return boolen TRUE on success, FALSE on fail.  If user save is FALSE, the user object will
442
   *   not be saved and reloaded, so a returned TRUE may be misleading.
443
   *   $user_auth_data should have successfully revoked consumer id removed.
444
   */
445
  public function revokeSingleAuthorization(&$user, $consumer_id, $consumer, &$user_auth_data, $user_save = FALSE, $reset = FALSE) {
446
    // Method must be overridden.
447
  }
448

    
449
  /**
450
   * @param object $user
451
   *   as drupal user object to have $consumer_id granted.
452
   * @param string lower case $consumer_id
453
   *   $consumer_id such as drupal role name, og group name, etc.
454
   * @param mixed $consumer
455
   *   depends on type of consumer.  Drupal roles are strings, og groups are ??
456
   * @param array $user_auth_data
457
   *   in form
458
   *   array('my drupal role' =>
459
   *     'date_granted' => 1351814718,
460
   *     'consumer_id_mixed_case' => 'My Drupal Role',
461
   *     )
462
   * @param bool $reset
463
   *   signifying if caches associated with $consumer_id should be invalidated.
464
   * @return boolean FALSE on failure or TRUE on success
465
   */
466
  public function grantSingleAuthorization(&$user, $consumer_id, $consumer, &$user_auth_data, $user_save = FALSE, $reset = FALSE) {
467
    // Method must be overridden.
468
  }
469

    
470
  /**
471
   * Return all user consumer ids
472
   *   regardless of it they were granted by this module.
473
   *
474
   * @param user object $user
475
   *
476
   * @return array of consumer ids such as array('3-2','7-2'), array('admin','user_admin')
477
   */
478
  public function usersAuthorizations(&$user) {
479
    // Method must be overridden.
480
  }
481

    
482
  /**
483
   * Put authorization ids in displayable format.
484
   */
485
  public function convertToFriendlyAuthorizationIds($authorizations) {
486
    return $authorizations;
487
  }
488

    
489
  /**
490
   * @param drupal user object $user
491
   *   to have $consumer_id granted.
492
   * @param string lower case $consumer_id
493
   *   $consumer_id such as drupal role name, og group name, etc.
494
   * @param mixed $consumer
495
   *   depends on type of consumer.  Drupal roles are strings, og groups are ??
496
   *
497
   *   return boolen TRUE on success, FALSE on fail.  If user save is FALSE, the user object will
498
   *   not be saved and reloaded, so a returned TRUE may be misleading.
499
   */
500
  public function createSingleAuthorization(&$user, $consumer_id, $consumer, &$user_auth_data) {
501
    // Method must be overridden.
502
  }
503

    
504
  /**
505
   * @param drupal user object $user
506
   * @param string lowercase $consumer_id
507
   *   such as drupal role name, og group name, etc.
508
   *
509
   * @return boolean if an ldap_authorization_* module granted the authorization id
510
   */
511
  public function hasLdapGrantedAuthorization(&$user, $consumer_id) {
512
    return (!empty($user->data['ldap_authorizations'][$this->consumerType][$consumer_id]));
513
  }
514

    
515
  /**
516
   * NOTE this is in mixed case, since we must rely on whatever module is storing
517
   * the authorization id.
518
   *
519
   * @param drupal user object $user
520
   * @param string lowercase case $consumer_id
521
   *   such as drupal role name, og group name, etc.
522
   *
523
   * @return param boolean is user has authorization id, regardless of what module granted it.
524
   */
525
  public function hasAuthorization(&$user, $consumer_id) {
526
    return @in_array($consumer_id, $this->usersAuthorizations($user));
527
  }
528

    
529
  /**
530
   * Validate authorization mappings on LDAP Authorization OG Admin form.
531
   *
532
   * @param array $mapping
533
   *   single mapping in format generated in normalizeMappings method.
534
   * @param array $form_values
535
   *   from authorization configuration form.
536
   * @param bool $clear_cache
537
   *
538
   * @return array of form array($message_type, $message_text) where message type is status, warning, or error
539
   *   and $message_text is what the user should see.
540
   */
541
  public function validateAuthorizationMappingTarget($mapping, $form_values = NULL, $clear_cache = FALSE) {
542
    $message_type = NULL;
543
    $message_text = NULL;
544
    return [$message_type, $message_text];
545
  }
546

    
547
}