You are here

class AcquiaSearchSolrService in Acquia Connector 7.3

Class AcquiaSearchSolrService.

Hierarchy

Expanded class hierarchy of AcquiaSearchSolrService

File

acquia_search/includes/AcquiaSearchSolrService.php, line 6

View source
class AcquiaSearchSolrService extends DrupalApacheSolrService {

  /**
   * {@inheritdoc}
   */
  public function makeServletRequest($servlet, $params = [], $options = []) {
    $params += [
      'wt' => 'json',
    ];
    $nonce = AcquiaSearchSolrCrypt::randomBytes(24);
    $url = $this
      ->_constructUrl($servlet, $params);
    $this
      ->prepareRequest($url, $options, $nonce);
    $response = $this
      ->_makeHttpRequest($url, $options);
    $response = $this
      ->checkResponse($response);
    return $this
      ->authenticateResponse($response, $nonce, $url);
  }

  /**
   * {@inheritdoc}
   */
  protected function _sendRawGet($url, $options = []) {

    // phpcs:ignore
    $nonce = AcquiaSearchSolrCrypt::randomBytes(24);
    $this
      ->prepareRequest($url, $options, $nonce);
    $response = $this
      ->_makeHttpRequest($url, $options);
    $response = $this
      ->checkResponse($response);
    return $this
      ->authenticateResponse($response, $nonce, $url);
  }

  /**
   * {@inheritdoc}
   */
  protected function _sendRawPost($url, $options = []) {

    // phpcs:ignore
    $options['method'] = 'POST';
    if (!isset($options['headers']['Content-Type'])) {
      $options['headers']['Content-Type'] = 'text/xml; charset=UTF-8';
    }
    $nonce = AcquiaSearchSolrCrypt::randomBytes(24);
    $this
      ->prepareRequest($url, $options, $nonce);
    $response = $this
      ->_makeHttpRequest($url, $options);
    $response = $this
      ->checkResponse($response);
    return $this
      ->authenticateResponse($response, $nonce, $url);
  }

  /**
   * Prepares request before send.
   *
   * @param string $url
   *   Request URL.
   * @param array $options
   *   Request options.
   * @param string $nonce
   *   Nonce.
   *
   * @throws \Exception
   */
  protected function prepareRequest(&$url, array &$options, $nonce) {
    $url = $this
      ->adjustUrl($url);
    if (!isset($options['headers'])) {
      $options['headers'] = [];
    }
    $string = !empty($options['data']) ? $options['data'] : NULL;
    $options['headers']['Cookie'] = $this
      ->createAuthCookie($url, $nonce, $string);
    $options['headers'] += $this
      ->addUserAgentHeader();
  }

  /**
   * Prepares URL parameters before request.
   *
   * @param string $url
   *   URL.
   *
   * @return string
   *   Adjusted URL.
   */
  protected function adjustUrl($url) {
    $url_components = parse_url($url);
    if (isset($url_components['scheme'])) {
      $url_components['scheme'] = sprintf('%s://', $url_components['scheme']);
    }
    if (!isset($url_components['query'])) {
      $url_components['query'] = '';
    }
    $query_pieces = drupal_get_query_array($url_components['query']);
    $query_pieces['request_id'] = uniqid();
    $query_string = drupal_http_build_query($query_pieces);
    $url_components['query'] = sprintf('?%s', $query_string);
    $url = implode('', $url_components);
    return $url;
  }

  /**
   * Builds user-agent header.
   *
   * @return array
   *   User-agent header.
   */
  protected function addUserAgentHeader() {
    $acquia_search_version = variable_get('acquia_search_solr_version', DRUPAL_CORE_COMPATIBILITY);
    $agent = sprintf('acquia_search_solr/%s', $acquia_search_version);
    return [
      'User-Agent' => $agent,
    ];
  }

  /**
   * Makes authentication checks.
   *
   * @param object $response
   *   Response object.
   * @param string $nonce
   *   Nonce.
   * @param string $url
   *   Request URL.
   *
   * @return mixed
   *   Throws exception in case of authentication check fail.
   *
   * @throws \Exception
   */
  protected function authenticateResponse($response, $nonce, $url) {
    $hmac = $this
      ->extractHmac($response->headers);
    if (!$this
      ->isValidResponse($hmac, $nonce, $response->data, NULL, $this->env_id)) {
      throw new Exception('Authentication of search content failed url: ' . $url);
    }
    return $response;
  }

  /**
   * Creates auth cookie.
   *
   * @param string $url
   *   Request URL.
   * @param string $nonce
   *   Nonce.
   * @param string $string
   *   Payload.
   *
   * @return string
   *   Cookie.
   */
  private function createAuthCookie($url, $nonce, $string = '') {
    if (!empty($string)) {
      $auth_string = $this
        ->buildAuthString($string, $nonce);
      return $auth_string;
    }
    $uri = parse_url($url);
    $path = isset($uri['path']) ? $uri['path'] : '/';
    $query = isset($uri['query']) ? '?' . $uri['query'] : '';
    $auth_string = $this
      ->buildAuthString($path . $query, $nonce);
    return $auth_string;
  }

