AssetBuilder - Define a fallback key (WEAK_SIGN) for sites that have not been configured
authorTim Otten <totten@civicrm.org>
Tue, 10 Jan 2023 01:07:57 +0000 (17:07 -0800)
committerTim Otten <totten@civicrm.org>
Tue, 10 Jan 2023 21:28:27 +0000 (13:28 -0800)
Civi/Core/AssetBuilder.php
Civi/Crypto/CryptoRegistry.php

index a671d8e7bad7d3bce29a4373e4a4537b1c5e7df1..69a4a57d78507a0ec87beca016c6db6da0dc4adb 100644 (file)
@@ -145,7 +145,7 @@ class AssetBuilder extends \Civi\Core\Service\AutoService {
           'asset' => [$name, $params],
           'exp' => 86400 * (floor(\CRM_Utils_Time::time() / 86400) + 2),
           // Caching-friendly TTL -- We want the URL to be stable for a decent amount of time.
-        ]),
+        ], ['SIGN', 'WEAK_SIGN']),
       ], TRUE, NULL, FALSE);
     }
   }
@@ -342,7 +342,7 @@ class AssetBuilder extends \Civi\Core\Service\AutoService {
       /** @var Assetbuilder $assets */
       $assets = \Civi::service('asset_builder');
 
-      $obj = \Civi::service('crypto.jwt')->decode($get['aj']);
+      $obj = \Civi::service('crypto.jwt')->decode($get['aj'], ['SIGN', 'WEAK_SIGN']);
       $arr = json_decode(json_encode($obj), TRUE);
       return $assets->render($arr['asset'][0], $arr['asset'][1]);
     }
index 0ae3d1afd20b0ccddc24827ac3d26d38c8bb0e7c..b45927c8fcb5391ab19de5e0dbe85f8d8b7cf9bb 100644 (file)
@@ -84,6 +84,31 @@ class CryptoRegistry {
         $registry->addSymmetricKey($registry->parseKey($keyExpr) + $key);
       }
     }
+    else {
+      // If you are upgrading an old site that does not have a signing key, then there is a status-check advising you to fix it.
+      // But apparently the current site hasn't fixed it yet. The UI+AssetBuilder need to work long enough for sysadmin to discover/resolve.
+      // This fallback is sufficient for short-term usage in limited scenarios (AssetBuilder=>OK; AuthX=>No).
+      // In a properly configured system, the WEAK_SIGN key is strictly unavailable - s.t. a normal site never uses WEAK_SIGN.
+      $registry->addSymmetricKey([
+        'tags' => ['WEAK_SIGN'],
+        'suite' => 'jwt-hs256',
+        'key' => hash_hkdf('sha256',
+          json_encode([
+            // DSN's and site-keys should usually be sufficient, but it's not strongly guaranteed,
+            // so we'll toss in more spaghetti. (At a minimum, this should mitigate bots/crawlers.)
+            \CRM_Utils_Constant::value('CIVICRM_DSN'),
+            \CRM_Utils_Constant::value('CIVICRM_UF_DSN'),
+            \CRM_Utils_Constant::value('CIVICRM_SITE_KEY') ?: $GLOBALS['civicrm_root'],
+            \CRM_Utils_Constant::value('CIVICRM_UF_BASEURL'),
+            \CRM_Utils_Constant::value('CIVICRM_DB_CACHE_PASSWORD'),
+            \CRM_Utils_System::getSiteID(),
+            \CRM_Utils_System::version(),
+            \CRM_Core_Config::singleton()->userSystem->getVersion(),
+            $_SERVER['HTTP_HOST'] ?? '',
+          ])
+        ),
+      ]);
+    }
 
     //if (isset($_COOKIE['CIVICRM_FORM_KEY'])) {
     //  $crypto->addSymmetricKey([
@@ -243,14 +268,15 @@ class CryptoRegistry {
   /**
    * Find all the keys that apply to a tag.
    *
-   * @param string $keyTag
+   * @param string|string[] $keyTag
    *
    * @return array
    *   List of keys, indexed by id, ordered by weight.
    */
   public function findKeysByTag($keyTag) {
+    $keyTag = (array) $keyTag;
     $keys = array_filter($this->keys, function ($key) use ($keyTag) {
-      return in_array($keyTag, $key['tags'] ?? []);
+      return !empty(array_intersect($keyTag, $key['tags'] ?? []));
     });
     uasort($keys, function($a, $b) {
       return ($a['weight'] ?? 0) - ($b['weight'] ?? 0);