Mercurial > hg > rr-repo
comparison sites/all/modules/captcha/captcha.test @ 2:b74b41bb73f0
-- Google analytics module
author | danieleb <danielebarchiesi@me.com> |
---|---|
date | Thu, 22 Aug 2013 17:22:54 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1:67ce89da90df | 2:b74b41bb73f0 |
---|---|
1 <?php | |
2 | |
3 /** | |
4 * @file | |
5 * Tests for CAPTCHA module. | |
6 */ | |
7 | |
8 // TODO: write test for CAPTCHAs on admin pages | |
9 // TODO: test for default challenge type | |
10 // TODO: test about placement (comment form, node forms, log in form, etc) | |
11 // TODO: test if captcha_cron does it work right | |
12 // TODO: test custom CAPTCHA validation stuff | |
13 // TODO: test if entry on status report (Already X blocked form submissions) works | |
14 // TODO: test space ignoring validation of image CAPTCHA | |
15 | |
16 // TODO: refactor the 'comment_body[' . LANGUAGE_NONE . '][0][value]' stuff | |
17 | |
18 // Some constants for better reuse. | |
19 define('CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE', | |
20 'The answer you entered for the CAPTCHA was not correct.'); | |
21 | |
22 define('CAPTCHA_SESSION_REUSE_ATTACK_ERROR_MESSAGE', | |
23 'CAPTCHA session reuse attack detected.'); | |
24 | |
25 define('CAPTCHA_UNKNOWN_CSID_ERROR_MESSAGE', | |
26 'CAPTCHA validation error: unknown CAPTCHA session ID. Contact the site administrator if this problem persists.'); | |
27 | |
28 | |
29 | |
30 /** | |
31 * Base class for CAPTCHA tests. | |
32 * | |
33 * Provides common setup stuff and various helper functions | |
34 */ | |
35 abstract class CaptchaBaseWebTestCase extends DrupalWebTestCase { | |
36 | |
37 /** | |
38 * User with various administrative permissions. | |
39 * @var Drupal user | |
40 */ | |
41 protected $admin_user; | |
42 | |
43 /** | |
44 * Normal visitor with limited permissions | |
45 * @var Drupal user; | |
46 */ | |
47 protected $normal_user; | |
48 | |
49 /** | |
50 * Form ID of comment form on standard (page) node | |
51 * @var string | |
52 */ | |
53 const COMMENT_FORM_ID = 'comment_node_page_form'; | |
54 | |
55 /** | |
56 * Drupal path of the (general) CAPTCHA admin page | |
57 */ | |
58 const CAPTCHA_ADMIN_PATH = 'admin/config/people/captcha'; | |
59 | |
60 | |
61 function setUp() { | |
62 // Load two modules: the captcha module itself and the comment module for testing anonymous comments. | |
63 parent::setUp('captcha', 'comment'); | |
64 module_load_include('inc', 'captcha'); | |
65 | |
66 // Create a normal user. | |
67 $permissions = array( | |
68 'access comments', 'post comments', 'skip comment approval', | |
69 'access content', 'create page content', 'edit own page content', | |
70 ); | |
71 $this->normal_user = $this->drupalCreateUser($permissions); | |
72 | |
73 // Create an admin user. | |
74 $permissions[] = 'administer CAPTCHA settings'; | |
75 $permissions[] = 'skip CAPTCHA'; | |
76 $permissions[] = 'administer permissions'; | |
77 $permissions[] = 'administer content types'; | |
78 $this->admin_user = $this->drupalCreateUser($permissions); | |
79 | |
80 // Put comments on page nodes on a separate page (default in D7: below post). | |
81 variable_set('comment_form_location_page', COMMENT_FORM_SEPARATE_PAGE); | |
82 | |
83 } | |
84 | |
85 /** | |
86 * Assert that the response is accepted: | |
87 * no "unknown CSID" message, no "CSID reuse attack detection" message, | |
88 * no "wrong answer" message. | |
89 */ | |
90 protected function assertCaptchaResponseAccepted() { | |
91 // There should be no error message about unknown CAPTCHA session ID. | |
92 $this->assertNoText(t(CAPTCHA_UNKNOWN_CSID_ERROR_MESSAGE), | |
93 'CAPTCHA response should be accepted (known CSID).', | |
94 'CAPTCHA'); | |
95 // There should be no error message about CSID reuse attack. | |
96 $this->assertNoText(t(CAPTCHA_SESSION_REUSE_ATTACK_ERROR_MESSAGE), | |
97 'CAPTCHA response should be accepted (no CAPTCHA session reuse attack detection).', | |
98 'CAPTCHA'); | |
99 // There should be no error message about wrong response. | |
100 $this->assertNoText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), | |
101 'CAPTCHA response should be accepted (correct response).', | |
102 'CAPTCHA'); | |
103 } | |
104 | |
105 /** | |
106 * Assert that there is a CAPTCHA on the form or not. | |
107 * @param bool $presence whether there should be a CAPTCHA or not. | |
108 */ | |
109 protected function assertCaptchaPresence($presence) { | |
110 if ($presence) { | |
111 $this->assertText(_captcha_get_description(), | |
112 'There should be a CAPTCHA on the form.', 'CAPTCHA'); | |
113 } | |
114 else { | |
115 $this->assertNoText(_captcha_get_description(), | |
116 'There should be no CAPTCHA on the form.', 'CAPTCHA'); | |
117 } | |
118 } | |
119 | |
120 /** | |
121 * Helper function to create a node with comments enabled. | |
122 * | |
123 * @return | |
124 * Created node object. | |
125 */ | |
126 protected function createNodeWithCommentsEnabled($type='page') { | |
127 $node_settings = array( | |
128 'type' => $type, | |
129 'comment' => COMMENT_NODE_OPEN, | |
130 ); | |
131 $node = $this->drupalCreateNode($node_settings); | |
132 return $node; | |
133 } | |
134 | |
135 /** | |
136 * Helper function to generate a form values array for comment forms | |
137 */ | |
138 protected function getCommentFormValues() { | |
139 $edit = array( | |
140 'subject' => 'comment_subject ' . $this->randomName(32), | |
141 'comment_body[' . LANGUAGE_NONE . '][0][value]' => 'comment_body ' . $this->randomName(256), | |
142 ); | |
143 return $edit; | |
144 } | |
145 | |
146 /** | |
147 * Helper function to generate a form values array for node forms | |
148 */ | |
149 protected function getNodeFormValues() { | |
150 $edit = array( | |
151 'title' => 'node_title ' . $this->randomName(32), | |
152 'body[' . LANGUAGE_NONE . '][0][value]' => 'node_body ' . $this->randomName(256), | |
153 ); | |
154 return $edit; | |
155 } | |
156 | |
157 | |
158 /** | |
159 * Get the CAPTCHA session id from the current form in the browser. | |
160 */ | |
161 protected function getCaptchaSidFromForm() { | |
162 $elements = $this->xpath('//input[@name="captcha_sid"]'); | |
163 $captcha_sid = (int) $elements[0]['value']; | |
164 return $captcha_sid; | |
165 } | |
166 /** | |
167 * Get the CAPTCHA token from the current form in the browser. | |
168 */ | |
169 protected function getCaptchaTokenFromForm() { | |
170 $elements = $this->xpath('//input[@name="captcha_token"]'); | |
171 $captcha_token = (int) $elements[0]['value']; | |
172 return $captcha_token; | |
173 } | |
174 | |
175 /** | |
176 * Get the solution of the math CAPTCHA from the current form in the browser. | |
177 */ | |
178 protected function getMathCaptchaSolutionFromForm() { | |
179 // Get the math challenge. | |
180 $elements = $this->xpath('//div[@class="form-item form-type-textfield form-item-captcha-response"]/span[@class="field-prefix"]'); | |
181 $challenge = (string) $elements[0]; | |
182 // Extract terms and operator from challenge. | |
183 $matches = array(); | |
184 $ret = preg_match('/\\s*(\\d+)\\s*(-|\\+)\\s*(\\d+)\\s*=\\s*/', $challenge, $matches); | |
185 // Solve the challenge | |
186 $a = (int) $matches[1]; | |
187 $b = (int) $matches[3]; | |
188 $solution = $matches[2] == '-' ? $a - $b : $a + $b; | |
189 return $solution; | |
190 } | |
191 | |
192 /** | |
193 * Helper function to allow comment posting for anonymous users. | |
194 */ | |
195 protected function allowCommentPostingForAnonymousVisitors() { | |
196 // Log in as admin. | |
197 $this->drupalLogin($this->admin_user); | |
198 // Post user permissions form | |
199 $edit = array( | |
200 '1[access comments]' => true, | |
201 '1[post comments]' => true, | |
202 '1[skip comment approval]' => true, | |
203 ); | |
204 $this->drupalPost('admin/people/permissions', $edit, 'Save permissions'); | |
205 $this->assertText('The changes have been saved.'); | |
206 // Log admin out | |
207 $this->drupalLogout(); | |
208 } | |
209 | |
210 } | |
211 | |
212 | |
213 | |
214 class CaptchaTestCase extends CaptchaBaseWebTestCase { | |
215 | |
216 public static function getInfo() { | |
217 return array( | |
218 'name' => t('General CAPTCHA functionality'), | |
219 'description' => t('Testing of the basic CAPTCHA functionality.'), | |
220 'group' => t('CAPTCHA'), | |
221 ); | |
222 } | |
223 | |
224 /** | |
225 * Testing the protection of the user log in form. | |
226 */ | |
227 function testCaptchaOnLoginForm() { | |
228 // Create user and test log in without CAPTCHA. | |
229 $user = $this->drupalCreateUser(); | |
230 $this->drupalLogin($user); | |
231 // Log out again. | |
232 $this->drupalLogout(); | |
233 | |
234 // Set a CAPTCHA on login form | |
235 captcha_set_form_id_setting('user_login', 'captcha/Math'); | |
236 | |
237 // Check if there is a CAPTCHA on the login form (look for the title). | |
238 $this->drupalGet('user'); | |
239 $this->assertCaptchaPresence(TRUE); | |
240 | |
241 // Try to log in, which should fail. | |
242 $edit = array( | |
243 'name' => $user->name, | |
244 'pass' => $user->pass_raw, | |
245 'captcha_response' => '?', | |
246 ); | |
247 $this->drupalPost('user', $edit, t('Log in')); | |
248 // Check for error message. | |
249 $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), | |
250 'CAPTCHA should block user login form', 'CAPTCHA'); | |
251 | |
252 // And make sure that user is not logged in: check for name and password fields on ?q=user | |
253 $this->drupalGet('user'); | |
254 $this->assertField('name', t('Username field found.'), 'CAPTCHA'); | |
255 $this->assertField('pass', t('Password field found.'), 'CAPTCHA'); | |
256 | |
257 } | |
258 | |
259 | |
260 /** | |
261 * Assert function for testing if comment posting works as it should. | |
262 * | |
263 * Creates node with comment writing enabled, tries to post comment | |
264 * with given CAPTCHA response (caller should enable the desired | |
265 * challenge on page node comment forms) and checks if the result is as expected. | |
266 * | |
267 * @param $captcha_response the response on the CAPTCHA | |
268 * @param $should_pass boolean describing if the posting should pass or should be blocked | |
269 * @param $message message to prefix to nested asserts | |
270 */ | |
271 protected function assertCommentPosting($captcha_response, $should_pass, $message) { | |
272 // Make sure comments on pages can be saved directely without preview. | |
273 variable_set('comment_preview_page', DRUPAL_OPTIONAL); | |
274 | |
275 // Create a node with comments enabled. | |
276 $node = $this->createNodeWithCommentsEnabled(); | |
277 | |
278 // Post comment on node. | |
279 $edit = $this->getCommentFormValues(); | |
280 $comment_subject = $edit['subject']; | |
281 $comment_body = $edit['comment_body[' . LANGUAGE_NONE . '][0][value]']; | |
282 $edit['captcha_response'] = $captcha_response; | |
283 $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Save')); | |
284 | |
285 if ($should_pass) { | |
286 // There should be no error message. | |
287 $this->assertCaptchaResponseAccepted(); | |
288 // Get node page and check that comment shows up. | |
289 $this->drupalGet('node/' . $node->nid); | |
290 $this->assertText($comment_subject, $message .' Comment should show up on node page.', 'CAPTCHA'); | |
291 $this->assertText($comment_body, $message . ' Comment should show up on node page.', 'CAPTCHA'); | |
292 } | |
293 else { | |
294 // Check for error message. | |
295 $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), $message .' Comment submission should be blocked.', 'CAPTCHA'); | |
296 // Get node page and check that comment is not present. | |
297 $this->drupalGet('node/' . $node->nid); | |
298 $this->assertNoText($comment_subject, $message .' Comment should not show up on node page.', 'CAPTCHA'); | |
299 $this->assertNoText($comment_body, $message . ' Comment should not show up on node page.', 'CAPTCHA'); | |
300 } | |
301 } | |
302 | |
303 /* | |
304 * Testing the case sensistive/insensitive validation. | |
305 */ | |
306 function testCaseInsensitiveValidation() { | |
307 // Set Test CAPTCHA on comment form | |
308 captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test'); | |
309 | |
310 // Log in as normal user. | |
311 $this->drupalLogin($this->normal_user); | |
312 | |
313 // Test case sensitive posting. | |
314 variable_set('captcha_default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_SENSITIVE); | |
315 $this->assertCommentPosting('Test 123', TRUE, 'Case sensitive validation of right casing.'); | |
316 $this->assertCommentPosting('test 123', FALSE, 'Case sensitive validation of wrong casing.'); | |
317 $this->assertCommentPosting('TEST 123', FALSE, 'Case sensitive validation of wrong casing.'); | |
318 | |
319 // Test case insensitive posting (the default) | |
320 variable_set('captcha_default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE); | |
321 $this->assertCommentPosting('Test 123', TRUE, 'Case insensitive validation of right casing.'); | |
322 $this->assertCommentPosting('test 123', TRUE, 'Case insensitive validation of wrong casing.'); | |
323 $this->assertCommentPosting('TEST 123', TRUE, 'Case insensitive validation of wrong casing.'); | |
324 | |
325 } | |
326 | |
327 /** | |
328 * Test if the CAPTCHA description is only shown if there are challenge widgets to show. | |
329 * For example, when a comment is previewed with correct CAPTCHA answer, | |
330 * a challenge is generated and added to the form but removed in the pre_render phase. | |
331 * The CAPTCHA description should not show up either. | |
332 * | |
333 * \see testCaptchaSessionReuseOnNodeForms() | |
334 */ | |
335 function testCaptchaDescriptionAfterCommentPreview() { | |
336 // Set Test CAPTCHA on comment form. | |
337 captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test'); | |
338 | |
339 // Log in as normal user. | |
340 $this->drupalLogin($this->normal_user); | |
341 | |
342 // Create a node with comments enabled. | |
343 $node = $this->createNodeWithCommentsEnabled(); | |
344 | |
345 // Preview comment with correct CAPTCHA answer. | |
346 $edit = $this->getCommentFormValues(); | |
347 $edit['captcha_response'] = 'Test 123'; | |
348 $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview')); | |
349 | |
350 // Check that there is no CAPTCHA after preview. | |
351 $this->assertCaptchaPresence(FALSE); | |
352 } | |
353 | |
354 /** | |
355 * Test if the CAPTCHA session ID is reused when previewing nodes: | |
356 * node preview after correct response should not show CAPTCHA anymore. | |
357 * The preview functionality of comments and nodes works slightly different under the hood. | |
358 * CAPTCHA module should be able to handle both. | |
359 * | |
360 * \see testCaptchaDescriptionAfterCommentPreview() | |
361 */ | |
362 function testCaptchaSessionReuseOnNodeForms() { | |
363 // Set Test CAPTCHA on page form. | |
364 captcha_set_form_id_setting('page_node_form', 'captcha/Test'); | |
365 | |
366 // Log in as normal user. | |
367 $this->drupalLogin($this->normal_user); | |
368 | |
369 // Page settings to post, with correct CAPTCHA answer. | |
370 $edit = $this->getNodeFormValues(); | |
371 $edit['captcha_response'] = 'Test 123'; | |
372 // Preview the node | |
373 $this->drupalPost('node/add/page', $edit, t('Preview')); | |
374 | |
375 // Check that there is no CAPTCHA after preview. | |
376 $this->assertCaptchaPresence(FALSE); | |
377 } | |
378 | |
379 | |
380 /** | |
381 * CAPTCHA should also be put on admin pages even if visitor | |
382 * has no access | |
383 */ | |
384 function testCaptchaOnLoginBlockOnAdminPagesIssue893810() { | |
385 // Set a CAPTCHA on login block form | |
386 captcha_set_form_id_setting('user_login_block', 'captcha/Math'); | |
387 | |
388 // Check if there is a CAPTCHA on home page. | |
389 $this->drupalGet('node'); | |
390 $this->assertCaptchaPresence(TRUE); | |
391 | |
392 // Check there is a CAPTCHA on "forbidden" admin pages | |
393 $this->drupalGet('admin'); | |
394 $this->assertCaptchaPresence(TRUE); | |
395 } | |
396 | |
397 } | |
398 | |
399 | |
400 class CaptchaAdminTestCase extends CaptchaBaseWebTestCase { | |
401 | |
402 public static function getInfo() { | |
403 return array( | |
404 'name' => t('CAPTCHA administration functionality'), | |
405 'description' => t('Testing of the CAPTCHA administration interface and functionality.'), | |
406 'group' => t('CAPTCHA'), | |
407 ); | |
408 } | |
409 | |
410 /** | |
411 * Test access to the admin pages. | |
412 */ | |
413 function testAdminAccess() { | |
414 $this->drupalLogin($this->normal_user); | |
415 $this->drupalGet(self::CAPTCHA_ADMIN_PATH); | |
416 file_put_contents('tmp.simpletest.html', $this->drupalGetContent()); | |
417 $this->assertText(t('Access denied'), 'Normal users should not be able to access the CAPTCHA admin pages', 'CAPTCHA'); | |
418 | |
419 $this->drupalLogin($this->admin_user); | |
420 $this->drupalGet(self::CAPTCHA_ADMIN_PATH); | |
421 $this->assertNoText(t('Access denied'), 'Admin users should be able to access the CAPTCHA admin pages', 'CAPTCHA'); | |
422 } | |
423 | |
424 /** | |
425 * Test the CAPTCHA point setting getter/setter. | |
426 */ | |
427 function testCaptchaPointSettingGetterAndSetter() { | |
428 $comment_form_id = self::COMMENT_FORM_ID; | |
429 // Set to 'none'. | |
430 captcha_set_form_id_setting($comment_form_id, 'none'); | |
431 $result = captcha_get_form_id_setting($comment_form_id); | |
432 $this->assertNotNull($result, 'Setting and getting CAPTCHA point: none', 'CAPTCHA'); | |
433 $this->assertNull($result->module, 'Setting and getting CAPTCHA point: none', 'CAPTCHA'); | |
434 $this->assertNull($result->captcha_type, 'Setting and getting CAPTCHA point: none', 'CAPTCHA'); | |
435 $result = captcha_get_form_id_setting($comment_form_id, TRUE); | |
436 $this->assertEqual($result, 'none', 'Setting and symbolic getting CAPTCHA point: "none"', 'CAPTCHA'); | |
437 // Set to 'default' | |
438 captcha_set_form_id_setting($comment_form_id, 'default'); | |
439 variable_set('captcha_default_challenge', 'foo/bar'); | |
440 $result = captcha_get_form_id_setting($comment_form_id); | |
441 $this->assertNotNull($result, 'Setting and getting CAPTCHA point: default', 'CAPTCHA'); | |
442 $this->assertEqual($result->module, 'foo', 'Setting and getting CAPTCHA point: default', 'CAPTCHA'); | |
443 $this->assertEqual($result->captcha_type, 'bar', 'Setting and getting CAPTCHA point: default', 'CAPTCHA'); | |
444 $result = captcha_get_form_id_setting($comment_form_id, TRUE); | |
445 $this->assertEqual($result, 'default', 'Setting and symbolic getting CAPTCHA point: "default"', 'CAPTCHA'); | |
446 // Set to 'baz/boo'. | |
447 captcha_set_form_id_setting($comment_form_id, 'baz/boo'); | |
448 $result = captcha_get_form_id_setting($comment_form_id); | |
449 $this->assertNotNull($result, 'Setting and getting CAPTCHA point: baz/boo', 'CAPTCHA'); | |
450 $this->assertEqual($result->module, 'baz', 'Setting and getting CAPTCHA point: baz/boo', 'CAPTCHA'); | |
451 $this->assertEqual($result->captcha_type, 'boo', 'Setting and getting CAPTCHA point: baz/boo', 'CAPTCHA'); | |
452 $result = captcha_get_form_id_setting($comment_form_id, TRUE); | |
453 $this->assertEqual($result, 'baz/boo', 'Setting and symbolic getting CAPTCHA point: "baz/boo"', 'CAPTCHA'); | |
454 // Set to NULL (which should delete the CAPTCHA point setting entry). | |
455 captcha_set_form_id_setting($comment_form_id, NULL); | |
456 $result = captcha_get_form_id_setting($comment_form_id); | |
457 $this->assertNull($result, 'Setting and getting CAPTCHA point: NULL', 'CAPTCHA'); | |
458 $result = captcha_get_form_id_setting($comment_form_id, TRUE); | |
459 $this->assertNull($result, 'Setting and symbolic getting CAPTCHA point: NULL', 'CAPTCHA'); | |
460 // Set with object. | |
461 $captcha_type = new stdClass; | |
462 $captcha_type->module = 'baba'; | |
463 $captcha_type->captcha_type = 'fofo'; | |
464 captcha_set_form_id_setting($comment_form_id, $captcha_type); | |
465 $result = captcha_get_form_id_setting($comment_form_id); | |
466 $this->assertNotNull($result, 'Setting and getting CAPTCHA point: baba/fofo', 'CAPTCHA'); | |
467 $this->assertEqual($result->module, 'baba', 'Setting and getting CAPTCHA point: baba/fofo', 'CAPTCHA'); | |
468 $this->assertEqual($result->captcha_type, 'fofo', 'Setting and getting CAPTCHA point: baba/fofo', 'CAPTCHA'); | |
469 $result = captcha_get_form_id_setting($comment_form_id, TRUE); | |
470 $this->assertEqual($result, 'baba/fofo', 'Setting and symbolic getting CAPTCHA point: "baba/fofo"', 'CAPTCHA'); | |
471 | |
472 } | |
473 | |
474 | |
475 /** | |
476 * Helper function for checking CAPTCHA setting of a form. | |
477 * | |
478 * @param $form_id the form_id of the form to investigate. | |
479 * @param $challenge_type what the challenge type should be: | |
480 * NULL, 'none', 'default' or something like 'captcha/Math' | |
481 */ | |
482 protected function assertCaptchaSetting($form_id, $challenge_type) { | |
483 $result = captcha_get_form_id_setting(self::COMMENT_FORM_ID, TRUE); | |
484 $this->assertEqual($result, $challenge_type, | |
485 t('Check CAPTCHA setting for form: expected: @expected, received: @received.', | |
486 array('@expected' => var_export($challenge_type, TRUE), '@received' => var_export($result, TRUE))), | |
487 'CAPTCHA'); | |
488 } | |
489 | |
490 /** | |
491 * Testing of the CAPTCHA administration links. | |
492 */ | |
493 function testCaptchAdminLinks() { | |
494 // Log in as admin | |
495 $this->drupalLogin($this->admin_user); | |
496 | |
497 // Enable CAPTCHA administration links. | |
498 $edit = array( | |
499 'captcha_administration_mode' => TRUE, | |
500 ); | |
501 $this->drupalPost(self::CAPTCHA_ADMIN_PATH, $edit, 'Save configuration'); | |
502 | |
503 // Create a node with comments enabled. | |
504 $node = $this->createNodeWithCommentsEnabled(); | |
505 | |
506 // Go to node page | |
507 $this->drupalGet('node/' . $node->nid); | |
508 | |
509 // Click the add new comment link | |
510 $this->clickLink(t('Add new comment')); | |
511 $add_comment_url = $this->getUrl(); | |
512 // Remove fragment part from comment URL to avoid problems with later asserts | |
513 $add_comment_url = strtok($add_comment_url, "#"); | |
514 | |
515 //////////////////////////////////////////////////////////// | |
516 // Click the CAPTCHA admin link to enable a challenge. | |
517 $this->clickLink(t('Place a CAPTCHA here for untrusted users.')); | |
518 // Enable Math CAPTCHA. | |
519 $edit = array('captcha_type' => 'captcha/Math'); | |
520 $this->drupalPost($this->getUrl(), $edit, t('Save')); | |
521 | |
522 // Check if returned to original comment form. | |
523 $this->assertUrl($add_comment_url, array(), | |
524 'After setting CAPTCHA with CAPTCHA admin links: should return to original form.', 'CAPTCHA'); | |
525 // Check if CAPTCHA was successfully enabled (on CAPTCHA admin links fieldset). | |
526 $this->assertText(t('CAPTCHA: challenge "@type" enabled', array('@type' => 'Math')), | |
527 'Enable a challenge through the CAPTCHA admin links', 'CAPTCHA'); | |
528 // Check if CAPTCHA was successfully enabled (through API). | |
529 $this->assertCaptchaSetting(self::COMMENT_FORM_ID, 'captcha/Math'); | |
530 | |
531 ////////////////////////////////////////////////////// | |
532 // Edit challenge type through CAPTCHA admin links. | |
533 $this->clickLink(t('change')); | |
534 // Enable Math CAPTCHA. | |
535 $edit = array('captcha_type' => 'default'); | |
536 $this->drupalPost($this->getUrl(), $edit, t('Save')); | |
537 | |
538 // Check if returned to original comment form. | |
539 $this->assertEqual($add_comment_url, $this->getUrl(), | |
540 'After editing challenge type CAPTCHA admin links: should return to original form.', 'CAPTCHA'); | |
541 // Check if CAPTCHA was successfully changed (on CAPTCHA admin links fieldset). | |
542 // This is actually the same as the previous setting because the captcha/Math is the | |
543 // default for the default challenge. TODO Make sure the edit is a real change. | |
544 $this->assertText(t('CAPTCHA: challenge "@type" enabled', array('@type' => 'Math')), | |
545 'Enable a challenge through the CAPTCHA admin links', 'CAPTCHA'); | |
546 // Check if CAPTCHA was successfully edited (through API). | |
547 $this->assertCaptchaSetting(self::COMMENT_FORM_ID, 'default'); | |
548 | |
549 | |
550 | |
551 ////////////////////////////////////////////////////// | |
552 // Disable challenge through CAPTCHA admin links. | |
553 $this->clickLink(t('disable')); | |
554 // And confirm. | |
555 $this->drupalPost($this->getUrl(), array(), 'Disable'); | |
556 | |
557 // Check if returned to original comment form. | |
558 $this->assertEqual($add_comment_url, $this->getUrl(), | |
559 'After disablin challenge with CAPTCHA admin links: should return to original form.', 'CAPTCHA'); | |
560 // Check if CAPTCHA was successfully disabled (on CAPTCHA admin links fieldset). | |
561 $this->assertText(t('CAPTCHA: no challenge enabled'), | |
562 'Disable challenge through the CAPTCHA admin links', 'CAPTCHA'); | |
563 // Check if CAPTCHA was successfully disabled (through API). | |
564 $this->assertCaptchaSetting(self::COMMENT_FORM_ID, 'none'); | |
565 | |
566 } | |
567 | |
568 | |
569 function testUntrustedUserPosting() { | |
570 // Set CAPTCHA on comment form. | |
571 captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Math'); | |
572 | |
573 // Create a node with comments enabled. | |
574 $node = $this->createNodeWithCommentsEnabled(); | |
575 | |
576 // Log in as normal (untrusted) user. | |
577 $this->drupalLogin($this->normal_user); | |
578 | |
579 // Go to node page and click the "add comment" link. | |
580 $this->drupalGet('node/' . $node->nid); | |
581 $this->clickLink(t('Add new comment')); | |
582 $add_comment_url = $this->getUrl(); | |
583 | |
584 // Check if CAPTCHA is visible on form. | |
585 $this->assertCaptchaPresence(TRUE); | |
586 // Try to post a comment with wrong answer. | |
587 $edit = $this->getCommentFormValues(); | |
588 $edit['captcha_response'] = 'xx'; | |
589 $this->drupalPost($add_comment_url, $edit, t('Preview')); | |
590 $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), | |
591 'wrong CAPTCHA should block form submission.', 'CAPTCHA'); | |
592 | |
593 //TODO: more testing for untrusted posts. | |
594 } | |
595 | |
596 | |
597 | |
598 /** | |
599 * Test XSS vulnerability on CAPTCHA description. | |
600 */ | |
601 function testXssOnCaptchaDescription() { | |
602 // Set CAPTCHA on user register form. | |
603 captcha_set_form_id_setting('user_register', 'captcha/Math'); | |
604 | |
605 // Put Javascript snippet in CAPTCHA description. | |
606 $this->drupalLogin($this->admin_user); | |
607 $xss = '<script type="text/javascript">alert("xss")</script>'; | |
608 $edit = array('captcha_description' => $xss); | |
609 $this->drupalPost(self::CAPTCHA_ADMIN_PATH, $edit, 'Save configuration'); | |
610 | |
611 // Visit user register form and check if Javascript snippet is there. | |
612 $this->drupalLogout(); | |
613 $this->drupalGet('user/register'); | |
614 $this->assertNoRaw($xss, 'Javascript should not be allowed in CAPTCHA description.', 'CAPTCHA'); | |
615 | |
616 } | |
617 | |
618 /** | |
619 * Test the CAPTCHA placement clearing. | |
620 */ | |
621 function testCaptchaPlacementCacheClearing() { | |
622 // Set CAPTCHA on user register form. | |
623 captcha_set_form_id_setting('user_register_form', 'captcha/Math'); | |
624 // Visit user register form to fill the CAPTCHA placement cache. | |
625 $this->drupalGet('user/register'); | |
626 // Check if there is CAPTCHA placement cache. | |
627 $placement_map = variable_get('captcha_placement_map_cache', NULL); | |
628 $this->assertNotNull($placement_map, 'CAPTCHA placement cache should be set.'); | |
629 // Clear the cache | |
630 $this->drupalLogin($this->admin_user); | |
631 $this->drupalPost(self::CAPTCHA_ADMIN_PATH, array(), t('Clear the CAPTCHA placement cache')); | |
632 // Check that the placement cache is unset | |
633 $placement_map = variable_get('captcha_placement_map_cache', NULL); | |
634 $this->assertNull($placement_map, 'CAPTCHA placement cache should be unset after cache clear.'); | |
635 } | |
636 | |
637 /** | |
638 * Helper function to get the CAPTCHA point setting straight from the database. | |
639 * @param string $form_id | |
640 * @return stdClass object | |
641 */ | |
642 private function getCaptchaPointSettingFromDatabase($form_id) { | |
643 $result = db_query( | |
644 "SELECT * FROM {captcha_points} WHERE form_id = :form_id", | |
645 array(':form_id' => $form_id) | |
646 )->fetchObject(); | |
647 return $result; | |
648 } | |
649 | |
650 /** | |
651 * Method for testing the CAPTCHA point administration | |
652 */ | |
653 function testCaptchaPointAdministration() { | |
654 // Generate CAPTCHA point data: | |
655 // Drupal form ID should consist of lowercase alphanumerics and underscore) | |
656 $captcha_point_form_id = 'form_' . strtolower($this->randomName(32)); | |
657 // the Math CAPTCHA by the CAPTCHA module is always available, so let's use it | |
658 $captcha_point_module = 'captcha'; | |
659 $captcha_point_type = 'Math'; | |
660 | |
661 // Log in as admin | |
662 $this->drupalLogin($this->admin_user); | |
663 | |
664 // Set CAPTCHA point through admin/user/captcha/captcha/captcha_point | |
665 $form_values = array( | |
666 'captcha_point_form_id' => $captcha_point_form_id, | |
667 'captcha_type' => $captcha_point_module .'/'. $captcha_point_type, | |
668 ); | |
669 $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point', $form_values, t('Save')); | |
670 $this->assertText(t('Saved CAPTCHA point settings.'), | |
671 'Saving of CAPTCHA point settings'); | |
672 | |
673 // Check in database | |
674 $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id); | |
675 $this->assertEqual($result->module, $captcha_point_module, | |
676 'Enabled CAPTCHA point should have module set'); | |
677 $this->assertEqual($result->captcha_type, $captcha_point_type, | |
678 'Enabled CAPTCHA point should have type set'); | |
679 | |
680 // Disable CAPTCHA point again | |
681 $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/disable', array(), t('Disable')); | |
682 $this->assertRaw(t('Disabled CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)), 'Disabling of CAPTCHA point'); | |
683 | |
684 // Check in database | |
685 $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id); | |
686 $this->assertNull($result->module, | |
687 'Disabled CAPTCHA point should have NULL as module'); | |
688 $this->assertNull($result->captcha_type, | |
689 'Disabled CAPTCHA point should have NULL as type'); | |
690 | |
691 // Set CAPTCHA point through admin/user/captcha/captcha/captcha_point/$form_id | |
692 $form_values = array( | |
693 'captcha_type' => $captcha_point_module .'/'. $captcha_point_type, | |
694 ); | |
695 $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id, $form_values, t('Save')); | |
696 $this->assertText(t('Saved CAPTCHA point settings.'), | |
697 'Saving of CAPTCHA point settings'); | |
698 | |
699 // Check in database | |
700 $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id); | |
701 $this->assertEqual($result->module, $captcha_point_module, | |
702 'Enabled CAPTCHA point should have module set'); | |
703 $this->assertEqual($result->captcha_type, $captcha_point_type, | |
704 'Enabled CAPTCHA point should have type set'); | |
705 | |
706 // Delete CAPTCHA point | |
707 $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/delete', array(), t('Delete')); | |
708 $this->assertRaw(t('Deleted CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)), | |
709 'Deleting of CAPTCHA point'); | |
710 | |
711 // Check in database | |
712 $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id); | |
713 $this->assertFalse($result, 'Deleted CAPTCHA point should be in database'); | |
714 } | |
715 | |
716 /** | |
717 * Method for testing the CAPTCHA point administration | |
718 */ | |
719 function testCaptchaPointAdministrationByNonAdmin() { | |
720 // First add a CAPTCHA point (as admin) | |
721 $this->drupalLogin($this->admin_user); | |
722 $captcha_point_form_id = 'form_' . strtolower($this->randomName(32)); | |
723 $captcha_point_module = 'captcha'; | |
724 $captcha_point_type = 'Math'; | |
725 $form_values = array( | |
726 'captcha_point_form_id' => $captcha_point_form_id, | |
727 'captcha_type' => $captcha_point_module .'/'. $captcha_point_type, | |
728 ); | |
729 $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/', $form_values, t('Save')); | |
730 $this->assertText(t('Saved CAPTCHA point settings.'), | |
731 'Saving of CAPTCHA point settings'); | |
732 | |
733 // Switch from admin to nonadmin | |
734 $this->drupalGet(url('logout', array('absolute' => TRUE))); | |
735 $this->drupalLogin($this->normal_user); | |
736 | |
737 | |
738 // Try to set CAPTCHA point through admin/user/captcha/captcha/captcha_point | |
739 $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point'); | |
740 $this->assertText(t('You are not authorized to access this page.'), | |
741 'Non admin should not be able to set a CAPTCHA point'); | |
742 | |
743 // Try to set CAPTCHA point through admin/user/captcha/captcha/captcha_point/$form_id | |
744 $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/' . 'form_' . strtolower($this->randomName(32))); | |
745 $this->assertText(t('You are not authorized to access this page.'), | |
746 'Non admin should not be able to set a CAPTCHA point'); | |
747 | |
748 // Try to disable the CAPTCHA point | |
749 $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/disable'); | |
750 $this->assertText(t('You are not authorized to access this page.'), | |
751 'Non admin should not be able to disable a CAPTCHA point'); | |
752 | |
753 // Try to delete the CAPTCHA point | |
754 $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/delete'); | |
755 $this->assertText(t('You are not authorized to access this page.'), | |
756 'Non admin should not be able to delete a CAPTCHA point'); | |
757 | |
758 // Switch from nonadmin to admin again | |
759 $this->drupalGet(url('logout', array('absolute' => TRUE))); | |
760 $this->drupalLogin($this->admin_user); | |
761 | |
762 // Check if original CAPTCHA point still exists in database | |
763 $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id); | |
764 $this->assertEqual($result->module, $captcha_point_module, | |
765 'Enabled CAPTCHA point should still have module set'); | |
766 $this->assertEqual($result->captcha_type, $captcha_point_type, | |
767 'Enabled CAPTCHA point should still have type set'); | |
768 | |
769 // Delete CAPTCHA point | |
770 $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/delete', array(), t('Delete')); | |
771 $this->assertRaw(t('Deleted CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)), | |
772 'Deleting of CAPTCHA point'); | |
773 } | |
774 | |
775 | |
776 | |
777 } | |
778 | |
779 | |
780 | |
781 class CaptchaPersistenceTestCase extends CaptchaBaseWebTestCase { | |
782 | |
783 public static function getInfo() { | |
784 return array( | |
785 'name' => t('CAPTCHA persistence functionality'), | |
786 'description' => t('Testing of the CAPTCHA persistence functionality.'), | |
787 'group' => t('CAPTCHA'), | |
788 ); | |
789 } | |
790 | |
791 /** | |
792 * Set up the persistence and CAPTCHA settings. | |
793 * @param int $persistence the persistence value. | |
794 */ | |
795 private function setUpPersistence($persistence) { | |
796 // Log in as admin | |
797 $this->drupalLogin($this->admin_user); | |
798 // Set persistence. | |
799 $edit = array('captcha_persistence' => $persistence); | |
800 $this->drupalPost(self::CAPTCHA_ADMIN_PATH, $edit, 'Save configuration'); | |
801 // Log admin out. | |
802 $this->drupalLogout(); | |
803 | |
804 // Set the Test123 CAPTCHA on user register and comment form. | |
805 // We have to do this with the function captcha_set_form_id_setting() | |
806 // (because the CATCHA admin form does not show the Test123 option). | |
807 // We also have to do this after all usage of the CAPTCHA admin form | |
808 // (because posting the CAPTCHA admin form would set the CAPTCHA to 'none'). | |
809 captcha_set_form_id_setting('user_login', 'captcha/Test'); | |
810 $this->drupalGet('user'); | |
811 $this->assertCaptchaPresence(TRUE); | |
812 captcha_set_form_id_setting('user_register_form', 'captcha/Test'); | |
813 $this->drupalGet('user/register'); | |
814 $this->assertCaptchaPresence(TRUE); | |
815 } | |
816 | |
817 protected function assertPreservedCsid($captcha_sid_initial) { | |
818 $captcha_sid = $this->getCaptchaSidFromForm(); | |
819 $this->assertEqual($captcha_sid_initial, $captcha_sid, | |
820 "CAPTCHA session ID should be preserved (expected: $captcha_sid_initial, found: $captcha_sid)."); | |
821 } | |
822 | |
823 protected function assertDifferentCsid($captcha_sid_initial) { | |
824 $captcha_sid = $this->getCaptchaSidFromForm(); | |
825 $this->assertNotEqual($captcha_sid_initial, $captcha_sid, | |
826 "CAPTCHA session ID should be different."); | |
827 } | |
828 | |
829 function testPersistenceAlways(){ | |
830 // Set up of persistence and CAPTCHAs. | |
831 $this->setUpPersistence(CAPTCHA_PERSISTENCE_SHOW_ALWAYS); | |
832 | |
833 // Go to login form and check if there is a CAPTCHA on the login form (look for the title). | |
834 $this->drupalGet('user'); | |
835 $this->assertCaptchaPresence(TRUE); | |
836 $captcha_sid_initial = $this->getCaptchaSidFromForm(); | |
837 | |
838 // Try to with wrong user name and password, but correct CAPTCHA. | |
839 $edit = array( | |
840 'name' => 'foobar', | |
841 'pass' => 'bazlaz', | |
842 'captcha_response' => 'Test 123', | |
843 ); | |
844 $this->drupalPost(NULL, $edit, t('Log in')); | |
845 // Check that there was no error message for the CAPTCHA. | |
846 $this->assertCaptchaResponseAccepted(); | |
847 | |
848 // Name and password were wrong, we should get an updated form with a fresh CAPTCHA. | |
849 $this->assertCaptchaPresence(TRUE); | |
850 $this->assertPreservedCsid($captcha_sid_initial); | |
851 | |
852 // Post from again. | |
853 $this->drupalPost(NULL, $edit, t('Log in')); | |
854 // Check that there was no error message for the CAPTCHA. | |
855 $this->assertCaptchaResponseAccepted(); | |
856 $this->assertPreservedCsid($captcha_sid_initial); | |
857 | |
858 } | |
859 | |
860 function testPersistencePerFormInstance(){ | |
861 // Set up of persistence and CAPTCHAs. | |
862 $this->setUpPersistence(CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE); | |
863 | |
864 // Go to login form and check if there is a CAPTCHA on the login form. | |
865 $this->drupalGet('user'); | |
866 $this->assertCaptchaPresence(TRUE); | |
867 $captcha_sid_initial = $this->getCaptchaSidFromForm(); | |
868 | |
869 // Try to with wrong user name and password, but correct CAPTCHA. | |
870 $edit = array( | |
871 'name' => 'foobar', | |
872 'pass' => 'bazlaz', | |
873 'captcha_response' => 'Test 123', | |
874 ); | |
875 $this->drupalPost(NULL, $edit, t('Log in')); | |
876 // Check that there was no error message for the CAPTCHA. | |
877 $this->assertCaptchaResponseAccepted(); | |
878 // There shouldn't be a CAPTCHA on the new form. | |
879 $this->assertCaptchaPresence(FALSE); | |
880 $this->assertPreservedCsid($captcha_sid_initial); | |
881 | |
882 // Start a new form instance/session | |
883 $this->drupalGet('node'); | |
884 $this->drupalGet('user'); | |
885 $this->assertCaptchaPresence(TRUE); | |
886 $this->assertDifferentCsid($captcha_sid_initial); | |
887 | |
888 // Check another form | |
889 $this->drupalGet('user/register'); | |
890 $this->assertCaptchaPresence(TRUE); | |
891 $this->assertDifferentCsid($captcha_sid_initial); | |
892 | |
893 } | |
894 | |
895 function testPersistencePerFormType(){ | |
896 // Set up of persistence and CAPTCHAs. | |
897 $this->setUpPersistence(CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE); | |
898 | |
899 // Go to login form and check if there is a CAPTCHA on the login form. | |
900 $this->drupalGet('user'); | |
901 $this->assertCaptchaPresence(TRUE); | |
902 $captcha_sid_initial = $this->getCaptchaSidFromForm(); | |
903 | |
904 // Try to with wrong user name and password, but correct CAPTCHA. | |
905 $edit = array( | |
906 'name' => 'foobar', | |
907 'pass' => 'bazlaz', | |
908 'captcha_response' => 'Test 123', | |
909 ); | |
910 $this->drupalPost(NULL, $edit, t('Log in')); | |
911 // Check that there was no error message for the CAPTCHA. | |
912 $this->assertCaptchaResponseAccepted(); | |
913 // There shouldn't be a CAPTCHA on the new form. | |
914 $this->assertCaptchaPresence(FALSE); | |
915 $this->assertPreservedCsid($captcha_sid_initial); | |
916 | |
917 // Start a new form instance/session | |
918 $this->drupalGet('node'); | |
919 $this->drupalGet('user'); | |
920 $this->assertCaptchaPresence(FALSE); | |
921 $this->assertDifferentCsid($captcha_sid_initial); | |
922 | |
923 // Check another form | |
924 $this->drupalGet('user/register'); | |
925 $this->assertCaptchaPresence(TRUE); | |
926 $this->assertDifferentCsid($captcha_sid_initial); | |
927 } | |
928 | |
929 function testPersistenceOnlyOnce(){ | |
930 // Set up of persistence and CAPTCHAs. | |
931 $this->setUpPersistence(CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL); | |
932 | |
933 // Go to login form and check if there is a CAPTCHA on the login form. | |
934 $this->drupalGet('user'); | |
935 $this->assertCaptchaPresence(TRUE); | |
936 $captcha_sid_initial = $this->getCaptchaSidFromForm(); | |
937 | |
938 // Try to with wrong user name and password, but correct CAPTCHA. | |
939 $edit = array( | |
940 'name' => 'foobar', | |
941 'pass' => 'bazlaz', | |
942 'captcha_response' => 'Test 123', | |
943 ); | |
944 $this->drupalPost(NULL, $edit, t('Log in')); | |
945 // Check that there was no error message for the CAPTCHA. | |
946 $this->assertCaptchaResponseAccepted(); | |
947 // There shouldn't be a CAPTCHA on the new form. | |
948 $this->assertCaptchaPresence(FALSE); | |
949 $this->assertPreservedCsid($captcha_sid_initial); | |
950 | |
951 // Start a new form instance/session | |
952 $this->drupalGet('node'); | |
953 $this->drupalGet('user'); | |
954 $this->assertCaptchaPresence(FALSE); | |
955 $this->assertDifferentCsid($captcha_sid_initial); | |
956 | |
957 // Check another form | |
958 $this->drupalGet('user/register'); | |
959 $this->assertCaptchaPresence(FALSE); | |
960 $this->assertDifferentCsid($captcha_sid_initial); | |
961 } | |
962 | |
963 } | |
964 | |
965 | |
966 class CaptchaSessionReuseAttackTestCase extends CaptchaBaseWebTestCase { | |
967 | |
968 public static function getInfo() { | |
969 return array( | |
970 'name' => t('CAPTCHA session reuse attack tests'), | |
971 'description' => t('Testing of the protection against CAPTCHA session reuse attacks.'), | |
972 'group' => t('CAPTCHA'), | |
973 ); | |
974 } | |
975 | |
976 /** | |
977 * Assert that the CAPTCHA session ID reuse attack was detected. | |
978 */ | |
979 protected function assertCaptchaSessionIdReuseAttackDetection() { | |
980 $this->assertText(t(CAPTCHA_SESSION_REUSE_ATTACK_ERROR_MESSAGE), | |
981 'CAPTCHA session ID reuse attack should be detected.', | |
982 'CAPTCHA'); | |
983 // There should be an error message about wrong response. | |
984 $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), | |
985 'CAPTCHA response should flagged as wrong.', | |
986 'CAPTCHA'); | |
987 } | |
988 | |
989 function testCaptchaSessionReuseAttackDetectionOnCommentPreview() { | |
990 // Create commentable node | |
991 $node = $this->createNodeWithCommentsEnabled(); | |
992 // Set Test CAPTCHA on comment form. | |
993 captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Math'); | |
994 variable_set('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE); | |
995 | |
996 // Log in as normal user. | |
997 $this->drupalLogin($this->normal_user); | |
998 | |
999 // Go to comment form of commentable node. | |
1000 $this->drupalGet('comment/reply/' . $node->nid); | |
1001 $this->assertCaptchaPresence(TRUE); | |
1002 | |
1003 // Get CAPTCHA session ID and solution of the challenge. | |
1004 $captcha_sid = $this->getCaptchaSidFromForm(); | |
1005 $captcha_token = $this->getCaptchaTokenFromForm(); | |
1006 $solution = $this->getMathCaptchaSolutionFromForm(); | |
1007 | |
1008 // Post the form with the solution. | |
1009 $edit = $this->getCommentFormValues(); | |
1010 $edit['captcha_response'] = $solution; | |
1011 $this->drupalPost(NULL, $edit, t('Preview')); | |
1012 // Answer should be accepted and further CAPTCHA ommitted. | |
1013 $this->assertCaptchaResponseAccepted(); | |
1014 $this->assertCaptchaPresence(FALSE); | |
1015 | |
1016 // Post a new comment, reusing the previous CAPTCHA session. | |
1017 $edit = $this->getCommentFormValues(); | |
1018 $edit['captcha_sid'] = $captcha_sid; | |
1019 $edit['captcha_token'] = $captcha_token; | |
1020 $edit['captcha_response'] = $solution; | |
1021 $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview')); | |
1022 // CAPTCHA session reuse attack should be detected. | |
1023 $this->assertCaptchaSessionIdReuseAttackDetection(); | |
1024 // There should be a CAPTCHA. | |
1025 $this->assertCaptchaPresence(TRUE); | |
1026 | |
1027 } | |
1028 | |
1029 function testCaptchaSessionReuseAttackDetectionOnNodeForm() { | |
1030 // Set CAPTCHA on page form. | |
1031 captcha_set_form_id_setting('page_node_form', 'captcha/Math'); | |
1032 variable_set('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE); | |
1033 | |
1034 // Log in as normal user. | |
1035 $this->drupalLogin($this->normal_user); | |
1036 | |
1037 // Go to node add form. | |
1038 $this->drupalGet('node/add/page'); | |
1039 $this->assertCaptchaPresence(TRUE); | |
1040 | |
1041 // Get CAPTCHA session ID and solution of the challenge. | |
1042 $captcha_sid = $this->getCaptchaSidFromForm(); | |
1043 $captcha_token = $this->getCaptchaTokenFromForm(); | |
1044 $solution = $this->getMathCaptchaSolutionFromForm(); | |
1045 | |
1046 // Page settings to post, with correct CAPTCHA answer. | |
1047 $edit = $this->getNodeFormValues(); | |
1048 $edit['captcha_response'] = $solution; | |
1049 // Preview the node | |
1050 $this->drupalPost(NULL, $edit, t('Preview')); | |
1051 // Answer should be accepted. | |
1052 $this->assertCaptchaResponseAccepted(); | |
1053 // Check that there is no CAPTCHA after preview. | |
1054 $this->assertCaptchaPresence(FALSE); | |
1055 | |
1056 // Post a new comment, reusing the previous CAPTCHA session. | |
1057 $edit = $this->getNodeFormValues(); | |
1058 $edit['captcha_sid'] = $captcha_sid; | |
1059 $edit['captcha_token'] = $captcha_token; | |
1060 $edit['captcha_response'] = $solution; | |
1061 $this->drupalPost('node/add/page', $edit, t('Preview')); | |
1062 // CAPTCHA session reuse attack should be detected. | |
1063 $this->assertCaptchaSessionIdReuseAttackDetection(); | |
1064 // There should be a CAPTCHA. | |
1065 $this->assertCaptchaPresence(TRUE); | |
1066 | |
1067 } | |
1068 | |
1069 function testCaptchaSessionReuseAttackDetectionOnLoginForm() { | |
1070 // Set CAPTCHA on login form. | |
1071 captcha_set_form_id_setting('user_login', 'captcha/Math'); | |
1072 variable_set('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE); | |
1073 | |
1074 // Go to log in form. | |
1075 $this->drupalGet('user'); | |
1076 $this->assertCaptchaPresence(TRUE); | |
1077 | |
1078 // Get CAPTCHA session ID and solution of the challenge. | |
1079 $captcha_sid = $this->getCaptchaSidFromForm(); | |
1080 $captcha_token = $this->getCaptchaTokenFromForm(); | |
1081 $solution = $this->getMathCaptchaSolutionFromForm(); | |
1082 | |
1083 // Log in through form. | |
1084 $edit = array( | |
1085 'name' => $this->normal_user->name, | |
1086 'pass' => $this->normal_user->pass_raw, | |
1087 'captcha_response' => $solution, | |
1088 ); | |
1089 $this->drupalPost(NULL, $edit, t('Log in')); | |
1090 $this->assertCaptchaResponseAccepted(); | |
1091 $this->assertCaptchaPresence(FALSE); | |
1092 // If a "log out" link appears on the page, it is almost certainly because | |
1093 // the login was successful. | |
1094 $pass = $this->assertLink(t('Log out'), 0, t('User %name successfully logged in.', array('%name' => $this->normal_user->name)), t('User login')); | |
1095 | |
1096 // Log out again. | |
1097 $this->drupalLogout(); | |
1098 | |
1099 // Try to log in again, reusing the previous CAPTCHA session. | |
1100 $edit += array( | |
1101 'captcha_sid' => $captcha_sid, | |
1102 'captcha_token' => $captcha_token, | |
1103 ); | |
1104 $this->drupalPost('user', $edit, t('Log in')); | |
1105 // CAPTCHA session reuse attack should be detected. | |
1106 $this->assertCaptchaSessionIdReuseAttackDetection(); | |
1107 // There should be a CAPTCHA. | |
1108 $this->assertCaptchaPresence(TRUE); | |
1109 } | |
1110 | |
1111 | |
1112 public function testMultipleCaptchaProtectedFormsOnOnePage() | |
1113 { | |
1114 // Set Test CAPTCHA on comment form and login block | |
1115 captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test'); | |
1116 captcha_set_form_id_setting('user_login_block', 'captcha/Math'); | |
1117 $this->allowCommentPostingForAnonymousVisitors(); | |
1118 | |
1119 // Create a node with comments enabled. | |
1120 $node = $this->createNodeWithCommentsEnabled(); | |
1121 | |
1122 // Preview comment with correct CAPTCHA answer. | |
1123 $edit = $this->getCommentFormValues(); | |
1124 $comment_subject = $edit['subject']; | |
1125 $edit['captcha_response'] = 'Test 123'; | |
1126 $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview')); | |
1127 // Post should be accepted: no warnings, | |
1128 // no CAPTCHA reuse detection (which could be used by user log in block). | |
1129 $this->assertCaptchaResponseAccepted(); | |
1130 $this->assertText($comment_subject); | |
1131 | |
1132 } | |
1133 | |
1134 } | |
1135 | |
1136 | |
1137 // Some tricks to debug: | |
1138 // drupal_debug($data) // from devel module | |
1139 // file_put_contents('tmp.simpletest.html', $this->drupalGetContent()); |