Introduction

Recently, I’ve been investigating Symfony as a solution for a student petitions web application that I’m working on at Taft College. Symfony is a PHP framework that greatly simplifies the creation of web applications. It’s essentially at Model View Controller (MVC) framework.
This blog outlines the enabling of Active Directory integration with Symfony. My reason for documenting it here, was because when I tried searching online for information/examples on how to achieve this, there were references on how to install various components but there were no real step-by-step instructions on how to verify everything it actually working. Hopefully this will help someone else out who is struggling to set this up properly.
If you don’t need to manage users and simply just need to authenticate against an Active Directory server, then look at my new article Symfony LDAP Component AD Authentication instead.

Installing Symfony

This blog presumes you have some Linux OS and are using LAMP (Linux Apache MySql/MariaDB PHP) and each of those is configured correctly. You will need to install Symfony and create your Symfony project that you’ll be using to setup the Active Directory integeration. The Symfony Book Installing and Configuring Symfony gives instructions on how to install Symfony (binary) and Composer (you’ll need this too); I recommend to fully go over most of the Symfony Book, as it will help you get familiar with Symfony. Once you’ve created your Symfony project, you can proceed with the next steps.

Install FOSUserBundle

The Friends Of Symfony User Bundle (FOSUserBundle), is a bundle that persists and fetches users in a database. To install it, use composer with the following command within the root of your Symfony web application. For example, let’s presume your apache DocumentRoot is ‘/var/www/html’ and you’ve created your Symfony project application as ‘test’ in the DocumentRoot, then you would run this command under ‘/var/www/html/test’. Run the following command to install FOSUserBundle:

composer require friendsofsymfony/user-bundle "~2.0@dev"

Install PHP LDAP

In this example, I’m using Centos 6. So if you have a different Linux distro, you may have to install with different commands (i.e. rpm, apt-get). Run the following command to install ext-ldap:

yum install php-ldap

There is no post install configuration required.

Install FR3DLdapBundle

The FR3DLdapBundle provide LDAP authentication. To install it, run the following composer command from your Symfony project root:

composer require fr3d/ldap-bundle "3.0.*@dev"

Configuration

You will need to edit a number of files described here to setup the user, security and Active Directory configuration. First, open the file ‘app/AppKernel.php’ and add the FOSUserBundle and FR3DLdapBundle bundles to the registerBundles function:

<?php
// app/AppKernel.php

public function registerBundles()
{
   $bundles = [
      // ...
      new FOS\UserBundle\FOSUserBundle(),
      new FR3D\LdapBundle\FR3DLdapBundle(),
      // ...
   ];
}

Create a file called ‘FOSUser.php’ under ‘src/AppBundle/Entity’. Note: create the Entity directory if it doesn’t exist. Add the following contents to FOSUser.php:

<?php
// src/AppBundle/Entity/FOSUser.php
namespace AppBundle\Entity;

use FOS\UserBundle\Model\User as BaseUser;
use FR3D\LdapBundle\Model\LdapUserInterface;
use Doctrine\ORM\Mapping as ORM;

/**
  * @ORM\Entity
  * @ORM\Table(name="fos_user")
  */
class FOSUser extends BaseUser implements LdapUserInterface{
   /**
    * @ORM\Id
    * @ORM\Column(type="integer")
    * @ORM\GeneratedValue(strategy="AUTO")
    */
   protected $id;

   /**
     * @ORM\Column(type="string")
     */
   protected $dn;

   public function __construct()
   {
      parent::__construct();
      if (empty($this->roles)) {
         $this->roles[] = 'ROLE_USER';
      }
   }

   /**
     * {@inheritDoc}
     */
   public function setDn($dn)
   { $this->dn = $dn; }

  /**
    * {@inheritDoc}
    */
  public function getDn()
  { return $this->dn; }
}

Open the file ‘app/config/routing.yml’ and make the following change:

# app/config/routing.yml
 ...
 fos_user:
    resource: "@FOSUserBundle/Resources/config/routing/all.xml"

The above setting enables Symfony routing based on configuration from the file vendor/friendsofsymfony/user-bundle/Resources/config/routing/all.xml which enables the routes such as “/login” and “/logout”, providing standard login/logout capability. The Bundle can be overriden but that is not discussed here.

Open the file ‘app/config/security.yml’ and make the following changes. NOTE: This is only my example; Read the Symfony Book > Security section for other examples on how you might configure security for your own scenario. Symfony is highly configurable, and this example is only used as a guideline on helping you to understand how security works in Symfony.

#  'app/config/security.yml'
security:
   # Preserve plain text password in token for refresh the user.
   # Analyze the security considerations before turn off this setting.
   erase_credentials: false

