CaptchaTest.php 8.83 KB
Newer Older
1
2
<?php

3
namespace Drupal\Tests\captcha\Functional;
4

5
/**
6
 * Tests CAPTCHA main test case sensitivity.
7
8
9
 *
 * @group captcha
 */
10
class CaptchaTest extends CaptchaWebTestBase {
11

12
13
14
15
16
  /**
   * Modules to enable.
   *
   * @var array
   */
17
  public static $modules = ['block', 'captcha_long_form_id_test'];
18

19
  /**
20
21
   * Testing the protection of the user log in form.
   */
22
  public function testCaptchaOnLoginForm() {
23
24
25
26
27
28
    // Create user and test log in without CAPTCHA.
    $user = $this->drupalCreateUser();
    $this->drupalLogin($user);
    // Log out again.
    $this->drupalLogout();

29
    // Set a CAPTCHA on login form.
30
    /* @var \Drupal\captcha\Entity\CaptchaPoint $captcha_point */
31
32
33
    $captcha_point = \Drupal::entityTypeManager()
      ->getStorage('captcha_point')
      ->load('user_login_form');
34
35
    $captcha_point->setCaptchaType('captcha/Math');
    $captcha_point->enable()->save();
36
37

    // Check if there is a CAPTCHA on the login form (look for the title).
38
    $this->drupalGet('user');
39
40
41
    $this->assertCaptchaPresence(TRUE);

    // Try to log in, which should fail.
42
    $edit = [
43
      'name' => $user->getDisplayName(),
44
45
      'pass' => $user->pass_raw,
      'captcha_response' => '?',
46
    ];
47
    $this->drupalPostForm(NULL, $edit, t('Log in'), [], self::LOGIN_HTML_FORM_ID);
48
    // Check for error message.
49
    $this->assertText(self::CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE, 'CAPTCHA should block user login form', 'CAPTCHA');
50

51
52
    // And make sure that user is not logged in:
    // check for name and password fields on ?q=user.
53
54
55
56
57
58
59
60
61
62
    $this->drupalGet('user');
    $this->assertField('name', t('Username field found.'), 'CAPTCHA');
    $this->assertField('pass', t('Password field found.'), 'CAPTCHA');
  }

  /**
   * Assert function for testing if comment posting works as it should.
   *
   * Creates node with comment writing enabled, tries to post comment
   * with given CAPTCHA response (caller should enable the desired
63
64
   * challenge on page node comment forms) and checks if
   * the result is as expected.
65
   *
66
67
68
69
70
71
   * @param string $captcha_response
   *   The response on the CAPTCHA.
   * @param bool $should_pass
   *   Describing if the posting should pass or should be blocked.
   * @param string $message
   *   To prefix to nested asserts.
72
73
   */
  protected function assertCommentPosting($captcha_response, $should_pass, $message) {
74
    // Make sure comments on pages can be saved directly without preview.
75
76
    $this->container->get('state')
      ->set('comment_preview_page', DRUPAL_OPTIONAL);
77
78

    // Create a node with comments enabled.
79
    $node = $this->drupalCreateNode();
80
81
82

    // Post comment on node.
    $edit = $this->getCommentFormValues();
tonnosf's avatar
tonnosf committed
83
    $comment_subject = $edit['subject[0][value]'];
84
    $comment_body = $edit['comment_body[0][value]'];
85
    $edit['captcha_response'] = $captcha_response;
86
    $this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit, t('Save'), [], 'comment-form');
87
88
89
90
91

    if ($should_pass) {
      // There should be no error message.
      $this->assertCaptchaResponseAccepted();
      // Get node page and check that comment shows up.
92
93
      $this->drupalGet('node/' . $node->id());
      $this->assertText($comment_subject, $message . ' Comment should show up on node page.', 'CAPTCHA');
94
95
96
97
      $this->assertText($comment_body, $message . ' Comment should show up on node page.', 'CAPTCHA');
    }
    else {
      // Check for error message.
98
      $this->assertText(self::CAPTCHA_WRONG_RESPONSE_ERROR_MESSAGE, $message . ' Comment submission should be blocked.', 'CAPTCHA');
99
      // Get node page and check that comment is not present.
100
101
      $this->drupalGet('node/' . $node->id());
      $this->assertNoText($comment_subject, $message . ' Comment should not show up on node page.', 'CAPTCHA');
102
103
104
105
      $this->assertNoText($comment_body, $message . ' Comment should not show up on node page.', 'CAPTCHA');
    }
  }

106
107
  /**
   * Testing the case sensitive/insensitive validation.
108
   */
