mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-06-19 19:28:08 +02:00
Force logout on routes not watched by the KickOutInactiveUser middleware
This commit is contained in:
parent
3ad068d1d7
commit
528a3be458
@ -73,12 +73,14 @@ class Kernel extends HttpKernel
|
|||||||
protected $middlewareAliases = [
|
protected $middlewareAliases = [
|
||||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||||
'admin' => \App\Http\Middleware\AdminOnly::class,
|
'admin' => \App\Http\Middleware\AdminOnly::class,
|
||||||
'guest' => \App\Http\Middleware\RejectIfAuthenticated::class,
|
'rejectIfAuthenticated' => \App\Http\Middleware\RejectIfAuthenticated::class,
|
||||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||||
'rejectIfDemoMode' => \App\Http\Middleware\RejectIfDemoMode::class,
|
'rejectIfDemoMode' => \App\Http\Middleware\RejectIfDemoMode::class,
|
||||||
'rejectIfReverseProxy' => \App\Http\Middleware\RejectIfReverseProxy::class,
|
'rejectIfReverseProxy' => \App\Http\Middleware\RejectIfReverseProxy::class,
|
||||||
'RejectIfSsoOnlyAndNotForAdmin' => \App\Http\Middleware\RejectIfSsoOnlyAndNotForAdmin::class,
|
'RejectIfSsoOnlyAndNotForAdmin' => \App\Http\Middleware\RejectIfSsoOnlyAndNotForAdmin::class,
|
||||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||||
|
'kickOutInactiveUser' => \App\Http\Middleware\KickOutInactiveUser::class,
|
||||||
|
'forceLogout' => \App\Http\Middleware\ForceLogout::class,
|
||||||
// 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
// 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
|
||||||
// 'signed' => \App\Http\Middleware\ValidateSignature::class,
|
// 'signed' => \App\Http\Middleware\ValidateSignature::class,
|
||||||
];
|
];
|
||||||
|
25
app/Http/Middleware/ForceLogout.php
Normal file
25
app/Http/Middleware/ForceLogout.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class ForceLogout
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Http\Request $request
|
||||||
|
* @param string $guards
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next, ...$guards)
|
||||||
|
{
|
||||||
|
if (Auth::user() != null) {
|
||||||
|
Auth::guard('web-guard')->logoutCurrentDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
@ -43,27 +43,30 @@ class LogoutListener extends AbstractAccessListener
|
|||||||
* @var \App\Models\User
|
* @var \App\Models\User
|
||||||
*/
|
*/
|
||||||
$user = $event->user;
|
$user = $event->user;
|
||||||
$ip = config('2fauth.proxy_headers.forIp')
|
|
||||||
? $this->request->header(config('2fauth.proxy_headers.forIp'), $this->request->ip())
|
|
||||||
: $this->request->ip();
|
|
||||||
$userAgent = $this->request->userAgent();
|
|
||||||
$log = $user->authentications()
|
|
||||||
->whereIpAddress($ip)
|
|
||||||
->whereUserAgent($userAgent)
|
|
||||||
->whereGuard($event->guard)
|
|
||||||
->orderByDesc('login_at')
|
|
||||||
->first();
|
|
||||||
|
|
||||||
if (! $log) {
|
if ($user != null) {
|
||||||
$log = new AuthLog([
|
$ip = config('2fauth.proxy_headers.forIp')
|
||||||
'ip_address' => $ip,
|
? $this->request->header(config('2fauth.proxy_headers.forIp'), $this->request->ip())
|
||||||
'user_agent' => $userAgent,
|
: $this->request->ip();
|
||||||
'guard' => $event->guard,
|
$userAgent = $this->request->userAgent();
|
||||||
'login_method' => $this->loginMethod(),
|
$log = $user->authentications()
|
||||||
]);
|
->whereIpAddress($ip)
|
||||||
|
->whereUserAgent($userAgent)
|
||||||
|
->whereGuard($event->guard)
|
||||||
|
->orderByDesc('login_at')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (! $log) {
|
||||||
|
$log = new AuthLog([
|
||||||
|
'ip_address' => $ip,
|
||||||
|
'user_agent' => $userAgent,
|
||||||
|
'guard' => $event->guard,
|
||||||
|
'login_method' => $this->loginMethod(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$log->logout_at = now();
|
||||||
|
$user->authentications()->save($log);
|
||||||
}
|
}
|
||||||
|
|
||||||
$log->logout_at = now();
|
|
||||||
$user->authentications()->save($log);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,9 @@ use Laravel\Passport\Http\Controllers\PersonalAccessTokenController;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Routes that only work for unauthenticated user (return an error otherwise)
|
* Routes that only work for unauthenticated user (return an error otherwise)
|
||||||
|
* 'kickOutInactiveUser',
|
||||||
*/
|
*/
|
||||||
Route::group(['middleware' => ['guest', 'rejectIfDemoMode', 'RejectIfSsoOnlyAndNotForAdmin']], function () {
|
Route::group(['middleware' => ['rejectIfDemoMode', 'RejectIfSsoOnlyAndNotForAdmin', 'forceLogout']], function () {
|
||||||
Route::post('user', [RegisterController::class, 'register'])->name('user.register');
|
Route::post('user', [RegisterController::class, 'register'])->name('user.register');
|
||||||
Route::post('user/password/lost', [ForgotPasswordController::class, 'sendResetLinkEmail'])->name('user.password.lost');
|
Route::post('user/password/lost', [ForgotPasswordController::class, 'sendResetLinkEmail'])->name('user.password.lost');
|
||||||
Route::post('user/password/reset', [ResetPasswordController::class, 'reset'])->name('password.reset');
|
Route::post('user/password/reset', [ResetPasswordController::class, 'reset'])->name('password.reset');
|
||||||
@ -46,15 +47,15 @@ Route::group(['middleware' => ['guest', 'rejectIfDemoMode', 'RejectIfSsoOnlyAndN
|
|||||||
/**
|
/**
|
||||||
* Routes that can be requested max 10 times per minute by the same IP
|
* Routes that can be requested max 10 times per minute by the same IP
|
||||||
*/
|
*/
|
||||||
Route::group(['middleware' => ['rejectIfDemoMode', 'throttle:10,1', 'RejectIfSsoOnlyAndNotForAdmin']], function () {
|
Route::group(['middleware' => ['rejectIfDemoMode', 'throttle:10,1', 'RejectIfSsoOnlyAndNotForAdmin', 'forceLogout']], function () {
|
||||||
Route::post('webauthn/recover', [WebAuthnRecoveryController::class, 'recover'])->name('webauthn.recover');
|
Route::post('webauthn/recover', [WebAuthnRecoveryController::class, 'recover'])->name('webauthn.recover');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Routes that only work for unauthenticated user (return an error otherwise)
|
* Routes that only work for unauthenticated user (return an error otherwise)
|
||||||
* that can be requested max 10 times per minute by the same IP
|
* that can be requested max 10 times per minute by the same IP 'kickOutInactiveUser',
|
||||||
*/
|
*/
|
||||||
Route::group(['middleware' => ['guest', 'throttle:10,1']], function () {
|
Route::group(['middleware' => ['forceLogout', 'throttle:10,1']], function () {
|
||||||
Route::post('user/login', [LoginController::class, 'login'])->name('user.login')->middleware('RejectIfSsoOnlyAndNotForAdmin');
|
Route::post('user/login', [LoginController::class, 'login'])->name('user.login')->middleware('RejectIfSsoOnlyAndNotForAdmin');
|
||||||
Route::post('webauthn/login', [WebAuthnLoginController::class, 'login'])->name('webauthn.login')->middleware('RejectIfSsoOnlyAndNotForAdmin');
|
Route::post('webauthn/login', [WebAuthnLoginController::class, 'login'])->name('webauthn.login')->middleware('RejectIfSsoOnlyAndNotForAdmin');
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ class ForgotPasswordControllerTest extends FeatureTestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function test_submit_email_password_request_when_authenticated_returns_bad_request()
|
public function test_submit_email_password_request_when_authenticated_returns_ok()
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
|
* @var \App\Models\User|\Illuminate\Contracts\Auth\Authenticatable
|
||||||
@ -106,7 +106,7 @@ class ForgotPasswordControllerTest extends FeatureTestCase
|
|||||||
->json('POST', '/user/password/lost', [
|
->json('POST', '/user/password/lost', [
|
||||||
'email' => $user->email,
|
'email' => $user->email,
|
||||||
])
|
])
|
||||||
->assertStatus(400)
|
->assertStatus(200)
|
||||||
->assertJsonStructure([
|
->assertJsonStructure([
|
||||||
'message',
|
'message',
|
||||||
]);
|
]);
|
||||||
|
@ -250,10 +250,7 @@ class LoginTest extends FeatureTestCase
|
|||||||
'email' => $this->user->email,
|
'email' => $this->user->email,
|
||||||
'password' => self::PASSWORD,
|
'password' => self::PASSWORD,
|
||||||
])
|
])
|
||||||
->assertStatus(400)
|
->assertStatus(200);
|
||||||
->assertJsonStructure([
|
|
||||||
'message',
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
@ -275,10 +275,7 @@ class WebAuthnLoginControllerTest extends FeatureTestCase
|
|||||||
->assertOk();
|
->assertOk();
|
||||||
|
|
||||||
$this->json('POST', '/webauthn/login', self::ASSERTION_RESPONSE)
|
$this->json('POST', '/webauthn/login', self::ASSERTION_RESPONSE)
|
||||||
->assertStatus(400)
|
->assertStatus(200);;
|
||||||
->assertJsonStructure([
|
|
||||||
'message',
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user