|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_Gdata |
|
17 * @subpackage Gdata |
|
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: HttpClient.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
21 */ |
|
22 |
|
23 /** |
|
24 * Zend_Http_Client |
|
25 */ |
|
26 require_once 'Zend/Http/Client.php'; |
|
27 |
|
28 /** |
|
29 * Gdata Http Client object. |
|
30 * |
|
31 * Class to extend the generic Zend Http Client with the ability to perform |
|
32 * secure AuthSub requests |
|
33 * |
|
34 * @category Zend |
|
35 * @package Zend_Gdata |
|
36 * @subpackage Gdata |
|
37 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
38 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
39 */ |
|
40 class Zend_Gdata_HttpClient extends Zend_Http_Client |
|
41 { |
|
42 |
|
43 /** |
|
44 * OpenSSL private key resource id |
|
45 * This key is used for AuthSub authentication. If this value is set, |
|
46 * it is assuemd that secure AuthSub is desired. |
|
47 * |
|
48 * @var resource |
|
49 */ |
|
50 private $_authSubPrivateKeyId = null; |
|
51 |
|
52 /** |
|
53 * Token for AuthSub authentication. |
|
54 * If this token is set, AuthSub authentication is used. |
|
55 * |
|
56 * @var string |
|
57 */ |
|
58 private $_authSubToken = null; |
|
59 |
|
60 /** |
|
61 * Token for ClientLogin authentication. |
|
62 * If only this token is set, ClientLogin authentication is used. |
|
63 * |
|
64 * @var string |
|
65 */ |
|
66 private $_clientLoginToken = null; |
|
67 |
|
68 /** |
|
69 * Token for ClientLogin authentication. |
|
70 * If this token is set, and the AuthSub key is not set, |
|
71 * ClientLogin authentication is used |
|
72 * |
|
73 * @var string |
|
74 */ |
|
75 private $_clientLoginKey = null; |
|
76 |
|
77 /** |
|
78 * True if this request is being made with data supplied by |
|
79 * a stream object instead of a raw encoded string. |
|
80 * |
|
81 * @var bool |
|
82 */ |
|
83 protected $_streamingRequest = null; |
|
84 |
|
85 /** |
|
86 * Sets the PEM formatted private key, as read from a file. |
|
87 * |
|
88 * This method reads the file and then calls setAuthSubPrivateKey() |
|
89 * with the file contents. |
|
90 * |
|
91 * @param string $file The location of the file containing the PEM key |
|
92 * @param string $passphrase The optional private key passphrase |
|
93 * @param bool $useIncludePath Whether to search the include_path |
|
94 * for the file |
|
95 * @return void |
|
96 */ |
|
97 public function setAuthSubPrivateKeyFile($file, $passphrase = null, |
|
98 $useIncludePath = false) { |
|
99 $fp = @fopen($file, "r", $useIncludePath); |
|
100 if (!$fp) { |
|
101 require_once 'Zend/Gdata/App/InvalidArgumentException.php'; |
|
102 throw new Zend_Gdata_App_InvalidArgumentException('Failed to open private key file for AuthSub.'); |
|
103 } |
|
104 |
|
105 $key = ''; |
|
106 while (!feof($fp)) { |
|
107 $key .= fread($fp, 8192); |
|
108 } |
|
109 $this->setAuthSubPrivateKey($key, $passphrase); |
|
110 fclose($fp); |
|
111 } |
|
112 |
|
113 /** |
|
114 * Sets the PEM formatted private key to be used for secure AuthSub auth. |
|
115 * |
|
116 * In order to call this method, openssl must be enabled in your PHP |
|
117 * installation. Otherwise, a Zend_Gdata_App_InvalidArgumentException |
|
118 * will be thrown. |
|
119 * |
|
120 * @param string $key The private key |
|
121 * @param string $passphrase The optional private key passphrase |
|
122 * @throws Zend_Gdata_App_InvalidArgumentException |
|
123 * @return Zend_Gdata_HttpClient Provides a fluent interface |
|
124 */ |
|
125 public function setAuthSubPrivateKey($key, $passphrase = null) { |
|
126 if ($key != null && !function_exists('openssl_pkey_get_private')) { |
|
127 require_once 'Zend/Gdata/App/InvalidArgumentException.php'; |
|
128 throw new Zend_Gdata_App_InvalidArgumentException( |
|
129 'You cannot enable secure AuthSub if the openssl module ' . |
|
130 'is not enabled in your PHP installation.'); |
|
131 } |
|
132 $this->_authSubPrivateKeyId = openssl_pkey_get_private( |
|
133 $key, $passphrase); |
|
134 return $this; |
|
135 } |
|
136 |
|
137 /** |
|
138 * Gets the openssl private key id |
|
139 * |
|
140 * @return string The private key |
|
141 */ |
|
142 public function getAuthSubPrivateKeyId() { |
|
143 return $this->_authSubPrivateKeyId; |
|
144 } |
|
145 |
|
146 /** |
|
147 * Gets the AuthSub token used for authentication |
|
148 * |
|
149 * @return string The token |
|
150 */ |
|
151 public function getAuthSubToken() { |
|
152 return $this->_authSubToken; |
|
153 } |
|
154 |
|
155 /** |
|
156 * Sets the AuthSub token used for authentication |
|
157 * |
|
158 * @param string $token The token |
|
159 * @return Zend_Gdata_HttpClient Provides a fluent interface |
|
160 */ |
|
161 public function setAuthSubToken($token) { |
|
162 $this->_authSubToken = $token; |
|
163 return $this; |
|
164 } |
|
165 |
|
166 /** |
|
167 * Gets the ClientLogin token used for authentication |
|
168 * |
|
169 * @return string The token |
|
170 */ |
|
171 public function getClientLoginToken() { |
|
172 return $this->_clientLoginToken; |
|
173 } |
|
174 |
|
175 /** |
|
176 * Sets the ClientLogin token used for authentication |
|
177 * |
|
178 * @param string $token The token |
|
179 * @return Zend_Gdata_HttpClient Provides a fluent interface |
|
180 */ |
|
181 public function setClientLoginToken($token) { |
|
182 $this->_clientLoginToken = $token; |
|
183 return $this; |
|
184 } |
|
185 |
|
186 /** |
|
187 * Filters the HTTP requests being sent to add the Authorization header. |
|
188 * |
|
189 * If both AuthSub and ClientLogin tokens are set, |
|
190 * AuthSub takes precedence. If an AuthSub key is set, then |
|
191 * secure AuthSub authentication is used, and the request is signed. |
|
192 * Requests must be signed only with the private key corresponding to the |
|
193 * public key registered with Google. If an AuthSub key is set, but |
|
194 * openssl support is not enabled in the PHP installation, an exception is |
|
195 * thrown. |
|
196 * |
|
197 * @param string $method The HTTP method |
|
198 * @param string $url The URL |
|
199 * @param array $headers An associate array of headers to be |
|
200 * sent with the request or null |
|
201 * @param string $body The body of the request or null |
|
202 * @param string $contentType The MIME content type of the body or null |
|
203 * @throws Zend_Gdata_App_Exception if there was a signing failure |
|
204 * @return array The processed values in an associative array, |
|
205 * using the same names as the params |
|
206 */ |
|
207 public function filterHttpRequest($method, $url, $headers = array(), $body = null, $contentType = null) { |
|
208 if ($this->getAuthSubToken() != null) { |
|
209 // AuthSub authentication |
|
210 if ($this->getAuthSubPrivateKeyId() != null) { |
|
211 // secure AuthSub |
|
212 $time = time(); |
|
213 $nonce = mt_rand(0, 999999999); |
|
214 $dataToSign = $method . ' ' . $url . ' ' . $time . ' ' . $nonce; |
|
215 |
|
216 // compute signature |
|
217 $pKeyId = $this->getAuthSubPrivateKeyId(); |
|
218 $signSuccess = openssl_sign($dataToSign, $signature, $pKeyId, |
|
219 OPENSSL_ALGO_SHA1); |
|
220 if (!$signSuccess) { |
|
221 require_once 'Zend/Gdata/App/Exception.php'; |
|
222 throw new Zend_Gdata_App_Exception( |
|
223 'openssl_signing failure - returned false'); |
|
224 } |
|
225 // encode signature |
|
226 $encodedSignature = base64_encode($signature); |
|
227 |
|
228 // final header |
|
229 $headers['authorization'] = 'AuthSub token="' . $this->getAuthSubToken() . '" ' . |
|
230 'data="' . $dataToSign . '" ' . |
|
231 'sig="' . $encodedSignature . '" ' . |
|
232 'sigalg="rsa-sha1"'; |
|
233 } else { |
|
234 // AuthSub without secure tokens |
|
235 $headers['authorization'] = 'AuthSub token="' . $this->getAuthSubToken() . '"'; |
|
236 } |
|
237 } elseif ($this->getClientLoginToken() != null) { |
|
238 $headers['authorization'] = 'GoogleLogin auth=' . $this->getClientLoginToken(); |
|
239 } |
|
240 return array('method' => $method, 'url' => $url, 'body' => $body, 'headers' => $headers, 'contentType' => $contentType); |
|
241 } |
|
242 |
|
243 /** |
|
244 * Method for filtering the HTTP response, though no filtering is |
|
245 * currently done. |
|
246 * |
|
247 * @param Zend_Http_Response $response The response object to filter |
|
248 * @return Zend_Http_Response The filterd response object |
|
249 */ |
|
250 public function filterHttpResponse($response) { |
|
251 return $response; |
|
252 } |
|
253 |
|
254 /** |
|
255 * Return the current connection adapter |
|
256 * |
|
257 * @return Zend_Http_Client_Adapter_Interface|string $adapter |
|
258 */ |
|
259 public function getAdapter() |
|
260 { |
|
261 return $this->adapter; |
|
262 } |
|
263 |
|
264 /** |
|
265 * Load the connection adapter |
|
266 * |
|
267 * @param Zend_Http_Client_Adapter_Interface $adapter |
|
268 * @return void |
|
269 */ |
|
270 public function setAdapter($adapter) |
|
271 { |
|
272 if ($adapter == null) { |
|
273 $this->adapter = $adapter; |
|
274 } else { |
|
275 parent::setAdapter($adapter); |
|
276 } |
|
277 } |
|
278 |
|
279 /** |
|
280 * Set the streamingRequest variable which controls whether we are |
|
281 * sending the raw (already encoded) POST data from a stream source. |
|
282 * |
|
283 * @param boolean $value The value to set. |
|
284 * @return void |
|
285 */ |
|
286 public function setStreamingRequest($value) |
|
287 { |
|
288 $this->_streamingRequest = $value; |
|
289 } |
|
290 |
|
291 /** |
|
292 * Check whether the client is set to perform streaming requests. |
|
293 * |
|
294 * @return boolean True if yes, false otherwise. |
|
295 */ |
|
296 public function getStreamingRequest() |
|
297 { |
|
298 if ($this->_streamingRequest()) { |
|
299 return true; |
|
300 } else { |
|
301 return false; |
|
302 } |
|
303 } |
|
304 |
|
305 /** |
|
306 * Prepare the request body (for POST and PUT requests) |
|
307 * |
|
308 * @return string |
|
309 * @throws Zend_Http_Client_Exception |
|
310 */ |
|
311 protected function _prepareBody() |
|
312 { |
|
313 if($this->_streamingRequest) { |
|
314 $this->setHeaders(self::CONTENT_LENGTH, |
|
315 $this->raw_post_data->getTotalSize()); |
|
316 return $this->raw_post_data; |
|
317 } |
|
318 else { |
|
319 return parent::_prepareBody(); |
|
320 } |
|
321 } |
|
322 |
|
323 /** |
|
324 * Clear all custom parameters we set. |
|
325 * |
|
326 * @return Zend_Http_Client |
|
327 */ |
|
328 public function resetParameters($clearAll = false) |
|
329 { |
|
330 $this->_streamingRequest = false; |
|
331 |
|
332 return parent::resetParameters($clearAll); |
|
333 } |
|
334 |
|
335 /** |
|
336 * Set the raw (already encoded) POST data from a stream source. |
|
337 * |
|
338 * This is used to support POSTing from open file handles without |
|
339 * caching the entire body into memory. It is a wrapper around |
|
340 * Zend_Http_Client::setRawData(). |
|
341 * |
|
342 * @param string $data The request data |
|
343 * @param string $enctype The encoding type |
|
344 * @return Zend_Http_Client |
|
345 */ |
|
346 public function setRawDataStream($data, $enctype = null) |
|
347 { |
|
348 $this->_streamingRequest = true; |
|
349 return $this->setRawData($data, $enctype); |
|
350 } |
|
351 |
|
352 } |