Adldap2 / Adldap2-Laravel

LDAP Authentication & Management for Laravel
MIT License
911 stars 184 forks source link

Active Directory Authentication Issues #708

Closed chaos520 closed 5 years ago

chaos520 commented 5 years ago

Description:

Hi, Admin I had tried the tutorial by referring https://github.com/jotaelesalinas/laravel-simple-ldap-auth

Open LDAP authentication is success without any issues, however for Active Directory authentication, it does not return any error message and redirected to Login page.

Therefore I posted here to seek for advice.

Please refer the code below.

Steps To Reproduce:

.env

LDAP_SCHEMA=ActiveDirectory
LDAP_HOSTS=***MyDomainController IP Address***
LDAP_BASE_DN=OU=***MyGroupUsers,DC=MyDomain,DC=com***
LDAP_USER_ATTRIBUTE=samaccountname
LDAP_USER_FORMAT=samaccountname=%s,dc=MyDomain,dc=com
LDAP_CONNECTION=default

ldap.php

return [
    'logging' => env('LDAP_LOGGING', false),
    'connections' => [
        'default' => [
            'auto_connect' => env('LDAP_AUTO_CONNECT', true),
            'connection' => Adldap\Connections\Ldap::class,
            'settings' => [
                'schema' => Adldap\Schemas\ActiveDirectory::class,
                'account_prefix' => env('LDAP_ACCOUNT_PREFIX', ''),
                'account_suffix' => env('LDAP_ACCOUNT_SUFFIX', ''),
                'hosts' => explode(' ', 
                    env('LDAP_HOSTS', '***MyDomainController IP Address***')
                ),
                'port' => env('LDAP_PORT', 389),
                'timeout' => env('LDAP_TIMEOUT', 5),
                'base_dn' => env('LDAP_BASE_DN', 
                    '***MyGroupUsers,DC=MyDomain,DC=com***'),
                'username' => env('LDAP_USERNAME'),
                'password' => env('LDAP_PASSWORD'),
                'follow_referrals' => false,
                'use_ssl' => env('LDAP_USE_SSL', false),
                'use_tls' => env('LDAP_USE_TLS', false),
            ],
        ],
    ],
];

for the LDAP_USERNAME, what should I use? samAccountName@Domain.com or Domain\samAccountName or samAccountName only?

ldap.auth.php

return [
    'connection' => env('LDAP_CONNECTION', 'default'),
    'provider' => Adldap\Laravel\Auth\DatabaseUserProvider::class,
    'model' => App\User::class,
    'rules' => [
        Adldap\Laravel\Validation\Rules\DenyTrashed::class,
    ],

    'scopes' => [
    ],

    'identifiers' => [
        'ldap' => [
            'locate_users_by' => 'samaccountname',
            'bind_users_by' => 'distinguishedname',
        ],
        'database' => [
            'guid_column' => 'objectguid',
            'username_column' => 'username',
        ],
        'windows' => [
            'locate_users_by' => 'samaccountname',
            'server_key' => 'AUTH_USER',
        ],
    ],

    'passwords' => [
        'sync' => env('LDAP_PASSWORD_SYNC', false),
        'column' => 'password',
    ],

    'login_fallback' => env('LDAP_LOGIN_FALLBACK', false),

    'usernames' => [
        'ldap' => [
            'discover' => env('LDAP_USER_ATTRIBUTE', 'samaccountname'),
            'authenticate' => env('LDAP_USER_ATTRIBUTE', 'samaccountname'),
        ],
        'eloquent' => 'samaccountname',
    ],

    'sync_attributes' => [
        'username' => 'samaccountname',
        'name' => 'cn',
        'phone' => 'telephonenumber',
        // 'email' => 'userprincipalname',
    ],

    'logging' => [
        'enabled' => env('LDAP_LOGGING', true),
        'events' => [
            \Adldap\Laravel\Events\Importing::class => \Adldap\Laravel\Listeners\LogImport::class,
            \Adldap\Laravel\Events\Synchronized::class => \Adldap\Laravel\Listeners\LogSynchronized::class,
            \Adldap\Laravel\Events\Synchronizing::class => \Adldap\Laravel\Listeners\LogSynchronizing::class,
            \Adldap\Laravel\Events\Authenticated::class => \Adldap\Laravel\Listeners\LogAuthenticated::class,
            \Adldap\Laravel\Events\Authenticating::class => \Adldap\Laravel\Listeners\LogAuthentication::class,
            \Adldap\Laravel\Events\AuthenticationFailed::class => \Adldap\Laravel\Listeners\LogAuthenticationFailure::class,
            \Adldap\Laravel\Events\AuthenticationRejected::class => \Adldap\Laravel\Listeners\LogAuthenticationRejection::class,
            \Adldap\Laravel\Events\AuthenticationSuccessful::class => \Adldap\Laravel\Listeners\LogAuthenticationSuccess::class,
            \Adldap\Laravel\Events\DiscoveredWithCredentials::class => \Adldap\Laravel\Listeners\LogDiscovery::class,
            \Adldap\Laravel\Events\AuthenticatedWithWindows::class => \Adldap\Laravel\Listeners\LogWindowsAuth::class,
            \Adldap\Laravel\Events\AuthenticatedModelTrashed::class => \Adldap\Laravel\Listeners\LogTrashedModel::class,
        ],
    ],
];