109
  public function testCaseInsensitiveValidation() {
110
    $config = $this->config('captcha.settings');
111
    // Set Test CAPTCHA on comment form.
112
113
114
    captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test');

    // Log in as normal user.
115
    $this->drupalLogin($this->normalUser);
116
117

    // Test case sensitive posting.
tonnosf's avatar
tonnosf committed
118
    $config->set('default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_SENSITIVE);
119
120
    $config->save();

121
122
123
124
    $this->assertCommentPosting('Test 123', TRUE, 'Case sensitive validation of right casing.');
    $this->assertCommentPosting('test 123', FALSE, 'Case sensitive validation of wrong casing.');
    $this->assertCommentPosting('TEST 123', FALSE, 'Case sensitive validation of wrong casing.');

125
    // Test case insensitive posting (the default).
tonnosf's avatar
tonnosf committed
126
    $config->set('default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE);
127
128
    $config->save();

129
130
131
132
133
134
    $this->assertCommentPosting('Test 123', TRUE, 'Case insensitive validation of right casing.');
    $this->assertCommentPosting('test 123', TRUE, 'Case insensitive validation of wrong casing.');
    $this->assertCommentPosting('TEST 123', TRUE, 'Case insensitive validation of wrong casing.');
  }

  /**
135
136
   * Test if the CAPTCHA description is only shown with  challenge widgets.
   *
137
   * For example, when a comment is previewed with correct CAPTCHA answer,
138
139
   * a challenge is generated and added to the form but removed in the
   * pre_render phase. The CAPTCHA description should not show up either.
140
   *
141
   * @see testCaptchaSessionReuseOnNodeForms()
142
   */
143
  public function testCaptchaDescriptionAfterCommentPreview() {
144
145
146
147
    // Set Test CAPTCHA on comment form.
    captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test');

    // Log in as normal user.
148
    $this->drupalLogin($this->normalUser);
149
150

    // Create a node with comments enabled.
151
    $node = $this->drupalCreateNode();
152
153
154
155

    // Preview comment with correct CAPTCHA answer.
    $edit = $this->getCommentFormValues();
    $edit['captcha_response'] = 'Test 123';
156
    $this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit, t('Preview'));
157
158
159
160
161
162

    // Check that there is no CAPTCHA after preview.
    $this->assertCaptchaPresence(FALSE);
  }

  /**
163
164
165
166
167
   * Test if the CAPTCHA session ID is reused when previewing nodes.
   *
   * Node preview after correct response should not show CAPTCHA anymore.
   * The preview functionality of comments and nodes works
   * slightly different under the hood.
168
169
   * CAPTCHA module should be able to handle both.
   *
170
   * @see testCaptchaDescriptionAfterCommentPreview()
171
   */
172
  public function testCaptchaSessionReuseOnNodeForms() {
173
    // Set Test CAPTCHA on page form.
174
    captcha_set_form_id_setting('node_page_form', 'captcha/Test');
175
176

    // Log in as normal user.
177
    $this->drupalLogin($this->normalUser);
178
179
180
181

    // Page settings to post, with correct CAPTCHA answer.
    $edit = $this->getNodeFormValues();
    $edit['captcha_response'] = 'Test 123';
182
183
    $this->drupalGet('node/add/page');
    $this->drupalPostForm(NULL, $edit, t('Preview'));
184
185
186
187
188

    $this->assertCaptchaPresence(FALSE);
  }

  /**
189
   * CAPTCHA should be put on admin pages even if visitor has no access.
190
   */
191
192
  public function testCaptchaOnLoginBlockOnAdminPagesIssue893810() {
    // Set a CAPTCHA on login block form.
193
    /* @var \Drupal\captcha\Entity\CaptchaPoint $captcha_point */
194
195
196
    $captcha_point = \Drupal::entityTypeManager()
      ->getStorage('captcha_point')
      ->load('user_login_form');
197
198
    $captcha_point->setCaptchaType('captcha/Math');
    $captcha_point->enable()->save();
199

200
    // Enable the user login block.
201
    $this->drupalPlaceBlock('user_login_block', ['id' => 'login']);
202

203
    // Check if there is a CAPTCHA on home page.
tonnosf's avatar
tonnosf committed
204
    $this->drupalGet('');
205
    $this->assertCaptchaPresence(TRUE);
206
207
208
209

    // Check there is a CAPTCHA on "forbidden" admin pages.
    $this->drupalGet('admin');
    $this->assertCaptchaPresence(TRUE);
210
  }
Lukas Schneider's avatar
Lukas Schneider committed
211

212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
  /**
   * Test that forms with IDs exceeding 64 characters can be assigned captchas.
   */
  public function testLongFormId() {
    // We add the form manually so we can mimic the character
    // truncation of the label field as formId.
    $this->drupalLogin($this->adminUser);
    $this->drupalGet(self::CAPTCHA_ADMIN_PATH);

    $label = 'this_formid_is_intentionally_longer_than_64_characters_to_test_captcha';
    // Truncated to 64 chars so it can be a machine name.
    $formId = substr($label, 0, 64);

    $form_values = [
      'label' => $label,
      'formId' => $formId,
      'captchaType' => 'captcha/Math',
    ];

    // Create intentionally long id Captcha Point.
    $this->drupalPostForm(self::CAPTCHA_ADMIN_PATH . '/captcha-points/add', $form_values, t('Save'));
    $this->assertRaw(t('Captcha Point for %label form was created.', ['%label' => $formId]));

    // We need to log out to test the captcha.
    $this->drupalLogout();

    // Navigate to the form with a >64 char id and confirm there is Captcha.
    $this->drupalGet('captcha/test_form/long_id');
    $this->assertCaptchaPresence(TRUE);
  }

243
}