From 51d2deeea911e84ea2e56b78544445de22f881b9 Mon Sep 17 00:00:00 2001
From: Andrew Dolgov <noreply@fakecake.org>
Date: Mon, 8 Feb 2021 19:11:31 +0300
Subject: [PATCH] fix hierarchy of authentication modules, make everything
 extend Auth_Base and implement hook_auth_user() for pluginhost

---
 classes/auth/base.php          | 19 +++++--------------
 classes/iauthmodule.php        |  1 +
 classes/userhelper.php         | 18 +++++++++---------
 plugins/auth_internal/init.php | 10 +++++++---
 plugins/auth_remote/init.php   |  9 +++------
 5 files changed, 25 insertions(+), 32 deletions(-)

diff --git a/classes/auth/base.php b/classes/auth/base.php
index 4cbc23589..1b9015fe3 100644
--- a/classes/auth/base.php
+++ b/classes/auth/base.php
@@ -1,6 +1,6 @@
 <?php
-class Auth_Base {
-	private $pdo;
+abstract class Auth_Base extends Plugin implements IAuthModule {
+	protected $pdo;
 
 	const AUTH_SERVICE_API = '_api';
 
@@ -8,18 +8,9 @@ class Auth_Base {
 		$this->pdo = Db::pdo();
 	}
 
-	/**
-	 * @SuppressWarnings(unused)
-	 */
-	function check_password($owner_uid, $password, $service = '') {
-		return false;
-	}
-
-	/**
-	 * @SuppressWarnings(unused)
-	 */
-	function authenticate($login, $password, $service = '') {
-		return false;
+	// compatibility wrapper, because of how pluginhost works (hook name == method name)
+	function hook_auth_user(...$args) {
+		return $this->authenticate(...$args);
 	}
 
 	// Auto-creates specified user if allowed by system configuration
diff --git a/classes/iauthmodule.php b/classes/iauthmodule.php
index 2d0c98709..e714cc6ca 100644
--- a/classes/iauthmodule.php
+++ b/classes/iauthmodule.php
@@ -1,4 +1,5 @@
 <?php
 interface IAuthModule {
 	function authenticate($login, $password); // + optional third parameter: $service
+	function hook_auth_user(...$args); // compatibility wrapper due to how hooks work
 }
diff --git a/classes/userhelper.php b/classes/userhelper.php
index b0a9dc598..4519f2803 100644
--- a/classes/userhelper.php
+++ b/classes/userhelper.php
@@ -7,15 +7,15 @@ class UserHelper {
 			$user_id = false;
 			$auth_module = false;
 
-			foreach (PluginHost::getInstance()->get_hooks(PluginHost::HOOK_AUTH_USER) as $plugin) {
-
-				$user_id = (int) $plugin->authenticate($login, $password, $service);
-
-				if ($user_id) {
-					$auth_module = strtolower(get_class($plugin));
-					break;
-				}
-			}
+			PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_AUTH_USER,
+				function ($result, $plugin) use (&$user_id, &$auth_module) {
+					if ($result) {
+						$user_id = (int)$result;
+						$auth_module = strtolower(get_class($plugin));
+						return true;
+					}
+				},
+				$login, $password, $service);
 
 			if ($user_id && !$check_only) {
 
diff --git a/plugins/auth_internal/init.php b/plugins/auth_internal/init.php
index 134d3b45e..b31a23187 100644
--- a/plugins/auth_internal/init.php
+++ b/plugins/auth_internal/init.php
@@ -1,5 +1,5 @@
 <?php
-class Auth_Internal extends Plugin implements IAuthModule {
+class Auth_Internal extends Auth_Base {
 
 	private $host;
 
@@ -13,7 +13,6 @@ class Auth_Internal extends Plugin implements IAuthModule {
 	/* @var PluginHost $host */
 	function init($host) {
 		$this->host = $host;
-		$this->pdo = Db::pdo();
 
 		$host->add_hook($host::HOOK_AUTH_USER, $this);
 	}
@@ -178,7 +177,7 @@ class Auth_Internal extends Plugin implements IAuthModule {
 		return false;
 	}
 
-	function check_password($owner_uid, $password) {
+	function check_password($owner_uid, $password, $service = '') {
 
 		$sth = $this->pdo->prepare("SELECT salt,login,otp_enabled FROM ttrss_users WHERE
 			id = ?");
@@ -189,6 +188,11 @@ class Auth_Internal extends Plugin implements IAuthModule {
 			$salt = $row['salt'];
 			$login = $row['login'];
 
+			// check app password only if service is specified
+			if ($service && get_schema_version() > 138) {
+				return $this->check_app_password($login, $password, $service);
+			}
+
 			if (!$salt) {
 				$password_hash1 = encrypt_password($password);
 				$password_hash2 = encrypt_password($password, $login);
diff --git a/plugins/auth_remote/init.php b/plugins/auth_remote/init.php
index 7635080a0..71f6cae2b 100644
--- a/plugins/auth_remote/init.php
+++ b/plugins/auth_remote/init.php
@@ -1,9 +1,7 @@
 <?php
-class Auth_Remote extends Plugin implements IAuthModule {
+class Auth_Remote extends Auth_Base {
 
 	private $host;
-	/* @var Auth_Base $base */
-	private $base;
 
 	function about() {
 		return array(1.0,
@@ -13,9 +11,8 @@ class Auth_Remote extends Plugin implements IAuthModule {
 	}
 
 	/* @var PluginHost $host */
-	function init($host ) {
+	function init($host) {
 		$this->host = $host;
-		$this->base = new Auth_Base();
 
 		$host->add_hook($host::HOOK_AUTH_USER, $this);
 	}
@@ -53,7 +50,7 @@ class Auth_Remote extends Plugin implements IAuthModule {
 		if (!$try_login) $try_login = $this->get_login_by_ssl_certificate();
 
 		if ($try_login) {
-			$user_id = $this->base->auto_create_user($try_login, $password);
+			$user_id = $this->auto_create_user($try_login, $password);
 
 			if ($user_id) {
 				$_SESSION["fake_login"] = $try_login;
-- 
GitLab