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

3
namespace Drupal\Tests\captcha\Functional;
4

5
use Drupal\Core\Entity\Entity\EntityFormDisplay;
6
7
8
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
9
use Drupal\Tests\captcha\Functional\CaptchaWebTestBase;
10

11
/**
12
 * Tests CAPTCHA main test case sensitivity.
13
14
15
 *
 * @group captcha
 */
16
class CaptchaTest extends CaptchaWebTestBase {
17

18
19
20
21
22
  /**
   * Modules to enable.
   *
   * @var array
   */
23
  public static $modules = ['block', 'captcha_long_form_id_test'];
24

25
  /**
26
27
   * Testing the protection of the user log in form.
   */
28
  public function testCaptchaOnLoginForm() {
29
30
31
32
33
34
    // Create user and test log in without CAPTCHA.
    $user = $this->drupalCreateUser();
    $this->drupalLogin($user);
    // Log out again.
    $this->drupalLogout();

35
    // Set a CAPTCHA on login form.
36
    /* @var \Drupal\captcha\Entity\CaptchaPoint $captcha_point */
37
38
39
    $captcha_point = \Drupal::entityTypeManager()
      ->getStorage('captcha_point')
      ->load('user_login_form');
40
41
    $captcha_point->setCaptchaType('captcha/Math');
    $captcha_point->enable()->save();
42
43

    // Check if there is a CAPTCHA on the login form (look for the title).
44
    $this->drupalGet('user');
45
46
47
    $this->assertCaptchaPresence(TRUE);

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

57
58
    // And make sure that user is not logged in:
    // check for name and password fields on ?q=user.
59
60
61
62
63
64
65
66
67
68
    $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
69
70
   * challenge on page node comment forms) and checks if
   * the result is as expected.
71
   *
72
73
74
75
76
77
   * @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.
78
79
   */
  protected function assertCommentPosting($captcha_response, $should_pass, $message) {
80
    // Make sure comments on pages can be saved directly without preview.
81
82
    $this->container->get('state')
      ->set('comment_preview_page', DRUPAL_OPTIONAL);
83
84

    // Create a node with comments enabled.
85
    $node = $this->drupalCreateNode();
86
87
88

    // Post comment on node.
    $edit = $this->getCommentFormValues();
tonnosf's avatar
tonnosf committed
89
    $comment_subject = $edit['subject[0][value]'];
90
    $comment_body = $edit['comment_body[0][value]'];
91
    $edit['captcha_response'] = $captcha_response;
92
    $this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit, t('Save'), [], 'comment-form');
93
94
95
96
97

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

112
113
  /**
   * Testing the case sensitive/insensitive validation.
114
   */
115
  public function testCaseInsensitiveValidation() {
116
    $config = $this->config('captcha.settings');
117
    // Set Test CAPTCHA on comment form.
118
119
120
    captcha_set_form_id_setting(self::COMMENT_FORM_ID, 'captcha/Test');

    // Log in as normal user.
121
    $this->drupalLogin($this->normalUser);
122
123

    // Test case sensitive posting.
tonnosf's avatar
tonnosf committed
124
    $config->set('default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_SENSITIVE);
125
126
    $config->save();

127
128
129
130
    $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.');

131
    // Test case insensitive posting (the default).
tonnosf's avatar
tonnosf committed
132
    $config->set('default_validation', CAPTCHA_DEFAULT_VALIDATION_CASE_INSENSITIVE);
133
134
    $config->save();

135
136
137
138
139
140
    $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.');
  }

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

    // Log in as normal user.
154
    $this->drupalLogin($this->normalUser);
155
156

    // Create a node with comments enabled.
157
    $node = $this->drupalCreateNode();
158
159
160
161

    // Preview comment with correct CAPTCHA answer.
    $edit = $this->getCommentFormValues();
    $edit['captcha_response'] = 'Test 123';
162
    $this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit, t('Preview'));
163
164
165
166
167
168

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

  /**
169
170
171
172
173
   * 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.
174
175
   * CAPTCHA module should be able to handle both.
   *
176
   * @see testCaptchaDescriptionAfterCommentPreview()
177
   */
178
  public function testCaptchaSessionReuseOnNodeForms() {
179
    // Set Test CAPTCHA on page form.
180
    captcha_set_form_id_setting('node_page_form', 'captcha/Test');
181
182

    // Log in as normal user.
183
    $this->drupalLogin($this->normalUser);
184
185
186
187

    // Page settings to post, with correct CAPTCHA answer.
    $edit = $this->getNodeFormValues();
    $edit['captcha_response'] = 'Test 123';
188
189
    $this->drupalGet('node/add/page');
    $this->drupalPostForm(NULL, $edit, t('Preview'));
190
191
192
193
194

    $this->assertCaptchaPresence(FALSE);
  }

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

206
    // Enable the user login block.
207
    $this->drupalPlaceBlock('user_login_block', ['id' => 'login']);
208

209
    // Check if there is a CAPTCHA on home page.
tonnosf's avatar
tonnosf committed
210
    $this->drupalGet('');
211
    $this->assertCaptchaPresence(TRUE);
212
213
214
215

    // Check there is a CAPTCHA on "forbidden" admin pages.
    $this->drupalGet('admin');
    $this->assertCaptchaPresence(TRUE);
216
  }
Lukas Schneider's avatar
Lukas Schneider committed
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
243
244
245
246
247
248
  /**
   * 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);
  }

249
}