diff --git a/ProcessMaker/Http/Kernel.php b/ProcessMaker/Http/Kernel.php index e3f9e8a0f5..86254692f8 100644 --- a/ProcessMaker/Http/Kernel.php +++ b/ProcessMaker/Http/Kernel.php @@ -42,6 +42,7 @@ class Kernel extends HttpKernel \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, Middleware\SessionStarted::class, Middleware\AuthenticateSession::class, + Middleware\EnsureAccountAllowsAccess::class, Middleware\SessionControlKill::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, //\ProcessMaker\Http\Middleware\VerifyCsrfToken::class, diff --git a/ProcessMaker/Http/Middleware/EnsureAccountAllowsAccess.php b/ProcessMaker/Http/Middleware/EnsureAccountAllowsAccess.php new file mode 100644 index 0000000000..5cedec09a4 --- /dev/null +++ b/ProcessMaker/Http/Middleware/EnsureAccountAllowsAccess.php @@ -0,0 +1,76 @@ +check()) { + continue; + } + + /** @var User $user */ + $user = Auth::guard($guard)->user(); + if (!$user instanceof User || !in_array($user->status, self::DENIED_STATUSES, true)) { + continue; + } + + return self::denyAccess($request, $guard, $user); + } + + return null; + } + + public function handle(Request $request, Closure $next): Response + { + $blocked = self::blockingResponseForRequest($request); + if ($blocked !== null) { + return $blocked; + } + + return $next($request); + } + + public static function denyAccess(Request $request, string $guard, User $user): Response + { + Auth::guard($guard)->logout(); + + if ($request->hasSession()) { + $request->session()->invalidate(); + $request->session()->regenerateToken(); + } + + if ($guard === 'api' || $request->expectsJson()) { + $message = $user->status === 'BLOCKED' + ? __('Account locked after too many failed attempts. Contact administrator.') + : __('Unauthorized'); + + return response()->json(['message' => $message], 401); + } + + return redirect() + ->guest(route('login')) + ->withErrors([ + 'username' => $user->status === 'BLOCKED' + ? __('Account locked after too many failed attempts. Contact administrator.') + : __('These credentials do not match our records.'), + ]); + } +} diff --git a/ProcessMaker/Http/Middleware/ProcessMakerAuthenticate.php b/ProcessMaker/Http/Middleware/ProcessMakerAuthenticate.php index 43e882090b..b64c13812e 100644 --- a/ProcessMaker/Http/Middleware/ProcessMakerAuthenticate.php +++ b/ProcessMaker/Http/Middleware/ProcessMakerAuthenticate.php @@ -2,11 +2,29 @@ namespace ProcessMaker\Http\Middleware; +use Closure; use Illuminate\Auth\Middleware\Authenticate; use Illuminate\Support\Str; class ProcessMakerAuthenticate extends Authenticate { + /** + * {@inheritdoc} + * + * After a successful authenticate(), reject BLOCKED/INACTIVE users so every auth:api route + * (core and packages) is covered without listing middleware per route file. + */ + public function handle($request, Closure $next, ...$guards) + { + $this->authenticate($request, $guards); + + if ($blocked = EnsureAccountAllowsAccess::blockingResponseForRequest($request)) { + return $blocked; + } + + return $next($request); + } + protected function authenticate($request, array $guards) { $this->addAcceptJsonHeaderIfApiCall($request, $guards);