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 apiForgotPassword(Request $request): JsonResponse { $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'], 'source' => 'api', ]); } catch (\Throwable) { // Do not reveal whether user exists or email failed. } return response()->json([ 'data' => ['message' => 'Jika akun ditemukan dan memiliki email terdaftar, link reset password telah dikirim.'], 'error' => null, ]); } 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.'); } } }