mirror of
https://github.com/phpbb/phpbb.git
synced 2025-10-11 23:14:34 +02:00
[ticket/15085] Add HTTP authentication subscriber for feed controllers
PHPBB-15085
This commit is contained in:
@@ -15,6 +15,16 @@ services:
|
||||
- '@language'
|
||||
- '%core.php_ext%'
|
||||
|
||||
feed.http_auth_subscriber:
|
||||
class: phpbb\feed\event\http_auth_subscriber
|
||||
arguments:
|
||||
- '@auth'
|
||||
- '@config'
|
||||
- '@request'
|
||||
- '@user'
|
||||
tags:
|
||||
- { name: kernel.event_subscriber }
|
||||
|
||||
feed.helper:
|
||||
class: phpbb\feed\helper
|
||||
arguments:
|
||||
|
242
phpBB/phpbb/feed/event/http_auth_subscriber.php
Normal file
242
phpBB/phpbb/feed/event/http_auth_subscriber.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace phpbb\feed\event;
|
||||
|
||||
use phpbb\auth\auth;
|
||||
use phpbb\config\config;
|
||||
use phpbb\request\request_interface;
|
||||
use phpbb\user;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Event subscriber for HTTP authentication on feed routes
|
||||
*/
|
||||
class http_auth_subscriber implements EventSubscriberInterface
|
||||
{
|
||||
/** @var auth */
|
||||
protected $auth;
|
||||
|
||||
/** @var config */
|
||||
protected $config;
|
||||
|
||||
/** @var request_interface */
|
||||
protected $request;
|
||||
|
||||
/** @var user */
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param auth $auth Auth object
|
||||
* @param config $config Config object
|
||||
* @param request_interface $request Request object
|
||||
* @param user $user User object
|
||||
*/
|
||||
public function __construct(auth $auth, config $config, request_interface $request, user $user)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
$this->config = $config;
|
||||
$this->request = $request;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle HTTP authentication for feed routes
|
||||
*
|
||||
* @param GetResponseEvent $event
|
||||
* @return void
|
||||
*/
|
||||
public function on_kernel_request(GetResponseEvent $event)
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
$route = $request->attributes->get('_route');
|
||||
|
||||
// Only apply to feed routes
|
||||
if (strpos($route, 'phpbb_feed_') !== 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if HTTP authentication is enabled
|
||||
if (!$this->config['feed_http_auth'])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// User is already logged in, no need to authenticate
|
||||
if (!empty($this->user->data['is_registered']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get HTTP authentication credentials
|
||||
$username = $this->get_http_username();
|
||||
$password = $this->get_http_password();
|
||||
|
||||
// If no credentials provided, send authentication challenge
|
||||
if ($username === null || $password === null)
|
||||
{
|
||||
$this->send_auth_challenge($event);
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to login with the provided credentials
|
||||
$auth_result = $this->auth->login($username, $password, false, true, false);
|
||||
|
||||
if ($auth_result['status'] == LOGIN_SUCCESS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if ($auth_result['status'] == LOGIN_ERROR_ATTEMPTS)
|
||||
{
|
||||
// Too many login attempts
|
||||
$response = new Response('', Response::HTTP_UNAUTHORIZED);
|
||||
$event->setResponse($response);
|
||||
return;
|
||||
}
|
||||
|
||||
// Authentication failed, send challenge
|
||||
$this->send_auth_challenge($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTTP username from request headers
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function get_http_username()
|
||||
{
|
||||
$username_keys = array(
|
||||
'PHP_AUTH_USER',
|
||||
'Authorization',
|
||||
'REMOTE_USER',
|
||||
'REDIRECT_REMOTE_USER',
|
||||
'HTTP_AUTHORIZATION',
|
||||
'REDIRECT_HTTP_AUTHORIZATION',
|
||||
'REMOTE_AUTHORIZATION',
|
||||
'REDIRECT_REMOTE_AUTHORIZATION',
|
||||
'AUTH_USER',
|
||||
);
|
||||
|
||||
foreach ($username_keys as $key)
|
||||
{
|
||||
if ($this->request->is_set($key, request_interface::SERVER))
|
||||
{
|
||||
$username = html_entity_decode($this->request->server($key), ENT_COMPAT);
|
||||
|
||||
// Decode Basic authentication header
|
||||
if (strpos($username, 'Basic ') === 0)
|
||||
{
|
||||
$credentials = base64_decode(substr($username, 6));
|
||||
if (strpos($credentials, ':') !== false)
|
||||
{
|
||||
list($username, ) = explode(':', $credentials, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return $username;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTTP password from request headers
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function get_http_password()
|
||||
{
|
||||
$password_keys = array(
|
||||
'PHP_AUTH_PW',
|
||||
'REMOTE_PASSWORD',
|
||||
'AUTH_PASSWORD',
|
||||
);
|
||||
|
||||
foreach ($password_keys as $key)
|
||||
{
|
||||
if ($this->request->is_set($key, request_interface::SERVER))
|
||||
{
|
||||
return html_entity_decode($this->request->server($key), ENT_COMPAT);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if password is in Authorization header (Basic auth)
|
||||
$username_keys = array(
|
||||
'PHP_AUTH_USER',
|
||||
'Authorization',
|
||||
'REMOTE_USER',
|
||||
'REDIRECT_REMOTE_USER',
|
||||
'HTTP_AUTHORIZATION',
|
||||
'REDIRECT_HTTP_AUTHORIZATION',
|
||||
'REMOTE_AUTHORIZATION',
|
||||
'REDIRECT_REMOTE_AUTHORIZATION',
|
||||
'AUTH_USER',
|
||||
);
|
||||
|
||||
foreach ($username_keys as $key)
|
||||
{
|
||||
if ($this->request->is_set($key, request_interface::SERVER))
|
||||
{
|
||||
$auth_header = html_entity_decode($this->request->server($key), ENT_COMPAT);
|
||||
|
||||
// Decode Basic authentication header
|
||||
if (strpos($auth_header, 'Basic ') === 0)
|
||||
{
|
||||
$credentials = base64_decode(substr($auth_header, 6));
|
||||
if (strpos($credentials, ':') !== false)
|
||||
{
|
||||
list(, $password) = explode(':', $credentials, 2);
|
||||
return $password;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send HTTP authentication challenge
|
||||
*
|
||||
* @param GetResponseEvent $event
|
||||
* @return void
|
||||
*/
|
||||
protected function send_auth_challenge(GetResponseEvent $event)
|
||||
{
|
||||
$realm = $this->config['sitename'];
|
||||
// Filter out non-ASCII characters per RFC2616
|
||||
$realm = preg_replace('/[\x80-\xFF]/', '?', $realm);
|
||||
|
||||
$response = new Response('', Response::HTTP_UNAUTHORIZED);
|
||||
$response->headers->set('WWW-Authenticate', 'Basic realm="' . $realm . '"');
|
||||
$event->setResponse($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
// Priority should be high to run after session_begin but before controller
|
||||
KernelEvents::REQUEST => array('on_kernel_request', 5),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user