  /**
   * Builds auth string.
   *
   * @param string $string
   *   Payload.
   * @param string $nonce
   *   Nonce.
   *
   * @return string
   *   Auth string.
   */
  private function buildAuthString($string, $nonce) {
    $api = _acquia_search_solr_get_api();
    if (empty($api)) {
      return '';
    }
    $preferredIndexService = $api
      ->getPreferredIndexService();
    if (empty($preferredIndexService
      ->isPreferredIndexAvailable())) {
      return '';
    }
    $index = $preferredIndexService
      ->getPreferredIndex();
    $derived_key = $this
      ->createDerivedKey($index['data']['product_policies']['salt'], $index['data']['key'], $index['data']['secret_key']);
    $hmac = hash_hmac('sha1', REQUEST_TIME . $nonce . $string, $derived_key);
    return sprintf('acquia_solr_time=%s; acquia_solr_nonce=%s; acquia_solr_hmac=%s;', REQUEST_TIME, $nonce, $hmac);
  }

  /**
   * Creates derived key.
   *
   * @param string $salt
   *   Key salt.
   * @param string $index_id
   *   Index ID.
   * @param string $key
   *   Secret key.
   *
   * @return string
   *   Derived key.
   */
  private function createDerivedKey($salt, $index_id, $key) {
    $pad_length = 80;
    $derivation_string = sprintf('%ssolr%s', $index_id, $salt);
    $data = str_pad($derivation_string, $pad_length, $derivation_string);
    $hmac = hash_hmac('sha1', $data, $key);
    return $hmac;
  }

  /**
   * Extracts HMAC value from headers.
   *
   * @param array $headers
   *   Headers list.
   *
   * @return string
   *   HMAC string.
   */
  private function extractHmac(array $headers) {
    $reg = [];
    if (is_array($headers)) {
      foreach ($headers as $name => $value) {
        if (strtolower($name) === 'pragma' && preg_match('/hmac_digest=([^;]+);/i', $value, $reg)) {
          return trim($reg[1]);
        }
      }
    }
    return '';
  }