LoginController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Adldap\Laravel\Facades\Adldap;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    public function username()
    {
        return config('ldap_auth.usernames.eloquent');
    }

    protected function validateLogin(Request $request)
    {
        $this->validate($request, [
            $this->username() => 'required|string|regex:/^\w+$/',
            'password' => 'required|string',
        ]);
    }

    protected function attemptLogin(Request $request)
    {
        $credentials = $request->only($this->username(), 'password');
        $username = $credentials[$this->username()];
        $password = $credentials['password'];

        $user_format = env('LDAP_USER_FORMAT', 'cn=%s,'.env('LDAP_BASE_DN', ''));
        $userdn = sprintf($user_format, $username);

        // you might need this, as reported in
        // [#14](https://github.com/jotaelesalinas/laravel-simple-ldap-auth/issues/14):
        // Adldap::auth()->bind($userdn, $password);

        if(Adldap::auth()->attempt($userdn, $password, $bindAsUser = true)) {
            // the user exists in the LDAP server, with the provided password

            $user = \App\User::where($this->username(), $username)->first();
            if (!$user) {
                // the user doesn't exist in the local database, so we have to create one

                $user = new \App\User();
                $user->username = $username;
                $user->password = '';

                // you can skip this if there are no extra attributes to read from the LDAP server
                // or you can move it below this if(!$user) block if you want to keep the user always
                // in sync with the LDAP server 
                $sync_attrs = $this->retrieveSyncAttributes($username);
                foreach ($sync_attrs as $field => $value) {
                    $user->$field = $value !== null ? $value : '';
                }
            }

            // by logging the user we create the session, so there is no need to login again (in the configured time).
            // pass false as second parameter if you want to force the session to expire when the user closes the browser.
            // have a look at the section 'session lifetime' in `config/session.php` for more options.
            $this->guard()->login($user, true);
            return true;
        }

        // the user doesn't exist in the LDAP server or the password is wrong
        // log error
        return false;
    }

    protected function retrieveSyncAttributes($username)
    {
        $ldapuser = Adldap::search()->where(env('LDAP_USER_ATTRIBUTE'), '=', $username)->first();
        if ( !$ldapuser ) {
            // log error
            return false;
        }
        // if you want to see the list of available attributes in your specific LDAP server:
        // var_dump($ldapuser->attributes); exit;

        // needed if any attribute is not directly accessible via a method call.
        // attributes in \Adldap\Models\User are protected, so we will need
        // to retrieve them using reflection.
        $ldapuser_attrs = null;

        $attrs = [];

        foreach (config('ldap_auth.sync_attributes') as $local_attr => $ldap_attr) {
            if ( $local_attr == 'username' ) {
                continue;
            }

            $method = 'get' . $ldap_attr;
            if (method_exists($ldapuser, $method)) {
                $attrs[$local_attr] = $ldapuser->$method();
                continue;
            }

            if ($ldapuser_attrs === null) {
                $ldapuser_attrs = self::accessProtected($ldapuser, 'attributes');
            }

            if (!isset($ldapuser_attrs[$ldap_attr])) {
                // an exception could be thrown
                $attrs[$local_attr] = null;
                continue;
            }

            if (!is_array($ldapuser_attrs[$ldap_attr])) {
                $attrs[$local_attr] = $ldapuser_attrs[$ldap_attr];
            }

            if (count($ldapuser_attrs[$ldap_attr]) == 0) {
                // an exception could be thrown
                $attrs[$local_attr] = null;
                continue;
            }

            // now it returns the first item, but it could return
            // a comma-separated string or any other thing that suits you better
            $attrs[$local_attr] = $ldapuser_attrs[$ldap_attr][0];
            //$attrs[$local_attr] = implode(',', $ldapuser_attrs[$ldap_attr]);
        }

        return $attrs;
    }

    protected static function accessProtected ($obj, $prop)
    {
        $reflection = new \ReflectionClass($obj);
        $property = $reflection->getProperty($prop);
        $property->setAccessible(true);
        return $property->getValue($obj);
    }
}

