/** * Sorts and normalizes request data and oauthValues. * * Section 9.1.1 of Oauth spec. * * - URL encode keys + values. * - Sort keys & values by byte value. * * @param \Cake\Network\Http\Request $request The request object. * @param array $oauthValues Oauth values. * * @return string sorted and normalized values */ protected function _normalizedParams($request, $oauthValues) { $query = parse_url($request->url(), PHP_URL_QUERY); parse_str($query, $queryArgs); $post = []; $body = $request->body(); if (is_string($body) && $request->getHeaderLine('content-type') === 'application/x-www-form-urlencoded') { parse_str($body, $post); } if (is_array($body)) { $post = $body; } $args = array_merge($queryArgs, $oauthValues, $post); uksort($args, 'strcmp'); $pairs = []; foreach ($args as $k => $val) { if (is_array($val)) { sort($val, SORT_STRING); foreach ($val as $nestedVal) { $pairs[] = "{$k}={$nestedVal}"; } } else { $val = rawurlencode($val); // Required for Twitter signatures $pairs[] = "{$k}={$val}"; } } return implode('&', $pairs); }
/** * Add Authorization header to the request. * * @param \Cake\Network\Http\Request $request Request instance. * @param array $credentials Credentials. * @return void * @see http://www.ietf.org/rfc/rfc2617.txt */ public function authentication(Request $request, array $credentials) { if (isset($credentials['encoding']) && $credentials['encoding'] === 'url') { $url = $request->url(); $urlEncoding = $this->_getUrlEncoding($credentials['key'], $credentials['shared_secret'], $url, $credentials['actor']); $request->header('Authorization', $urlEncoding); } else { if (isset($credentials['key'], $credentials['shared_secret'])) { $nonce = $this->_getNonce($credentials['key'], $credentials['shared_secret']); $request->header('Authorization', $nonce); } } }
/** * {@inheritdoc} */ protected function sendInternalRequest(InternalRequestInterface $internalRequest) { $request = new Request(); foreach ($this->prepareHeaders($internalRequest) as $name => $value) { $request->header($name, $value); } $request->method($internalRequest->getMethod()); $request->body($this->prepareBody($internalRequest)); $request->url($uri = (string) $internalRequest->getUri()); $request->version($this->getConfiguration()->getProtocolVersion()); try { $response = $this->client->send($request, array('timeout' => $this->getConfiguration()->getTimeout(), 'redirect' => false)); } catch (\Exception $e) { throw HttpAdapterException::cannotFetchUri($uri, $this->getName(), $e->getMessage()); } return $this->getConfiguration()->getMessageFactory()->createResponse((int) $response->statusCode(), $response->version(), $response->headers(), $response->body()); }
/** * {@inheritdoc} */ public function sendRequest(RequestInterface $request) { $cakeRequest = new Request(); $cakeRequest->method($request->getMethod()); $cakeRequest->url((string) $request->getUri()); $cakeRequest->version($request->getProtocolVersion()); $cakeRequest->body($request->getBody()->getContents()); foreach ($request->getHeaders() as $header => $values) { $cakeRequest->header($header, $request->getHeaderLine($header)); } if (null === $cakeRequest->header('Content-Type')) { $cakeRequest->header('Content-Type', 'application/x-www-form-urlencoded'); } try { $cakeResponse = $this->client->send($cakeRequest, $this->client->config()); } catch (Exception $exception) { throw new NetworkException('Failed to send request', $request, $exception); } return $this->responseFactory->createResponse($cakeResponse->statusCode(), null, $cakeResponse->headers(), $cakeResponse->body(), $cakeResponse->version()); }
/** * Generate the header Authorization * * @param \Cake\Network\Http\Request $request The request object. * @param array $credentials Authentication credentials. * @return string */ protected function _generateHeader(Request $request, $credentials) { $path = parse_url($request->url(), PHP_URL_PATH); $a1 = md5($credentials['username'] . ':' . $credentials['realm'] . ':' . $credentials['password']); $a2 = md5($request->method() . ':' . $path); if (empty($credentials['qop'])) { $response = md5($a1 . ':' . $credentials['nonce'] . ':' . $a2); } else { $credentials['cnonce'] = uniqid(); $nc = sprintf('%08x', $credentials['nc']++); $response = md5($a1 . ':' . $credentials['nonce'] . ':' . $nc . ':' . $credentials['cnonce'] . ':auth:' . $a2); } $authHeader = 'Digest '; $authHeader .= 'username="******"'], ['\\\\', '\\"'], $credentials['username']) . '", '; $authHeader .= 'realm="' . $credentials['realm'] . '", '; $authHeader .= 'nonce="' . $credentials['nonce'] . '", '; $authHeader .= 'uri="' . $path . '", '; $authHeader .= 'response="' . $response . '"'; if (!empty($credentials['opaque'])) { $authHeader .= ', opaque="' . $credentials['opaque'] . '"'; } if (!empty($credentials['qop'])) { $authHeader .= ', qop="auth", nc=' . $nc . ', cnonce="' . $credentials['cnonce'] . '"'; } return $authHeader; }
/** * Test send() + context options for SSL. * * @return void */ public function testSendContextSsl() { $request = new Request(); $request->url('https://localhost.com/test.html'); $options = ['ssl_verify_host' => true, 'ssl_verify_peer' => true, 'ssl_verify_depth' => 9000, 'ssl_allow_self_signed' => false]; $this->stream->send($request, $options); $result = $this->stream->contextOptions(); $expected = ['CN_match' => 'localhost.com', 'verify_peer' => true, 'verify_depth' => 9000, 'allow_self_signed' => false]; foreach ($expected as $k => $v) { $this->assertEquals($v, $result[$k]); } }
/** * Open the stream and send the request. * * @param Request $request * @return array Array of populated Response objects * @throws \Cake\Error\Exception */ protected function _send(Request $request) { $url = $request->url(); $this->_open($url); $content = ''; while (!feof($this->_stream)) { $content .= fread($this->_stream, 8192); } $meta = stream_get_meta_data($this->_stream); fclose($this->_stream); if ($meta['timed_out']) { throw new Error\Exception('Connection timed out ' . $url); } $headers = $meta['wrapper_data']; if (isset($meta['wrapper_type']) && $meta['wrapper_type'] === 'curl') { $headers = $meta['wrapper_data']['headers']; } return $this->createResponses($headers, $content); }
/** * Open the stream and send the request. * * @param \Cake\Network\Http\Request $request The request object. * @return array Array of populated Response objects * @throws \Cake\Core\Exception\Exception */ protected function _send(Request $request) { $deadline = false; if (isset($this->_contextOptions['timeout']) && $this->_contextOptions['timeout'] > 0) { $deadline = time() + $this->_contextOptions['timeout']; } $url = $request->url(); $this->_open($url); $content = ''; $timedOut = false; while (!feof($this->_stream)) { if ($deadline !== false) { stream_set_timeout($this->_stream, max($deadline - time(), 1)); } $content .= fread($this->_stream, 8192); $meta = stream_get_meta_data($this->_stream); if ($meta['timed_out'] || $deadline !== false && time() > $deadline) { $timedOut = true; break; } } $meta = stream_get_meta_data($this->_stream); fclose($this->_stream); if ($timedOut) { throw new Exception('Connection timed out ' . $url); } $headers = $meta['wrapper_data']; if (isset($headers['headers']) && is_array($headers['headers'])) { $headers = $headers['headers']; } return $this->createResponses($headers, $content); }
/** * Test HMAC-SHA1 signing. * * Hash result + parameters taken from * http://wiki.oauth.net/w/page/12238556/TestCases * * @return void */ public function testHmacSigning() { $request = new Request(); $request->url('http://photos.example.net/photos')->body(['file' => 'vacation.jpg', 'size' => 'original']); $options = ['consumerKey' => 'dpf43f3p2l4k3l03', 'consumerSecret' => 'kd94hf93k423kf44', 'tokenSecret' => 'pfkkdhi9sl3r4s00', 'token' => 'nnch734d00sl2jdk', 'nonce' => 'kllo9940pd9333jh', 'timestamp' => '1191242096']; $auth = new Twitter(); $request = $auth->authentication($request, $options); $result = $request->header('Authorization'); $expected = 'tR3+Ty81lMeYAr/Fid0kMTYa/WM='; $this->assertContains('oauth_signature="' . $expected . '"', urldecode($result)); }
/** * Sorts and normalizes request data and oauthValues * * Section 9.1.1 of Oauth spec. * * - URL encode keys + values. * - Sort keys & values by byte value. * * @param \Cake\Network\Http\Request $request The request object. * @param array $oauthValues Oauth values. * @return string sorted and normalized values */ protected function _normalizedParams($request, $oauthValues) { $query = parse_url($request->url(), PHP_URL_QUERY); parse_str($query, $queryArgs); $post = []; $body = $request->body(); if (is_array($body)) { $post = $body; } $args = array_merge($queryArgs, $oauthValues, $post); uksort($args, 'strcmp'); $pairs = []; foreach ($args as $k => $val) { if (is_array($val)) { sort($val, SORT_STRING); foreach ($val as $nestedVal) { $pairs[] = "$k=$nestedVal"; } } else { $pairs[] = "$k=$val"; } } return implode('&', $pairs); }
/** * Test send() + context options for SSL. * * @return void */ public function testSendContextSsl() { $request = new Request(); $request->url('https://localhost.com/test.html'); $options = ['ssl_verify_host' => true, 'ssl_verify_peer' => true, 'ssl_verify_depth' => 9000, 'ssl_allow_self_signed' => false, 'proxy' => ['proxy' => '127.0.0.1:8080']]; $this->stream->send($request, $options); $result = $this->stream->contextOptions(); $expected = ['peer_name' => 'localhost.com', 'verify_peer' => true, 'verify_depth' => 9000, 'allow_self_signed' => false, 'proxy' => '127.0.0.1:8080']; foreach ($expected as $k => $v) { $this->assertEquals($v, $result[$k]); } $this->assertTrue(is_readable($result['cafile'])); }
/** * Open the stream and stream responses using a generator. * * @param \Cake\Network\Http\Request $request The request object. * @return \Generator Response generator */ protected function _send(Request $request) { $this->_open($request->url()); return $this->_stream($this->_stream); }
/** * Test that an exception is raised when timed out. * * @expectedException \Cake\Core\Exception\Exception * @expectedExceptionMessage Connection timed out cakephp://dummy/?sleep * @return void */ public function testMissDeadline() { $request = new Request(); $request->url('cakephp://dummy/?sleep'); $options = ['timeout' => 2]; $stream = new Stream(); $stream->send($request, $options); }
/** * Test RSA-SHA1 signing with a private key string and passphrase file * * Hash result + parameters taken from * http://wiki.oauth.net/w/page/12238556/TestCases * * @return void */ public function testRsaSigningStringWithPassphraseFile() { $this->skipIf(PHP_EOL != "\n", 'Just the line ending "\\n" is supported. You can run the test again e.g. on a linux system.'); $request = new Request(); $request->url('http://photos.example.net/photos')->body(['file' => 'vacaction.jpg', 'size' => 'original']); $privateKey = $this->privateKeyStringEnc; $passphrase = fopen(TEST_APP . DS . 'config' . DS . 'key_passphrase_lf', 'r'); $options = ['method' => 'RSA-SHA1', 'consumerKey' => 'dpf43f3p2l4k3l03', 'nonce' => '13917289812797014437', 'timestamp' => '1196666512', 'privateKey' => $privateKey, 'privateKeyPassphrase' => $passphrase]; $auth = new Oauth(); $auth->authentication($request, $options); $result = $request->header('Authorization'); $expected = 'jvTp/wX1TYtByB1m+Pbyo0lnCOLIsyGCH7wke8AUs3BpnwZJtAuEJkvQL2/9n4s5wUmUl4aCI4BwpraNx4RtEXMe5qg5T1LVTGliMRpKasKsW//e+RinhejgCuzoH26dyF8iY2ZZ/5D1ilgeijhV/vBka5twt399mXwaYdCwFYE='; $this->assertContains('oauth_signature="' . $expected . '"', urldecode($result)); $expected = 0; $this->assertEquals($expected, ftell($passphrase)); }