diff --git a/config-templates/module_proxystatistics.php b/config-templates/module_proxystatistics.php index ad4b0de6f16fca9f1176c7d39d58bf94eda8119b..c5ff12eb772a1ac2ba4e19418a4e2055be64f37e 100644 --- a/config-templates/module_proxystatistics.php +++ b/config-templates/module_proxystatistics.php @@ -104,6 +104,16 @@ $config = [ */ //'apiWritePasswordHash' => password_hash('ap1Wr1T3rP@S$'), + /* + * Map of credentials for API writer (has no effect if write is disabled). + * Either apiWriteUsername and apiWritePasswordHash or this array has to contain valid credentials pair. + */ + + //'apiWriters' => [ + // 'api_writer' => password_hash('ap1Wr1T3rP@S$'), + // 'api_writer2' => password_hash('ap1Wr1T3rP@S$'), + //], + /* * List of IDP and/or SP EntityIDs for which the login statistic will be ignored even * when requested to be instered into the storage. By default lists are empty diff --git a/lib/Config.php b/lib/Config.php index 6f8b9a3bda5258cece63dca2e1c81f17f08e723d..a85e76044c2857fe6e7ec5ca3050538fbbb4ace4 100644 --- a/lib/Config.php +++ b/lib/Config.php @@ -41,6 +41,8 @@ class Config private const API_WRITE_PASSWORD_HASH = 'apiWritePasswordHash'; + private const API_WRITERS_CREDENTIALS = 'apiWriteCredentials'; + private const IGNORED_IDS = 'ignoredIds'; private const CRON_ENABLED = 'cronEnabled'; @@ -63,9 +65,7 @@ class Config private $apiWriteEnabled; - private $apiWriteUsername; - - private $apiWritePasswordHash; + private $apiWriters; private $ignoredIds; @@ -87,13 +87,20 @@ class Config $this->apiWriteEnabled = $this->config->getBoolean(self::API_WRITE_ENABLED, false); $this->ignoredIds = $this->config->getArray(self::IGNORED_IDS, []); if ($this->apiWriteEnabled) { - $this->apiWriteUsername = $this->config->getString(self::API_WRITE_USERNAME); - if (empty(trim($this->apiWriteUsername))) { - throw new Exception('Username for API write cannot be empty'); + $apiWriteUsername = $this->config->getString(self::API_WRITE_USERNAME, null); + $apiWritePasswordHash = $this->config->getString(self::API_WRITE_PASSWORD_HASH, null); + $this->apiWriters = $this->config->getArray(self::API_WRITERS_CREDENTIALS, []); + if (!empty(trim($apiWriteUsername)) && !empty(trim($apiWritePasswordHash))) { + $this->apiWriters[$apiWriteUsername] = $apiWritePasswordHash; } - $this->apiWritePasswordHash = $this->config->getString(self::API_WRITE_PASSWORD_HASH); - if (empty(trim($this->apiWritePasswordHash))) { - throw new Exception('Password for API write cannot be empty'); + + foreach ($this->apiWriters as $username => $passwordHash) { + if (empty(trim($username))) { + throw new Exception('Username for API write cannot be empty'); + } + if (empty(trim($passwordHash))) { + throw new Exception('Password for API write (' . $username . ') cannot be empty'); + } } } } @@ -163,14 +170,9 @@ class Config return $this->apiWriteEnabled; } - public function getApiWriteUsername() - { - return $this->apiWriteUsername; - } - - public function getApiWritePasswordHash() + public function getApiWriteCredentials() { - return $this->apiWritePasswordHash; + return $this->apiWriters; } public function getIgnoredIds() diff --git a/www/writeLoginApi.php b/www/writeLoginApi.php index 60ad003c0723e82632f38a9263e6db699bf94897..23bd6b6fb41c35f4efdadee3e190d6ad3b61d905 100644 --- a/www/writeLoginApi.php +++ b/www/writeLoginApi.php @@ -26,11 +26,17 @@ if (!$config->isApiWriteEnabled()) { $authUsername = $_SERVER['PHP_AUTH_USER'] ?? ''; $authPass = $_SERVER['PHP_AUTH_PW'] ?? ''; -$username = $config->getApiWriteUsername(); -$passwordHash = $config->getApiWritePasswordHash(); +$apiCredentials = $config->getApiWriteCredentials(); +$validCreds = false; +foreach ($apiCredentials as $username => $passwordHash) { + if ($authUsername === $username && password_verify($authPass, $passwordHash)) { + $validCreds = true; + break; + } +} // If we get here, username was provided. Check password. -if ($authUsername !== $username || !password_verify($authPass, $passwordHash)) { +if (!$validCreds) { Logger::info( sprintf( "%s - API write called with bad credentials (%s:%s) returning 401 response code",