Files
ADconsle/app/Http/Controllers/Auth/LoginController.php
T
kzbkowskiandClaude Sonnet 5 1126d96271
CI / PHP 8.2 (push) Failing after 2m46s
CI / PHP 8.3 (push) Failing after 59s
CI / PHP 8.4 (push) Failing after 1m7s
ADconsole v1.0.0
First public release.

- docs: document the audit log, user offboarding, CSV export and the
  "require a reason for destructive actions" setting across README, docs/
  and CLAUDE/AGENTS.md; note retention for panel_audit
- docs: fill the publishing placeholders (repo URL, security contact,
  issue-template links) and add a semantic-versioning policy
- move agent/contributor context into CLAUDE/ (AGENTS.md + a README);
  root CLAUDE.md is now a thin @-import pointer
- add a favicon (shield-lock, matching the login screen) to the login
  page and the app layout
- CHANGELOG: promote [Unreleased] to [1.0.0]; keep the earlier internal
  build as [0.1.0]

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UfuvfwexztdS7LDpGuKsuK
2026-09-08 23:14:39 +02:00

115 lines
3.3 KiB
PHP

<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Illuminate\View\View;
use LdapRecord\LdapRecordException;
/**
* Logowanie do panelu kontem Active Directory.
*
* Guard 'ldap' (LdapRecord "plain bind") sprawdza login + hasło bindem do DC,
* a dostęp do panelu wymusza reguła MemberOfLoginGroup (członkostwo w grupie
* z AD_LOGIN_GROUP). Nie prowadzimy lokalnej tabeli users - po zalogowaniu
* profil admina ląduje w sesji pod kluczem 'ad_admin'.
*/
class LoginController extends Controller
{
/**
* Maksymalna liczba nieudanych prób logowania (login + IP) zanim
* zadziała throttling.
*/
private const MAX_ATTEMPTS = 5;
public function show(): View
{
return view('auth.login');
}
public function login(Request $request): RedirectResponse
{
$credentials = $request->validate([
'login' => ['required', 'string', 'max:255'],
'password' => ['required', 'string'],
], attributes: [
'login' => __('auth.attributes.login'),
'password' => __('auth.attributes.password'),
]);
$this->ensureIsNotRateLimited($request);
try {
$authenticated = Auth::guard('ldap')->attempt([
'samaccountname' => $credentials['login'],
'password' => $credentials['password'],
]);
} catch (LdapRecordException $e) {
report($e);
throw ValidationException::withMessages([
'login' => __('auth.failed_dc'),
]);
}
if (! $authenticated) {
RateLimiter::hit($this->throttleKey($request));
throw ValidationException::withMessages([
'login' => __('auth.failed_credentials'),
]);
}
RateLimiter::clear($this->throttleKey($request));
$request->session()->regenerate();
$request->session()->put(
'ad_admin',
Auth::guard('ldap')->user()->toPanelProfile()
);
return redirect()->route('dashboard.index');
}
public function logout(Request $request): RedirectResponse
{
Auth::guard('ldap')->logout();
$request->session()->forget('ad_admin');
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('login')->with('status', __('auth.logged_out'));
}
/**
* @throws ValidationException
*/
protected function ensureIsNotRateLimited(Request $request): void
{
if (! RateLimiter::tooManyAttempts($this->throttleKey($request), self::MAX_ATTEMPTS)) {
return;
}
$seconds = RateLimiter::availableIn($this->throttleKey($request));
throw ValidationException::withMessages([
'login' => __('auth.throttled', ['seconds' => $seconds]),
]);
}
protected function throttleKey(Request $request): string
{
return Str::transliterate(
Str::lower((string) $request->input('login')).'|'.$request->ip()
);
}
}