From f416cb6faa30b10bec99ec24f94fbe057aae9513 Mon Sep 17 00:00:00 2001
From: PatchRanger <Staratel@1209848.no-reply.drupal.org>
Date: Mon, 15 Jul 2013 18:43:17 +0700
Subject: [PATCH] Issue #2042205 by PatchRanger: Create plugin for Basic HTTP
 authentication

---
 http_client.info                              |    3 +-
 http_client_oauth.info                        |    9 --
 http_client_oauth.module                      |    2 -
 includes/HttpClientOAuth.inc                  |   76 -------------
 includes/HttpClientXMLFormatter.inc           |  144 -------------------------
 includes/auth/basic/HttpClientBasicAuth.inc   |   13 +++
 includes/auth/oauth/HttpClientOAuth.inc       |   76 +++++++++++++
 includes/auth/oauth/http_client_oauth.info    |    9 ++
 includes/auth/oauth/http_client_oauth.module  |    2 +
 includes/formatter/HttpClientXMLFormatter.inc |  144 +++++++++++++++++++++++++
 10 files changed, 246 insertions(+), 232 deletions(-)
 delete mode 100644 http_client_oauth.info
 delete mode 100644 http_client_oauth.module
 delete mode 100644 includes/HttpClientOAuth.inc
 delete mode 100644 includes/HttpClientXMLFormatter.inc
 create mode 100644 includes/auth/basic/HttpClientBasicAuth.inc
 create mode 100644 includes/auth/oauth/HttpClientOAuth.inc
 create mode 100644 includes/auth/oauth/http_client_oauth.info
 create mode 100644 includes/auth/oauth/http_client_oauth.module
 create mode 100644 includes/formatter/HttpClientXMLFormatter.inc

diff --git a/http_client.info b/http_client.info
index 5f7a1e1..75ceb12 100644
--- a/http_client.info
+++ b/http_client.info
@@ -2,8 +2,9 @@ name = Http Client
 description = Provides a Http client for use with the services Http server
 
 files[] = includes/HttpClient.inc
-files[] = includes/HttpClientXMLFormatter.inc
 files[] = includes/HttpClientCurlDelegate.inc
+files[] = includes/auth/basic/HttpClientBasicAuth.inc
+files[] = includes/formatter/HttpClientXMLFormatter.inc
 
 package = Services - clients
 core = 7.x
