Add basic authentication support (#728)
* Move configuration in its own class in order to reduce the verbosity of index.php * Add authentication mechanism using HTTP auth * Add a method to get the config parameters * Remove the installation checks from the index page * Log all failed authentication attempts
This commit is contained in:
parent
95686b803c
commit
937ea49271
5 changed files with 164 additions and 89 deletions
|
@ -24,4 +24,21 @@ name = "Hidden proxy name"
|
|||
; Allow users to disable proxy usage for specific requests.
|
||||
; true = enabled
|
||||
; false = disabled (default)
|
||||
by_bridge = false
|
||||
by_bridge = false
|
||||
|
||||
[authentication]
|
||||
|
||||
; Enables authentication for all requests to this RSS-Bridge instance.
|
||||
;
|
||||
; Warning: You'll have to upgrade existing feeds after enabling this option!
|
||||
;
|
||||
; true = enabled
|
||||
; false = disabled (default)
|
||||
enable = false
|
||||
|
||||
; The username for authentication. Insert this name when prompted for login.
|
||||
username = ""
|
||||
|
||||
; The password for authentication. Insert this password when prompted for login.
|
||||
; Use a strong password to prevent others from guessing your login!
|
||||
password = ""
|
||||
|
|
96
index.php
96
index.php
|
@ -1,67 +1,21 @@
|
|||
<?php
|
||||
/*
|
||||
TODO :
|
||||
- factorize the annotation system
|
||||
- factorize to adapter : Format, Bridge, Cache(actually code is almost the same)
|
||||
- implement annotation cache for entrance page
|
||||
- Cache : I think logic must be change as least to avoid to reconvert object from json in FileCache case.
|
||||
- add namespace to avoid futur problem ?
|
||||
- see FIXME mentions in the code
|
||||
- implement header('X-Cached-Version: '.date(DATE_ATOM, filemtime($cachefile)));
|
||||
*/
|
||||
require_once __DIR__ . '/lib/RssBridge.php';
|
||||
|
||||
if(!file_exists('config.default.ini.php'))
|
||||
die('The default configuration file "config.default.ini.php" is missing!');
|
||||
|
||||
$config = parse_ini_file('config.default.ini.php', true, INI_SCANNER_TYPED);
|
||||
if(!$config)
|
||||
die('Error parsing config.default.ini.php');
|
||||
|
||||
if(file_exists('config.ini.php')) {
|
||||
// Replace default configuration with custom settings
|
||||
foreach(parse_ini_file('config.ini.php', true, INI_SCANNER_TYPED) as $header => $section) {
|
||||
foreach($section as $key => $value) {
|
||||
// Skip unknown sections and keys
|
||||
if(array_key_exists($header, $config) && array_key_exists($key, $config[$header])) {
|
||||
$config[$header][$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_string($config['proxy']['url']))
|
||||
die('Parameter [proxy] => "url" is not a valid string! Please check "config.ini.php"!');
|
||||
|
||||
if(!empty($config['proxy']['url']))
|
||||
define('PROXY_URL', $config['proxy']['url']);
|
||||
|
||||
if(!is_bool($config['proxy']['by_bridge']))
|
||||
die('Parameter [proxy] => "by_bridge" is not a valid Boolean! Please check "config.ini.php"!');
|
||||
|
||||
define('PROXY_BYBRIDGE', $config['proxy']['by_bridge']);
|
||||
|
||||
if(!is_string($config['proxy']['name']))
|
||||
die('Parameter [proxy] => "name" is not a valid string! Please check "config.ini.php"!');
|
||||
|
||||
define('PROXY_NAME', $config['proxy']['name']);
|
||||
|
||||
if(!is_bool($config['cache']['custom_timeout']))
|
||||
die('Parameter [cache] => "custom_timeout" is not a valid Boolean! Please check "config.ini.php"!');
|
||||
|
||||
define('CUSTOM_CACHE_TIMEOUT', $config['cache']['custom_timeout']);
|
||||
|
||||
// Defines the minimum required PHP version for RSS-Bridge
|
||||
define('PHP_VERSION_REQUIRED', '5.6.0');
|
||||
|
||||
date_default_timezone_set('UTC');
|
||||
error_reporting(0);
|
||||
|
||||
// Specify directory for cached files (using FileCache)
|
||||
define('CACHE_DIR', __DIR__ . '/cache');
|
||||
|
||||
// Specify path for whitelist file
|
||||
define('WHITELIST_FILE', __DIR__ . '/whitelist.txt');
|
||||
|
||||
Configuration::verifyInstallation();
|
||||
Configuration::loadConfiguration();
|
||||
|
||||
Authentication::showPromptIfNeeded();
|
||||
|
||||
date_default_timezone_set('UTC');
|
||||
error_reporting(0);
|
||||
|
||||
/*
|
||||
Move the CLI arguments to the $_GET array, in order to be able to use
|
||||
|
@ -91,40 +45,6 @@ if(file_exists('DEBUG')) {
|
|||
}
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/lib/RssBridge.php';
|
||||
|
||||
// Check PHP version
|
||||
if(version_compare(PHP_VERSION, PHP_VERSION_REQUIRED) === -1)
|
||||
die('RSS-Bridge requires at least PHP version ' . PHP_VERSION_REQUIRED . '!');
|
||||
|
||||
// extensions check
|
||||
if(!extension_loaded('openssl'))
|
||||
die('"openssl" extension not loaded. Please check "php.ini"');
|
||||
|
||||
if(!extension_loaded('libxml'))
|
||||
die('"libxml" extension not loaded. Please check "php.ini"');
|
||||
|
||||
if(!extension_loaded('mbstring'))
|
||||
die('"mbstring" extension not loaded. Please check "php.ini"');
|
||||
|
||||
if(!extension_loaded('simplexml'))
|
||||
die('"simplexml" extension not loaded. Please check "php.ini"');
|
||||
|
||||
if(!extension_loaded('curl'))
|
||||
die('"curl" extension not loaded. Please check "php.ini"');
|
||||
|
||||
// configuration checks
|
||||
if(ini_get('allow_url_fopen') !== "1")
|
||||
die('"allow_url_fopen" is not set to "1". Please check "php.ini');
|
||||
|
||||
// Check cache folder permissions (write permissions required)
|
||||
if(!is_writable(CACHE_DIR))
|
||||
die('RSS-Bridge does not have write permissions for ' . CACHE_DIR . '!');
|
||||
|
||||
// Check whitelist file permissions (only in DEBUG mode)
|
||||
if(!file_exists(WHITELIST_FILE) && !is_writable(dirname(WHITELIST_FILE)))
|
||||
die('RSS-Bridge does not have write permissions for ' . WHITELIST_FILE . '!');
|
||||
|
||||
// FIXME : beta test UA spoofing, please report any blacklisting by PHP-fopen-unfriendly websites
|
||||
|
||||
$userAgent = 'Mozilla/5.0(X11; Linux x86_64; rv:30.0)';
|
||||
|
|
31
lib/Authentication.php
Normal file
31
lib/Authentication.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
class Authentication {
|
||||
|
||||
public static function showPromptIfNeeded() {
|
||||
|
||||
if(Configuration::getConfig('authentication', 'enable') === true) {
|
||||
if(!Authentication::verifyPrompt()) {
|
||||
header('WWW-Authenticate: Basic realm="RSS-Bridge"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
die('Please authenticate in order to access this instance !');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static function verifyPrompt() {
|
||||
|
||||
if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
|
||||
if(Configuration::getConfig('authentication', 'username') === $_SERVER['PHP_AUTH_USER']
|
||||
&& Configuration::getConfig('authentication', 'password') === $_SERVER['PHP_AUTH_PW']) {
|
||||
return true;
|
||||
} else {
|
||||
error_log('[RSS-Bridge] Failed authentication attempt from ' . $_SERVER['REMOTE_ADDR']);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
105
lib/Configuration.php
Normal file
105
lib/Configuration.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
class Configuration {
|
||||
|
||||
public static $config = null;
|
||||
|
||||
public static function verifyInstallation() {
|
||||
|
||||
// Check PHP version
|
||||
if(version_compare(PHP_VERSION, PHP_VERSION_REQUIRED) === -1)
|
||||
die('RSS-Bridge requires at least PHP version ' . PHP_VERSION_REQUIRED . '!');
|
||||
|
||||
// extensions check
|
||||
if(!extension_loaded('openssl'))
|
||||
die('"openssl" extension not loaded. Please check "php.ini"');
|
||||
|
||||
if(!extension_loaded('libxml'))
|
||||
die('"libxml" extension not loaded. Please check "php.ini"');
|
||||
|
||||
if(!extension_loaded('mbstring'))
|
||||
die('"mbstring" extension not loaded. Please check "php.ini"');
|
||||
|
||||
if(!extension_loaded('simplexml'))
|
||||
die('"simplexml" extension not loaded. Please check "php.ini"');
|
||||
|
||||
if(!extension_loaded('curl'))
|
||||
die('"curl" extension not loaded. Please check "php.ini"');
|
||||
|
||||
// configuration checks
|
||||
if(ini_get('allow_url_fopen') !== "1")
|
||||
die('"allow_url_fopen" is not set to "1". Please check "php.ini');
|
||||
|
||||
// Check cache folder permissions (write permissions required)
|
||||
if(!is_writable(CACHE_DIR))
|
||||
die('RSS-Bridge does not have write permissions for ' . CACHE_DIR . '!');
|
||||
|
||||
// Check whitelist file permissions (only in DEBUG mode)
|
||||
if(!file_exists(WHITELIST_FILE) && !is_writable(dirname(WHITELIST_FILE)))
|
||||
die('RSS-Bridge does not have write permissions for ' . WHITELIST_FILE . '!');
|
||||
|
||||
}
|
||||
|
||||
public static function loadConfiguration() {
|
||||
|
||||
if(!file_exists('config.default.ini.php'))
|
||||
die('The default configuration file "config.default.ini.php" is missing!');
|
||||
|
||||
Configuration::$config = parse_ini_file('config.default.ini.php', true, INI_SCANNER_TYPED);
|
||||
if(!Configuration::$config)
|
||||
die('Error parsing config.default.ini.php');
|
||||
|
||||
if(file_exists('config.ini.php')) {
|
||||
// Replace default configuration with custom settings
|
||||
foreach(parse_ini_file('config.ini.php', true, INI_SCANNER_TYPED) as $header => $section) {
|
||||
foreach($section as $key => $value) {
|
||||
// Skip unknown sections and keys
|
||||
if(array_key_exists($header, Configuration::$config) && array_key_exists($key, Configuration::$config[$header])) {
|
||||
Configuration::$config[$header][$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!is_string(self::getConfig('proxy', 'url')))
|
||||
die('Parameter [proxy] => "url" is not a valid string! Please check "config.ini.php"!');
|
||||
|
||||
if(!empty(self::getConfig('proxy', 'url')))
|
||||
define('PROXY_URL', self::getConfig('proxy', 'url'));
|
||||
|
||||
if(!is_bool(self::getConfig('proxy', 'by_bridge')))
|
||||
die('Parameter [proxy] => "by_bridge" is not a valid Boolean! Please check "config.ini.php"!');
|
||||
|
||||
define('PROXY_BYBRIDGE', self::getConfig('proxy', 'by_bridge'));
|
||||
|
||||
if(!is_string(self::getConfig('proxy', 'name')))
|
||||
die('Parameter [proxy] => "name" is not a valid string! Please check "config.ini.php"!');
|
||||
|
||||
define('PROXY_NAME', self::getConfig('proxy', 'name'));
|
||||
|
||||
if(!is_bool(self::getConfig('cache', 'custom_timeout')))
|
||||
die('Parameter [cache] => "custom_timeout" is not a valid Boolean! Please check "config.ini.php"!');
|
||||
|
||||
define('CUSTOM_CACHE_TIMEOUT', self::getConfig('cache', 'custom_timeout'));
|
||||
|
||||
if(!is_bool(self::getConfig('authentication', 'enable')))
|
||||
die('Parameter [authentication] => "enable" is not a valid Boolean! Please check "config.ini.php"!');
|
||||
|
||||
if(!is_string(self::getConfig('authentication', 'username')))
|
||||
die('Parameter [authentication] => "username" is not a valid string! Please check "config.ini.php"!');
|
||||
|
||||
if(!is_string(self::getConfig('authentication', 'password')))
|
||||
die('Parameter [authentication] => "password" is not a valid string! Please check "config.ini.php"!');
|
||||
|
||||
}
|
||||
|
||||
public static function getConfig($category, $key) {
|
||||
|
||||
if(array_key_exists($category, self::$config) && array_key_exists($key, self::$config[$category])) {
|
||||
return self::$config[$category][$key];
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -14,6 +14,8 @@ require __DIR__ . '/Bridge.php';
|
|||
require __DIR__ . '/BridgeAbstract.php';
|
||||
require __DIR__ . '/FeedExpander.php';
|
||||
require __DIR__ . '/Cache.php';
|
||||
require __DIR__ . '/Authentication.php';
|
||||
require __DIR__ . '/Configuration.php';
|
||||
|
||||
require __DIR__ . '/validation.php';
|
||||
require __DIR__ . '/html.php';
|
||||
|
|
Loading…
Reference in a new issue