Migration Files

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('username')->unique();
            $table->string('phone');
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

Login.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Login') }}</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('login') }}">
                        @csrf

<!--                         <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" required autofocus>

                                @if ($errors->has('email'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div> -->

                        <div class="form-group row">
                            <label for="username" class="col-sm-4 col-form-label text-md-right">{{ __('Username') }}</label>
                            <div class="col-md-6">
                                <input id="username" type="username" class="form-control{{ $errors->has('username') ? ' is-invalid' : '' }}" name="username" value="{{ old('username') }}" required autofocus>
                                @if ($errors->has('username'))
                                <span class="invalid-feedback" role="alert">
                                    <strong>{{ $errors->first('username') }}</strong>
                                </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>

                                @if ($errors->has('password'))
                                <span class="invalid-feedback" role="alert">
                                    <strong>{{ $errors->first('password') }}</strong>
                                </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group row">
                            <div class="col-md-6 offset-md-4">
                                <div class="form-check">
                                    <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

                                    <label class="form-check-label" for="remember">
                                        {{ __('Remember Me') }}
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Login') }}
                                </button>

<!--                                 @if (Route::has('password.request'))
                                <a class="btn btn-link" href="{{ route('password.request') }}">
                                    {{ __('Forgot Your Password?') }}
                                </a>
                                @endif
                            </div> -->
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
Artistan commented 5 years ago

I finally found out that the ldap user for admin needed to be with a domain name...

 'username' => env('LDAP_USERNAME', 'ldapauth@test.local'),

otherwise it will throw something like

80090308: LdapErr: DSID-0C090400, comment: AcceptSecurityContext error, data 52e, v1db1

I found this by dumping in the \Adldap\Auth\Guard::bind catch ....

dd($username, $password,$this->connection->getDetailedError(), $e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine());exit;
stevebauman commented 5 years ago

Hi @chaos520,

@Artistan is correct, you can only use users full distinguished names or user principal names to authenticate with ActiveDirectory. Here's an example of each:

Distinguished Name:

cn=John Doe,ou=Users,dc=acme,dc=org

User Principal Name

jdoe@acme.org

From first glance, you're doing a ton of custom auth work in the LoginController. You don't need to do this using the Adldap2-Laravel auth driver.

You are also missing the username input field from your login.blade.php view - it's currently using an email input field.

Please follow the quick start here:

https://adldap2.github.io/Adldap2-Laravel/#/auth/introduction?id=quick-start-from-scratch

chaos520 commented 5 years ago

Hi @stevebauman

As I recreate the project again, seems still couldn't get it.

ldap_auth.php

<?php

return [
    'connection' => env('LDAP_CONNECTION', 'default'),
    'provider' => Adldap\Laravel\Auth\DatabaseUserProvider::class,
    'model' => App\User::class,
    'rules' => [
        Adldap\Laravel\Validation\Rules\DenyTrashed::class,
    ],
    'scopes' => [
    ],
    'identifiers' => [
        'ldap' => [
            'locate_users_by' => 'userprincipalname',
            'bind_users_by' => 'distinguishedname',
        ],
        'database' => [
            'guid_column' => 'objectguid',
            'username_column' => 'email',
        ],
        'windows' => [
            'locate_users_by' => 'samaccountname',
            'server_key' => 'AUTH_USER',
        ],
    ],

    'passwords' => [
        'sync' => env('LDAP_PASSWORD_SYNC', false),
        'column' => 'password',
    ],
    'login_fallback' => env('LDAP_LOGIN_FALLBACK', false),
    'sync_attributes' => [
        'email' => 'userprincipalname',
        'name' => 'cn',
    ],
    'logging' => [
        'enabled' => env('LDAP_LOGGING', true),
        'events' => [
            \Adldap\Laravel\Events\Importing::class => \Adldap\Laravel\Listeners\LogImport::class,
            \Adldap\Laravel\Events\Synchronized::class => \Adldap\Laravel\Listeners\LogSynchronized::class,
            \Adldap\Laravel\Events\Synchronizing::class => \Adldap\Laravel\Listeners\LogSynchronizing::class,
            \Adldap\Laravel\Events\Authenticated::class => \Adldap\Laravel\Listeners\LogAuthenticated::class,
            \Adldap\Laravel\Events\Authenticating::class => \Adldap\Laravel\Listeners\LogAuthentication::class,
            \Adldap\Laravel\Events\AuthenticationFailed::class => \Adldap\Laravel\Listeners\LogAuthenticationFailure::class,
            \Adldap\Laravel\Events\AuthenticationRejected::class => \Adldap\Laravel\Listeners\LogAuthenticationRejection::class,
            \Adldap\Laravel\Events\AuthenticationSuccessful::class => \Adldap\Laravel\Listeners\LogAuthenticationSuccess::class,
            \Adldap\Laravel\Events\DiscoveredWithCredentials::class => \Adldap\Laravel\Listeners\LogDiscovery::class,
            \Adldap\Laravel\Events\AuthenticatedWithWindows::class => \Adldap\Laravel\Listeners\LogWindowsAuth::class,
            \Adldap\Laravel\Events\AuthenticatedModelTrashed::class => \Adldap\Laravel\Listeners\LogTrashedModel::class,
        ],
    ],
];

LoginController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    public function username()
    {
      return 'username';
    }

}

User.php

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'username', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

login.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Login') }}</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('login') }}">
                        @csrf

<!--                         <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" required autofocus>

                                @if ($errors->has('email'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div> -->

                        <div class="form-group row">
                            <label for="username" class="col-md-4 col-form-label text-md-right">{{ __('Username') }}</label>

                            <div class="col-md-6">
                                <input id="username" type="username" class="form-control{{ $errors->has('username') ? ' is-invalid' : '' }}" name="username" value="{{ old('username') }}" required autofocus>

                                @if ($errors->has('username'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('username') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>                        

                        <div class="form-group row">
                            <label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>

                                @if ($errors->has('password'))
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group row">
                            <div class="col-md-6 offset-md-4">
                                <div class="form-check">
                                    <input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

                                    <label class="form-check-label" for="remember">
                                        {{ __('Remember Me') }}
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-8 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Login') }}
                                </button>

                                @if (Route::has('password.request'))
                                    <a class="btn btn-link" href="{{ route('password.request') }}">
                                        {{ __('Forgot Your Password?') }}
                                    </a>
                                @endif
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

It throws this exception after I try to login via UI with userprincipalname and password RuntimeException The 'email' key is missing from the given credentials array.

chaos520 commented 5 years ago

As I tested command php artisan adldap:import, it does return my Active Directory user list so I would assume that my ldap.php settings is correct, just left the ldap_auth.php settings need to be fine tuned.

[2019-04-09 10:43:39] local.INFO: User 'Domain displayName' is being imported.
[2019-04-09 10:43:39] local.INFO: User 'Domain displayName' is being synchronized.
[2019-04-09 10:43:39] local.INFO: User 'Domain displayName' has been successfully synchronized.
[2019-04-09 10:43:39] local.ERROR: Unable to import user Domain displayName. SQLSTATE[HY000]: General error: 1364 Field 'username' doesn't have a default value (SQL: insert into users (objectguid, email, name, password, updated_at, created_at)

but it does not allow me to import to db as well.

jee-soon commented 5 years ago

Hi @chaos520 ,

I have a exact problem as your, did by any chance you already fix this?

chaos520 commented 5 years ago

@jee-soon Yes, end up I have sorted the issues by myself.

You may post your config then I can help you to check on it.

jee-soon commented 5 years ago

@chaos520 i also sorted it out. Thanks!

luisbauti92 commented 5 years ago

I have a same problem

[2019-08-28 15:00:17] local.INFO: LDAP (ldap://181.xxx.xxx.xxx:389) - Connection: default - Operation: Binding - Username:   
[2019-08-28 15:00:17] local.INFO: LDAP (ldap://181.xxx.xxx.xxx:389) - Connection: default - Operation: Bound - Username:   
[2019-08-28 15:00:17] local.INFO: LDAP (ldap://181.xxx.xxx.xxx:389) - Connection: default - Operation: Search - Base DN: dc=corp,dc=xxx,dc=com,DC=bo - Filter: (&(objectclass=user)(objectcategory=person)(!(objectclass=contact))(samaccountname=labautistab)) - Selected: (*,objectguid) - Time Elapsed: 28.29

Any idea? Could you show me your settings including the .env?

Thanks.

joseasanchezzz91 commented 5 years ago

I have the same problem @luisbauti92 did you solve it?

pleone commented 5 years ago

@chaos520 @jee-soon can you share how you sorted out the problem? that would help the community to solve the problem as well.

Thanks!

joseasanchezzz91 commented 5 years ago

@pleone I solved it by placing the suffix directly in the LDAP_USERNAME=user@corp.com

I hope it helps you

luisbauti92 commented 5 years ago

@joseasanchezzz91 did you solve it just with that? user@corp.com, what is user parameter?

joseasanchezzz91 commented 5 years ago

@luisbauti92 I resolved with this LDAP configuration

LDAP_HOSTS=xx.x.x.xxx

LDAP_PORT=xxx

LDAP_BASE_DN="dc=corp,dc=xxx,dc=com"

LDAP_USERNAME=usuario( with this config it doesn't work for me)

LDAP_USERNAME=usuario@corp.com (this is the user that has permission in the LDAP )

LDAP_PASSWORD=xxxxxxx

in the ldap_auth file change to this 'ldap' => [

            'locate_users_by' => 'mail',

            'bind_users_by' => 'distinguishedname',

        ], change to mail because placing the suffix to the username already connected to the LDAP but did not authenticate it then reading the log change the match variable

luisbauti92 commented 5 years ago

@luisbauti92 I resolved with this LDAP configuration

LDAP_HOSTS=xx.x.x.xxx

LDAP_PORT=xxx

LDAP_BASE_DN="dc=corp,dc=xxx,dc=com"

LDAP_USERNAME=usuario( with this config it doesn't work for me)

LDAP_USERNAME=usuario@corp.com (this is the user that has permission in the LDAP )

LDAP_PASSWORD=xxxxxxx

in the ldap_auth file change to this 'ldap' => [

        'locate_users_by' => 'mail',

        'bind_users_by' => 'distinguishedname',

    ],

change to mail because placing the suffix to the username already connected to the LDAP but did not authenticate it then reading the log change the match variable

can you speak spanish? usuario jeje. Thanks, I will try it.