diff --git a/shield.services.yml b/shield.services.yml index 8780ed0..e8cb6ac 100644 --- a/shield.services.yml +++ b/shield.services.yml @@ -1,7 +1,7 @@ services: shield.middleware: class: Drupal\shield\ShieldMiddleware - arguments: ['@config.factory'] + arguments: ['@config.factory', '@password', '@module_handler', '@entity.manager'] tags: # Ensure to come before page caching, so you don't serve cached pages to # banned users. diff --git a/src/ShieldMiddleware.php b/src/ShieldMiddleware.php index ae2f8da..0ade171 100644 --- a/src/ShieldMiddleware.php +++ b/src/ShieldMiddleware.php @@ -4,6 +4,9 @@ namespace Drupal\shield; use Drupal\Component\Utility\Crypt; use Drupal\Core\Config\ConfigFactoryInterface; +use Drupal\Core\Password\PasswordInterface; +use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\Extension\ModuleHandlerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -27,6 +30,27 @@ class ShieldMiddleware implements HttpKernelInterface { */ protected $configFactory; + /** + * The password hashing service. + * + * @var \Drupal\Core\Password\PasswordInterface + */ + protected $passwordChecker; + + /** + * The module handler. + * + * @var \Drupal\Core\Extension\ModuleHandlerInterface + */ + protected $moduleHandler; + + /** + * The user storage. + * + * @var \Drupal\user\UserStorageInterface + */ + protected $userStorage; + /** * Constructs a BanMiddleware object. * @@ -34,10 +58,25 @@ class ShieldMiddleware implements HttpKernelInterface { * The decorated kernel. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The configuration factory. + * @param \Drupal\Core\Password\PasswordInterface $password_checker + * The password service. + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + * The module handler. + * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager + * The entity manager. */ - public function __construct(HttpKernelInterface $http_kernel, ConfigFactoryInterface $config_factory) { + public function __construct( + HttpKernelInterface $http_kernel, + ConfigFactoryInterface $config_factory, + PasswordInterface $password_checker, + ModuleHandlerInterface $module_handler, + EntityManagerInterface $entity_manager + ) { $this->httpKernel = $http_kernel; $this->configFactory = $config_factory; + $this->passwordChecker = $password_checker; + $this->moduleHandler = $module_handler; + $this->userStorage = $entity_manager->getStorage('user'); } /** @@ -46,12 +85,14 @@ class ShieldMiddleware implements HttpKernelInterface { public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) { $config = $this->configFactory->get('shield.settings'); $allow_cli = $config->get('allow_cli'); + $basic_auth_enabled = $this->moduleHandler->moduleExists('basic_auth'); switch ($config->get('credential_provider')) { case 'shield': $user = $config->get('credentials.shield.user'); $pass = $config->get('credentials.shield.pass'); break; + case 'key': $user = $config->get('credentials.key.user'); @@ -63,6 +104,7 @@ class ShieldMiddleware implements HttpKernelInterface { $pass = $pass_key->getKeyValue(); } break; + case 'multikey': /** @var \Drupal\Core\Entity\EntityStorageInterface $storage */ $storage = \Drupal::entityTypeManager()->getStorage('key'); @@ -96,16 +138,34 @@ class ShieldMiddleware implements HttpKernelInterface { } if (isset($input_user) && $input_user === $user && Crypt::hashEquals($pass, $input_pass)) { + // Fix: allow access after the shield authentication, + // in the case is the core module basic_auth enabled. + if ($basic_auth_enabled) { + $request->headers->set('PHP_AUTH_PW', NULL); + $request->headers->set('PHP_AUTH_USER', NULL); + } return $this->httpKernel->handle($request, $type, $catch); } } + // Fix: allow rest api web service access, + // in the case is the core module basic_auth enabled. + if ($basic_auth_enabled && !empty($input_user) && strlen($input_pass) > 0) { + // Check exist account by username + $account_search = $this->userStorage->loadByProperties(['name' => $input_user]); + if ($account = reset($account_search)) { + if ($this->passwordChecker->check($input_pass, $account->getPassword())) { + return $this->httpKernel->handle($request, $type, $catch); + } + } + } + $response = new Response(); $response->headers->add([ 'WWW-Authenticate' => 'Basic realm="' . strtr($config->get('print'), [ - '[user]' => $user, - '[pass]' => $pass, - ]) . '"', + '[user]' => $user, + '[pass]' => $pass, + ]) . '"', ]); $response->setStatusCode(401); return $response;