Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace ProcessMaker\Http\Controllers\Api;

use Carbon\Carbon;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
Expand Down Expand Up @@ -35,6 +36,10 @@ public function update(Request $request)

$user->setAttribute('password', Hash::make($request->json('password')));
$user->setAttribute('force_change_password', 0);
$user->setAttribute('password_changed_at', Carbon::now()->toDateTimeString());

// Remove login error message related to password expired if exists
session()->forget('login-error');

try {
$user = $user->save();
Expand Down
9 changes: 9 additions & 0 deletions ProcessMaker/Http/Controllers/Api/UserController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace ProcessMaker\Http\Controllers\Api;

use Carbon\Carbon;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
Expand Down Expand Up @@ -167,6 +168,10 @@ public function store(Request $request)

if (isset($fields['password'])) {
$fields['password'] = Hash::make($fields['password']);
$fields['password_changed_at'] = Carbon::now()->toDateTimeString();

// Remove login error message related to password expired if exists
session()->forget('login-error');
}

$user->fill($fields);
Expand Down Expand Up @@ -301,6 +306,10 @@ public function update(User $user, Request $request)
$fields = $request->json()->all();
if (isset($fields['password'])) {
$fields['password'] = Hash::make($fields['password']);
$fields['password_changed_at'] = Carbon::now()->toDateTimeString();

// Remove login error message related to password expired if exists
session()->forget('login-error');
}
$original = $user->getOriginal();
$user->fill($fields);
Expand Down
19 changes: 19 additions & 0 deletions ProcessMaker/Http/Middleware/VerifyChangePasswordNeeded.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace ProcessMaker\Http\Middleware;

use Carbon\Carbon;
use Closure;
use Illuminate\Support\Facades\Auth;

Expand All @@ -20,11 +21,29 @@ public function handle($request, Closure $next)
return redirect()->route('password.change');
}

if ($this->checkPasswordExpiration()) {
// Set the error message
session()->put('login-error', _('Your password has expired.'));

// Redirect to change password screen
return redirect()->route('password.change');
}

return $next($request);
}

public function checkForForceChangePassword()
{
return Auth::user() && Auth::user()->force_change_password;
}

public function checkPasswordExpiration()
{
$validationRequired = config('password-policies.expiration_days') &&
Auth::user() && Auth::user()->password_changed_at;

return $validationRequired &&
(Carbon::now()->diffInDays(Auth::user()->password_changed_at) >=
config('password-policies.expiration_days'));
}
}
1 change: 1 addition & 0 deletions ProcessMaker/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class User extends Authenticatable implements HasMedia
'manager_id',
'schedule',
'force_change_password',
'password_changed_at',
];

protected $appends = [
Expand Down
2 changes: 1 addition & 1 deletion config/password-policies.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
'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
'expiration_days' => env('PASSWORD_POLICY_EXPIRATION_DAYS', null),
'login_attempts' => env('PASSWORD_POLICY_LOGIN_ATTEMPTS', 5),
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->timestamp('password_changed_at')->nullable();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('password_changed_at');
});
}
};
3 changes: 2 additions & 1 deletion resources/lang/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1801,5 +1801,6 @@
"This environment already contains an older version of the {{ item }} named '{{ name }}.'": "Diese Umgebung enthält bereits eine ältere Version des {{ item }} namens '{{ name }}'.",
"This environment already contains the same version of the {{ item }} named '{{ name }}.'": "Diese Umgebung enthält bereits die gleiche Version des {{ item }} namens '{{ name }}'.",
"Visit our Gallery for more Templates": "Besuchen Sie unsere Galerie für mehr Vorlagen",
"Start a new process from a blank canvas, a text description, or a preset template.": "Starten Sie einen neuen Prozess von einer leeren Leinwand, einer Textbeschreibung oder einer voreingestellten Vorlage."
"Start a new process from a blank canvas, a text description, or a preset template.": "Starten Sie einen neuen Prozess von einer leeren Leinwand, einer Textbeschreibung oder einer voreingestellten Vorlage.",
"Your password has expired.": "Your password has expired."
}
1 change: 1 addition & 0 deletions resources/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,7 @@
"Your account has been timed out for security.": "Your account has been timed out for security.",
"Your password has been reset!": "Your password has been reset!",
"Your password has been updated.": "Your password has been updated.",
"Your password has expired.": "Your password has expired.",
"Your PMQL contains invalid syntax.": "Your PMQL contains invalid syntax.",
"Your PMQL search could not be completed.": "Your PMQL search could not be completed.",
"Your profile was saved.": "Your profile was saved.",
Expand Down
3 changes: 2 additions & 1 deletion resources/lang/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1802,5 +1802,6 @@
"This environment already contains an older version of the {{ item }} named '{{ name }}.'": "Este entorno ya contiene una versión más antigua del {{ item }} llamado '{{ name }}'.",
"This environment already contains the same version of the {{ item }} named '{{ name }}.'": "Este entorno ya contiene la misma versión del {{ item }} llamado '{{ name }}'.",
"Visit our Gallery for more Templates": "Visita nuestra Galería para más Plantillas",
"Start a new process from a blank canvas, a text description, or a preset template.": "Inicie un nuevo proceso desde un lienzo en blanco, una descripción de texto o una plantilla preestablecida."
"Start a new process from a blank canvas, a text description, or a preset template.": "Inicie un nuevo proceso desde un lienzo en blanco, una descripción de texto o una plantilla preestablecida.",
"Your password has expired.": "Tu contraseña ha expirado."
}
3 changes: 2 additions & 1 deletion resources/lang/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1801,5 +1801,6 @@
"This environment already contains an older version of the {{ item }} named '{{ name }}.'": "Cet environnement contient déjà une version plus ancienne de {{ item }} nommé '{{ name }}'.",
"This environment already contains the same version of the {{ item }} named '{{ name }}.'": "Cet environnement contient déjà la même version de l'{{ item }} nommé '{{ name }}'.",
"Visit our Gallery for more Templates": "Visitez notre Galerie pour plus de Modèles",
"Start a new process from a blank canvas, a text description, or a preset template.": "Démarrez un nouveau processus à partir d'une toile vierge, d'une description textuelle ou d'un modèle prédéfini."
"Start a new process from a blank canvas, a text description, or a preset template.": "Démarrez un nouveau processus à partir d'une toile vierge, d'une description textuelle ou d'un modèle prédéfini.",
"Your password has expired.": "Your password has expired."
}