DirectoryTree / LdapRecord-Laravel

Multi-domain LDAP Authentication & Management for Laravel.
https://ldaprecord.com/docs/laravel/v3
MIT License
496 stars 52 forks source link

wrong filter data #448

Closed miquelangeld closed 2 years ago

miquelangeld commented 2 years ago

Environment:

Describe the bug: I'm trying to get LdapRecord working with Laravel Backpack. I think all the configuration are OK. when I try to logon, Laravel uses the correct driver. But I always get wrong user/pass. But in the log I don't understand what I'm seeing:

Filter: (&(objectclass=\74\6f\70)(objectclass=\70\65\72\73\6f\6e)(objectclass=\6f\72\67\61\6e\69\7a\61\74\69\6f\6e\61\6c\70\65\72\73\6f\6e)(objectclass=\75\73\65\72)(email=\6d\61\64\61\6e\69\65\6c\40\6d\61\72\68\6f\74\65\6c\73\2e\63\6f\6d)(!(objectclass=\63\6f\6d\70\75\74\65\72))) - Selected: (objectguid,*) Why do I see this \6d\61\64\61\6e\69\65\6c\40\6d\61\72\68\6f\74\65\6c\73\2e\63\6f\6d instead my email?

Maybe it's a backpack issue, in that case I apologize.

stevebauman commented 2 years ago

Hi @miquelangeld! What you're seeing is the fully escaped LDAP filter. Raw filter values may contain binary, which can corrupt text files and cause other issues. The escaped filter is printed in the log to avoid this problem.

I've never used Laravel Backpack. Can you post the code on how you've configured LdapRecord, along with your authentication drivers (config/auth.php), and anything else that may help in debugging auth with Backpack?

If you run the below code, you'll get the real value of your email that your LDAP server will understand:

https://ldaprecord.com/docs/core/v2/helpers/#unescape-1

use LdapRecord\Utilities;

// Returns: madaniel@xxxxxxx
Utilities::unescape('\6d\61\64\61\6e\69\65\6c\40\6d\61\72\68\6f\74\65\6c\73\2e\63\6f\6d');
miquelangeld commented 2 years ago

Hi Steve! what is returning seems correct.

This is my auth.php

 'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],
'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    ],
  'providers' => [
        'users' => [
            'driver' => 'ldap',
            'model' => LdapRecord\Models\ActiveDirectory\User::class,
            'rules' => [],
            'database' => [
                'model' => App\User::class,
                'sync_passwords' => false,
                'sync_attributes' => [
                    'name' => 'cn',
                    'email' => 'mail',
                ],
                'sync_existing' => [
                    'email' => 'mail',
                ],
            ],
        ],
    ],

My User model

<?php

namespace App\Models;

use Backpack\CRUD\app\Models\Traits\CrudTrait;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use LdapRecord\Laravel\Auth\LdapAuthenticatable;
use LdapRecord\Laravel\Auth\AuthenticatesWithLdap;
//se Backpack\CRUD\app\Models\Traits\CrudTrait;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable implements LdapAuthenticatable
{
    use CrudTrait;
    use HasApiTokens, HasFactory, Notifiable;
    use AuthenticatesWithLdap;
    use HasRoles;

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

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}
stevebauman commented 2 years ago

Ok great, everything looks configured fine there. However, we'll need to alter how the credentials are sent through the Auth::login() method, as shown here:

https://ldaprecord.com/docs/laravel/v2/auth/database/logging-in

use Illuminate\Support\Facades\Auth;

$credentials = [
    'mail' => 'jdoe@local.com', // <-- Notice the "mail" key, instead of "email".
    'password' => 'password',
];

if (Auth::attempt($credentials)) {
    // ...
}

It looks like Backpack uses Laravel UI to handle authentication (or at least, a copy of it). You'll need to alter the credentials here, though I'm not sure if backpack publishes these so you're able to edit them safely without changes being lost via a composer update:

https://github.com/Laravel-Backpack/CRUD/blob/5281dc1f1ffa07f629fce14fd91f188f81155844/src/app/Library/Auth/AuthenticatesUsers.php#L96-L99

Can you confirm that?

miquelangeld commented 2 years ago

This is the Authentication config parameters that backpack allow to change out of the box. In this question https://stackoverflow.com/questions/66426767/how-to-use-backpack-for-laravel-with-ldaprecord-laravel The laravel backpack creator suggested to change the guard that backpack use from packpack to null in order to use the config.auth.defaults.guard configuration, which I did but still not working for me (But it worked for the fellow that made the question)

` -------------------------------------------------------------------------- Authentication
*/

// Fully qualified namespace of the User model

// 'user_model_fqn' => config('auth.providers.users.model'), // 'user_model_fqn' => App\User::class, // works on Laravel <= 7 'user_model_fqn' => App\Models\User::class, // works on Laravel >= 8

// The classes for the middleware to check if the visitor is an admin
// Can be a single class or an array of classes
'middleware_class' => [
    App\Http\Middleware\CheckIfAdmin::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    \Backpack\CRUD\app\Http\Middleware\UseBackpackAuthGuardInsteadOfDefaultAuthGuard::class,
],

// Alias for that middleware
'middleware_key' => 'admin',
// Note: It's recommended to use the backpack_middleware() helper everywhere, which pulls this key for you.

// Username column for authentication
// The Backpack default is the same as the Laravel default (email)
// If you need to switch to username, you also need to create that column in your db
'authentication_column'      => 'email',
'authentication_column_name' => 'Email',

// The guard that protects the Backpack admin panel.
// If null, the config.auth.defaults.guard value will be used.

// 'guard' => 'backpack', 'guard' => null, // The password reset configuration for Backpack. // If null, the config.auth.defaults.passwords value will be used. 'passwords' => null, `

stevebauman commented 2 years ago

Hmmm, you can try changing authentication_column to mail and see if that works?

miquelangeld commented 2 years ago

Yes, that seems to get me one step forward. Now i'm getting Class '\App\User' not found at Synchronizer.php:281

which is a function named createEloquentModel

I think I know what the problem is, let me try something.

miquelangeld commented 2 years ago

My mistake in auth.providers.users.database.model i had the wrong path to the model App\User::class instead App\Models\User::class

Now it's working and sync it's also working! Thanks for the help because it wasn't any problem with LdapRecord, you're so kind

stevebauman commented 2 years ago

Awesome! I’m glad you’re up and running @miquelangeld! Happy to help 😄