Pass-through / SSO Setup

Middleware

To enable single-sign-on in your Laravel application, insert the included WindowsAuthenticate middleware on your middleware stack inside your app/Http/Kernel.php file:

protected $middlewareGroups = [
    'web' => [
        // ...
        \LdapRecord\Laravel\Middleware\WindowsAuthenticate::class,
    ],
];

The WindowsAuthenticate middleware uses the rules you have configured inside your config/auth.php file. A user may successfully authenticate against your LDAP server when visiting your site, but depending on your rules, may not be imported or logged in.

Multi-Domain SSO

To be able to use multi-domain single-sign-on, your LDAP directory servers must first be joined in a trust.

Consider we have two domains: alpha.local and bravo.local.

If you have a web server that is joined to the alpha.local domain that is hosting your Laravel application, it must allow users to authenticate to the bravo.local domain.

Once you have a working trust defined between your domains, you must follow the steps of setting up multi-domain authentication. You may skip step 2, if you do not need a login page for your users.

After completing the above linked guide, you must instruct the WindowsAuthenticate middleware to utilize your LDAP authentication guards that you have configured in your config/auth.php file by calling the guards method:

// app/Providers/AuthServiceProvider.php

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    WindowsAuthenticate::guards(['alpha', 'bravo']);
}

Or, if you prefer, you may define the WindowsAuthenticate middleware as a named middleware inside your app/Http/Kernel.php, and insert the guard names in the definition of your routes:

// app/Http/Kernel.php

/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array
 */
protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.windows' => \LdapRecord\Laravel\Middleware\WindowsAuthenticate::class,
    // ...
],

Then, utilize it inside your routes file:

Remember, when guarding your routes that require authentication via the auth middleware, you must add both guard names into it as well.

// routes/web.php

Route::middleware([
    'auth.windows:alpha,bravo',
    'auth:alpha,bravo',
])->group(function () {
    // ...
});

The actual ordering of the middleware definition is important here, so your users that are accessing your site through single-sign-on are logged in, prior to the auth middleware. Otherwise, they will be simply redirected to your login page.

SSO Domain Verification

To prevent security issues using multiple-domain authentication using the WindowsAuthenticate middleware, domain verification will be performed on the authenticating user.

This verification checks if the users domain name is contained inside of their full distinguished name, which is retrieved from each of your configured LDAP guards.

Only 'Domain Components' are checked in the users distinguished name. More on this below.

To describe this issue in further detail -- the WindowsAuthenticate middleware retrieves all of your configured authentication guards inside of your config/auth.php file. It then determines which one is using the ldap driver, and attempts to locate the authenticating users from each connection.

Since there is the possibility of users having the same sAMAccountName on two separate domains, LdapRecord must verify that the user retrieved from your domain is in-fact the user who is connecting to your Laravel application via Single-Sign-On.

For example, if a user visits your Laravel application with the username of:

ACME\sbauman

And LdapRecord locates a user with the distinguished name of:

cn=sbauman,ou=users,dc=local,dc=com

They will be denied authentication. This is because the authenticating user has a domain of ACME, but it is not contained inside of their distinguished name domain components (dc).

Using the same example, if the located users distinguished name is:

cn=sbauman,ou=users,dc=acme,dc=com

Then they will be allowed to authenticate, as their ACME domain exists inside of their distinguished name domain components (dc=acme). Comparison against each domain component will be performed in a case-insensitive manor.

If you would like to disable this check, you must call the static method bypassDomainVerification on the WindowsAuthenticate middleware inside of your AuthServiceProvider:

Important: This is a security issue if you use multi-domain authentication, since users who have the same sAMAccountName could sign in as each other. You have been warned. If however, you connect to only one domain inside your application, there is no security issue, and you may disable this check as shown below.

// app/Providers/AuthServiceProvider.php

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    WindowsAuthenticate::bypassDomainVerification();
}

Changing the Server Key

By default, the WindowsAuthenticate middleware uses the AUTH_USER key inside of PHP's $_SERVER array ($_SERVER['AUTH_USER']). If you would like to change this, call the serverKey method on the WindowsAuthenticate middleware inside of your AuthServiceProvider:

// app/Providers/AuthServiceProvider.php

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    WindowsAuthenticate::serverKey('PHP_AUTH_USER');
}

Remember Single-Sign-On users

As of LdapRecord-Laravel version v1.9.0, users signed in to your application via the WindowsAuthenticate middleware will no longer be automatically "remembered".

This shouldn't have any effect on your application, but if you need to re-enable this feature, you must call the rememberAuthenticatedUsers method on the WindowsAuthenticate middleware inside of your AuthServiceProvider:

// app/Providers/AuthServiceProvider.php

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    WindowsAuthenticate::rememberAuthenticatedUsers();
}

Selective / Bypassing Single-Sign-On

Occasionally you may need to allow users who are not a part of the domain to login to your application, as well as allowing domain users to automatically sign in via Single-Sign-On.

Depending on your web servers OS, this process can be different.

Linux (HTTPD)

If you're using the Apache httpd server with plugins enabling the sharing of a domain joined user's username via the REMOTE_USER server variable, you must update the WindowsAuthenticate middleware to use this variable, instead of the default AUTH_USER.

To do this, call the WindowsAuthenticate::serverKey() method in your AuthServiceProvider::boot() method:

// app/Providers/AuthServiceProvider.php

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    WindowsAuthenticate::serverKey('REMOTE_USER');
}

If a user is not on a domain joined computer, then the REMOTE_USER variable will be null and the WindowsAuthenticate middleware will be automatically bypassed, allowing regular web application users to sign in.

Windows (IIS)

A Windows hosted application with NTLM / Windows authentication enabled is unfortunately all-or-nothing on your entire web application instance. This means, you cannot enable a single HTTP endpoint in your application to use Single-Sign-On or exempt a portion of your application. However, there is a workaround that is used frequently in the industry.

The goal is to have two URL's that point to the same Laravel application. One has Windows authentication enabled, and another does not. This is typically identified by an sso sub-domain:

<!-- Standard URL -->
my-app.com

<!-- Single-Sign-On URL -->
sso.my-app.com

To do this, you must create a new IIS application instance and point to the same Laravel application. Then, you simply have Windows authentication enabled on one instance, and left disabled on another.

Nothing needs to be done in your Laravel application. The WindowsAuthenticate middleware will only attempt to authenticate users when the AUTH_USER server key is present, so it can remain in the global middleware stack.

Forcing logouts on non Single-Sign-On users

If a user successfully authenticates to your Laravel application through single-sign-on, and their LDAP account happens to be deleted or disabled, the user will remain authenticated to your application for the duration of your Laravel application's session.

If you would like all users in your application to be signed out automatically if SSO credentials are not available from your web server, call the logoutUnauthenticatedUsers method on the WindowsAuthenticate middleware in your AuthServiceProvider::boot() method:

Important: Only enable this feature if Single-Sign-On is the only way you authenticate users. If a non-Single-Sign-On user has a session open, it will be ended automatically on their next request.

// app/Providers/AuthServiceProvider.php

/**
 * Register any authentication / authorization services.
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    WindowsAuthenticate::logoutUnauthenticatedUsers();
}
← Previous Topic

Overview

Next Topic →

Lumen