You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
5.0 KiB
152 lines
5.0 KiB
<?php |
|
|
|
namespace App\Http\Controllers; |
|
|
|
use App\Services\AuditLogService; |
|
use App\Services\LdapAuthService; |
|
use App\Services\LdapPasswordResetService; |
|
use Illuminate\Http\RedirectResponse; |
|
use Illuminate\Http\Request; |
|
use Illuminate\View\View; |
|
|
|
class AuthController extends Controller |
|
{ |
|
public function __construct( |
|
private readonly LdapAuthService $ldapAuth, |
|
private readonly LdapPasswordResetService $passwordReset, |
|
private readonly AuditLogService $audit |
|
) { |
|
} |
|
|
|
public function showLogin(Request $request): View|RedirectResponse |
|
{ |
|
if ($request->session()->get('ldap_authenticated')) { |
|
return $request->session()->get('ldap_is_admin') |
|
? redirect()->route('databases.index') |
|
: redirect()->route('profile.show'); |
|
} |
|
|
|
return view('auth.login'); |
|
} |
|
|
|
public function login(Request $request): RedirectResponse |
|
{ |
|
$credentials = $request->validate([ |
|
'username' => ['required', 'string', 'max:100'], |
|
'password' => ['required', 'string', 'max:255'], |
|
]); |
|
|
|
$user = $this->ldapAuth->attempt($credentials['username'], $credentials['password']); |
|
|
|
if ($user === null) { |
|
$this->audit->logPublic('auth.login.failed', $credentials['username'], $request, [ |
|
'username' => $credentials['username'], |
|
]); |
|
|
|
return back() |
|
->withInput($request->only('username')) |
|
->withErrors(['username' => 'Invalid LDAP credentials.']); |
|
} |
|
|
|
$request->session()->regenerate(); |
|
$request->session()->put([ |
|
'ldap_authenticated' => true, |
|
'ldap_is_admin' => $user['is_admin'], |
|
'ldap_username' => $user['username'], |
|
'ldap_display_name' => $user['display_name'], |
|
]); |
|
|
|
$this->audit->logWeb('auth.login', $user['username'], $request, [ |
|
'is_admin' => $user['is_admin'], |
|
]); |
|
$request->attributes->set('audit_logged', true); |
|
|
|
$defaultRoute = $user['is_admin'] ? 'databases.index' : 'profile.show'; |
|
|
|
return redirect()->intended(route($defaultRoute)); |
|
} |
|
|
|
public function logout(Request $request): RedirectResponse |
|
{ |
|
$request->session()->invalidate(); |
|
$request->session()->regenerateToken(); |
|
|
|
return redirect()->route('login'); |
|
} |
|
|
|
public function showForgotPassword(): View |
|
{ |
|
return view('auth.forgot-password'); |
|
} |
|
|
|
public function sendForgotPassword(Request $request): RedirectResponse |
|
{ |
|
$data = $request->validate([ |
|
'username' => ['required', 'string', 'max:100', 'regex:/^[a-zA-Z0-9._-]+$/'], |
|
]); |
|
|
|
try { |
|
$this->passwordReset->sendResetLink($data['username']); |
|
$this->audit->logPublic('auth.password.forgot', $data['username'], $request, [ |
|
'username' => $data['username'], |
|
]); |
|
} catch (\Throwable) { |
|
// Do not reveal whether user exists or mail failed. |
|
} |
|
|
|
return back()->with( |
|
'success', |
|
'If the account exists and has an email registered in LDAP, a password reset link has been sent.' |
|
); |
|
} |
|
|
|
public function showResetPassword(string $token): View|RedirectResponse |
|
{ |
|
$username = $this->passwordReset->validateToken($token); |
|
|
|
if ($username === null) { |
|
return redirect()->route('login')->with('error', 'Reset link is invalid or has expired.'); |
|
} |
|
|
|
return view('auth.reset-password', [ |
|
'token' => $token, |
|
'username' => $username, |
|
]); |
|
} |
|
|
|
public function resetPassword(Request $request, string $token): RedirectResponse |
|
{ |
|
$data = $request->validate([ |
|
'password' => ['required', 'string', 'min:8', 'max:128', 'confirmed'], |
|
'confirm_action' => ['required', 'accepted'], |
|
'confirm_username' => ['required', 'string'], |
|
]); |
|
|
|
$username = $this->passwordReset->validateToken($token); |
|
|
|
if ($username === null) { |
|
return redirect()->route('login')->with('error', 'Reset link is invalid or has expired.'); |
|
} |
|
|
|
if (mb_strtolower($data['confirm_username']) !== mb_strtolower($username)) { |
|
return back()->withInput()->with('error', 'Username confirmation does not match.'); |
|
} |
|
|
|
try { |
|
$this->passwordReset->resetPassword($token, $data['password']); |
|
|
|
$this->audit->logPublic('auth.password.reset', $username, $request, [ |
|
'username' => $username, |
|
]); |
|
|
|
return redirect()->route('login')->with( |
|
'success', |
|
'Password has been reset. You can now sign in with your new password.' |
|
); |
|
} catch (\InvalidArgumentException $e) { |
|
return back()->withInput()->with('error', $e->getMessage()); |
|
} catch (\Throwable) { |
|
return back()->withInput()->with('error', 'Password reset failed. Please try again.'); |
|
} |
|
} |
|
}
|
|
|