encoders:
   FOS\UserBundle\Model\UserInterface: bcrypt

role_hierarchy:
   ROLE_ADMIN:       ROLE_USER
   ROLE_SUPER_ADMIN: ROLE_ADMIN

providers:
   chain_provider:
      chain:
         providers: [fos_userbundle, fr3d_ldapbundle]
   fr3d_ldapbundle:
      id: fr3d_ldap.security.user.provider
   fos_userbundle:
      id: fos_user.user_provider.username

firewalls:
  # disables authentication for assets and the profiler, adapt it according to your needs
  dev:
    pattern: ^/(_(profiler|wdt)|css|images|js)/
    fr3d_ldap:  ~
    security: false
    form_login:
       always_use_default_target_path: true
       default_target_path: /profile
    logout:       true
    anonymous:    true

 main:
    pattern: ^/
    fr3d_ldap:  ~
    form_login:
       always_use_default_target_path: true
       default_target_path: /profile
    logout:       true
    anonymous:    true

 access_control:
    - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/admin/, role: ROLE_ADMIN }

 

Open the file ‘app/config/config.yml’ and add the following lines at the bottom of the file:

#  app/config/config.yml
...
# Friends of Symfony user
fos_user:
   db_driver: orm
   firewall_name: main
   user_class: AppBundle\Entity\FOSUser
   from_email:
      address: someone@somewhere.com
      sender_name: someone

fr3d_ldap:
   driver:
      host: ldap.forumsys.com
   user:
      baseDn: dc=example, dc=com
      attributes:
         - { ldap_attr: uid,  user_method: setUsername }
         - { ldap_attr: mail,  user_method: setEmail }
      filter: (&(ObjectClass=person))

In the above configuration, I’m using the online test LDAP server ‘ldap.forumsys.com’, which is available for anyone to use to test LDAP authentication. Information on this LDAP test server is found at the following web site: http://www.forumsys.com/tutorials/integration-how-to/ldap/online-ldap-test-server/

Update Schema

Run the following command from the project root directory:

php bin/console doctrine:schema:update --force

This updates the database schema.

Testing Operation

This section describes the steps needed to verify that the above configuration is actually working and doing what it is supposed to. The key to troubleshooting is checking the ‘var/logs/dev.log’ entries. Since the login page configured is ‘^/login$’, you need to point your browser to your apache Directory path. I’m presuming here that you’ve configured this as your Symfony root/web path (the web folder under your Symfony project root directory). Then in your browser enter the following URL:

http://host.name/app_dev.php/login

Where ‘host.name’ is either an IP address or hostname where your apache web server is running. Notice the path contains ‘app_dev.php’. This is a file located in the web folder. If you are not running your browser on the same host that the apache web server is running on, then you’ll need to open this file and add the IP address of your host machine to the ‘REMOTE_ADDR’ array. NOTE: Only add trusted hosts to the ‘REMOTE_ADDR’ array. The following line shows an example where my host machine has an IP address of ‘192.168.40.208’:

//    web/app_dev.php
...
if (isset($_SERVER['HTTP_CLIENT_IP'])
   || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
   || !(in_array(@$_SERVER['REMOTE_ADDR'], ['192.168.40.208', '127.0.0.1',
   'fe80::1', '::1']) || php_sapi_name() === 'cli-server')
)

After you browse to the login page, you should should see labels and text fields for entering username and password and a submit button. Enter a username of “riemann” and password of “password”, then click “security.login.submit”, then you should the profile information for the user. Click the “layout.logout” link to logout.

If the login/logout works correctly, then the normal login URL to use is:

http://host.name/login

And to logout, simply use:

http://host.name/logout

 

Getting AD Authentication to Work

Once you have verified the above (verifies LDAP authentication works), then you need to change your “config.yml” to use your Active Directory server. Edit your “config.yml” as follows (the following data is obsfucated):

# FILE: app/config/config.yml
...
fr3d_ldap:
   driver:
      host: my_ad_server.hostname.com
      username: ad_admin_user_account
      password: admin_password
      accountDomainName: DOM.hostname.com
      accountDomainNameShort: DOM # i.e. prefix you use to login.
   user:
      usernameAttribute: sAMAccountName
      baseDn: cn=Users,dc=hostname,dc=com # Use a LDAP browser to verify this.
      filter: (&(ObjectClass=Person))
      attributes:
         - { ldap_attr: samaccountname, user_method: setUsername }
         - { ldap_attr: mail, user_method: setEmail }

You should now be able to login to your Symfony system using your Active Directory accounts. Always start in the dev environment (append ‘app_dev.php’ to URL) to check first that things are working normally, and check the var/logs/dev.log for error messages.

 

Advertisement