authx - Allow `civicrm/ajax/rest` to accept auth params akin to `extern/rest.php`
authorTim Otten <totten@civicrm.org>
Thu, 4 Mar 2021 09:25:20 +0000 (01:25 -0800)
committerTim Otten <totten@civicrm.org>
Mon, 24 Jan 2022 21:53:49 +0000 (13:53 -0800)
ext/authx/Civi/Authx/LegacyRestAuthenticator.php [new file with mode: 0644]
ext/authx/authx.php
ext/authx/settings/authx.setting.php
tests/phpunit/E2E/Extern/AuthxRestTest.php [new file with mode: 0644]

diff --git a/ext/authx/Civi/Authx/LegacyRestAuthenticator.php b/ext/authx/Civi/Authx/LegacyRestAuthenticator.php
new file mode 100644 (file)
index 0000000..aaf3789
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Authx;
+
+use GuzzleHttp\Psr7\Response;
+
+/**
+ * Historically, 'extern/rest.php' and 'civicrm/ajax/rest' were similar interfaces
+ * based on the same controller, but they used different authentication styles.
+ *
+ * This authenticator is activated if one requests 'civicrm/ajax/rest' using the
+ * authentication style of 'extern/rest.php'.
+ *
+ * @package Civi\Authx
+ */
+class LegacyRestAuthenticator extends Authenticator {
+
+  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));
+    \CRM_Utils_System::sendResponse($r);
+  }
+
+  protected function login(AuthenticatorTarget $tgt) {
+    parent::login($tgt);
+    \Civi::dispatcher()->addListener('hook_civicrm_permission_check', function ($e) {
+      if ($e->permission === 'access AJAX API') {
+        $e->granted = TRUE;
+      }
+    });
+  }
+
+}
index 25fe959f4c37ddce5b238e5780010f2974a8a16a..81b25c11df64f323d1b5460bc4540b0568f8b177 100644 (file)
@@ -36,6 +36,10 @@ Civi::dispatcher()->addListener('civi.invoke.auth', function($e) {
       _authx_redact(['_authx']);
     }
   }
+
+  if (count($e->args) > 2 && $e->args[1] === 'ajax' && $e->args[2] === 'rest' && (!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]);
+  }
 });
 
 /**
index 81ed26587c31c86c0ed2460c0d24a9b579a0831b..4745d06e45436c32f4462777f508780ade6e3f04 100644 (file)
@@ -17,7 +17,7 @@ use CRM_Authx_ExtensionUtil as E;
  * @copyright CiviCRM LLC https://civicrm.org/licensing
  */
 $_authx_settings = function() {
-  $flows = ['param', 'header', 'xheader', 'login', 'auto', 'script', 'pipe'];
+  $flows = ['param', 'header', 'xheader', 'login', 'auto', 'script', 'pipe', 'legacyrest'];
   $basic = [
     'group_name' => 'CiviCRM Preferences',
     'group' => 'authx',
@@ -77,6 +77,9 @@ $_authx_settings = function() {
     ];
   }
 
+  // Override defaults for a few specific elements
+  $s['authx_legacyrest_cred']['default'] = ['jwt', 'api_key'];
+  $s['authx_legacyrest_user']['default'] = 'require';
   $s['authx_param_cred']['default'] = ['jwt', 'api_key'];
   $s['authx_header_cred']['default'] = ['jwt', 'api_key'];
   $s['authx_xheader_cred']['default'] = ['jwt', 'api_key'];
diff --git a/tests/phpunit/E2E/Extern/AuthxRestTest.php b/tests/phpunit/E2E/Extern/AuthxRestTest.php
new file mode 100644 (file)
index 0000000..ef38cad
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Verify that the REST API bindings correctly parse and authenticate requests.
+ *
+ * @group e2e
+ */
+class E2E_Extern_AuthxRestTest extends E2E_Extern_BaseRestTest {
+
+  public static function setUpBeforeClass() {
+    parent::setUpBeforeClass();
+    \Civi\Test::e2e()
+      ->install(['authx'])
+      ->callback(
+        function() {
+          \CRM_Utils_System::synchronizeUsers();
+        },
+        'synchronizeUsers'
+      )
+      ->apply();
+  }
+
+  protected function getRestUrl() {
+    return CRM_Utils_System::url('civicrm/ajax/rest', NULL, TRUE, NULL, FALSE, TRUE);
+  }
+
+  public function apiTestCases() {
+    $r = parent::apiTestCases();
+    $r = array_filter($r, function($case) {
+      // The 'civicrm/ajax/rest' end-point does not support '?q' inputs.
+      return !isset($case[0]['q']);
+    });
+    return $r;
+  }
+
+}