security.rst 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. Security
  2. ========
  3. User management
  4. ---------------
  5. By default, the SonataAdminBundle does not come with any user management,
  6. however it is most likely the application requires such a feature. The Sonata
  7. Project includes a ``SonataUserBundle`` which integrates the ``FOSUserBundle``.
  8. The ``FOSUserBundle`` adds support for a database-backed user system in Symfony.
  9. It provides a flexible framework for user management that aims to handle common
  10. tasks such as user login, registration and password retrieval.
  11. The ``SonataUserBundle`` is just a thin wrapper to include the ``FOSUserBundle``
  12. into the ``AdminBundle``. The ``SonataUserBundle`` includes:
  13. * A default login area
  14. * A default ``user_block`` template which is used to display the current user
  15. and the logout link
  16. * 2 Admin classes: User and Group
  17. * A default class for User and Group.
  18. There is a little magic in the ``SonataAdminBundle``: if the bundle detects the
  19. ``SonataUserBundle`` class, then the default ``user_block`` template will be
  20. changed to use the one provided by the ``SonataUserBundle``.
  21. The install process is available on the dedicated
  22. `SonataUserBundle's documentation area`_.
  23. Security handlers
  24. -----------------
  25. The security part is managed by a ``SecurityHandler``, the bundle comes with 3 handlers:
  26. - ``sonata.admin.security.handler.role``: ROLES to handle permissions
  27. - ``sonata.admin.security.handler.acl``: ACL and ROLES to handle permissions
  28. - ``sonata.admin.security.handler.noop``: always returns true, can be used
  29. with the Symfony firewall
  30. The default value is ``sonata.admin.security.handler.noop``, if you want to
  31. change the default value you can set the ``security_handler`` to
  32. ``sonata.admin.security.handler.acl`` or ``sonata.admin.security.handler.role``.
  33. To quickly secure an admin the role security can be used. It allows to specify
  34. the actions a user can do with the admin. The ACL security system is more advanced
  35. and allows to secure the objects. For people using the previous ACL
  36. implementation, you can switch the ``security_handler`` to the role security handler.
  37. Configuration
  38. ~~~~~~~~~~~~~
  39. Only the security handler is required to determine which type of security to use.
  40. The other parameters are set as default, change them if needed.
  41. Using roles:
  42. .. configuration-block::
  43. .. code-block:: yaml
  44. # app/config/config.yml
  45. sonata_admin:
  46. security:
  47. handler: sonata.admin.security.handler.role
  48. Using ACL:
  49. .. configuration-block::
  50. .. code-block:: yaml
  51. # app/config/config.yml
  52. sonata_admin:
  53. security:
  54. handler: sonata.admin.security.handler.acl
  55. # acl security information
  56. information:
  57. GUEST: [VIEW, LIST]
  58. STAFF: [EDIT, LIST, CREATE]
  59. EDITOR: [OPERATOR, EXPORT]
  60. ADMIN: [MASTER]
  61. # permissions not related to an object instance and also to be available when objects do not exist
  62. # the DELETE admin permission means the user is allowed to batch delete objects
  63. admin_permissions: [CREATE, LIST, DELETE, UNDELETE, EXPORT, OPERATOR, MASTER]
  64. # permission related to the objects
  65. object_permissions: [VIEW, EDIT, DELETE, UNDELETE, OPERATOR, MASTER, OWNER]
  66. Later, we will explain how to set up ACL with the ``FriendsOfSymfony/UserBundle``.
  67. Role handler
  68. ------------
  69. The ``sonata.admin.security.handler.role`` allows you to operate finely on the
  70. actions that can be done (depending on the entity class), without requiring to set up ACL.
  71. Configuration
  72. ~~~~~~~~~~~~~
  73. First, activate the role security handler as described above.
  74. Each time a user tries to do an action in the admin, Sonata checks if he is
  75. either a super admin (``ROLE_SUPER_ADMIN``) **or** has the permission.
  76. The permissions are:
  77. ========== ==================================================
  78. Permission Description
  79. ========== ==================================================
  80. LIST view the list of objects
  81. VIEW view the detail of one object
  82. CREATE create a new object
  83. EDIT update an existing object
  84. DELETE delete an existing object
  85. EXPORT (for the native Sonata export links)
  86. ALL grants LIST, VIEW, CREATE, EDIT, DELETE and EXPORT
  87. ========== ==================================================
  88. Each permission is relative to an admin: if you try to get a list in FooAdmin (declared as ``app.admin.foo``
  89. service), Sonata will check if the user has the ``ROLE_APP_ADMIN_FOO_EDIT`` or ``ROLE_APP_ADMIN_FOO_ALL`` roles.
  90. The role name will be based on the name of your admin service. For instance, ``acme.blog.post.admin`` will become ``ROLE_ACME_BLOG_POST_ADMIN_{ACTION}``.
  91. .. note::
  92. If your admin service is named like ``my.blog.admin.foo_bar`` (note the underscore ``_``) it will become: ``ROLE_MY_BLOG_ADMIN_FOO_BAR_{ACTION}``
  93. So our ``security.yml`` file may look something like this:
  94. .. configuration-block::
  95. .. code-block:: yaml
  96. # app/config/security.yml
  97. security:
  98. # ...
  99. role_hierarchy:
  100. # for convenience, I decided to gather Sonata roles here
  101. ROLE_SONATA_FOO_READER:
  102. - ROLE_SONATA_ADMIN_DEMO_FOO_LIST
  103. - ROLE_SONATA_ADMIN_DEMO_FOO_VIEW
  104. ROLE_SONATA_FOO_EDITOR:
  105. - ROLE_SONATA_ADMIN_DEMO_FOO_CREATE
  106. - ROLE_SONATA_ADMIN_DEMO_FOO_EDIT
  107. ROLE_SONATA_FOO_ADMIN:
  108. - ROLE_SONATA_ADMIN_DEMO_FOO_DELETE
  109. - ROLE_SONATA_ADMIN_DEMO_FOO_EXPORT
  110. # those are the roles I will use (less verbose)
  111. ROLE_STAFF: [ROLE_USER, ROLE_SONATA_FOO_READER]
  112. ROLE_ADMIN: [ROLE_STAFF, ROLE_SONATA_FOO_EDITOR, ROLE_SONATA_FOO_ADMIN]
  113. ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
  114. # you could alternatively use for an admin who has all rights
  115. ROLE_ALL_ADMIN: [ROLE_STAFF, ROLE_SONATA_FOO_ALL]
  116. # set access_strategy to unanimous, else you may have unexpected behaviors
  117. access_decision_manager:
  118. strategy: unanimous
  119. Note that we also set ``access_strategy`` to unanimous.
  120. It means that if one voter (for example Sonata) refuses access, access will be denied.
  121. For more information on this subject, please see `changing the access decision strategy`_
  122. in the Symfony documentation.
  123. Usage
  124. ~~~~~
  125. You can now test if a user is authorized from an Admin class:
  126. .. code-block:: php
  127. if ($this->hasAccess('list')) {
  128. // ...
  129. }
  130. From a controller extending ``Sonata\AdminBundle\Controller\CRUDController``:
  131. .. code-block:: php
  132. if ($this->admin->hasAccess('list')) {
  133. // ...
  134. }
  135. Or from a Twig template:
  136. .. code-block:: jinja
  137. {% if is_granted('VIEW') %}
  138. <p>Hello there!</p>
  139. {% endif %}
  140. Note that you do not have to re-specify the prefix.
  141. Sonata checks those permissions for the action it handles internally.
  142. Of course you will have to recheck them in your own code.
  143. Yon can also create your own permissions, for example ``EMAIL``
  144. (which will turn into role ``ROLE_APP_ADMIN_FOO_EMAIL``).
  145. Going further
  146. ~~~~~~~~~~~~~
  147. Because Sonata role handler supplements Symfony security, but does not override it, you are free to do more advanced operations.
  148. For example, you can `create your own voter`_
  149. Customizing the handler behavior
  150. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  151. If you want to change the handler behavior (for example, to pass the current object to voters), extend
  152. ``Sonata\AdminBundle\Security\Handler\RoleSecurityHandler``, and override the ``isGranted`` method.
  153. Then declare your handler as a service:
  154. .. configuration-block::
  155. .. code-block:: xml
  156. <service id="app.security.handler.role" class="AppBundle\Security\Handler\RoleSecurityHandler" public="false">
  157. <argument type="service" id="security.context" on-invalid="null" />
  158. <argument type="collection">
  159. <argument>ROLE_SUPER_ADMIN</argument>
  160. </argument>
  161. </service>
  162. And specify it as Sonata security handler on your configuration:
  163. .. configuration-block::
  164. .. code-block:: yaml
  165. # app/config/config.yml
  166. sonata_admin:
  167. security:
  168. handler: app.security.handler.role
  169. ACL and FriendsOfSymfony/UserBundle
  170. -----------------------------------
  171. If you want an easy way to handle users, please use:
  172. - `FOSUserBundle <https://github.com/FriendsOfSymfony/FOSUserBundle>`_: handles
  173. users and groups stored in RDBMS or MongoDB
  174. - `SonataUserBundle <https://github.com/sonata-project/SonataUserBundle>`_: integrates the
  175. ``FriendsOfSymfony/UserBundle`` with the ``AdminBundle``
  176. The security integration is a work in progress and has some known issues:
  177. - ACL permissions are immutables
  178. - A listener must be implemented that creates the object Access Control List
  179. with the required rules if objects are created outside the Admin
  180. Configuration
  181. ~~~~~~~~~~~~~
  182. Before you can use ``FriendsOfSymfony/FOSUserBundle`` you need to set it up as
  183. described in the documentation of the bundle. In step 4 you need to create a
  184. User class (in a custom UserBundle). Do it as follows:
  185. .. code-block:: php
  186. <?php
  187. // src/AppBundle/Entity/User.php
  188. namespace AppBundle\Entity;
  189. use Sonata\UserBundle\Entity\BaseUser as BaseUser;
  190. use Doctrine\ORM\Mapping as ORM;
  191. /**
  192. * @ORM\Entity
  193. * @ORM\Table(name="fos_user")
  194. */
  195. class User extends BaseUser
  196. {
  197. /**
  198. * @ORM\Id
  199. * @ORM\Column(type="integer")
  200. * @ORM\GeneratedValue(strategy="AUTO")
  201. */
  202. protected $id;
  203. public function __construct()
  204. {
  205. parent::__construct();
  206. // your own logic
  207. }
  208. }
  209. In your ``app/config/config.yml`` you then need to put the following:
  210. .. configuration-block::
  211. .. code-block:: yaml
  212. # app/config/config.yml
  213. fos_user:
  214. db_driver: orm
  215. firewall_name: main
  216. user_class: AppBundle\Entity\User
  217. The following configuration for the SonataUserBundle defines:
  218. - the ``FriendsOfSymfony/FOSUserBundle`` as a security provider
  219. - the login form for authentication
  220. - the access control: resources with related required roles, the important
  221. part is the admin configuration
  222. - the ``acl`` option to enable the ACL
  223. - the ``AdminPermissionMap`` defines the permissions of the Admin class
  224. .. configuration-block::
  225. .. code-block:: yaml
  226. # src/AppBundle/Resources/config/services.yml
  227. # Symfony >= 3
  228. services:
  229. security.acl.permission.map:
  230. class: Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap
  231. # optionally use a custom MaskBuilder
  232. #sonata.admin.security.mask.builder:
  233. # class: Sonata\AdminBundle\Security\Acl\Permission\MaskBuilder
  234. # Symfony < 3
  235. parameters:
  236. security.acl.permission.map.class: Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap
  237. # optionally use a custom MaskBuilder
  238. #sonata.admin.security.mask.builder.class: Sonata\AdminBundle\Security\Acl\Permission\MaskBuilder
  239. In ``app/config/security.yml``:
  240. .. configuration-block::
  241. .. code-block:: yaml
  242. # app/config/security.yml
  243. security:
  244. providers:
  245. fos_userbundle:
  246. id: fos_user.user_manager
  247. firewalls:
  248. main:
  249. pattern: .*
  250. form-login:
  251. provider: fos_userbundle
  252. login_path: /login
  253. use_forward: false
  254. check_path: /login_check
  255. failure_path: null
  256. logout: true
  257. anonymous: true
  258. access_control:
  259. # The WDT has to be allowed to anonymous users to avoid requiring the login with the AJAX request
  260. - { path: ^/wdt/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  261. - { path: ^/profiler/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  262. # AsseticBundle paths used when using the controller for assets
  263. - { path: ^/js/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  264. - { path: ^/css/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  265. # URL of FOSUserBundle which need to be available to anonymous users
  266. - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  267. - { path: ^/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY } # for the case of a failed login
  268. - { path: ^/user/new$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  269. - { path: ^/user/check-confirmation-email$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  270. - { path: ^/user/confirm/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  271. - { path: ^/user/confirmed$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  272. - { path: ^/user/request-reset-password$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  273. - { path: ^/user/send-resetting-email$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  274. - { path: ^/user/check-resetting-email$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  275. - { path: ^/user/reset-password/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  276. # Secured part of the site
  277. # This config requires being logged for the whole site and having the admin role for the admin part.
  278. # Change these rules to adapt them to your needs
  279. - { path: ^/admin/, role: ROLE_ADMIN }
  280. - { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
  281. role_hierarchy:
  282. ROLE_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN]
  283. ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
  284. acl:
  285. connection: default
  286. - Install the ACL tables ``php app/console init:acl``
  287. - Create a new root user:
  288. .. code-block:: bash
  289. $ php app/console fos:user:create --super-admin
  290. Please choose a username:root
  291. Please choose an email:root@domain.com
  292. Please choose a password:root
  293. Created user root
  294. If you have Admin classes, you can install or update the related CRUD ACL rules:
  295. .. code-block:: bash
  296. $ php app/console sonata:admin:setup-acl
  297. Starting ACL AdminBundle configuration
  298. > install ACL for sonata.media.admin.media
  299. - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_GUEST, permissions: ["VIEW","LIST"]
  300. - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_STAFF, permissions: ["EDIT","LIST","CREATE"]
  301. - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_EDITOR, permissions: ["OPERATOR","EXPORT"]
  302. - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_ADMIN, permissions: ["MASTER"]
  303. ... skipped ...
  304. If you already have objects, you can generate the object ACL rules for each
  305. object of an admin:
  306. .. code-block:: bash
  307. $ php app/console sonata:admin:generate-object-acl
  308. Optionally, you can specify an object owner, and step through each admin. See
  309. the help of the command for more information.
  310. If you try to access to the admin class you should see the login form, just
  311. log in with the ``root`` user.
  312. An Admin is displayed in the dashboard (and menu) when the user has the role
  313. ``LIST``. To change this override the ``showIn`` method in the Admin class.
  314. Roles and Access control lists
  315. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  316. A user can have several roles when working with an application. Each Admin class
  317. has several roles, and each role specifies the permissions of the user for the
  318. ``Admin`` class. Or more specifically, what the user can do with the domain object(s)
  319. the ``Admin`` class is created for.
  320. By default each ``Admin`` class contains the following roles, override the
  321. property ``$securityInformation`` to change this:
  322. - ``ROLE_SONATA_..._GUEST``
  323. a guest that is allowed to ``VIEW`` an object and a ``LIST`` of objects;
  324. - ``ROLE_SONATA_..._STAFF``
  325. probably the biggest part of the users, a staff user has the same permissions
  326. as guests and is additionally allowed to ``EDIT`` and ``CREATE`` new objects;
  327. - ``ROLE_SONATA_..._EDITOR``
  328. an editor is granted all access and, compared to the staff users, is allowed to ``DELETE``;
  329. - ``ROLE_SONATA_..._ADMIN``
  330. an administrative user is granted all access and on top of that, the user is allowed to grant other users access.
  331. Owner:
  332. - when an object is created, the currently logged in user is set as owner for
  333. that object and is granted all access for that object;
  334. - this means the user owning the object is always allowed to ``DELETE`` the
  335. object, even when they only have the staff role.
  336. Vocabulary used for Access Control Lists:
  337. - **Role:** a user role;
  338. - **ACL:** a list of access rules, the Admin uses 2 types;
  339. - **Admin ACL:** created from the Security information of the Admin class
  340. for each admin and shares the Access Control Entries that specify what
  341. the user can do (permissions) with the admin;
  342. - **Object ACL:** also created from the security information of the ``Admin``
  343. class however created for each object, it uses 2 scopes:
  344. - **Class-Scope:** the class scope contains the rules that are valid
  345. for all object of a certain class;
  346. - **Object-Scope:** specifies the owner;
  347. - **Sid:** Security identity, an ACL role for the Class-Scope ACL and the
  348. user for the Object-Scope ACL;
  349. - **Oid:** Object identity, identifies the ACL, for the admin ACL this is
  350. the admin code, for the object ACL this is the object id;
  351. - **ACE:** a role (or sid) and its permissions;
  352. - **Permission:** this tells what the user is allowed to do with the Object
  353. identity;
  354. - **Bitmask:** a permission can have several bitmasks, each bitmask
  355. represents a permission. When permission ``VIEW`` is requested and it
  356. contains the ``VIEW`` and ``EDIT`` bitmask and the user only has the
  357. ``EDIT`` permission, then the permission ``VIEW`` is granted.
  358. - **PermissionMap:** configures the bitmasks for each permission, to change
  359. the default mapping create a voter for the domain class of the Admin.
  360. There can be many voters that may have different permission maps. However,
  361. prevent that multiple voters vote on the same class with overlapping bitmasks.
  362. See the cookbook article "`Advanced ACL concepts
  363. <http://symfony.com/doc/current/cookbook/security/acl_advanced.html#pre-authorization-decisions.>`_"
  364. for the meaning of the different permissions.
  365. How is access granted?
  366. ~~~~~~~~~~~~~~~~~~~~~~
  367. In the application the security context is asked if access is granted for a role
  368. or a permission (``admin.isGranted``):
  369. - **Token:** a token identifies a user between requests;
  370. - **Voter:** sort of judge that returns whether access is granted or denied, if the
  371. voter should not vote for a case, it returns abstain;
  372. - **AccessDecisionManager:** decides whether access is granted or denied according
  373. a specific strategy. It grants access if at least one (affirmative strategy),
  374. all (unanimous strategy) or more then half (consensus strategy) of the
  375. counted votes granted access;
  376. - **RoleVoter:** votes for all attributes stating with ``ROLE_`` and grants
  377. access if the user has this role;
  378. - **RoleHierarchyVoter:** when the role ``ROLE_SONATA_ADMIN`` is voted for,
  379. it also votes "granted" if the user has the role ``ROLE_SUPER_ADMIN``;
  380. - **AclVoter:** grants access for the permissions of the ``Admin`` class if
  381. the user has the permission, the user has a permission that is included in
  382. the bitmasks of the permission requested to vote for or the user owns the
  383. object.
  384. Create a custom voter or a custom permission map
  385. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  386. In some occasions you need to create a custom voter or a custom permission map
  387. because for example you want to restrict access using extra rules:
  388. - create a custom voter class that extends the ``AclVoter``
  389. .. code-block:: php
  390. <?php
  391. // src/AppBundle/Security/Authorization/Voter/UserAclVoter.php
  392. namespace AppBundle\Security\Authorization\Voter;
  393. use FOS\UserBundle\Model\UserInterface;
  394. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  395. use Symfony\Component\Security\Acl\Voter\AclVoter;
  396. class UserAclVoter extends AclVoter
  397. {
  398. public function supportsClass($class)
  399. {
  400. // support the Class-Scope ACL for votes with the custom permission map
  401. // return $class === 'Sonata\UserBundle\Admin\Entity\UserAdmin' || is_subclass_of($class, 'FOS\UserBundle\Model\UserInterface');
  402. // if you use php >=5.3.7 you can check the inheritance with is_a($class, 'Sonata\UserBundle\Admin\Entity\UserAdmin');
  403. // support the Object-Scope ACL
  404. return is_subclass_of($class, 'FOS\UserBundle\Model\UserInterface');
  405. }
  406. public function supportsAttribute($attribute)
  407. {
  408. return $attribute === 'EDIT' || $attribute === 'DELETE';
  409. }
  410. public function vote(TokenInterface $token, $object, array $attributes)
  411. {
  412. if (!$this->supportsClass(get_class($object))) {
  413. return self::ACCESS_ABSTAIN;
  414. }
  415. foreach ($attributes as $attribute) {
  416. if ($this->supportsAttribute($attribute) && $object instanceof UserInterface) {
  417. if ($object->isSuperAdmin() && !$token->getUser()->isSuperAdmin()) {
  418. // deny a non super admin user to edit a super admin user
  419. return self::ACCESS_DENIED;
  420. }
  421. }
  422. }
  423. // use the parent vote with the custom permission map:
  424. // return parent::vote($token, $object, $attributes);
  425. // otherwise leave the permission voting to the AclVoter that is using the default permission map
  426. return self::ACCESS_ABSTAIN;
  427. }
  428. }
  429. - optionally create a custom permission map, copy to start the
  430. ``Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap.php`` to
  431. your bundle
  432. - declare the voter and permission map as a service
  433. .. configuration-block::
  434. .. code-block:: xml
  435. <!-- src/AppBundle/Resources/config/services.xml -->
  436. <!-- <service id="security.acl.user_permission.map" class="AppBundle\Security\Acl\Permission\UserAdminPermissionMap" public="false"></service> -->
  437. <service id="security.acl.voter.user_permissions" class="AppBundle\Security\Authorization\Voter\UserAclVoter" public="false">
  438. <tag name="monolog.logger" channel="security" />
  439. <argument type="service" id="security.acl.provider" />
  440. <argument type="service" id="security.acl.object_identity_retrieval_strategy" />
  441. <argument type="service" id="security.acl.security_identity_retrieval_strategy" />
  442. <argument type="service" id="security.acl.permission.map" />
  443. <argument type="service" id="logger" on-invalid="null" />
  444. <tag name="security.voter" priority="255" />
  445. </service>
  446. - change the access decision strategy to ``unanimous``
  447. .. configuration-block::
  448. .. code-block:: yaml
  449. # app/config/security.yml
  450. security:
  451. access_decision_manager:
  452. # strategy value can be: affirmative, unanimous or consensus
  453. strategy: unanimous
  454. - to make this work the permission needs to be checked using the Object ACL
  455. - modify the template (or code) where applicable:
  456. .. code-block:: html+jinja
  457. {% if admin.hasAccess('edit', user_object) %}
  458. {# ... #}
  459. {% endif %}
  460. - because the object ACL permission is checked, the ACL for the object must
  461. have been created, otherwise the ``AclVoter`` will deny ``EDIT`` access
  462. for a non super admin user trying to edit another non super admin user.
  463. This is automatically done when the object is created using the Admin.
  464. If objects are also created outside the Admin, have a look at the
  465. ``createSecurityObject`` method in the ``AclSecurityHandler``.
  466. Usage
  467. ~~~~~
  468. Every time you create a new ``Admin`` class, you should start with the command
  469. ``php app/console sonata:admin:setup-acl`` so the ACL database will be updated
  470. with the latest roles and permissions.
  471. In the templates, or in your code, you can use the Admin method ``hasAccess()``:
  472. - check for an admin that the user is allowed to ``EDIT``:
  473. .. code-block:: html+jinja
  474. {# use the admin security method #}
  475. {% if admin.hasAccess('edit') %}
  476. {# ... #}
  477. {% endif %}
  478. {# or use the default is_granted Symfony helper, the following will give the same result #}
  479. {% if is_granted('ROLE_SUPER_ADMIN') or is_granted('EDIT', admin) %}
  480. {# ... #}
  481. {% endif %}
  482. - check for an admin that the user is allowed to ``DELETE``, the object is added
  483. to also check if the object owner is allowed to ``DELETE``:
  484. .. code-block:: html+jinja
  485. {# use the admin security method #}
  486. {% if admin.hasAccess('delete', object) %}
  487. {# ... #}
  488. {% endif %}
  489. {# or use the default is_granted Symfony helper, the following will give the same result #}
  490. {% if is_granted('ROLE_SUPER_ADMIN') or is_granted('DELETE', object) %}
  491. {# ... #}
  492. {% endif %}
  493. List filtering
  494. ~~~~~~~~~~~~~~
  495. List filtering using ACL is available as a third party bundle:
  496. `CoopTilleulsAclSonataAdminExtensionBundle <https://github.com/coopTilleuls/CoopTilleulsAclSonataAdminExtensionBundle>`_.
  497. When enabled, the logged in user will only see the objects for which it has the `VIEW` right (or superior).
  498. ACL editor
  499. ----------
  500. SonataAdminBundle provides a user-friendly ACL editor
  501. interface.
  502. It will be automatically available if the ``sonata.admin.security.handler.acl``
  503. security handler is used and properly configured.
  504. The ACL editor is only available for users with `OWNER` or `MASTER` permissions
  505. on the object instance.
  506. The `OWNER` and `MASTER` permissions can only be edited by an user with the
  507. `OWNER` permission on the object instance.
  508. .. figure:: ../images/acl_editor.png
  509. :align: center
  510. :alt: The ACL editor
  511. :width: 700px
  512. User list customization
  513. ~~~~~~~~~~~~~~~~~~~~~~~
  514. By default, the ACL editor allows to set permissions for all users managed by
  515. ``FOSUserBundle``.
  516. To customize displayed user override
  517. ``Sonata\AdminBundle\Controller\CRUDController::getAclUsers()``. This method must
  518. return an iterable collection of users.
  519. .. code-block:: php
  520. protected function getAclUsers()
  521. {
  522. $userManager = $container->get('fos_user.user_manager');
  523. // Display only kevin and anne
  524. $users[] = $userManager->findUserByUsername('kevin');
  525. $users[] = $userManager->findUserByUsername('anne');
  526. return new \ArrayIterator($users);
  527. }
  528. Role list customization
  529. ~~~~~~~~~~~~~~~~~~~~~~~
  530. By default, the ACL editor allows to set permissions for all roles.
  531. To customize displayed role override
  532. ``Sonata\AdminBundle\Controller\CRUDController::getAclRoles()``. This method must
  533. return an iterable collection of roles.
  534. .. code-block:: php
  535. protected function getAclRoles()
  536. {
  537. // Display only ROLE_BAPTISTE and ROLE_HELENE
  538. $roles = array(
  539. 'ROLE_BAPTISTE',
  540. 'ROLE_HELENE'
  541. );
  542. return new \ArrayIterator($roles);
  543. }
  544. Custom user manager
  545. ~~~~~~~~~~~~~~~~~~~
  546. If your project does not use `FOSUserBundle`, you can globally configure another
  547. service to use when retrieving your users.
  548. - Create a service with a method called ``findUsers()`` returning an iterable
  549. collection of users
  550. - Update your admin configuration to reference your service name
  551. .. configuration-block::
  552. .. code-block:: yaml
  553. # app/config/config.yml
  554. sonata_admin:
  555. security:
  556. # the name of your service
  557. acl_user_manager: my_user_manager
  558. .. _`SonataUserBundle's documentation area`: https://sonata-project.org/bundles/user/master/doc/reference/installation.html
  559. .. _`changing the access decision strategy`: http://symfony.com/doc/2.2/cookbook/security/voters.html#changing-the-access-decision-strategy
  560. .. _`create your own voter`: http://symfony.com/doc/2.2/cookbook/security/voters.html