Closed fcno closed 3 years ago
Hi @Babiute,
How are you authenticating with Fortify
? Can you post your usage? For example:
Fortify::authenticateUsing('...');
Hi @stevebauman .
// app/providers/AuthServiceProvider
Fortify::authenticateUsing(function ($request) {
// Determine the guard name by the submitted domain.
$guard = $request->domain == 'alpha' ? 'alpha' : 'bravo';
//Set default guard
config(['fortify.guard' => $guard]);
Auth::shouldUse($guard);
$validated = Auth::validate([
'samaccountname' => $request->input('username'),
'password' => $request->input('password')
]);
return $validate ? Auth::getLastAttempted() : null;
});
Ok, can you share your login view so I can understand how you're sending the post request?
Also, do you have two-factor authentication enabled inside of your config/fortify.php
file?
About the routes, I do not have my own login/logout routes. Im using the Login and Logout routes provided by Fortify default installation.
@include('layout.partial.top')
<nav class="navbar navbar-dark bg-secondary">
<span class="navbar-brand">{{ config('app.name') }}</span>
</nav>
<section class="container">
<div class="row justify-content-center">
<div class="col-12 col-lg-6 my-3">
<img class="mx-auto my-3 d-block" id="logo" src="{{ asset('imagem/logo.svg') }}" alt="logo">
<form>
@csrf
{{--Input usuário--}}
<input
class="form-control my-3 @error('username') is-invalid @enderror"
type="text"
name="username"
id="username"
placeholder="Usuário de rede"
autocomplete="off"
title="Informar o seu usuário de rede"
required
autofocus
value="{{ old('username') }}">
{{--Input senha--}}
<input
class="form-control my-3 @error('password') is-invalid @enderror"
type="password"
name="password"
id="password"
placeholder="Senha de rede"
autocomplete="off"
title="Informar a sua senha de rede"
required>
{{--Select órgão--}}
<select
class="form-control my-3 @error('domain') is-invalid @enderror"
name="domain"
id="domain"
required>
<option value="">Escolha o órgão</option>
@foreach (config('orgao.nome_completo') as $orgao => $nome_completo)
<option {{ old('domain') == $orgao ? 'selected' : '' }} value="{{ $orgao }}" >{{ $nome_completo }}</option>
@endforeach
</select>
{{--Botão para entrar na aplicação--}}
<button
class="btn btn-primary btn-block my-3"
type="submit"
formmethod="POST"
formaction="{{ route('login') }}"
name="button-autenticar"
title="Acessar o sistema">
Entrar
</button>
</form>
@include('layout.partial.errors')
</div>
</div>
</section>
@include('layout.partial.footer')
Also, do you have two-factor authentication enabled inside of your
config/fortify.php
file?
No. Every default feature is disabled.
I do not have my own login/logout routes. Im using the Login and Logout routes provided by Fortify default installation.
Yup absolutely -- I did not ask for the routes.
Can you post your App\Models\User.php
?
About the routes, I was just trying to antecipate a possible question 👍
As I'm using multi-domain authentication, Im not using the default model. Im using the 'alpha' user.
<?php
namespace App\Ldap\Alpha;
use LdapRecord\Models\ActiveDirectory\User as LdapUser;
class User extends LdapUser
{
protected $connection = 'alpha';
}
No worries!
Aren't you using database synchronization? That's what the logs indicate.
I'm looking for your applications Eloquent
User model -- not the LDAP model. 👍
Your Eloquent
user model would be configured inside of each guard inside of your config/auth.php
file. For example:
// config/auth.php
'providers' => [
// ...
'ldap' => [
'driver' => 'ldap',
'model' => LdapRecord\Models\ActiveDirectory\User::class,
'database' => [
'model' => App\Models\User::class, // <-- This model here.
'...',
],
],
],
Yes I got it. It was an error to post the synchronization log. I enabled synchronization today (step by step), so I can learn how to properly use each feature in your library But this double authentication has been going on since before. The correct log would be this, from the branch without synchronization that I think is not what causes the problem.
[2020-10-19 15:22:03] local.INFO: User [xxx] has been successfully located for authentication.
[2020-10-19 15:22:03] local.INFO: User [xxx] is authenticating.
[2020-10-19 15:22:03] local.INFO: User [xxx] has successfully passed LDAP authentication.
[2020-10-19 15:22:03] local.INFO: User [xxx] has been successfully located for authentication.
[2020-10-19 15:22:03] local.INFO: User [xxx] is authenticating.
[2020-10-19 15:22:03] local.INFO: User [xxx] has successfully passed LDAP authentication.
Either way follows the model, but it doesn't even exist in the plain authentication branch where the double authentication is happening too.
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use LdapRecord\Laravel\Auth\LdapAuthenticatable;
use LdapRecord\Laravel\Auth\AuthenticatesWithLdap;
class User extends Authenticatable implements LdapAuthenticatable
{
use HasFactory, Notifiable, AuthenticatesWithLdap;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'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',
];
}
I think I've discovered the issue. In Laravel Fortify, by default, it will always attempt the $authenticateUsingCallback
twice if you do not override the $authenticateThroughCallback
inside of the loginPipeline
method shown here:
protected function loginPipeline(LoginRequest $request)
{
if (Fortify::$authenticateThroughCallback) {
return (new Pipeline(app()))->send($request)->through(array_filter(
call_user_func(Fortify::$authenticateThroughCallback, $request)
));
}
if (is_array(config('fortify.pipelines.login'))) {
return (new Pipeline(app()))->send($request)->through(array_filter(
config('fortify.pipelines.login')
));
}
return (new Pipeline(app()))->send($request)->through(array_filter([
config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,
RedirectIfTwoFactorAuthenticatable::class, // <-- `$authenticateUsingCallback` called here
AttemptToAuthenticate::class, // <-- `$authenticateUsingCallback` called here
PrepareAuthenticatedSession::class,
]));
}
First, the RedirectIfTwoFactorAuthenticatable
action is used, which calls the $authenticateUsingCallback
(regardless if you have the feature disabled):
The $authenticateUsingCallback
is called a second time inside of the AttemptToAuthenticate
action:
To work around this, you either have to define your own login pipeline inside of your config/fortify.php
file, or define an $authenticateThroughCallback
using Fortify::authenticateThrough()
.
Hey Steve. Thx for the quick replay. As I'm still in the learning curve of Laravel, I do not know how to properly do it. But thx for you help and I hope it helps who face the same problem :)
Hi @Babiute, last night I pushed a PR into Laravel Fortify that resolves this issue and it was merged this morning 🎉 :
https://github.com/laravel/fortify/pull/127#event-3898653390
Once a new release of Laravel Fortify is created, it should contain this fix 👍
Using LdapRecord - 1.7.3 Fortify with custom UI 1.6 Laravel 8
Hello. I don't know if this would be the normal procedure, but it seems to me, from the log bellow, that the authentication routine is running twice. It would be normal or there is probably something wrong with my application, because if that's the case, I've tried to investigate here and I couldn't find where the problem could be. Any tips?