It’s been a very long time since I did anything with Laravel. I found another job around the time of Laravel 6, and today they are up to Laravel 9 – much has changed.

I was keen to look at using Laravel with LDAP both for authentication and management.

Building the App

First, I had to figure out how to get all the parts I used to know working again. It seems there are new JavaScript components and a change of CSS framework. I wanted to get back to using Vue.js, and it seemed not very straight forward to do that – until I discovered this article:

https://laravel.io/articles/setting-up-laravel-with-inertiajs-vuejs-tailwind-css

This worked out well, and I have an environment where I can use Vue. I just have to figure out the differences required for me to adopt TailWindCSS.

There are quite a few new things to figure out. Inertiajs is the glue that brings Laravel and vue together.

For handling LDAP processes I previously I would have used Adldap2-Laravel, this has been superseded by LdapRecord-Laravel. At the time of writing, it’s not ready for Laravel 9. This means the setup of the Vue.js project above must be done using Laravel 8:

composer create-project laravel/laravel:^8.0 myproject

Using LDAP

I want to use my Laravel project to manage LDAP and authenticate using LDAP, I don’t really want to synchronise my LDAP credentials over into a database.

Going through the LdapRecord setup guide, I find I need to install Jetstream. Jetstream is Laravel’s authentication starter kit. When you first start looking at a simple application, you’ll find Laravel has Breeze and Jetstream for authentication. Breeze is the basic offering using database authentication – Jetstream is a step-up to using different authentication platforms.

I can do this by ignoring the synchronisation settings. I have to be sure to make sure I notice the changes in code to use OpenLDAP, not Active Directory. At the end of the guide I find I have a number of Vue pages for login and registration and can launch the app from my browser – with one problem.

When I tried to log on, I saw in the LDAP logs that it was successful, but Laravel failed with a database error. It could not write to the session table because the user_id column does not match the data type it’s trying to write.

SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for type bigint: "7bde0af4-e393-1039-8b6c-117754cdf7d5" (SQL: update "sessions" set "payload" = YTo0OntzOjY6Il90b2tlbiI7czo0MDoiUjNad09lUmFuemhOZGZ6elBQU0ZFalpWMUxZdEkzRGJwdlpRZUt0bCI7czo2OiJfZmxhc2giO2E6Mjp7czozOiJvbGQiO2E6MDp7fXM6MzoibmV3IjthOjA6e319czo5OiJfcHJldmlvdXMiO2E6MTp7czozOiJ1cmwiO3M6Mjc6Imh0dHA6Ly8xOTIuMTY4LjEyMi4xOTE6ODAwMCI7fXM6NTA6ImxvZ2luX3dlYl81OWJhMzZhZGRjMmIyZjk0MDE1ODBmMDE0YzdmNThlYTRlMzA5ODlkIjtzOjM2OiI3YmRlMGFmNC1lMzkzLTEwMzktOGI2Yy0xMTc3NTRjZGY3ZDUiO30=, "last_activity" = 1653135298, "user_id" = 7bde0af4-e393-1039-8b6c-117754cdf7d5, "ip_address" = 192.168.122.1, "user_agent" = Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.162 Safari/537.36, "id" = 5hu2fA8e10NguxqYewrbt2zku31uVSVMXNUWpdr1 where "id" = 5hu2fA8e10NguxqYewrbt2zku31uVSVMXNUWpdr1)

In the migration for ...create_sessions_table.php I see it is using a foreignId for the column type.

Schema::create('sessions', function (Blueprint $table) {
    $table->string('id')->primary();
    $table->foreignId('user_id')->nullable()->index();
    $table->string('ip_address', 45)->nullable();
    $table->text('user_agent')->nullable();
    $table->text('payload');
    $table->integer('last_activity')->index();
});

I’m guessing in most cases this would be OK for sessions related to a database ID, but using LDAP it’s coming up with the entryUUID for user_id. I changed this to:

$table->uuid('user_id')->nullable()->index();

Then rolled back and forward the migration to change the column type, and now I can log on, and the session table gets updated correctly.

Access to LDAP Attributes

One thing I didn’t want is for Laravel to have access to all of my LDAP users attributes – especially userPassword, but also anything else I may have in there that I don’t need for basic authentication, or attributes my app has no need of.

I could see all LDAP attributes were available to Laravel from the Vue Dev Tools extension in my browser

For this, I created an LDAP User Model as per LdapRecord:

php artisan make:ldap-model User

Now edit the file Ldap\User.php, change the class extension, and set up the protected variables:

<?php

namespace App\Ldap;

// use LdapRecord\Models\Model;

class User extends \LdapRecord\Models\OpenLDAP\User
{
    /**
     * The object classes of the LDAP model.
     *
     * @var array
     */
    protected $hidden = ['userPassword'];
    protected $visible = ['cn', 'mail', 'sn', 'givenName', 'initials'];

    public static $objectClasses = [
        'top',
        'person',
        'organizationalperson',
    ];
}

I probably don’t need $hidden and $visible, as $visible should allow access to only those attributes I want it to. Now change the config/auth.php so it uses this user model and not the default:

'ldap' => [
    'driver' => 'ldap',
    'model' => App\Ldap\User::class,
    // 'model' => LdapRecord\Models\OpenLDAP\User::class,
],

Now, when I log on to the Jetstream app and look in the Vue Dev Tools, I only see the white listed attributes as per $visible.