-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathding_wayf.module
336 lines (297 loc) · 10 KB
/
ding_wayf.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
<?php
/**
* @file
* This module enables login through WAYF services, which includes NemLogin.This
* authentication module is based on idea's from the simpleSAMLAuth module, which
* can be found at http://code.google.com/p/drupalsimplesaml/.
*/
/**
* Implementation of hook_perm().
*/
function ding_wayf_perm() {
return array(
'configure wayf',
);
}
/**
* Implementation of hook_menu().
*/
function ding_wayf_menu() {
$items = array();
// Administation interface.
$items['admin/settings/ding/wayf'] = array(
'title' => t('Ding! WAYF'),
'description' => t('Configure Ding! WAYF'),
'page callback' => 'drupal_get_form',
'page arguments' => array('ding_wayf_admin_settings_form'),
'access arguments' => array('configure wayf'),
'file' => 'includes/ding_wayf.admin.inc',
);
// WAYF login callback.
$items['wayf/login'] = array(
'title' => t('Logon to the site'),
'description' => t('Provides WAYF login.'),
'page callback' => 'ding_wayf_redirect_login',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['wayf/error'] = array(
'title' => t('WAYF login was unsuccessful'),
'description' => t('Message displayed when WAYF login fails.'),
'page callback' => 'ding_wayf_login_error',
'access callback' => TRUE,
);
return $items;
}
/**
* Helper function that handles the login procedure. If the user is not yet
* authenticated by WAYF - the user will be redirected to WAYF login. If the
* user is authenticated the user will be logged into the drupal site as a
* library user.
*
* The library system may block the user and he/she will automaticly be logged
* out of WAYF.
*
* If the user is logged into both system, the user will be redirecte to a
* preconfigured URL.
*/
function ding_wayf_redirect_login() {
global $user;
global $conf;
// Load configuration.
$config = variable_get('ding_wayf', NULL);
if (!$config || !isset($conf['ding_wayf_passwd'])) {
// The configuration have not be created yet, so send user to the front page
// with an error message.
drupal_set_message(t('The WAYF login module is not configured yet, plase contact the site administrator.'), 'error', FALSE);
// Redirect user to previous context or fallback to the front page.
ding_wayf_redirect_user('<front>');
}
// Load simple saml php.
require_once($config['installdir'] . '/lib/_autoload.php');
// Check if user is already logged in, if not continue with wayf login.
if ($user->uid == 0) {
// Get saml connection, using the SP defined by the administrator.
$saml = ding_wayf_get_saml_connection($config['sp']);
// User is not logged into drupal, check wayf.
if ($saml->isAuthenticated()) {
// The user was logged into WAYF, so try to log into drupal.
$saml_attributes = $saml->getAttributes();
if (isset($saml_attributes)) {
if (isset($saml_attributes[$config['attribute']]) && !empty($saml_attributes[$config['attribute']])) {
// Attributes was return from saml.
$auth_name = ding_wayf_get_credentials($saml_attributes[$config['attribute']], $config['attribute_field']);
if ($auth_name) {
$creds = array(
'name' => ding_wayf_get_credentials($saml_attributes[$config['attribute']], $config['attribute_field']),
'pass' => $conf['ding_wayf_passwd'],
);
}
}
}
// Login into the drupal site, if this fails the user will be logout and
// redirected to the front page.
ding_wayf_login($creds);
// Send the user back to her context or use the fallback URL.
ding_wayf_redirect_user($config['redirect']);
return;
}
else {
// Redirect the user to the WAYF login page.
$saml->requireAuth();
}
}
// Send the user back to her context or use the fallback URL.
ding_wayf_redirect_user($config['redirect']);
return;
}
/**
* Login a wayf user, as thay where logged in by the library system.
*/
function ding_wayf_login($creds) {
global $user;
// Ask the provider if the user can be logged into the backend.
$auth_res = ding_provider_invoke('user', 'authenticate', $creds['name'], $creds['pass']);
// Test that the response was valided.
if (!is_array($auth_res) || !isset($auth_res['result']) || empty($auth_res['result'])) {
drupal_set_message(t('You could not be logged into the library system, so you have been logged out of WAYF.'), 'warning');
watchdog('ding_wayf', 'Provider returned invalid result: @res', array('@res' => print_r($auth_res, TRUE)), WATCHDOG_DEBUG);
ding_wayf_logout(FALSE);
return;
}
// TODO: Code seems to be a copy/paste of ding_library_user_user_login_validate
// and https://github.com/dingproject/ding-borger-api/blob/master/ding_borger_api/ding_borger_api.module#L64.
// We should refactor this at some point.
if ($auth_res['result']) {
if (isset($auth_res['authname']) && !empty($auth_res['authname'])) {
// If provider supplied an authname, use it.
$auth_name = $auth_res['authname'];
}
else {
// Else use a standard authname.
$auth_name = ding_library_user_default_authname($creds['name']);
}
// This sets the proper global $user.
user_external_login_register($auth_name, 'ding_library_user');
// Let authenticate module provide some properties for the $user
// object. Thus they can set properties that gets used in
// hook_user('login').
if (isset($auth_res['user'])) {
foreach ($auth_res['user'] as $key => $value) {
$user->$key = $value;
}
}
// Finalize login.
user_authenticate_finalize($creds);
// user_authenticate_finalize above just regenerated the session, so we've
// waited until now to stuff things in it.
if (isset($auth_res['creds'])) {
$_SESSION['ding_library_user_creds'][$user->uid] = $auth_res['creds'];
}
if (ding_provider_supports('user', 'authenticate finalize')) {
ding_provider_invoke('user', 'authenticate finalize', $user);
}
}
else {
if (isset($auth_res['messages'])) {
foreach ($auth_res['messages'] as $message) {
if (is_array($message)) {
list($message, $type) = $message;
} else {
$type = 'warning';
}
drupal_set_message($message, $type);
}
}
// We need to logout of wayf at this point, as we never got logged into the
// drupal site.
ding_wayf_logout(FALSE);
}
}
/**
* Helper function that redirectes the user to previous context or the fallback
* URL given as parameter.
*
* @param string $url
*/
function ding_wayf_redirect_user($url) {
if ($_REQUEST['destination']) {
$url = $_REQUEST['destination'];
}
else {
global $user;
$url = str_replace('%uid', $user->uid, $url);
}
drupal_goto($url);
}
/**
* Helper function that logs the current user out from WAYF.
*
* @param boolean $logged_in_library
* Indicates if the user have been logged into the library system.
*/
function ding_wayf_logout($logged_in_library = TRUE) {
$config = variable_get('ding_wayf', array());
if (empty($config)) {
// No configuration found, so user can't be logged in with wayf.
return;
}
// Load simple saml php.
require_once($config['installdir'] . '/lib/_autoload.php');
// Get saml connection.
$saml = ding_wayf_get_saml_connection($config['sp']);
// Check if the user is logged into WAYF and log out the user.
if ($saml->isAuthenticated()) {
$url = $config['no_library_user'];
if ($logged_in_library) {
$url = '/logout';
}
// This function dose not return and will terminate the normal logout
// process. But it can perform a redirect to a URL, which will be /logout
// hence restart the drupal logout process.
$saml->logout($url);
}
}
/**
* Helper function that extracts a field from a saml attribute string.
*
* @param string $data
* @param string $field
* @return string
*/
function ding_wayf_get_credentials($data, $field) {
return substr($data[0], strpos($data[0], $field) + strlen($field) + 1);
}
/**
* Gets a connection to simple saml php.
*
* @param string $sp
* @return SimpleSAML_Auth_Simple
*/
function ding_wayf_get_saml_connection($sp) {
return new SimpleSAML_Auth_Simple($sp);
}
/**
* Implementation of hook_user(). Ensures that the WAYF logout function is called
* on user logout.
*/
function ding_wayf_user($op, &$edit, &$account, $category = NULL) {
if ($op == 'logout') {
ding_wayf_logout();
}
}
/**
* Implementation of hook_block(). A block is created with the login link to
* WAYF.
*/
function ding_wayf_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$block[0] = array(
'info' => t('WAYF login block'),
'cache' => BLOCK_NO_CACHE,
);
break;
case 'view':
global $user;
// Only show login link for anon. users.
if ($user->uid == 0) {
$block['content'] = l(t('Login using WAYF'), 'wayf/login', array('query' => drupal_get_destination()));
}
break;
}
return $block;
}
/**
* Check that simpleSAMLphp is installed at the location given.
*/
function ding_wayf_check_simplesamlphp($path) {
// Check that simple saml php is found at the location given.
if (!file_exists($path . '/lib/_autoload.php')) {
return FALSE;
}
return TRUE;
}
/**
* Implementation of hook_theme().
*/
function ding_wayf_theme() {
return array(
'ding_wayf_error_page' => array(
'template' => 'templates/ding-wayf-error-page',
'arguments' => array('headline' => NULL, 'content' => NULL),
),
);
}
/**
* Menu callback that displayes a default error message. It will be used if the
* administrator have not created another error page in the administration
* interface for ding wayf.
*
* @return string
*/
function ding_wayf_login_error() {
return theme('ding_wayf_error_page',
t('Your attempt to login with nem-id was unsuccessful'),
t('This may be because you are not registered as a borrower, or because we do not have your Social Security number in the library system.'));
}