diff --git a/http_client_oauth.info b/http_client_oauth.info
deleted file mode 100644
index 5ad9163..0000000
--- a/http_client_oauth.info
+++ /dev/null
@@ -1,9 +0,0 @@
-name = Http Client OAuth
-description = Provides a OAuth authentication mechanism for the Http Client
-dependencies[] = oauth_common
-dependencies[] = http_client
-
-files[] = includes/HttpClientOAuth.inc
-
-package = Services - clients
-core = 7.x
diff --git a/http_client_oauth.module b/http_client_oauth.module
deleted file mode 100644
index 6000b73..0000000
--- a/http_client_oauth.module
+++ /dev/null
@@ -1,2 +0,0 @@
-<?php
-// All functionality is in includes/HttpClientOAuth.inc
diff --git a/includes/HttpClientOAuth.inc b/includes/HttpClientOAuth.inc
deleted file mode 100644
index e6e11da..0000000
--- a/includes/HttpClientOAuth.inc
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-
-class HttpClientOAuth implements HttpClientAuthentication {
-  private $consumer;
-  private $token;
-  private $sign;
-  private $signImpl;
-  private $hash_body;
-  private $header_auth;
-  private $realm;
-
-  public function __construct($consumer, $token = NULL, $sign_impl = NULL, $hash_body = TRUE, $header_auth = FALSE, $realm = NULL) {
-    $this->consumer = $consumer;
-    $this->token = $token;
-    $this->signImpl = $sign_impl;
-    $this->sign = is_object($sign_impl);
-    $this->hash_body = $hash_body;
-    $this->header_auth = $header_auth;
-    $this->realm = $realm;
-  }
-
-  /**
-   * Enables and disables request signing.
-   * N.B. Signing will always be disabled if no signing implementation was
-   * passed to the constructor.
-   *
-   * @param bool $sign
-   *  Set to FALSE to disable signing, TRUE to enable.
-   * @return void
-   */
-  public function signRequests($sign) {
-    $this->sign = $sign;
-  }
-
-  /**
-   * Used by the HttpClient to authenticate requests.
-   *
-   * @param HttpClientRequest $request
-   * @return void
-   */
-  public function authenticate($request) {
-    // Create a OAuth request object.
-    $req = OAuthRequest::from_consumer_and_token($this->consumer, $this->token,
-      $request->method, $request->url, $request->parameters);
-
-    if ($this->hash_body) {
-      // Add a body hash if applicable.
-      $content_type = $request->getHeader('Content-type', TRUE);
-      if (in_array($request->method, array('POST', 'PUT')) && $content_type !== 'application/x-www-form-urlencoded') {
-        $data = $request->data;
-        $data || $data = '';
-        $req->set_parameter('oauth_body_hash', base64_encode(sha1($data, TRUE)));
-      }
-    }
-
-    // Sign the request if we can and should.
-    if ($this->sign && $this->signImpl) {
-      $req->sign_request($this->signImpl, $this->consumer, $this->token);
-    }
-
-    // Make sure that we use the normalized url for the request
-    $request->url = $req->get_normalized_http_url();
-
-    // Transfer the parameters to the request objects
-    foreach ($req->get_parameters() as $key => $val) {
-      if (!$this->header_auth || substr($key, 0, 5) != 'oauth') {
-        $request->parameters[$key] = $val;
-      }
-    }
-
-    if ($this->header_auth) {
-      $auth_header = explode(':', $req->to_header($this->realm), 2);
-      $request->setHeader($auth_header[0], trim($auth_header[1]));
-    }
-  }
-}
diff --git a/includes/HttpClientXMLFormatter.inc b/includes/HttpClientXMLFormatter.inc
deleted file mode 100644
index 67ad1b8..0000000
--- a/includes/HttpClientXMLFormatter.inc
+++ /dev/null
@@ -1,144 +0,0 @@
-<?php
-
-/**
- * Class for handling xml-responses.
- * Returns a SimpleXML object
- *
- * @author Simon Ljungberg <simon.ljungberg@goodold.se>
- */
-
-class HttpClientXMLFormatter implements HttpClientFormatter {
-  private $adaptive_root;
-  private $default_root;
-
-  /**
-   * Creates a HttpClientXMLFormatter.
-   *
-   * @param string $default_root
-   *  Optional. Defaults to 'result'. The default name that should be used for root elements,
-   *  if $adaptive_root is set to FALSE the default name will always be used.
-   * @param bool $adaptive_root
-   *  Optional. Defaults to FALSE. If $adaptive_root is set to TRUE and the source data has a
-   *  single root attribute the serializer will use that attribute as root. The object {"foo":"bar"}
-   *  would be serialized to <foo>bar</foo> instead of <result><foo>bar</foo></result>.
-   */
-  public function __construct($default_root = 'result', $adaptive_root = FALSE) {
-    $this->default_root = $default_root;
-    $this->adaptive_root = $adaptive_root;
-  }
-
-  /**
-   * Serializes arbitrary data to the implemented format.
-   * Directly stolen from http_server by Hugo Wetterberg
-   *
-   * @param mixed $data
-   *  The data that should be serialized.
-   * @return string
-   *  The serialized data as a string.
-   */
-  public function serialize($data) {
-    $doc = new DOMDocument('1.0', 'utf-8');
-    $root_tag = $this->default_root;
-
-    // Normalize any objects into an array.
-    if (is_object($data)) {
-      $data = get_object_vars($data);
-    }
-    // Check if we should adapt the name of the root element.
-    if ($this->adaptive_root && is_array($data) && (count($data) == 1) && !is_numeric(key($data))) {
-      $root_tag = $this->sanitizeNodeName(key($data));
-      $data = current($data);
-    }
-
-    $root = $doc->createElement($root_tag);
-    $doc->appendChild($root);
-
-    $this->xml_recurse($doc, $root, $data);
-
-    return $doc->saveXML();
-  }
-
-  /**
-   * Sanitizes a string so that it's suitable for use as a element
-   * or attribute name.
-   *
-   * @param string $name
-   * @return string
-   *  The sanitized name.
-   */
-  private function sanitizeNodeName($name) {
-    $name = preg_replace('/[^A-Za-z0-9_]/', '_', $name);
-    return preg_replace('/^([0-9]+)/', '_$1', $name);
-  }
-
-  /**
-   * Return the mime type that the formatter can parse.
-   */
-  public function accepts(){
-    return $this->mimeType();
-  }
-
-  /**
-   * Return the content type form the data the formatter generates.
-   */
-  public function contentType(){
-    return $this->mimeType();
-  }
-
-  /**
-   * Unserializes data in the implemented format.
-   *
-   * @param string $data
-   *  The data that should be unserialized.
-   * @return mixed
-   *  The unserialized data.
-   */
-  public function unserialize($data) {
-    $xml = simplexml_load_string($data);
-
-    if ($xml instanceof SimpleXMLElement) {
-      // Only return data if we got well formed xml
-      return $xml;
-    }
-    else {
-      // Data was messed up
-      throw new InvalidArgumentException('XML response was malformed.');
-    }
-  }
-
-  public function mimeType() {
-    return 'application/xml';
-  }
-
-  /**
-   * Directly stolen from http_server by Hugo Wetterberg
-   */
-  protected function xml_recurse(&$doc, &$parent, $data) {
-    if (is_object($data)) {
-      $data = get_object_vars($data);
-    }
-
-    if (is_array($data)) {
-      $assoc = FALSE || empty($data);
-      foreach ($data as $key => $value) {
-        if (is_numeric($key)) {
-          $key = 'item';
-        }
-        else {
-          $assoc = TRUE;
-          $key = $this->sanitizeNodeName($key);
-        }
-        $element = $doc->createElement($key);
-        $parent->appendChild($element);
-        $this->xml_recurse($doc, $element, $value);
-      }
-
-      if (!$assoc) {
-        $parent->setAttribute('is_array', 'true');
-      }
-    }
-    else if ($data !== NULL) {
-      $parent->appendChild($doc->createTextNode($data));
-    }
-  }
-}
diff --git a/includes/auth/basic/HttpClientBasicAuth.inc b/includes/auth/basic/HttpClientBasicAuth.inc
new file mode 100644
index 0000000..b19d955
--- /dev/null
+++ b/includes/auth/basic/HttpClientBasicAuth.inc
@@ -0,0 +1,13 @@
+<?php
+
+class HttpClientBasicAuth implements HttpClientAuthentication {
+  function __construct($username, $password = NULL) {
+    $this->username = $username;
+    $this->password = $password;
+  }
+
+  public function authenticate($request) {
+    // Some API require only API-key with empty password.
+    $request->options['curlopts'][CURLOPT_USERPWD] = (!empty($this->password)) ? "{$this->username}:{$this->password}" : $this->username;
+  }
+}
diff --git a/includes/auth/oauth/HttpClientOAuth.inc b/includes/auth/oauth/HttpClientOAuth.inc
new file mode 100644
index 0000000..e6e11da
--- /dev/null
+++ b/includes/auth/oauth/HttpClientOAuth.inc
@@ -0,0 +1,76 @@
+<?php
+
+class HttpClientOAuth implements HttpClientAuthentication {
+  private $consumer;
+  private $token;
+  private $sign;
+  private $signImpl;
+  private $hash_body;
+  private $header_auth;
+  private $realm;
+
+  public function __construct($consumer, $token = NULL, $sign_impl = NULL, $hash_body = TRUE, $header_auth = FALSE, $realm = NULL) {
+    $this->consumer = $consumer;
+    $this->token = $token;
+    $this->signImpl = $sign_impl;
+    $this->sign = is_object($sign_impl);
+    $this->hash_body = $hash_body;
+    $this->header_auth = $header_auth;
+    $this->realm = $realm;
+  }
+
+  /**
+   * Enables and disables request signing.
+   * N.B. Signing will always be disabled if no signing implementation was
+   * passed to the constructor.
+   *
+   * @param bool $sign
+   *  Set to FALSE to disable signing, TRUE to enable.
+   * @return void
+   */
+  public function signRequests($sign) {
+    $this->sign = $sign;
+  }
+
+  /**
+   * Used by the HttpClient to authenticate requests.
+   *
+   * @param HttpClientRequest $request
+   * @return void
+   */
+  public function authenticate($request) {
+    // Create a OAuth request object.
+    $req = OAuthRequest::from_consumer_and_token($this->consumer, $this->token,
+      $request->method, $request->url, $request->parameters);
+
+    if ($this->hash_body) {
+      // Add a body hash if applicable.
+      $content_type = $request->getHeader('Content-type', TRUE);
+      if (in_array($request->method, array('POST', 'PUT')) && $content_type !== 'application/x-www-form-urlencoded') {
+        $data = $request->data;
+        $data || $data = '';
+        $req->set_parameter('oauth_body_hash', base64_encode(sha1($data, TRUE)));
+      }
+    }
+
+    // Sign the request if we can and should.
+    if ($this->sign && $this->signImpl) {
+      $req->sign_request($this->signImpl, $this->consumer, $this->token);
+    }
+
+    // Make sure that we use the normalized url for the request
+    $request->url = $req->get_normalized_http_url();
+
+    // Transfer the parameters to the request objects
+    foreach ($req->get_parameters() as $key => $val) {
+      if (!$this->header_auth || substr($key, 0, 5) != 'oauth') {
+        $request->parameters[$key] = $val;
+      }
+    }
+
+    if ($this->header_auth) {
+      $auth_header = explode(':', $req->to_header($this->realm), 2);
+      $request->setHeader($auth_header[0], trim($auth_header[1]));
+    }
+  }
+}
diff --git a/includes/auth/oauth/http_client_oauth.info b/includes/auth/oauth/http_client_oauth.info
new file mode 100644
index 0000000..126d780
--- /dev/null
+++ b/includes/auth/oauth/http_client_oauth.info
@@ -0,0 +1,9 @@
+name = Http Client OAuth
+description = Provides a OAuth authentication mechanism for the Http Client
+dependencies[] = oauth_common
+dependencies[] = http_client
+
+files[] = includes/auth/oauth/HttpClientOAuth.inc
+
+package = Services - clients
+core = 7.x
diff --git a/includes/auth/oauth/http_client_oauth.module b/includes/auth/oauth/http_client_oauth.module
new file mode 100644
index 0000000..6000b73
--- /dev/null
+++ b/includes/auth/oauth/http_client_oauth.module
@@ -0,0 +1,2 @@
+<?php
+// All functionality is in includes/HttpClientOAuth.inc
diff --git a/includes/formatter/HttpClientXMLFormatter.inc b/includes/formatter/HttpClientXMLFormatter.inc
new file mode 100644
index 0000000..67ad1b8
--- /dev/null
+++ b/includes/formatter/HttpClientXMLFormatter.inc
@@ -0,0 +1,144 @@
+<?php
+
+/**
+ * Class for handling xml-responses.
+ * Returns a SimpleXML object
+ *
+ * @author Simon Ljungberg <simon.ljungberg@goodold.se>
+ */
+
+class HttpClientXMLFormatter implements HttpClientFormatter {
+  private $adaptive_root;
+  private $default_root;
+
+  /**
+   * Creates a HttpClientXMLFormatter.
+   *
+   * @param string $default_root
+   *  Optional. Defaults to 'result'. The default name that should be used for root elements,
+   *  if $adaptive_root is set to FALSE the default name will always be used.
+   * @param bool $adaptive_root
+   *  Optional. Defaults to FALSE. If $adaptive_root is set to TRUE and the source data has a
+   *  single root attribute the serializer will use that attribute as root. The object {"foo":"bar"}
+   *  would be serialized to <foo>bar</foo> instead of <result><foo>bar</foo></result>.
+   */
+  public function __construct($default_root = 'result', $adaptive_root = FALSE) {
+    $this->default_root = $default_root;
+    $this->adaptive_root = $adaptive_root;
+  }
+
+  /**
+   * Serializes arbitrary data to the implemented format.
+   * Directly stolen from http_server by Hugo Wetterberg
+   *
+   * @param mixed $data
+   *  The data that should be serialized.
+   * @return string
+   *  The serialized data as a string.
+   */
+  public function serialize($data) {
+    $doc = new DOMDocument('1.0', 'utf-8');
+    $root_tag = $this->default_root;
+
+    // Normalize any objects into an array.
+    if (is_object($data)) {
+      $data = get_object_vars($data);
+    }
+    // Check if we should adapt the name of the root element.
+    if ($this->adaptive_root && is_array($data) && (count($data) == 1) && !is_numeric(key($data))) {
+      $root_tag = $this->sanitizeNodeName(key($data));
+      $data = current($data);
+    }
+
+    $root = $doc->createElement($root_tag);
+    $doc->appendChild($root);
+
+    $this->xml_recurse($doc, $root, $data);
+
+    return $doc->saveXML();
+  }
+
+  /**
+   * Sanitizes a string so that it's suitable for use as a element
+   * or attribute name.
+   *
+   * @param string $name
+   * @return string
+   *  The sanitized name.
+   */
+  private function sanitizeNodeName($name) {
+    $name = preg_replace('/[^A-Za-z0-9_]/', '_', $name);
+    return preg_replace('/^([0-9]+)/', '_$1', $name);
+  }
+
+  /**
+   * Return the mime type that the formatter can parse.
+   */
+  public function accepts(){
+    return $this->mimeType();
+  }
+
+  /**
+   * Return the content type form the data the formatter generates.
+   */
+  public function contentType(){
+    return $this->mimeType();
+  }
+
+  /**
+   * Unserializes data in the implemented format.
+   *
+   * @param string $data
+   *  The data that should be unserialized.
+   * @return mixed
+   *  The unserialized data.
+   */
+  public function unserialize($data) {
+    $xml = simplexml_load_string($data);
+
+    if ($xml instanceof SimpleXMLElement) {
+      // Only return data if we got well formed xml
+      return $xml;
+    }
+    else {
+      // Data was messed up
+      throw new InvalidArgumentException('XML response was malformed.');
+    }
+  }
+
+  public function mimeType() {
+    return 'application/xml';
+  }
+
+  /**
+   * Directly stolen from http_server by Hugo Wetterberg
+   */
+  protected function xml_recurse(&$doc, &$parent, $data) {
+    if (is_object($data)) {
+      $data = get_object_vars($data);
+    }
+
+    if (is_array($data)) {
+      $assoc = FALSE || empty($data);
+      foreach ($data as $key => $value) {
+        if (is_numeric($key)) {
+          $key = 'item';
+        }
+        else {
+          $assoc = TRUE;
+          $key = $this->sanitizeNodeName($key);
+        }
+        $element = $doc->createElement($key);
+        $parent->appendChild($element);
+        $this->xml_recurse($doc, $element, $value);
+      }
+
+      if (!$assoc) {
+        $parent->setAttribute('is_array', 'true');
+      }
+    }
+    else if ($data !== NULL) {
+      $parent->appendChild($doc->createTextNode($data));
+    }
+  }
+}
-- 
1.7.9.5

