updated core and modules
This commit is contained in:
@@ -4,9 +4,11 @@ description: 'Provides the HTTP Basic authentication provider'
|
||||
package: Web services
|
||||
# version: VERSION
|
||||
# core: 8.x
|
||||
dependencies:
|
||||
- user
|
||||
|
||||
# Information added by Drupal.org packaging script on 2016-08-03
|
||||
version: '8.1.8'
|
||||
# Information added by Drupal.org packaging script on 2017-08-16
|
||||
version: '8.3.7'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1470233792
|
||||
datestamp: 1502903957
|
||||
|
||||
@@ -15,7 +15,7 @@ function basic_auth_help($route_name, RouteMatchInterface $route_match) {
|
||||
case 'help.page.basic_auth':
|
||||
$output = '';
|
||||
$output .= '<h3>' . t('About') . '</h3>';
|
||||
$output .= '<p>' . t('The HTTP Basic Authentication module supplies an <a href="http://en.wikipedia.org/wiki/Basic_access_authentication">HTTP Basic authentication</a> provider for web service requests. This authentication provider authenticates requests using the HTTP Basic Authentication username and password, as an alternative to using Drupal\'s standard cookie-based authentication system. It is only useful if your site provides web services configured to use this type of authentication (for instance, the <a href=":rest_help">RESTful Web Services module</a>). For more information, see the <a href=":hba_do">online documentation for the HTTP Basic Authentication module</a>.', array(':hba_do' => 'https://www.drupal.org/documentation/modules/basic_auth', ':rest_help' => (\Drupal::moduleHandler()->moduleExists('rest')) ? \Drupal::url('help.page', array('name' => 'rest')) : '#')) . '</p>';
|
||||
$output .= '<p>' . t('The HTTP Basic Authentication module supplies an <a href="http://en.wikipedia.org/wiki/Basic_access_authentication">HTTP Basic authentication</a> provider for web service requests. This authentication provider authenticates requests using the HTTP Basic Authentication username and password, as an alternative to using Drupal\'s standard cookie-based authentication system. It is only useful if your site provides web services configured to use this type of authentication (for instance, the <a href=":rest_help">RESTful Web Services module</a>). For more information, see the <a href=":hba_do">online documentation for the HTTP Basic Authentication module</a>.', [':hba_do' => 'https://www.drupal.org/documentation/modules/basic_auth', ':rest_help' => (\Drupal::moduleHandler()->moduleExists('rest')) ? \Drupal::url('help.page', ['name' => 'rest']) : '#']) . '</p>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ class BasicAuth implements AuthenticationProviderInterface, AuthenticationProvid
|
||||
// in to many different user accounts. We have a reasonably high limit
|
||||
// since there may be only one apparent IP for all users at an institution.
|
||||
if ($this->flood->isAllowed('basic_auth.failed_login_ip', $flood_config->get('ip_limit'), $flood_config->get('ip_window'))) {
|
||||
$accounts = $this->entityManager->getStorage('user')->loadByProperties(array('name' => $username, 'status' => 1));
|
||||
$accounts = $this->entityManager->getStorage('user')->loadByProperties(['name' => $username, 'status' => 1]);
|
||||
$account = reset($accounts);
|
||||
if ($account) {
|
||||
if ($flood_config->get('uid_only')) {
|
||||
@@ -127,9 +127,9 @@ class BasicAuth implements AuthenticationProviderInterface, AuthenticationProvid
|
||||
*/
|
||||
public function challengeException(Request $request, \Exception $previous) {
|
||||
$site_name = $this->configFactory->get('system.site')->get('name');
|
||||
$challenge = SafeMarkup::format('Basic realm="@realm"', array(
|
||||
$challenge = SafeMarkup::format('Basic realm="@realm"', [
|
||||
'@realm' => !empty($site_name) ? $site_name : 'Access restricted',
|
||||
));
|
||||
]);
|
||||
return new UnauthorizedHttpException((string) $challenge, 'No authentication credentials provided.', $previous);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,15 @@
|
||||
|
||||
namespace Drupal\basic_auth\Tests;
|
||||
|
||||
@trigger_error(__FILE__ . ' is deprecated in Drupal 8.3.0 and will be removed before Drupal 9.0.0. Use \Drupal\Tests\basic_auth\Traits\BasicAuthTestTrait instead. See https://www.drupal.org/node/2862800.', E_USER_DEPRECATED);
|
||||
|
||||
/**
|
||||
* Provides common functionality for Basic Authentication test classes.
|
||||
*
|
||||
* @deprecated in Drupal 8.3.0 and will be removed before Drupal 9.0.0.
|
||||
* Use \Drupal\Tests\basic_auth\Traits\BasicAuthTestTrait instead.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2862800
|
||||
*/
|
||||
trait BasicAuthTestTrait {
|
||||
|
||||
@@ -51,7 +58,7 @@ trait BasicAuthTestTrait {
|
||||
*
|
||||
* @see \Drupal\simpletest\WebTestBase::drupalPostForm()
|
||||
*/
|
||||
protected function basicAuthPostForm($path, $edit, $submit, $username, $password, array $options = array(), $form_html_id = NULL, $extra_post = NULL) {
|
||||
protected function basicAuthPostForm($path, $edit, $submit, $username, $password, array $options = [], $form_html_id = NULL, $extra_post = NULL) {
|
||||
return $this->drupalPostForm($path, $edit, $submit, $options, $this->getBasicAuthHeaders($username, $password), $form_html_id, $extra_post);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
name: 'HTTP Basic Authentication test'
|
||||
type: module
|
||||
description: 'Support module for HTTP Basic Authentication testing.'
|
||||
package: Testing
|
||||
# version: VERSION
|
||||
# core: 8.x
|
||||
|
||||
# Information added by Drupal.org packaging script on 2017-08-16
|
||||
version: '8.3.7'
|
||||
core: '8.x'
|
||||
project: 'drupal'
|
||||
datestamp: 1502903957
|
||||
@@ -0,0 +1,16 @@
|
||||
basic_auth_test.state.modify:
|
||||
path: '/basic_auth_test/state/modify'
|
||||
defaults:
|
||||
_controller: '\Drupal\basic_auth_test\BasicAuthTestController::modifyState'
|
||||
options:
|
||||
_auth:
|
||||
- basic_auth
|
||||
requirements:
|
||||
_user_is_logged_in: 'TRUE'
|
||||
|
||||
basic_auth_test.state.read:
|
||||
path: '/basic_auth_test/state/read'
|
||||
defaults:
|
||||
_controller: '\Drupal\basic_auth_test\BasicAuthTestController::readState'
|
||||
requirements:
|
||||
_access: 'TRUE'
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\basic_auth_test;
|
||||
|
||||
class BasicAuthTestController {
|
||||
|
||||
/**
|
||||
* @see \Drupal\basic_auth\Tests\Authentication\BasicAuthTest::testControllerNotCalledBeforeAuth()
|
||||
*/
|
||||
public function modifyState() {
|
||||
\Drupal::state()->set('basic_auth_test.state.controller_executed', TRUE);
|
||||
return ['#markup' => 'Done'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Drupal\basic_auth\Tests\Authentication\BasicAuthTest::testControllerNotCalledBeforeAuth()
|
||||
*/
|
||||
public function readState() {
|
||||
// Mark this page as being uncacheable.
|
||||
\Drupal::service('page_cache_kill_switch')->trigger();
|
||||
|
||||
return [
|
||||
'#markup' => \Drupal::state()->get('basic_auth_test.state.controller_executed') ? 'yep' : 'nope',
|
||||
'#cache' => [
|
||||
'max-age' => 0,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\basic_auth\Functional;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\basic_auth\Traits\BasicAuthTestTrait;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
|
||||
/**
|
||||
* Tests for BasicAuth authentication provider.
|
||||
*
|
||||
* @group basic_auth
|
||||
*/
|
||||
class BasicAuthTest extends BrowserTestBase {
|
||||
|
||||
use BasicAuthTestTrait;
|
||||
|
||||
/**
|
||||
* Modules installed for all tests.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = ['basic_auth', 'router_test', 'locale', 'basic_auth_test'];
|
||||
|
||||
/**
|
||||
* Test http basic authentication.
|
||||
*/
|
||||
public function testBasicAuth() {
|
||||
// Enable page caching.
|
||||
$config = $this->config('system.performance');
|
||||
$config->set('cache.page.max_age', 300);
|
||||
$config->save();
|
||||
|
||||
$account = $this->drupalCreateUser();
|
||||
$url = Url::fromRoute('router_test.11');
|
||||
|
||||
$this->basicAuthGet($url, $account->getUsername(), $account->pass_raw);
|
||||
$this->assertText($account->getUsername(), 'Account name is displayed.');
|
||||
$this->assertResponse('200', 'HTTP response is OK');
|
||||
$this->mink->resetSessions();
|
||||
$this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'));
|
||||
$this->assertIdentical(strpos($this->drupalGetHeader('Cache-Control'), 'public'), FALSE, 'Cache-Control is not set to public');
|
||||
|
||||
$this->basicAuthGet($url, $account->getUsername(), $this->randomMachineName());
|
||||
$this->assertNoText($account->getUsername(), 'Bad basic auth credentials do not authenticate the user.');
|
||||
$this->assertResponse('403', 'Access is not granted.');
|
||||
$this->mink->resetSessions();
|
||||
|
||||
$this->drupalGet($url);
|
||||
$this->assertEqual($this->drupalGetHeader('WWW-Authenticate'), SafeMarkup::format('Basic realm="@realm"', ['@realm' => \Drupal::config('system.site')->get('name')]));
|
||||
$this->assertResponse('401', 'Not authenticated on the route that allows only basic_auth. Prompt to authenticate received.');
|
||||
|
||||
$this->drupalGet('admin');
|
||||
$this->assertResponse('403', 'No authentication prompt for routes not explicitly defining authentication providers.');
|
||||
|
||||
$account = $this->drupalCreateUser(['access administration pages']);
|
||||
|
||||
$this->basicAuthGet(Url::fromRoute('system.admin'), $account->getUsername(), $account->pass_raw);
|
||||
$this->assertNoLink('Log out', 'User is not logged in');
|
||||
$this->assertResponse('403', 'No basic authentication for routes not explicitly defining authentication providers.');
|
||||
$this->mink->resetSessions();
|
||||
|
||||
// Ensure that pages already in the page cache aren't returned from page
|
||||
// cache if basic auth credentials are provided.
|
||||
$url = Url::fromRoute('router_test.10');
|
||||
$this->drupalGet($url);
|
||||
$this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'MISS');
|
||||
$this->basicAuthGet($url, $account->getUsername(), $account->pass_raw);
|
||||
$this->assertFalse($this->drupalGetHeader('X-Drupal-Cache'));
|
||||
$this->assertIdentical(strpos($this->drupalGetHeader('Cache-Control'), 'public'), FALSE, 'No page cache response when requesting a cached page with basic auth credentials.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the global login flood control.
|
||||
*/
|
||||
public function testGlobalLoginFloodControl() {
|
||||
$this->config('user.flood')
|
||||
->set('ip_limit', 2)
|
||||
// Set a high per-user limit out so that it is not relevant in the test.
|
||||
->set('user_limit', 4000)
|
||||
->save();
|
||||
|
||||
$user = $this->drupalCreateUser([]);
|
||||
$incorrect_user = clone $user;
|
||||
$incorrect_user->pass_raw .= 'incorrect';
|
||||
$url = Url::fromRoute('router_test.11');
|
||||
|
||||
// Try 2 failed logins.
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$this->basicAuthGet($url, $incorrect_user->getUsername(), $incorrect_user->pass_raw);
|
||||
}
|
||||
|
||||
// IP limit has reached to its limit. Even valid user credentials will fail.
|
||||
$this->basicAuthGet($url, $user->getUsername(), $user->pass_raw);
|
||||
$this->assertResponse('403', 'Access is blocked because of IP based flood prevention.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the per-user login flood control.
|
||||
*/
|
||||
public function testPerUserLoginFloodControl() {
|
||||
$this->config('user.flood')
|
||||
// Set a high global limit out so that it is not relevant in the test.
|
||||
->set('ip_limit', 4000)
|
||||
->set('user_limit', 2)
|
||||
->save();
|
||||
|
||||
$user = $this->drupalCreateUser([]);
|
||||
$incorrect_user = clone $user;
|
||||
$incorrect_user->pass_raw .= 'incorrect';
|
||||
$user2 = $this->drupalCreateUser([]);
|
||||
$url = Url::fromRoute('router_test.11');
|
||||
|
||||
// Try a failed login.
|
||||
$this->basicAuthGet($url, $incorrect_user->getUsername(), $incorrect_user->pass_raw);
|
||||
|
||||
// A successful login will reset the per-user flood control count.
|
||||
$this->basicAuthGet($url, $user->getUsername(), $user->pass_raw);
|
||||
$this->assertResponse('200', 'Per user flood prevention gets reset on a successful login.');
|
||||
|
||||
// Try 2 failed logins for a user. They will trigger flood control.
|
||||
for ($i = 0; $i < 2; $i++) {
|
||||
$this->basicAuthGet($url, $incorrect_user->getUsername(), $incorrect_user->pass_raw);
|
||||
}
|
||||
|
||||
// Now the user account is blocked.
|
||||
$this->basicAuthGet($url, $user->getUsername(), $user->pass_raw);
|
||||
$this->assertResponse('403', 'The user account is blocked due to per user flood prevention.');
|
||||
|
||||
// Try one successful attempt for a different user, it should not trigger
|
||||
// any flood control.
|
||||
$this->basicAuthGet($url, $user2->getUsername(), $user2->pass_raw);
|
||||
$this->assertResponse('200', 'Per user flood prevention does not block access for other users.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests compatibility with locale/UI translation.
|
||||
*/
|
||||
public function testLocale() {
|
||||
ConfigurableLanguage::createFromLangcode('de')->save();
|
||||
$this->config('system.site')->set('default_langcode', 'de')->save();
|
||||
|
||||
$account = $this->drupalCreateUser();
|
||||
$url = Url::fromRoute('router_test.11');
|
||||
|
||||
$this->basicAuthGet($url, $account->getUsername(), $account->pass_raw);
|
||||
$this->assertText($account->getUsername(), 'Account name is displayed.');
|
||||
$this->assertResponse('200', 'HTTP response is OK');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a comprehensive message is displayed when the route is denied.
|
||||
*/
|
||||
public function testUnauthorizedErrorMessage() {
|
||||
$account = $this->drupalCreateUser();
|
||||
$url = Url::fromRoute('router_test.11');
|
||||
|
||||
// Case when no credentials are passed.
|
||||
$this->drupalGet($url);
|
||||
$this->assertResponse('401', 'The user is blocked when no credentials are passed.');
|
||||
$this->assertNoText('Exception', "No raw exception is displayed on the page.");
|
||||
$this->assertText('Please log in to access this page.', "A user friendly access unauthorized message is displayed.");
|
||||
|
||||
// Case when empty credentials are passed.
|
||||
$this->basicAuthGet($url, NULL, NULL);
|
||||
$this->assertResponse('403', 'The user is blocked when empty credentials are passed.');
|
||||
$this->assertText('Access denied', "A user friendly access denied message is displayed");
|
||||
|
||||
// Case when wrong credentials are passed.
|
||||
$this->basicAuthGet($url, $account->getUsername(), $this->randomMachineName());
|
||||
$this->assertResponse('403', 'The user is blocked when wrong credentials are passed.');
|
||||
$this->assertText('Access denied', "A user friendly access denied message is displayed");
|
||||
|
||||
// Case when correct credentials but hasn't access to the route.
|
||||
$url = Url::fromRoute('router_test.15');
|
||||
$this->basicAuthGet($url, $account->getUsername(), $account->pass_raw);
|
||||
$this->assertResponse('403', 'The used authentication method is not allowed on this route.');
|
||||
$this->assertText('Access denied', "A user friendly access denied message is displayed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the controller is called before authentication.
|
||||
*
|
||||
* @see https://www.drupal.org/node/2817727
|
||||
*/
|
||||
public function testControllerNotCalledBeforeAuth() {
|
||||
$this->drupalGet('/basic_auth_test/state/modify');
|
||||
$this->assertResponse(401);
|
||||
$this->drupalGet('/basic_auth_test/state/read');
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('nope');
|
||||
|
||||
$account = $this->drupalCreateUser();
|
||||
$this->basicAuthGet('/basic_auth_test/state/modify', $account->getUsername(), $account->pass_raw);
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('Done');
|
||||
|
||||
$this->mink->resetSessions();
|
||||
$this->drupalGet('/basic_auth_test/state/read');
|
||||
$this->assertResponse(200);
|
||||
$this->assertRaw('yep');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Drupal\Tests\basic_auth\Traits;
|
||||
|
||||
/**
|
||||
* Provides common functionality for Basic Authentication test classes.
|
||||
*/
|
||||
trait BasicAuthTestTrait {
|
||||
|
||||
/**
|
||||
* Retrieves a Drupal path or an absolute path using basic authentication.
|
||||
*
|
||||
* @param \Drupal\Core\Url|string $path
|
||||
* Drupal path or URL to load into the internal browser.
|
||||
* @param string $username
|
||||
* The username to use for basic authentication.
|
||||
* @param string $password
|
||||
* The password to use for basic authentication.
|
||||
* @param array $options
|
||||
* (optional) Options to be forwarded to the url generator.
|
||||
*
|
||||
* @return string
|
||||
* The retrieved HTML string, also available as $this->getRawContent().
|
||||
*/
|
||||
protected function basicAuthGet($path, $username, $password, array $options = []) {
|
||||
return $this->drupalGet($path, $options, $this->getBasicAuthHeaders($username, $password));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a form submission using basic authentication.
|
||||
*
|
||||
* @param string $path
|
||||
* Location of the post form.
|
||||
* @param array $edit
|
||||
* Field data in an associative array.
|
||||
* @param string $submit
|
||||
* Value of the submit button whose click is to be emulated.
|
||||
* @param string $username
|
||||
* The username to use for basic authentication.
|
||||
* @param string $password
|
||||
* The password to use for basic authentication.
|
||||
* @param array $options
|
||||
* Options to be forwarded to the url generator.
|
||||
* @param string $form_html_id
|
||||
* (optional) HTML ID of the form to be submitted.
|
||||
* @param string $extra_post
|
||||
* (optional) A string of additional data to append to the POST submission.
|
||||
*
|
||||
* @return string
|
||||
* The retrieved HTML string.
|
||||
*
|
||||
* @see \Drupal\simpletest\WebTestBase::drupalPostForm()
|
||||
*/
|
||||
protected function basicAuthPostForm($path, $edit, $submit, $username, $password, array $options = [], $form_html_id = NULL, $extra_post = NULL) {
|
||||
return $this->drupalPostForm($path, $edit, $submit, $options, $this->getBasicAuthHeaders($username, $password), $form_html_id, $extra_post);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTTP headers that can be used for basic authentication in Curl.
|
||||
*
|
||||
* @param string $username
|
||||
* The username to use for basic authentication.
|
||||
* @param string $password
|
||||
* The password to use for basic authentication.
|
||||
*
|
||||
* @return array
|
||||
* An array of raw request headers as used by curl_setopt().
|
||||
*/
|
||||
protected function getBasicAuthHeaders($username, $password) {
|
||||
// Set up Curl to use basic authentication with the test user's credentials.
|
||||
return ['Authorization' => 'Basic ' . base64_encode("$username:$password")];
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user