Request.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Oauth\Helper;
  7. use Magento\Framework\App\RequestInterface;
  8. use Zend\Uri\UriFactory;
  9. class Request
  10. {
  11. /**#@+
  12. * HTTP Response Codes
  13. */
  14. const HTTP_OK = 200;
  15. const HTTP_BAD_REQUEST = 400;
  16. const HTTP_UNAUTHORIZED = 401;
  17. const HTTP_METHOD_NOT_ALLOWED = 405;
  18. const HTTP_INTERNAL_ERROR = 500;
  19. /**#@-*/
  20. /**
  21. * Process HTTP request object and prepare for token validation
  22. *
  23. * @param RequestInterface $httpRequest
  24. * @return array
  25. */
  26. public function prepareRequest($httpRequest)
  27. {
  28. $oauthParams = $this->_processRequest(
  29. $httpRequest->getHeader('Authorization'),
  30. $httpRequest->getHeader(\Zend_Http_Client::CONTENT_TYPE),
  31. $httpRequest->getContent(),
  32. $this->getRequestUrl($httpRequest)
  33. );
  34. return $oauthParams;
  35. }
  36. /**
  37. * Compute the request Url from the Http request
  38. *
  39. * @param RequestInterface $httpRequest
  40. * @return string
  41. */
  42. public function getRequestUrl($httpRequest)
  43. {
  44. return $httpRequest->getScheme() . '://' . $httpRequest->getHttpHost(false) . $httpRequest->getRequestUri();
  45. }
  46. /**
  47. * Process oauth related protocol information and return as an array
  48. *
  49. * @param string $authHeaderValue
  50. * @param string $contentTypeHeader
  51. * @param string $requestBodyString
  52. * @param string $requestUrl
  53. * @return array
  54. * merged array of oauth protocols and request parameters. eg :
  55. * <pre>
  56. * array (
  57. * 'oauth_version' => '1.0',
  58. * 'oauth_signature_method' => 'HMAC-SHA1',
  59. * 'oauth_nonce' => 'rI7PSWxTZRHWU3R',
  60. * 'oauth_timestamp' => '1377183099',
  61. * 'oauth_consumer_key' => 'a6aa81cc3e65e2960a4879392445e718',
  62. * 'oauth_signature' => 'VNg4mhFlXk7%2FvsxMqqUd5DWIj9s%3D'
  63. * )
  64. * </pre>
  65. */
  66. protected function _processRequest($authHeaderValue, $contentTypeHeader, $requestBodyString, $requestUrl)
  67. {
  68. $protocolParams = [];
  69. if (!$this->_processHeader($authHeaderValue, $protocolParams)) {
  70. return [];
  71. }
  72. if ($contentTypeHeader && 0 === strpos($contentTypeHeader, \Zend_Http_Client::ENC_URLENCODED)) {
  73. $protocolParamsNotSet = !$protocolParams;
  74. parse_str($requestBodyString, $protocolBodyParams);
  75. foreach ($protocolBodyParams as $bodyParamName => $bodyParamValue) {
  76. if (!$this->_isProtocolParameter($bodyParamName)) {
  77. $protocolParams[$bodyParamName] = $bodyParamValue;
  78. } elseif ($protocolParamsNotSet) {
  79. $protocolParams[$bodyParamName] = $bodyParamValue;
  80. }
  81. }
  82. }
  83. $protocolParamsNotSet = !$protocolParams;
  84. $queryString = UriFactory::factory($requestUrl)->getQuery();
  85. $this->_extractQueryStringParams($protocolParams, $queryString);
  86. if ($protocolParamsNotSet) {
  87. $this->_fetchProtocolParamsFromQuery($protocolParams, $queryString);
  88. }
  89. // Combine request and header parameters
  90. return $protocolParams;
  91. }
  92. /**
  93. * Retrieve protocol parameters from query string
  94. *
  95. * @param array &$protocolParams
  96. * @param array $queryString
  97. * @return void
  98. */
  99. protected function _fetchProtocolParamsFromQuery(&$protocolParams, $queryString)
  100. {
  101. if (is_array($queryString)) {
  102. foreach ($queryString as $queryParamName => $queryParamValue) {
  103. if ($this->_isProtocolParameter($queryParamName)) {
  104. $protocolParams[$queryParamName] = $queryParamValue;
  105. }
  106. }
  107. }
  108. }
  109. /**
  110. * Check if attribute is oAuth related
  111. *
  112. * @param string $attrName
  113. * @return bool
  114. */
  115. protected function _isProtocolParameter($attrName)
  116. {
  117. return (bool)preg_match('/oauth_[a-z_-]+/', $attrName);
  118. }
  119. /**
  120. * Process header parameters for Oauth
  121. *
  122. * @param string $authHeaderValue
  123. * @param array &$protocolParams
  124. * @return bool true if parameters from oauth headers are processed correctly
  125. */
  126. protected function _processHeader($authHeaderValue, &$protocolParams)
  127. {
  128. $oauthValuePosition = stripos(($authHeaderValue ? $authHeaderValue : ''), 'oauth ');
  129. if ($authHeaderValue && $oauthValuePosition !== false) {
  130. // Ignore anything before and including 'OAuth ' (trailing values validated later)
  131. $authHeaderValue = substr($authHeaderValue, $oauthValuePosition + 6);
  132. foreach (explode(',', $authHeaderValue) as $paramStr) {
  133. $nameAndValue = explode('=', trim($paramStr), 2);
  134. if (count($nameAndValue) < 2) {
  135. continue;
  136. }
  137. if ($this->_isProtocolParameter($nameAndValue[0])) {
  138. $protocolParams[rawurldecode($nameAndValue[0])] = rawurldecode(trim($nameAndValue[1], '"'));
  139. }
  140. }
  141. return true;
  142. }
  143. return false;
  144. }
  145. /**
  146. * Process query string for Oauth
  147. *
  148. * @param array &$protocolParams
  149. * @param string $queryString
  150. * @return void
  151. */
  152. protected function _extractQueryStringParams(&$protocolParams, $queryString)
  153. {
  154. if ($queryString) {
  155. foreach (explode('&', $queryString) as $paramToValue) {
  156. $paramData = explode('=', $paramToValue);
  157. if (2 === count($paramData) && !$this->_isProtocolParameter($paramData[0])) {
  158. $protocolParams[rawurldecode($paramData[0])] = rawurldecode($paramData[1]);
  159. }
  160. }
  161. }
  162. }
  163. /**
  164. * Create response string for problem during request and set HTTP error code
  165. *
  166. * @param \Exception $exception
  167. * @param \Magento\Framework\HTTP\PhpEnvironment\Response $response OPTIONAL If NULL - will use internal getter
  168. * @return array
  169. */
  170. public function prepareErrorResponse(
  171. \Exception $exception,
  172. \Magento\Framework\HTTP\PhpEnvironment\Response $response = null
  173. ) {
  174. $errorMsg = $exception->getMessage();
  175. if ($exception instanceof \Magento\Framework\Oauth\Exception) {
  176. $responseCode = self::HTTP_UNAUTHORIZED;
  177. } elseif ($exception instanceof \Magento\Framework\Oauth\OauthInputException) {
  178. $responseCode = self::HTTP_BAD_REQUEST;
  179. if ($errorMsg == 'One or more input exceptions have occurred.') {
  180. $errorMsg = $exception->getAggregatedErrorMessage();
  181. }
  182. } else {
  183. $errorMsg = 'internal_error&message=' . ($errorMsg ? $errorMsg : 'empty_message');
  184. $responseCode = self::HTTP_INTERNAL_ERROR;
  185. }
  186. $response->setHttpResponseCode($responseCode);
  187. return ['oauth_problem' => $errorMsg];
  188. }
  189. }