vendor/pimcore/pimcore/bundles/AdminBundle/Controller/AdminController.php line 68

Open in your IDE?
  1. <?php
  2. /**
  3. * Pimcore
  4. *
  5. * This source file is available under two different licenses:
  6. * - GNU General Public License version 3 (GPLv3)
  7. * - Pimcore Commercial License (PCL)
  8. * Full copyright and license information is available in
  9. * LICENSE.md which is distributed with this source code.
  10. *
  11. * @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12. * @license http://www.pimcore.org/license GPLv3 and PCL
  13. */
  14. namespace Pimcore\Bundle\AdminBundle\Controller;
  15. use Pimcore\Bundle\AdminBundle\HttpFoundation\JsonResponse;
  16. use Pimcore\Bundle\AdminBundle\Security\User\TokenStorageUserResolver;
  17. use Pimcore\Bundle\AdminBundle\Security\User\User as UserProxy;
  18. use Pimcore\Controller\Controller;
  19. use Pimcore\Extension\Bundle\PimcoreBundleManager;
  20. use Pimcore\Logger;
  21. use Pimcore\Model\User;
  22. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  23. use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
  24. use Symfony\Component\Serializer\Encoder\DecoderInterface;
  25. use Symfony\Component\Serializer\SerializerInterface;
  26. use Symfony\Component\Translation\Exception\InvalidArgumentException;
  27. use Symfony\Contracts\Translation\TranslatorInterface;
  28. abstract class AdminController extends Controller implements AdminControllerInterface
  29. {
  30. public static function getSubscribedServices()
  31. {
  32. $services = parent::getSubscribedServices();
  33. $services['translator'] = TranslatorInterface::class;
  34. $services[TokenStorageUserResolver::class] = TokenStorageUserResolver::class;
  35. $services[PimcoreBundleManager::class] = PimcoreBundleManager::class;
  36. $services['pimcore_admin.serializer'] = '?Pimcore\\Admin\\Serializer';
  37. return $services;
  38. }
  39. /**
  40. * {@inheritdoc}
  41. */
  42. public function needsSessionDoubleAuthenticationCheck()
  43. {
  44. return true;
  45. }
  46. /**
  47. * {@inheritdoc}
  48. */
  49. public function needsStorageDoubleAuthenticationCheck()
  50. {
  51. return true;
  52. }
  53. /**
  54. * Get user from user proxy object which is registered on security component
  55. *
  56. * @param bool $proxyUser Return the proxy user (UserInterface) instead of the pimcore model
  57. *
  58. * @return UserProxy|User|null
  59. */
  60. protected function getAdminUser($proxyUser = false)
  61. {
  62. $resolver = $this->get(TokenStorageUserResolver::class);
  63. if ($proxyUser) {
  64. return $resolver->getUserProxy();
  65. }
  66. return $resolver->getUser();
  67. }
  68. /**
  69. * Check user permission
  70. *
  71. * @param string $permission
  72. *
  73. * @throws AccessDeniedHttpException
  74. */
  75. protected function checkPermission($permission)
  76. {
  77. if (!$this->getAdminUser() || !$this->getAdminUser()->isAllowed($permission)) {
  78. Logger::error(
  79. 'User {user} attempted to access {permission}, but has no permission to do so',
  80. [
  81. 'user' => $this->getAdminUser()->getName(),
  82. 'permission' => $permission,
  83. ]
  84. );
  85. throw $this->createAccessDeniedHttpException();
  86. }
  87. }
  88. /**
  89. * @param string $message
  90. * @param \Throwable|null $previous
  91. * @param int $code
  92. * @param array $headers
  93. *
  94. * @return AccessDeniedHttpException
  95. */
  96. protected function createAccessDeniedHttpException(string $message = 'Access Denied.', \Throwable $previous = null, int $code = 0, array $headers = []): AccessDeniedHttpException
  97. {
  98. // $headers parameter not supported by Symfony 3.4
  99. return new AccessDeniedHttpException($message, $previous, $code, $headers);
  100. }
  101. /**
  102. * @param string[] $permissions
  103. */
  104. protected function checkPermissionsHasOneOf(array $permissions)
  105. {
  106. $allowed = false;
  107. $permission = null;
  108. foreach ($permissions as $permission) {
  109. if ($this->getAdminUser()->isAllowed($permission)) {
  110. $allowed = true;
  111. break;
  112. }
  113. }
  114. if (!$this->getAdminUser() || !$allowed) {
  115. Logger::error(
  116. 'User {user} attempted to access {permission}, but has no permission to do so',
  117. [
  118. 'user' => $this->getAdminUser()->getName(),
  119. 'permission' => $permission,
  120. ]
  121. );
  122. throw new AccessDeniedHttpException('Attempt to access ' . $permission . ', but has no permission to do so.');
  123. }
  124. }
  125. /**
  126. * Check permission against all controller actions. Can optionally exclude a list of actions.
  127. *
  128. * @param ControllerEvent $event
  129. * @param string $permission
  130. * @param array $unrestrictedActions
  131. */
  132. protected function checkActionPermission(ControllerEvent $event, string $permission, array $unrestrictedActions = [])
  133. {
  134. $actionName = null;
  135. $controller = $event->getController();
  136. if (is_array($controller) && count($controller) === 2 && is_string($controller[1])) {
  137. $actionName = $controller[1];
  138. }
  139. if (null === $actionName || !in_array($actionName, $unrestrictedActions)) {
  140. $this->checkPermission($permission);
  141. }
  142. }
  143. /**
  144. * Encodes data into JSON string
  145. *
  146. * @param mixed $data The data to be encoded
  147. * @param array $context Context to pass to serializer when using serializer component
  148. * @param int $options Options passed to json_encode
  149. * @param bool $useAdminSerializer
  150. *
  151. * @TODO check if $useAdminSerializer still required?
  152. *
  153. * @return string
  154. */
  155. protected function encodeJson($data, array $context = [], $options = JsonResponse::DEFAULT_ENCODING_OPTIONS, bool $useAdminSerializer = true)
  156. {
  157. /** @var SerializerInterface $serializer */
  158. $serializer = null;
  159. if ($useAdminSerializer) {
  160. $serializer = $this->container->get('pimcore_admin.serializer');
  161. } else {
  162. $serializer = $this->container->get('serializer');
  163. }
  164. return $serializer->serialize($data, 'json', array_merge([
  165. 'json_encode_options' => $options,
  166. ], $context));
  167. }
  168. /**
  169. * Decodes a JSON string into an array/object
  170. *
  171. * @param mixed $json The data to be decoded
  172. * @param bool $associative Whether to decode into associative array or object
  173. * @param array $context Context to pass to serializer when using serializer component
  174. * @param bool $useAdminSerializer
  175. *
  176. * @return mixed
  177. */
  178. protected function decodeJson($json, $associative = true, array $context = [], bool $useAdminSerializer = true)
  179. {
  180. /** @var SerializerInterface|DecoderInterface $serializer */
  181. $serializer = null;
  182. if ($useAdminSerializer) {
  183. $serializer = $this->container->get('pimcore_admin.serializer');
  184. } else {
  185. $serializer = $this->container->get('serializer');
  186. }
  187. if ($associative) {
  188. $context['json_decode_associative'] = true;
  189. }
  190. return $serializer->decode($json, 'json', $context);
  191. }
  192. /**
  193. * Returns a JsonResponse that uses the admin serializer
  194. *
  195. * @param mixed $data The response data
  196. * @param int $status The status code to use for the Response
  197. * @param array $headers Array of extra headers to add
  198. * @param array $context Context to pass to serializer when using serializer component
  199. * @param bool $useAdminSerializer
  200. *
  201. * @return JsonResponse
  202. */
  203. protected function adminJson($data, $status = 200, $headers = [], $context = [], bool $useAdminSerializer = true)
  204. {
  205. $json = $this->encodeJson($data, $context, JsonResponse::DEFAULT_ENCODING_OPTIONS, $useAdminSerializer);
  206. return new JsonResponse($json, $status, $headers, true);
  207. }
  208. /**
  209. * Translates the given message.
  210. *
  211. * @param string $id The message id (may also be an object that can be cast to string)
  212. * @param array $parameters An array of parameters for the message
  213. * @param string|null $domain The domain for the message or null to use the default
  214. * @param string|null $locale The locale or null to use the default
  215. *
  216. * @return string The translated string
  217. *
  218. * @throws InvalidArgumentException If the locale contains invalid characters
  219. */
  220. public function trans($id, array $parameters = [], $domain = 'admin', $locale = null)
  221. {
  222. $translator = $this->get('translator');
  223. return $translator->trans($id, $parameters, $domain, $locale);
  224. }
  225. }