Commit | Line | Data |
---|---|---|
7f254ad8 AE |
1 | <?php |
2 | ||
3 | /** | |
4 | * @file | |
5 | * Tests for cas.module. | |
6 | */ | |
7 | ||
8 | class CasTestHelper extends DrupalWebTestCase { | |
9 | protected $admin_user; | |
10 | ||
11 | /** | |
12 | * Helper class for CAS tests. | |
13 | * | |
14 | * Creates an administrative user and downloads phpCAS. | |
15 | */ | |
16 | function setUp() { | |
17 | // Install modules needed for this test. This could have been passed in as | |
18 | // either a single array argument or a variable number of string arguments. | |
19 | // @todo Remove this compatibility layer in Drupal 8, and only accept | |
20 | // $modules as a single array argument. | |
21 | $modules = func_get_args(); | |
22 | if (isset($modules[0]) && is_array($modules[0])) { | |
23 | $modules = $modules[0]; | |
24 | } | |
25 | ||
26 | // cas_test requires the CAS Server module. | |
27 | $modules = array_merge(array('cas', 'cas_test', 'cas_server'), $modules); | |
28 | parent::setUp($modules); | |
29 | ||
30 | // Tests will fail unless clean URLs are enabled, due to an incompatibility | |
31 | // in phpCAS. | |
32 | variable_set('clean_url', TRUE); | |
33 | ||
34 | // Create admin user. | |
35 | $this->admin_user = $this->drupalCreateUser(array('administer users', 'administer cas')); | |
36 | ||
37 | // Download and extract in PHPCAS. | |
38 | $this->downloadExtractPhpCas('1.3.3'); | |
39 | } | |
40 | ||
41 | /** | |
42 | * Download and extract phpCAS. | |
43 | * | |
44 | * Sets the 'cas_library_dir' variable to the directory where phpCAS | |
45 | * is downloaded. | |
46 | * | |
47 | * @param $version | |
48 | * The phpCAS version number to download and extract. | |
49 | */ | |
50 | function downloadExtractPhpCas($version) { | |
51 | // Find the most URL of the most recent phpCAS version. | |
52 | $directory = 'CAS-' . $version; | |
53 | $filename = 'CAS-' . $version . '.tgz'; | |
54 | $url = 'http://downloads.jasig.org/cas-clients/php/' . $version . '/' . $filename; | |
55 | ||
56 | // Avoid downloading the file dozens of times | |
57 | $simpletest_cache = $this->originalFileDirectory . '/simpletest/cas'; | |
58 | if (!file_exists($simpletest_cache)) { | |
59 | mkdir($simpletest_cache); | |
60 | } | |
61 | ||
62 | // Local archive name. | |
63 | $local_archive = $simpletest_cache . '/' . $filename; | |
64 | $cas_library_dir = $simpletest_cache . '/' . $directory; | |
65 | ||
66 | // Begin single threaded code. | |
67 | if (function_exists('sem_get')) { | |
68 | $semaphore = sem_get(ftok(__FILE__, 1)); | |
69 | sem_acquire($semaphore); | |
70 | } | |
71 | ||
72 | // Download and extact the archive, but only in one thread. | |
73 | if (!file_exists($local_archive)) { | |
74 | $local_archive = system_retrieve_file($url, $local_archive, FALSE, FILE_EXISTS_REPLACE); | |
75 | } | |
76 | if (!file_exists($cas_library_dir)) { | |
77 | // Extract the files. | |
78 | $archiver = archiver_get_archiver($local_archive); | |
79 | $archiver->extract($simpletest_cache); | |
80 | } | |
81 | if (function_exists('sem_get')) { | |
82 | sem_release($semaphore); | |
83 | } | |
84 | // End single threaded code. | |
85 | ||
86 | // Verify that files were successfully extracted. | |
87 | $this->assertTrue(file_exists($cas_library_dir . '/CAS.php'), t('CAS.php found in @cas_library_dir.', array('@cas_library_dir' => $cas_library_dir))); | |
88 | ||
89 | // Set the CAS library directory. | |
90 | variable_set('cas_library_dir', $cas_library_dir); | |
91 | } | |
92 | ||
93 | /** | |
94 | * Create a CAS user with the specified username. | |
95 | * | |
96 | * @param $cas_name | |
97 | * The CAS username. If omitted, a CAS username will be automatically | |
98 | * generated. | |
99 | * @param $permissions | |
100 | * An array of permissions to assign to the created user. | |
101 | * | |
102 | * @return | |
103 | * A user account object. The CAS username is present in the cas_name | |
104 | * field. | |
105 | */ | |
106 | function casCreateUser($cas_name = NULL, $permissions = array('access comments', 'access content', 'post comments', 'skip comment approval')) { | |
107 | // Create user. | |
108 | $account = $this->drupalCreateUser($permissions); | |
109 | $pass_raw = $account->pass_raw; | |
110 | ||
111 | // Add CAS username. | |
112 | if (empty($cas_name)) { | |
113 | $cas_name = $this->randomName(); | |
114 | } | |
115 | $edit['cas_name'] = $cas_name; | |
116 | $account = user_save($account, $edit); | |
117 | ||
118 | // Restore password. | |
119 | $account->pass_raw = $pass_raw; | |
120 | return $account; | |
121 | } | |
122 | ||
123 | /** | |
124 | * Log in a CAS user with the internal browser. | |
125 | * | |
126 | * @param $account | |
127 | * A user object with a valid CAS username field, or the CAS username as a | |
128 | * string. | |
129 | * @param $attributes | |
130 | * Additional attributes for the CAS user. | |
131 | */ | |
132 | function casLogin($account, $attributes = array()) { | |
133 | if ($this->loggedInUser) { | |
134 | $this->drupalLogout(); | |
135 | } | |
136 | ||
137 | // Log in the user. | |
138 | $cas_name = $this->setCasUser($account, $attributes); | |
139 | $this->drupalGet('cas'); | |
140 | ||
141 | $pass = $this->assertLink(t('Log out'), 0, t('CAS user %cas_name successfully logged in.', array('%cas_name' => $cas_name)), t('User login')); | |
142 | if ($pass) { | |
143 | $this->loggedInUser = cas_user_load_by_name($cas_name, TRUE, TRUE); | |
144 | } | |
145 | } | |
146 | ||
147 | /** | |
148 | * Set the CAS username and attributes for the next CAS login request. | |
149 | * | |
150 | * @param $account | |
151 | * A user object with a valid CAS username field, or the CAS username as a | |
152 | * string. | |
153 | * @param $attributes | |
154 | * Additional attributes for the CAS user. | |
155 | * | |
156 | * @return | |
157 | * The CAS username. | |
158 | */ | |
159 | function setCasUser($account, $attributes = array()) { | |
160 | $cas_name = is_object($account) ? $account->cas_name : $account; | |
161 | $cas_user = array('name' => $cas_name, 'attributes' => $attributes); | |
162 | variable_set('cas_test_cas_user', $cas_user); | |
163 | return $cas_name; | |
164 | } | |
165 | ||
166 | /** | |
167 | * Clear the CAS username and attributes for the next CAS login request. | |
168 | */ | |
169 | function clearCasUser() { | |
170 | variable_del('cas_test_cas_user'); | |
171 | } | |
172 | ||
173 | /** | |
174 | * Assert that the user has logged in. | |
175 | * | |
176 | * @return | |
177 | * TRUE if the assertion succeeded, FALSE otherwise. | |
178 | */ | |
179 | function assertLoggedIn($account) { | |
180 | $pass = $this->assertLink(t('Log out'), 0, t('CAS user %cas_name successfully logged in.', array('%cas_name' => $account->cas_name)), t('User login')); | |
181 | if ($pass) { | |
182 | $this->loggedInUser = $account; | |
183 | } | |
184 | return $pass; | |
185 | } | |
186 | ||
187 | /** | |
188 | * Assert that the user has been logged out. | |
189 | * | |
190 | * @return | |
191 | * TRUE if the assertion succeeded, FALSE otherwise. | |
192 | */ | |
193 | function assertLoggedOut() { | |
194 | $this->drupalGet('user'); | |
195 | $pass = $this->assertField('name', t('Username field found.'), t('Logout')); | |
196 | $pass = $pass && $this->assertField('pass', t('Password field found.'), t('Logout')); | |
197 | if ($pass) { | |
198 | $this->loggedInUser = FALSE; | |
199 | } | |
200 | return $pass; | |
201 | } | |
202 | ||
203 | /** | |
204 | * Assert the value of the token. | |
205 | * | |
206 | * @param $token | |
207 | * A token to evaluate for the current CAS user. | |
208 | * @param $value | |
209 | * The expected value after the token is evaluated. | |
210 | * @param $message | |
211 | * The message to display along with the assertion. | |
212 | * | |
213 | * @return | |
214 | * TRUE if the assertion succeeded, FALSE otherwise. | |
215 | */ | |
216 | function assertToken($token, $value, $message = '') { | |
217 | $options = array( | |
218 | 'query' => array( | |
219 | 'token' => $token, | |
220 | 'name' => $this->loggedInUser->cas_name, | |
221 | ), | |
222 | ); | |
223 | $path = 'cas_test/token'; | |
224 | $out = $this->drupalGet($path, $options); | |
225 | return $this->assertEqual($out, $value, $message, 'Token'); | |
226 | } | |
227 | ||
228 | } | |
229 | ||
230 | class CasUserAdminTestCase extends CasTestHelper { | |
231 | ||
232 | public static function getInfo() { | |
233 | return array( | |
234 | 'name' => 'User administration', | |
235 | 'description' => 'Test CAS user administration.', | |
236 | 'group' => 'Central Authentication Service' | |
237 | ); | |
238 | } | |
239 | ||
240 | /** | |
241 | * Registers, modifies, and deletes a CAS user using User API hooks. | |
242 | */ | |
243 | function testCASUserHooks() { | |
244 | // Create a test account. | |
245 | $account = $this->drupalCreateUser(); | |
246 | $uid = $account->uid; | |
247 | ||
248 | // Add a CAS username. | |
249 | $cas_name = $this->randomName(); | |
250 | $edit = array('cas_name' => $cas_name); | |
251 | $account = user_save($account, $edit); | |
252 | $this->assertEqual($cas_name, $account->cas_name, t('CAS username %cas_name successfully created.', array('%cas_name' => $cas_name))); | |
253 | ||
254 | // Reload the account and ensure the CAS name is still present. | |
255 | $account = user_load($uid); | |
256 | $this->assertEqual($cas_name, $account->cas_name, t('CAS username %cas_name successfully saved.', array('%cas_name' => $cas_name))); | |
257 | ||
258 | // Load the account by the CAS username. | |
259 | $account = cas_user_load_by_name($cas_name); | |
260 | $this->assertEqual($uid, $account->uid, t('Loaded the correct account with CAS username %cas_name.', array('%cas_name' => $cas_name))); | |
261 | ||
262 | // Change the CAS username. | |
263 | $cas_new_name = $this->randomName(); | |
264 | $account = user_load($uid); | |
265 | $edit = array('cas_name' => $cas_new_name); | |
266 | user_save($account, $edit); | |
267 | $account = user_load($uid); | |
268 | $this->assertEqual($cas_new_name, $account->cas_name, t('CAS username %cas_name successfully updated.', array('%cas_name' => $cas_new_name))); | |
269 | $this->assertEqual(count($account->cas_names), 1, t('Only one CAS username is present.')); | |
270 | $account = cas_user_load_by_name($cas_name); | |
271 | $this->assertFalse($account, t('Could not load account using old CAS username.')); | |
272 | ||
273 | // Remove the CAS username. | |
274 | $account = user_load($uid); | |
275 | $edit = array('cas_name' => NULL); | |
276 | user_save($account, $edit); | |
277 | $account = user_load($uid); | |
278 | $this->assertFalse($account->cas_name, t('CAS username successfully deleted.')); | |
279 | $this->assertEqual(count($account->cas_names), 0, t('No CAS usernames are present.')); | |
280 | ||
281 | // Attempt to load by a non-existent CAS username. | |
282 | $account = cas_user_load_by_name($cas_new_name); | |
283 | $this->assertFalse($account, t('Could not load account with non-existent CAS username.')); | |
284 | ||
285 | // Verify that all CAS usernames have been removed from {cas_user}. | |
286 | $cas_uid_count = db_select('cas_user') | |
287 | ->condition('cas_name', array($cas_name, $cas_new_name), 'IN') | |
288 | ->countQuery() | |
289 | ->execute() | |
290 | ->fetchField(); | |
291 | $this->assertEqual($cas_uid_count, 0, t('CAS usernames successfully removed from {cas_user}.')); | |
292 | } | |
293 | /** | |
294 | * Tests adding a user with a CAS username in the administrative interface. | |
295 | */ | |
296 | function testUserAdd() { | |
297 | $this->drupalLogin($this->admin_user); | |
298 | ||
299 | // Register a user with a CAS username. | |
300 | $cas_name = $this->randomName(); | |
301 | $edit = array( | |
302 | 'name' => $this->randomName(), | |
303 | 'mail' => $this->randomName() . '@example.com', | |
304 | 'cas_name' => $cas_name, | |
305 | 'pass[pass1]' => $pass = $this->randomString(), | |
306 | 'pass[pass2]' => $pass, | |
307 | 'notify' => FALSE, | |
308 | ); | |
309 | $this->drupalPost('admin/people/create', $edit, t('Create new account')); | |
310 | $this->assertText(t('Created a new user account for @name. No e-mail has been sent.', array('@name' => $edit['name'])), 'User created'); | |
311 | ||
312 | $this->drupalGet('admin/people'); | |
313 | $this->assertText($edit['name'], 'User found in list of users'); | |
314 | $this->assertText($edit['cas_name'], 'CAS username found in list of users'); | |
315 | ||
316 | // Verify that duplicate CAS usernames are not allowed. | |
317 | $edit = array( | |
318 | 'name' => $this->randomName(), | |
319 | 'mail' => $this->randomName() . '@example.com', | |
320 | 'cas_name' => $cas_name, | |
321 | 'pass[pass1]' => $pass = $this->randomString(), | |
322 | 'pass[pass2]' => $pass, | |
323 | 'notify' => FALSE, | |
324 | ); | |
325 | $this->drupalPost('admin/people/create', $edit, t('Create new account')); | |
326 | $this->assertText(t('The CAS username is already in use on this site.'), 'CAS username already in use.'); | |
327 | } | |
328 | ||
329 | /** | |
330 | * Tests adding a CAS user in the administrative interface. | |
331 | */ | |
332 | function testCasUserAdd() { | |
333 | $this->drupalLogin($this->admin_user); | |
334 | ||
335 | // Add 3 CAS users. | |
336 | $edit = array(); | |
337 | for ($i = 0; $i < 3; $i++) { | |
338 | $cas_names[] = $this->randomName(); | |
339 | } | |
340 | $edit['cas_name'] = implode("\n", $cas_names); | |
341 | $this->drupalPost('admin/people/cas/create', $edit, t('Create new account(s)')); | |
342 | $this->assertText(t('The following 3 CAS usernames were created: @cas_names', array('@cas_names' => implode(', ', $cas_names))), 'Users created'); | |
343 | ||
344 | // Verify the users show up in the list of all users. | |
345 | $this->drupalGet('admin/people'); | |
346 | foreach ($cas_names as $cas_name) { | |
347 | $this->assertNoUniqueText($cas_name, 'User and CAS username found in list of users'); | |
348 | } | |
349 | ||
350 | // Attempt to add one of the users again and see that it fails. | |
351 | $edit['cas_name'] = $cas_names[0]; | |
352 | $this->drupalPost('admin/people/cas/create', $edit, t('Create new account(s)')); | |
353 | $this->assertText(t('The CAS username is already in use on this site.'), 'CAS username already in use.'); | |
354 | } | |
355 | } | |
356 | ||
357 | /** | |
358 | * Test case to test user editing behavior. | |
359 | */ | |
360 | class CasUserTestCase extends CasTestHelper { | |
361 | ||
362 | public static function getInfo() { | |
363 | return array( | |
364 | 'name' => 'User behavior', | |
365 | 'description' => 'Test CAS user behavior, including auto-registration and user editing.', | |
366 | 'group' => 'Central Authentication Service', | |
367 | ); | |
368 | } | |
369 | ||
370 | /** | |
371 | * Tests automatically registering a user on login. | |
372 | */ | |
373 | function testCasAutoRegister() { | |
374 | $cas_name = $this->randomName(); | |
375 | $this->setCasUser($cas_name); | |
376 | ||
377 | // Test that the user is not automatically registered. | |
378 | variable_set('cas_user_register', FALSE); | |
379 | $this->drupalGet('cas'); | |
380 | $this->assertRaw(t('No account found for %cas_name.', array('%cas_name' => $cas_name))); | |
381 | ||
382 | // Ensure that the login result is not cached. | |
383 | $cas_name = $this->randomName(); | |
384 | $this->setCasUser($cas_name); | |
385 | $this->drupalGet('cas'); | |
386 | $this->assertRaw(t('No account found for %cas_name.', array('%cas_name' => $cas_name))); | |
387 | ||
388 | // Test that the user is automatically registered. | |
389 | variable_set('cas_user_register', TRUE); | |
390 | $this->drupalGet('cas'); | |
391 | $this->loggedInUser = cas_user_load_by_name($cas_name, TRUE); | |
392 | $this->assertRaw(t('Logged in via CAS as %cas_username.', array('%cas_username' => $cas_name))); | |
393 | $this->drupalLogout(); | |
394 | ||
395 | // Create a new user. | |
396 | $user2 = $this->drupalCreateUser(); | |
397 | $cas_name = $user2->name; | |
398 | $this->setCasUser($cas_name); | |
399 | ||
400 | // Test that CAS does not hijack an existing username. | |
401 | $this->drupalGet('cas'); | |
402 | $this->assertRaw(t('A new account could not be created for %cas_name. The username is already in use on this site.', array('%cas_name' => $cas_name))); | |
403 | } | |
404 | ||
405 | function testUserEdit() { | |
406 | $cas_name = $this->randomName(); | |
407 | $account = $this->casCreateUser($cas_name, array('change own username')); | |
408 | ||
409 | $this->casLogin($cas_name); | |
410 | ||
411 | // Standard user page. | |
412 | variable_set('cas_hide_email', FALSE); | |
413 | variable_set('cas_hide_password', FALSE); | |
414 | $this->drupalGet("user/$account->uid/edit"); | |
415 | $this->assertField('mail', 'E-mail field is present.'); | |
416 | $this->assertField('current_pass', 'Current password field is present.'); | |
417 | $this->assertField('pass[pass1]', 'Existing password field 1 is present.'); | |
418 | $this->assertField('pass[pass2]', 'Existing password field 2 is present.'); | |
419 | $edit = array( | |
420 | 'mail' => $mail = $this->randomName() . '@example.com', | |
421 | 'current_pass' => $account->pass_raw, | |
422 | ); | |
423 | $this->drupalPost("user/$account->uid/edit", $edit, t('Save')); | |
424 | $this->assertFieldByName('mail', $mail); | |
425 | ||
426 | // Hide the password, ensure edits can be made without providing | |
427 | // the current password. | |
428 | variable_set('cas_hide_password', TRUE); | |
429 | $this->drupalGet("user/$account->uid/edit"); | |
430 | $this->assertNoField('current_pass', 'Current password field is not present.'); | |
431 | $this->assertNoField('pass[pass1]', 'Existing password field 1 is not present.'); | |
432 | $this->assertNoField('pass[pass2]', 'Existing password field 2 is not present.'); | |
433 | $edit = array( | |
434 | 'mail' => $mail = $this->randomName() . '@example.com', | |
435 | ); | |
436 | $this->drupalPost("user/$account->uid/edit", $edit, t('Save')); | |
437 | $this->assertFieldByName('mail', $mail); | |
438 | ||
439 | // Hide the e-mail field as well, ensure that it is not visible. | |
440 | variable_set('cas_hide_email', TRUE); | |
441 | $this->drupalGet("user/$account->uid/edit"); | |
442 | $this->assertNoField('mail', 'E-mail field is not present.'); | |
443 | } | |
444 | ||
445 | function testNameToken() { | |
446 | $account = $this->casCreateUser(); | |
447 | $this->casLogin($account); | |
448 | ||
449 | $this->assertToken('[cas:name]', $account->cas_name); | |
450 | } | |
451 | ||
452 | function testCaseInsensitiveLogin() { | |
453 | $account = $this->casCreateUser(); | |
454 | $this->casLogin(strtoupper($account->cas_name)); | |
455 | $this->assertLoggedIn($account); | |
456 | } | |
457 | ||
458 | } | |
459 | ||
460 | /** | |
461 | * Test case to test user logout behavior. | |
462 | */ | |
463 | class CasLogoutRedirectionTestCase extends CasTestHelper { | |
464 | ||
465 | public static function getInfo() { | |
466 | return array( | |
467 | 'name' => 'Logout redirection', | |
468 | 'description' => 'Test CAS user logout redirection.', | |
469 | 'group' => 'Central Authentication Service', | |
470 | ); | |
471 | } | |
472 | ||
473 | /** | |
474 | * Test redirection on user logout. | |
475 | */ | |
476 | function testLogoutRedirection() { | |
477 | $account = $this->casCreateUser(); | |
478 | ||
479 | $this->casLogin($account); | |
480 | $this->drupalGet('caslogout'); | |
481 | $this->assertText('Logged out. No redirection provided.'); | |
482 | $this->assertLoggedOut(); | |
483 | ||
484 | // Verify the destination parameter may be passed on logout, i.e., | |
485 | // caslogout?destination=node | |
486 | $destination = 'node'; | |
487 | $this->casLogin($account); | |
488 | $this->drupalGet('caslogout', array('query' => array('destination' => $destination))); | |
489 | $this->assertText(t('Logged out. Continue to @url.', array('@url' => url($destination, array('absolute' => TRUE))))); | |
490 | $this->assertLoggedOut(); | |
491 | ||
492 | // Verify that remote destination parameters are not allowed. | |
493 | $destination = 'http://example.com/?query=yes#fragment'; | |
494 | $this->casLogin($account); | |
495 | $this->drupalGet('caslogout', array('query' => array('destination' => $destination))); | |
496 | $this->assertText(t('Logged out. No redirection provided.')); | |
497 | $this->assertLoggedOut(); | |
498 | ||
499 | // Verify 'cas_logout_destination' works for a variety of destinations, | |
500 | // including remote destinations. | |
501 | $destinations = array('<front>', 'http://example.com/?query=yes#fragment', 'node/1'); | |
502 | foreach ($destinations as $destination) { | |
503 | variable_set('cas_logout_destination', $destination); | |
504 | $this->casLogin($account); | |
505 | $this->drupalGet('caslogout'); | |
506 | $this->assertText(t('Logged out. Continue to @url.', array('@url' => url($destination, array('absolute' => TRUE))))); | |
507 | $this->assertLoggedOut(); | |
508 | } | |
509 | ||
510 | // Verify 'cas_logout_destination' can be overwritten by passing the | |
511 | // destination query string. | |
512 | variable_set('cas_logout_destination', 'http://example.com/'); | |
513 | $destination = 'node/1'; | |
514 | $this->casLogin($account); | |
515 | $this->drupalGet('caslogout', array('query' => array('destination' => $destination))); | |
516 | $this->assertText(t('Logged out. Continue to @url.', array('@url' => url($destination, array('absolute' => TRUE))))); | |
517 | $this->assertLoggedOut(); | |
518 | } | |
519 | } | |
520 | ||
521 | /** | |
522 | * Test case to test user login behavior. | |
523 | */ | |
524 | class CasLoginRedirectionTestCase extends CasTestHelper { | |
525 | ||
526 | public static function getInfo() { | |
527 | return array( | |
528 | 'name' => 'Login redirection', | |
529 | 'description' => 'Test CAS user login redirection.', | |
530 | 'group' => 'Central Authentication Service', | |
531 | ); | |
532 | } | |
533 | ||
534 | /** | |
535 | * Verify login redirection for an existing user. | |
536 | */ | |
537 | function testExistingUserLoginRedirection() { | |
538 | $node1 = $this->drupalCreateNode(); | |
539 | $node2 = $this->drupalCreateNode(); | |
540 | $node3 = $this->drupalCreateNode(); | |
541 | ||
542 | // Create a CAS user. | |
543 | $account = $this->casCreateUser(); | |
544 | $cas_name = $account->cas_name; | |
545 | $this->setCasUser($cas_name); | |
546 | ||
547 | // Test going to 'cas' | |
548 | $this->drupalGet('cas'); | |
549 | $this->assertLoggedIn($account); | |
550 | $this->assertUrl(''); | |
551 | $this->drupalLogout(); | |
552 | ||
553 | // Test going to 'cas?destination=node/$node1->nid' | |
554 | $destination = "node/$node1->nid"; | |
555 | $this->drupalGet('cas', array('query' => array('destination' => $destination))); | |
556 | $this->assertLoggedIn($account); | |
557 | $this->assertUrl($destination); | |
558 | $this->drupalLogout(); | |
559 | ||
560 | // Use the login block on $node2. | |
561 | $destination = "node/$node2->nid"; | |
562 | variable_set('cas_login_form', CAS_ADD_LINK); | |
563 | $edit = array('cas_identifier' => TRUE); | |
564 | $this->drupalPost($destination, $edit, t('Log in')); | |
565 | $this->assertLoggedIn($account); | |
566 | $this->assertUrl($destination); | |
567 | $this->drupalLogout(); | |
568 | ||
569 | // Use the regular login page, without a destination. | |
570 | $edit = array('cas_identifier' => TRUE); | |
571 | $this->drupalPost('user/login', $edit, t('Log in')); | |
572 | $this->assertLoggedIn($account); | |
573 | $this->assertUrl('user'); | |
574 | $this->drupalLogout(); | |
575 | ||
576 | // Use the regular login page, with a destination. | |
577 | $destination = "node/$node3->nid"; | |
578 | $edit = array('cas_identifier' => TRUE); | |
579 | $this->drupalPost('user/login', $edit, t('Log in'), array('query' => array('destination' => $destination))); | |
580 | $this->assertLoggedIn($account); | |
581 | $this->assertUrl($destination); | |
582 | $this->drupalLogout(); | |
583 | ||
584 | // External destinations are not allowed. | |
585 | $destination = ''; | |
586 | $this->drupalGet('cas', array('query' => array('destination' => 'http://example.com/node/3'))); | |
587 | $this->assertLoggedIn($account); | |
588 | $this->assertUrl($destination); | |
589 | $this->drupalLogout(); | |
590 | } | |
591 | ||
592 | /** | |
593 | * Verify login redirection for a new user. | |
594 | */ | |
595 | function testNewUserLoginRedirection() { | |
596 | // Initial login without a destination goes to front page. | |
597 | $cas_name = $this->randomName(); | |
598 | $this->casLogin($cas_name); | |
599 | $this->assertUrl(''); | |
600 | $this->drupalLogout(); | |
601 | ||
602 | // Initial login with redirection goes to specified destination. | |
603 | $node = $this->drupalCreateNode(); | |
604 | variable_set('cas_first_login_destination', "node/$node->nid"); | |
605 | $cas_name = $this->randomName(); | |
606 | $account = $this->casLogin($cas_name); | |
607 | $this->assertUrl("node/$node->nid"); | |
608 | $this->drupalLogout(); | |
609 | ||
610 | // The second login should not be redirected. | |
611 | $this->casLogin($cas_name); | |
612 | $this->assertUrl(''); | |
613 | $this->drupalLogout(); | |
614 | ||
615 | // Initial login with a admin-created account goes to the specified | |
616 | // destination. | |
617 | $account = $this->casCreateUser(); | |
618 | $this->casLogin($account); | |
619 | $this->assertUrl("node/$node->nid"); | |
620 | $this->drupalLogout(); | |
621 | ||
622 | // The second login should not be redirected. | |
623 | $this->casLogin($account); | |
624 | $this->assertUrl(''); | |
625 | $this->drupalLogout(); | |
626 | } | |
627 | } | |
628 | ||
629 | /** | |
630 | * Test CAS Single Sign-Out. | |
631 | */ | |
632 | class CasSingleSignOutTestCase extends CasTestHelper { | |
633 | ||
634 | public static function getInfo() { | |
635 | return array( | |
636 | 'name' => 'Single Sign-Out', | |
637 | 'description' => 'Test CAS Single Sign-Out.', | |
638 | 'group' => 'Central Authentication Service', | |
639 | ); | |
640 | } | |
641 | ||
642 | function testSingleSignOut() { | |
643 | // Create a user, and log in. | |
644 | $cas_name = $this->randomName(); | |
645 | $account = $this->casCreateUser($cas_name); | |
646 | $this->casLogin($account); | |
647 | ||
648 | cas_test_single_sign_out($cas_name); | |
649 | $this->assertLoggedOut(); | |
650 | ||
651 | // @todo: Add additional tests for other methods of logging in (especially | |
652 | // methods coming from cas_pages). | |
653 | } | |
654 | ||
655 | function testSingleSignOutDoubleEncode() { | |
656 | // Create a user, and log in. | |
657 | $cas_name = $this->randomName(); | |
658 | $account = $this->casCreateUser($cas_name); | |
659 | $this->casLogin($account); | |
660 | ||
661 | cas_test_single_sign_out($cas_name, TRUE); | |
662 | $this->assertLoggedOut(); | |
663 | ||
664 | // @todo: Add additional tests for other methods of logging in (especially | |
665 | // methods coming from cas_pages). | |
666 | } | |
667 | } | |
668 | ||
669 | /** | |
670 | * Test case for CAS gateway feature. | |
671 | */ | |
672 | class CasGatewayTestCase extends CasTestHelper { | |
673 | ||
674 | public static function getInfo() { | |
675 | return array( | |
676 | 'name' => 'CAS Gateway', | |
677 | 'description' => 'Test CAS Gateway ("Check to see if user is already logged in") feature.', | |
678 | 'group' => 'Central Authentication Service', | |
679 | ); | |
680 | } | |
681 | ||
682 | function setUp() { | |
683 | parent::setUp(); | |
684 | } | |
685 | ||
686 | /** | |
687 | * Test the CAS Gateway functionality of the user is not logged in. | |
688 | */ | |
689 | function testCasGatewayLoggedOut() { | |
690 | $node1 = $this->drupalCreateNode(); | |
691 | ||
692 | variable_set('cas_check_frequency', CAS_CHECK_ONCE); | |
693 | $this->drupalGet(''); | |
694 | $this->assertTrue($this->redirect_count == 2, 'Polled CAS server on first request.'); | |
695 | $this->drupalGet(''); | |
696 | $this->assertEqual($this->redirect_count, 0, 'Did not poll CAS server on second request.'); | |
697 | $this->drupalGet('node/' . $node1->nid); | |
698 | $this->assertEqual($this->redirect_count, 0, 'Did not poll CAS server on third request.'); | |
699 | $this->assertFalse($this->loggedInUser); | |
700 | ||
701 | variable_set('cas_check_frequency', CAS_CHECK_ALWAYS); | |
702 | $this->drupalGet(''); | |
703 | $this->assertTrue($this->redirect_count == 2, 'Polled CAS server on first request'); | |
704 | $this->drupalGet(''); | |
705 | $this->assertTrue($this->redirect_count == 2, 'Polled CAS server on second request'); | |
706 | $this->drupalGet('node/' . $node1->nid); | |
707 | $this->assertEqual($this->redirect_count == 2, 'Polled CAS server on third request'); | |
708 | $this->assertFalse($this->loggedInUser); | |
709 | } | |
710 | ||
711 | /** | |
712 | * Test the CAS Gateway functionality of the user is logged in. | |
713 | */ | |
714 | function testCasGatewayLoggedIn() { | |
715 | // Create a user. | |
716 | $cas_name = $this->randomName(); | |
717 | $account = $this->casCreateUser($cas_name); | |
718 | $this->setCasUser($cas_name); | |
719 | ||
720 | variable_set('cas_check_frequency', CAS_CHECK_ONCE); | |
721 | $this->drupalGet(''); | |
722 | $this->assertLoggedIn($account); | |
723 | // Logging out should immediately log a user back in | |
724 | $this->drupalGet('user/logout'); | |
725 | $this->assertLoggedIn($account); | |
726 | ||
727 | variable_set('cas_check_frequency', CAS_CHECK_ALWAYS); | |
728 | $this->drupalGet(''); | |
729 | $this->assertLoggedIn($account); | |
730 | // Logging out should immediately log a user back in | |
731 | $this->drupalGet('user/logout'); | |
732 | $this->assertLoggedIn($account); | |
733 | } | |
734 | } | |
735 | ||
736 | /** | |
737 | * Test case for CAS force login feature. | |
738 | */ | |
739 | class CasRequiredLoginTestCase extends CasTestHelper { | |
740 | ||
741 | public static function getInfo() { | |
742 | return array( | |
743 | 'name' => 'Required Login', | |
744 | 'description' => 'Test CAS required login redirection.', | |
745 | 'group' => 'Central Authentication Service', | |
746 | ); | |
747 | } | |
748 | ||
749 | /** | |
750 | * Test redirection forced by cas_access and cas_pages variables. | |
751 | */ | |
752 | function testCasPages() { | |
753 | $node1 = $this->drupalCreateNode(); | |
754 | $node2 = $this->drupalCreateNode(); | |
755 | $account = $this->casCreateUser(); | |
756 | $this->setCasUser($account); | |
757 | ||
758 | $this->drupalGet("node/$node2->nid"); | |
759 | ||
760 | // Enable required login for $node. | |
761 | variable_set('cas_access', 0); | |
762 | variable_set('cas_pages', "node/$node1->nid\nnode/$node2->nid"); | |
763 | ||
764 | // Visit the node and verify we are logged in. | |
765 | $this->drupalGet("node/$node2->nid"); | |
766 | $this->assertLoggedIn($account); | |
767 | $this->assertUrl("node/$node2->nid"); | |
768 | $this->drupalLogout(); | |
769 | ||
770 | // Invert the access restrictions. Verify we can get the access the node | |
771 | // without restriction. | |
772 | variable_set('cas_access', 1); | |
773 | $this->drupalGet("node/$node1->nid"); | |
774 | $this->assertField('name', t('Username field found.'), t('Logout')); | |
775 | $this->assertField('pass', t('Password field found.'), t('Logout')); | |
776 | ||
777 | // Verify that accessing any other page redirects to the login page. | |
778 | $this->clearCasUser(); | |
779 | $this->drupalGet('node'); | |
780 | $this->assertText('No CAS name provided.'); | |
781 | } | |
782 | ||
783 | /** | |
784 | * Test redirection prevented by cas_exclude. | |
785 | */ | |
786 | function testCasExclude() { | |
787 | $node = $this->drupalCreateNode(); | |
788 | $account = $this->casCreateUser(); | |
789 | $this->setCasUser($account); | |
790 | ||
791 | variable_set('cas_check_frequency', CAS_CHECK_ONCE); | |
792 | variable_set('cas_exclude', "node/$node->nid"); | |
793 | ||
794 | // Visit an excluded page and ensure we did not try to log in. | |
795 | $this->drupalGet("node/$node->nid"); | |
796 | $this->assertField('name', t('Username field found.'), t('Logout')); | |
797 | $this->assertField('pass', t('Password field found.'), t('Logout')); | |
798 | ||
799 | // Visit another page and ensure we logged in. | |
800 | $this->drupalGet('node'); | |
801 | $this->assertLoggedIn($account); | |
802 | $this->assertUrl('node'); | |
803 | } | |
804 | } | |
805 | ||
806 | /** | |
807 | * Tests the visibility and functionality of the CAS login block. | |
808 | */ | |
809 | class CasLoginBlockTestCase extends CasTestHelper { | |
810 | public static function getInfo() { | |
811 | return array( | |
812 | 'name' => 'CAS login block', | |
813 | 'description' => 'Tests the CAS login block.', | |
814 | 'group' => 'Central Authentication Service', | |
815 | ); | |
816 | } | |
817 | ||
818 | function setUp() { | |
819 | parent::setUp(); | |
820 | ||
821 | // Enable the CAS login block. | |
822 | $admin_user = $this->drupalCreateUser(array('administer blocks')); | |
823 | $this->drupalLogin($admin_user); | |
824 | $edit = array( | |
825 | 'blocks[user_login][region]' => '-1', | |
826 | 'blocks[cas_login][region]' => 'sidebar_first', | |
827 | ); | |
828 | $this->drupalPost('admin/structure/block', $edit, t('Save blocks')); | |
829 | $this->drupalLogout(); | |
830 | } | |
831 | ||
832 | /** | |
833 | * Asserts that the CAS login block is shown or not shown. | |
834 | * | |
835 | * @param $visible | |
836 | * Whether or not the CAS login block is expected to be shown. | |
837 | * | |
838 | * @return | |
839 | * TRUE if the assertion succeeded, FALSE otherwise. | |
840 | */ | |
841 | function assertCasLoginBlock($visible) { | |
842 | $xpath = '//div[@id=block-cas-0]/*'; | |
843 | $xpath = $this->buildXPathQuery('//div[@id=:id]/*', array(':id' => 'block-cas-login')); | |
844 | if ($visible) { | |
845 | return $this->assertFieldByXPath($xpath, NULL, t('CAS login block found.')); | |
846 | } | |
847 | else { | |
848 | return $this->assertNoFieldByXPath($xpath, NULL, t('CAS login block not found.')); | |
849 | } | |
850 | } | |
851 | ||
852 | /** | |
853 | * Tests the visibility and functionality of the CAS login block. | |
854 | */ | |
855 | function testCasLoginBlock() { | |
856 | $account = $this->casCreateUser(); | |
857 | $this->setCasUser($account); | |
858 | ||
859 | // Verify that the block is shown on some pages, but not on others. | |
860 | $this->drupalGet(''); | |
861 | $this->assertCasLoginBlock(TRUE); | |
862 | ||
863 | $this->drupalGet('user'); | |
864 | $this->assertCasLoginBlock(FALSE); | |
865 | ||
866 | $this->drupalGet('user/1'); | |
867 | $this->assertCasLoginBlock(TRUE); | |
868 | ||
869 | // Log in using the login block, and verify redirection works. | |
870 | $edit = array(); | |
871 | $submit = t(variable_get('cas_login_invite', CAS_LOGIN_INVITE_DEFAULT)); | |
872 | ||
873 | $this->drupalPost('', $edit, $submit); | |
874 | $this->assertLoggedIn($account); | |
875 | $this->assertUrl('node'); | |
876 | ||
877 | // Block should not be shown to logged in users. | |
878 | $this->assertCasLoginBlock(FALSE); | |
879 | } | |
880 | } |