protected function setUp() { $this->_helper = new Magento_Test_Helper_ObjectManager($this); $this->_helperData = $this->getMockBuilder('Mage_Webapi_Helper_Data')->disableOriginalConstructor()->setMethods(array('__'))->getMock(); $this->_helperData->expects($this->any())->method('__')->will($this->returnArgument(0)); $this->_objectManager = $this->getMockBuilder('Magento_ObjectManager')->disableOriginalConstructor()->setMethods(array('create'))->getMockForAbstractClass(); }
/** * Check permissions on specific resource in ACL. * * @param string $resource * @param string $method * @throws Mage_Webapi_Exception */ public function checkResourceAcl($resource, $method) { $coreAuthorization = $this->_coreAuthorization; if (!$coreAuthorization->isAllowed($resource . Mage_Webapi_Model_Acl_Rule::RESOURCE_SEPARATOR . $method) && !$coreAuthorization->isAllowed(Mage_Webapi_Model_Authorization::API_ACL_RESOURCES_ROOT_ID)) { throw new Mage_Webapi_Exception($this->_helper->__('Access to resource is forbidden.'), Mage_Webapi_Exception::HTTP_FORBIDDEN); } }
/** * Get renderer for Mime-Type specified in Accept header of request. * * @return Mage_Webapi_Controller_Response_Rest_RendererInterface * @throws Mage_Webapi_Exception * @throws LogicException */ public function get() { $acceptTypes = $this->_request->getAcceptTypes(); $availableRenderers = (array) $this->_applicationConfig->getNode(self::XML_PATH_WEBAPI_RESPONSE_RENDERS); if (!is_array($acceptTypes)) { $acceptTypes = array($acceptTypes); } foreach ($acceptTypes as $acceptType) { foreach ($availableRenderers as $rendererConfig) { $rendererType = (string) $rendererConfig->type; if ($acceptType == $rendererType || $acceptType == current(explode('/', $rendererType)) . '/*' || $acceptType == '*/*') { $rendererClass = (string) $rendererConfig->model; break 2; } } } if (!isset($rendererClass)) { /** If server does not have renderer for any of the accepted types it SHOULD send 406 (not acceptable). */ throw new Mage_Webapi_Exception($this->_helper->__('Server cannot understand Accept HTTP header media type.'), Mage_Webapi_Exception::HTTP_NOT_ACCEPTABLE); } $renderer = $this->_objectManager->get($rendererClass); if (!$renderer instanceof Mage_Webapi_Controller_Response_Rest_RendererInterface) { throw new LogicException('The renderer must implement "Mage_Webapi_Controller_Response_Rest_RendererInterface".'); } return $renderer; }
public function testCheckResourceAclMageWebapiException() { $this->_coreAuthorization->expects($this->exactly(2))->method('isAllowed')->will($this->returnValue(false)); $this->_helperMock->expects($this->once())->method('__')->will($this->returnArgument(0)); $this->setExpectedException('Mage_Webapi_Exception', 'Access to resource is forbidden.'); $this->_webapiAuthorization->checkResourceAcl('invalidResource', 'invalidMethod'); }
protected function setUp() { /** Prepare mocks for SUT constructor. */ $this->_apiConfigMock = $this->getMockBuilder('Mage_Webapi_Model_Config_Rest')->disableOriginalConstructor()->getMock(); $interpreterFactory = $this->getMockBuilder('Mage_Webapi_Controller_Request_Rest_Interpreter_Factory')->disableOriginalConstructor()->getMock(); $this->_helperMock = $this->getMockBuilder('Mage_Webapi_Helper_Data')->disableOriginalConstructor()->setMethods(array('__'))->getMock(); $this->_helperMock->expects($this->any())->method('__')->will($this->returnArgument(0)); $this->_routeMock = $this->getMockBuilder('Mage_Webapi_Controller_Router_Route_Rest')->disableOriginalConstructor()->setMethods(array('match'))->getMock(); $this->_request = new Mage_Webapi_Controller_Request_Rest($interpreterFactory, $this->_helperMock); /** Initialize SUT. */ $this->_router = new Mage_Webapi_Controller_Router_Rest($this->_helperMock, $this->_apiConfigMock); }
/** * Parse Request body into array of params. * * @param string $encodedBody Posted content from request. * @return array|null Return NULL if content is invalid. * @throws InvalidArgumentException * @throws Mage_Webapi_Exception If decoding error was encountered. */ public function interpret($encodedBody) { if (!is_string($encodedBody)) { throw new InvalidArgumentException(sprintf('Invalid data type "%s". String is expected.', gettype($encodedBody))); } try { /** @var Mage_Core_Helper_Data $jsonHelper */ $jsonHelper = $this->_helperFactory->get('Mage_Core_Helper_Data'); $decodedBody = $jsonHelper->jsonDecode($encodedBody); } catch (Zend_Json_Exception $e) { if (!$this->_app->isDeveloperMode()) { throw new Mage_Webapi_Exception($this->_helper->__('Decoding error.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } else { throw new Mage_Webapi_Exception('Decoding error: ' . PHP_EOL . $e->getMessage() . PHP_EOL . $e->getTraceAsString(), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } } return $decodedBody; }
/** * Identify versions of resources that should be used for API configuration generation. * * @return array * @throws Mage_Webapi_Exception When GET parameters are invalid */ public function getRequestedResources() { $wsdlParam = Mage_Webapi_Model_Soap_Server::REQUEST_PARAM_WSDL; $resourcesParam = Mage_Webapi_Model_Soap_Server::REQUEST_PARAM_RESOURCES; $requestParams = array_keys($this->getParams()); $allowedParams = array(Mage_Webapi_Controller_Router_Route_Webapi::PARAM_API_TYPE, $wsdlParam, $resourcesParam); $notAllowedParameters = array_diff($requestParams, $allowedParams); if (count($notAllowedParameters)) { $message = $this->_helper->__('Not allowed parameters: %s. ', implode(', ', $notAllowedParameters)) . $this->_helper->__('Please use only "%s" and "%s".', $wsdlParam, $resourcesParam); throw new Mage_Webapi_Exception($message, Mage_Webapi_Exception::HTTP_BAD_REQUEST); } $requestedResources = $this->getParam($resourcesParam); if (empty($requestedResources) || !is_array($requestedResources)) { $message = $this->_helper->__('Requested resources are missing.'); throw new Mage_Webapi_Exception($message, Mage_Webapi_Exception::HTTP_BAD_REQUEST); } return $requestedResources; }
/** * Authenticate user. * * @param stdClass $usernameToken WS-Security UsernameToken object * @throws Mage_Webapi_Exception If authentication failed */ public function authenticate($usernameToken) { try { $token = $this->_tokenFactory->createFromArray(); $request = $usernameToken; // @codingStandardsIgnoreStart $user = $token->authenticate($request->Username, $request->Password, $request->Created, $request->Nonce); // @codingStandardsIgnoreEnd $this->_roleLocator->setRoleId($user->getRoleId()); } catch (Mage_Webapi_Model_Soap_Security_UsernameToken_NonceUsedException $e) { throw new Mage_Webapi_Exception($this->_helper->__('WS-Security UsernameToken Nonce is already used.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } catch (Mage_Webapi_Model_Soap_Security_UsernameToken_TimestampRefusedException $e) { throw new Mage_Webapi_Exception($this->_helper->__('WS-Security UsernameToken Created timestamp is refused.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } catch (Mage_Webapi_Model_Soap_Security_UsernameToken_InvalidCredentialException $e) { throw new Mage_Webapi_Exception($this->_helper->__('Invalid Username or Password.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } catch (Mage_Webapi_Model_Soap_Security_UsernameToken_InvalidDateException $e) { throw new Mage_Webapi_Exception($this->_helper->__('Invalid UsernameToken Created date.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } }
/** * Identify version of requested operation. * * This method is required when there are two or more resource versions specified in request: * http://magento.host/api/soap?wsdl&resources[resource_a]=v1&resources[resource_b]=v2 <br/> * In this case it is not obvious what version of requested operation should be used. * * @param string $operationName * @return int * @throws Mage_Webapi_Exception */ protected function _getOperationVersion($operationName) { $requestedResources = $this->_request->getRequestedResources(); $resourceName = $this->_apiConfig->getResourceNameByOperation($operationName); if (!isset($requestedResources[$resourceName])) { throw new Mage_Webapi_Exception($this->_helper->__('The version of "%s" operation cannot be identified.', $operationName), Mage_Webapi_Exception::HTTP_NOT_FOUND); } $version = (int) str_replace('V', '', ucfirst($requestedResources[$resourceName])); $this->_apiConfig->validateVersionNumber($version, $resourceName); return $version; }
/** * Check whether current request matches any route of specified method or not. Method version is taken into account. * * @param Mage_Webapi_Controller_Request_Rest $request * @param string $methodName * @param string $version * @throws Mage_Webapi_Exception In case when request does not match any route of specified method. */ public function checkRoute(Mage_Webapi_Controller_Request_Rest $request, $methodName, $version) { $resourceName = $request->getResourceName(); $routes = $this->_apiConfig->getMethodRestRoutes($resourceName, $methodName, $version); foreach ($routes as $route) { if ($route->match($request)) { return; } } throw new Mage_Webapi_Exception($this->_helper->__('Request does not match any route.'), Mage_Webapi_Exception::HTTP_NOT_FOUND); }
/** * Process API exception. * * Create report if not in developer mode and render error to send correct API response. * * @param Exception $exception * @param int $httpCode * @SuppressWarnings(PHPMD.ExitExpression) */ public function renderException(Exception $exception, $httpCode = self::DEFAULT_ERROR_HTTP_CODE) { if ($this->_app->isDeveloperMode() || $exception instanceof Mage_Webapi_Exception) { $this->render($exception->getMessage(), $exception->getTraceAsString(), $exception->getCode()); } else { $reportId = $this->_logException($exception); $this->render($this->_apiHelper->__('Internal Error. Details are available in Magento log file. Report ID: "%s"', $reportId), 'Trace is not available.', $httpCode); } // TODO: Move die() call to render() method when it will be covered with functional tests. die; }
/** * Test renderException method with turned on Developer mode. */ public function testRenderExecutionInDeveloperMode() { $this->markTestIncomplete("Think how to replace this test."); $_SERVER['HTTP_ACCEPT'] = 'json'; /** Init base Exception object. */ $exception = new Exception('Message'); /** Mock app to return enabled developer mode flag. */ $this->_appMock->expects($this->any())->method('isDeveloperMode')->will($this->returnValue(true)); /** Assert jsonEncode will be executed once. */ $this->_helperMock->expects($this->once())->method('jsonEncode'); $this->_errorProcessor->renderException($exception); }
/** * Retrieve proper interpreter for the specified content type. * * @param string $contentType * @return Mage_Webapi_Controller_Request_Rest_InterpreterInterface * @throws LogicException|Mage_Webapi_Exception */ public function get($contentType) { $interpretersMetadata = (array) $this->_applicationConfig->getNode(self::XML_PATH_WEBAPI_REQUEST_INTERPRETERS); if (empty($interpretersMetadata) || !is_array($interpretersMetadata)) { throw new LogicException('Request interpreter adapter is not set.'); } foreach ($interpretersMetadata as $interpreterMetadata) { $interpreterType = (string) $interpreterMetadata->type; if ($interpreterType == $contentType) { $interpreterClass = (string) $interpreterMetadata->model; break; } } if (!isset($interpreterClass) || empty($interpreterClass)) { throw new Mage_Webapi_Exception($this->_helper->__('Server cannot understand Content-Type HTTP header media type "%s"', $contentType), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } $interpreter = $this->_objectManager->get($interpreterClass); if (!$interpreter instanceof Mage_Webapi_Controller_Request_Rest_InterpreterInterface) { throw new LogicException('The interpreter must implement "Mage_Webapi_Controller_Request_Rest_InterpreterInterface".'); } return $interpreter; }
/** * Convert XML document into array. * * @param string $xmlRequestBody XML document * @return array Data converted from XML document to array. Root node is excluded from response. * @throws InvalidArgumentException In case of invalid argument type. * @throws Mage_Webapi_Exception If decoding error occurs. */ public function interpret($xmlRequestBody) { if (!is_string($xmlRequestBody)) { throw new InvalidArgumentException(sprintf('Invalid data type "%s". String is expected.', gettype($xmlRequestBody))); } /** Disable external entity loading to prevent possible vulnerability */ $previousLoaderState = libxml_disable_entity_loader(true); set_error_handler(array($this, 'handleErrors')); $this->_xmlParser->loadXML($xmlRequestBody); restore_error_handler(); libxml_disable_entity_loader($previousLoaderState); /** Process errors during XML parsing. */ if ($this->_errorMessage !== null) { if (!$this->_app->isDeveloperMode()) { $exceptionMessage = $this->_helper->__('Decoding error.'); } else { $exceptionMessage = 'Decoding Error: ' . $this->_errorMessage; } throw new Mage_Webapi_Exception($exceptionMessage, Mage_Webapi_Exception::HTTP_BAD_REQUEST); } $data = $this->_xmlParser->xmlToArray(); /** Data will always have exactly one element so it is safe to call reset here. */ return reset($data); }
/** * Determine current API type using application request (not web API request). * * @return string * @throws Mage_Core_Exception * @throws Mage_Webapi_Exception If requested API type is invalid. */ public function determineApiType() { if (is_null($this->_apiType)) { $request = $this->_application->getRequest(); $apiRoute = $this->_routeFactory->createRoute('Mage_Webapi_Controller_Router_Route_Webapi', Mage_Webapi_Controller_Router_Route_Webapi::getApiRoute()); if (!($apiTypeMatch = $apiRoute->match($request, true))) { throw new Mage_Webapi_Exception($this->_helper->__('Request does not match any API type route.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } $apiType = $apiTypeMatch[Mage_Webapi_Controller_Router_Route_Webapi::PARAM_API_TYPE]; if (!in_array($apiType, $this->getListOfAvailableApiTypes())) { throw new Mage_Webapi_Exception($this->_helper->__('The "%s" API type is not defined.', $apiType), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } $this->_apiType = $apiType; } return $this->_apiType; }
/** * Fetch data from request and prepare it for passing to specified action. * * @param object $controllerInstance * @param string $action * @return array */ public function fetchRequestData($controllerInstance, $action) { $methodReflection = Mage_Webapi_Helper_Data::createMethodReflection($controllerInstance, $action); $methodName = $this->_configHelper->getMethodNameWithoutVersionSuffix($methodReflection); $bodyParamName = $this->_configHelper->getOperationBodyParamName($methodReflection); $requestParams = array_merge($this->_request->getParams(), array($bodyParamName => $this->_getRequestBody($methodName))); /** Convert names of ID and Parent ID params in request to those which are used in method interface. */ $idArgumentName = $this->_configHelper->getOperationIdParamName($methodReflection); $parentIdParamName = Mage_Webapi_Controller_Router_Route_Rest::PARAM_PARENT_ID; $idParamName = Mage_Webapi_Controller_Router_Route_Rest::PARAM_ID; if (isset($requestParams[$parentIdParamName]) && $idArgumentName != $parentIdParamName) { $requestParams[$idArgumentName] = $requestParams[$parentIdParamName]; unset($requestParams[$parentIdParamName]); } elseif (isset($requestParams[$idParamName]) && $idArgumentName != $idParamName) { $requestParams[$idArgumentName] = $requestParams[$idParamName]; unset($requestParams[$idParamName]); } return $this->_apiHelper->prepareMethodParams($controllerInstance, $action, $requestParams, $this->_apiConfig); }
protected final function _applyCollectionModifiers(Varien_Data_Collection_Db $collection) { $pageNumber = $this->getRequest()->getPageNumber(); if ($pageNumber != abs($pageNumber)) { throw new Mage_Webapi_Exception($this->_translationHelper->__("Page number is invalid."), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } $pageSize = $this->getRequest()->getPageSize(); if (null == $pageSize) { $pageSize = self::PAGE_SIZE_DEFAULT; } else { if ($pageSize != abs($pageSize) || $pageSize > self::PAGE_SIZE_MAX) { throw new Mage_Webapi_Exception($this->_translationHelper->__('The paging limit exceeds the allowed number.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } } $orderField = $this->getRequest()->getOrderField(); if (null !== $orderField) { if (!is_string($orderField)) { throw new Mage_Webapi_Exception($this->_translationHelper->__('Collection "order" value is invalid.'), Mage_Webapi_Exception::HTTP_BAD_REQUEST); } $collection->setOrder($orderField, $this->getRequest()->getOrderDirection()); } $collection->setCurPage($pageNumber)->setPageSize($pageSize); return $collection; }
public function testGenerateRestRoutesInvalidMethod() { $this->setExpectedException('InvalidArgumentException', '"invalidMethodNameV2" is an invalid API resource method.'); $this->_model->generateRestRoutes(Mage_Webapi_Helper_Data::createMethodReflection('Vendor_Module_Controller_Webapi_Invalid_Interface', 'invalidMethodNameV2')); }
/** * Initialize unique fields. * * @return Mage_Webapi_Model_Resource_Acl_User */ protected function _initUniqueFields() { $this->_uniqueFields = array(array('field' => 'api_key', 'title' => $this->_helper->__('API Key'))); return $this; }
/** * @dataProvider dataProviderForTestPrepareMethodParamsNegative * @param string|object $class * @param string $methodName * @param array $requestData * @param string $exceptionClass * @param string $exceptionMessage */ public function testPrepareMethodParamsNegative($class, $methodName, $requestData, $exceptionClass, $exceptionMessage) { $this->setExpectedException($exceptionClass, $exceptionMessage); $this->_helper->prepareMethodParams($class, $methodName, $requestData, $this->_getApiConfig()); }
/** * Initialize unique fields. * * @return Mage_Webapi_Model_Resource_Acl_Role */ protected function _initUniqueFields() { $this->_uniqueFields = array(array('field' => 'role_name', 'title' => $this->_helper->__('Role Name'))); return $this; }
public function testGetIdParamException() { $className = 'Vendor_Module_Webapi_Resource_Invalid'; $this->setExpectedException('LogicException', sprintf('"%s" is not a valid resource class.', $className)); $this->_helper->getOperationIdParamName(Mage_Webapi_Helper_Data::createMethodReflection($className, 'updateV1')); }