/[drupal]/contributions/modules/calnet/calnet.module
ViewVC logotype

Contents of /contributions/modules/calnet/calnet.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Sat Jun 9 03:01:37 2007 UTC (2 years, 5 months ago) by robroy
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-4-7
File MIME type: text/x-php
Adding CalNet authentication module for authenticating against UC Berkeley's CalNet system. This initial commit is for Drupal 4.7 and needs upgrade to Drupal 5 along with a bunch of other TODOs listed in the README.txt. These need to happen before we publish any release or project page.
1 <?php
2 // $Id: $
3
4 /*
5 Copyright (c) 2006, CommerceNet and University of California, Berkeley
6 All rights reserved.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 * Neither the name of the copyright holders nor the names of their
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY COMMERCENET, THE UC REGENTS, AND
20 CONTRIBUTORS``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
21 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COMMERCENET, THE UC
23 REGENTS, AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /**
33 * @file
34 * Enables third-party authentication with the CalNet API.
35 */
36
37 /**
38 * Implementation of hook_help().
39 */
40 function calnet_help($section) {
41 switch ($section) {
42 case 'admin/modules#description':
43 return t('Enables authentication with the CalNet API.');
44 }
45 }
46
47 /**
48 * Implementation of hook_menu().
49 */
50 function calnet_menu($may_cache) {
51 global $user;
52 $items = array();
53
54 if ($may_cache) {
55 $access = ($user->uid == 0);
56 $items[] = array(
57 'path' => 'calnet/login',
58 'title' => t('Login'),
59 'type' => MENU_CALLBACK,
60 'callback' => 'drupal_goto',
61 'callback arguments' => array(_calnet_login_url()),
62 'access' => $access,
63 );
64 /*$items[] = array(
65 'path' => 'calnet/register',
66 'title' => t('Register: Step 1'),
67 'type' => MENU_CALLBACK,
68 'callback' => 'calnet_register_page',
69 'access' => $access,
70 );*/
71 $items[] = array(
72 'path' => 'calnet/reentry',
73 'title' => t('Reentry'),
74 'type' => MENU_CALLBACK,
75 'callback' => 'calnet_process_reentry',
76 'access' => $access,
77 );
78 }
79
80 return $items;
81 }
82
83 /**
84 * Implementation of hook_block().
85 */
86 function calnet_block($op = 'list', $delta = 0, $edit = array()) {
87 global $user;
88
89 switch ($op) {
90 case 'list':
91 $blocks = array();
92 $blocks[0] = array('info' => t('CalNet Login'));
93 return $blocks;
94
95 case 'view':
96 $block = array();
97 switch ($delta) {
98 case 0:
99 if ($user->uid) {
100 $block['subject'] = t('For Students');
101 $block['content'] = '<p>'. t('You are logged in as %user.', array('%user' => $user->name)) .'</p>';
102 $block['content'] .= l(t('My personal page'), 'welcome', array('class' => 'button button-yellow-white'));
103 $block['content'] .= '&nbsp;'. l(t('Log out'), 'logout');
104 }
105 else {
106 $block['subject'] = t('For Students');
107 $block['content'] = '<p>'. t('Already a registered member?') .'<br />';
108 $block['content'] .= t('Log in to your personal page.') .'</p>';
109 $block['content'] .= l(t('Log in'), 'calnet/login', array('class' => 'button button-yellow-white'));
110 $block['content'] .= '&nbsp;'. l(t('Register'), 'calnet/register');
111 }
112
113 return $block;
114 }
115 break;
116 }
117 }
118
119 /**
120 * Menu callback; process entry from CalNet authentication site.
121 */
122 function calnet_process_reentry() {
123 global $user;
124 // If user is already logged in, send them to welcome page and show a message.
125 if ($user->uid) {
126 drupal_set_message(t('It appears you are already logged in to the Big Ideas website.'));
127 drupal_goto('welcome');
128 return;
129 }
130
131 require_once('aws.php');
132
133 $options = array(
134 'reentryurl_begin' => url(NULL, NULL, NULL, TRUE),
135 'allow_testid' => $_SERVER['DOMAINNAME'] == 'dev' ? TRUE : FALSE, // Allow test ID on dev server only.
136 );
137 $aws = calnet_aws3_verify($_POST, $options);
138 if (!$aws) {
139 /* Verification or Validation Failure, throw out */
140 $_SESSION['calnet_uid'] = FALSE;
141 watchdog('calnet', t('Processing CalNet ID validation failed.'), WATCHDOG_ERROR);
142 return FALSE;
143 }
144
145 /* Otherwise the token verified and validated successfully */
146 $_SESSION['calnet_uid'] = $aws['uid'];
147
148 // Now we should check if this user already has a local Drupal account created.
149 // If so, we'll log them in to that account, if not redirect to register page.
150 $drupal_uid = calnet_login_calnet_user($_SESSION['calnet_uid']);
151 if ($drupal_uid) {
152 drupal_goto('welcome');
153 }
154 else {
155 drupal_goto('user/register');
156 }
157 }
158
159 /**
160 * Helper function to log a user in by CalNet ID.
161 */
162 function calnet_login_calnet_user($calnet_uid) {
163 global $user;
164
165 $drupal_uid = db_result(db_query('SELECT drupal_uid FROM {calnet} WHERE calnet_uid = %d', $calnet_uid));
166
167 if ($drupal_uid) {
168 $account = user_load(array('uid' => $drupal_uid, 'status' => 1));
169 if ($account->uid) {
170 // Set global $user to the matched local account.
171 $user = $account;
172
173 // Process login so other modules can react.
174 $form_values = array(
175 'name' => $account->name,
176 );
177 watchdog('calnet', t('Login: CalNet ID %calnet successfully matched to Drupal account for %name.', array('%calnet' => theme('placeholder', $calnet_uid), '%name' => theme('placeholder', $user->name))));
178
179 user_login_submit('user_login', $form_values);
180 return $drupal_uid;
181 }
182 }
183
184 return FALSE;
185 }
186
187 /**
188 * Implementation of hook_form_alter().
189 */
190 function calnet_form_alter($form_id, &$form) {
191 global $user;
192 if (isset($form['#validate']['user_register_validate'])) {
193 if (!user_access('administer users')) {
194 // On accessing this form, redirect if they need to validate through CalNet.
195 if (!_calnet_is_valid_session_calnet_id()) {
196 drupal_goto(_calnet_login_url());
197 return;
198 }
199
200 // Form modifications for preview callback.
201 $form['#after_build'] = array('calnet_user_register_form_add_preview');
202 $form['#prefix'] = '<div id="block-custom-register-2" class="block"><div class="h2-title"><div class="corner-top"><ul><li>&nbsp;</li></ul></div><h2 class="title-content">Enter Information</h2></div><div class="content">';
203 $form['#suffix'] = '</div></div>';
204 $form['preview'] = array('#type' => 'button', '#value' => t('Continue registration'), '#weight' => 25);
205
206 // Tidy up additional Big Ideas user profile registration fields.
207 foreach(element_properties($form['personal information']) as $key) {
208 unset($form['personal information'][$key]);
209 }
210 $form['account'] = array_merge($form['account'], $form['personal information']);
211 unset($form['personal information']);
212 $form['account']['#type'] = 'markup';
213 $form['account']['profile_name']['#weight'] = -2;
214
215 // Add password to user register form and validation to check against CalNet API.
216 $form['#validate']['calnet_user_register_validate'] = array();
217
218 // Map CalNet ID to Drupal user ID on registration submission.
219 $form['#submit']['calnet_user_register_submit'] = array();
220
221 $form['submit_prefix'] = array('#value' => '<div class="buttons">', '#weight' => 15);
222 $form['submit_suffix'] = array('#value' => '</div>', '#weight' => 35);
223
224 $form['account']['name']['#title'] = t('Big Ideas username');
225 $form['account']['name']['#description'] = t('Your preferred Big Ideas username; only letters, numbers and spaces are allowed. Your username may be attached to your posts and publicly viewable.');
226
227 // Generate a random local password for CalNet accounts.
228 /*$form['account']['pass'] = array(
229 '#type' => 'hidden',
230 '#value' => user_password(20),
231 );*/
232
233 // Show a display field with CalNet auth info.
234 /*$form['account']['display_name'] = array(
235 '#type' => 'item',
236 '#title' => t('CalNet ID'),
237 '#value' => $_SESSION['calnet_uid'],
238 '#weight' => -10,
239 );*/
240 }
241 }
242 elseif (isset($form['#validate']['user_login_validate'])) {
243 // If user is not an admin, we need to have them log in through CalNet first.
244 $form['#validate'] = array('calnet_login_validate' => array());
245 }
246 elseif ($form_id == 'user_edit' && !user_access('administer users')) {
247 // Only allow admins to change local passwords since they're autogenerated
248 // for CalNet users to prevent directly logging on.
249 unset($form['account']['pass']);
250 }
251 elseif ($form_id == 'user_pass') {
252 // Make sure non-admins aren't requesting new passwords.
253 $form['#validate']['calnet_user_pass_validate'] = array();
254 }
255 }
256
257 /**
258 * Forms API validation callback to validate logins.
259 */
260 function calnet_login_validate($form_id, $form_values) {
261 global $user;
262
263 if ($form_values['name']) {
264 if (user_is_blocked($form_values['name'])) {
265 // blocked in user administration
266 form_set_error('login', t('The username %name has not been activated or is blocked.', array('%name' => theme('placeholder', $form_values['name']))));
267 }
268 else if (drupal_is_denied('user', $form_values['name'])) {
269 // denied by access controls
270 form_set_error('login', t('The name %name is a reserved username.', array('%name' => theme('placeholder', $form_values['name']))));
271 }
272 else if ($form_values['pass']) {
273 // Try to log in the user locally. Don't set $user unless successful and
274 // this user doesn't require to be authenticated through CalNet.
275 if ($account = user_load(array('name' => $form_values['name'], 'pass' => $form_values['pass'], 'status' => 1))) {
276 // If they have a local account AND need to pass through CalNet, redirect.
277 /*if ($account->uid && calnet_user_needs_to_authenticate($account)) {
278 watchdog('calnet', t('User %user attempted to login directly and was redirected to the CalNet login page.', array('%user' => theme('placeholder', $form_values['name']))));
279
280 // Destroy session.
281 session_unset();
282 session_destroy();
283
284 // Send to CalNet login.
285 drupal_goto(_calnet_login_url());
286 return;
287 }
288 else {*/
289 $user = $account;
290 //}
291 }
292
293 if (!$user->uid) {
294 form_set_error('login', t('Sorry. Unrecognized username or password.') .' '. l(t('Have you forgotten your password?'), 'user/password'));
295 watchdog('user', t('Login attempt failed for %user.', array('%user' => theme('placeholder', $form_values['name']))));
296 }
297 }
298 }
299 }
300
301 function calnet_user_needs_to_authenticate($user) {
302 return $user->uid != 1;
303 }
304
305 /**
306 * Forms API validation callback to check that non-admins aren't using Drupal
307 * to request new passwords as their local passwords are auto-generated.
308 */
309 function calnet_user_pass_validate($form_id, $form_values) {
310 if ($form_values['name']) {
311 $account = user_load(array('name' => $form_values['name'], 'status' => 1));
312 }
313 else {
314 $account = user_load(array('mail' => $form_values['mail'], 'status' => 1));
315 }
316
317 // If this account isn't an admin, tell them to go to CalNet.
318 if (isset($account) && !isset($account->roles[BIGIDEAS_ADMIN_RID])) {
319 form_set_error('', t('Students must request new passwords through CalNet.'));
320 }
321 }
322
323 /**
324 * Forms API validation callback to check that $_SESSION['calnet_uid'] is set.
325 */
326 function calnet_user_register_validate($form_id, $form_values, $form) {
327 // If there is a bad CalNet ID in user's session, set an error and redirect.
328 // Shouldn't happen since we redirect in form_alter, but just to be sure.
329 if (!_calnet_is_valid_session_calnet_id()) {
330 form_set_error('', t('You must first %login before registering.', array('%login' => l(t('login through CalNet', _calnet_login_url())))));
331 }
332 }
333
334 /**
335 * Forms API validation callback to map $_SESSION['calnet_uid'] to Drupal user
336 * ID in the {calnet} table.
337 */
338 function calnet_user_register_submit($form_id, $form_values) {
339 global $user;
340
341 // Try to log in the user locally using Drupal username and email. Don't set $user unless successful.
342 if ($account = user_load(array('name' => $form_values['name'], 'init' => $form_values['mail'], 'status' => 1))) {
343 // Add this user to the 'student' role.
344 $array = array('roles' => $account->roles);
345 $array['roles'][BIGIDEAS_STUDENT_RID] = TRUE;
346 $user = user_save($account, $array);
347
348 // Create CalNet UID to Drupal UID mapping.
349 db_query('INSERT INTO {calnet} (drupal_uid, calnet_uid) VALUES (%d, %d)', $user->uid, $_SESSION['calnet_uid']);
350
351 watchdog('calnet', t('Register: CalNet ID %calnet successfully matched to Drupal account for %name.', array('%calnet' => theme('placeholder', $_SESSION['calnet_uid']), '%name' => theme('placeholder', $user->name))));
352
353 // Clear the message set by user.module and show our own welcome message.
354 drupal_get_messages();
355 drupal_set_message(t('Welcome to Big Ideas @ Berkeley! This is your first login message.'));
356 }
357 }
358
359 /**
360 * Helper function for user_register form. Adds a preview screen before
361 * creating a new user account. Called from the #after_build in the
362 * user_register form.
363 */
364 function calnet_user_register_form_add_preview($form) {
365 global $form_values;
366
367 $op = isset($_POST['op']) ? $_POST['op'] : '';
368 if ($op == t('Continue registration')) {
369 drupal_validate_form($form['form_id']['#value'], $form);
370 if (!form_get_errors()) {
371 $form['#prefix'] = '<div id="block-custom-register-3" class="block"><div class="h2-title"><div class="corner-top"><ul><li>&nbsp;</li></ul></div><h2 class="title-content">Enter Information</h2></div><div class="content"><p>You entered the following information. If all the information entered is correct then click Create new account.</p>';
372 $form['#suffix'] = '</div></div>';
373 foreach (element_children($form['account']) as $key) {
374 if ($form['account'][$key]['#type'] == 'textfield' || $form['account'][$key]['#type'] == 'textarea') {
375 $form['account'][$key]['#type'] = 'hidden';
376
377 // We pass the global $form_values here to preserve any changes made
378 // during form validation.
379 $form['account']['markup'][$key] = array(
380 '#type' => 'item',
381 '#title' => $form['account'][$key]['#title'],
382 '#value' => $form_values[$key],
383 '#weight' => $form['account'][$key]['#weight'],
384 );
385 }
386 }
387
388 // Allow users to go back and re-edit fields if they want.
389 $form['preview']['#value'] = t('Edit Information');
390 }
391 }
392 if (form_get_errors() || $op != t('Continue registration')) {
393 unset($form['submit']);
394 }
395 //dpr($form);
396 return $form;
397 }
398
399 function calnet_register_page() {
400 $output = '';
401
402 $output .= l(t('Log in to your CalNet account'), 'calnet/login', array('class' => 'button button-yellow-white'));
403 return $output;
404 }
405
406 /**
407 * Implementation of hook_user().
408 */
409 function calnet_user($type, &$edit, &$account, $category = NULL) {
410 if ($type == 'delete') {
411 db_query('DELETE FROM {calnet} WHERE drupal_uid = %d', $account->uid);
412 }
413 }
414
415 function _calnet_is_valid_session_calnet_id() {
416 return isset($_SESSION['calnet_uid']) && $_SESSION['calnet_uid'] !== FALSE;
417 }
418
419 function _calnet_login_url() {
420 $reentry_url = str_replace('http://', 'https://', url('calnet/reentry', NULL, NULL, TRUE));
421 return url('https://net-auth.berkeley.edu/cgi-bin/krbaws-v3', 'AppName='. drupal_urlencode('Big Ideas') .'&AppentryURL='. drupal_urlencode($reentry_url));
422 }

  ViewVC Help
Powered by ViewVC 1.1.2