security.rst 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. Security
  2. ========
  3. Users management
  4. ----------------
  5. By default, the SonataAdminBundle does not come with any user management,
  6. however it is most likely the application requires such feature. The Sonata
  7. Project includes a ``SonataUserBundle`` which integrates the ``FOSUserBundle``.
  8. The ``FOSUserBundle`` adds support for a database-backed user system in Symfony2.
  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 `SonataUserBundle's
  22. documentation area
  23. <http://sonata-project.org/bundles/user/master/doc/reference/installation.html>`_
  24. Security handlers
  25. -----------------
  26. The security part is managed by a ``SecurityHandler``, the bundle comes with 3
  27. handlers
  28. - ``sonata.admin.security.handler.role`` : ROLES to handle permissions
  29. - ``sonata.admin.security.handler.acl`` : ACL and ROLES to handle permissions
  30. - ``sonata.admin.security.handler.noop`` : always returns true, can be used
  31. with the Symfony2 firewall
  32. The default value is ``sonata.admin.security.handler.noop``, if you want to
  33. change the default value you can set the ``security_handler`` to
  34. ``sonata.admin.security.handler.acl`` or ``sonata.admin.security.handler.role``.
  35. To quickly secure an admin the role security can be used. It allows to specify
  36. the actions a user can with the admin. The ACL security system is more advanced
  37. and allows to secure the objects. For people using the previous ACL
  38. implementation, you can switch the security_handler to the role security handler.
  39. Configuration
  40. ~~~~~~~~~~~~~
  41. Only the security handler is required to determine which type of security to use.
  42. The other parameters are set as default, change them if needed.
  43. Using roles:
  44. .. code-block:: yaml
  45. sonata_admin:
  46. security:
  47. handler: sonata.admin.security.handler.role
  48. # role security information
  49. information:
  50. EDIT: EDIT
  51. LIST: LIST
  52. CREATE: CREATE
  53. VIEW: VIEW
  54. DELETE: DELETE
  55. EXPORT: EXPORT
  56. OPERATOR: OPERATOR
  57. MASTER: MASTER
  58. Using ACL:
  59. .. code-block:: yaml
  60. # app/config/config.yml
  61. sonata_admin:
  62. security:
  63. handler: sonata.admin.security.handler.acl
  64. # acl security information
  65. information:
  66. GUEST: [VIEW, LIST]
  67. STAFF: [EDIT, LIST, CREATE]
  68. EDITOR: [OPERATOR, EXPORT]
  69. ADMIN: [MASTER]
  70. # permissions not related to an object instance and also to be available when objects do not exist
  71. # the DELETE admin permission means the user is allowed to batch delete objects
  72. admin_permissions: [CREATE, LIST, DELETE, UNDELETE, EXPORT, OPERATOR, MASTER]
  73. # permission related to the objects
  74. object_permissions: [VIEW, EDIT, DELETE, UNDELETE, OPERATOR, MASTER, OWNER]
  75. The following section explains how to set up ACL with the
  76. ``FriendsOfSymfony/UserBundle``.
  77. ACL and FriendsOfSymfony/UserBundle
  78. -----------------------------------
  79. If you want an easy way to handle users, please use :
  80. - https://github.com/FriendsOfSymfony/FOSUserBundle : handle users and groups
  81. stored in RDMS or MongoDB
  82. - https://github.com/sonata-project/SonataUserBundle : integrates the
  83. ``FriendsOfSymfony/UserBundle`` with the ``AdminBundle``
  84. The security integration is a work in progress and has some known issues :
  85. - ACL permissions are immutables
  86. - A listener must be implemented that creates the object Access Control List
  87. with the required rules if objects are created outside the Admin
  88. Configuration
  89. ~~~~~~~~~~~~~
  90. Before you can use ``FriendsOfSymfony/FOSUserBundle`` you need to set it up as
  91. described in the documentation of the bundle. In step 4 you need to create a
  92. User class (in a custom UserBundle). Do it as follows:
  93. .. code-block:: php
  94. <?php
  95. namespace Acme\UserBundle\Entity;
  96. use Sonata\UserBundle\Entity\BaseUser as BaseUser;
  97. use Doctrine\ORM\Mapping as ORM;
  98. /**
  99. * @ORM\Entity
  100. * @ORM\Table(name="fos_user")
  101. \*/
  102. class User extends BaseUser
  103. {
  104. /**
  105. * @ORM\Id
  106. * @ORM\Column(type="integer")
  107. * @ORM\GeneratedValue(strategy="AUTO")
  108. \*/
  109. protected $id;
  110. public function __construct()
  111. {
  112. parent::__construct();
  113. // your own logic
  114. }
  115. }
  116. In your ``app/config/config.yml`` you then need to put the following:
  117. .. code-block:: yaml
  118. fos_user:
  119. db_driver: orm
  120. firewall_name: main
  121. user_class: Acme\UserBundle\Entity\User
  122. The following configuration for the SonataUserBundle defines:
  123. - the ``FriendsOfSymfony/FOSUserBundle`` as a security provider
  124. - the login form for authentication
  125. - the access control : resources with related required roles, the important
  126. part is the admin configuration
  127. - the ``acl`` option to enable the ACL.
  128. - the ``AdminPermissionMap`` defines the permissions of the Admin class
  129. .. code-block:: yaml
  130. # app/config/security.yml
  131. parameters:
  132. # ... other parameters
  133. security.acl.permission.map.class: Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap
  134. # optionally use a custom MaskBuilder
  135. #sonata.admin.security.mask.builder.class: Sonata\AdminBundle\Security\Acl\Permission\MaskBuilder
  136. In ``app/config/security.yml``:
  137. .. code-block:: yaml
  138. security:
  139. providers:
  140. fos_userbundle:
  141. id: fos_user.user_manager
  142. firewalls:
  143. main:
  144. pattern: .*
  145. form-login:
  146. provider: fos_userbundle
  147. login_path: /login
  148. use_forward: false
  149. check_path: /login_check
  150. failure_path: null
  151. logout: true
  152. anonymous: true
  153. access_control:
  154. # The WDT has to be allowed to anonymous users to avoid requiring the login with the AJAX request
  155. - { path: ^/wdt/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  156. - { path: ^/profiler/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  157. # AsseticBundle paths used when using the controller for assets
  158. - { path: ^/js/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  159. - { path: ^/css/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  160. # URL of FOSUserBundle which need to be available to anonymous users
  161. - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  162. - { path: ^/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY } # for the case of a failed login
  163. - { path: ^/user/new$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  164. - { path: ^/user/check-confirmation-email$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  165. - { path: ^/user/confirm/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  166. - { path: ^/user/confirmed$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  167. - { path: ^/user/request-reset-password$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  168. - { path: ^/user/send-resetting-email$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  169. - { path: ^/user/check-resetting-email$, role: IS_AUTHENTICATED_ANONYMOUSLY }
  170. - { path: ^/user/reset-password/, role: IS_AUTHENTICATED_ANONYMOUSLY }
  171. # Secured part of the site
  172. # This config requires being logged for the whole site and having the admin role for the admin part.
  173. # Change these rules to adapt them to your needs
  174. - { path: ^/admin/, role: ROLE_ADMIN }
  175. - { path: ^/.*, role: IS_AUTHENTICATED_ANONYMOUSLY }
  176. role_hierarchy:
  177. ROLE_ADMIN: [ROLE_USER, ROLE_SONATA_ADMIN]
  178. ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
  179. acl:
  180. connection: default
  181. - Install the ACL tables ``php app/console init:acl``
  182. - Create a new root user :
  183. .. code-block:: sh
  184. # php app/console fos:user:create --super-admin
  185. Please choose a username:root
  186. Please choose an email:root@domain.com
  187. Please choose a password:root
  188. Created user root
  189. If you have Admin classes, you can install or update the related CRUD ACL rules :
  190. .. code-block:: sh
  191. # php app/console sonata:admin:setup-acl
  192. Starting ACL AdminBundle configuration
  193. > install ACL for sonata.media.admin.media
  194. - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_GUEST, permissions: ["VIEW","LIST"]
  195. - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_STAFF, permissions: ["EDIT","LIST","CREATE"]
  196. - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_EDITOR, permissions: ["OPERATOR","EXPORT"]
  197. - add role: ROLE_SONATA_MEDIA_ADMIN_MEDIA_ADMIN, permissions: ["MASTER"]
  198. ... skipped ...
  199. If you already have objects, you can generate the object ACL rules for each
  200. object of an admin:
  201. .. code-block:: sh
  202. $ php app/console sonata:admin:generate-object-acl
  203. Optionally, you can specify an object owner, and step through each admin. See
  204. the help of the command for more information.
  205. If you try to access to the admin class you should see the login form, just
  206. log in with the ``root`` user.
  207. An Admin is displayed in the dashboard (and menu) when the user has the role
  208. ``LIST``. To change this override the ``showIn`` method in the Admin class.
  209. Roles and Access control lists
  210. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  211. A user can have several roles when working with an application. Each Admin class
  212. has several roles, and each role specifies the permissions of the user for the
  213. ``Admin`` class. Or more specifically, what the user can do with the domain object(s)
  214. the ``Admin`` class is created for.
  215. By default each ``Admin`` class contains the following roles, override the
  216. property ``$securityInformation`` to change this:
  217. - ``ROLE_SONATA_..._GUEST`` : a guest that is allowed to view an object and a
  218. list of objects;
  219. - ``ROLE_SONATA_..._STAFF`` : probably the biggest part of the users, a staff
  220. user has the same permissions as guests and is additionally allowed to
  221. ``EDIT`` and ``CREATE`` new objects;
  222. - ``ROLE_SONATA_..._EDITOR`` : an editor is granted all access and, compared to
  223. the staff users, is allowed to ``DELETE``;
  224. - ``ROLE_SONATA_..._ADMIN`` : an administrative user is granted all access and
  225. on top of that, the user is allowed to grant other users access.
  226. Owner:
  227. - when an object is created, the currently logged in user is set as owner for
  228. that object and is granted all access for that object;
  229. - this means the user owning the object is always allowed to ``DELETE`` the
  230. object, even when it only has the staff role.
  231. Vocabulary used for Access Control Lists:
  232. - **Role :** a user role;
  233. - **ACL :** a list of access rules, the Admin uses 2 types:
  234. - **Admin ACL :** created from the Security information of the Admin class
  235. for each admin and shares the Access Control Entries that specify what
  236. the user can do (permissions) with the admin
  237. - **Object ACL :** also created from the security information of the ``Admin``
  238. class however created for each object, it uses 2 scopes:
  239. - **Class-Scope :** the class scope contains the rules that are valid
  240. for all object of a certain class;
  241. - **Object-Scope :** specifies the owner;
  242. - **Sid :** Security identity, an ACL role for the Class-Scope ACL and the
  243. user for the Object-Scope ACL;
  244. - **Oid :** Object identity, identifies the ACL, for the admin ACL this is
  245. the admin code, for the object ACL this is the object id;
  246. - **ACE :** a role (or sid) and its permissions;
  247. - **Permission :** this tells what the user is allowed to do with the Object
  248. identity;
  249. - **Bitmask :** a permission can have several bitmasks, each bitmask
  250. represents a permission. When permission ``VIEW`` is requested and it
  251. contains the ``VIEW`` and ``EDIT`` bitmask and the user only has the
  252. ``EDIT`` permission, then the permission ``VIEW`` is granted.
  253. - **PermissionMap :** configures the bitmasks for each permission, to change
  254. the default mapping create a voter for the domain class of the Admin.
  255. There can be many voters that may have different permission maps. However,
  256. prevent that multiple voters vote on the same class with overlapping bitmasks.
  257. See the cookbook article "Advanced ACL concepts" for the meaning of the different
  258. permissions:
  259. http://symfony.com/doc/current/cookbook/security/acl_advanced.html#pre-authorization-decisions.
  260. How is access granted?
  261. ~~~~~~~~~~~~~~~~~~~~~~
  262. In the application the security context is asked if access is granted for a role
  263. or a permission (``admin.isGranted``):
  264. - **Token :** a token identifies a user between requests;
  265. - **Voter :** sort of judge that returns if access is granted of denied, if the
  266. voter should not vote for a case, it returns abstrain;
  267. - **AccessDecisionManager :** decides if access is granted or denied according
  268. a specific strategy. It grants access if at least one (affirmative strategy),
  269. all (unanimous strategy) or more then half (consensus strategy) of the
  270. counted votes granted access;
  271. - **RoleVoter :** votes for all attributes stating with ``ROLE_`` and grants
  272. access if the user has this role;
  273. - **RoleHierarchieVoter :** when the role ``ROLE_SONATA_ADMIN`` is voted for,
  274. it also votes "granted" if the user has the role ``ROLE_SUPER_ADMIN``;
  275. - **AclVoter :** grants access for the permissions of the ``Admin`` class if
  276. the user has the permission, the user has a permission that is included in
  277. the bitmasks of the permission requested to vote for or the user owns the
  278. object.
  279. Create a custom voter or a custom permission map
  280. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  281. In some occasions you need to create a custom voter or a custom permission map
  282. because for example you want to restrict access using extra rules:
  283. - create a custom voter class that extends the ``AclVoter``
  284. .. code-block:: php
  285. <?php
  286. namespace Acme\DemoBundle\Security\Authorization\Voter;
  287. use FOS\UserBundle\Model\UserInterface;
  288. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  289. use Symfony\Component\Security\Acl\Voter\AclVoter;
  290. class UserAclVoter extends AclVoter
  291. {
  292. /**
  293. * {@InheritDoc}
  294. */
  295. public function supportsClass($class)
  296. {
  297. // support the Class-Scope ACL for votes with the custom permission map
  298. // return $class === 'Sonata\UserBundle\Admin\Entity\UserAdmin' || $is_subclass_of($class, 'FOS\UserBundle\Model\UserInterface');
  299. // if you use php >=5.3.7 you can check the inheritance with is_a($class, 'Sonata\UserBundle\Admin\Entity\UserAdmin');
  300. // support the Object-Scope ACL
  301. return is_subclass_of($class, 'FOS\UserBundle\Model\UserInterface');
  302. }
  303. public function supportsAttribute($attribute)
  304. {
  305. return $attribute === 'EDIT' || $attribute === 'DELETE';
  306. }
  307. public function vote(TokenInterface $token, $object, array $attributes)
  308. {
  309. if (!$this->supportsClass(get_class($object))) {
  310. return self::ACCESS_ABSTAIN;
  311. }
  312. foreach ($attributes as $attribute) {
  313. if ($this->supportsAttribute($attribute) && $object instanceof UserInterface) {
  314. if ($object->isSuperAdmin() && !$token->getUser()->isSuperAdmin()) {
  315. // deny a non super admin user to edit a super admin user
  316. return self::ACCESS_DENIED;
  317. }
  318. }
  319. }
  320. // use the parent vote with the custom permission map:
  321. // return parent::vote($token, $object, $attributes);
  322. // otherwise leave the permission voting to the AclVoter that is using the default permission map
  323. return self::ACCESS_ABSTAIN;
  324. }
  325. }
  326. - optionally create a custom permission map, copy to start the
  327. ``Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap.php`` to
  328. your bundle
  329. - declare the voter and permission map as a service
  330. .. code-block:: xml
  331. <!-- src/Acme/DemoBundle/Resources/config/services.xml -->
  332. <parameters>
  333. <parameter key="security.acl.user_voter.class">Acme\DemoBundle\Security\Authorization\Voter\UserAclVoter</parameter>
  334. <!-- <parameter key="security.acl.user_permission.map.class">Acme\DemoBundle\Security\Acl\Permission\UserAdminPermissionMap</parameter> -->
  335. </parameters>
  336. <services>
  337. <!-- <service id="security.acl.user_permission.map" class="%security.acl.permission.map.class%" public="false"></service> -->
  338. <service id="security.acl.voter.user_permissions" class="%security.acl.user_voter.class%" public="false">
  339. <tag name="monolog.logger" channel="security" />
  340. <argument type="service" id="security.acl.provider" />
  341. <argument type="service" id="security.acl.object_identity_retrieval_strategy" />
  342. <argument type="service" id="security.acl.security_identity_retrieval_strategy" />
  343. <argument type="service" id="security.acl.permission.map" />
  344. <argument type="service" id="logger" on-invalid="null" />
  345. <tag name="security.voter" priority="255" />
  346. </service>
  347. </services>
  348. - change the access decision strategy to ``unanimous``
  349. .. code-block:: yaml
  350. # app/config/security.yml
  351. security:
  352. access_decision_manager:
  353. # Strategy can be: affirmative, unanimous or consensus
  354. strategy: unanimous
  355. - to make this work the permission needs to be checked using the Object ACL
  356. - modify the template (or code) where applicable:
  357. .. code-block:: html+jinja
  358. {% if admin.isGranted('EDIT', user_object) %} {# ... #} {% endif %}
  359. - because the object ACL permission is checked, the ACL for the object must
  360. have been created, otherwise the ``AclVoter`` will deny ``EDIT`` access
  361. for a non super admin user trying to edit another non super admin user.
  362. This is automatically done when the object is created using the Admin.
  363. If objects are also created outside the Admin, have a look at the
  364. ``createSecurityObject`` method in the ``AclSecurityHandler``.
  365. Usage
  366. ~~~~~
  367. Every time you create a new ``Admin`` class, you should start with the command
  368. ``php app/console sonata:admin:setup-acl`` so the ACL database will be updated
  369. with the latest roles and permissions.
  370. In the templates, or in your code, you can use the Admin method ``isGranted()`` :
  371. - check for an admin that the user is allowed to ``EDIT`` :
  372. .. code-block:: html+jinja
  373. {# use the admin security method #}
  374. {% if admin.isGranted('EDIT') %} {# ... #} {% endif %}
  375. {# or use the default is_granted symfony helper, the following will give the same result #}
  376. {% if is_granted('ROLE_SUPER_ADMIN') or is_granted('EDIT', admin) %} {# ... #} {% endif %}
  377. - check for an admin that the user is allowed to ``DELETE``, the object is added
  378. to also check if the object owner is allowed to ``DELETE`` :
  379. .. code-block:: html+jinja
  380. {# use the admin security method #}
  381. {% if admin.isGranted('DELETE', object) %} {# ... #} {% endif %}
  382. {# or use the default is_granted symfony helper, the following will give the same result #}
  383. {% if is_granted('ROLE_SUPER_ADMIN') or is_granted('DELETE', object) %} {# ... #} {% endif %}