BackendValidator.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. declare(strict_types=1);
  7. namespace Magento\Backend\App\Request;
  8. use Magento\Backend\App\AbstractAction;
  9. use Magento\Framework\App\ActionInterface;
  10. use Magento\Framework\App\CsrfAwareActionInterface;
  11. use Magento\Framework\App\Request\InvalidRequestException;
  12. use Magento\Framework\App\Request\ValidatorInterface;
  13. use Magento\Framework\App\RequestInterface;
  14. use Magento\Backend\Model\Auth;
  15. use Magento\Framework\App\Request\Http as HttpRequest;
  16. use Magento\Framework\Controller\Result\RawFactory;
  17. use Magento\Framework\Controller\Result\Raw as RawResult;
  18. use Magento\Framework\Controller\Result\RedirectFactory;
  19. use Magento\Framework\Data\Form\FormKey\Validator as FormKeyValidator;
  20. use Magento\Backend\Model\UrlInterface as BackendUrl;
  21. use Magento\Framework\Phrase;
  22. /**
  23. * Do backend validations.
  24. *
  25. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  26. */
  27. class BackendValidator implements ValidatorInterface
  28. {
  29. /**
  30. * @var Auth
  31. */
  32. private $auth;
  33. /**
  34. * @var FormKeyValidator
  35. */
  36. private $formKeyValidator;
  37. /**
  38. * @var BackendUrl
  39. */
  40. private $backendUrl;
  41. /**
  42. * @var RedirectFactory
  43. */
  44. private $redirectFactory;
  45. /**
  46. * @var RawFactory
  47. */
  48. private $rawResultFactory;
  49. /**
  50. * @param Auth $auth
  51. * @param FormKeyValidator $formKeyValidator
  52. * @param BackendUrl $backendUrl
  53. * @param RedirectFactory $redirectFactory
  54. * @param RawFactory $rawResultFactory
  55. */
  56. public function __construct(
  57. Auth $auth,
  58. FormKeyValidator $formKeyValidator,
  59. BackendUrl $backendUrl,
  60. RedirectFactory $redirectFactory,
  61. RawFactory $rawResultFactory
  62. ) {
  63. $this->auth = $auth;
  64. $this->formKeyValidator = $formKeyValidator;
  65. $this->backendUrl = $backendUrl;
  66. $this->redirectFactory = $redirectFactory;
  67. $this->rawResultFactory = $rawResultFactory;
  68. }
  69. /**
  70. * Validate request
  71. *
  72. * @param RequestInterface $request
  73. * @param ActionInterface $action
  74. *
  75. * @return bool
  76. */
  77. private function validateRequest(
  78. RequestInterface $request,
  79. ActionInterface $action
  80. ): bool {
  81. /** @var bool|null $valid */
  82. $valid = null;
  83. if ($action instanceof CsrfAwareActionInterface) {
  84. $valid = $action->validateForCsrf($request);
  85. }
  86. if ($valid === null) {
  87. $validFormKey = true;
  88. $validSecretKey = true;
  89. if ($request instanceof HttpRequest && $request->isPost()) {
  90. $validFormKey = $this->formKeyValidator->validate($request);
  91. } elseif ($this->auth->isLoggedIn()
  92. && $this->backendUrl->useSecretKey()
  93. ) {
  94. $secretKeyValue = (string)$request->getParam(
  95. BackendUrl::SECRET_KEY_PARAM_NAME,
  96. null
  97. );
  98. $secretKey = $this->backendUrl->getSecretKey();
  99. $validSecretKey = ($secretKeyValue === $secretKey);
  100. }
  101. $valid = $validFormKey && $validSecretKey;
  102. }
  103. return $valid;
  104. }
  105. /**
  106. * Create exception
  107. *
  108. * @param RequestInterface $request
  109. * @param ActionInterface $action
  110. *
  111. * @return InvalidRequestException
  112. */
  113. private function createException(
  114. RequestInterface $request,
  115. ActionInterface $action
  116. ): InvalidRequestException {
  117. /** @var InvalidRequestException|null $exception */
  118. $exception = null;
  119. if ($action instanceof CsrfAwareActionInterface) {
  120. $exception = $action->createCsrfValidationException($request);
  121. }
  122. if ($exception === null) {
  123. if ($request instanceof HttpRequest && $request->isAjax()) {
  124. //Sending empty response for AJAX request since we don't know
  125. //the expected response format and it's pointless to redirect.
  126. /** @var RawResult $response */
  127. $response = $this->rawResultFactory->create();
  128. $response->setHttpResponseCode(401);
  129. $response->setContents('');
  130. $exception = new InvalidRequestException($response);
  131. } else {
  132. //For regular requests.
  133. $response = $this->redirectFactory->create()
  134. ->setUrl($this->backendUrl->getStartupPageUrl());
  135. $exception = new InvalidRequestException(
  136. $response,
  137. [
  138. new Phrase(
  139. 'Invalid security or form key. Please refresh the page.'
  140. )
  141. ]
  142. );
  143. }
  144. }
  145. return $exception;
  146. }
  147. /**
  148. * @inheritDoc
  149. */
  150. public function validate(
  151. RequestInterface $request,
  152. ActionInterface $action
  153. ): void {
  154. if ($action instanceof AbstractAction) {
  155. //Abstract Action has built-in validation.
  156. if (!$action->_processUrlKeys()) {
  157. throw new InvalidRequestException($action->getResponse());
  158. }
  159. } else {
  160. //Fallback validation.
  161. if (!$this->validateRequest($request, $action)) {
  162. throw $this->createException($request, $action);
  163. }
  164. }
  165. }
  166. }