diff --git a/cookbook/security/acl.rst b/cookbook/security/acl.rst index 7b4c36b54a7..b4c3e706846 100644 --- a/cookbook/security/acl.rst +++ b/cookbook/security/acl.rst @@ -12,7 +12,7 @@ the ACL system comes in. Imagine you are designing a blog system where your users can comment on your posts. Now, you want a user to be able to edit his own comments, but not those of other users; besides, you yourself want to be able to edit all comments. In -this scenario, ``Comment`` would be our domain object that you want to +this scenario, ``Comment`` would be the domain object that you want to restrict access to. You could take several approaches to accomplish this using Symfony2, two basic approaches are (non-exhaustive): @@ -27,13 +27,13 @@ logic to your business code which makes it less reusable elsewhere, and also increases the difficulty of unit testing. Besides, you could run into performance issues if many users would have access to a single domain object. -Fortunately, there is a better way, which we will talk about now. +Fortunately, there is a better way, which you will find out about now. Bootstrapping ------------- -Now, before we finally can get into action, we need to do some bootstrapping. -First, we need to configure the connection the ACL system is supposed to use: +Now, before you can finally get into action, you need to do some bootstrapping. +First, you need to configure the connection the ACL system is supposed to use: .. configuration-block:: @@ -67,8 +67,8 @@ First, we need to configure the connection the ACL system is supposed to use: domain objects. You can use whatever mapper you like for your objects, be it Doctrine ORM, MongoDB ODM, Propel, raw SQL, etc. The choice is yours. -After the connection is configured, we have to import the database structure. -Fortunately, we have a task for this. Simply run the following command: +After the connection is configured, you have to import the database structure. +Fortunately, there is a task for this. Simply run the following command: .. code-block:: bash @@ -77,7 +77,7 @@ Fortunately, we have a task for this. Simply run the following command: Getting Started --------------- -Coming back to our small example from the beginning, let's implement ACL for +Coming back to the small example from the beginning, let's implement ACL for it. Creating an ACL, and adding an ACE @@ -136,11 +136,11 @@ have no actual domain object instance at hand. This will be extremely helpful if you want to check permissions for a large number of objects without actually hydrating these objects. -The other interesting part is the ``->insertObjectAce()`` call. In our -example, we are granting the user who is currently logged in owner access to +The other interesting part is the ``->insertObjectAce()`` call. In the +example, you are granting the user who is currently logged in owner access to the Comment. The ``MaskBuilder::MASK_OWNER`` is a pre-defined integer bitmask; don't worry the mask builder will abstract away most of the technical details, -but using this technique we can store many different permissions in one +but using this technique you can store many different permissions in one database row which gives us a considerable boost in performance. .. tip:: @@ -175,7 +175,7 @@ Checking Access } } -In this example, we check whether the user has the ``EDIT`` permission. +In this example, you check whether the user has the ``EDIT`` permission. Internally, Symfony2 maps the permission to several integer bitmasks, and checks whether the user has any of them. @@ -188,10 +188,10 @@ checks whether the user has any of them. Cumulative Permissions ---------------------- -In our first example above, we only granted the user the ``OWNER`` base +In the first example above, you only granted the user the ``OWNER`` base permission. While this effectively also allows the user to perform any operation such as view, edit, etc. on the domain object, there are cases where -we want to grant these permissions explicitly. +you may want to grant these permissions explicitly. The ``MaskBuilder`` can be used for creating bit masks easily by combining several base permissions: diff --git a/cookbook/security/acl_advanced.rst b/cookbook/security/acl_advanced.rst index 1959a59fb59..3e741572ae2 100644 --- a/cookbook/security/acl_advanced.rst +++ b/cookbook/security/acl_advanced.rst @@ -24,9 +24,9 @@ objectives: As indicated by the first point, one of the main capabilities of Symfony2's ACL system is a high-performance way of retrieving ACLs/ACEs. This is extremely important since each ACL might have several ACEs, and inherit from -another ACL in a tree-like fashion. Therefore, we specifically do not leverage -any ORM, but the default implementation interacts with your connection -directly using Doctrine's DBAL. +another ACL in a tree-like fashion. Therefore, no ORM is leveraged, instead +the default implementation interacts with your connection directly using Doctrine's +DBAL. Object Identities ~~~~~~~~~~~~~~~~~ @@ -71,16 +71,16 @@ Scope of Access Control Entries ------------------------------- Access control entries can have different scopes in which they apply. In -Symfony2, we have basically two different scopes: +Symfony2, there are basically two different scopes: - Class-Scope: These entries apply to all objects with the same class. -- Object-Scope: This was the scope we solely used in the previous chapter, and +- Object-Scope: This was the scope solely used in the previous chapter, and it only applies to one specific object. Sometimes, you will find the need to apply an ACE only to a specific field of the object. Let's say you want the ID only to be viewable by an administrator, -but not by your customer service. To solve this common problem, we have added -two more sub-scopes: +but not by your customer service. To solve this common problem, two more sub-scopes +have been added: - Class-Field-Scope: These entries apply to all objects with the same class, but only to a specific field of the objects. @@ -91,10 +91,10 @@ Pre-Authorization Decisions --------------------------- For pre-authorization decisions, that is decisions made before any secure method (or -secure action) is invoked, we rely on the proven AccessDecisionManager service -that is also used for reaching authorization decisions based on roles. Just -like roles, the ACL system adds several new attributes which may be used to -check for different permissions. +secure action) is invoked, the proven AccessDecisionManager service is used. +The AccessDecisionManager is also used for reaching authorization decisions based +on roles. Just like roles, the ACL system adds several new attributes which may be +used to check for different permissions. Built-in Permission Map ~~~~~~~~~~~~~~~~~~~~~~~ @@ -153,8 +153,8 @@ Extensibility The above permission map is by no means static, and theoretically could be completely replaced at will. However, it should cover most problems you -encounter, and for interoperability with other bundles, we encourage you to -stick to the meaning we have envisaged for them. +encounter, and for interoperability with other bundles, you are encouraged to +stick to the meaning envisaged for them. Post Authorization Decisions ---------------------------- diff --git a/cookbook/security/custom_authentication_provider.rst b/cookbook/security/custom_authentication_provider.rst index 5b35743dd73..cc2a8be663f 100644 --- a/cookbook/security/custom_authentication_provider.rst +++ b/cookbook/security/custom_authentication_provider.rst @@ -45,8 +45,8 @@ The Token The role of the token in the Symfony2 security context is an important one. A token represents the user authentication data present in the request. Once a request is authenticated, the token retains the user's data, and delivers -this data across the security context. First, we will create our token class. -This will allow the passing of all relevant information to our authentication +this data across the security context. First, you'll create your token class. +This will allow the passing of all relevant information to your authentication provider. .. code-block:: php @@ -332,7 +332,7 @@ a firewall in your security configuration. .. note:: - You may be wondering "why do we need a special factory class to add listeners + You may be wondering "why do you need a special factory class to add listeners and providers to the dependency injection container?". This is a very good question. The reason is you can use your firewall multiple times, to secure multiple parts of your application. Because of this, each diff --git a/cookbook/security/custom_provider.rst b/cookbook/security/custom_provider.rst index c33f9cb126c..7367bb14556 100644 --- a/cookbook/security/custom_provider.rst +++ b/cookbook/security/custom_provider.rst @@ -10,9 +10,9 @@ the configured user provider to return a user object for a given username. Symfony then checks whether the password of this user is correct and generates a security token so the user stays authenticated during the current session. Out of the box, Symfony has an "in_memory" and an "entity" user provider. -In this entry we'll see how you can create your own user provider, which +In this entry you'll see how you can create your own user provider, which could be useful if your users are accessed via a custom database, a file, -or - as we show in this example - a web service. +or - as shown in this example - a web service. Create a User Class ------------------- @@ -21,7 +21,7 @@ First, regardless of *where* your user data is coming from, you'll need to create a ``User`` class that represents that data. The ``User`` can look however you want and contain any data. The only requirement is that the class implements :class:`Symfony\\Component\\Security\\Core\\User\\UserInterface`. -The methods in this interface should therefore be defined in the custom user +The methods in this interface should therefore be defined in the custom user class: ``getRoles()``, ``getPassword()``, ``getSalt()``, ``getUsername()``, ``eraseCredentials()``, ``equals()``. @@ -101,12 +101,12 @@ For more details on each of the methods, see :class:`Symfony\\Component\\Securit Create a User Provider ---------------------- -Now that we have a ``User`` class, we'll create a user provider, which will +Now that you have a ``User`` class, you'll create a user provider, which will grab user information from some web service, create a ``WebserviceUser`` object, and populate it with data. -The user provider is just a plain PHP class that has to implement the -:class:`Symfony\\Component\\Security\\Core\\User\\UserProviderInterface`, +The user provider is just a plain PHP class that has to implement the +:class:`Symfony\\Component\\Security\\Core\\User\\UserProviderInterface`, which requires three methods to be defined: ``loadUserByUsername($username)``, ``refreshUser(UserInterface $user)``, and ``supportsClass($class)``. For more details, see :class:`Symfony\\Component\\Security\\Core\\User\\UserProviderInterface`. @@ -158,7 +158,7 @@ Here's an example of how this might look:: Create a Service for the User Provider -------------------------------------- -Now we make the user provider available as a service. +Now you make the user provider available as a service: .. configuration-block:: @@ -167,29 +167,29 @@ Now we make the user provider available as a service. # src/Acme/WebserviceUserBundle/Resources/config/services.yml parameters: webservice_user_provider.class: Acme\WebserviceUserBundle\Security\User\WebserviceUserProvider - + services: webservice_user_provider: class: "%webservice_user_provider.class%" - + .. code-block:: xml Acme\WebserviceUserBundle\Security\User\WebserviceUserProvider - + - + .. code-block:: php - + // src/Acme/WebserviceUserBundle/Resources/config/services.php use Symfony\Component\DependencyInjection\Definition; - + $container->setParameter('webservice_user_provider.class', 'Acme\WebserviceUserBundle\Security\User\WebserviceUserProvider'); - + $container->setDefinition('webservice_user_provider', new Definition('%webservice_user_provider.class%'); .. tip:: @@ -207,7 +207,7 @@ Modify ``security.yml`` ----------------------- In ``/app/config/security.yml`` everything comes together. Add the user provider -to the list of providers in the "security" section. Choose a name for the user provider +to the list of providers in the "security" section. Choose a name for the user provider (e.g. "webservice") and mention the id of the service you just defined. .. code-block:: yaml @@ -218,8 +218,8 @@ to the list of providers in the "security" section. Choose a name for the user p id: webservice_user_provider Symfony also needs to know how to encode passwords that are supplied by website -users, e.g. by filling in a login form. You can do this by adding a line to the -"encoders" section in ``/app/config/security.yml``. +users, e.g. by filling in a login form. You can do this by adding a line to the +"encoders" section in ``/app/config/security.yml``. .. code-block:: yaml @@ -241,7 +241,7 @@ options, the password may be encoded multiple times and encoded to base64. nothing, then the submitted password is simply encoded using the algorithm you specify in ``security.yml``. If a salt *is* specified, then the following value is created and *then* hashed via the algorithm: - + ``$password.'{'.$salt.'}';`` If your external users have their passwords salted via a different method, @@ -249,13 +249,13 @@ options, the password may be encoded multiple times and encoded to base64. the password. That is beyond the scope of this entry, but would include sub-classing ``MessageDigestPasswordEncoder`` and overriding the ``mergePasswordAndSalt`` method. - + Additionally, the hash, by default, is encoded multiple times and encoded to base64. For specific details, see `MessageDigestPasswordEncoder`_. To prevent this, configure it in ``security.yml``: - + .. code-block:: yaml - + security: encoders: Acme\WebserviceUserBundle\Security\User\WebserviceUser: diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index b1f75d26104..d77f7bb7f4d 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -159,7 +159,7 @@ For more details on each of these, see :class:`Symfony\\Component\\Security\\Cor To keep it simple, the ``equals()`` method just compares the ``username`` field but it's also possible to do more checks depending on the complexity of your data model. On the other hand, the ``eraseCredentials()`` method remains empty -as we don't care about it in this tutorial. +for the purposes of this tutorial. Below is an export of my ``User`` table from MySQL. For details on how to create user records and encode their password, see :ref:`book-security-encoding-user-password`. @@ -192,7 +192,7 @@ layer is a piece of cake. Everything resides in the configuration of the Below is an example of configuration where the user will enter his/her username and password via HTTP basic authentication. That information will -then be checked against our User entity records in the database: +then be checked against your User entity records in the database: .. configuration-block:: @@ -236,7 +236,7 @@ the ``username`` unique field. In other words, this tells Symfony how to fetch the user from the database before checking the password validity. This code and configuration works but it's not enough to secure the application -for **active** users. As of now, we still can authenticate with ``maxime``. The +for **active** users. As of now, you can still authenticate with ``maxime``. The next section explains how to forbid non active users. Forbid non Active Users @@ -295,7 +295,7 @@ For this example, the first three methods will return ``true`` whereas the } } -If we try to authenticate a ``maxime``, the access is now forbidden as this +If you try to authenticate as ``maxime``, the access is now forbidden as this user does not have an enabled account. The next session will focus on how to write a custom entity provider to authenticate a user with his username or his email address. @@ -400,7 +400,7 @@ from the database. As mentioned previously, when your user is loaded, its ``getRoles()`` method returns the array of security roles that should be assigned to the user. You can load this data from anywhere - a hardcoded list used for all users (e.g. ``array('ROLE_USER')``), a Doctrine array -property called ``roles``, or via a Doctrine relationship, as we'll learn +property called ``roles``, or via a Doctrine relationship, as you'll learn about in this section. .. caution:: diff --git a/cookbook/security/voters.rst b/cookbook/security/voters.rst index b7198a9241f..10242b37ca3 100644 --- a/cookbook/security/voters.rst +++ b/cookbook/security/voters.rst @@ -45,16 +45,16 @@ values: * ``VoterInterface::ACCESS_ABSTAIN``: The voter cannot decide if the user is granted or not * ``VoterInterface::ACCESS_DENIED``: The user is not allowed to access the application -In this example, we will check if the user's IP address matches against a list of -blacklisted addresses. If the user's IP is blacklisted, we will return -``VoterInterface::ACCESS_DENIED``, otherwise we will return +In this example, you'll check if the user's IP address matches against a list of +blacklisted addresses. If the user's IP is blacklisted, you'll return +``VoterInterface::ACCESS_DENIED``, otherwise you'll return ``VoterInterface::ACCESS_ABSTAIN`` as this voter's purpose is only to deny access, not to grant access. Creating a Custom Voter ----------------------- -To blacklist a user based on its IP, we can use the ``request`` service +To blacklist a user based on its IP, you can use the ``request`` service and compare the IP address against a set of blacklisted IP addresses: .. code-block:: php @@ -76,13 +76,13 @@ and compare the IP address against a set of blacklisted IP addresses: public function supportsAttribute($attribute) { - // we won't check against a user attribute, so we return true + // you won't check against a user attribute, so return true return true; } public function supportsClass($class) { - // our voter supports all type of token classes, so we return true + // your voter supports all type of token classes, so return true return true; } @@ -103,7 +103,7 @@ the security layer. This can be done easily through the service container. Declaring the Voter as a Service -------------------------------- -To inject the voter into the security layer, we must declare it as a service, +To inject the voter into the security layer, you must declare it as a service, and tag it as a "security.voter": .. configuration-block:: @@ -160,11 +160,11 @@ and tag it as a "security.voter": Changing the Access Decision Strategy ------------------------------------- -In order for the new voter to take effect, we need to change the default access +In order for the new voter to take effect, you need to change the default access decision strategy, which, by default, grants access if *any* voter grants access. -In our case, we will choose the ``unanimous`` strategy. Unlike the ``affirmative`` +In this case, choose the ``unanimous`` strategy. Unlike the ``affirmative`` strategy (the default), with the ``unanimous`` strategy, if only one voter denies access (e.g. the ``ClientIpVoter``), access is not granted to the end user.