danielebarchiesi@2: normal_user = $this->drupalCreateUser($permissions); danielebarchiesi@2: danielebarchiesi@2: // Create an admin user. danielebarchiesi@2: $permissions[] = 'administer CAPTCHA settings'; danielebarchiesi@2: $permissions[] = 'skip CAPTCHA'; danielebarchiesi@2: $permissions[] = 'administer permissions'; danielebarchiesi@2: $permissions[] = 'administer content types'; danielebarchiesi@2: $this->admin_user = $this->drupalCreateUser($permissions); danielebarchiesi@2: danielebarchiesi@2: // Put comments on page nodes on a separate page (default in D7: below post). danielebarchiesi@2: variable_set('comment_form_location_page', COMMENT_FORM_SEPARATE_PAGE); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Assert that the response is accepted: danielebarchiesi@2: * no "unknown CSID" message, no "CSID reuse attack detection" message, danielebarchiesi@2: * no "wrong answer" message. danielebarchiesi@2: */ danielebarchiesi@2: protected function assertCaptchaResponseAccepted() { danielebarchiesi@2: // There should be no error message about unknown CAPTCHA session ID. danielebarchiesi@2: $this->assertNoText(t(CAPTCHA_UNKNOWN_CSID_ERROR_MESSAGE), danielebarchiesi@2: 'CAPTCHA response should be accepted (known CSID).', danielebarchiesi@2: 'CAPTCHA'); danielebarchiesi@2: // There should be no error message about CSID reuse attack. danielebarchiesi@2: $this->assertNoText(t(CAPTCHA_SESSION_REUSE_ATTACK_ERROR_MESSAGE), danielebarchiesi@2: 'CAPTCHA response should be accepted (no CAPTCHA session reuse attack detection).', danielebarchiesi@2: 'CAPTCHA'); danielebarchiesi@2: // There should be no error message about wrong response. danielebarchiesi@2: $this->assertNoText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), danielebarchiesi@2: 'CAPTCHA response should be accepted (correct response).', danielebarchiesi@2: 'CAPTCHA'); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Assert that there is a CAPTCHA on the form or not. danielebarchiesi@2: * @param bool $presence whether there should be a CAPTCHA or not. danielebarchiesi@2: */ danielebarchiesi@2: protected function assertCaptchaPresence($presence) { danielebarchiesi@2: if ($presence) { danielebarchiesi@2: $this->assertText(_captcha_get_description(), danielebarchiesi@2: 'There should be a CAPTCHA on the form.', 'CAPTCHA'); danielebarchiesi@2: } danielebarchiesi@2: else { danielebarchiesi@2: $this->assertNoText(_captcha_get_description(), danielebarchiesi@2: 'There should be no CAPTCHA on the form.', 'CAPTCHA'); danielebarchiesi@2: } danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Helper function to create a node with comments enabled. danielebarchiesi@2: * danielebarchiesi@2: * @return danielebarchiesi@2: * Created node object. danielebarchiesi@2: */ danielebarchiesi@2: protected function createNodeWithCommentsEnabled($type='page') { danielebarchiesi@2: $node_settings = array( danielebarchiesi@2: 'type' => $type, danielebarchiesi@2: 'comment' => COMMENT_NODE_OPEN, danielebarchiesi@2: ); danielebarchiesi@2: $node = $this->drupalCreateNode($node_settings); danielebarchiesi@2: return $node; danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Helper function to generate a form values array for comment forms danielebarchiesi@2: */ danielebarchiesi@2: protected function getCommentFormValues() { danielebarchiesi@2: $edit = array( danielebarchiesi@2: 'subject' => 'comment_subject ' . $this->randomName(32), danielebarchiesi@2: 'comment_body[' . LANGUAGE_NONE . '][0][value]' => 'comment_body ' . $this->randomName(256), danielebarchiesi@2: ); danielebarchiesi@2: return $edit; danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Helper function to generate a form values array for node forms danielebarchiesi@2: */ danielebarchiesi@2: protected function getNodeFormValues() { danielebarchiesi@2: $edit = array( danielebarchiesi@2: 'title' => 'node_title ' . $this->randomName(32), danielebarchiesi@2: 'body[' . LANGUAGE_NONE . '][0][value]' => 'node_body ' . $this->randomName(256), danielebarchiesi@2: ); danielebarchiesi@2: return $edit; danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Get the CAPTCHA session id from the current form in the browser. danielebarchiesi@2: */ danielebarchiesi@2: protected function getCaptchaSidFromForm() { danielebarchiesi@2: $elements = $this->xpath('//input[@name="captcha_sid"]'); danielebarchiesi@2: $captcha_sid = (int) $elements[0]['value']; danielebarchiesi@2: return $captcha_sid; danielebarchiesi@2: } danielebarchiesi@2: /** danielebarchiesi@2: * Get the CAPTCHA token from the current form in the browser. danielebarchiesi@2: */ danielebarchiesi@2: protected function getCaptchaTokenFromForm() { danielebarchiesi@2: $elements = $this->xpath('//input[@name="captcha_token"]'); danielebarchiesi@2: $captcha_token = (int) $elements[0]['value']; danielebarchiesi@2: return $captcha_token; danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Get the solution of the math CAPTCHA from the current form in the browser. danielebarchiesi@2: */ danielebarchiesi@2: protected function getMathCaptchaSolutionFromForm() { danielebarchiesi@2: // Get the math challenge. danielebarchiesi@2: $elements = $this->xpath('//div[@class="form-item form-type-textfield form-item-captcha-response"]/span[@class="field-prefix"]'); danielebarchiesi@2: $challenge = (string) $elements[0]; danielebarchiesi@2: // Extract terms and operator from challenge. danielebarchiesi@2: $matches = array(); danielebarchiesi@2: $ret = preg_match('/\\s*(\\d+)\\s*(-|\\+)\\s*(\\d+)\\s*=\\s*/', $challenge, $matches); danielebarchiesi@2: // Solve the challenge danielebarchiesi@2: $a = (int) $matches[1]; danielebarchiesi@2: $b = (int) $matches[3]; danielebarchiesi@2: $solution = $matches[2] == '-' ? $a - $b : $a + $b; danielebarchiesi@2: return $solution; danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Helper function to allow comment posting for anonymous users. danielebarchiesi@2: */ danielebarchiesi@2: protected function allowCommentPostingForAnonymousVisitors() { danielebarchiesi@2: // Log in as admin. danielebarchiesi@2: $this->drupalLogin($this->admin_user); danielebarchiesi@2: // Post user permissions form danielebarchiesi@2: $edit = array( danielebarchiesi@2: '1[access comments]' => true, danielebarchiesi@2: '1[post comments]' => true, danielebarchiesi@2: '1[skip comment approval]' => true, danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost('admin/people/permissions', $edit, 'Save permissions'); danielebarchiesi@2: $this->assertText('The changes have been saved.'); danielebarchiesi@2: // Log admin out danielebarchiesi@2: $this->drupalLogout(); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: class CaptchaTestCase extends CaptchaBaseWebTestCase { danielebarchiesi@2: danielebarchiesi@2: public static function getInfo() { danielebarchiesi@2: return array( danielebarchiesi@2: 'name' => t('General CAPTCHA functionality'), danielebarchiesi@2: 'description' => t('Testing of the basic CAPTCHA functionality.'), danielebarchiesi@2: 'group' => t('CAPTCHA'), danielebarchiesi@2: ); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Testing the protection of the user log in form. danielebarchiesi@2: */ danielebarchiesi@2: function testCaptchaOnLoginForm() { danielebarchiesi@2: // Create user and test log in without CAPTCHA. danielebarchiesi@2: $user = $this->drupalCreateUser(); danielebarchiesi@2: $this->drupalLogin($user); danielebarchiesi@2: // Log out again. danielebarchiesi@2: $this->drupalLogout(); danielebarchiesi@2: danielebarchiesi@2: // Set a CAPTCHA on login form danielebarchiesi@2: captcha_set_form_id_setting('user_login', 'captcha/Math'); danielebarchiesi@2: danielebarchiesi@2: // Check if there is a CAPTCHA on the login form (look for the title). danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: danielebarchiesi@2: // Try to log in, which should fail. danielebarchiesi@2: $edit = array( danielebarchiesi@2: 'name' => $user->name, danielebarchiesi@2: 'pass' => $user->pass_raw, danielebarchiesi@2: 'captcha_response' => '?', danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost('user', $edit, t('Log in')); danielebarchiesi@2: // Check for error message. danielebarchiesi@2: $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), danielebarchiesi@2: 'CAPTCHA should block user login form', 'CAPTCHA'); danielebarchiesi@2: danielebarchiesi@2: // And make sure that user is not logged in: check for name and password fields on ?q=user danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertField('name', t('Username field found.'), 'CAPTCHA'); danielebarchiesi@2: $this->assertField('pass', t('Password field found.'), 'CAPTCHA'); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Assert function for testing if comment posting works as it should. danielebarchiesi@2: * danielebarchiesi@2: * Creates node with comment writing enabled, tries to post comment danielebarchiesi@2: * with given CAPTCHA response (caller should enable the desired danielebarchiesi@2: * challenge on page node comment forms) and checks if the result is as expected. danielebarchiesi@2: * danielebarchiesi@2: * @param $captcha_response the response on the CAPTCHA danielebarchiesi@2: * @param $should_pass boolean describing if the posting should pass or should be blocked danielebarchiesi@2: * @param $message message to prefix to nested asserts danielebarchiesi@2: */ danielebarchiesi@2: protected function assertCommentPosting($captcha_response, $should_pass, $message) { danielebarchiesi@2: // Make sure comments on pages can be saved directely without preview. danielebarchiesi@2: variable_set('comment_preview_page', DRUPAL_OPTIONAL); danielebarchiesi@2: danielebarchiesi@2: // Create a node with comments enabled. danielebarchiesi@2: $node = $this->createNodeWithCommentsEnabled(); danielebarchiesi@2: danielebarchiesi@2: // Post comment on node. danielebarchiesi@2: $edit = $this->getCommentFormValues(); danielebarchiesi@2: $comment_subject = $edit['subject']; danielebarchiesi@2: $comment_body = $edit['comment_body[' . LANGUAGE_NONE . '][0][value]']; danielebarchiesi@2: $edit['captcha_response'] = $captcha_response; danielebarchiesi@2: $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Save')); danielebarchiesi@2: danielebarchiesi@2: if ($should_pass) { danielebarchiesi@2: // There should be no error message. danielebarchiesi@2: $this->assertCaptchaResponseAccepted(); danielebarchiesi@2: // Get node page and check that comment shows up. danielebarchiesi@2: $this->drupalGet('node/' . $node->nid); danielebarchiesi@2: $this->assertText($comment_subject, $message .' Comment should show up on node page.', 'CAPTCHA'); danielebarchiesi@2: $this->assertText($comment_body, $message . ' Comment should show up on node page.', 'CAPTCHA'); danielebarchiesi@2: } danielebarchiesi@2: else { danielebarchiesi@2: // Check for error message. danielebarchiesi@2: $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), $message .' Comment submission should be blocked.', 'CAPTCHA'); danielebarchiesi@2: // Get node page and check that comment is not present. danielebarchiesi@2: $this->drupalGet('node/' . $node->nid); danielebarchiesi@2: $this->assertNoText($comment_subject, $message .' Comment should not show up on node page.', 'CAPTCHA'); danielebarchiesi@2: $this->assertNoText($comment_body, $message . ' Comment should not show up on node page.', 'CAPTCHA'); danielebarchiesi@2: } danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /* danielebarchiesi@2: * Testing the case sensistive/insensitive validation. danielebarchiesi@2: */ danielebarchiesi@2: function testCaseInsensitiveValidation() { danielebarchiesi@2: // Set Test CAPTCHA on comment form danielebarchiesi@2: captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test'); danielebarchiesi@2: danielebarchiesi@2: // Log in as normal user. danielebarchiesi@2: $this->drupalLogin($this->normal_user); danielebarchiesi@2: danielebarchiesi@2: // Test case sensitive posting. danielebarchiesi@2: variable_set('captcha_default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_SENSITIVE); danielebarchiesi@2: $this->assertCommentPosting('Test 123', TRUE, 'Case sensitive validation of right casing.'); danielebarchiesi@2: $this->assertCommentPosting('test 123', FALSE, 'Case sensitive validation of wrong casing.'); danielebarchiesi@2: $this->assertCommentPosting('TEST 123', FALSE, 'Case sensitive validation of wrong casing.'); danielebarchiesi@2: danielebarchiesi@2: // Test case insensitive posting (the default) danielebarchiesi@2: variable_set('captcha_default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE); danielebarchiesi@2: $this->assertCommentPosting('Test 123', TRUE, 'Case insensitive validation of right casing.'); danielebarchiesi@2: $this->assertCommentPosting('test 123', TRUE, 'Case insensitive validation of wrong casing.'); danielebarchiesi@2: $this->assertCommentPosting('TEST 123', TRUE, 'Case insensitive validation of wrong casing.'); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Test if the CAPTCHA description is only shown if there are challenge widgets to show. danielebarchiesi@2: * For example, when a comment is previewed with correct CAPTCHA answer, danielebarchiesi@2: * a challenge is generated and added to the form but removed in the pre_render phase. danielebarchiesi@2: * The CAPTCHA description should not show up either. danielebarchiesi@2: * danielebarchiesi@2: * \see testCaptchaSessionReuseOnNodeForms() danielebarchiesi@2: */ danielebarchiesi@2: function testCaptchaDescriptionAfterCommentPreview() { danielebarchiesi@2: // Set Test CAPTCHA on comment form. danielebarchiesi@2: captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test'); danielebarchiesi@2: danielebarchiesi@2: // Log in as normal user. danielebarchiesi@2: $this->drupalLogin($this->normal_user); danielebarchiesi@2: danielebarchiesi@2: // Create a node with comments enabled. danielebarchiesi@2: $node = $this->createNodeWithCommentsEnabled(); danielebarchiesi@2: danielebarchiesi@2: // Preview comment with correct CAPTCHA answer. danielebarchiesi@2: $edit = $this->getCommentFormValues(); danielebarchiesi@2: $edit['captcha_response'] = 'Test 123'; danielebarchiesi@2: $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview')); danielebarchiesi@2: danielebarchiesi@2: // Check that there is no CAPTCHA after preview. danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Test if the CAPTCHA session ID is reused when previewing nodes: danielebarchiesi@2: * node preview after correct response should not show CAPTCHA anymore. danielebarchiesi@2: * The preview functionality of comments and nodes works slightly different under the hood. danielebarchiesi@2: * CAPTCHA module should be able to handle both. danielebarchiesi@2: * danielebarchiesi@2: * \see testCaptchaDescriptionAfterCommentPreview() danielebarchiesi@2: */ danielebarchiesi@2: function testCaptchaSessionReuseOnNodeForms() { danielebarchiesi@2: // Set Test CAPTCHA on page form. danielebarchiesi@2: captcha_set_form_id_setting('page_node_form', 'captcha/Test'); danielebarchiesi@2: danielebarchiesi@2: // Log in as normal user. danielebarchiesi@2: $this->drupalLogin($this->normal_user); danielebarchiesi@2: danielebarchiesi@2: // Page settings to post, with correct CAPTCHA answer. danielebarchiesi@2: $edit = $this->getNodeFormValues(); danielebarchiesi@2: $edit['captcha_response'] = 'Test 123'; danielebarchiesi@2: // Preview the node danielebarchiesi@2: $this->drupalPost('node/add/page', $edit, t('Preview')); danielebarchiesi@2: danielebarchiesi@2: // Check that there is no CAPTCHA after preview. danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * CAPTCHA should also be put on admin pages even if visitor danielebarchiesi@2: * has no access danielebarchiesi@2: */ danielebarchiesi@2: function testCaptchaOnLoginBlockOnAdminPagesIssue893810() { danielebarchiesi@2: // Set a CAPTCHA on login block form danielebarchiesi@2: captcha_set_form_id_setting('user_login_block', 'captcha/Math'); danielebarchiesi@2: danielebarchiesi@2: // Check if there is a CAPTCHA on home page. danielebarchiesi@2: $this->drupalGet('node'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: danielebarchiesi@2: // Check there is a CAPTCHA on "forbidden" admin pages danielebarchiesi@2: $this->drupalGet('admin'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: class CaptchaAdminTestCase extends CaptchaBaseWebTestCase { danielebarchiesi@2: danielebarchiesi@2: public static function getInfo() { danielebarchiesi@2: return array( danielebarchiesi@2: 'name' => t('CAPTCHA administration functionality'), danielebarchiesi@2: 'description' => t('Testing of the CAPTCHA administration interface and functionality.'), danielebarchiesi@2: 'group' => t('CAPTCHA'), danielebarchiesi@2: ); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Test access to the admin pages. danielebarchiesi@2: */ danielebarchiesi@2: function testAdminAccess() { danielebarchiesi@2: $this->drupalLogin($this->normal_user); danielebarchiesi@2: $this->drupalGet(self::CAPTCHA_ADMIN_PATH); danielebarchiesi@2: file_put_contents('tmp.simpletest.html', $this->drupalGetContent()); danielebarchiesi@2: $this->assertText(t('Access denied'), 'Normal users should not be able to access the CAPTCHA admin pages', 'CAPTCHA'); danielebarchiesi@2: danielebarchiesi@2: $this->drupalLogin($this->admin_user); danielebarchiesi@2: $this->drupalGet(self::CAPTCHA_ADMIN_PATH); danielebarchiesi@2: $this->assertNoText(t('Access denied'), 'Admin users should be able to access the CAPTCHA admin pages', 'CAPTCHA'); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Test the CAPTCHA point setting getter/setter. danielebarchiesi@2: */ danielebarchiesi@2: function testCaptchaPointSettingGetterAndSetter() { danielebarchiesi@2: $comment_form_id = self::COMMENT_FORM_ID; danielebarchiesi@2: // Set to 'none'. danielebarchiesi@2: captcha_set_form_id_setting($comment_form_id, 'none'); danielebarchiesi@2: $result = captcha_get_form_id_setting($comment_form_id); danielebarchiesi@2: $this->assertNotNull($result, 'Setting and getting CAPTCHA point: none', 'CAPTCHA'); danielebarchiesi@2: $this->assertNull($result->module, 'Setting and getting CAPTCHA point: none', 'CAPTCHA'); danielebarchiesi@2: $this->assertNull($result->captcha_type, 'Setting and getting CAPTCHA point: none', 'CAPTCHA'); danielebarchiesi@2: $result = captcha_get_form_id_setting($comment_form_id, TRUE); danielebarchiesi@2: $this->assertEqual($result, 'none', 'Setting and symbolic getting CAPTCHA point: "none"', 'CAPTCHA'); danielebarchiesi@2: // Set to 'default' danielebarchiesi@2: captcha_set_form_id_setting($comment_form_id, 'default'); danielebarchiesi@2: variable_set('captcha_default_challenge', 'foo/bar'); danielebarchiesi@2: $result = captcha_get_form_id_setting($comment_form_id); danielebarchiesi@2: $this->assertNotNull($result, 'Setting and getting CAPTCHA point: default', 'CAPTCHA'); danielebarchiesi@2: $this->assertEqual($result->module, 'foo', 'Setting and getting CAPTCHA point: default', 'CAPTCHA'); danielebarchiesi@2: $this->assertEqual($result->captcha_type, 'bar', 'Setting and getting CAPTCHA point: default', 'CAPTCHA'); danielebarchiesi@2: $result = captcha_get_form_id_setting($comment_form_id, TRUE); danielebarchiesi@2: $this->assertEqual($result, 'default', 'Setting and symbolic getting CAPTCHA point: "default"', 'CAPTCHA'); danielebarchiesi@2: // Set to 'baz/boo'. danielebarchiesi@2: captcha_set_form_id_setting($comment_form_id, 'baz/boo'); danielebarchiesi@2: $result = captcha_get_form_id_setting($comment_form_id); danielebarchiesi@2: $this->assertNotNull($result, 'Setting and getting CAPTCHA point: baz/boo', 'CAPTCHA'); danielebarchiesi@2: $this->assertEqual($result->module, 'baz', 'Setting and getting CAPTCHA point: baz/boo', 'CAPTCHA'); danielebarchiesi@2: $this->assertEqual($result->captcha_type, 'boo', 'Setting and getting CAPTCHA point: baz/boo', 'CAPTCHA'); danielebarchiesi@2: $result = captcha_get_form_id_setting($comment_form_id, TRUE); danielebarchiesi@2: $this->assertEqual($result, 'baz/boo', 'Setting and symbolic getting CAPTCHA point: "baz/boo"', 'CAPTCHA'); danielebarchiesi@2: // Set to NULL (which should delete the CAPTCHA point setting entry). danielebarchiesi@2: captcha_set_form_id_setting($comment_form_id, NULL); danielebarchiesi@2: $result = captcha_get_form_id_setting($comment_form_id); danielebarchiesi@2: $this->assertNull($result, 'Setting and getting CAPTCHA point: NULL', 'CAPTCHA'); danielebarchiesi@2: $result = captcha_get_form_id_setting($comment_form_id, TRUE); danielebarchiesi@2: $this->assertNull($result, 'Setting and symbolic getting CAPTCHA point: NULL', 'CAPTCHA'); danielebarchiesi@2: // Set with object. danielebarchiesi@2: $captcha_type = new stdClass; danielebarchiesi@2: $captcha_type->module = 'baba'; danielebarchiesi@2: $captcha_type->captcha_type = 'fofo'; danielebarchiesi@2: captcha_set_form_id_setting($comment_form_id, $captcha_type); danielebarchiesi@2: $result = captcha_get_form_id_setting($comment_form_id); danielebarchiesi@2: $this->assertNotNull($result, 'Setting and getting CAPTCHA point: baba/fofo', 'CAPTCHA'); danielebarchiesi@2: $this->assertEqual($result->module, 'baba', 'Setting and getting CAPTCHA point: baba/fofo', 'CAPTCHA'); danielebarchiesi@2: $this->assertEqual($result->captcha_type, 'fofo', 'Setting and getting CAPTCHA point: baba/fofo', 'CAPTCHA'); danielebarchiesi@2: $result = captcha_get_form_id_setting($comment_form_id, TRUE); danielebarchiesi@2: $this->assertEqual($result, 'baba/fofo', 'Setting and symbolic getting CAPTCHA point: "baba/fofo"', 'CAPTCHA'); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Helper function for checking CAPTCHA setting of a form. danielebarchiesi@2: * danielebarchiesi@2: * @param $form_id the form_id of the form to investigate. danielebarchiesi@2: * @param $challenge_type what the challenge type should be: danielebarchiesi@2: * NULL, 'none', 'default' or something like 'captcha/Math' danielebarchiesi@2: */ danielebarchiesi@2: protected function assertCaptchaSetting($form_id, $challenge_type) { danielebarchiesi@2: $result = captcha_get_form_id_setting(self::COMMENT_FORM_ID, TRUE); danielebarchiesi@2: $this->assertEqual($result, $challenge_type, danielebarchiesi@2: t('Check CAPTCHA setting for form: expected: @expected, received: @received.', danielebarchiesi@2: array('@expected' => var_export($challenge_type, TRUE), '@received' => var_export($result, TRUE))), danielebarchiesi@2: 'CAPTCHA'); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Testing of the CAPTCHA administration links. danielebarchiesi@2: */ danielebarchiesi@2: function testCaptchAdminLinks() { danielebarchiesi@2: // Log in as admin danielebarchiesi@2: $this->drupalLogin($this->admin_user); danielebarchiesi@2: danielebarchiesi@2: // Enable CAPTCHA administration links. danielebarchiesi@2: $edit = array( danielebarchiesi@2: 'captcha_administration_mode' => TRUE, danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost(self::CAPTCHA_ADMIN_PATH, $edit, 'Save configuration'); danielebarchiesi@2: danielebarchiesi@2: // Create a node with comments enabled. danielebarchiesi@2: $node = $this->createNodeWithCommentsEnabled(); danielebarchiesi@2: danielebarchiesi@2: // Go to node page danielebarchiesi@2: $this->drupalGet('node/' . $node->nid); danielebarchiesi@2: danielebarchiesi@2: // Click the add new comment link danielebarchiesi@2: $this->clickLink(t('Add new comment')); danielebarchiesi@2: $add_comment_url = $this->getUrl(); danielebarchiesi@2: // Remove fragment part from comment URL to avoid problems with later asserts danielebarchiesi@2: $add_comment_url = strtok($add_comment_url, "#"); danielebarchiesi@2: danielebarchiesi@2: //////////////////////////////////////////////////////////// danielebarchiesi@2: // Click the CAPTCHA admin link to enable a challenge. danielebarchiesi@2: $this->clickLink(t('Place a CAPTCHA here for untrusted users.')); danielebarchiesi@2: // Enable Math CAPTCHA. danielebarchiesi@2: $edit = array('captcha_type' => 'captcha/Math'); danielebarchiesi@2: $this->drupalPost($this->getUrl(), $edit, t('Save')); danielebarchiesi@2: danielebarchiesi@2: // Check if returned to original comment form. danielebarchiesi@2: $this->assertUrl($add_comment_url, array(), danielebarchiesi@2: 'After setting CAPTCHA with CAPTCHA admin links: should return to original form.', 'CAPTCHA'); danielebarchiesi@2: // Check if CAPTCHA was successfully enabled (on CAPTCHA admin links fieldset). danielebarchiesi@2: $this->assertText(t('CAPTCHA: challenge "@type" enabled', array('@type' => 'Math')), danielebarchiesi@2: 'Enable a challenge through the CAPTCHA admin links', 'CAPTCHA'); danielebarchiesi@2: // Check if CAPTCHA was successfully enabled (through API). danielebarchiesi@2: $this->assertCaptchaSetting(self::COMMENT_FORM_ID, 'captcha/Math'); danielebarchiesi@2: danielebarchiesi@2: ////////////////////////////////////////////////////// danielebarchiesi@2: // Edit challenge type through CAPTCHA admin links. danielebarchiesi@2: $this->clickLink(t('change')); danielebarchiesi@2: // Enable Math CAPTCHA. danielebarchiesi@2: $edit = array('captcha_type' => 'default'); danielebarchiesi@2: $this->drupalPost($this->getUrl(), $edit, t('Save')); danielebarchiesi@2: danielebarchiesi@2: // Check if returned to original comment form. danielebarchiesi@2: $this->assertEqual($add_comment_url, $this->getUrl(), danielebarchiesi@2: 'After editing challenge type CAPTCHA admin links: should return to original form.', 'CAPTCHA'); danielebarchiesi@2: // Check if CAPTCHA was successfully changed (on CAPTCHA admin links fieldset). danielebarchiesi@2: // This is actually the same as the previous setting because the captcha/Math is the danielebarchiesi@2: // default for the default challenge. TODO Make sure the edit is a real change. danielebarchiesi@2: $this->assertText(t('CAPTCHA: challenge "@type" enabled', array('@type' => 'Math')), danielebarchiesi@2: 'Enable a challenge through the CAPTCHA admin links', 'CAPTCHA'); danielebarchiesi@2: // Check if CAPTCHA was successfully edited (through API). danielebarchiesi@2: $this->assertCaptchaSetting(self::COMMENT_FORM_ID, 'default'); danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: ////////////////////////////////////////////////////// danielebarchiesi@2: // Disable challenge through CAPTCHA admin links. danielebarchiesi@2: $this->clickLink(t('disable')); danielebarchiesi@2: // And confirm. danielebarchiesi@2: $this->drupalPost($this->getUrl(), array(), 'Disable'); danielebarchiesi@2: danielebarchiesi@2: // Check if returned to original comment form. danielebarchiesi@2: $this->assertEqual($add_comment_url, $this->getUrl(), danielebarchiesi@2: 'After disablin challenge with CAPTCHA admin links: should return to original form.', 'CAPTCHA'); danielebarchiesi@2: // Check if CAPTCHA was successfully disabled (on CAPTCHA admin links fieldset). danielebarchiesi@2: $this->assertText(t('CAPTCHA: no challenge enabled'), danielebarchiesi@2: 'Disable challenge through the CAPTCHA admin links', 'CAPTCHA'); danielebarchiesi@2: // Check if CAPTCHA was successfully disabled (through API). danielebarchiesi@2: $this->assertCaptchaSetting(self::COMMENT_FORM_ID, 'none'); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: function testUntrustedUserPosting() { danielebarchiesi@2: // Set CAPTCHA on comment form. danielebarchiesi@2: captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Math'); danielebarchiesi@2: danielebarchiesi@2: // Create a node with comments enabled. danielebarchiesi@2: $node = $this->createNodeWithCommentsEnabled(); danielebarchiesi@2: danielebarchiesi@2: // Log in as normal (untrusted) user. danielebarchiesi@2: $this->drupalLogin($this->normal_user); danielebarchiesi@2: danielebarchiesi@2: // Go to node page and click the "add comment" link. danielebarchiesi@2: $this->drupalGet('node/' . $node->nid); danielebarchiesi@2: $this->clickLink(t('Add new comment')); danielebarchiesi@2: $add_comment_url = $this->getUrl(); danielebarchiesi@2: danielebarchiesi@2: // Check if CAPTCHA is visible on form. danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: // Try to post a comment with wrong answer. danielebarchiesi@2: $edit = $this->getCommentFormValues(); danielebarchiesi@2: $edit['captcha_response'] = 'xx'; danielebarchiesi@2: $this->drupalPost($add_comment_url, $edit, t('Preview')); danielebarchiesi@2: $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), danielebarchiesi@2: 'wrong CAPTCHA should block form submission.', 'CAPTCHA'); danielebarchiesi@2: danielebarchiesi@2: //TODO: more testing for untrusted posts. danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Test XSS vulnerability on CAPTCHA description. danielebarchiesi@2: */ danielebarchiesi@2: function testXssOnCaptchaDescription() { danielebarchiesi@2: // Set CAPTCHA on user register form. danielebarchiesi@2: captcha_set_form_id_setting('user_register', 'captcha/Math'); danielebarchiesi@2: danielebarchiesi@2: // Put Javascript snippet in CAPTCHA description. danielebarchiesi@2: $this->drupalLogin($this->admin_user); danielebarchiesi@2: $xss = ''; danielebarchiesi@2: $edit = array('captcha_description' => $xss); danielebarchiesi@2: $this->drupalPost(self::CAPTCHA_ADMIN_PATH, $edit, 'Save configuration'); danielebarchiesi@2: danielebarchiesi@2: // Visit user register form and check if Javascript snippet is there. danielebarchiesi@2: $this->drupalLogout(); danielebarchiesi@2: $this->drupalGet('user/register'); danielebarchiesi@2: $this->assertNoRaw($xss, 'Javascript should not be allowed in CAPTCHA description.', 'CAPTCHA'); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Test the CAPTCHA placement clearing. danielebarchiesi@2: */ danielebarchiesi@2: function testCaptchaPlacementCacheClearing() { danielebarchiesi@2: // Set CAPTCHA on user register form. danielebarchiesi@2: captcha_set_form_id_setting('user_register_form', 'captcha/Math'); danielebarchiesi@2: // Visit user register form to fill the CAPTCHA placement cache. danielebarchiesi@2: $this->drupalGet('user/register'); danielebarchiesi@2: // Check if there is CAPTCHA placement cache. danielebarchiesi@2: $placement_map = variable_get('captcha_placement_map_cache', NULL); danielebarchiesi@2: $this->assertNotNull($placement_map, 'CAPTCHA placement cache should be set.'); danielebarchiesi@2: // Clear the cache danielebarchiesi@2: $this->drupalLogin($this->admin_user); danielebarchiesi@2: $this->drupalPost(self::CAPTCHA_ADMIN_PATH, array(), t('Clear the CAPTCHA placement cache')); danielebarchiesi@2: // Check that the placement cache is unset danielebarchiesi@2: $placement_map = variable_get('captcha_placement_map_cache', NULL); danielebarchiesi@2: $this->assertNull($placement_map, 'CAPTCHA placement cache should be unset after cache clear.'); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Helper function to get the CAPTCHA point setting straight from the database. danielebarchiesi@2: * @param string $form_id danielebarchiesi@2: * @return stdClass object danielebarchiesi@2: */ danielebarchiesi@2: private function getCaptchaPointSettingFromDatabase($form_id) { danielebarchiesi@2: $result = db_query( danielebarchiesi@2: "SELECT * FROM {captcha_points} WHERE form_id = :form_id", danielebarchiesi@2: array(':form_id' => $form_id) danielebarchiesi@2: )->fetchObject(); danielebarchiesi@2: return $result; danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Method for testing the CAPTCHA point administration danielebarchiesi@2: */ danielebarchiesi@2: function testCaptchaPointAdministration() { danielebarchiesi@2: // Generate CAPTCHA point data: danielebarchiesi@2: // Drupal form ID should consist of lowercase alphanumerics and underscore) danielebarchiesi@2: $captcha_point_form_id = 'form_' . strtolower($this->randomName(32)); danielebarchiesi@2: // the Math CAPTCHA by the CAPTCHA module is always available, so let's use it danielebarchiesi@2: $captcha_point_module = 'captcha'; danielebarchiesi@2: $captcha_point_type = 'Math'; danielebarchiesi@2: danielebarchiesi@2: // Log in as admin danielebarchiesi@2: $this->drupalLogin($this->admin_user); danielebarchiesi@2: danielebarchiesi@2: // Set CAPTCHA point through admin/user/captcha/captcha/captcha_point danielebarchiesi@2: $form_values = array( danielebarchiesi@2: 'captcha_point_form_id' => $captcha_point_form_id, danielebarchiesi@2: 'captcha_type' => $captcha_point_module .'/'. $captcha_point_type, danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point', $form_values, t('Save')); danielebarchiesi@2: $this->assertText(t('Saved CAPTCHA point settings.'), danielebarchiesi@2: 'Saving of CAPTCHA point settings'); danielebarchiesi@2: danielebarchiesi@2: // Check in database danielebarchiesi@2: $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id); danielebarchiesi@2: $this->assertEqual($result->module, $captcha_point_module, danielebarchiesi@2: 'Enabled CAPTCHA point should have module set'); danielebarchiesi@2: $this->assertEqual($result->captcha_type, $captcha_point_type, danielebarchiesi@2: 'Enabled CAPTCHA point should have type set'); danielebarchiesi@2: danielebarchiesi@2: // Disable CAPTCHA point again danielebarchiesi@2: $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/disable', array(), t('Disable')); danielebarchiesi@2: $this->assertRaw(t('Disabled CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)), 'Disabling of CAPTCHA point'); danielebarchiesi@2: danielebarchiesi@2: // Check in database danielebarchiesi@2: $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id); danielebarchiesi@2: $this->assertNull($result->module, danielebarchiesi@2: 'Disabled CAPTCHA point should have NULL as module'); danielebarchiesi@2: $this->assertNull($result->captcha_type, danielebarchiesi@2: 'Disabled CAPTCHA point should have NULL as type'); danielebarchiesi@2: danielebarchiesi@2: // Set CAPTCHA point through admin/user/captcha/captcha/captcha_point/$form_id danielebarchiesi@2: $form_values = array( danielebarchiesi@2: 'captcha_type' => $captcha_point_module .'/'. $captcha_point_type, danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id, $form_values, t('Save')); danielebarchiesi@2: $this->assertText(t('Saved CAPTCHA point settings.'), danielebarchiesi@2: 'Saving of CAPTCHA point settings'); danielebarchiesi@2: danielebarchiesi@2: // Check in database danielebarchiesi@2: $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id); danielebarchiesi@2: $this->assertEqual($result->module, $captcha_point_module, danielebarchiesi@2: 'Enabled CAPTCHA point should have module set'); danielebarchiesi@2: $this->assertEqual($result->captcha_type, $captcha_point_type, danielebarchiesi@2: 'Enabled CAPTCHA point should have type set'); danielebarchiesi@2: danielebarchiesi@2: // Delete CAPTCHA point danielebarchiesi@2: $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/delete', array(), t('Delete')); danielebarchiesi@2: $this->assertRaw(t('Deleted CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)), danielebarchiesi@2: 'Deleting of CAPTCHA point'); danielebarchiesi@2: danielebarchiesi@2: // Check in database danielebarchiesi@2: $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id); danielebarchiesi@2: $this->assertFalse($result, 'Deleted CAPTCHA point should be in database'); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Method for testing the CAPTCHA point administration danielebarchiesi@2: */ danielebarchiesi@2: function testCaptchaPointAdministrationByNonAdmin() { danielebarchiesi@2: // First add a CAPTCHA point (as admin) danielebarchiesi@2: $this->drupalLogin($this->admin_user); danielebarchiesi@2: $captcha_point_form_id = 'form_' . strtolower($this->randomName(32)); danielebarchiesi@2: $captcha_point_module = 'captcha'; danielebarchiesi@2: $captcha_point_type = 'Math'; danielebarchiesi@2: $form_values = array( danielebarchiesi@2: 'captcha_point_form_id' => $captcha_point_form_id, danielebarchiesi@2: 'captcha_type' => $captcha_point_module .'/'. $captcha_point_type, danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/', $form_values, t('Save')); danielebarchiesi@2: $this->assertText(t('Saved CAPTCHA point settings.'), danielebarchiesi@2: 'Saving of CAPTCHA point settings'); danielebarchiesi@2: danielebarchiesi@2: // Switch from admin to nonadmin danielebarchiesi@2: $this->drupalGet(url('logout', array('absolute' => TRUE))); danielebarchiesi@2: $this->drupalLogin($this->normal_user); danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: // Try to set CAPTCHA point through admin/user/captcha/captcha/captcha_point danielebarchiesi@2: $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point'); danielebarchiesi@2: $this->assertText(t('You are not authorized to access this page.'), danielebarchiesi@2: 'Non admin should not be able to set a CAPTCHA point'); danielebarchiesi@2: danielebarchiesi@2: // Try to set CAPTCHA point through admin/user/captcha/captcha/captcha_point/$form_id danielebarchiesi@2: $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/' . 'form_' . strtolower($this->randomName(32))); danielebarchiesi@2: $this->assertText(t('You are not authorized to access this page.'), danielebarchiesi@2: 'Non admin should not be able to set a CAPTCHA point'); danielebarchiesi@2: danielebarchiesi@2: // Try to disable the CAPTCHA point danielebarchiesi@2: $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/disable'); danielebarchiesi@2: $this->assertText(t('You are not authorized to access this page.'), danielebarchiesi@2: 'Non admin should not be able to disable a CAPTCHA point'); danielebarchiesi@2: danielebarchiesi@2: // Try to delete the CAPTCHA point danielebarchiesi@2: $this->drupalGet(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/delete'); danielebarchiesi@2: $this->assertText(t('You are not authorized to access this page.'), danielebarchiesi@2: 'Non admin should not be able to delete a CAPTCHA point'); danielebarchiesi@2: danielebarchiesi@2: // Switch from nonadmin to admin again danielebarchiesi@2: $this->drupalGet(url('logout', array('absolute' => TRUE))); danielebarchiesi@2: $this->drupalLogin($this->admin_user); danielebarchiesi@2: danielebarchiesi@2: // Check if original CAPTCHA point still exists in database danielebarchiesi@2: $result = $this->getCaptchaPointSettingFromDatabase($captcha_point_form_id); danielebarchiesi@2: $this->assertEqual($result->module, $captcha_point_module, danielebarchiesi@2: 'Enabled CAPTCHA point should still have module set'); danielebarchiesi@2: $this->assertEqual($result->captcha_type, $captcha_point_type, danielebarchiesi@2: 'Enabled CAPTCHA point should still have type set'); danielebarchiesi@2: danielebarchiesi@2: // Delete CAPTCHA point danielebarchiesi@2: $this->drupalPost(self::CAPTCHA_ADMIN_PATH . '/captcha/captcha_point/'. $captcha_point_form_id .'/delete', array(), t('Delete')); danielebarchiesi@2: $this->assertRaw(t('Deleted CAPTCHA for form %form_id.', array('%form_id' => $captcha_point_form_id)), danielebarchiesi@2: 'Deleting of CAPTCHA point'); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: class CaptchaPersistenceTestCase extends CaptchaBaseWebTestCase { danielebarchiesi@2: danielebarchiesi@2: public static function getInfo() { danielebarchiesi@2: return array( danielebarchiesi@2: 'name' => t('CAPTCHA persistence functionality'), danielebarchiesi@2: 'description' => t('Testing of the CAPTCHA persistence functionality.'), danielebarchiesi@2: 'group' => t('CAPTCHA'), danielebarchiesi@2: ); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Set up the persistence and CAPTCHA settings. danielebarchiesi@2: * @param int $persistence the persistence value. danielebarchiesi@2: */ danielebarchiesi@2: private function setUpPersistence($persistence) { danielebarchiesi@2: // Log in as admin danielebarchiesi@2: $this->drupalLogin($this->admin_user); danielebarchiesi@2: // Set persistence. danielebarchiesi@2: $edit = array('captcha_persistence' => $persistence); danielebarchiesi@2: $this->drupalPost(self::CAPTCHA_ADMIN_PATH, $edit, 'Save configuration'); danielebarchiesi@2: // Log admin out. danielebarchiesi@2: $this->drupalLogout(); danielebarchiesi@2: danielebarchiesi@2: // Set the Test123 CAPTCHA on user register and comment form. danielebarchiesi@2: // We have to do this with the function captcha_set_form_id_setting() danielebarchiesi@2: // (because the CATCHA admin form does not show the Test123 option). danielebarchiesi@2: // We also have to do this after all usage of the CAPTCHA admin form danielebarchiesi@2: // (because posting the CAPTCHA admin form would set the CAPTCHA to 'none'). danielebarchiesi@2: captcha_set_form_id_setting('user_login', 'captcha/Test'); danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: captcha_set_form_id_setting('user_register_form', 'captcha/Test'); danielebarchiesi@2: $this->drupalGet('user/register'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: protected function assertPreservedCsid($captcha_sid_initial) { danielebarchiesi@2: $captcha_sid = $this->getCaptchaSidFromForm(); danielebarchiesi@2: $this->assertEqual($captcha_sid_initial, $captcha_sid, danielebarchiesi@2: "CAPTCHA session ID should be preserved (expected: $captcha_sid_initial, found: $captcha_sid)."); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: protected function assertDifferentCsid($captcha_sid_initial) { danielebarchiesi@2: $captcha_sid = $this->getCaptchaSidFromForm(); danielebarchiesi@2: $this->assertNotEqual($captcha_sid_initial, $captcha_sid, danielebarchiesi@2: "CAPTCHA session ID should be different."); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: function testPersistenceAlways(){ danielebarchiesi@2: // Set up of persistence and CAPTCHAs. danielebarchiesi@2: $this->setUpPersistence(CAPTCHA_PERSISTENCE_SHOW_ALWAYS); danielebarchiesi@2: danielebarchiesi@2: // Go to login form and check if there is a CAPTCHA on the login form (look for the title). danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: $captcha_sid_initial = $this->getCaptchaSidFromForm(); danielebarchiesi@2: danielebarchiesi@2: // Try to with wrong user name and password, but correct CAPTCHA. danielebarchiesi@2: $edit = array( danielebarchiesi@2: 'name' => 'foobar', danielebarchiesi@2: 'pass' => 'bazlaz', danielebarchiesi@2: 'captcha_response' => 'Test 123', danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost(NULL, $edit, t('Log in')); danielebarchiesi@2: // Check that there was no error message for the CAPTCHA. danielebarchiesi@2: $this->assertCaptchaResponseAccepted(); danielebarchiesi@2: danielebarchiesi@2: // Name and password were wrong, we should get an updated form with a fresh CAPTCHA. danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: $this->assertPreservedCsid($captcha_sid_initial); danielebarchiesi@2: danielebarchiesi@2: // Post from again. danielebarchiesi@2: $this->drupalPost(NULL, $edit, t('Log in')); danielebarchiesi@2: // Check that there was no error message for the CAPTCHA. danielebarchiesi@2: $this->assertCaptchaResponseAccepted(); danielebarchiesi@2: $this->assertPreservedCsid($captcha_sid_initial); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: function testPersistencePerFormInstance(){ danielebarchiesi@2: // Set up of persistence and CAPTCHAs. danielebarchiesi@2: $this->setUpPersistence(CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE); danielebarchiesi@2: danielebarchiesi@2: // Go to login form and check if there is a CAPTCHA on the login form. danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: $captcha_sid_initial = $this->getCaptchaSidFromForm(); danielebarchiesi@2: danielebarchiesi@2: // Try to with wrong user name and password, but correct CAPTCHA. danielebarchiesi@2: $edit = array( danielebarchiesi@2: 'name' => 'foobar', danielebarchiesi@2: 'pass' => 'bazlaz', danielebarchiesi@2: 'captcha_response' => 'Test 123', danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost(NULL, $edit, t('Log in')); danielebarchiesi@2: // Check that there was no error message for the CAPTCHA. danielebarchiesi@2: $this->assertCaptchaResponseAccepted(); danielebarchiesi@2: // There shouldn't be a CAPTCHA on the new form. danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: $this->assertPreservedCsid($captcha_sid_initial); danielebarchiesi@2: danielebarchiesi@2: // Start a new form instance/session danielebarchiesi@2: $this->drupalGet('node'); danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: $this->assertDifferentCsid($captcha_sid_initial); danielebarchiesi@2: danielebarchiesi@2: // Check another form danielebarchiesi@2: $this->drupalGet('user/register'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: $this->assertDifferentCsid($captcha_sid_initial); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: function testPersistencePerFormType(){ danielebarchiesi@2: // Set up of persistence and CAPTCHAs. danielebarchiesi@2: $this->setUpPersistence(CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_TYPE); danielebarchiesi@2: danielebarchiesi@2: // Go to login form and check if there is a CAPTCHA on the login form. danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: $captcha_sid_initial = $this->getCaptchaSidFromForm(); danielebarchiesi@2: danielebarchiesi@2: // Try to with wrong user name and password, but correct CAPTCHA. danielebarchiesi@2: $edit = array( danielebarchiesi@2: 'name' => 'foobar', danielebarchiesi@2: 'pass' => 'bazlaz', danielebarchiesi@2: 'captcha_response' => 'Test 123', danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost(NULL, $edit, t('Log in')); danielebarchiesi@2: // Check that there was no error message for the CAPTCHA. danielebarchiesi@2: $this->assertCaptchaResponseAccepted(); danielebarchiesi@2: // There shouldn't be a CAPTCHA on the new form. danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: $this->assertPreservedCsid($captcha_sid_initial); danielebarchiesi@2: danielebarchiesi@2: // Start a new form instance/session danielebarchiesi@2: $this->drupalGet('node'); danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: $this->assertDifferentCsid($captcha_sid_initial); danielebarchiesi@2: danielebarchiesi@2: // Check another form danielebarchiesi@2: $this->drupalGet('user/register'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: $this->assertDifferentCsid($captcha_sid_initial); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: function testPersistenceOnlyOnce(){ danielebarchiesi@2: // Set up of persistence and CAPTCHAs. danielebarchiesi@2: $this->setUpPersistence(CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL); danielebarchiesi@2: danielebarchiesi@2: // Go to login form and check if there is a CAPTCHA on the login form. danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: $captcha_sid_initial = $this->getCaptchaSidFromForm(); danielebarchiesi@2: danielebarchiesi@2: // Try to with wrong user name and password, but correct CAPTCHA. danielebarchiesi@2: $edit = array( danielebarchiesi@2: 'name' => 'foobar', danielebarchiesi@2: 'pass' => 'bazlaz', danielebarchiesi@2: 'captcha_response' => 'Test 123', danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost(NULL, $edit, t('Log in')); danielebarchiesi@2: // Check that there was no error message for the CAPTCHA. danielebarchiesi@2: $this->assertCaptchaResponseAccepted(); danielebarchiesi@2: // There shouldn't be a CAPTCHA on the new form. danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: $this->assertPreservedCsid($captcha_sid_initial); danielebarchiesi@2: danielebarchiesi@2: // Start a new form instance/session danielebarchiesi@2: $this->drupalGet('node'); danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: $this->assertDifferentCsid($captcha_sid_initial); danielebarchiesi@2: danielebarchiesi@2: // Check another form danielebarchiesi@2: $this->drupalGet('user/register'); danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: $this->assertDifferentCsid($captcha_sid_initial); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: class CaptchaSessionReuseAttackTestCase extends CaptchaBaseWebTestCase { danielebarchiesi@2: danielebarchiesi@2: public static function getInfo() { danielebarchiesi@2: return array( danielebarchiesi@2: 'name' => t('CAPTCHA session reuse attack tests'), danielebarchiesi@2: 'description' => t('Testing of the protection against CAPTCHA session reuse attacks.'), danielebarchiesi@2: 'group' => t('CAPTCHA'), danielebarchiesi@2: ); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: /** danielebarchiesi@2: * Assert that the CAPTCHA session ID reuse attack was detected. danielebarchiesi@2: */ danielebarchiesi@2: protected function assertCaptchaSessionIdReuseAttackDetection() { danielebarchiesi@2: $this->assertText(t(CAPTCHA_SESSION_REUSE_ATTACK_ERROR_MESSAGE), danielebarchiesi@2: 'CAPTCHA session ID reuse attack should be detected.', danielebarchiesi@2: 'CAPTCHA'); danielebarchiesi@2: // There should be an error message about wrong response. danielebarchiesi@2: $this->assertText(t(CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE), danielebarchiesi@2: 'CAPTCHA response should flagged as wrong.', danielebarchiesi@2: 'CAPTCHA'); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: function testCaptchaSessionReuseAttackDetectionOnCommentPreview() { danielebarchiesi@2: // Create commentable node danielebarchiesi@2: $node = $this->createNodeWithCommentsEnabled(); danielebarchiesi@2: // Set Test CAPTCHA on comment form. danielebarchiesi@2: captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Math'); danielebarchiesi@2: variable_set('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE); danielebarchiesi@2: danielebarchiesi@2: // Log in as normal user. danielebarchiesi@2: $this->drupalLogin($this->normal_user); danielebarchiesi@2: danielebarchiesi@2: // Go to comment form of commentable node. danielebarchiesi@2: $this->drupalGet('comment/reply/' . $node->nid); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: danielebarchiesi@2: // Get CAPTCHA session ID and solution of the challenge. danielebarchiesi@2: $captcha_sid = $this->getCaptchaSidFromForm(); danielebarchiesi@2: $captcha_token = $this->getCaptchaTokenFromForm(); danielebarchiesi@2: $solution = $this->getMathCaptchaSolutionFromForm(); danielebarchiesi@2: danielebarchiesi@2: // Post the form with the solution. danielebarchiesi@2: $edit = $this->getCommentFormValues(); danielebarchiesi@2: $edit['captcha_response'] = $solution; danielebarchiesi@2: $this->drupalPost(NULL, $edit, t('Preview')); danielebarchiesi@2: // Answer should be accepted and further CAPTCHA ommitted. danielebarchiesi@2: $this->assertCaptchaResponseAccepted(); danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: danielebarchiesi@2: // Post a new comment, reusing the previous CAPTCHA session. danielebarchiesi@2: $edit = $this->getCommentFormValues(); danielebarchiesi@2: $edit['captcha_sid'] = $captcha_sid; danielebarchiesi@2: $edit['captcha_token'] = $captcha_token; danielebarchiesi@2: $edit['captcha_response'] = $solution; danielebarchiesi@2: $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview')); danielebarchiesi@2: // CAPTCHA session reuse attack should be detected. danielebarchiesi@2: $this->assertCaptchaSessionIdReuseAttackDetection(); danielebarchiesi@2: // There should be a CAPTCHA. danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: function testCaptchaSessionReuseAttackDetectionOnNodeForm() { danielebarchiesi@2: // Set CAPTCHA on page form. danielebarchiesi@2: captcha_set_form_id_setting('page_node_form', 'captcha/Math'); danielebarchiesi@2: variable_set('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE); danielebarchiesi@2: danielebarchiesi@2: // Log in as normal user. danielebarchiesi@2: $this->drupalLogin($this->normal_user); danielebarchiesi@2: danielebarchiesi@2: // Go to node add form. danielebarchiesi@2: $this->drupalGet('node/add/page'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: danielebarchiesi@2: // Get CAPTCHA session ID and solution of the challenge. danielebarchiesi@2: $captcha_sid = $this->getCaptchaSidFromForm(); danielebarchiesi@2: $captcha_token = $this->getCaptchaTokenFromForm(); danielebarchiesi@2: $solution = $this->getMathCaptchaSolutionFromForm(); danielebarchiesi@2: danielebarchiesi@2: // Page settings to post, with correct CAPTCHA answer. danielebarchiesi@2: $edit = $this->getNodeFormValues(); danielebarchiesi@2: $edit['captcha_response'] = $solution; danielebarchiesi@2: // Preview the node danielebarchiesi@2: $this->drupalPost(NULL, $edit, t('Preview')); danielebarchiesi@2: // Answer should be accepted. danielebarchiesi@2: $this->assertCaptchaResponseAccepted(); danielebarchiesi@2: // Check that there is no CAPTCHA after preview. danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: danielebarchiesi@2: // Post a new comment, reusing the previous CAPTCHA session. danielebarchiesi@2: $edit = $this->getNodeFormValues(); danielebarchiesi@2: $edit['captcha_sid'] = $captcha_sid; danielebarchiesi@2: $edit['captcha_token'] = $captcha_token; danielebarchiesi@2: $edit['captcha_response'] = $solution; danielebarchiesi@2: $this->drupalPost('node/add/page', $edit, t('Preview')); danielebarchiesi@2: // CAPTCHA session reuse attack should be detected. danielebarchiesi@2: $this->assertCaptchaSessionIdReuseAttackDetection(); danielebarchiesi@2: // There should be a CAPTCHA. danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: function testCaptchaSessionReuseAttackDetectionOnLoginForm() { danielebarchiesi@2: // Set CAPTCHA on login form. danielebarchiesi@2: captcha_set_form_id_setting('user_login', 'captcha/Math'); danielebarchiesi@2: variable_set('captcha_persistence', CAPTCHA_PERSISTENCE_SKIP_ONCE_SUCCESSFUL_PER_FORM_INSTANCE); danielebarchiesi@2: danielebarchiesi@2: // Go to log in form. danielebarchiesi@2: $this->drupalGet('user'); danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: danielebarchiesi@2: // Get CAPTCHA session ID and solution of the challenge. danielebarchiesi@2: $captcha_sid = $this->getCaptchaSidFromForm(); danielebarchiesi@2: $captcha_token = $this->getCaptchaTokenFromForm(); danielebarchiesi@2: $solution = $this->getMathCaptchaSolutionFromForm(); danielebarchiesi@2: danielebarchiesi@2: // Log in through form. danielebarchiesi@2: $edit = array( danielebarchiesi@2: 'name' => $this->normal_user->name, danielebarchiesi@2: 'pass' => $this->normal_user->pass_raw, danielebarchiesi@2: 'captcha_response' => $solution, danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost(NULL, $edit, t('Log in')); danielebarchiesi@2: $this->assertCaptchaResponseAccepted(); danielebarchiesi@2: $this->assertCaptchaPresence(FALSE); danielebarchiesi@2: // If a "log out" link appears on the page, it is almost certainly because danielebarchiesi@2: // the login was successful. danielebarchiesi@2: $pass = $this->assertLink(t('Log out'), 0, t('User %name successfully logged in.', array('%name' => $this->normal_user->name)), t('User login')); danielebarchiesi@2: danielebarchiesi@2: // Log out again. danielebarchiesi@2: $this->drupalLogout(); danielebarchiesi@2: danielebarchiesi@2: // Try to log in again, reusing the previous CAPTCHA session. danielebarchiesi@2: $edit += array( danielebarchiesi@2: 'captcha_sid' => $captcha_sid, danielebarchiesi@2: 'captcha_token' => $captcha_token, danielebarchiesi@2: ); danielebarchiesi@2: $this->drupalPost('user', $edit, t('Log in')); danielebarchiesi@2: // CAPTCHA session reuse attack should be detected. danielebarchiesi@2: $this->assertCaptchaSessionIdReuseAttackDetection(); danielebarchiesi@2: // There should be a CAPTCHA. danielebarchiesi@2: $this->assertCaptchaPresence(TRUE); danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: public function testMultipleCaptchaProtectedFormsOnOnePage() danielebarchiesi@2: { danielebarchiesi@2: // Set Test CAPTCHA on comment form and login block danielebarchiesi@2: captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test'); danielebarchiesi@2: captcha_set_form_id_setting('user_login_block', 'captcha/Math'); danielebarchiesi@2: $this->allowCommentPostingForAnonymousVisitors(); danielebarchiesi@2: danielebarchiesi@2: // Create a node with comments enabled. danielebarchiesi@2: $node = $this->createNodeWithCommentsEnabled(); danielebarchiesi@2: danielebarchiesi@2: // Preview comment with correct CAPTCHA answer. danielebarchiesi@2: $edit = $this->getCommentFormValues(); danielebarchiesi@2: $comment_subject = $edit['subject']; danielebarchiesi@2: $edit['captcha_response'] = 'Test 123'; danielebarchiesi@2: $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview')); danielebarchiesi@2: // Post should be accepted: no warnings, danielebarchiesi@2: // no CAPTCHA reuse detection (which could be used by user log in block). danielebarchiesi@2: $this->assertCaptchaResponseAccepted(); danielebarchiesi@2: $this->assertText($comment_subject); danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: } danielebarchiesi@2: danielebarchiesi@2: danielebarchiesi@2: // Some tricks to debug: danielebarchiesi@2: // drupal_debug($data) // from devel module danielebarchiesi@2: // file_put_contents('tmp.simpletest.html', $this->drupalGetContent());