SetAclCommand.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\SecurityBundle\Command;
  11. use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
  12. use Symfony\Component\Console\Input\InputArgument;
  13. use Symfony\Component\Console\Input\InputInterface;
  14. use Symfony\Component\Console\Input\InputOption;
  15. use Symfony\Component\Console\Output\OutputInterface;
  16. use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
  17. use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
  18. use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
  19. use Symfony\Component\Security\Acl\Exception\AclAlreadyExistsException;
  20. use Symfony\Component\Security\Acl\Model\MutableAclProviderInterface;
  21. use Symfony\Component\Security\Acl\Permission\MaskBuilder;
  22. /**
  23. * Sets ACL for objects.
  24. *
  25. * @author Kévin Dunglas <kevin@les-tilleuls.coop>
  26. */
  27. class SetAclCommand extends ContainerAwareCommand
  28. {
  29. /**
  30. * {@inheritdoc}
  31. */
  32. public function isEnabled()
  33. {
  34. if (!$this->getContainer()->has('security.acl.provider')) {
  35. return false;
  36. }
  37. $provider = $this->getContainer()->get('security.acl.provider');
  38. if (!$provider instanceof MutableAclProviderInterface) {
  39. return false;
  40. }
  41. return parent::isEnabled();
  42. }
  43. /**
  44. * {@inheritdoc}
  45. */
  46. protected function configure()
  47. {
  48. $this
  49. ->setName('acl:set')
  50. ->setDescription('Sets ACL for objects')
  51. ->setHelp(<<<EOF
  52. The <info>%command.name%</info> command sets ACL.
  53. The ACL system must have been initialized with the <info>init:acl</info> command.
  54. To set <comment>VIEW</comment> and <comment>EDIT</comment> permissions for the user <comment>kevin</comment> on the instance of
  55. <comment>Acme\MyClass</comment> having the identifier <comment>42</comment>:
  56. <info>php %command.full_name% --user=Symfony/Component/Security/Core/User/User:kevin VIEW EDIT Acme/MyClass:42</info>
  57. Note that you can use <comment>/</comment> instead of <comment>\\ </comment>for the namespace delimiter to avoid any
  58. problem.
  59. To set permissions for a role, use the <info>--role</info> option:
  60. <info>php %command.full_name% --role=ROLE_USER VIEW Acme/MyClass:1936</info>
  61. To set permissions at the class scope, use the <info>--class-scope</info> option:
  62. <info>php %command.full_name% --class-scope --user=Symfony/Component/Security/Core/User/User:anne OWNER Acme/MyClass:42</info>
  63. EOF
  64. )
  65. ->addArgument('arguments', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'A list of permissions and object identities (class name and ID separated by a column)')
  66. ->addOption('user', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'A list of security identities')
  67. ->addOption('role', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'A list of roles')
  68. ->addOption('class-scope', null, InputOption::VALUE_NONE, 'Use class-scope entries')
  69. ;
  70. }
  71. /**
  72. * {@inheritdoc}
  73. */
  74. protected function execute(InputInterface $input, OutputInterface $output)
  75. {
  76. // Parse arguments
  77. $objectIdentities = array();
  78. $maskBuilder = $this->getMaskBuilder();
  79. foreach ($input->getArgument('arguments') as $argument) {
  80. $data = explode(':', $argument, 2);
  81. if (\count($data) > 1) {
  82. $objectIdentities[] = new ObjectIdentity($data[1], strtr($data[0], '/', '\\'));
  83. } else {
  84. $maskBuilder->add($data[0]);
  85. }
  86. }
  87. // Build permissions mask
  88. $mask = $maskBuilder->get();
  89. $userOption = $input->getOption('user');
  90. $roleOption = $input->getOption('role');
  91. $classScopeOption = $input->getOption('class-scope');
  92. if (empty($userOption) && empty($roleOption)) {
  93. throw new \InvalidArgumentException('A Role or a User must be specified.');
  94. }
  95. // Create security identities
  96. $securityIdentities = array();
  97. if ($userOption) {
  98. foreach ($userOption as $user) {
  99. $data = explode(':', $user, 2);
  100. if (1 === \count($data)) {
  101. throw new \InvalidArgumentException('The user must follow the format "Acme/MyUser:username".');
  102. }
  103. $securityIdentities[] = new UserSecurityIdentity($data[1], strtr($data[0], '/', '\\'));
  104. }
  105. }
  106. if ($roleOption) {
  107. foreach ($roleOption as $role) {
  108. $securityIdentities[] = new RoleSecurityIdentity($role);
  109. }
  110. }
  111. /** @var $container \Symfony\Component\DependencyInjection\ContainerInterface */
  112. $container = $this->getContainer();
  113. /** @var $aclProvider MutableAclProviderInterface */
  114. $aclProvider = $container->get('security.acl.provider');
  115. // Sets ACL
  116. foreach ($objectIdentities as $objectIdentity) {
  117. // Creates a new ACL if it does not already exist
  118. try {
  119. $aclProvider->createAcl($objectIdentity);
  120. } catch (AclAlreadyExistsException $e) {
  121. }
  122. $acl = $aclProvider->findAcl($objectIdentity, $securityIdentities);
  123. foreach ($securityIdentities as $securityIdentity) {
  124. if ($classScopeOption) {
  125. $acl->insertClassAce($securityIdentity, $mask);
  126. } else {
  127. $acl->insertObjectAce($securityIdentity, $mask);
  128. }
  129. }
  130. $aclProvider->updateAcl($acl);
  131. }
  132. }
  133. /**
  134. * Gets the mask builder.
  135. *
  136. * @return MaskBuilder
  137. */
  138. protected function getMaskBuilder()
  139. {
  140. return new MaskBuilder();
  141. }
  142. }