Projet

Général

Profil

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

root / drupal7 / sites / all / modules / ldap / ldap_authorization / LdapAuthorizationConsumerAbstract.class.php @ 5136ce55

1
<?php
2

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

    
13
class LdapAuthorizationConsumerAbstract {
14

    
15
  public $consumerType = NULL; // machine name of consumer.  e.g. og_group, drupal_role, etc.
16

    
17
  /**
18
   * the following properties are generally populated from a
19
   * call to hook_ldap_authorization_consumer()
20
   */
21
  public $name;  // user interface name of consumer. e.g.  drupal role, og group
22
  public $namePlural; // user interface name of consumer. e.g. drupal roles, og groups
23
  public $shortName; // user interface short name of consumer. e.g. role, group
24
  public $shortNamePlural; //  user interface short name of consumer plural, e.g. roles, groups
25
  public $description;// e.g. roles, groups
26
  public $consumerModule; // module providing consumer functionality e.g. ldap_authorization_drupal_roles
27

    
28
  public $consumerConf; // LDAPConsumerConf object class encapuslating admin form
29
  public $testLink; // link to test this consumer
30
  public $editLink; // link to configure this consumer
31

    
32
  public $emptyConsumer = array(
33
    'exists' => TRUE,
34
    'value' => NULL,
35
    'name' => NULL,
36
    'map_to_string' => NULL
37
    );
38

    
39
   /**
40
   * @property boolean $allowConsumerObjectCreation
41
   *
42
   *  Does this consumer module support creating consumer objects
43
   * (drupal roles,  og groups, etc.)
44
   *
45
   */
46

    
47
  public $allowConsumerObjectCreation = FALSE;
48

    
49
   /**
50
   * @property boolean $detailedWatchdogLog
51
   *
52
   *  should watchdog log be used for debugging, useful for non programmers
53
   *  who don't have php debugging enabled
54
   *
55
   */
56
  public $detailedWatchdogLog = FALSE;
57

    
58

    
59
   /**
60
   * @property array $defaultConsumerConfProperties
61
   * default properties for consumer admin UI form
62
   */
63
  public $defaultConsumerConfProperties = array(
64
      'onlyApplyToLdapAuthenticated' => TRUE,
65
      'useMappingsAsFilter' => TRUE,
66
      'synchOnLogon' => TRUE,
67
      'revokeLdapProvisioned' => TRUE,
68
      'regrantLdapProvisioned' => TRUE,
69
      'createConsumers' => TRUE,
70
      );
71

    
72
 /**
73
   * Constructor Method
74
   *
75
   * @param string $consumer_type e.g. drupal_role, og_group
76
   * @param array $params as associative array of default properties
77
   *
78
   */
79
  function __construct($consumer_type, $params) {
80
    $this->consumerType = $consumer_type;
81
    $this->name = $params['consumer_name'];
82
    $this->namePlural= $params['consumer_name_plural'];
83
    $this->shortName = $params['consumer_short_name'];
84
    $this->shortNamePlural= $params['consumer_short_name_plural'];
85
    $this->consumerModule = $params['consumer_module'];
86
    $this->mappingDirections = $params['consumer_mapping_directions'];
87
    $this->testLink = l(t('test') . ' ' . $this->name, LDAP_SERVERS_MENU_BASE_PATH . '/authorization/test/' . $this->consumerType);
88
    $this->editLink = l(t('edit') . ' ' . $this->name, LDAP_SERVERS_MENU_BASE_PATH . '/authorization/edit/' . $this->consumerType);
89
    ldap_servers_module_load_include('php', 'ldap_authorization', 'LdapAuthorizationConsumerConfAdmin.class');
90
    $this->consumerConf = new LdapAuthorizationConsumerConf($this);
91
  }
92

    
93

    
94
  /**
95
   * function to normalize mappings
96
   * should be overridden when mappings are not stored as map|authorization_id format
97
   * where authorization_id is the format returned by
98
   *   LdapAuthorizationConsumerAbstract::usersAuthorizations()
99
   *
100
   * for example ldap_authorization_og may store mapping target as:
101
   *   Campus Accounts|group-name=knitters,role-name=administrator member
102
   *
103
   *   normalized mappings are of form such as for organic groups:
104
   *
105
   *   array(
106
         array(
107
           'from' => 'students',
108
           'normalized' => 'node:21:1',
109
           'simplified' => 'node:students:member',
110
           'user_entered' => 'students'
111
           'valid' => TRUE,
112
           'error_message' => '',
113
           ),
114

115
         ...
116
        )
117

118
   *   or for drupal role where rid 3 is moderator and rid 2 is admin:
119
   *   array(
120
         array(
121
           'from' => 'students',
122
           'normalized' => '2',
123
           'simplified' => 'admin',
124
           'user_entered' => 'admin',
125
           'valid' => TRUE,
126
           'error_message' => '',
127
           ),
128
         ...
129
        )
130

131
        where 'normalized' is in id format and 'simplified' is user shorthand
132
   )
133
   */
134
  public function normalizeMappings($mappings) {
135
    return $mappings;
136
  }
137

    
138
  /**
139
   *
140
   * create authorization consumers
141
   *
142
   * @param string (lowercase) $consumer_id
143
   * @param array $consumer as associative array with the following key/values
144
   *   'value' => NULL | mixed consumer such as drupal role name, og group entity, etc.
145
   *   'name' => name of consumer for UI, logging etc.
146
   *   'map_to_string' => string mapped to in ldap authorization.  mixed case string
147
   *   'exists' => TRUE indicates consumer is known to exist,
148
   *               FALSE indicates consumer is known to not exist,
149
   *               NULL indicate consumer's existance not checked yet
150
   *
151
   */
152
  public function createConsumer($consumer_id, $consumer) {
153
    // method must be overridden
154
  }
155

    
156
  /**
157
   * populate consumer side of $consumers array
158
   *
159
   * @param array $consumers as associative array keyed on $consumer_id with values
160
   *   of $consumer.  $consumer_id and $consumer have structure in LdapAuthorizationConsumerAbstractClass::createConsumer
161
   *   when values are $consumer['exists'] != TRUE need to be populated by consumer object
162
   * @param boolean $create_missing_consumers indicates if consumers (drupal roles, og groups, etc) should be created
163
   *   if values are NULL, object will be created if
164
   *
165
   * @return $consumers by reference
166
   */
167

    
168
  public function populateConsumersFromConsumerIds(&$consumers, $create_missing_consumers = FALSE) {
169
    // method must be overridden
170
  }
171

    
172
  public function authorizationDiff($initial, $current) {
173
    return array_diff($initial, $current);
174
  }
175

    
176

    
177
  /**
178
   * grant authorizations to a user
179
   *
180
   * @param object $user drupal user object
181
   * @param array $consumers in form of LdapAuthorizationConsumerAbstractClass::populateConsumersFromConsumerIds
182
   * @param array $ldap_entry is ldap data from ldap entry which drupal user is mapped to
183
   * @param boolean $user_save.  should user object be saved by authorizationGrant method
184
   *
185
   * @return array $results.  Array of form
186
   *   array(
187
   *    <authz consumer id1> => 1,
188
   *    <authz consumer id2> => 0,
189
   *   )
190
   *   where 1s and 0s represent success and failure to grant
191
   *
192
   *
193
   *  method may be desireable to override, if consumer benefits from adding grants as a group rather than one at a time
194
   */
195

    
196
  public function authorizationGrant(&$user, &$user_auth_data, $consumers, $ldap_entry = NULL, $user_save = TRUE) {
197
    $this->filterOffPastAuthorizationRecords($user, $user_auth_data);
198
    $this->grantsAndRevokes('grant', $user, $user_auth_data, $consumers, $ldap_entry, $user_save);
199
  }
200

    
201
  /**
202
   * revoke authorizations to a user
203
   *
204
   * @param object $user drupal user object
205
   * @param array $consumers in form of LdapAuthorizationConsumerAbstractClass::populateConsumersFromConsumerIds
206
   * @param array $ldap_entry is ldap data from ldap entry which drupal user is mapped to
207
   * @param boolean $user_save.  should user object be saved by authorizationGrant method
208
   *
209
   * @return array $results.  Array of form
210
   *   array(
211
   *    <authz consumer id1> => 1,
212
   *    <authz consumer id2> => 0,
213
   *   )
214
   *   where 1s and 0s represent success and failure to revoke
215
   *  $user_auth_data is returned by reference
216
   *
217
   *  method may be desireable to override, if consumer benefits from revoking grants as a group rather than one at a time
218
   */
219

    
220
  public function authorizationRevoke(&$user, &$user_auth_data, $consumers, $ldap_entry, $user_save = TRUE) {
221
    $this->filterOffPastAuthorizationRecords($user, $user_auth_data);
222
    $this->grantsAndRevokes('revoke', $user, $user_auth_data, $consumers, $ldap_entry, $user_save);
223
  }
224

    
225

    
226

    
227
  /**
228
   * this is a function to clear off
229
   */
230
  public function filterOffPastAuthorizationRecords(&$user, &$user_auth_data, $time = NULL) {
231
    if ($time != NULL || variable_get('ldap_help_user_data_clear', 0)) {
232
      $clear_time = ($time) ? $time : variable_get('ldap_help_user_data_clear_set_date', 0);
233
      if ($clear_time > 0 && $clear_time < time()) {
234
        foreach ($user_auth_data as $consumer_id => $entry) {
235
          if ($entry['date_granted'] < $clear_time) {
236
            unset($user_auth_data[$consumer_id]);
237
            if (isset($user->data['ldap_authorizations'][$this->consumerType][$consumer_id])) {
238
              unset($user->data['ldap_authorizations'][$this->consumerType][$consumer_id]);
239
            }
240
          }
241
        }
242
      }
243
    }
244
  }
245

    
246
  /**
247
   * some authorization schemes such as organic groups, require a certain order.  implement this method
248
   * to sort consumer ids/authorization ids
249
   *
250
   * @param string $op 'grant' or 'revoke' signifying what to do with the $consumer_ids
251
   * @param $consumers associative array in form of LdapAuthorizationConsumerAbstract::populateConsumersFromConsumerIds
252
   *
253
   * alters $consumers by reference
254
   *
255
   */
256
  public function sortConsumerIds($op, &$consumers) { }
257

    
258

    
259
  /**
260
   * attempt to flush related caches.  This will be something like og_invalidate_cache($gids)
261
   *
262
   * @param $consumers associative array in form of LdapAuthorizationConsumerAbstract::populateConsumersFromConsumerIds
263
   *
264
   *
265
   */
266
  public function flushRelatedCaches($consumers = NULL) { }
267

    
268
  /**
269
   * @param string $op 'grant' or 'revoke' signifying what to do with the $consumer_ids
270
   * @param drupal user object $object
271
   * @param array $user_auth_data is array specific to this consumer_type.  Stored at $user->data['ldap_authorizations'][<consumer_type>]
272
   * @param $consumers as associative array in form of LdapAuthorizationConsumerAbstract::populateConsumersFromConsumerIds
273
   * @param array $ldap_entry, when available user's ldap entry.
274
   * @param boolean $user_save indicates is user data array should be saved or not.  this depends on the implementation calling this function
275
   */
276

    
277
  protected function grantsAndRevokes($op, &$user, &$user_auth_data, $consumers, &$ldap_entry = NULL, $user_save = TRUE) {
278

    
279
    if (!is_array($user_auth_data)) {
280
      $user_auth_data = array();
281
    }
282

    
283
    $detailed_watchdog_log = variable_get('ldap_help_watchdog_detail', 0);
284
    $this->sortConsumerIds($op, $consumers);
285
    $results = array();
286
    $watchdog_tokens = array();
287
    $watchdog_tokens['%username'] = $user->name;
288
    $watchdog_tokens['%action'] = $op;
289
    $watchdog_tokens['%user_save'] = $user_save;
290
    $consumer_ids_log = array();
291
    $users_authorization_ids = $this->usersAuthorizations($user);
292
    $watchdog_tokens['%users_authorization_ids'] = join(', ', $users_authorization_ids);
293
    if ($detailed_watchdog_log) {
294
      watchdog('ldap_authorization', "on call of grantsAndRevokes: user_auth_data=" . print_r($user_auth_data, TRUE), $watchdog_tokens, WATCHDOG_DEBUG);
295
    }
296

    
297
    foreach ($consumers as $consumer_id => $consumer) {
298
      if ($detailed_watchdog_log) {
299
        watchdog('ldap_authorization', "consumer_id=$consumer_id, user_save=$user_save, op=$op", $watchdog_tokens, WATCHDOG_DEBUG);
300
      }
301
      $log = "consumer_id=$consumer_id, op=$op,";
302
      $user_has_authorization = in_array($consumer_id, $users_authorization_ids);
303
      $user_has_authorization_recorded = isset($user_auth_data[$consumer_id]);
304

    
305
      /** grants **/
306
      if ($op == 'grant') {
307
        if ($user_has_authorization && !$user_has_authorization_recorded) {
308
          // grant case 1: authorization id already exists for user, but is not ldap provisioned.  mark as ldap provisioned, but don't regrant
309
          $results[$consumer_id] = TRUE;
310
          $user_auth_data[$consumer_id] = array(
311
            'date_granted' => time(),
312
            'consumer_id_mixed_case' => $consumer_id,
313
          );
314
        }
315
        elseif (!$user_has_authorization && $consumer['exists']) {
316
          // grant case 2: consumer exists, but user is not member. grant authorization
317
          $results[$consumer_id] = $this->grantSingleAuthorization($user, $consumer_id, $consumer, $user_auth_data, $user_save);  // allow consuming module to add additional data to $user_auth_data
318
          $existing = empty($user_auth_data[$consumer_id]) ? array() : $user_auth_data[$consumer_id];
319
          $user_auth_data[$consumer_id] = $existing + array(
320
            'date_granted' => time(),
321
            'consumer_id_mixed_case' => $consumer_id,
322
          );
323
        }
324
        elseif ($consumer['exists'] !== TRUE) {
325
          // grant case 3: something is wrong. consumers should have been created before calling grantsAndRevokes
326
          $results[$consumer_id] = FALSE;
327
        }
328
        elseif ($consumer['exists'] === TRUE) {
329
          // grant case 4: consumer exists and user has authorization recorded. do nothing
330
          $results[$consumer_id] = TRUE;
331
        }
332
        else {
333
          // grant case 5: $consumer['exists'] has not been properly set before calling function
334
          $results[$consumer_id] = FALSE;
335
          watchdog('ldap_authorization', "grantsAndRevokes consumer[exists] not properly set. consumer_id=$consumer_id, op=$op, username=%username", $watchdog_tokens, WATCHDOG_ERROR);
336
        }
337
      }
338
      /** revokes **/
339
      elseif ($op == 'revoke') {
340

    
341
        $log .= "revoking existing consumer object, ";
342
        if ($user_has_authorization) {
343
          // revoke case 1: user has authorization, revoke it.  revokeSingleAuthorization will remove $user_auth_data[$consumer_id]
344
          //debug("op=revoke, consumer_id=$consumer_id, calling revokeSingleAuthorization");
345
          $results[$consumer_id] = $this->revokeSingleAuthorization($user, $consumer_id, $consumer, $user_auth_data, $user_save);  // defer to default for $user_save param
346
          $log .= t(',result=') . (boolean)($results[$consumer_id]);
347
        }
348
        elseif ($user_has_authorization_recorded)  {
349
          // revoke case 2: user does not have authorization, but has record of it. remove record of it.
350
          unset($user_auth_data[$consumer_id]);
351
          $results[$consumer_id] = TRUE;
352
        }
353
        else {
354
          // revoke case 3: trying to revoke something that isn't there
355
          $results[$consumer_id] = TRUE;
356
        }
357

    
358
      }
359
      $consumer_ids_log[] = $log;
360
      if ($detailed_watchdog_log) {
361
        watchdog('ldap_authorization', "user_auth_data after consumer $consumer_id" . print_r($user_auth_data, TRUE), $watchdog_tokens, WATCHDOG_DEBUG);
362
      }
363

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

    
367
   // debug("user->data and user_auth_data"); debug($user->data); debug($user_auth_data);
368
    if ($user_save) {
369
      $user = user_load($user->uid, TRUE);
370
      $user_edit = $user->data;
371
      $user_edit['data']['ldap_authorizations'][$this->consumerType] = $user_auth_data;
372
      $user = user_save($user, $user_edit);
373
      $user_auth_data = $user->data['ldap_authorizations'][$this->consumerType];  // reload this.
374
    }
375
    $this->flushRelatedCaches($consumers);
376

    
377
    if ($detailed_watchdog_log) {
378
      watchdog('ldap_authorization', '%username:
379
        <hr/>LdapAuthorizationConsumerAbstract grantsAndRevokes() method log.  action=%action:<br/> %consumer_ids_log
380
        ',
381
        $watchdog_tokens, WATCHDOG_DEBUG);
382
    }
383

    
384
  }
385

    
386
  /**
387
   * @param drupal user object $user to have $consumer_id revoked
388
   * @param string lower case $consumer_id $consumer_id such as drupal role name, og group name, etc.
389
   * @param mixed $consumer.  depends on type of consumer.  Drupal roles are strings, og groups are ??
390
   * @param array $user_auth_data array of $user data specific to this consumer type.
391
   *   stored in $user->data['ldap_authorizations'][<consumer_type>] array
392
   * @param boolean $reset signifying if caches associated with $consumer_id should be invalidated.
393
   *
394
   * return boolen TRUE on success, FALSE on fail.  If user save is FALSE, the user object will
395
   *   not be saved and reloaded, so a returned TRUE may be misleading.
396
   *   $user_auth_data should have successfully revoked consumer id removed
397
   */
398

    
399
  public function revokeSingleAuthorization(&$user, $consumer_id, $consumer, &$user_auth_data, $user_save = FALSE, $reset = FALSE) {
400
     // method must be overridden
401
  }
402

    
403
  /**
404
   * @param stdClass $user as drupal user object to have $consumer_id granted
405
   * @param string lower case $consumer_id $consumer_id such as drupal role name, og group name, etc.
406
   * @param mixed $consumer.  depends on type of consumer.  Drupal roles are strings, og groups are ??
407
   * @param array $user_auth_data in form
408
   *   array('my drupal role' =>
409
   *     'date_granted' => 1351814718,
410
   *     'consumer_id_mixed_case' => 'My Drupal Role',
411
   *     )
412
   * @param boolean $reset signifying if caches associated with $consumer_id should be invalidated.
413
   *  @return boolean FALSE on failure or TRUE on success
414
   */
415
  public function grantSingleAuthorization(&$user, $consumer_id, $consumer, &$user_auth_data, $user_save = FALSE, $reset = FALSE) {
416
     // method must be overridden
417
  }
418

    
419
  /**
420
         * Return all user consumer ids
421
         *   regardless of it they were granted by this module
422
         *
423
         * @param user object $user
424
         * @return array of consumer ids such as array('3-2','7-2'), array('admin','user_admin')
425
         */
426

    
427
  public function usersAuthorizations(&$user) {
428
    // method must be overridden
429
  }
430

    
431
  /**
432
   * put authorization ids in displayable format
433
   */
434
  public function convertToFriendlyAuthorizationIds($authorizations) {
435
    return $authorizations;
436
  }
437

    
438
  /**
439
  * @param drupal user object $user to have $consumer_id granted
440
  * @param string lower case $consumer_id $consumer_id such as drupal role name, og group name, etc.
441
  * @param mixed $consumer.  depends on type of consumer.  Drupal roles are strings, og groups are ??
442
  *
443
  * return boolen TRUE on success, FALSE on fail.  If user save is FALSE, the user object will
444
  *   not be saved and reloaded, so a returned TRUE may be misleading.
445
  */
446
  public function createSingleAuthorization(&$user, $consumer_id, $consumer, &$user_auth_data) {
447
     // method must be overridden
448
  }
449

    
450
  /**
451
  * @param drupal user object $user
452
  * @param string lowercase $consumer_id such as drupal role name, og group name, etc.
453
  *
454
  * @return boolean if an ldap_authorization_* module granted the authorization id
455
  */
456
  public function hasLdapGrantedAuthorization(&$user, $consumer_id) {
457
    return (!empty($user->data['ldap_authorizations'][$this->consumerType][$consumer_id]));
458
  }
459

    
460
  /**
461
   * NOTE this is in mixed case, since we must rely on whatever module is storing
462
   * the authorization id
463
   *
464
   * @param drupal user object $user
465
   * @param string lowercase case $consumer_id such as drupal role name, og group name, etc.
466
   *
467
   * @return param boolean is user has authorization id, regardless of what module granted it.
468
   */
469
  public function hasAuthorization(&$user, $consumer_id) {
470
    return @in_array($consumer_id, $this->usersAuthorizations($user));
471
  }
472

    
473
  /**
474
         * Validate authorization mappings on LDAP Authorization OG Admin form.
475
         *
476
         * @param array $mapping single mapping in format generated in normalizeMappings method
477
         * @param array $form_values from authorization configuration form
478
         * @param boolean $clear_cache
479
         *
480
         * @return array of form array($message_type, $message_text) where message type is status, warning, or error
481
         *   and $message_text is what the user should see.
482
         *
483
         */
484

    
485
  public function validateAuthorizationMappingTarget($mapping, $form_values = NULL, $clear_cache = FALSE) {
486
    $message_type = NULL;
487
    $message_text = NULL;
488
    return array($message_type, $message_text);
489
  }
490

    
491

    
492
}