Fix fatal errors and notices
[friendica.git/.git] / src / Util / ExAuth.php
index a6851c3..7771712 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-/*
+/**
  * ejabberd extauth script for the integration with friendica
  *
  * Originally written for joomla by Dalibor Karlovic <dado@krizevci.info>
  * Installation:
  *
  *     - Change it's owner to whichever user is running the server, ie. ejabberd
- *       $ chown ejabberd:ejabberd /path/to/friendica/scripts/auth_ejabberd.php
+ *       $ chown ejabberd:ejabberd /path/to/friendica/bin/auth_ejabberd.php
  *
  *     - Change the access mode so it is readable only to the user ejabberd and has exec
- *       $ chmod 700 /path/to/friendica/scripts/auth_ejabberd.php
+ *       $ chmod 700 /path/to/friendica/bin/auth_ejabberd.php
  *
  *     - Edit your ejabberd.cfg file, comment out your auth_method and add:
  *       {auth_method, external}.
- *       {extauth_program, "/path/to/friendica/script/auth_ejabberd.php"}.
+ *       {extauth_program, "/path/to/friendica/bin/auth_ejabberd.php"}.
  *
  *     - Restart your ejabberd service, you should be able to login with your friendica auth info
  *
 
 namespace Friendica\Util;
 
-use Friendica\Core\Config;
-use Friendica\Core\PConfig;
-use Friendica\Database\DBM;
+use Exception;
+use Friendica\App;
+use Friendica\Core\Config\IConfig;
+use Friendica\Core\PConfig\IPConfig;
+use Friendica\Database\Database;
+use Friendica\DI;
 use Friendica\Model\User;
-use Friendica\Util\Network;
-use dba;
-
-require_once 'include/dba.php';
+use Friendica\Network\HTTPException;
 
 class ExAuth
 {
@@ -49,13 +49,43 @@ class ExAuth
        private $host;
 
        /**
-        * @brief Create the class
-        *
-        * @param boolean $bDebug Debug mode
+        * @var App\Mode
+        */
+       private $appMode;
+       /**
+        * @var IConfig
+        */
+       private $config;
+       /**
+        * @var IPConfig
+        */
+       private $pConfig;
+       /**
+        * @var Database
         */
