Laravel AD LDAP

  • Enable PHP for LDAP via INI by enabling the ldap extension:
extension=ldap
  • Install LDAP Record (installs in vendor\directorytree folder)
composer require directorytree/ldaprecord-laravel
  • Publish the LDAP configuration file
php artisan vendor:publish --provider="LdapRecord\Laravel\LdapServiceProvider"
  • Make sure you re-run config:cache after making config changes, to re-cache your modifications, otherwise your config changes won't take affect!

edit the config/ldap.php host variable

//'hosts' => [env('LDAP_HOST', '127.0.0.1')], // This is the original Entry - comment out and replace with below
'hosts' => [env('LDAP_HOST1', '127.0.0.1'), env('LDAP_HOST2', '127.0.0.1')],
  • Configure your LDAP connection (tls recommended - not setup below - as lab environment)
LDAP_LOGGING=true
LDAP_CONNECTION=default
LDAP_HOST1=LAB2-AD-01.lab2.purplepi.ie
LDAP_HOST2=192.168.1.236
LDAP_USERNAME="CN=ldap user,CN=Users,DC=lab2,DC=purplepi,DC=ie"
LDAP_PASSWORD=PKwpQtJe:A}J8vM=
LDAP_PORT=389
LDAP_BASE_DN="DC=lab2,DC=purplepi,DC=ie"
LDAP_TIMEOUT=5
LDAP_SSL=false
LDAP_TLS=false
  • create a new LdapRecord model
  • Confirm if needed - I think not for authenticaion - but if you want to do lookups on specific AD attributes that are not stored in the database
php artisan make:ldap-model User
  • Edit your config/auth.php file
// config/auth.php
 
'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'ldap', // Changed to 'ldap'
    ],
 
 
'providers' => [
    // ...
 
    'ldap' => [
        'driver' => 'ldap',
        'model' => LdapRecord\Models\ActiveDirectory\User::class,
    ],
  • Edit vendor\laravel\ui\auth-backend\AuthenticatesUsers.php
    • Note the Documentation states to edit the LoginController - but if you have installed laravel UI with authentication you would edit the above file.
    protected function credentials(Request $request)
    {
        return [
            'mail' => $request->get('email'),
            'password' => $request->get('password'),
        ];
    }
  • Publish the Migration
    • LdapRecord requires you to have two additional user database columns, guid and domain.
php artisan vendor:publish --provider="LdapRecord\Laravel\LdapAuthServiceProvider"
php artisan migrate
  • Setting up your database user model
    • These are required so LdapRecord can set and retrieve your users domain and guid database columns.
// app/User.php
 
// ...
use LdapRecord\Laravel\Auth\AuthenticatesWithLdap;
use LdapRecord\Laravel\Auth\LdapAuthenticatable;
 
class User extends Authenticatable implements LdapAuthenticatable
{
    use Notifiable, AuthenticatesWithLdap;
 
    // ...
}
  • Use the –delete option to soft delete users who have been disabled
  • Use the –delete-missing option to delete any users not found (because they have been deleted on the AD) - be careful if not found in filter - then all existing users could be soft deleted! (can restore if necessary using a simple SQL query).
  • Use the –restore option to un-softdelete a user if they have been reenabled.
php artisan ldap:import ldap --filter "(objectclass=user)" --delete-missing --delete --restore

Sync any users who are Enabled

php artisan ldap:import ldap --filter "(&(objectclass=user)(|(userAccountControl=512)(userAccountControl=66048)))

Sync any users who are Disabled and who are NOT SystemCriticalObjects

php artisan ldap:import ldap --filter "(&(objectclass=user)(!(isCriticalSystemObject=TRUE))(|(userAccountControl=514)(userAccountControl=66050)))

Note: to use scheduling you must set up a cronjob or task manager to run ever min.

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

For more details click here

Reference
To run the import as a scheduled job, place the following in your app/Console/Kernel.php in the command scheduler:

protected function schedule(Schedule $schedule)
{
    // Import LDAP users hourly.
    $schedule->command('ldap:import ldap', [
        '--no-interaction',
        '--restore',
        '--delete',
        '--filter' => '(objectclass=user)',
    ])->hourly();
}

Lets say you only want to allow users who are a member of IVRadmin to log in. Reference

  • Create an authentication rule
php artisan make:ldap-rule IVRAdmin

Edit this new rule - full example below:

<?php
 
namespace App\Ldap\Rules;
 
use LdapRecord\Laravel\Auth\Rule;
use LdapRecord\Models\ActiveDirectory\Group;
 
class IVRAdmin extends Rule
{
    /**
     * Check if the rule passes validation.
     *
     * @return bool
     */
    public function isValid()
    {
        $ivradmin = Group::find('CN=IVRAdmin,CN=Users,DC=lab2,DC=purplepi,DC=ie');
 
        return $this->user->groups()->recursive()->exists($ivradmin);
    }
}
  • Add the rule to the authentication provider
  1. >
  2. 'providers' => [
  3. // ...
  4.  
  5. 'ldap' => [
  6. 'driver' => 'ldap',
  7. 'model' => LdapRecord\Models\ActiveDirectory\User::class,
  8. 'rules' => [
  9. App\Ldap\Rules\IVRAdmin::class,
  10. ],
  11. 'database' => [
  12. 'model' => App\User::class,
  13. 'sync_passwords' => false,
  14. 'sync_attributes' => [
  15. 'name' => 'cn',
  16. 'email' => 'mail',
  17. ],
  18. ],
  19. ],
  20. ],
  • If you are caching your configuration, make sure you re-run config:cache to re-cache your modifications.

Using the option

 'password_column' => false 

allows you to remove the password column from the users table. Reference: https://ldaprecord.com/docs/laravel/auth/configuration/#database-password-sync

    'providers' => [
 
        'ldap' => [
            'driver' => 'ldap',
            'model' => LdapRecord\Models\ActiveDirectory\User::class,
            'database' => [
                'password_column' => false, 
                'model' => App\User::class,
                'sync_attributes' => [
                    'name' => 'cn',
                    'username' => 'samaccountname',
                ],
            ],
        ],
    ],