  /**
   * Validates response.
   *
   * @param string $hmac
   *   HMAC string.
   * @param string $nonce
   *   Nonce.
   * @param string $string
   *   Payload.
   * @param string|null $derived_key
   *   Derived key.
   * @param string|null $env_id
   *   Search environment ID.
   *
   * @return bool
   *   TRUE if request is valid, otherwise - FALSE.
   */
  private function isValidResponse($hmac, $nonce, $string, $derived_key = NULL, $env_id = NULL) {
    if (empty($env_id)) {
      $env_id = apachesolr_default_environment();
    }
    if (empty($derived_key)) {
      $environment = apachesolr_environment_load($env_id);
      if (empty($environment['url'])) {
        return FALSE;
      }
      $index_id = substr($environment['url'], strrpos($environment['url'], '/') + 1);
      $api = _acquia_search_solr_get_api();
      if (empty($api)) {
        return FALSE;
      }
      $indexes = $api
        ->getIndexes();
      if (empty($indexes[$index_id]['data'])) {
        return FALSE;
      }
      $derived_key = $this
        ->createDerivedKey($indexes[$index_id]['data']['product_policies']['salt'], $indexes[$index_id]['data']['key'], $indexes[$index_id]['data']['secret_key']);
    }
    return $hmac === hash_hmac('sha1', $nonce . $string, $derived_key);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
AcquiaSearchSolrService::addUserAgentHeader protected function Builds user-agent header.
AcquiaSearchSolrService::adjustUrl protected function Prepares URL parameters before request.
AcquiaSearchSolrService::authenticateResponse protected function Makes authentication checks.
AcquiaSearchSolrService::buildAuthString private function Builds auth string.
AcquiaSearchSolrService::createAuthCookie private function Creates auth cookie.
AcquiaSearchSolrService::createDerivedKey private function Creates derived key.
AcquiaSearchSolrService::extractHmac private function Extracts HMAC value from headers.
AcquiaSearchSolrService::isValidResponse private function Validates response.
AcquiaSearchSolrService::makeServletRequest public function Make a request to a servlet (a path) that's not a standard path. Overrides DrupalApacheSolrService::makeServletRequest
AcquiaSearchSolrService::prepareRequest protected function Prepares request before send.
AcquiaSearchSolrService::_sendRawGet protected function Central method for making a GET operation against this Solr Server Overrides DrupalApacheSolrService::_sendRawGet
AcquiaSearchSolrService::_sendRawPost protected function Central method for making a POST operation against this Solr Server Overrides DrupalApacheSolrService::_sendRawPost
DrupalApacheSolrService::$env_id protected property
DrupalApacheSolrService::$luke protected property
DrupalApacheSolrService::$parsed_url protected property Server url
DrupalApacheSolrService::$soft_commit protected property Flag that denotes whether to use soft commits for Solr 4.x, defaults to FALSE.
DrupalApacheSolrService::$stats protected property
DrupalApacheSolrService::$system_info protected property
DrupalApacheSolrService::$update_url protected property Constructed servlet full path URLs
DrupalApacheSolrService::$_defaultTimeout protected property Default HTTP timeout when one is not specified (initialized to default_socket_timeout ini setting)
DrupalApacheSolrService::addDocuments public function Add an array of Solr Documents to the index all at once Overrides DrupalApacheSolrServiceInterface::addDocuments
DrupalApacheSolrService::checkResponse protected function Check the reponse code and thow an exception if it's not 200.
DrupalApacheSolrService::clearCache public function Clear cached Solr data. Overrides DrupalApacheSolrServiceInterface::clearCache
DrupalApacheSolrService::commit public function Send a commit command. Will be synchronous unless both wait parameters are set to false. Overrides DrupalApacheSolrServiceInterface::commit
DrupalApacheSolrService::deleteById public function Create a delete document based on document ID Overrides DrupalApacheSolrServiceInterface::deleteById
DrupalApacheSolrService::deleteByMultipleIds public function Create and post a delete document based on multiple document IDs. Overrides DrupalApacheSolrServiceInterface::deleteByMultipleIds
DrupalApacheSolrService::deleteByQuery public function Create a delete document based on a query and submit it Overrides DrupalApacheSolrServiceInterface::deleteByQuery
DrupalApacheSolrService::escape public static function Escape a value for special query characters such as ':', '(', ')', '*', '?', etc.
DrupalApacheSolrService::escapePhrase public static function Escape a value meant to be contained in a phrase for special query characters
DrupalApacheSolrService::findCaller public function Determine the routine that called this query.
DrupalApacheSolrService::getFields public function Get just the field meta-data about the index. Overrides DrupalApacheSolrServiceInterface::getFields
DrupalApacheSolrService::getId function Overrides DrupalApacheSolrServiceInterface::getId
DrupalApacheSolrService::getLuke public function Get meta-data about the index. Overrides DrupalApacheSolrServiceInterface::getLuke
DrupalApacheSolrService::getSoftCommit public function Returns the flag that denotes whether to use soft commits for Solr 4.x.
DrupalApacheSolrService::getSolrVersion public function Get the current solr version. This could be 1, 3 or 4 Overrides DrupalApacheSolrServiceInterface::getSolrVersion
DrupalApacheSolrService::getStats public function Get information about the Solr Core. Overrides DrupalApacheSolrServiceInterface::getStats
DrupalApacheSolrService::getStatsSummary public function Get summary information about the Solr Core. Overrides DrupalApacheSolrServiceInterface::getStatsSummary
DrupalApacheSolrService::getSystemInfo public function Get information about the Solr Core. Overrides DrupalApacheSolrServiceInterface::getSystemInfo
DrupalApacheSolrService::getUrl public function Get the Solr url Overrides DrupalApacheSolrServiceInterface::getUrl
DrupalApacheSolrService::httpBuildQuery protected function Like PHP's built in http_build_query(), but uses rawurlencode() and no [] for repeated params.
DrupalApacheSolrService::LUKE_SERVLET constant
DrupalApacheSolrService::NAMED_LIST_FORMAT constant How NamedLists should be formatted in the output. This specifically effects facet counts. Valid values are 'map' (default) or 'flat'.
DrupalApacheSolrService::optimize public function Send an optimize command. Will be synchronous unless both wait parameters are set to false. Overrides DrupalApacheSolrServiceInterface::optimize
DrupalApacheSolrService::phrase public static function Convenience function for creating phrase syntax from a value
DrupalApacheSolrService::ping public function Call the /admin/ping servlet, to test the connection to the server. Overrides DrupalApacheSolrServiceInterface::ping
DrupalApacheSolrService::PING_SERVLET constant Servlet mappings
DrupalApacheSolrService::search public function Simple Search interface Overrides DrupalApacheSolrServiceInterface::search
DrupalApacheSolrService::SEARCH_SERVLET constant
DrupalApacheSolrService::setLuke protected function Sets $this->luke with the meta-data about the index from admin/luke.
DrupalApacheSolrService::setSoftCommit public function Flags whether to use soft commits for Solr 4.x.
DrupalApacheSolrService::setStats protected function Sets $this->stats with the information about the Solr Core form
DrupalApacheSolrService::setSystemInfo protected function Call the /admin/system servlet
DrupalApacheSolrService::setUrl public function Set the Solr url. Overrides DrupalApacheSolrServiceInterface::setUrl
DrupalApacheSolrService::STATS_SERVLET constant
DrupalApacheSolrService::STATS_SERVLET_4 constant
DrupalApacheSolrService::SYSTEM_SERVLET constant
DrupalApacheSolrService::update public function Raw update Method. Takes a raw post body and sends it to the update service. Post body should be a complete and well formed xml document. Overrides DrupalApacheSolrServiceInterface::update
DrupalApacheSolrService::UPDATE_SERVLET constant
DrupalApacheSolrService::_clearCache protected function
DrupalApacheSolrService::_constructUrl protected function Return a valid http URL given this server's host, port and path and a provided servlet name
DrupalApacheSolrService::_makeHttpRequest protected function Central method for making the actual http request to the Solr Server
DrupalApacheSolrService::__construct public function Constructor Overrides DrupalApacheSolrServiceInterface::__construct