-       public function __construct()
+       private $dba;
+       /**
+        * @var App\BaseURL
+        */
+       private $baseURL;
+
+       /**
+        * @param App\Mode    $appMode
+        * @param IConfig      $config
+        * @param IPConfig     $pConfig
+        * @param Database    $dba
+        * @param App\BaseURL $baseURL
+        * @throws Exception
+        */
+       public function __construct(App\Mode $appMode, IConfig $config, IPConfig $pConfig, Database $dba, App\BaseURL $baseURL)
        {
-               $this->bDebug = (int) Config::get('jabber', 'debug');
+               $this->appMode = $appMode;
+               $this->config  = $config;
+               $this->pConfig = $pConfig;
+               $this->dba     = $dba;
+               $this->baseURL = $baseURL;
+
+               $this->bDebug = (int)$config->get('jabber', 'debug');
 
                openlog('auth_ejabberd', LOG_PID, LOG_USER);
 
@@ -63,21 +93,31 @@ class ExAuth
        }
 
        /**
-        * @brief Standard input reading function, executes the auth with the provided
+        * Standard input reading function, executes the auth with the provided
         * parameters
         *
-        * @return null
+        * @throws HTTPException\InternalServerErrorException
         */
        public function readStdin()
        {
+               if (!$this->appMode->isNormal()) {
+                       $this->writeLog(LOG_ERR, 'The node isn\'t ready.');
+                       return;
+               }
+
                while (!feof(STDIN)) {
                        // Quit if the database connection went down
-                       if (!dba::connected()) {
+                       if (!$this->dba->isConnected()) {
                                $this->writeLog(LOG_ERR, 'the database connection went down');
                                return;
                        }
 
                        $iHeader = fgets(STDIN, 3);
+                       if (empty($iHeader)) {
+                               $this->writeLog(LOG_ERR, 'empty stdin');
+                               return;
+                       }
+
                        $aLength = unpack('n', $iHeader);
                        $iLength = $aLength['1'];
 
@@ -120,14 +160,13 @@ class ExAuth
        }
 
        /**
-        * @brief Check if the given username exists
+        * Check if the given username exists
         *
         * @param array $aCommand The command array
+        * @throws HTTPException\InternalServerErrorException
         */
        private function isUser(array $aCommand)
        {
-               $a = get_app();
-
                // Check if there is a username
                if (!isset($aCommand[1])) {
                        $this->writeLog(LOG_NOTICE, 'invalid isuser command, no username given');
@@ -143,9 +182,9 @@ class ExAuth
                $sUser = str_replace(['%20', '(a)'], [' ', '@'], $aCommand[1]);
 
                // Does the hostname match? So we try directly
-               if ($a->get_hostname() == $aCommand[2]) {
+               if ($this->baseURL->getHostname() == $aCommand[2]) {
                        $this->writeLog(LOG_INFO, 'internal user check for ' . $sUser . '@' . $aCommand[2]);
-                       $found = dba::exists('user', ['nickname' => $sUser]);
+                       $found = $this->dba->exists('user', ['nickname' => $sUser]);
                } else {
                        $found = false;
                }
@@ -167,13 +206,14 @@ class ExAuth
        }
 
        /**
-        * @brief Check remote user existance via HTTP(S)
+        * Check remote user existance via HTTP(S)
         *
-        * @param string $host The hostname
-        * @param string $user Username
-        * @param boolean $ssl Should the check be done via SSL?
+        * @param string  $host The hostname
+        * @param string  $user Username
+        * @param boolean $ssl  Should the check be done via SSL?
         *
         * @return boolean Was the user found?
+        * @throws HTTPException\InternalServerErrorException
         */
        private function checkUser($host, $user, $ssl)
        {
@@ -181,17 +221,17 @@ class ExAuth
 
                $url = ($ssl ? 'https' : 'http') . '://' . $host . '/noscrape/' . $user;
 
-               $data = Network::curl($url);
+               $curlResult = DI::httpRequest()->get($url);
 
-               if (!is_array($data)) {
+               if (!$curlResult->isSuccess()) {
                        return false;
                }
 
-               if ($data['return_code'] != '200') {
+               if ($curlResult->getReturnCode() != 200) {
                        return false;
                }
 
-               $json = @json_decode($data['body']);
+               $json = @json_decode($curlResult->getBody());
                if (!is_object($json)) {
                        return false;
                }
@@ -200,14 +240,13 @@ class ExAuth
        }
 
        /**
-        * @brief Authenticate the given user and password
+        * Authenticate the given user and password
         *
         * @param array $aCommand The command array
+        * @throws Exception
         */
        private function auth(array $aCommand)
        {
-               $a = get_app();
-
                // check user authentication
                if (sizeof($aCommand) != 4) {
                        $this->writeLog(LOG_NOTICE, 'invalid auth command, data missing');
@@ -222,35 +261,29 @@ class ExAuth
                // We now check if the password match
                $sUser = str_replace(['%20', '(a)'], [' ', '@'], $aCommand[1]);
 
+               $Error = false;
                // Does the hostname match? So we try directly
-               if ($a->get_hostname() == $aCommand[2]) {
-                       $this->writeLog(LOG_INFO, 'internal auth for ' . $sUser . '@' . $aCommand[2]);
-
-                       $aUser = dba::selectFirst('user', ['uid', 'password', 'legacy_password'], ['nickname' => $sUser]);
-                       if (DBM::is_result($aUser)) {
-                               $uid = $aUser['uid'];
-                               $success = User::authenticate($aUser, $aCommand[3]);
-                               $Error = $success === false;
-                       } else {
-                               $this->writeLog(LOG_WARNING, 'user not found: ' . $sUser);
-                               $Error = true;
-                               $uid = -1;
-                       }
-                       if ($Error) {
+               if ($this->baseURL->getHostname() == $aCommand[2]) {
+                       try {
+                               $this->writeLog(LOG_INFO, 'internal auth for ' . $sUser . '@' . $aCommand[2]);
+                               User::getIdFromPasswordAuthentication($sUser, $aCommand[3], true);
+                       } catch (HTTPException\ForbiddenException $ex) {
+                               // User exists, authentication failed
                                $this->writeLog(LOG_INFO, 'check against alternate password for ' . $sUser . '@' . $aCommand[2]);
-                               $sPassword = PConfig::get($uid, 'xmpp', 'password', null, true);
+                               $aUser = User::getByNickname($sUser, ['uid']);
+                               $sPassword = $this->pConfig->get($aUser['uid'], 'xmpp', 'password', null, true);
                                $Error = ($aCommand[3] != $sPassword);
+                       } catch (\Throwable $ex) {
+                               // User doesn't exist and any other failure case
+                               $this->writeLog(LOG_WARNING, $ex->getMessage() . ': ' . $sUser);
+                               $Error = true;
                        }
                } else {
                        $Error = true;
                }
 
                // If the hostnames doesn't match or there is some failure, we try to check remotely
-               if ($Error) {
-                       $Error = !$this->checkCredentials($aCommand[2], $aCommand[1], $aCommand[3], true);
-               }
-
-               if ($Error) {
+               if ($Error && !$this->checkCredentials($aCommand[2], $aCommand[1], $aCommand[3], true)) {
                        $this->writeLog(LOG_WARNING, 'authentification failed for user ' . $sUser . '@' . $aCommand[2]);
                        fwrite(STDOUT, pack('nn', 2, 0));
                } else {
@@ -260,7 +293,7 @@ class ExAuth
        }
 
        /**
-        * @brief Check remote credentials via HTTP(S)
+        * Check remote credentials via HTTP(S)
         *
         * @param string $host The hostname
         * @param string $user Username
@@ -295,7 +328,7 @@ class ExAuth
        }
 
        /**
-        * @brief Set the hostname for this process
+        * Set the hostname for this process
         *
         * @param string $host The hostname
         */
@@ -309,7 +342,7 @@ class ExAuth
 
                $this->host = $host;
 
-               $lockpath = Config::get('jabber', 'lockpath');
+               $lockpath = $this->config->get('jabber', 'lockpath');
                if (is_null($lockpath)) {
                        $this->writeLog(LOG_INFO, 'No lockpath defined.');
                        return;
@@ -333,7 +366,7 @@ class ExAuth
        }
 
        /**
-        * @brief write data to the syslog
+        * write data to the syslog
         *
         * @param integer $loglevel The syslog loglevel
         * @param string $sMessage The syslog message
@@ -347,7 +380,7 @@ class ExAuth
        }
 
        /**
-        * @brief destroy the class, close the syslog connection.
+        * destroy the class, close the syslog connection.
         */
        public function __destruct()
        {