Skip to content

Commit 4e1b054

Browse files
committed
Prevent access for BLOCKED/INACTIVE users
Add middleware to block authenticated users whose status is BLOCKED or INACTIVE. Introduces EnsureAccountAllowsAccess middleware (with blockingResponseForRequest and denyAccess helpers) that logs out the user, invalidates the session, and returns a JSON 401 for API requests or redirects to login with appropriate error messages for web requests. Wire the middleware into the HTTP kernel and update ProcessMakerAuthenticate to invoke the same blocking check after successful authentication so auth:api routes (core and packages) are also enforced.
1 parent 25c7763 commit 4e1b054

3 files changed

Lines changed: 95 additions & 0 deletions

File tree

ProcessMaker/Http/Kernel.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class Kernel extends HttpKernel
4242
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
4343
Middleware\SessionStarted::class,
4444
Middleware\AuthenticateSession::class,
45+
Middleware\EnsureAccountAllowsAccess::class,
4546
Middleware\SessionControlKill::class,
4647
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
4748
//\ProcessMaker\Http\Middleware\VerifyCsrfToken::class,
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace ProcessMaker\Http\Middleware;
4+
5+
use Closure;
6+
use Illuminate\Http\Request;
7+
use Illuminate\Support\Facades\Auth;
8+
use ProcessMaker\Models\User;
9+
use Symfony\Component\HttpFoundation\Response;
10+
11+
class EnsureAccountAllowsAccess
12+
{
13+
/**
14+
* Status values that cannot use the application while authenticated (aligned with LoginController).
15+
*/
16+
private const DENIED_STATUSES = ['BLOCKED', 'INACTIVE'];
17+
18+
/**
19+
* If any active guard has a blocked/inactive user, log out and return the appropriate response.
20+
* Used by the web middleware group and by ProcessMakerAuthenticate (covers all auth:api routes, including packages).
21+
*/
22+
public static function blockingResponseForRequest(Request $request): ?Response
23+
{
24+
foreach (['web', 'api'] as $guard) {
25+
if (!Auth::guard($guard)->check()) {
26+
continue;
27+
}
28+
29+
/** @var User $user */
30+
$user = Auth::guard($guard)->user();
31+
if (!$user instanceof User || !in_array($user->status, self::DENIED_STATUSES, true)) {
32+
continue;
33+
}
34+
35+
return self::denyAccess($request, $guard, $user);
36+
}
37+
38+
return null;
39+
}
40+
41+
public function handle(Request $request, Closure $next): Response
42+
{
43+
$blocked = self::blockingResponseForRequest($request);
44+
if ($blocked !== null) {
45+
return $blocked;
46+
}
47+
48+
return $next($request);
49+
}
50+
51+
public static function denyAccess(Request $request, string $guard, User $user): Response
52+
{
53+
Auth::guard($guard)->logout();
54+
55+
if ($request->hasSession()) {
56+
$request->session()->invalidate();
57+
$request->session()->regenerateToken();
58+
}
59+
60+
if ($guard === 'api' || $request->expectsJson()) {
61+
$message = $user->status === 'BLOCKED'
62+
? __('Account locked after too many failed attempts. Contact administrator.')
63+
: __('Unauthorized');
64+
65+
return response()->json(['message' => $message], 401);
66+
}
67+
68+
return redirect()
69+
->guest(route('login'))
70+
->withErrors([
71+
'username' => $user->status === 'BLOCKED'
72+
? __('Account locked after too many failed attempts. Contact administrator.')
73+
: __('These credentials do not match our records.'),
74+
]);
75+
}
76+
}

ProcessMaker/Http/Middleware/ProcessMakerAuthenticate.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,29 @@
22

33
namespace ProcessMaker\Http\Middleware;
44

5+
use Closure;
56
use Illuminate\Auth\Middleware\Authenticate;
67
use Illuminate\Support\Str;
78

89
class ProcessMakerAuthenticate extends Authenticate
910
{
11+
/**
12+
* {@inheritdoc}
13+
*
14+
* After a successful authenticate(), reject BLOCKED/INACTIVE users so every auth:api route
15+
* (core and packages) is covered without listing middleware per route file.
16+
*/
17+
public function handle($request, Closure $next, ...$guards)
18+
{
19+
$this->authenticate($request, $guards);
20+
21+
if ($blocked = EnsureAccountAllowsAccess::blockingResponseForRequest($request)) {
22+
return $blocked;
23+
}
24+
25+
return $next($request);
26+
}
27+
1028
protected function authenticate($request, array $guards)
1129
{
1230
$this->addAcceptJsonHeaderIfApiCall($request, $guards);

0 commit comments

Comments
 (0)