b197a7631a190f5c1ccdb57b61dc5e35ac5778cb
[yaffs-website] / src / Functional / BasicAuthTest.php
1 <?php
2
3 namespace Drupal\Tests\basic_auth\Functional;
4
5 use Drupal\Component\Utility\SafeMarkup;
6 use Drupal\Core\Url;
7 use Drupal\Tests\basic_auth\Traits\BasicAuthTestTrait;
8 use Drupal\language\Entity\ConfigurableLanguage;
9 use Drupal\Tests\BrowserTestBase;
10
11 /**
12  * Tests for BasicAuth authentication provider.
13  *
14  * @group basic_auth
15  */
16 class BasicAuthTest extends BrowserTestBase {
17
18   use BasicAuthTestTrait;
19
20   /**
21    * Modules installed for all tests.
22    *
23    * @var array
24    */
25   public static $modules = ['basic_auth', 'router_test', 'locale', 'basic_auth_test'];
26
27   /**
28    * Test http basic authentication.
29    */
30   public function testBasicAuth() {
31     // Enable page caching.
32     $config = $this->config('system.performance');
33     $config->set('cache.page.max_age', 300);
34     $config->save();
35
36     $account = $this->drupalCreateUser();
37     $url = Url::fromRoute('router_test.11');
38
39     $this->basicAuthGet($url, $account->getUsername(), $account->pass_raw);
40     $this->assertText($account->getUsername(), 'Account name is displayed.');
41     $this->assertResponse('200', 'HTTP response is OK');
42     $this->mink->resetSessions();
43     $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'));
44     $this->assertIdentical(strpos($this->drupalGetHeader('Cache-Control'), 'public'), FALSE, 'Cache-Control is not set to public');
45
46     $this->basicAuthGet($url, $account->getUsername(), $this->randomMachineName());
47     $this->assertNoText($account->getUsername(), 'Bad basic auth credentials do not authenticate the user.');
48     $this->assertResponse('403', 'Access is not granted.');
49     $this->mink->resetSessions();
50
51     $this->drupalGet($url);
52     $this->assertEqual($this->drupalGetHeader('WWW-Authenticate'), SafeMarkup::format('Basic realm="@realm"', ['@realm' => \Drupal::config('system.site')->get('name')]));
53     $this->assertResponse('401', 'Not authenticated on the route that allows only basic_auth. Prompt to authenticate received.');
54
55     $this->drupalGet('admin');
56     $this->assertResponse('403', 'No authentication prompt for routes not explicitly defining authentication providers.');
57
58     $account = $this->drupalCreateUser(['access administration pages']);
59
60     $this->basicAuthGet(Url::fromRoute('system.admin'), $account->getUsername(), $account->pass_raw);
61     $this->assertNoLink('Log out', 'User is not logged in');
62     $this->assertResponse('403', 'No basic authentication for routes not explicitly defining authentication providers.');
63     $this->mink->resetSessions();
64
65     // Ensure that pages already in the page cache aren't returned from page
66     // cache if basic auth credentials are provided.
67     $url = Url::fromRoute('router_test.10');
68     $this->drupalGet($url);
69     $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
70     $this->basicAuthGet($url, $account->getUsername(), $account->pass_raw);
71     $this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'));
72     $this->assertIdentical(strpos($this->drupalGetHeader('Cache-Control'), 'public'), FALSE, 'No page cache response when requesting a cached page with basic auth credentials.');
73   }
74
75   /**
76    * Test the global login flood control.
77    */
78   public function testGlobalLoginFloodControl() {
79     $this->config('user.flood')
80       ->set('ip_limit', 2)
81       // Set a high per-user limit out so that it is not relevant in the test.
82       ->set('user_limit', 4000)
83       ->save();
84
85     $user = $this->drupalCreateUser([]);
86     $incorrect_user = clone $user;
87     $incorrect_user->pass_raw .= 'incorrect';
88     $url = Url::fromRoute('router_test.11');
89
90     // Try 2 failed logins.
91     for ($i = 0; $i < 2; $i++) {
92       $this->basicAuthGet($url, $incorrect_user->getUsername(), $incorrect_user->pass_raw);
93     }
94
95     // IP limit has reached to its limit. Even valid user credentials will fail.
96     $this->basicAuthGet($url, $user->getUsername(), $user->pass_raw);
97     $this->assertResponse('403', 'Access is blocked because of IP based flood prevention.');
98   }
99
100   /**
101    * Test the per-user login flood control.
102    */
103   public function testPerUserLoginFloodControl() {
104     $this->config('user.flood')
105       // Set a high global limit out so that it is not relevant in the test.
106       ->set('ip_limit', 4000)
107       ->set('user_limit', 2)
108       ->save();
109
110     $user = $this->drupalCreateUser([]);
111     $incorrect_user = clone $user;
112     $incorrect_user->pass_raw .= 'incorrect';
113     $user2 = $this->drupalCreateUser([]);
114     $url = Url::fromRoute('router_test.11');
115
116     // Try a failed login.
117     $this->basicAuthGet($url, $incorrect_user->getUsername(), $incorrect_user->pass_raw);
118
119     // A successful login will reset the per-user flood control count.
120     $this->basicAuthGet($url, $user->getUsername(), $user->pass_raw);
121     $this->assertResponse('200', 'Per user flood prevention gets reset on a successful login.');
122
123     // Try 2 failed logins for a user. They will trigger flood control.
124     for ($i = 0; $i < 2; $i++) {
125       $this->basicAuthGet($url, $incorrect_user->getUsername(), $incorrect_user->pass_raw);
126     }
127
128     // Now the user account is blocked.
129     $this->basicAuthGet($url, $user->getUsername(), $user->pass_raw);
130     $this->assertResponse('403', 'The user account is blocked due to per user flood prevention.');
131
132     // Try one successful attempt for a different user, it should not trigger
133     // any flood control.
134     $this->basicAuthGet($url, $user2->getUsername(), $user2->pass_raw);
135     $this->assertResponse('200', 'Per user flood prevention does not block access for other users.');
136   }
137
138   /**
139    * Tests compatibility with locale/UI translation.
140    */
141   public function testLocale() {
142     ConfigurableLanguage::createFromLangcode('de')->save();
143     $this->config('system.site')->set('default_langcode', 'de')->save();
144
145     $account = $this->drupalCreateUser();
146     $url = Url::fromRoute('router_test.11');
147
148     $this->basicAuthGet($url, $account->getUsername(), $account->pass_raw);
149     $this->assertText($account->getUsername(), 'Account name is displayed.');
150     $this->assertResponse('200', 'HTTP response is OK');
151   }
152
153   /**
154    * Tests if a comprehensive message is displayed when the route is denied.
155    */
156   public function testUnauthorizedErrorMessage() {
157     $account = $this->drupalCreateUser();
158     $url = Url::fromRoute('router_test.11');
159
160     // Case when no credentials are passed.
161     $this->drupalGet($url);
162     $this->assertResponse('401', 'The user is blocked when no credentials are passed.');
163     $this->assertNoText('Exception', "No raw exception is displayed on the page.");
164     $this->assertText('Please log in to access this page.', "A user friendly access unauthorized message is displayed.");
165
166     // Case when empty credentials are passed.
167     $this->basicAuthGet($url, NULL, NULL);
168     $this->assertResponse('403', 'The user is blocked when empty credentials are passed.');
169     $this->assertText('Access denied', "A user friendly access denied message is displayed");
170
171     // Case when wrong credentials are passed.
172     $this->basicAuthGet($url, $account->getUsername(), $this->randomMachineName());
173     $this->assertResponse('403', 'The user is blocked when wrong credentials are passed.');
174     $this->assertText('Access denied', "A user friendly access denied message is displayed");
175
176     // Case when correct credentials but hasn't access to the route.
177     $url = Url::fromRoute('router_test.15');
178     $this->basicAuthGet($url, $account->getUsername(), $account->pass_raw);
179     $this->assertResponse('403', 'The used authentication method is not allowed on this route.');
180     $this->assertText('Access denied', "A user friendly access denied message is displayed");
181   }
182
183   /**
184    * Tests if the controller is called before authentication.
185    *
186    * @see https://www.drupal.org/node/2817727
187    */
188   public function testControllerNotCalledBeforeAuth() {
189     $this->drupalGet('/basic_auth_test/state/modify');
190     $this->assertResponse(401);
191     $this->drupalGet('/basic_auth_test/state/read');
192     $this->assertResponse(200);
193     $this->assertRaw('nope');
194
195     $account = $this->drupalCreateUser();
196     $this->basicAuthGet('/basic_auth_test/state/modify', $account->getUsername(), $account->pass_raw);
197     $this->assertResponse(200);
198     $this->assertRaw('Done');
199
200     $this->mink->resetSessions();
201     $this->drupalGet('/basic_auth_test/state/read');
202     $this->assertResponse(200);
203     $this->assertRaw('yep');
204   }
205
206 }