diff --git a/ProcessMaker/Http/Controllers/Auth/LoginController.php b/ProcessMaker/Http/Controllers/Auth/LoginController.php index d4012a6877..45e8f64f58 100644 --- a/ProcessMaker/Http/Controllers/Auth/LoginController.php +++ b/ProcessMaker/Http/Controllers/Auth/LoginController.php @@ -38,6 +38,8 @@ class LoginController extends Controller */ protected $redirectTo = '/'; + protected $maxAttempts; + /** * Create a new controller instance. * @@ -46,6 +48,7 @@ class LoginController extends Controller public function __construct() { $this->middleware('guest')->except(['logout', 'beforeLogout', 'keepAlive']); + $this->maxAttempts = (int) config('password-policies.login_attempts'); } /** diff --git a/ProcessMaker/Models/User.php b/ProcessMaker/Models/User.php index 8e2cd4e8ef..541e91ba8c 100644 --- a/ProcessMaker/Models/User.php +++ b/ProcessMaker/Models/User.php @@ -8,12 +8,12 @@ use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Validation\Rule; +use Illuminate\Validation\Rules\Password; use Laravel\Passport\HasApiTokens; use ProcessMaker\Models\EmptyModel; use ProcessMaker\Notifications\ResetPassword as ResetPasswordNotification; use ProcessMaker\Query\Traits\PMQL; use ProcessMaker\Rules\StringHasAtLeastOneUpperCaseCharacter; -use ProcessMaker\Rules\StringHasNumberOrSpecialCharacter; use ProcessMaker\Traits\Exportable; use ProcessMaker\Traits\HasAuthorization; use ProcessMaker\Traits\HideSystemResources; @@ -183,13 +183,28 @@ public static function rules(self $existing = null) */ public static function passwordRules(self $existing = null) { - return array_filter([ + // Mandatory policies + $passwordPolicies = [ 'required', $existing ? 'sometimes' : '', - 'min:8', - new StringHasNumberOrSpecialCharacter(), - new StringHasAtLeastOneUpperCaseCharacter(), - ]); + ]; + // Configurable policies + $passwordRules = Password::min(config('password-policies.minimum_length')); + if (config('password-policies.maximum_length')) { + $passwordPolicies[] = 'max:' . config('password-policies.maximum_length'); + } + if (config('password-policies.numbers')) { + $passwordRules->numbers(); + } + if (config('password-policies.uppercase')) { + $passwordPolicies[] = new StringHasAtLeastOneUpperCaseCharacter(); + } + if (config('password-policies.special')) { + $passwordRules->symbols(); + } + $passwordPolicies[] = $passwordRules; + + return $passwordPolicies; } /** diff --git a/config/password-policies.php b/config/password-policies.php new file mode 100644 index 0000000000..1bb8d9cefa --- /dev/null +++ b/config/password-policies.php @@ -0,0 +1,11 @@ + env('PASSWORD_POLICY_MINIMUM_LENGTH', 8), + 'maximum_length' => env('PASSWORD_POLICY_MAXIMUM_LENGTH', null), + 'numbers' => env('PASSWORD_POLICY_NUMBERS', true), + 'uppercase' => env('PASSWORD_POLICY_UPPERCASE', true), + 'special' => env('PASSWORD_POLICY_SPECIAL', true), + //'expiration_days' => env('PASSWORD_POLICY_EXPIRATION_DAYS', 0), // 0 never expires + 'login_attempts' => env('PASSWORD_POLICY_LOGIN_ATTEMPTS', 5), +]; diff --git a/resources/views/admin/users/edit.blade.php b/resources/views/admin/users/edit.blade.php index f00ae382df..c34292b5cb 100644 --- a/resources/views/admin/users/edit.blade.php +++ b/resources/views/admin/users/edit.blade.php @@ -396,12 +396,6 @@ delete this.formData.password; return true } - if (this.formData.password.trim().length > 0 && this.formData.password.trim().length < 8) { - this.errors.password = ['Password must be at least 8 characters'] - this.password = '' - this.submitted = false - return false - } if (this.formData.password !== this.formData.confPassword) { this.errors.password = ['Passwords must match'] this.password = '' diff --git a/resources/views/auth/passwords/change.blade.php b/resources/views/auth/passwords/change.blade.php index 0627e07982..5b5ddca593 100644 --- a/resources/views/auth/passwords/change.blade.php +++ b/resources/views/auth/passwords/change.blade.php @@ -45,7 +45,7 @@ 'v-bind:class' => '{\'form-control\':true, \'is-invalid\':errors.password}']) !!} - @{{ errors.password[0] }} + @{{ error }}