diff --git a/components/index.rst b/components/index.rst
index 43aa14e5e40..620fbc239d7 100644
--- a/components/index.rst
+++ b/components/index.rst
@@ -22,6 +22,7 @@ The Components
http_foundation/index
http_kernel/index
intl
+ ldap
options_resolver
phpunit_bridge
process
diff --git a/components/ldap.rst b/components/ldap.rst
new file mode 100644
index 00000000000..b1f51043dd4
--- /dev/null
+++ b/components/ldap.rst
@@ -0,0 +1,72 @@
+.. index::
+ single: Ldap
+ single: Components; Ldap
+
+The Ldap Component
+==================
+
+ The Ldap component provides a means to connect to an LDAP server (OpenLDAP or Active Directory).
+
+Installation
+------------
+
+You can install the component in 2 different ways:
+
+* :doc:`Install it via Composer ` (``symfony/ldap`` on `Packagist`_);
+* Use the official Git repository (https://github.com/symfony/ldap).
+
+.. include:: /components/require_autoload.rst.inc
+
+Usage
+-----
+
+The :class:`Symfony\\Component\\Ldap\\LdapClient` class provides methods
+to authenticate and query against an LDAP server.
+
+The :class:`Symfony\\Component\\Ldap\\LdapClient` class can be configured
+using the following options:
+
+``host``
+ IP or hostname of the LDAP server
+
+``port``
+ Port used to access the LDAP server
+
+``version``
+ The version of the LDAP protocol to use
+
+``useSsl``
+ Whether or not to secure the connection using SSL
+
+``useStartTls``
+ Whether or not to secure the connection using StartTLS
+
+``optReferrals``
+ Specifies whether to automatically follow referrals
+ returned by the LDAP server
+
+For example, to connect to a start-TLS secured LDAP server::
+
+ use Symfony\Component\Ldap\LdapClient;
+
+ $ldap = new LdapClient('my-server', 389, 3, false, true);
+
+The :method:`Symfony\\Component\\Ldap\\LdapClient::bind` method
+authenticates a previously configured connection using both the
+distinguished name (DN) and the password of a user::
+
+ use Symfony\Component\Ldap\LdapClient;
+ // ...
+
+ $ldap->bind($dn, $password);
+
+Once bound (or if you enabled anonymous authentication on your
+LDAP server), you may query the LDAP server using the
+:method:`Symfony\\Component\\Ldap\\LdapClient::find` method::
+
+ use Symfony\Component\Ldap\LdapClient;
+ // ...
+
+ $ldap->find('dc=symfony,dc=com', '(&(objectclass=person)(ou=Maintainers))');
+
+.. _Packagist: https://packagist.org/packages/symfony/ldap
diff --git a/components/map.rst.inc b/components/map.rst.inc
index deb5d6b84c8..2bcd97e9df2 100644
--- a/components/map.rst.inc
+++ b/components/map.rst.inc
@@ -112,6 +112,10 @@
* :doc:`/components/intl`
+* **Ldap**
+
+ * :doc:`/components/ldap`
+
* **OptionsResolver**
* :doc:`/components/options_resolver`
diff --git a/cookbook/map.rst.inc b/cookbook/map.rst.inc
index 2b56dfa5ec8..a3329a29d0c 100644
--- a/cookbook/map.rst.inc
+++ b/cookbook/map.rst.inc
@@ -164,6 +164,7 @@
* :doc:`Security Authentication (Identifying/Logging in the User) `
* :doc:`/cookbook/security/form_login_setup`
+ * :doc:`/cookbook/security/ldap`
* :doc:`/cookbook/security/entity_provider`
* :doc:`/cookbook/security/guard-authentication`
* :doc:`/cookbook/security/remember_me`
diff --git a/cookbook/security/index.rst b/cookbook/security/index.rst
index 61efff1aa23..44778bc227e 100644
--- a/cookbook/security/index.rst
+++ b/cookbook/security/index.rst
@@ -8,6 +8,7 @@ Authentication (Identifying/Logging in the User)
:maxdepth: 2
form_login_setup
+ ldap
entity_provider
guard-authentication
remember_me
diff --git a/cookbook/security/ldap.rst b/cookbook/security/ldap.rst
new file mode 100644
index 00000000000..8d197dbc72a
--- /dev/null
+++ b/cookbook/security/ldap.rst
@@ -0,0 +1,384 @@
+.. index::
+ single: Security; Authenticating against an LDAP server
+
+Authenticating against an LDAP server
+=====================================
+
+Symfony provides different means to work with an LDAP server.
+
+The Security component offers:
+
+* The ``ldap`` user provider, using the
+ :class:`Symfony\\Component\\Security\\Core\\User\\LdapUserProvider`
+ class. Like all other user providers, it can be used with any
+ authentication provider.
+
+* The ``form_login_ldap`` authentication provider, for authenticating
+ against an LDAP server using a login form. Like all other
+ authentication providers, it can be used with any user provider.
+
+* The ``http_basic_ldap`` authentication provider, for authenticating
+ against an LDAP server using HTTP Basic. Like all other
+ authentication providers, it can be used with any user provider.
+
+This means that the following scenarios will work:
+
+* Checking a user's password and fetching user information against an
+ LDAP server. This can be done using both the LDAP user provider and
+ either the LDAP form login or LDAP HTTP Basic authentication providers.
+
+* Checking a user's password against an LDAP server while fetching user
+ information from another source (database using FOSUserBundle, for
+ example).
+
+* Loading user information from an LDAP server, while using another
+ authentication strategy (token-based pre-authentication, for example).
+
+Ldap Configuration Reference
+----------------------------
+
+See :doc:`/reference/configuration/security` for the full LDAP
+configuration reference (``form_login_ldap``, ``http_basic_ldap``, ``ldap``).
+Some of the more interesting options are explained below.
+
+Configuring the LDAP client
+---------------------------
+
+All mechanisms actually need an LDAP client previously configured.
+The providers are configured to use a default service named ``ldap``,
+but you can override this setting in the security component's
+configuration.
+
+An LDAP client can be simply configured, using the following service
+definition:
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # app/config/services.yml
+ services:
+ ldap:
+ class: 'Symfony\Component\Ldap\LdapClient'
+ arguments:
+ - my-server # host
+ - 389 # port
+ - 3 # version
+ - false # SSL
+ - true # TLS
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+ my-server
+ 389
+ 3
+ false
+ true
+
+
+
+
+ .. code-block:: php
+
+ // app/config/services.php
+ $container
+ ->register('ldap', 'Symfony\Component\Ldap\LdapClient')
+ ->addArgument('my-server')
+ ->addArgument(389)
+ ->addArgument(3)
+ ->addArgument(false)
+ ->addArgument(true);
+
+ $container
+ ->register('newsletter_manager', 'NewsletterManager')
+ ->addMethodCall('setMailer', array(new Reference('mailer')));
+
+Fetching Users Using the LDAP User Provider
+-------------------------------------------
+
+If you want to fetch user information from an LDAP server, you may want to
+use the ``ldap`` user provider.
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # app/config/security.yml
+ security:
+ # ...
+
+ providers:
+ my_ldap:
+ ldap:
+ service: ldap
+ base_dn: dc=example,dc=com
+ search_dn: "cn=read-only-admin,dc=example,dc=com"
+ search_password: password
+ default_roles: ROLE_USER
+ uid_key: uid
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ $container->loadFromExtension('security', array(
+ 'providers' => array(
+ 'ldap_users' => array(
+ 'ldap' => array(
+ 'service' => 'ldap',
+ 'base_dn' => 'dc=example,dc=com',
+ 'search_dn' => 'cn=read-only-admin,dc=example,dc=com',
+ 'search_password' => 'password',
+ 'default_roles' => 'ROLE_USER',
+ 'uid_key' => 'uid',
+ ),
+ ),
+ ),
+ );
+
+The ``ldap`` user provider supports many different configuration options:
+
+service
+.......
+
+**type**: ``string`` **default**: ``ldap``
+
+This is the name of your configured LDAP client. You can freely chose the
+name, but it must be unique in your application and it cannot start with a
+number or contain white spaces.
+
+base_dn
+.......
+
+**type**: ``string`` **default**: ``null``
+
+This is the base DN for the directory
+
+search_dn
+.........
+
+**type**: ``string`` **default**: ``null``
+
+This is your read-only user's DN, which will be used to authenticate
+against the LDAP server in order to fetch the user's information.
+
+search_password
+...............
+
+**type**: ``string`` **default**: ``null``
+
+This is your read-only user's password, wich will be used to authenticate
+against the LDAP server in order to fetch the user's information.
+
+default_roles
+.............
+
+**type**: ``array`` **default**: ``[]``
+
+This is the default role you wish to give to a user fetched from the LDAP
+server. If you do not configure this key, your users won't have any roles,
+and will not be considered as authenticated fully.
+
+uid_key
+.......
+
+**type**: ``string`` **default**: ``sAMAccountName``
+
+This is the entry's key to use as its UID. Depends on your LDAP server
+implementation. Commonly used values are:
+
+* ``sAMAccountName``
+* ``userPrincipalName``
+* ``uid``
+
+filter
+......
+
+**type**: ``string`` **default**: ``({uid_key}={username})``
+
+This key lets you configure which LDAP query will be used. The ``{uid_key}``
+string will be replaced by the value of the ``uid_key`` configuration value
+(by default, ``sAMAccountName``), and the ``{username}`` string will be
+replaced by the username you are trying to load.
+
+For example, with a ``uid_key`` of ``uid``, and if you are trying to
+load the user ``fabpot``, the final string will be: ``(uid=fabpot)``.
+
+Of course, the username will be escaped, in order to prevent `LDAP injection`_.
+
+The syntax for the ``filter`` key is defined by `RFC4515`_.
+
+Authenticating against an LDAP server
+-------------------------------------
+
+Authenticating against an LDAP server can be done using either the form
+login or the HTTP Basic authentication providers.
+
+They are configured exactly as their non-LDAP counterparts, with the
+addition of two configuration keys:
+
+service
+.......
+
+**type**: ``string`` **default**: ``ldap``
+
+This is the name of your configured LDAP client. You can freely chose the
+name, but it must be unique in your application and it cannot start with a
+number or contain white spaces.
+
+dn_string
+.........
+
+**type**: ``string`` **default**: ``{username}``
+
+This key defines the form of the string used in order to compose the
+DN of the user, from the username. The ``{username}`` string is
+replaced by the actual username of the person trying to authenticate.
+
+For example, if your users have DN strings in the form
+``uid=einstein,dc=example,dc=com``, then the ``dn_string`` will be
+``uid={username},dc=example,dc=com``.
+
+Examples are provided below, for both ``form_login_ldap`` and
+``http_basic_ldap``.
+
+Configuration example for form login
+....................................
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # app/config/security.yml
+ security:
+ # ...
+
+ firewalls:
+ main:
+ # ...
+ form_login_ldap:
+ login_path: login
+ login_check: login_check
+ # ...
+ service: ldap
+ dn_string: 'uid={username},dc=example,dc=com'
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ $container->loadFromExtension('security', array(
+ 'firewalls' => array(
+ 'main' => array(
+ 'form_login_ldap' => array(
+ 'login_path' => 'login',
+ 'login_check' => 'login_check',
+ 'service' => 'ldap',
+ 'dn_string' => 'uid={username},dc=example,dc=com',
+ // ...
+ ),
+ ),
+ )
+ );
+
+Configuration example for HTTP Basic
+....................................
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # app/config/security.yml
+ security:
+ # ...
+
+ firewalls:
+ main:
+ # ...
+ http_basic_ldap:
+ # ...
+ service: ldap
+ dn_string: 'uid={username},dc=example,dc=com'
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+ .. code-block:: php
+
+ $container->loadFromExtension('security', array(
+ 'firewalls' => array(
+ 'main' => array(
+ 'http_basic_ldap' => array(
+ 'service' => 'ldap',
+ 'dn_string' => 'uid={username},dc=example,dc=com',
+ // ...
+ ),
+ 'stateless' => true,
+ ),
+ ),
+ );
+
+.. _`RFC4515`: http://www.faqs.org/rfcs/rfc4515.html
+.. _`LDAP injection`: http://projects.webappsec.org/w/page/13246947/LDAP%20Injection
diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst
index c3e723cf487..69f3cb861fe 100644
--- a/reference/configuration/security.rst
+++ b/reference/configuration/security.rst
@@ -99,6 +99,16 @@ Each part will be explained in the next section.
# name of a non-default entity manager
manager_name: ~
+ my_ldap_provider:
+ ldap:
+ service: ~
+ base_dn: ~
+ search_dn: ~
+ search_password: ~
+ default_roles: 'ROLE_USER'
+ uid_key: 'sAMAccountName'
+ filter: '({uid_key}={username})'
+
# Example custom provider
my_some_custom_provider:
id: ~
@@ -131,6 +141,10 @@ Each part will be explained in the next section.
provider: some_key_from_above
http_basic:
provider: some_key_from_above
+ http_basic_ldap:
+ provider: some_key_from_above
+ service: ldap
+ dn_string: '{username}'
http_digest:
provider: some_key_from_above
guard:
@@ -183,6 +197,50 @@ Each part will be explained in the next section.
# new in Symfony 2.3
require_previous_session: true
+ form_login_ldap:
+ # submit the login form here
+ check_path: /login_check
+
+ # the user is redirected here when they need to log in
+ login_path: /login
+
+ # if true, forward the user to the login form instead of redirecting
+ use_forward: false
+
+ # login success redirecting options (read further below)
+ always_use_default_target_path: false
+ default_target_path: /
+ target_path_parameter: _target_path
+ use_referer: false
+
+ # login failure redirecting options (read further below)
+ failure_path: /foo
+ failure_forward: false
+ failure_path_parameter: _failure_path
+ failure_handler: some.service.id
+ success_handler: some.service.id
+
+ # field names for the username and password fields
+ username_parameter: _username
+ password_parameter: _password
+
+ # csrf token options
+ csrf_parameter: _csrf_token
+ csrf_token_id: authenticate
+ csrf_token_generator: my.csrf_token_generator.id
+
+ # by default, the login form *must* be a POST, not a GET
+ post_only: true
+ remember_me: false
+
+ # by default, a session must exist before submitting an authentication request
+ # if false, then Request::hasPreviousSession is not called during authentication
+ # new in Symfony 2.3
+ require_previous_session: true
+
+ service: ~
+ dn_string: '{username}'
+
remember_me:
token_provider: name
secret: "%secret%"
@@ -255,6 +313,13 @@ Each part will be explained in the next section.
The ``secret`` option of ``anonymous`` and ``remember_me`` was introduced
in Symfony 2.8. Prior to 2.8, it was called ``key``.
+.. versionadded:: 2.8
+ The ``http_basic_ldap`` and ``form_login_ldap`` authentication providers
+ were introduced in Symfony 2.8.
+
+.. versionadded:: 2.8
+ The ``ldap`` user provider was introduced in Symfony 2.8
+
.. _reference-security-firewall-form-login:
Form Login Configuration
@@ -354,6 +419,72 @@ The ``invalidate_session`` option allows to redefine this behavior. Set this
option to ``false`` in every firewall and the user will only be logged out from
the current firewall and not the other ones.
+.. _reference-security-ldap:
+
+LDAP functionality
+------------------
+
+There are several options for connecting against an LDAP server,
+using the ``form_login_ldap`` and ``http_basic_ldap`` authentication
+providers or the ``ldap`` user provider.
+
+For even more details, see :doc:`/cookbook/security/ldap`.
+
+Authentication
+~~~~~~~~~~~~~~
+
+You can authenticate to an LDAP server using the LDAP variants of the
+``form_login`` and ``http_basic`` authentication providers. Simply use
+``form_login_ldap`` and ``http_basic_ldap``, which will attempt to
+``bind`` against a LDAP server instead of using password comparison.
+
+Both authentication providers have the same arguments as their normal
+counterparts, with the addition of two configuration keys:
+
+service
+.......
+
+**type**: ``string`` **default**: ``ldap``
+
+This is the name of your configured LDAP client.
+
+dn_string
+.........
+
+**type**: ``string`` **default**: ``{username}``
+
+This is the string which will be used as the bind DN. The ``{username}``
+placeholder will be replaced with the user-provided value (his login).
+Depending on your LDAP server's configuration, you may need to override
+this value.
+
+User provider
+~~~~~~~~~~~~~
+
+Users will still be fetched from the configured user provider. If you
+wish to fetch your users from a LDAP server, you will need to use the
+``ldap`` user provider, in addition to one of the two authentication
+providers (``form_login_ldap`` or ``http_basic_ldap``).
+
+.. configuration-block::
+
+ .. code-block:: yaml
+
+ # app/config/security.yml
+ security:
+ # ...
+
+ providers:
+ my_ldap_users:
+ ldap:
+ service: ldap
+ base_dn: 'dc=symfony,dc=com'
+ search_dn: '%ldap.search_dn%'
+ search_password: '%ldap.search_password%'
+ default_roles: ''
+ uid_key: 'uid'
+ filter: '(&({uid_key}={username})(objectclass=person)(ou=Users))'
+
Using the PBKDF2 Encoder: Security and Speed
--------------------------------------------