aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar drosoCode <44530920+drosoCode@users.noreply.github.com> 2022-04-02 21:40:30 +0200
committerGravatar GitHub <noreply@github.com> 2022-04-02 21:40:30 +0200
commit2aba861bc983555faf6dd96c5daa4e40e5328c54 (patch)
tree68d63f76d0ce79e06cb3cabaaaeb3cd82849c175
parent191abf5ba541107c5a1c5f14202b99e17bee2074 (diff)
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>
-rw-r--r--app/Models/SystemConfiguration.php1
-rw-r--r--config.default.php8
-rw-r--r--docs/en/admins/09_AccessControl.md12
-rw-r--r--lib/lib_rss.php55
4 files changed, 74 insertions, 2 deletions
diff --git a/app/Models/SystemConfiguration.php b/app/Models/SystemConfiguration.php
index 3b07bc9ff..3170a4180 100644
--- a/app/Models/SystemConfiguration.php
+++ b/app/Models/SystemConfiguration.php
@@ -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 {
diff --git a/config.default.php b/config.default.php
index a9f6a12ec..df8e9133e 100644
--- a/config.default.php
+++ b/config.default.php
@@ -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',
+ ]
);
diff --git a/docs/en/admins/09_AccessControl.md b/docs/en/admins/09_AccessControl.md
index 8ee193cea..4bd4dc8b5 100644
--- a/docs/en/admins/09_AccessControl.md
+++ b/docs/en/admins/09_AccessControl.md
@@ -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-proxy’s 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 isn’t 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.
diff --git a/lib/lib_rss.php b/lib/lib_rss.php
index b6fde6437..677e4a413 100644
--- a/lib/lib_rss.php
+++ b/lib/lib_rss.php
@@ -555,14 +555,67 @@ function get_user_configuration($username) {
}
/**
+ * 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 '';