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
|
}
|