From f09423795d55574af56242ab67d351c2b3085e68 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 1 Jan 2014 17:16:17 -0600 Subject: [PATCH 01/33] [#3276] Trying to further clarify the session storage directory details --- cookbook/session/sessions_directory.rst | 87 +++++++++++++++++++++---- 1 file changed, 74 insertions(+), 13 deletions(-) diff --git a/cookbook/session/sessions_directory.rst b/cookbook/session/sessions_directory.rst index ad662846f82..2f1a2209820 100644 --- a/cookbook/session/sessions_directory.rst +++ b/cookbook/session/sessions_directory.rst @@ -4,23 +4,84 @@ Configuring the Directory Where Sessions Files are Saved ======================================================== -By default, Symfony stores the session data in files in the cache -directory ``%kernel.cache_dir%/sessions``. This means that when you clear -the cache, any current sessions will also be deleted. +By default, the Symfony Standard Edition uses the global ``php.ini`` values +for ``session.save_handler`` and ``session.save_path`` to determine where +to store session data. This is because of the following configuration: -.. note:: +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + framework: + session: + # handler_id set to null will use default session handler from php.ini + handler_id: ~ + + .. code-block:: xml + + + + + + + + - If the ``session`` configuration key is set to ``~``, Symfony will use the - global PHP ini values for ``session.save_handler`` and associated - ``session.save_path`` from ``php.ini``. + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('framework', array( + 'session' => array( + 'handler-id' => null, + ), + )); -.. note:: +With this configuration, changing *where* your session metadata is stored +is entirely up to your ``php.ini`` configuration. - While the Symfony Full Stack Framework defaults to using the - ``session.handler.native_file``, the Symfony Standard Edition is - configured to use PHP's global session settings by default and therefor - sessions will be stored according to the ``session.save_path`` location - and will not be deleted when clearing the cache. +However, if you have the following configuration, Symfony will store the session +data in files in the cache directory ``%kernel.cache_dir%/sessions``. This +means that when you clear the cache, any current sessions will also be deleted: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + framework: + session: ~ + + .. code-block:: xml + + + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('framework', array( + 'session' => array(), + )); Using a different directory to save session data is one method to ensure that your current sessions aren't lost when you clear Symfony's cache. From 45612ad1980883936d253f5078b048fb130ffd42 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 9 Dec 2013 21:08:43 +0100 Subject: [PATCH 02/33] improve the serialization of custom user models (cherry picked from commit 7b34eabe4b506c3e49e4dedbefee66c1612bb83d) --- cookbook/security/entity_provider.rst | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index 3c6adebc57f..a21dab82574 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -149,6 +149,9 @@ focus on the most important methods that come from the { return serialize(array( $this->id, + $this->username, + $this->salt, + $this->password, )); } @@ -159,10 +162,20 @@ focus on the most important methods that come from the { list ( $this->id, + $this->username, + $this->salt, + $this->password, ) = unserialize($serialized); } } +.. note:: + + When implementing the + :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`, + you determine yourself which properties need to be compared to distinguish + your user objects. + .. tip:: :ref:`Generate the database table ` @@ -573,7 +586,7 @@ methods have changed:: class User implements AdvancedUserInterface, \Serializable { // ... - + /** * @ORM\ManyToMany(targetEntity="Role", inversedBy="users") * @@ -589,7 +602,7 @@ methods have changed:: { return $this->roles->toArray(); } - + // ... } @@ -646,7 +659,7 @@ of the application:: { return $this->role; } - + // ... getters and setters for each property } From a84acd8dbba3bace371dac34397cefedcc4b67aa Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 18 Dec 2013 19:44:49 -0500 Subject: [PATCH 03/33] [#3307] Adding an additional note about deserialization issues (cherry picked from commit 7325ec5044c0339275a9700e767d88707116f79d) --- cookbook/security/entity_provider.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index a21dab82574..7bce66c6ef7 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -420,6 +420,13 @@ For this example, the first three methods will return ``true`` whereas the Now, if you try to authenticate as a user who's ``is_active`` database field is set to 0, you won't be allowed. +.. note:: + + When using the ``AdvancedUserInterface``, you should also add any of + the properties used by these methods (like ``isActive``) to the ``serialize`` + method. If you *don't* do this, your user may not be deserialized correctly + from the session on each request. + The next session will focus on how to write a custom entity provider to authenticate a user with their username or email address. From f0e9108e11b581165073ff7f69d363d0b7601a12 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 19 Dec 2013 07:19:26 -0500 Subject: [PATCH 04/33] [#3307] Fix thanks to @xabbuh (cherry picked from commit 38612bc190ab2f97f2fbd3f3bc18a591df153cbe) --- cookbook/security/entity_provider.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index 7bce66c6ef7..1d3db726726 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -423,7 +423,7 @@ is set to 0, you won't be allowed. .. note:: When using the ``AdvancedUserInterface``, you should also add any of - the properties used by these methods (like ``isActive``) to the ``serialize`` + the properties used by these methods (like ``isActive()``) to the ``serialize()`` method. If you *don't* do this, your user may not be deserialized correctly from the session on each request. From d64258d101b3f0328302b40ba3a1ea5113f551da Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 26 Dec 2013 11:07:08 -0500 Subject: [PATCH 05/33] Clarifying some details on serialize/unserialize and making it consistent with changes we recently made (cherry picked from commit f285c5a572ee88e94a9314e152a5075243811d49) Conflicts: cookbook/security/entity_provider.rst --- cookbook/security/entity_provider.rst | 44 +++++++++++---------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index 1d3db726726..b412c878c9f 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -171,7 +171,7 @@ focus on the most important methods that come from the .. note:: - When implementing the + If you choose to implement :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`, you determine yourself which properties need to be compared to distinguish your user objects. @@ -198,35 +198,27 @@ interface forces the class to implement the five following methods: For more details on each of these, see :class:`Symfony\\Component\\Security\\Core\\User\\UserInterface`. -.. versionadded:: 2.1 - In Symfony 2.1, the ``equals`` method was removed from ``UserInterface``. - If you need to override the default implementation of comparison logic, - implement the new :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface` - interface and implement the ``isEqualTo`` method. - -.. code-block:: php - - // src/Acme/UserBundle/Entity/User.php - - namespace Acme\UserBundle\Entity; - - use Symfony\Component\Security\Core\User\EquatableInterface; - - // ... - - public function isEqualTo(UserInterface $user) - { - return $this->id === $user->getId(); - } - -.. note:: +.. sidebar:: What is the importance of serialize and unserialize? The :phpclass:`Serializable` interface and its ``serialize`` and ``unserialize`` methods have been added to allow the ``User`` class to be serialized to the session. This may or may not be needed depending on your setup, - but it's probably a good idea. Only the ``id`` needs to be serialized, - because the :method:`Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider::refreshUser` - method reloads the user on each request by using the ``id``. + but it's probably a good idea. The ``id`` is the most important value + that needs to be serialized because the + :method:`Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider::refreshUser` + method reloads the user on each request by using the ``id``. In practice, + this means that the User object is reloaded from the database on each + request using the ``id`` from the serialized object. This makes sure + all of the User's data is fresh. + + Symfony also uses the ``username``, ``salt``, and ``password`` to verify + that the User has not changed between requests. Failing to serialize + these may cause you to be logged out on each request. If your User implements + :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`, + then instead of these properties being checked, your ``isEqualTo`` method + is simply called, and you can check whatever properties you want. Unless + you understand this, you probably *won't* need to implement this interface + or worry about it. Below is an export of the ``User`` table from MySQL with user ``admin`` and password ``admin`` (which has been encoded). For details on how to create From 2a1a34936336b360cbd0336a8fe4f90c1e49aaf4 Mon Sep 17 00:00:00 2001 From: Wouter J Date: Tue, 17 Dec 2013 21:01:54 +0100 Subject: [PATCH 06/33] Changed sha1 into bcrypt --- book/security.rst | 26 ++++++++++++++++---------- cookbook/security/entity_provider.rst | 16 +++++----------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/book/security.rst b/book/security.rst index 2e7409bdb8a..66388dbdb1d 100644 --- a/book/security.rst +++ b/book/security.rst @@ -1363,6 +1363,15 @@ any extra encoding. You can now calculate the hashed password either programmati Supported algorithms for this method depend on your PHP version. A full list is available calling the PHP function :phpfunction:`hash_algos`. +.. caution:: + + The above example is not meaned for practical usage, it uses a weak hash + algorithm and it is only done to be able to generate the password easily. Using + :ref:`BCrypt ` is a better option. + +.. versionadded:: 2.2 + The BCrypt encoder was introduced in Symfony 2.2. + If you're creating your users dynamically (and storing them in a database), you can use even tougher hashing algorithms and then rely on an actual password encoder object to help you encode passwords. For example, suppose your User @@ -1378,7 +1387,7 @@ configure the encoder for that user: # ... encoders: - Acme\UserBundle\Entity\User: sha512 + Acme\UserBundle\Entity\User: bcrypt .. code-block:: xml @@ -1386,7 +1395,7 @@ configure the encoder for that user: - + .. code-block:: php @@ -1395,20 +1404,17 @@ configure the encoder for that user: $container->loadFromExtension('security', array( // ... 'encoders' => array( - 'Acme\UserBundle\Entity\User' => 'sha512', + 'Acme\UserBundle\Entity\User' => 'bcrypt', ), )); -In this case, you're using the stronger ``sha512`` algorithm. Also, since -you've simply specified the algorithm (``sha512``) as a string, the system -will default to hashing your password 5000 times in a row and then encoding -it as base64. In other words, the password has been greatly obfuscated so -that the hashed password can't be decoded (i.e. you can't determine the password -from the hashed password). +In this case, you're using the strong ``bcrypt`` algorithm. This means that the +password has been greatly obfuscated so that the hashed password can't be +decoded (i.e. you can't determine the password from the hashed password). .. versionadded:: 2.2 As of Symfony 2.2 you can also use the :ref:`PBKDF2 ` - and :ref:`BCrypt ` password encoders. + password encoder. Determining the Hashed Password ............................... diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index b412c878c9f..9a7836a5314 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -257,9 +257,7 @@ then be checked against your User entity records in the database: security: encoders: Acme\UserBundle\Entity\User: - algorithm: sha1 - encode_as_base64: false - iterations: 1 + algorithm: bcrypt role_hierarchy: ROLE_ADMIN: ROLE_USER @@ -282,9 +280,7 @@ then be checked against your User entity records in the database: ROLE_USER @@ -307,9 +303,7 @@ then be checked against your User entity records in the database: $container->loadFromExtension('security', array( 'encoders' => array( 'Acme\UserBundle\Entity\User' => array( - 'algorithm' => 'sha1', - 'encode_as_base64' => false, - 'iterations' => 1, + 'algorithm' => 'bcrypt', ), ), 'role_hierarchy' => array( @@ -335,9 +329,9 @@ then be checked against your User entity records in the database: ), )); -The ``encoders`` section associates the ``sha1`` password encoder to the entity +The ``encoders`` section associates the ``bcrypt`` password encoder to the entity class. This means that Symfony will expect the password that's stored in -the database to be encoded using this algorithm. For details on how to create +the database to be encoded using this encoder. For details on how to create a new User object with a properly encoded password, see the :ref:`book-security-encoding-user-password` section of the security chapter. From 3a7020ce0446d6a1a96c868ae7a4cf8353bb335d Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 1 Jan 2014 17:49:51 -0600 Subject: [PATCH 07/33] [#3356] Fixing ticks that don't work inside a bold and removing extra details in intro area that aren't necessary (you'll need to read the cookbook entry for more details anyways) --- book/security.rst | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/book/security.rst b/book/security.rst index 66388dbdb1d..319d643fe0a 100644 --- a/book/security.rst +++ b/book/security.rst @@ -660,7 +660,7 @@ see :doc:`/cookbook/security/form_login`. ), ), - **3. Be sure ``/login_check`` is behind a firewall** + **3. Be sure /login_check is behind a firewall** Next, make sure that your ``check_path`` URL (e.g. ``/login_check``) is behind the firewall you're using for your form login (in this example, @@ -1206,19 +1206,6 @@ custom user class is that it implements the :class:`Symfony\\Component\\Security interface. This means that your concept of a "user" can be anything, as long as it implements this interface. -.. versionadded:: 2.1 - In Symfony 2.1, the ``equals`` method was removed from ``UserInterface``. - If you need to override the default implementation of comparison logic, - implement the new :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface` - interface. - -.. note:: - - The user object will be serialized and saved in the session during requests, - therefore it is recommended that you `implement the \Serializable interface`_ - in your user object. This is especially important if your ``User`` class - has a parent class with private properties. - Next, configure an ``entity`` user provider, and point it to your ``User`` class: From dfa761bb4d1658b6786b5f5096cf0dc929e4fbb4 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 1 Jan 2014 18:14:00 -0600 Subject: [PATCH 08/33] [#3356] Changing to use the bcrypt algorithm Also removing one example (now possible with using bcrypt from the beginning) and related tweaks. --- book/security.rst | 113 +++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 71 deletions(-) diff --git a/book/security.rst b/book/security.rst index 319d643fe0a..c1f189ad2a9 100644 --- a/book/security.rst +++ b/book/security.rst @@ -1265,7 +1265,7 @@ in plain text (whether those users are stored in a configuration file or in a database somewhere). Of course, in a real application, you'll want to encode your users' passwords for security reasons. This is easily accomplished by mapping your User class to one of several built-in "encoders". For example, -to store your users in memory, but obscure their passwords via ``sha1``, +to store your users in memory, but obscure their passwords via ``bcrypt``, do the following: .. configuration-block:: @@ -1279,14 +1279,17 @@ do the following: in_memory: memory: users: - ryan: { password: bb87a29949f3a1ee0559f8a57357487151281386, roles: 'ROLE_USER' } - admin: { password: 74913f5cd5f61ec0bcfdb775414c2fb3d161b620, roles: 'ROLE_ADMIN' } + ryan: + password: $2a$12$w/aHvnC/XNeDVrrl65b3dept8QcKqpADxUlbraVXXsC03Jam5hvoO + roles: 'ROLE_USER' + admin: + password: $2a$12$HmOsqRDJK0HuMDQ5Fb2.AOLMQHyNHGD0seyjU3lEVusjT72QQEIpW + roles: 'ROLE_ADMIN' encoders: Symfony\Component\Security\Core\User\User: - algorithm: sha1 - iterations: 1 - encode_as_base64: false + algorithm: bcrypt + cost: 12 .. code-block:: xml @@ -1296,18 +1299,18 @@ do the following: + algorithm="bcrypt" + cost="12" + /> .. code-block:: php @@ -1320,11 +1323,11 @@ do the following: 'memory' => array( 'users' => array( 'ryan' => array( - 'password' => 'bb87a29949f3a1ee0559f8a57357487151281386', + 'password' => '$2a$12$w/aHvnC/XNeDVrrl65b3dept8QcKqpADxUlbraVXXsC03Jam5hvoO', 'roles' => 'ROLE_USER', ), 'admin' => array( - 'password' => '74913f5cd5f61ec0bcfdb775414c2fb3d161b620', + 'password' => '$2a$12$HmOsqRDJK0HuMDQ5Fb2.AOLMQHyNHGD0seyjU3lEVusjT72QQEIpW', 'roles' => 'ROLE_ADMIN', ), ), @@ -1333,71 +1336,35 @@ do the following: ), 'encoders' => array( 'Symfony\Component\Security\Core\User\User' => array( - 'algorithm' => 'sha1', - 'iterations' => 1, - 'encode_as_base64' => false, + 'algorithm' => 'bcrypt', + 'iterations' => 12, ), ), )); -By setting the ``iterations`` to ``1`` and the ``encode_as_base64`` to false, -the password is simply run through the ``sha1`` algorithm one time and without -any extra encoding. You can now calculate the hashed password either programmatically -(e.g. ``hash('sha1', 'ryanpass')``) or via some online tool like `functions-online.com`_ - -.. tip:: - - Supported algorithms for this method depend on your PHP version. - A full list is available calling the PHP function :phpfunction:`hash_algos`. - -.. caution:: - - The above example is not meaned for practical usage, it uses a weak hash - algorithm and it is only done to be able to generate the password easily. Using - :ref:`BCrypt ` is a better option. - .. versionadded:: 2.2 The BCrypt encoder was introduced in Symfony 2.2. -If you're creating your users dynamically (and storing them in a database), -you can use even tougher hashing algorithms and then rely on an actual password -encoder object to help you encode passwords. For example, suppose your User -object is ``Acme\UserBundle\Entity\User`` (like in the above example). First, -configure the encoder for that user: - -.. configuration-block:: - - .. code-block:: yaml +You can now calculate the hashed password either programmatically +(e.g. ``password_hash('ryanpass', PASSWORD_BCRYPT, array('cost' => 12));``) +or via some online tool. - # app/config/security.yml - security: - # ... - - encoders: - Acme\UserBundle\Entity\User: bcrypt - - .. code-block:: xml +.. caution:: - - - + If you're using PHP 5.4 or lower, you'll need to install the ``ircmaxell/password-compat`` + library via Composer: - - + .. code-block:: json - .. code-block:: php - - // app/config/security.php - $container->loadFromExtension('security', array( - // ... - 'encoders' => array( - 'Acme\UserBundle\Entity\User' => 'bcrypt', - ), - )); + { + "require": { + "...": "all the other dependencies...", + "ircmaxell/password-compat": "~1.0.3" + } + } -In this case, you're using the strong ``bcrypt`` algorithm. This means that the -password has been greatly obfuscated so that the hashed password can't be -decoded (i.e. you can't determine the password from the hashed password). +Supported algorithms for this method depend on your PHP version. A full list +is available by calling the PHP function :phpfunction:`hash_algos`. .. versionadded:: 2.2 As of Symfony 2.2 you can also use the :ref:`PBKDF2 ` @@ -1406,10 +1373,11 @@ decoded (i.e. you can't determine the password from the hashed password). Determining the Hashed Password ............................... -If you have some sort of registration form for users, you'll need to be able -to determine the hashed password so that you can set it on your user. No -matter what algorithm you configure for your user object, the hashed password -can always be determined in the following way from a controller:: +If you're storing users in the database and you have some sort of registration +form for users, you'll need to be able to determine the hashed password so +that you can set it on your user before inserting it. No matter what algorithm +you configure for your user object, the hashed password can always be determined +in the following way from a controller:: $factory = $this->get('security.encoder_factory'); $user = new Acme\UserBundle\Entity\User(); @@ -1418,6 +1386,10 @@ can always be determined in the following way from a controller:: $password = $encoder->encodePassword('ryanpass', $user->getSalt()); $user->setPassword($password); +In order for this to work, just make sure that you have the encoder for your +user class (e.g. ``Acme\UserBundle\Entity\User``) configured under the ``encoders`` +key in ``app/config/security.yml``. + .. caution:: When you allow a user to submit a plaintext password (e.g. registration @@ -2070,5 +2042,4 @@ Learn more from the Cookbook .. _`JMSSecurityExtraBundle`: http://jmsyst.com/bundles/JMSSecurityExtraBundle/1.2 .. _`FOSUserBundle`: https://github.com/FriendsOfSymfony/FOSUserBundle .. _`implement the \Serializable interface`: http://php.net/manual/en/class.serializable.php -.. _`functions-online.com`: http://www.functions-online.com/sha1.html .. _`Timing attack`: http://en.wikipedia.org/wiki/Timing_attack From 0e6cc4d2af6213d08ccadf218cb6d3dbbeba0802 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 1 Jan 2014 18:31:44 -0600 Subject: [PATCH 09/33] [#3356] Moving serialize and Equatable logic further down for clarity --- cookbook/security/entity_provider.rst | 89 ++++++++++++++++----------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index 9a7836a5314..481394f1fde 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -32,7 +32,7 @@ The Data Model -------------- For the purpose of this cookbook, the ``AcmeUserBundle`` bundle contains a -``User`` entity class with the following fields: ``id``, ``username``, ``salt``, +``User`` entity class with the following fields: ``id``, ``username``, ``password``, ``email`` and ``isActive``. The ``isActive`` field tells whether or not the user account is active. @@ -77,11 +77,6 @@ focus on the most important methods that come from the */ private $username; - /** - * @ORM\Column(type="string", length=32) - */ - private $salt; - /** * @ORM\Column(type="string", length=64) */ @@ -100,7 +95,6 @@ focus on the most important methods that come from the public function __construct() { $this->isActive = true; - $this->salt = md5(uniqid(null, true)); } /** @@ -116,7 +110,7 @@ focus on the most important methods that come from the */ public function getSalt() { - return $this->salt; + return null; } /** @@ -192,33 +186,15 @@ interface forces the class to implement the five following methods: * ``getRoles()``, * ``getPassword()``, -* ``getSalt()``, +* ``getPassword()``, * ``getUsername()``, * ``eraseCredentials()`` For more details on each of these, see :class:`Symfony\\Component\\Security\\Core\\User\\UserInterface`. -.. sidebar:: What is the importance of serialize and unserialize? - - The :phpclass:`Serializable` interface and its ``serialize`` and ``unserialize`` - methods have been added to allow the ``User`` class to be serialized - to the session. This may or may not be needed depending on your setup, - but it's probably a good idea. The ``id`` is the most important value - that needs to be serialized because the - :method:`Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider::refreshUser` - method reloads the user on each request by using the ``id``. In practice, - this means that the User object is reloaded from the database on each - request using the ``id`` from the serialized object. This makes sure - all of the User's data is fresh. - - Symfony also uses the ``username``, ``salt``, and ``password`` to verify - that the User has not changed between requests. Failing to serialize - these may cause you to be logged out on each request. If your User implements - :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`, - then instead of these properties being checked, your ``isEqualTo`` method - is simply called, and you can check whatever properties you want. Unless - you understand this, you probably *won't* need to implement this interface - or worry about it. +If you're curious about the ``serialize`` method or are looking for details +on the logic of seeing if the User stored in the session is the same as the +one stored in the database, see :ref:`cookbook-security-serialize-equatable`. Below is an export of the ``User`` table from MySQL with user ``admin`` and password ``admin`` (which has been encoded). For details on how to create @@ -227,11 +203,11 @@ user records and encode their password, see :ref:`book-security-encoding-user-pa .. code-block:: bash $ mysql> select * from acme_users; - +----+----------+------+------------------------------------------+--------------------+-----------+ - | id | username | salt | password | email | is_active | - +----+----------+------+------------------------------------------+--------------------+-----------+ - | 1 | admin | | d033e22ae348aeb5660fc2140aec35850c4da997 | admin@example.com | 1 | - +----+----------+------+------------------------------------------+--------------------+-----------+ + +----+----------+------------------------------------------+--------------------+-----------+ + | id | username | password | email | is_active | + +----+----------+------------------------------------------+--------------------+-----------+ + | 1 | admin | d033e22ae348aeb5660fc2140aec35850c4da997 | admin@example.com | 1 | + +----+----------+------------------------------------------+--------------------+-----------+ The next part will focus on how to authenticate one of these users thanks to the Doctrine entity user provider and a couple of lines of @@ -743,3 +719,46 @@ fetch the user and their associated roles with a single query:: The ``QueryBuilder::leftJoin()`` method joins and fetches related roles from the ``AcmeUserBundle:User`` model class when a user is retrieved by their email address or username. + +.. _`cookbook-security-serialize-equatable`: + +Understanding serialize and how a User is Saved in the Session +-------------------------------------------------------------- + +If you're curious about the importance of the ``serialize`` method inside +the User class or how the User object is serialized or deserialized, then +this section is for you. If not, feel free to skip this. + +Once the user is logged in, the entire User object is serialized into the +session. On the next request, the User object is deserialized. Then, value +of the ``id`` property is used to re-query for a fresh User object from the +database. Finally, the fresh User object is compared in some way to the deserialized +User object to make sure that they represent the same user. For example, if +the ``username`` on the 2 User objects doesn't match for some reason, then +the user will be logged out for security reasons. + +Even though this all happens automatically, there are a few important side-effects. + +First, the :phpclass:`Serializable` interface and its ``serialize`` and ``unserialize`` +methods have been added to allow the ``User`` class to be serialized +to the session. This may or may not be needed depending on your setup, +but it's probably a good idea. Only the ``id`` needs to be serialized, +because the :method:`Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider::refreshUser` +method refreshes the user on each request by using the ``id`` (as explained +above). In practice, this means that the User object is reloaded from the +database on each request using the ``id`` from the serialized object. This +makes sure all of the User's data is fresh. + + +Symfony also uses the ``username``, ``salt``, and ``password`` to verify +that the User has not changed between requests. Failing to serialize +these may cause you to be logged out on each request. If your User implements +:class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`, +then instead of these properties being checked, your ``isEqualTo`` method +is simply called, and you can check whatever properties you want. Unless +you understand this, you probably *won't* need to implement this interface +or worry about it. + +.. versionadded:: 2.1 + In Symfony 2.1, the ``equals`` method was removed from ``UserInterface`` + and the ``EquatableInterface`` was added in its place. From 1eefb1b33da12f163f5110bfc71750c161711e05 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 1 Jan 2014 18:55:53 -0600 Subject: [PATCH 10/33] [#3356] Clarifying when you need a salt Also filling in other details related to using BCrypt --- book/security.rst | 14 +------- .../_ircmaxwell_password-compat.rst.inc | 13 +++++++ cookbook/security/entity_provider.rst | 35 +++++++++++++------ 3 files changed, 39 insertions(+), 23 deletions(-) create mode 100644 cookbook/security/_ircmaxwell_password-compat.rst.inc diff --git a/book/security.rst b/book/security.rst index c1f189ad2a9..59432b994d9 100644 --- a/book/security.rst +++ b/book/security.rst @@ -1349,19 +1349,7 @@ You can now calculate the hashed password either programmatically (e.g. ``password_hash('ryanpass', PASSWORD_BCRYPT, array('cost' => 12));``) or via some online tool. -.. caution:: - - If you're using PHP 5.4 or lower, you'll need to install the ``ircmaxell/password-compat`` - library via Composer: - - .. code-block:: json - - { - "require": { - "...": "all the other dependencies...", - "ircmaxell/password-compat": "~1.0.3" - } - } +.. include:: /cookbook/security/_ircmaxwell_password-compat.rst.inc Supported algorithms for this method depend on your PHP version. A full list is available by calling the PHP function :phpfunction:`hash_algos`. diff --git a/cookbook/security/_ircmaxwell_password-compat.rst.inc b/cookbook/security/_ircmaxwell_password-compat.rst.inc new file mode 100644 index 00000000000..20764184e3d --- /dev/null +++ b/cookbook/security/_ircmaxwell_password-compat.rst.inc @@ -0,0 +1,13 @@ +.. caution:: + + If you're using PHP 5.4 or lower, you'll need to install the ``ircmaxell/password-compat`` + library via Composer in order to be able to use the ``bcrypt`` encoder: + + .. code-block:: json + + { + "require": { + "...": "all the other dependencies...", + "ircmaxell/password-compat": "~1.0.3" + } + } \ No newline at end of file diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index 481394f1fde..68c5430c323 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -95,6 +95,8 @@ focus on the most important methods that come from the public function __construct() { $this->isActive = true; + // may not be needed, see section on salt below + // $this->salt = md5(uniqid(null, true)); } /** @@ -110,6 +112,8 @@ focus on the most important methods that come from the */ public function getSalt() { + // you *may* need a real salt depending on your encoder + // see section on salt below return null; } @@ -144,8 +148,9 @@ focus on the most important methods that come from the return serialize(array( $this->id, $this->username, - $this->salt, $this->password, + // see section on salt below + // $this->salt, )); } @@ -157,19 +162,13 @@ focus on the most important methods that come from the list ( $this->id, $this->username, - $this->salt, $this->password, + // see section on salt below + // $this->salt ) = unserialize($serialized); } } -.. note:: - - If you choose to implement - :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`, - you determine yourself which properties need to be compared to distinguish - your user objects. - .. tip:: :ref:`Generate the database table ` @@ -186,7 +185,7 @@ interface forces the class to implement the five following methods: * ``getRoles()``, * ``getPassword()``, -* ``getPassword()``, +* ``getSalt()``, * ``getUsername()``, * ``eraseCredentials()`` @@ -213,6 +212,20 @@ The next part will focus on how to authenticate one of these users thanks to the Doctrine entity user provider and a couple of lines of configuration. +.. sidebar:: Do you need to use a Salt? + + Yes. Hashing a password with a salt is a necessary step so that encoded + passwords can't be decoded. However, some encoders - like Bcrypt - have + a built-in salt mechanism. If you configure ``bcrypt`` as your encoder + in ``security.yml`` (see the next section), then ``getSalt()`` should + return ``null``, so that Bcrypt generates the salt itself. + + However, if you use an encoder that does *not* have a built-in salting + ability (e.g. ``sha512``), you *must* (from a security perspective) generate + your own, random salt, store it on a ``salt`` property that is saved to + the database, and return it from ``getSalt()``. Some of the code needed + is commented out in the above example. + Authenticating Someone against a Database ----------------------------------------- @@ -311,6 +324,8 @@ the database to be encoded using this encoder. For details on how to create a new User object with a properly encoded password, see the :ref:`book-security-encoding-user-password` section of the security chapter. +.. include:: /cookbook/security/_ircmaxwell_password-compat.rst.inc + The ``providers`` section defines an ``administrators`` user provider. A user provider is a "source" of where users are loaded during authentication. In this case, the ``entity`` keyword means that Symfony will use the Doctrine From 4436dae9690310bafdc8479d045e0d4ed946346e Mon Sep 17 00:00:00 2001 From: Luis Cordova Date: Mon, 6 Jan 2014 13:37:56 -0500 Subject: [PATCH 11/33] add warning for inifile loader --- components/config/introduction.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/components/config/introduction.rst b/components/config/introduction.rst index 047ff599cc0..80792be075c 100644 --- a/components/config/introduction.rst +++ b/components/config/introduction.rst @@ -12,6 +12,13 @@ The Config component provides several classes to help you find, load, combine, autofill and validate configuration values of any kind, whatever their source may be (YAML, XML, INI files, or for instance a database). +.. caution:: + + ``IniFileLoader`` parses with the `parse_ini_file` function, therefore + it can only configure parameters as string values. For other + data types support (e.g. Boolean, integer, etc), the other loaders + are recommended. + Installation ------------ From 4fb6e59b1492a0923a9cd351fcbbaf7604cb51ec Mon Sep 17 00:00:00 2001 From: ghostika Date: Thu, 9 Jan 2014 20:49:57 +0100 Subject: [PATCH 12/33] Add host config to the security documentation --- book/security.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/book/security.rst b/book/security.rst index e60e581abc5..b006beb260b 100644 --- a/book/security.rst +++ b/book/security.rst @@ -151,6 +151,9 @@ that looks like the following: Let's look briefly at how security works and how each part of the configuration comes into play. +.. versionadded:: 2.4 + A new property was added to the firewall configuration, where you can make a restriction, called ``host``. + How Security Works: Authentication and Authorization ---------------------------------------------------- From 0244173f3a3b187c3e57a108ab30766652dc9768 Mon Sep 17 00:00:00 2001 From: Ghostika Date: Thu, 9 Jan 2014 21:15:30 +0100 Subject: [PATCH 13/33] add host to the config page --- reference/configuration/security.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index bdaa387acc8..4a6b355782a 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -98,6 +98,8 @@ Each part will be explained in the next section. # Examples: somename: pattern: .* + # restrict the firewall for a specific host + host: admin\.example\.com request_matcher: some.service.id access_denied_url: /foo/error403 access_denied_handler: some.service.id From cc8d19ac8729da4fa0cc0cd1bf4a364e6a1cb722 Mon Sep 17 00:00:00 2001 From: Ghostika Date: Thu, 9 Jan 2014 22:14:46 +0100 Subject: [PATCH 14/33] line break --- book/security.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/book/security.rst b/book/security.rst index b006beb260b..68f322823cb 100644 --- a/book/security.rst +++ b/book/security.rst @@ -152,7 +152,8 @@ Let's look briefly at how security works and how each part of the configuration comes into play. .. versionadded:: 2.4 - A new property was added to the firewall configuration, where you can make a restriction, called ``host``. + A new property was added to the firewall configuration, where you can +make a restriction, called ``host``. How Security Works: Authentication and Authorization ---------------------------------------------------- From fe5abd38d2d1eaaf5b0cb174884db9ba6dbfd669 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 9 Jan 2014 23:04:52 +0100 Subject: [PATCH 15/33] fix indentation so that the text is rendered properly --- contributing/code/patches.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contributing/code/patches.rst b/contributing/code/patches.rst index 7f0667ea960..cffd4f52b51 100644 --- a/contributing/code/patches.rst +++ b/contributing/code/patches.rst @@ -200,7 +200,7 @@ When your patch is not about a bug fix (when you add a new feature or change an existing one for instance), it must also include the following: * An explanation of the changes in the relevant ``CHANGELOG`` file(s) (the - ``[BC BREAK]`` or the ``[DEPRECATION]`` prefix must be used when relevant); + ``[BC BREAK]`` or the ``[DEPRECATION]`` prefix must be used when relevant); * An explanation on how to upgrade an existing application in the relevant ``UPGRADE`` file(s) if the changes break backward compatibility or if you @@ -396,9 +396,9 @@ type this command, an editor will popup showing a list of commits: To squash all commits into the first one, remove the word ``pick`` before the second and the last commits, and replace it by the word ``squash`` or just - ``s``. When you save, Git will start rebasing, and if successful, will ask - you to edit the commit message, which by default is a listing of the commit - messages of all the commits. When you are finished, execute the push command. +``s``. When you save, Git will start rebasing, and if successful, will ask +you to edit the commit message, which by default is a listing of the commit +messages of all the commits. When you are finished, execute the push command. .. _ProGit: http://git-scm.com/book .. _GitHub: https://github.com/signup/free From 22b3d0cd143d56e4b2e4bf5ff80d1cbb0417b448 Mon Sep 17 00:00:00 2001 From: Philipp Rieber Date: Mon, 6 Jan 2014 21:28:34 +0100 Subject: [PATCH 16/33] [Reference][Form Types] Update "radio" form type --- reference/forms/types/radio.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/radio.rst b/reference/forms/types/radio.rst index 6d29555f3fa..b12cd6ebf6b 100644 --- a/reference/forms/types/radio.rst +++ b/reference/forms/types/radio.rst @@ -28,7 +28,7 @@ If you want to have a Boolean field, use :doc:`checkbox ` | +| Parent type | :doc:`form ` | +-------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RadioType` | +-------------+---------------------------------------------------------------------+ From be47b90beca127aee45f792ae76284dba6bc1c1a Mon Sep 17 00:00:00 2001 From: Philipp Rieber Date: Tue, 7 Jan 2014 12:13:07 +0100 Subject: [PATCH 17/33] Fix parent type doc reference --- reference/forms/types/radio.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/forms/types/radio.rst b/reference/forms/types/radio.rst index b12cd6ebf6b..6316ec3b0c2 100644 --- a/reference/forms/types/radio.rst +++ b/reference/forms/types/radio.rst @@ -28,7 +28,7 @@ If you want to have a Boolean field, use :doc:`checkbox ` | +| Parent type | :doc:`checkbox ` | +-------------+---------------------------------------------------------------------+ | Class | :class:`Symfony\\Component\\Form\\Extension\\Core\\Type\\RadioType` | +-------------+---------------------------------------------------------------------+ From 322b21e191c19d2c2d6a83f92762f72a5122b742 Mon Sep 17 00:00:00 2001 From: Philipp Rieber Date: Tue, 7 Jan 2014 21:24:43 +0100 Subject: [PATCH 18/33] Update&Outsource "value" option & update references --- reference/forms/types/checkbox.rst | 12 +-------- reference/forms/types/options/value.rst.inc | 12 +++++++++ reference/forms/types/radio.rst | 27 ++++++--------------- 3 files changed, 21 insertions(+), 30 deletions(-) create mode 100644 reference/forms/types/options/value.rst.inc diff --git a/reference/forms/types/checkbox.rst b/reference/forms/types/checkbox.rst index fc529e3a7d9..159ef755c30 100644 --- a/reference/forms/types/checkbox.rst +++ b/reference/forms/types/checkbox.rst @@ -42,17 +42,7 @@ Example Usage Field Options ------------- -value -~~~~~ - -**type**: ``mixed`` **default**: ``1`` - -The value that's actually used as the value for the checkbox. This does -not affect the value that's set on your object. - -.. caution:: - - To make a checkbox checked by default, set the `data`_ option to ``true``. +.. include:: /reference/forms/types/options/value.rst.inc Inherited options ----------------- diff --git a/reference/forms/types/options/value.rst.inc b/reference/forms/types/options/value.rst.inc new file mode 100644 index 00000000000..6c94904764f --- /dev/null +++ b/reference/forms/types/options/value.rst.inc @@ -0,0 +1,12 @@ +value +~~~~~ + +**type**: ``mixed`` **default**: ``1`` + +The value that's actually used as the value for the checkbox or radio button. +This does not affect the value that's set on your object. + +.. caution:: + + To make a checkbox or radio button checked by default, use the `data`_ + option. diff --git a/reference/forms/types/radio.rst b/reference/forms/types/radio.rst index 6316ec3b0c2..0cf937db3bb 100644 --- a/reference/forms/types/radio.rst +++ b/reference/forms/types/radio.rst @@ -15,10 +15,9 @@ If you want to have a Boolean field, use :doc:`checkbox ` +type: + +.. include:: /reference/forms/types/options/value.rst.inc + These options inherit from the :doc:`form ` type: .. include:: /reference/forms/types/options/data.rst.inc From dc22276c0ae514d2e6e4ba892552d7618dd42de3 Mon Sep 17 00:00:00 2001 From: Philipp Rieber Date: Wed, 8 Jan 2014 22:00:52 +0100 Subject: [PATCH 19/33] [Reference][Form Types] Add missing (but existing) form options to "form" type --- reference/forms/types/form.rst | 15 +++++++++--- .../options/_error_bubbling_body.rst.inc | 4 ++-- .../forms/types/options/by_reference.rst.inc | 10 ++++---- .../forms/types/options/empty_data.rst.inc | 23 +++++++++++-------- .../forms/types/options/error_mapping.rst.inc | 10 ++++---- 5 files changed, 37 insertions(+), 25 deletions(-) diff --git a/reference/forms/types/form.rst b/reference/forms/types/form.rst index fc630baa1b1..dfe67119f6c 100644 --- a/reference/forms/types/form.rst +++ b/reference/forms/types/form.rst @@ -45,8 +45,17 @@ on all fields. .. include:: /reference/forms/types/options/max_length.rst.inc -inherit_data ------------- +.. include:: /reference/forms/types/options/empty_data.rst.inc + +.. include:: /reference/forms/types/options/by_reference.rst.inc + +.. include:: /reference/forms/types/options/error_bubbling.rst.inc + +.. include:: /reference/forms/types/options/inherit_data.rst.inc + +.. include:: /reference/forms/types/options/error_mapping.rst.inc + +.. include:: /reference/forms/types/options/invalid_message.rst.inc -See :doc:`/cookbook/form/inherit_data_option`. +.. include:: /reference/forms/types/options/invalid_message_parameters.rst.inc diff --git a/reference/forms/types/options/_error_bubbling_body.rst.inc b/reference/forms/types/options/_error_bubbling_body.rst.inc index 32f5ad33401..5fd93614456 100644 --- a/reference/forms/types/options/_error_bubbling_body.rst.inc +++ b/reference/forms/types/options/_error_bubbling_body.rst.inc @@ -1,3 +1,3 @@ -If true, any errors for this field will be passed to the parent field -or form. For example, if set to true on a normal field, any errors for +If ``true``, any errors for this field will be passed to the parent field +or form. For example, if set to ``true`` on a normal field, any errors for that field will be attached to the main form, not to the specific field. \ No newline at end of file diff --git a/reference/forms/types/options/by_reference.rst.inc b/reference/forms/types/options/by_reference.rst.inc index 26dbd65a020..8f7fffab0fe 100644 --- a/reference/forms/types/options/by_reference.rst.inc +++ b/reference/forms/types/options/by_reference.rst.inc @@ -3,8 +3,8 @@ by_reference **type**: ``Boolean`` **default**: ``true`` -In most cases, if you have a ``name`` field, then you expect ``setName`` -to be called on the underlying object. In some cases, however, ``setName`` +In most cases, if you have a ``name`` field, then you expect ``setName()`` +to be called on the underlying object. In some cases, however, ``setName()`` may *not* be called. Setting ``by_reference`` ensures that the setter is called in all cases. @@ -20,13 +20,13 @@ To explain this further, here's a simple example:: ) If ``by_reference`` is true, the following takes place behind the scenes -when you call ``submit`` (or ``handleRequest``) on the form:: +when you call ``submit()`` (or ``handleRequest()``) on the form:: $article->setTitle('...'); $article->getAuthor()->setName('...'); $article->getAuthor()->setEmail('...'); -Notice that ``setAuthor`` is not called. The author is modified by reference. +Notice that ``setAuthor()`` is not called. The author is modified by reference. If you set ``by_reference`` to false, submitting looks like this:: @@ -42,4 +42,4 @@ call the setter on the parent object. Similarly, if you're using the :doc:`collection` form type where your underlying collection data is an object (like with Doctrine's ``ArrayCollection``), then ``by_reference`` must be set to ``false`` if you -need the setter (e.g. ``setAuthors``) to be called. +need the setter (e.g. ``setAuthors()``) to be called. diff --git a/reference/forms/types/options/empty_data.rst.inc b/reference/forms/types/options/empty_data.rst.inc index d62ddabc470..1e150b4b503 100644 --- a/reference/forms/types/options/empty_data.rst.inc +++ b/reference/forms/types/options/empty_data.rst.inc @@ -1,20 +1,23 @@ empty_data ~~~~~~~~~~ -**type**: ``mixed`` **default**: ``array()`` if ``multiple`` or ``expanded``, ``''`` otherwise +**type**: ``mixed`` **default**: depends on other field options, see below -This option determines what value the field will return when the ``empty_value`` -choice is selected. +This option determines what value the field will return when the submitted +value is empty. This may happen when the ``empty_value`` choice in a +``choice`` field is selected or when an ``input`` field of some type is not +required and left empty by the user. -The true default value of this option depends on the field options: +The true default value of this option depends on other field options: -* If ``data_class`` is set and ``required`` is ``true``, then ``new $data_class()``; -* If ``data_class`` is set and ``required`` is ``false``, then ``null``; -* If ``data_class`` is not set and ``compound`` is ``true``, then ``array()``; -* If ``data_class`` is not set and ``compound`` is ``false``, then ``null``. +* If ``data_class`` is set and ``required`` is ``true``, then ``new $data_class()``; +* If ``data_class`` is set and ``required`` is ``false``, then ``null``; +* If ``data_class`` is not set and ``compound`` is ``true``, then ``array()``; +* If ``data_class`` is not set and ``compound`` is ``false``, then ``''`` (empty string). -But you can customize this to your needs. For example, if you want the ``gender`` field to be -explicitly set to ``null`` when no value is selected, you can do it like this: +But you can customize this to your needs. For example, if you want the +``gender`` choice field to be explicitly set to ``null`` when no value is +selected, you can do it like this: .. code-block:: php diff --git a/reference/forms/types/options/error_mapping.rst.inc b/reference/forms/types/options/error_mapping.rst.inc index ba67e1d5cdb..e2af2edebad 100644 --- a/reference/forms/types/options/error_mapping.rst.inc +++ b/reference/forms/types/options/error_mapping.rst.inc @@ -27,14 +27,14 @@ field so that it displays above it:: Here are the rules for the left and the right side of the mapping: -* The left side contains property paths. +* The left side contains property paths; * If the violation is generated on a property or method of a class, its path - is simply "propertyName". + is simply ``propertyName``; * If the violation is generated on an entry of an ``array`` or ``ArrayAccess`` - object, the property path is ``[indexName]``. + object, the property path is ``[indexName]``; * You can construct nested property paths by concatenating them, separating - properties by dots. For example: ``addresses[work].matchingCityAndZipCode`` + properties by dots. For example: ``addresses[work].matchingCityAndZipCode``; * The left side of the error mapping also accepts a dot ``.``, which refers to the field itself. That means that any error added to the field is added - to the given nested field instead. + to the given nested field instead; * The right side contains simply the names of fields in the form. From dd3dd709c91e47c480c957d5d8a129bb1f390075 Mon Sep 17 00:00:00 2001 From: Luis Cordova Date: Fri, 10 Jan 2014 17:51:10 -0500 Subject: [PATCH 20/33] address comments, even the Boolean one --- components/config/introduction.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/config/introduction.rst b/components/config/introduction.rst index 80792be075c..894d78c5914 100644 --- a/components/config/introduction.rst +++ b/components/config/introduction.rst @@ -14,9 +14,9 @@ may be (YAML, XML, INI files, or for instance a database). .. caution:: - ``IniFileLoader`` parses with the `parse_ini_file` function, therefore - it can only configure parameters as string values. For other - data types support (e.g. Boolean, integer, etc), the other loaders + The ``IniFileLoader`` parses with the :phpfunction:`parse_ini_file` function, + therefore, you can only set parameters to string values. To set parameters + to other data types (e.g. boolean, integer, etc), the other loaders are recommended. Installation From 4f02a8a551c311cf38c274cb41ffb0f4c6ab2ba0 Mon Sep 17 00:00:00 2001 From: Luis Cordova Date: Fri, 10 Jan 2014 18:24:37 -0500 Subject: [PATCH 21/33] address comments --- components/config/introduction.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/config/introduction.rst b/components/config/introduction.rst index 894d78c5914..89eb4beaec9 100644 --- a/components/config/introduction.rst +++ b/components/config/introduction.rst @@ -14,10 +14,10 @@ may be (YAML, XML, INI files, or for instance a database). .. caution:: - The ``IniFileLoader`` parses with the :phpfunction:`parse_ini_file` function, - therefore, you can only set parameters to string values. To set parameters - to other data types (e.g. boolean, integer, etc), the other loaders - are recommended. + The ``IniFileLoader`` parses the file contents using the + :phpfunction:`parse_ini_file` function, therefore, you can only set + parameters to string values. To set parameters to other data types + (e.g. boolean, integer, etc), the other loaders are recommended. Installation ------------ From eec82edb05f8aa38c6f337f5374a09c4c9ce4784 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 10 Jan 2014 22:58:20 +0100 Subject: [PATCH 22/33] remove confusing outdated note on interactive rebasing --- contributing/code/patches.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/contributing/code/patches.rst b/contributing/code/patches.rst index 7f0667ea960..cf504e854a0 100644 --- a/contributing/code/patches.rst +++ b/contributing/code/patches.rst @@ -244,7 +244,7 @@ Check that all tests still pass and push your branch remotely: .. code-block:: bash - $ git push -f origin BRANCH_NAME + $ git push --force origin BRANCH_NAME Make a Pull Request ~~~~~~~~~~~~~~~~~~~ @@ -369,11 +369,11 @@ patch. Before re-submitting the patch, rebase with ``upstream/master`` or .. code-block:: bash $ git rebase -f upstream/master - $ git push -f origin BRANCH_NAME + $ git push --force origin BRANCH_NAME .. note:: - when doing a ``push --force``, always specify the branch name explicitly + When doing a ``push --force``, always specify the branch name explicitly to avoid messing other branches in the repo (``--force`` tells Git that you really want to mess with things so do it carefully). @@ -383,10 +383,9 @@ convert many commits to one commit. To do this, use the rebase command: .. code-block:: bash $ git rebase -i upstream/master - $ git push -f origin BRANCH_NAME + $ git push --force origin BRANCH_NAME -The number 3 here must equal the amount of commits in your branch. After you -type this command, an editor will popup showing a list of commits: +After you type this command, an editor will popup showing a list of commits: .. code-block:: text From e6b1c7d46f6735b8e02e12a030fd4fddbc95faf7 Mon Sep 17 00:00:00 2001 From: Andrew M Date: Sat, 11 Jan 2014 16:27:24 +0200 Subject: [PATCH 23/33] Replace ... with etc --- cookbook/testing/profiling.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cookbook/testing/profiling.rst b/cookbook/testing/profiling.rst index 2ee70f00eae..3d3e660e4b7 100644 --- a/cookbook/testing/profiling.rst +++ b/cookbook/testing/profiling.rst @@ -11,7 +11,7 @@ various things and enforce some metrics. The Symfony2 :ref:`Profiler ` gathers a lot of data for each request. Use this data to check the number of database calls, the time -spent in the framework, ... But before writing assertions, enable the profiler +spent in the framework, etc. But before writing assertions, enable the profiler and check that the profiler is indeed available (it is enabled by default in the ``test`` environment):: From b1a4f29c56facb2f51c72f23a5906974e7292feb Mon Sep 17 00:00:00 2001 From: Andrew M Date: Sat, 11 Jan 2014 16:34:48 +0200 Subject: [PATCH 24/33] Fix typos in cookbook/testing/database --- cookbook/testing/database.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cookbook/testing/database.rst b/cookbook/testing/database.rst index 6d290b733df..ab869fa3a62 100644 --- a/cookbook/testing/database.rst +++ b/cookbook/testing/database.rst @@ -49,7 +49,7 @@ Suppose the class you want to test looks like this:: public function calculateTotalSalary($id) { $employeeRepository = $this->entityManager->getRepository('AcmeDemoBundle::Employee'); - $employee = $userRepository->find($id); + $employee = $employeeRepository->find($id); return $employee->getSalary() + $employee->getBonus(); } @@ -62,7 +62,6 @@ it's easy to pass a mock object within a test:: class SalaryCalculatorTest extends \PHPUnit_Framework_TestCase { - public function testCalculateTotalSalary() { // First, mock the object to be used in the test From 3e42b84281ac6a17764873b4d450e8869bdfe720 Mon Sep 17 00:00:00 2001 From: Ghostika Date: Sat, 11 Jan 2014 20:26:10 +0100 Subject: [PATCH 25/33] Add versionadded tag to security config reference, reference cookbok entry in book --- book/security.rst | 7 ++++--- reference/configuration/security.rst | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/book/security.rst b/book/security.rst index 68f322823cb..389df85d3ff 100644 --- a/book/security.rst +++ b/book/security.rst @@ -152,8 +152,8 @@ Let's look briefly at how security works and how each part of the configuration comes into play. .. versionadded:: 2.4 - A new property was added to the firewall configuration, where you can -make a restriction, called ``host``. + Support for restricting security firewalls to a specific host was added in + Symfony 2.4. How Security Works: Authentication and Authorization ---------------------------------------------------- @@ -1102,7 +1102,7 @@ Thanks to the SensioFrameworkExtraBundle, you can also secure your controller us // ... } -For more information, see the +For more information, see the :doc:`FrameworkExtraBundle documentation `. Securing other Services @@ -2168,6 +2168,7 @@ Learn more from the Cookbook * :doc:`Blacklist users by IP address with a custom voter ` * :doc:`Access Control Lists (ACLs) ` * :doc:`/cookbook/security/remember_me` +* :doc:`How to Restrict Firewalls to a Specific Host ` .. _`FOSUserBundle`: https://github.com/FriendsOfSymfony/FOSUserBundle .. _`implement the \Serializable interface`: http://php.net/manual/en/class.serializable.php diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index 4a6b355782a..c69a9a987a5 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -13,6 +13,10 @@ Full Default Configuration The following is the full default configuration for the security system. Each part will be explained in the next section. +.. versionadded:: 2.4 + Support for restricting security firewalls to a specific host was added in + Symfony 2.4. + .. configuration-block:: .. code-block:: yaml From 6cba1922f54066a36594a8f352cb506c3064f80f Mon Sep 17 00:00:00 2001 From: Ghostika Date: Sat, 11 Jan 2014 20:52:16 +0100 Subject: [PATCH 26/33] remove versionadded from book and fix words --- book/security.rst | 4 ---- cookbook/security/host_restriction.rst | 2 +- reference/configuration/security.rst | 4 ++-- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/book/security.rst b/book/security.rst index 389df85d3ff..671e9373dac 100644 --- a/book/security.rst +++ b/book/security.rst @@ -151,10 +151,6 @@ that looks like the following: Let's look briefly at how security works and how each part of the configuration comes into play. -.. versionadded:: 2.4 - Support for restricting security firewalls to a specific host was added in - Symfony 2.4. - How Security Works: Authentication and Authorization ---------------------------------------------------- diff --git a/cookbook/security/host_restriction.rst b/cookbook/security/host_restriction.rst index 232f1cd5ff6..b5b2e529d95 100644 --- a/cookbook/security/host_restriction.rst +++ b/cookbook/security/host_restriction.rst @@ -5,7 +5,7 @@ How to Restrict Firewalls to a Specific Host ============================================ .. versionadded:: 2.4 - Support for restricting security firewalls to a specific host was added in + Support for restricting security firewalls to a specific host was introduced in Symfony 2.4. When using the Security component, you can create firewalls that match certain diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index c69a9a987a5..6a1d6c6ed67 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -14,7 +14,7 @@ The following is the full default configuration for the security system. Each part will be explained in the next section. .. versionadded:: 2.4 - Support for restricting security firewalls to a specific host was added in + Support for restricting security firewalls to a specific host was introduced in Symfony 2.4. .. configuration-block:: @@ -102,7 +102,7 @@ Each part will be explained in the next section. # Examples: somename: pattern: .* - # restrict the firewall for a specific host + # restrict the firewall to a specific host host: admin\.example\.com request_matcher: some.service.id access_denied_url: /foo/error403 From f35152bd3e3326bbbfc030eea6e5f203a66f88cd Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 11 Jan 2014 20:57:46 +0100 Subject: [PATCH 27/33] change wording in versionadded example to be consistent with what we use today --- contributing/documentation/overview.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contributing/documentation/overview.rst b/contributing/documentation/overview.rst index da849040e48..695960bad64 100644 --- a/contributing/documentation/overview.rst +++ b/contributing/documentation/overview.rst @@ -135,7 +135,7 @@ tag and a short description: .. code-block:: text .. versionadded:: 2.3 - The ``askHiddenResponse`` method was added in Symfony 2.3. + The ``askHiddenResponse`` method was introduced in Symfony 2.3. You can also ask a question and hide the response. This is particularly... From 24be69041ad32e68e583bda9275934e487aca32f Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 12 Jan 2014 12:32:35 +0100 Subject: [PATCH 28/33] enclose YAML string with double quotes to fix syntax highlighting --- cookbook/routing/service_container_parameters.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cookbook/routing/service_container_parameters.rst b/cookbook/routing/service_container_parameters.rst index 8eaa7d524f8..9ac05c48e60 100644 --- a/cookbook/routing/service_container_parameters.rst +++ b/cookbook/routing/service_container_parameters.rst @@ -18,16 +18,17 @@ inside your routing configuration: .. code-block:: yaml + # app/config/routing.yml contact: path: /{_locale}/contact defaults: { _controller: AcmeDemoBundle:Main:contact } requirements: - _locale: %acme_demo.locales% + _locale: "%acme_demo.locales%" .. code-block:: xml + - @@ -40,6 +41,7 @@ inside your routing configuration: .. code-block:: php + // app/config/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; @@ -82,14 +84,15 @@ path): .. code-block:: yaml + # app/config/routing.yml some_route: path: /%acme_demo.route_prefix%/contact defaults: { _controller: AcmeDemoBundle:Main:contact } .. code-block:: xml + - @@ -101,6 +104,7 @@ path): .. code-block:: php + // app/config/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; @@ -116,7 +120,7 @@ path): Just like in normal service container configuration files, if you actually need a ``%`` in your route, you can escape the percent sign by doubling it, e.g. ``/score-50%%``, which would resolve to ``/score-50%``. - + However, as the ``%`` characters included in any URL are automatically encoded, the resulting URL of this example would be ``/score-50%25`` (``%25`` is the result of encoding the ``%`` character). From 81abeaa3571088ac73a17a0d0343c82956827c88 Mon Sep 17 00:00:00 2001 From: Daniel Gomes Date: Sun, 12 Jan 2014 21:48:19 +0000 Subject: [PATCH 29/33] Fixed `versionadded` inconsistencies --- components/http_foundation/trusting_proxies.rst | 2 +- reference/configuration/framework.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/http_foundation/trusting_proxies.rst b/components/http_foundation/trusting_proxies.rst index 591a58b09b7..fcd32d70b83 100644 --- a/components/http_foundation/trusting_proxies.rst +++ b/components/http_foundation/trusting_proxies.rst @@ -15,7 +15,7 @@ headers by default. If you are behind a proxy, you should manually whitelist your proxy. .. versionadded:: 2.3 - CIDR notation support was introduced, so you can whitelist whole + CIDR notation support was introduced in Symfony 2.3, so you can whitelist whole subnets (e.g. ``10.0.0.0/8``, ``fc00::/7``). .. code-block:: php diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index b1a1b7ee1d0..ca972b6bcb1 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -125,7 +125,7 @@ Configures the IP addresses that should be trusted as proxies. For more details, see :doc:`/components/http_foundation/trusting_proxies`. .. versionadded:: 2.3 - CIDR notation support was introduced, so you can whitelist whole + CIDR notation support was introduced in Symfony 2.3, so you can whitelist whole subnets (e.g. ``10.0.0.0/8``, ``fc00::/7``). .. configuration-block:: From 1620ed8992f6bea2a54084177b366d3983c822b8 Mon Sep 17 00:00:00 2001 From: Luis Cordova Date: Sun, 19 Jan 2014 21:17:06 -0700 Subject: [PATCH 30/33] 3363-doctrine-file-upload-example-uses-dir --- cookbook/doctrine/file_uploads.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cookbook/doctrine/file_uploads.rst b/cookbook/doctrine/file_uploads.rst index 8b6b30c3b48..b48997268b0 100644 --- a/cookbook/doctrine/file_uploads.rst +++ b/cookbook/doctrine/file_uploads.rst @@ -300,6 +300,15 @@ object, which is what's returned after a ``file`` field is submitted:: Using Lifecycle Callbacks ------------------------- +.. caution:: + + Using lifecycle callbacks is a limited technique that has some drawbacks. + If you want to remove the hard coded ``__DIR__`` reference inside + the ``Document::getUploadRootDir()`` method, the best way is to start + using explicit :doc:`doctrine listeners ` + where you will be able to inject kernel parameters such as + ``kernel.root_dir`` to be able to build absolute paths. + Even if this implementation works, it suffers from a major flaw: What if there is a problem when the entity is persisted? The file would have already moved to its final location even though the entity's ``path`` property didn't From adc57bed8145f8681b2dedf35c9c8fb5db491ba0 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Mon, 20 Jan 2014 20:36:24 -0600 Subject: [PATCH 31/33] [#3404] Adding a few comments, per @WouterJ --- cookbook/session/sessions_directory.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cookbook/session/sessions_directory.rst b/cookbook/session/sessions_directory.rst index 2f1a2209820..974764df923 100644 --- a/cookbook/session/sessions_directory.rst +++ b/cookbook/session/sessions_directory.rst @@ -31,6 +31,7 @@ to store session data. This is because of the following configuration: http://symfony.com/schema/dic/symfony/symfony-1.0.xsd" > + @@ -40,6 +41,7 @@ to store session data. This is because of the following configuration: // app/config/config.php $container->loadFromExtension('framework', array( 'session' => array( + // handler_id set to null will use default session handler from php.ini 'handler-id' => null, ), )); From 473f8c19c8fe48439a89abab6a5eccddf45a9ea1 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Mon, 20 Jan 2014 20:41:59 -0600 Subject: [PATCH 32/33] [#3405] Tweaks thanks to @WouterJ and @xabbuh --- .../security/_ircmaxwell_password-compat.rst.inc | 4 ++-- cookbook/security/entity_provider.rst | 15 +++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/cookbook/security/_ircmaxwell_password-compat.rst.inc b/cookbook/security/_ircmaxwell_password-compat.rst.inc index 20764184e3d..3f96c454488 100644 --- a/cookbook/security/_ircmaxwell_password-compat.rst.inc +++ b/cookbook/security/_ircmaxwell_password-compat.rst.inc @@ -7,7 +7,7 @@ { "require": { - "...": "all the other dependencies...", + ... "ircmaxell/password-compat": "~1.0.3" } - } \ No newline at end of file + } diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index 68c5430c323..b6919839b83 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -740,8 +740,8 @@ address or username. Understanding serialize and how a User is Saved in the Session -------------------------------------------------------------- -If you're curious about the importance of the ``serialize`` method inside -the User class or how the User object is serialized or deserialized, then +If you're curious about the importance of the ``serialize()`` method inside +the ``User`` class or how the User object is serialized or deserialized, then this section is for you. If not, feel free to skip this. Once the user is logged in, the entire User object is serialized into the @@ -757,18 +757,17 @@ Even though this all happens automatically, there are a few important side-effec First, the :phpclass:`Serializable` interface and its ``serialize`` and ``unserialize`` methods have been added to allow the ``User`` class to be serialized to the session. This may or may not be needed depending on your setup, -but it's probably a good idea. Only the ``id`` needs to be serialized, +but it's probably a good idea. In theory, only the ``id`` needs to be serialized, because the :method:`Symfony\\Bridge\\Doctrine\\Security\\User\\EntityUserProvider::refreshUser` method refreshes the user on each request by using the ``id`` (as explained -above). In practice, this means that the User object is reloaded from the -database on each request using the ``id`` from the serialized object. This -makes sure all of the User's data is fresh. - +above). However in practice, this means that the User object is reloaded from +the database on each request using the ``id`` from the serialized object. +This makes sure all of the User's data is fresh. Symfony also uses the ``username``, ``salt``, and ``password`` to verify that the User has not changed between requests. Failing to serialize these may cause you to be logged out on each request. If your User implements -:class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`, +the :class:`Symfony\\Component\\Security\\Core\\User\\EquatableInterface`, then instead of these properties being checked, your ``isEqualTo`` method is simply called, and you can check whatever properties you want. Unless you understand this, you probably *won't* need to implement this interface From 0dac73fe6ab90903bd3ab76d5e8618825be6135a Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Mon, 20 Jan 2014 20:50:14 -0600 Subject: [PATCH 33/33] [#3419] Minor language tweak thanks to @xabbuh --- cookbook/doctrine/file_uploads.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cookbook/doctrine/file_uploads.rst b/cookbook/doctrine/file_uploads.rst index b48997268b0..adb30e27e1f 100644 --- a/cookbook/doctrine/file_uploads.rst +++ b/cookbook/doctrine/file_uploads.rst @@ -303,11 +303,11 @@ Using Lifecycle Callbacks .. caution:: Using lifecycle callbacks is a limited technique that has some drawbacks. - If you want to remove the hard coded ``__DIR__`` reference inside + If you want to remove the hardcoded ``__DIR__`` reference inside the ``Document::getUploadRootDir()`` method, the best way is to start - using explicit :doc:`doctrine listeners ` - where you will be able to inject kernel parameters such as - ``kernel.root_dir`` to be able to build absolute paths. + using explicit :doc:`doctrine listeners `. + There you will be able to inject kernel parameters such as ``kernel.root_dir`` + to be able to build absolute paths. Even if this implementation works, it suffers from a major flaw: What if there is a problem when the entity is persisted? The file would have already moved