Skip to content

Commit

Permalink
Implementation of Admin Two Factor Authentication Guard
Browse files Browse the repository at this point in the history
  • Loading branch information
hiamir committed Nov 2, 2022
1 parent 1624713 commit d3c7d35
Show file tree
Hide file tree
Showing 10 changed files with 234 additions and 41 deletions.
166 changes: 166 additions & 0 deletions app/Actions/Fortify/AdminRedirectIfTwoFactorAuthenticatable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<?php

namespace App\Actions\Fortify;

use Illuminate\Auth\Events\Failed;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Illuminate\Validation\ValidationException;
use Laravel\Fortify\Events\TwoFactorAuthenticationChallenged;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\LoginRateLimiter;
use Laravel\Fortify\TwoFactorAuthenticatable;

class AdminRedirectIfTwoFactorAuthenticatable
{
/**
* The guard implementation.
*
* @var \Illuminate\Contracts\Auth\StatefulGuard
*/
protected $guard,$model;

/**
* The login rate limiter instance.
*
* @var \Laravel\Fortify\LoginRateLimiter
*/
protected $limiter;

/**
* Create a new controller instance.
*
* @param \Illuminate\Contracts\Auth\StatefulGuard $guard
* @param \Laravel\Fortify\LoginRateLimiter $limiter
* @return void
*/
public function __construct(StatefulGuard $guard, LoginRateLimiter $limiter)
{
$this->guard = $guard;
$this->limiter = $limiter;
$this->model = $this->guard->getProvider()->getModel();
}

/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @param callable $next
* @return mixed
*/
public function handle($request, $next)
{
$user = $this->validateCredentials($request);
($this->model==='App\Models\Admin') ? Session::put('active_two_factor','admin') : Session::put('active_two_factor','web');
if (Fortify::confirmsTwoFactorAuthentication()) {
if (optional($user)->two_factor_secret &&
!is_null(optional($user)->two_factor_confirmed_at) &&
in_array(TwoFactorAuthenticatable::class, class_uses_recursive($user))) {
return $this->twoFactorChallengeResponse($request, $user);
} else {
return $next($request);
}
}

if (optional($user)->two_factor_secret &&
in_array(TwoFactorAuthenticatable::class, class_uses_recursive($user))) {
return $this->twoFactorChallengeResponse($request, $user);
}

return $next($request);
}

/**
* Attempt to validate the incoming credentials.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
protected function validateCredentials($request)
{
if (Fortify::$authenticateUsingCallback) {
return tap(call_user_func(Fortify::$authenticateUsingCallback, $request), function ($user) use ($request) {
if (!$user) {
$this->fireFailedEvent($request);

$this->throwFailedAuthenticationException($request);
}
});
}

$model = $this->guard->getProvider()->getModel();

return tap($model::where(Fortify::username(), $request->{Fortify::username()})->first(), function ($user) use ($request) {
if (!$user || !$this->guard->getProvider()->validateCredentials($user, ['password' => $request->password])) {
$this->fireFailedEvent($request, $user);

$this->throwFailedAuthenticationException($request);
}
});
}

/**
* Throw a failed authentication validation exception.
*
* @param \Illuminate\Http\Request $request
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function throwFailedAuthenticationException($request)
{
$this->limiter->increment($request);

throw ValidationException::withMessages([
Fortify::username() => [trans('auth.failed')],
]);
}

/**
* Fire the failed authentication attempt event with the given arguments.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Contracts\Auth\Authenticatable|null $user
* @return void
*/
protected function fireFailedEvent($request, $user = null)
{
event(new Failed(config('fortify.guard'), $user, [
Fortify::username() => $request->{Fortify::username()},
'password' => $request->password,
]));
}

/**
* Get the two factor authentication enabled response.
*
* @param \Illuminate\Http\Request $request
* @param mixed $user
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function twoFactorChallengeResponse($request, $user)
{
$request->session()->put([
'login.id' => $user->getKey(),
'login.remember' => $request->filled('remember'),
]);

TwoFactorAuthenticationChallenged::dispatch($user);
$table = $user->getTable();
Session::put('table', $table);

if ($user->getTable() == 'admins') {

return $request->wantsJson()
? response()->json(['admin.two_factor' => true])
: redirect()->route('admin.two-factor.login');
} else {

return $request->wantsJson()
? response()->json(['two_factor' => true])
: redirect()->route('two-factor.login');
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,13 @@ public function store(TwoFactorLoginRequest $request)

public function adminTwoFactorLogout(Request $request)
{
$session=Session::get('active_two_factor');
Auth::guard('admin')->logout();

$request->session()->invalidate();

$request->session()->regenerateToken();
return (Session::get('active_two_factor') ? redirect()->route('admin.login') : redirect()->route('login'));

return (($session === 'admin') ? redirect()->route('admin.login') : redirect()->route('login'));
}
}
9 changes: 3 additions & 6 deletions app/Actions/Fortify/RedirectIfTwoFactorAuthenticatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class RedirectIfTwoFactorAuthenticatable
*
* @var \Illuminate\Contracts\Auth\StatefulGuard
*/
protected $guard;
protected $guard,$model;

/**
* The login rate limiter instance.
Expand All @@ -37,11 +37,9 @@ class RedirectIfTwoFactorAuthenticatable
*/
public function __construct(StatefulGuard $guard, LoginRateLimiter $limiter)
{

$this->guard = $guard;
$this->limiter = $limiter;
$model = $this->guard->getProvider()->getModel();

$this->model = $this->guard->getProvider()->getModel();
}

/**
Expand All @@ -53,9 +51,8 @@ public function __construct(StatefulGuard $guard, LoginRateLimiter $limiter)
*/
public function handle($request, $next)
{

$user = $this->validateCredentials($request);
Session::put('active_two_factor','admin');
($this->model==='App\Models\Admin') ? Session::put('active_two_factor','admin') : Session::put('active_two_factor','web');
if (Fortify::confirmsTwoFactorAuthentication()) {
if (optional($user)->two_factor_secret &&
!is_null(optional($user)->two_factor_confirmed_at) &&
Expand Down
9 changes: 6 additions & 3 deletions app/Http/Controllers/AdminController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Http\Controllers;

use App\Actions\Fortify\AdminRedirectIfTwoFactorAuthenticatable;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
Expand Down Expand Up @@ -39,9 +40,11 @@ public function __construct(StatefulGuard $guard)
$this->guard = $guard;



}

public function loginForm(){

return view('auth.login',['guard'=>'admin']);
}

Expand All @@ -64,7 +67,8 @@ public function create(Request $request): LoginViewResponse
*/
public function store(LoginRequest $request)
{

Session::forget('guard');
Session::put('guard','admin');
return $this->loginPipeline($request)->then(function ($request) {
return app(AdminLoginResponse::class);
});
Expand Down Expand Up @@ -94,7 +98,7 @@ protected function loginPipeline(LoginRequest $request)
return (new Pipeline(app()))->send($request)->through(array_filter([
config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class,

Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null,
Features::enabled(Features::twoFactorAuthentication()) ? AdminRedirectIfTwoFactorAuthenticatable::class : null,
AttemptToAuthenticate::class,
PrepareAuthenticatedSession::class,

Expand All @@ -109,7 +113,6 @@ protected function loginPipeline(LoginRequest $request)
*/
public function destroy(Request $request): AdminLogoutResponse
{

Auth::guard('admin')->logout();

$request->session()->invalidate();
Expand Down
30 changes: 13 additions & 17 deletions app/Http/Controllers/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Routing\Pipeline;
use App\Actions\Fortify\AttemptToAuthenticate;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Laravel\Fortify\Actions\AttemptToAuthenticate;
use Laravel\Fortify\Actions\EnsureLoginIsNotThrottled;
use Laravel\Fortify\Actions\PrepareAuthenticatedSession;
use App\Actions\Fortify\RedirectIfTwoFactorAuthenticatable;
use App\Http\Responses\AdminLoginResponse;
use Laravel\Fortify\Contracts\LoginResponse;
use Laravel\Fortify\Contracts\LoginViewResponse;
use App\Http\Responses\LogoutResponse;
use Laravel\Fortify\Contracts\LogoutResponse;
use Laravel\Fortify\Features;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\Http\Requests\LoginRequest;
Expand All @@ -31,49 +30,46 @@ class UserController extends Controller
/**
* Create a new controller instance.
*
* @param \Illuminate\Contracts\Auth\StatefulGuard $guard
* @param \Illuminate\Contracts\Auth\StatefulGuard $guard
* @return void
*/
public function __construct(StatefulGuard $guard)
{
$this->guard = $guard;
$model = ($guard->getProvider()->getModel());
if ($model === 'App\Models\User') Session::put('guard', 'web');
}

public function loginForm(){
return view('auth.login',['guard'=>'admin']);
}

/**
* Show the login view.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Request $request
* @return \Laravel\Fortify\Contracts\LoginViewResponse
*/
public function create(Request $request): LoginViewResponse
{

return app(LoginViewResponse::class);
}

/**
* Attempt to authenticate a new session.
*
* @param \Laravel\Fortify\Http\Requests\LoginRequest $request
* @param \Laravel\Fortify\Http\Requests\LoginRequest $request
* @return mixed
*/
public function store(LoginRequest $request)
{

Session::forget('guard');
Session::put('guard','web');
return $this->loginPipeline($request)->then(function ($request) {
return app(AdminLoginResponse::class);
return app(LoginResponse::class);
});
}

/**
* Get the authentication pipeline instance.
*
* @param \Laravel\Fortify\Http\Requests\LoginRequest $request
* @param \Laravel\Fortify\Http\Requests\LoginRequest $request
* @return \Illuminate\Pipeline\Pipeline
*/
protected function loginPipeline(LoginRequest $request)
Expand All @@ -85,7 +81,7 @@ protected function loginPipeline(LoginRequest $request)
}

if (is_array(config('fortify.pipelines.login'))) {
return (new \Illuminate\Pipeline\Pipeline(app()))->send($request)->through(array_filter(
return (new Pipeline(app()))->send($request)->through(array_filter(
config('fortify.pipelines.login')
));
}
Expand All @@ -101,7 +97,7 @@ protected function loginPipeline(LoginRequest $request)
/**
* Destroy an authenticated session.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Request $request
* @return \Laravel\Fortify\Contracts\LogoutResponse
*/
public function destroy(Request $request): LogoutResponse
Expand Down
13 changes: 11 additions & 2 deletions app/Http/Middleware/CheckGuard.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Session;

class CheckGuard
Expand All @@ -17,9 +19,16 @@ class CheckGuard
*/
public function handle(Request $request, Closure $next)
{

if (Session::get('active_two_factor') === 'admin') {
return redirect()->route('admin.two-factor.login');
if (Route::currentRouteName() !== 'admin.two-factor.login') {
return redirect()->route('admin.two-factor.login');
}
} else if (Session::get('active_two_factor') === 'web') {
if (Route::currentRouteName() !== 'two-factor.login') {
return redirect()->route('two-factor.login');
}
} else if (Auth::guard('admin')->check() || Auth::guard('web')->check()) {
return redirect()->back();
}
return $next($request);
}
Expand Down
Loading

0 comments on commit d3c7d35

Please sign in to comment.