Add HTTP_REMOTE_USER header for auth (#4063)

* add HTTP_REMOTE_USER header for auth

* add ip whitelist for HTTP_REMOTE_USER header

* add IPv6 support for header auth

* fix formatting

* A few fixes

* Add some default trusted sources

* Fix IPv6 doc

* More standard header names

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
This commit is contained in:
drosoCode
2022-04-02 21:40:30 +02:00
committed by GitHub
parent 191abf5ba5
commit 2aba861bc9
4 changed files with 74 additions and 2 deletions

View File

@@ -22,6 +22,7 @@
* @property-read string $salt
* @property-read bool $simplepie_syslog_enabled
* @property string $unsafe_autologin_enabled
* @property-read array<string> $trusted_sources
*/
class FreshRSS_SystemConfiguration extends Minz_Configuration {

View File

@@ -189,4 +189,12 @@ return array(
# Disable self-update,
'disable_update' => false,
# Trusted IPs that are allowed to send unsafe headers
# Please read the documentation, before configuring this
# https://freshrss.github.io/FreshRSS/en/admins/09_AccessControl.html
'trusted_sources' => [
'127.0.0.0/8',
'::1/128',
]
);

View File

@@ -15,13 +15,23 @@ You may also choose to use HTTP Authentication provided by your web server.[^1]
If you choose to use this option, create a `./p/i/.htaccess` file with a matching `.htpasswd` file.
You can also use any authentication backend as long as your web server exposes the authenticated user through the `REMOTE_USER` variable.
You can also use any authentication backend as long as your web server exposes the authenticated user through the `Remote-User` variable.
By default, new users allowed by HTTP Basic Auth will automatically be created in FreshRSS the first time they log in.
You can disable auto-registration of new users by setting `http_auth_auto_register` to `false` in the configuration file.
When using auto-registration, you can optionally use the `http_auth_auto_register_email_field` to specify the name of a web server
variable containing the email address of the authenticated user (e.g. `REMOTE_USER_EMAIL`).
## External Authentication
You may also use the `Remote-User` or `X-WebAuth-User` header to integrate with a your reverse-proxys authentication.
To enable this feature, you need to add the IP range (in CIDR notation) of your trusted proxy in the `trusted_sources` configuration option.
To allow only one IPv4, you can use a `/32` like this: `trusted_sources => [ '192.168.1.10/32' ]`.
Likewise to allow only one IPv6, you can use a `/128` like this: `trusted_sources => [ '::1/128' ]`.
WARNING: FreshRSS will trust any IP configured in the `trusted_sources` option, if your proxy isnt properly secured, an attacker could simply attach this header and get admin access.
## No Authentication
Not using authentication on your server is dangerous, as anyone with access to your server would be able to make changes as an admin.

View File

@@ -554,15 +554,68 @@ function get_user_configuration($username) {
return $user_conf;
}
/**
* Converts an IP (v4 or v6) to a binary representation using inet_pton
*
* @param string $ip the IP to convert
* @return string a binary representation of the specified IP
*/
function ipToBits(string $ip): string {
$binaryip = '';
foreach (str_split(inet_pton($ip)) as $char) {
$binaryip .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT);
}
return $binaryip;
}
/**
* Check if an ip belongs to the provided range (in CIDR format)
*
* @param string $ip the IP that we want to verify (ex: 192.168.16.1)
* @param string $range the range to check against (ex: 192.168.16.0/24)
* @return boolean true if the IP is in the range, otherwise false
*/
function checkCIDR(string $ip, string $range): bool {
$binary_ip = ipToBits($ip);
list($subnet, $mask_bits) = explode('/', $range);
$mask_bits = intval($mask_bits);
$binary_subnet = ipToBits($subnet);
$ip_net_bits = substr($binary_ip, 0, $mask_bits);
$subnet_bits = substr($binary_subnet, 0, $mask_bits);
return $ip_net_bits === $subnet_bits;
}
/**
* Check if the client is allowed to send unsafe headers
* This uses the REMOTE_ADDR header to determine the sender's IP
* and the configuration option "trusted_sources" to get an array of the authorized ranges
*
* @return boolean, true if the sender's IP is in one of the ranges defined in the configuration, else false
*/
function checkTrustedIP(): bool {
if (!empty($_SERVER['REMOTE_ADDR'])) {
foreach (FreshRSS_Context::$system_conf->trusted_sources as $cidr) {
if (checkCIDR($_SERVER['REMOTE_ADDR'], $cidr)) {
return true;
}
}
}
return false;
}
/**
* @return string
*/
function httpAuthUser() {
if (!empty($_SERVER['REMOTE_USER'])) {
return $_SERVER['REMOTE_USER'];
} elseif (!empty($_SERVER['HTTP_REMOTE_USER']) && checkTrustedIP()) {
return $_SERVER['HTTP_REMOTE_USER'];
} elseif (!empty($_SERVER['REDIRECT_REMOTE_USER'])) {
return $_SERVER['REDIRECT_REMOTE_USER'];
} elseif (!empty($_SERVER['HTTP_X_WEBAUTH_USER'])) {
} elseif (!empty($_SERVER['HTTP_X_WEBAUTH_USER']) && checkTrustedIP()) {
return $_SERVER['HTTP_X_WEBAUTH_USER'];
}
return '';