Authenticate users in Laravel against an adminless LDAP server
To understand how configuration works, you have to know first the different steps of the authentication process and the objects and fields involved:
-
The user provides their credentials with two fields: identifier and password. We use the generic word "identifier" because it can be a username, an email, a staff number, a phone number... you name it.
For now, let's say that the identifier is
jdoe
. -
We check in the LDAP server if there is any user with the given identifier. No password checks yet (this is how Laravel Auth works).
This check is done using the attribute
LDAP_USER_SEARCH_ATTRIBUTE
in the LDAP server. It can beuid
,sAMAccountName
... Depends on the LDAP server. In this example, it will beuid
.If there is a matching user, we will have a list of attributes from the LDAP user like this:
[ 'uid' => 'jdoe', 'cn' => 'John Doe', 'mail' => '[email protected]', 'telephonenumber' => '555-12-23-34', 'department' => 'Sales', 'location' => 'HQ', 'distinguishedName' => 'cn=John Doe,dc=example,dc=com', ... ]
-
Then, we check that the credentials are correct. But! For authentication, LDAP does not use identifier + password. It uses "distinguished name" + password.
The distinguished name is a comma-separated list of fields that uniquely identifies an item inside the LDAP registry. In this example:
cn=John Doe,dc=example,dc=com
.Gasp! For the password validation we might have to use a different field than the one used to search the user.
To avoid asking the users for their
uid
and theircn
in the login form, we need another .env variable,LDAP_USER_BIND_ATTRIBUTE
, in this casecn
.The rest of the fields of the distinguished name,
dc=example,dc=com
, go into the .env variableLDAP_BASE_DN
.It could happen that both are the same, e.g.
LDAP_USER_SEARCH_ATTRIBUTE=uid
andLDAP_USER_BIND_ATTRIBUTE=uid
. -
Finally, when the user is retrieved and the password validated, the data from the LDAP server is converted into an object of class
LdapUser
. This is the object returned byAuth::user()
.This object will have the identifier stored in the property that you specify in the .env variable
AUTH_USER_KEY_FIELD
. If it isid
, the user will have a propertyid
equal tojdoe
. If you chooseusername
, the user will have a propertyusername
equal tojdoe
.Also, using the config variable
ldap_auth.sync_attributes
you will be able to tell which fields from the LDAP server you want "imported" into the Auth user, and under which names. For security reasons, you have to whitelist the attributes to be imported.As an example, if you have this entry in
config/ldap_auth.php
:'sync_attributes' => [ // 'field_in_local_user_model' => 'attribute_in_ldap_server', env('AUTH_USER_KEY_FIELD', null) => env('LDAP_USER_SEARCH_ATTRIBUTE', null), 'name' => 'cn', 'email' => 'mail', 'phone' => 'telephonenumber', ],
Given the sample LDAP user from the step 2, you will have the following Auth user:
JotaEleSalinas\AdminlessLdap\LdapUser { "username": "jdoe", "name": "John Doe", "email": "[email protected]", "phone": "555-12-23-34", }
And this is the user object that you will use thoughout your Laravel app.
LdapUser
is not an Eloquent model! You cannot doLdapUser::where('uid', '=', 'jdoe')
and all the nice things that you might be used to do with Eloquent.
Don't hesitate to propose improvements if you think something is unclear or not properly explained.
Bonus! This document was a yawner, but you finished it! Congratulations! Now you can also login to the public testing LDAP server using these new users: euler
and euclid
. The password is password
for both of them.
Was this package useful? Give it a star!