Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FOUR-11419 Block the user when has X incorrect attempts #5765

Merged
merged 2 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions ProcessMaker/Http/Controllers/Admin/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public function edit(User $user)
$status = [
['value' => 'ACTIVE', 'text' => __('Active')],
['value' => 'INACTIVE', 'text' => __('Inactive')],
['value' => 'BLOCKED', 'text' => __('Blocked')],
];

$timezones = array_reduce(
Expand Down
61 changes: 60 additions & 1 deletion ProcessMaker/Http/Controllers/Auth/LoginController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Validation\ValidationException;
use ProcessMaker\Events\Logout;
use ProcessMaker\Http\Controllers\Controller;
use ProcessMaker\Managers\LoginManager;
Expand Down Expand Up @@ -177,6 +178,8 @@ public function loginWithIntendedCheck(Request $request)
$user = User::where('username', $request->input('username'))->first();
if (!$user || $user->status === 'INACTIVE') {
$this->sendFailedLoginResponse($request);
} elseif ($user->status === 'BLOCKED') {
$this->throwLockedLoginResponse();
}

$addons = $this->getPluginAddons('command', []);
Expand All @@ -194,7 +197,7 @@ public function loginWithIntendedCheck(Request $request)
}
}

return $this->login($request);
return $this->login($request, $user);
}

/**
Expand Down Expand Up @@ -237,4 +240,60 @@ public function loggedOut(Request $request)

return $response;
}

/**
* Handle a login request to the application.
* Overrides the original login action.
*
* @param \Illuminate\Http\Request $request
* @param \ProcessMaker\Models\User $user
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*
* @throws \Illuminate\Validation\ValidationException
*/
public function login(Request $request, User $user)
{
$this->validateLogin($request);

// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {

// Block the user
$user->status = 'BLOCKED';
$user->save();

// Throw locked error message
$this->throwLockedLoginResponse();
}

if ($this->attemptLogin($request)) {
if ($request->hasSession()) {
$request->session()->put('auth.password_confirmed_at', time());
}

return $this->sendLoginResponse($request);
}

// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);

return $this->sendFailedLoginResponse($request);
}

/**
* Throws locked error message
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function throwLockedLoginResponse()
{
throw ValidationException::withMessages([
$this->username() => [_('Account locked after too many failed attempts. Contact administrator.')],
]);
}
}
4 changes: 2 additions & 2 deletions ProcessMaker/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class User extends Authenticatable implements HasMedia
* @OA\Property(property="expires_at", type="string"),
* @OA\Property(property="loggedin_at", type="string"),
* @OA\Property(property="remember_token", type="string"),
* @OA\Property(property="status", type="string", enum={"ACTIVE", "INACTIVE", "SCHEDULED", "OUT_OF_OFFICE"}),
* @OA\Property(property="status",type="string",enum={"ACTIVE","INACTIVE","SCHEDULED","OUT_OF_OFFICE","BLOCKED"}),
* @OA\Property(property="fullname", type="string"),
* @OA\Property(property="avatar", type="string"),
* @OA\Property(property="media", type="array", @OA\Items(ref="#/components/schemas/media")),
Expand Down Expand Up @@ -170,7 +170,7 @@ public static function rules(self $existing = null)
'phone' /*******/ => ['nullable', 'regex:/^[+\.0-9x\)\(\-\s\/]*$/'],
'fax' /*********/ => ['nullable', 'regex:/^[+\.0-9x\)\(\-\s\/]*$/'],
'cell' /********/ => ['nullable', 'regex:/^[+\.0-9x\)\(\-\s\/]*$/'],
'status' /******/ => ['required', 'in:ACTIVE,INACTIVE,OUT_OF_OFFICE,SCHEDULED'],
'status' /******/ => ['required', 'in:ACTIVE,INACTIVE,OUT_OF_OFFICE,SCHEDULED,BLOCKED'],
'password' /****/ => static::passwordRules($existing),
];
}
Expand Down
5 changes: 3 additions & 2 deletions resources/js/admin/users/components/UsersListing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<avatar-image size="25" :input-data="props.rowData" hide-name="true"></avatar-image>
</template>
<template slot="actions" slot-scope="props">
<ellipsis-menu
<ellipsis-menu
@navigate="onNavigate"
:actions="actions"
:permission="permission"
Expand Down Expand Up @@ -151,7 +151,8 @@ export default {
active: "text-success",
inactive: "text-danger",
draft: "text-warning",
archived: "text-info"
archived: "text-info",
blocked: "text-danger"
};
return (
'<i class="fas fa-circle ' +
Expand Down
4 changes: 3 additions & 1 deletion resources/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1819,5 +1819,7 @@
"Password expiration": "Password expiration",
"Password will expire in the days configured here.": "Password will expire in the days configured here.",
"Login failed": "Login failed",
"Number of consecutive unsuccessful login attempts before block the login action momentarily.": "Number of consecutive unsuccessful login attempts before block the login action momentarily."
"Number of consecutive unsuccessful login attempts before block the login action momentarily.": "Number of consecutive unsuccessful login attempts before block the login action momentarily.",
"Blocked": "Blocked",
"Account locked after too many failed attempts. Contact administrator.": "Account locked after too many failed attempts. Contact administrator."
}
2 changes: 2 additions & 0 deletions resources/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"Accepted": "Accepted",
"Access token generated successfully": "Access token generated successfully",
"Accessed_at": "Accessed at",
"Account locked after too many failed attempts. Contact administrator.": "Account locked after too many failed attempts. Contact administrator.",
"Account Timeout": "Account Timeout",
"action": "action",
"Actions": "Actions",
Expand Down Expand Up @@ -191,6 +192,7 @@
"Before Date": "Before Date",
"Before or Equal to Date": "Before or Equal to Date",
"Between Min & Max": "Between Min & Max",
"Blocked": "Blocked",
"Body of the text annotation": "Body of the text annotation",
"Body": "Body",
"Bold": "Bold",
Expand Down
4 changes: 3 additions & 1 deletion resources/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1820,5 +1820,7 @@
"Password expiration": "Password expiration",
"Password will expire in the days configured here.": "Password will expire in the days configured here.",
"Login failed": "Login failed",
"Number of consecutive unsuccessful login attempts before block the login action momentarily.": "Number of consecutive unsuccessful login attempts before block the login action momentarily."
"Number of consecutive unsuccessful login attempts before block the login action momentarily.": "Number of consecutive unsuccessful login attempts before block the login action momentarily.",
"Blocked": "Blocked",
"Account locked after too many failed attempts. Contact administrator.": "Account locked after too many failed attempts. Contact administrator."
}
4 changes: 3 additions & 1 deletion resources/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1819,5 +1819,7 @@
"Password expiration": "Password expiration",
"Password will expire in the days configured here.": "Password will expire in the days configured here.",
"Login failed": "Login failed",
"Number of consecutive unsuccessful login attempts before block the login action momentarily.": "Number of consecutive unsuccessful login attempts before block the login action momentarily."
"Number of consecutive unsuccessful login attempts before block the login action momentarily.": "Number of consecutive unsuccessful login attempts before block the login action momentarily.",
"Blocked": "Blocked",
"Account locked after too many failed attempts. Contact administrator.": "Account locked after too many failed attempts. Contact administrator."
}
3 changes: 2 additions & 1 deletion storage/api-docs/api-docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -6590,7 +6590,8 @@
"ACTIVE",
"INACTIVE",
"SCHEDULED",
"OUT_OF_OFFICE"
"OUT_OF_OFFICE",
"BLOCKED"
]
},
"fullname": {
Expand Down