ezsystems/ezmbpaex-ls
Legacy eZ Publish extension (MBPAEx) that adds password expiration and policy enforcement to user accounts, so sites can require periodic password changes and notify affected users. Packaged as ezsystems/ezmbpaex-ls for older eZ Publish installations.
First, reset expectations: this is not a Laravel package. ezsystems/ezmbpaex-ls is the legacy-stack (-ls) build of an eZ Publish 4.x/5.x extension (password expiry / password-change enforcement). It has no service provider, no PSR-4 autoloading, no facades, and no config publishing. Its classes extend eZ Publish kernel types (eZPersistentObject, eZUser, eZINI) that simply do not exist in a Laravel process. Combined with the archive flag, zero dependents, and a NOASSERTION license, treat this repository as a specification to read, not a dependency to install.
Where to look first, in order:
composer.json / ezinfo.php — confirms the target (eZ Publish legacy) and the extension version. If you see no autoload section, stop trying to composer require it.extension/mbpaex/settings/*.ini — conventionally the real "API" of an eZ extension. This is where the policy lives: expiry interval, grace period, whether expiry is enforced at login, which user groups are exempt, notification behaviour. Read this file before any PHP.extension/mbpaex/classes/ — the enforcement logic. Look for the login hook / event listener and the eZUser extension, since that's where "password is stale → block or redirect" is decided.design/ — shows the UX contract: what the user sees, what routes are reachable while in the expired state.First use case in Laravel: reproduce the policy, not the code. Add password_changed_at (nullable timestamp) to users, migrate existing rows from updated_at, then gate access with a middleware and an Artisan command for warning emails. You can have the equivalent behaviour in an afternoon, with tests, instead of a week fighting a dead framework.
Pattern 1 — Treat the INI as a requirements document. Map each setting to a Laravel config key and a test case:
| eZ INI concern | Laravel equivalent |
|---|---|
| Expiry window (days) | config('auth.password_expiry.days') |
| Grace / warning period | password_expiry.warn_days |
| Exempt user groups | password_expiry.exempt_roles |
| Enforce on login | middleware vs. post-login event |
Build a Pest/PHPUnit dataset from those rows so your policy matrix is provably equivalent to the old system before you decommission it.
Pattern 2 — Middleware for enforcement, listener for the clock.
// app/Http/Middleware/EnsurePasswordIsFresh.php
public function handle($request, Closure $next)
{
$user = $request->user();
if ($user && $this->isExpired($user) && ! $request->routeIs('password.*', 'logout')) {
return redirect()->route('password.expired');
}
return $next($request);
}
Keep the timestamp update in a PasswordChanged listener rather than in controllers, so password resets, admin-forced changes, and profile updates all reset the clock identically. Register the middleware in the web group after Authenticate, and allowlist the password-change and logout routes — the classic infinite-redirect bug comes from forgetting the allowlist.
Pattern 3 — Scheduled warnings. The eZ extension's notification path maps to php artisan schedule:work plus a queued job that queries password_changed_at < now()->subDays($warnDays) and sends a mailable. Chunk the query (->chunkById(500)) — this table is the whole user base.
Pattern 4 — Coexistence, if you genuinely must run both. Do not share PHP classes. Give the legacy eZ Publish app its own vhost/container and share state at the database or HTTP layer: either a shared users table with a strict column contract, or a small internal API that Laravel calls to force a password reset. Everything else (sessions, cookies, CSRF) must stay separate.
Pattern 5 — Migration ordering. Backfill password_changed_at before enabling enforcement, and ship the middleware behind a feature flag. Users whose password age is unknown should be treated as "must change at next login", not "expired now", or you will lock out the entire user base on deploy.
NOASSERTION means no security patches and unclear copying rights. The eZ Publish legacy stack is generally GPL-2.0, but the repo doesn't assert it. Read the policy, write your own implementation; do not paste files into a proprietary Laravel codebase without a license review.each(), dynamic properties, unqualified eZ* class references). Another reason porting beats adapting.ExpiryDays and nothing happened"). In Laravel, the analogue is php artisan config:clear; if your expiry window looks wrong in production, that's the first thing to check.password_changed_at in UTC and compare with CarbonImmutable; never compare formatted date strings.AuthenticateSession middleware and Auth::logoutOtherDevices(); the eZ extension likely did not handle this, so don't assume parity is sufficient for security.How can I help you explore Laravel packages today?