/** * @param $data * @param $message * @return bool */ public function isValidRequest($data, $message) { $key = $this->config('acquia_connector.settings')->get('key'); if (!isset($data['authenticator']) || !isset($data['authenticator']['time']) || !isset($data['authenticator']['nonce'])) { return FALSE; } $string = $data['authenticator']['time'] . ':' . $data['authenticator']['nonce'] . ':' . $message; $hash = CryptConnector::acquiaHash($key, $string); if ($hash == $data['authenticator']['hash']) { return TRUE; } else { return FALSE; } }
/** * {@inheritdoc} */ protected function setUp() { // Generate and store a random set of credentials. // Make them as close to the production values as possible // Something like AAAA-1234 $this->id = $this->randomMachineName(10); // Most of the keys and salts have a 32char lenght $this->key = $this->randomMachineName(32); $this->salt = $this->randomMachineName(32); // Include Solarium autoloader. $dirs = drupal_phpunit_contrib_extension_directory_roots(); $extensions = []; foreach ($dirs as $path) { $extensions += drupal_phpunit_find_extension_directories($path); } require_once $extensions['search_api_solr'] . '/vendor/autoload.php'; unset($extensions); $this->searchSubscriber = new SearchSubscriber(); $this->derivedKey = CryptConnector::createDerivedKey($this->salt, $this->id, $this->key); }
/** * @param array $data * @return array */ protected function validateAuthenticator($data) { $fields = array('time' => 'is_numeric', 'identifier' => 'is_string', 'nonce' => 'is_string', 'hash' => 'is_string'); $result = $this->basicAuthenticator($fields, $data); if (!empty($result['error'])) { return $result; } if (strpos($data['authenticator']['identifier'], 'TEST_') !== 0) { return $this->errorResponse(self::ACQTEST_SUBSCRIPTION_NOT_FOUND, t('Subscription not found')); } switch ($data['authenticator']['identifier']) { case self::ACQTEST_ID: $key = self::ACQTEST_KEY; break; case self::ACQTEST_EXPIRED_ID: $key = self::ACQTEST_EXPIRED_KEY; break; case self::ACQTEST_503_ID: $key = self::ACQTEST_503_KEY; break; default: $key = self::ACQTEST_ERROR_KEY; break; } $hash = CryptConnector::acquiaHash($key, $data['authenticator']['time'] . ':' . $data['authenticator']['nonce']); $hash_simple = CryptConnector::acquiaHash($key, $data['authenticator']['time'] . ':' . $data['authenticator']['nonce']); if ($hash !== $data['authenticator']['hash'] && $hash_simple != $data['authenticator']['hash']) { return $this->errorResponse(self::ACQTEST_SUBSCRIPTION_VALIDATION_ERROR, t('HMAC validation error: ') . "{$hash} != {$data['authenticator']['hash']}"); } if ($key === self::ACQTEST_EXPIRED_KEY) { return $this->errorResponse(self::ACQTEST_SUBSCRIPTION_EXPIRED, t('Subscription expired.')); } // Record connections. $connections = \Drupal::config('acquia_connector.settings')->get('test_connections' . $data['authenticator']['identifier']); $connections++; \Drupal::configFactory()->getEditable('acquia_connector.settings')->set('test_connections' . $data['authenticator']['identifier'], $connections)->save(); if ($connections == 3 && $data['authenticator']['identifier'] == self::ACQTEST_503_ID) { // Trigger a 503 response on 3rd call to this (1st is // acquia.agent.subscription and 2nd is acquia.agent.validate) $this->headers->set("Status", "503 Server Error"); print ''; exit; } $result['error'] = FALSE; $result['body']['subscription_name'] = 'TEST_AcquiaConnectorTestID'; $result['body']['active'] = 1; $result['body']['href'] = 'http://acquia.com/network'; $result['body']['expiration_date']['value'] = '2023-10-08T06:30:00'; $result['body']['product'] = '91990'; $result['body']['derived_key_salt'] = $data['authenticator']['identifier'] . '_KEY_SALT'; $result['body']['update_service'] = 1; $result['body']['search_service_enabled'] = 1; if (isset($data['body']['rpc_version'])) { $result['body']['rpc_version'] = $data['body']['rpc_version']; } $result['secret']['data'] = $data; $result['secret']['nid'] = '91990'; $result['secret']['node'] = $data['authenticator']['identifier'] . '_NODE'; $result['secret']['key'] = $key; //$result['secret']['nonce'] = ''; $result['authenticator'] = $data['authenticator']; $result['authenticator']['hash'] = ''; $result['authenticator']['time'] += 1; $result['authenticator']['nonce'] = $data['authenticator']['nonce']; return $result; }
/** * Get the derived key for the solr hmac using the information shared with acquia.com. * @param null $env_id * @return mixed */ public function getDerivedKey($env_id = NULL) { if (empty($env_id)) { $env_id = $this->client->getEndpoint()->getKey(); } if (!isset($this->derived_key[$env_id])) { // If we set an explicit environment, check if this needs to overridden // Use the default $identifier = \Drupal::config('acquia_connector.settings')->get('identifier'); $key = \Drupal::config('acquia_connector.settings')->get('key'); // See if we need to overwrite these values // In any case, this is equal for all subscriptions. Also // even if the search sub is different, the main subscription should be // active $derived_key_salt = $this->getDerivedKeySalt(); // We use a salt from acquia.com in key derivation since this is a shared // value that we could change on the AN side if needed to force any // or all clients to use a new derived key. We also use a string // ('solr') specific to the service, since we want each service using a // derived key to have a separate one. if (empty($derived_key_salt) || empty($key) || empty($identifier)) { // Expired or invalid subscription - don't continue. $this->derived_key[$env_id] = ''; } elseif (!isset($derived_key[$env_id])) { $this->derived_key[$env_id] = CryptConnector::createDerivedKey($derived_key_salt, $identifier, $key); } } return $this->derived_key[$env_id]; }
/** * Calculates a HMAC-SHA1 according to RFC2104 (http://www.ietf.org/rfc/rfc2104.txt). * * @param string $key * @param int $time * @param string $nonce * @param array $params * @return string */ protected function hash($key, $time, $nonce, $params = array()) { $string = $time . ':' . $nonce; return CryptConnector::acquiaHash($key, $string); }