From 0b48e34f25259af346531fbba4d3dbfb3742016f Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 20 Oct 2022 11:41:28 -0700 Subject: [PATCH] authx - Move listener to service class --- ext/authx/Civi/Authx/Authenticator.php | 46 ++++++++++++++++++- .../Civi/Authx/LegacyRestAuthenticator.php | 12 +++++ ext/authx/authx.php | 41 ----------------- 3 files changed, 57 insertions(+), 42 deletions(-) diff --git a/ext/authx/Civi/Authx/Authenticator.php b/ext/authx/Civi/Authx/Authenticator.php index b17bc7c17a..b9c7d8a3b3 100644 --- a/ext/authx/Civi/Authx/Authenticator.php +++ b/ext/authx/Civi/Authx/Authenticator.php @@ -11,6 +11,9 @@ namespace Civi\Authx; +use Civi\Core\Event\GenericHookEvent; +use Civi\Core\HookInterface; +use Civi\Core\Service\AutoService; use Civi\Crypto\Exception\CryptoException; use GuzzleHttp\Psr7\Response; @@ -19,8 +22,49 @@ use GuzzleHttp\Psr7\Response; * checks if current policy accepts this credential, and logs in as the target person. * * @package Civi\Authx + * @service authx.authenticator */ -class Authenticator { +class Authenticator extends AutoService implements HookInterface { + + /** + * When 'CRM_Core_Invoke' fires 'civi.invoke.auth', we should check for credentials. + * + * @param \Civi\Core\Event\GenericHookEvent $e + * @return bool|void + * @throws \Exception + */ + public function on_civi_invoke_auth(GenericHookEvent $e) { + $params = ($_SERVER['REQUEST_METHOD'] === 'GET') ? $_GET : $_POST; + $siteKey = $_SERVER['HTTP_X_CIVI_KEY'] ?? $params['_authxSiteKey'] ?? NULL; + + if (!empty($_SERVER['HTTP_X_CIVI_AUTH'])) { + return $this->auth($e, ['flow' => 'xheader', 'cred' => $_SERVER['HTTP_X_CIVI_AUTH'], 'siteKey' => $siteKey]); + } + + if (!empty($_SERVER['HTTP_AUTHORIZATION']) && !empty(\Civi::settings()->get('authx_header_cred'))) { + return $this->auth($e, ['flow' => 'header', 'cred' => $_SERVER['HTTP_AUTHORIZATION'], 'siteKey' => $siteKey]); + } + + if (!empty($params['_authx'])) { + if ((implode('/', $e->args) === 'civicrm/authx/login')) { + $this->auth($e, ['flow' => 'login', 'cred' => $params['_authx'], 'useSession' => TRUE, 'siteKey' => $siteKey]); + _authx_redact(['_authx']); + } + elseif (!empty($params['_authxSes'])) { + $this->auth($e, ['flow' => 'auto', 'cred' => $params['_authx'], 'useSession' => TRUE, 'siteKey' => $siteKey]); + if ($_SERVER['REQUEST_METHOD'] === 'GET') { + _authx_reload(implode('/', $e->args), $_SERVER['QUERY_STRING']); + } + else { + _authx_redact(['_authx', '_authxSes']); + } + } + else { + $this->auth($e, ['flow' => 'param', 'cred' => $params['_authx'], 'siteKey' => $siteKey]); + _authx_redact(['_authx']); + } + } + } /** * @var \Civi\Authx\AuthxInterface diff --git a/ext/authx/Civi/Authx/LegacyRestAuthenticator.php b/ext/authx/Civi/Authx/LegacyRestAuthenticator.php index aaf37892ca..26fbab54cb 100644 --- a/ext/authx/Civi/Authx/LegacyRestAuthenticator.php +++ b/ext/authx/Civi/Authx/LegacyRestAuthenticator.php @@ -11,6 +11,7 @@ namespace Civi\Authx; +use Civi\Core\Event\GenericHookEvent; use GuzzleHttp\Psr7\Response; /** @@ -21,9 +22,20 @@ use GuzzleHttp\Psr7\Response; * authentication style of 'extern/rest.php'. * * @package Civi\Authx + * @service authx.legacy_authenticator */ class LegacyRestAuthenticator extends Authenticator { + public function on_civi_invoke_auth(GenericHookEvent $e) { + // Accept legacy auth (?key=...&api_key=...) for 'civicrm/ajax/rest' and 'civicrm/ajax/api4/*'. + // The use of `?key=` could clash on some endpoints. Only accept on a small list of endpoints that are compatible with it. + if (count($e->args) > 2 && $e->args[1] === 'ajax' && in_array($e->args[2], ['rest', 'api4'])) { + if ((!empty($_REQUEST['api_key']) || !empty($_REQUEST['key']))) { + return $this->auth($e, ['flow' => 'legacyrest', 'cred' => 'Bearer ' . $_REQUEST['api_key'] ?? '', 'siteKey' => $_REQUEST['key'] ?? NULL]); + } + } + } + protected function reject($message = 'Authentication failed') { $data = ["error_message" => "FATAL: $message", "is_error" => 1]; $r = new Response(200, ['Content-Type' => 'text/javascript'], json_encode($data)); diff --git a/ext/authx/authx.php b/ext/authx/authx.php index 61fff6ed41..f6c50359a9 100644 --- a/ext/authx/authx.php +++ b/ext/authx/authx.php @@ -5,47 +5,6 @@ require_once 'authx.civix.php'; use CRM_Authx_ExtensionUtil as E; // phpcs:enable -Civi::dispatcher()->addListener('civi.invoke.auth', function($e) { - $params = ($_SERVER['REQUEST_METHOD'] === 'GET') ? $_GET : $_POST; - $siteKey = $_SERVER['HTTP_X_CIVI_KEY'] ?? $params['_authxSiteKey'] ?? NULL; - - if (!empty($_SERVER['HTTP_X_CIVI_AUTH'])) { - return (new \Civi\Authx\Authenticator())->auth($e, ['flow' => 'xheader', 'cred' => $_SERVER['HTTP_X_CIVI_AUTH'], 'siteKey' => $siteKey]); - } - - if (!empty($_SERVER['HTTP_AUTHORIZATION']) && !empty(Civi::settings()->get('authx_header_cred'))) { - return (new \Civi\Authx\Authenticator())->auth($e, ['flow' => 'header', 'cred' => $_SERVER['HTTP_AUTHORIZATION'], 'siteKey' => $siteKey]); - } - - if (!empty($params['_authx'])) { - if ((implode('/', $e->args) === 'civicrm/authx/login')) { - (new \Civi\Authx\Authenticator())->auth($e, ['flow' => 'login', 'cred' => $params['_authx'], 'useSession' => TRUE, 'siteKey' => $siteKey]); - _authx_redact(['_authx']); - } - elseif (!empty($params['_authxSes'])) { - (new \Civi\Authx\Authenticator())->auth($e, ['flow' => 'auto', 'cred' => $params['_authx'], 'useSession' => TRUE, 'siteKey' => $siteKey]); - if ($_SERVER['REQUEST_METHOD'] === 'GET') { - _authx_reload(implode('/', $e->args), $_SERVER['QUERY_STRING']); - } - else { - _authx_redact(['_authx', '_authxSes']); - } - } - else { - (new \Civi\Authx\Authenticator())->auth($e, ['flow' => 'param', 'cred' => $params['_authx'], 'siteKey' => $siteKey]); - _authx_redact(['_authx']); - } - } - - // Accept legacy auth (?key=...&api_key=...) for 'civicrm/ajax/rest' and 'civicrm/ajax/api4/*'. - // The use of `?key=` could clash on some endpoints. Only accept on a small list of endpoints that are compatible with it. - if (count($e->args) > 2 && $e->args[1] === 'ajax' && in_array($e->args[2], ['rest', 'api4'])) { - if ((!empty($_REQUEST['api_key']) || !empty($_REQUEST['key']))) { - return (new \Civi\Authx\LegacyRestAuthenticator())->auth($e, ['flow' => 'legacyrest', 'cred' => 'Bearer ' . $_REQUEST['api_key'] ?? '', 'siteKey' => $_REQUEST['key'] ?? NULL]); - } - } -}); - /** * Perform a system login. * -- 2.25.1