Project

General

Profile

Download (12 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
// $Id: shib_auth.module,v 1.3.4.5.2.10.2.5 2008/09/26 11:58:24 niif Exp $
3

    
4
/**
5
 * @file
6
 * Provides user authentication with Shibboleth (both v1.3 and v2.0) as well as some authorisation features (automatic role assignment base on Shibboleth attributes).
7
 */
8

    
9
/**
10
 * Display help and module information
11
 * @param path which path of the site we're displaying help
12
 * @param arg array that holds the current path as would be returned from arg() function
13
 * @return help text for the path
14
 */
15
function shib_auth_help($section) {
16
  $output = '';
17
  switch ($section) {
18
    case 'admin/help#shib_auth':
19
      //TODO
20
      $output = '<p>'. t("The Shibboleth authentication module let you utilize the advantages of the Single Sign On (SSO) methods.") .'</p>';
21
      break;
22
  }
23
  return $output;
24
} // function shib_auth_help
25

    
26
/**
27
 * Create a new user based on informations from the Shibboleth handler if it's necessary or log in.
28
 */
29
function shib_auth_init() {
30
  global $user;
31

    
32
  if (variable_get('shib_auth_debug_state', FALSE)) {
33
    $debug_message = print_r($_SERVER, TRUE);
34
    drupal_set_message('<pre>'. $debug_message .'</pre>');
35
  }
36
  
37
  $uname= $_SERVER[variable_get('shib_auth_username_variable', 'REMOTE_USER')];
38
  $umail= $_SERVER[variable_get('shib_auth_username_email', 'HTTP_SHIB_MAIL')];
39
  $umail_single = preg_replace('/;.*/', '', $umail);
40
  // If
41
  // - The user isn't logged in
42
  // - There is Shibboleth authentication in the background
43
  // - The settings are fine and there has been a valid username setted up
44
  // - The settings are fine and there has been a valid user email address setted up
45
  if (!$user->uid && ($_SERVER['HTTP_SHIB_IDENTITY_PROVIDER'] || $_SERVER['Shib-Identity-Provider'])) {
46
    if ($uname && $umail_single) {
47
      user_external_login_register($uname, "shib_auth");
48
      $account = user_save($user, array('mail' => $umail_single));
49
      // Terminate if an error occured during user_save().
50
      if (!$account) {
51
        drupal_set_message(t("Error saving user account."), 'error');
52
        return;
53
      }
54
      $user = $account;
55

    
56
    }
57
    else {
58
      $message = 'Username or e-mail address is missing. Maybe the Shibboleth configuration is not perfect.'; 
59
      drupal_set_message(t($message), 'error');
60
      watchdog('shib_auth', $message, WATCHDOG_CRITICAL);
61
    }
62
  }
63
  role_assign(); 
64
  //var_dump($user->roles);print('<br>');
65

    
66
} // function shib_auth_init()
67

    
68
/**
69
 * Role assign 
70
 *
71
 */
72
function role_assign() {
73
global $user;
74

    
75
$rules = db_query("SELECT * FROM {shib_auth}");
76

    
77
while ($rule = db_fetch_array($rules)) {
78
    $fieldname = $rule['field'];
79
    $expression = '/'. $rule['regexpression'] .'/';
80
      foreach (explode(';', $_SERVER[$fieldname]) as $value) {
81
        if (preg_match($expression, trim($value))) {
82
          $roles = unserialize($rule['role']);
83
          if (!empty($roles)){
84
            foreach ($roles as $key => $value) {
85
              $user->roles[$key] = $value;
86
            }
87
          }
88
      }
89
    }
90
  }
91

    
92
$user->roles = array_filter($user->roles);
93
}// function role_assign()
94

    
95
/**
96
 * Let the user exit from the Shibboleth authority when he/she log out from the actual Drupal site.
97
 * @param op What kind of action is being performed.
98
 * @param edit The array of form values submitted by the user.
99
 * @param account The user object on which the operation is being performed.
100
 * @param category The active category of user information being edited.
101
 */
102
function shib_auth_user($op, &$edit, &$account, $category = NULL) {
103
  global $base_url, $user;
104

    
105
  if ($op == "logout") {
106
    $handler_url = variable_get('shib_auth_handler_url', '/Shibboleth.sso');
107
    $handler_protocol = variable_get('shib_auth_handler_protocol', 'https');
108
    if (ereg("^http[s]{0,1}://", $handler_url) ) {
109
      // If handlerURL is an absolute path
110
      $logout_handler = $handler_url .'/Logout';
111
    }
112
    else {
113
      // Else, if the handlerURL is a relative path
114
      // If the WAYF's URI doesn't start with slash then extend it
115
      if ( !ereg("^/", $handler_url) ) $handler_url = '/'. $handler_url;
116
      $logout_handler = $handler_protocol .'://'. $_SERVER['HTTP_HOST'] . $handler_url .'/Logout';
117
    }
118
    $return_url = variable_get('logout_return_url', $base_url);
119
    drupal_goto("$logout_handler?return=$return_url");
120
  }
121
} // function shib_auth_user(logout)
122

    
123
/**
124
 * Valid permissions for this module
125
 * @return array An array of valid permissions for the shib_auth module
126
 */
127
function shib_auth_perm() {
128
  return array('administer shibboleth authentication');
129
} // function shib_auth_perm()
130

    
131
/**
132
 * Generate the login text in HTML format using the 't' function
133
 * @returns HTML text of the login form
134
 */
135
function generate_login_text() {
136
  global $base_url, $user;
137
  
138
  if (!$user->uid) {
139
    $handler_url = variable_get('shib_auth_handler_url', '/Shibboleth.sso');
140
    $handler_protocol = variable_get('shib_auth_handler_protocol', 'https');
141
    $wayf_uri = variable_get('shib_auth_wayf_uri', '/WAYF/HREF');
142

    
143
    // If the WAYF's URI doesn't start with slash then extend it
144
    if ( !ereg('^/', $wayf_uri) ) {
145
      $wayf_uri = '/'. $wayf_uri;
146
    }
147
  
148
    $handler = '';
149
    $block_content = '';
150
  
151
    if (ereg("^http[s]{0,1}://", $handler_url) ) {
152
      // If handlerURL is an absolute path
153
      $handler = $handler_url . $wayf_uri;
154
    }
155
    else {
156
      // Else, if the handlerURL is a relative path
157
      // If the WAYF's URI doesn't start with slash then extend it
158
      if ( !ereg("^/", $handler_url) ) $handler_url = "/" . $handler_url;
159
      $handler = $handler_protocol .'://'. $_SERVER['HTTP_HOST'] . $handler_url . $wayf_uri;
160
    }
161
    //$actualLocation: the path where the Shibboleth should return
162
    //orig: $actual_location = (isset($_SERVER['HTTPS']) ? 'https' : 'http') .'://'. $_SERVER['HTTP_HOST'] . request_uri();
163
	$actual_location = variable_get('login_target_protocol', 'https') .'://'. $_SERVER['HTTP_HOST'] . request_uri();
164
    
165
    // If there is no session yet then we should put the login text into the block
166
    $block_content .= '<p><b><a href='. $handler .'?target='. $actual_location .'>'
167
                      . variable_get('auth_link_text', t('Click here to login via Shibboleth!')) 
168
                      .'</a></b></p>';
169

    
170
    return $block_content;
171
  }
172
} // function generate_login_text()
173

    
174
/**
175
 * Generate the HTML text for the shib_auth login block
176
 * @param op the operation from the URL
177
 * @param delta offset
178
 * @returns block HTML 
179
 */
180
function shib_auth_block($op='list', $delta=0, $edit = array()) {
181
  // listing of blocks, such as on the admin/block page
182
  switch ($op) {
183
    case "list":
184
      $blocks[0] = array(
185
        'info'       => t('Shibboleth authentication'),
186
        'status'     => TRUE,
187
        'visibility' => 1,
188
        'weight'     => 0,
189
        'region'     => 'left'
190
      );
191
      return $blocks;
192
    case 'configure':
193
      $form = array();
194
      switch ($delta) {
195
        case 0:
196
          $form['auth_link_text'] = array(
197
            '#type' => 'textfield',
198
            '#title' => t('Text of the auth link'),
199
            '#require' => TRUE,
200
            '#size' => 60,
201
            '#description' => t('Here you can replace the text of the authentication link.'),
202
            '#default_value' => variable_get('auth_link_text', t('Click here to login via Shibboleth!')),
203
          );
204
      }
205
      return $form;
206
    case 'save':
207
      switch ($delta) {
208
        case 0:
209
          variable_set('auth_link_text', $edit['auth_link_text']);
210
      }
211
      break;
212
    case "view": default:
213
      switch ($delta) {
214
        case 0:
215
          $block = array(
216
          'subject' => t('Shibboleth login'),
217
          'content' => generate_login_text() );
218
          break;
219
      }
220
      return $block;
221
  }
222
} // function shib_auth_block()
223

    
224
/**
225
 * Generate the menu element to access the Shibboleth authentication module's administration page
226
 * @returns HTML text of the administer menu element
227
 */
228
function shib_auth_menu($may_cache) {
229
  $items = array();
230
 
231
  if ($may_cache) { 
232
    $items[] = array(
233
      'path' => 'admin/user/shib_auth',
234
      'title' => t('Shibboleth settings'),
235
      'description' => t('Control the various settings of the shibboleth authentication module'),
236
      'callback' => 'drupal_get_form',
237
      'callback arguments' => array('shib_auth_admin'),
238
      'access' => user_access('administer shibboleth authentication'),
239
      'weight' => -10,
240
    );
241

    
242
    $items[] = array(
243
      'path' => 'admin/user/shib_auth/general',
244
      'title' => t('General settings'),
245
      'access' => user_access('administer shibboleth authentication'),
246
      'weight' => -10,
247
      'type' => MENU_DEFAULT_LOCAL_TASK,
248
    );
249
  
250
    $items[] = array(
251
      'path' => 'admin/user/shib_auth/rules',
252
      'title' => t('Shibboleth group rules'),
253
      'description' => t('Administer the users group membership'),
254
      'callback' => 'shib_auth_list_rules',
255
      'access' => user_access('administer access control'),
256
      'type' => MENU_LOCAL_TASK,
257
      'weight' => -8,
258
    );
259
  
260
    $items[] = array(
261
      'path' => 'admin/user/shib_auth/rules/general',
262
      'title' => t('Rules'),
263
      'access' => user_access('administer shibboleth authentication'),
264
      'weight' => -10,
265
      'type' => MENU_DEFAULT_LOCAL_TASK,
266
    );
267

    
268
    $items[] = array(
269
      'path' => 'admin/user/shib_auth/rules/New',
270
      'title' => t('Add new rule'),
271
      'description' => t('Add new shibboleth based role adjudication'),
272
      'callback' => 'drupal_get_form',
273
      'callback arguments' => array('shib_auth_new_rule_form'),
274
      'access' => user_access('administer access control'),
275
      'type' => MENU_LOCAL_TASK,
276
      'weight' => -7,
277
    );
278
  }
279
  else{
280
    role_assign(); 
281

    
282
    $items[] = array(
283
      'path' => 'admin/user/shib_auth/rules/Delete/'. arg(5),
284
      'callback' => 'shib_auth_delete_rule',
285
      'callback arguments' => array(arg(5)),
286
      'access' => user_access('administer access control'),
287
      //'type' => MENU_CALLBACK,
288
    );
289

    
290
    $items[] = array(
291
      'path' => 'admin/user/shib_auth/rules/Edit/'. arg(5),
292
      'callback' => 'drupal_get_form',
293
      'callback arguments' => array('shib_auth_edit_rule'),
294
      'access' => user_access('administer access control'),
295
      'type' => MENU_NORMAL_ITEM,
296
    );
297

    
298
    $items[] = array(
299
      'path' => 'admin/user/shib_auth/rules/Clone/'. arg(5),
300
      'callback' => 'drupal_get_form',
301
      'callback arguments' => array('shib_auth_clone_rule'),
302
      'access' => user_access('administer access control'),
303
      'type' => MENU_CALLBACK,
304
    );
305
  }
306

    
307
  return $items;
308
} // function shib_auth_menu()
309

    
310
/**
311
 * Alters forms for the shibboleth authentication module.
312
 *
313
 * @param $form_id The form ID.
314
 * @param $form The form.
315
 */
316
function shib_auth_form_alter($form_id, &$form) {
317
  if ($form_id == 'user_login') {
318
    $form['shibboleth'] = array(
319
      '#type' => 'hidden', 
320
      '#weight' => -1,
321
      '#prefix' => generate_login_text(), 
322
      '#suffix' => '', 
323
    );
324
  }
325
}
326

    
327
/**
328
 * Helper function for authentication modules. Either login in or registers the
329
 * current user, based on username. Either way, the global $user object is
330
 * populated based on $name.
331
 *
332
 * Backport this function from user.module of Drupal 6.x.
333
 *
334
 * @param $name The user's name.
335
 * @param $module Name of the module which process the authetication.
336
 */
337
function user_external_login_register($name, $module) {
338
  global $user;
339

    
340
  // Try to load the user
341
  $user = user_load(array('name' => $name));
342

    
343
  if (!isset($user->uid)) {
344
    // Register this new user.
345
    $userinfo = array(
346
      'name' => $name,
347
      'pass' => user_password(),
348
      'init' => $name,
349
      'status' => 1,
350
      "authname_$module" => $name,
351
      'access' => time()
352
    );
353
    $account = user_save('', $userinfo);
354
    // Terminate if an error occured during user_save().
355
    if (!$account) {
356
      drupal_set_message(t("Error saving user account."), 'error');
357
      return;
358
    }
359
    $user = $account;
360
    watchdog('user', 'New external user: %name using module %module.', array('%name' => $name, '%module' => $module), WATCHDOG_NOTICE, l(t('edit'), 'user/'. $user->uid .'/edit'));
361
  }
362
}
363

    
364
// include the admin form if it really want to use
365
if (arg(0) === 'admin' AND arg(1) === 'user' AND arg(2) === 'shib_auth') {
366
  include_once('shib_auth_admin.inc');
367
}
(6-6/7)