Enhance logging during authentication (#163)

This commit is contained in:
Bubka 2023-03-16 13:25:43 +01:00
parent 960d1ca5f9
commit 9913560787
8 changed files with 39 additions and 9 deletions

View File

@ -7,6 +7,7 @@ use App\Api\v1\Resources\UserResource;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
class UserController extends Controller class UserController extends Controller
{ {
@ -76,6 +77,8 @@ class UserController extends Controller
$request->user()['preferences->' . $preferenceName] = $validated['value']; $request->user()['preferences->' . $preferenceName] = $validated['value'];
$request->user()->save(); $request->user()->save();
Log::info(sprintf('User ID #%s changed its preference %s to %s', $request->user()->id, var_export($preferenceName, true), var_export($validated['value'], true)));
return response()->json([ return response()->json([
'key' => $preferenceName, 'key' => $preferenceName,

View File

@ -6,6 +6,7 @@ use App\Models\WebAuthnAuthenticatable;
use Closure; use Closure;
use Illuminate\Auth\Passwords\PasswordBroker; use Illuminate\Auth\Passwords\PasswordBroker;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Support\Facades\Log;
class WebauthnCredentialBroker extends PasswordBroker class WebauthnCredentialBroker extends PasswordBroker
{ {
@ -18,6 +19,9 @@ class WebauthnCredentialBroker extends PasswordBroker
*/ */
public function sendResetLink(array $credentials, Closure $callback = null) : string public function sendResetLink(array $credentials, Closure $callback = null) : string
{ {
/**
* @var \App\Models\User
*/
$user = $this->getUser($credentials); $user = $this->getUser($credentials);
if (! $user instanceof WebAuthnAuthenticatable) { if (! $user instanceof WebAuthnAuthenticatable) {
@ -36,6 +40,8 @@ class WebauthnCredentialBroker extends PasswordBroker
$user->sendWebauthnRecoveryNotification($token); $user->sendWebauthnRecoveryNotification($token);
} }
Log::notice(sprintf('Webauthn recovery email sent to user ID #%s', $user->id));
return static::RESET_LINK_SENT; return static::RESET_LINK_SENT;
} }

View File

@ -37,7 +37,7 @@ class LoginController extends Controller
*/ */
public function login(LoginRequest $request) public function login(LoginRequest $request)
{ {
Log::info('User login requested'); Log::info(sprintf('User login requested by %s from %s', var_export($request['email'], true), $request->ip()));
// If the class is using the ThrottlesLogins trait, we can automatically throttle // If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and // the login attempts for this application. We'll key this by the username and
@ -46,6 +46,12 @@ class LoginController extends Controller
$this->hasTooManyLoginAttempts($request)) { $this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request); $this->fireLockoutEvent($request);
Log::notice(sprintf(
'%s from %s locked-out, too many failed login attempts (using email+password)',
var_export($request['email'], true),
$request->ip()
));
return $this->sendLockoutResponse($request); return $this->sendLockoutResponse($request);
} }
@ -58,7 +64,13 @@ class LoginController extends Controller
// user surpasses their maximum number of attempts they will get locked out. // user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request); $this->incrementLoginAttempts($request);
Log::info('User login failed'); Log::notice(sprintf(
'Failed login for %s from %s - Attemp %d/%d (using email+password)',
var_export($request['email'], true),
$request->ip(),
$this->limiter()->attempts($this->throttleKey($request)),
$this->maxAttempts()
));
return $this->sendFailedLoginResponse($request); return $this->sendFailedLoginResponse($request);
} }
@ -154,6 +166,6 @@ class LoginController extends Controller
$user->last_seen_at = Carbon::now()->format('Y-m-d H:i:s'); $user->last_seen_at = Carbon::now()->format('Y-m-d H:i:s');
$user->save(); $user->save();
Log::info(sprintf('User ID #%s authenticated using login & pwd', $user->id)); Log::info(sprintf('User ID #%s authenticated (using email+password)', $user->id));
} }
} }

View File

@ -57,12 +57,12 @@ class WebAuthnManageController extends Controller
// no more registered device exists. // no more registered device exists.
// See #110 // See #110
if (blank($user->webAuthnCredentials()->WhereEnabled()->get())) { if (blank($user->webAuthnCredentials()->WhereEnabled()->get())) {
Log::notice('No Webauthn credential enabled, Webauthn settings reset to default');
$request->user()->preferences['useWebauthnOnly'] = false; $request->user()->preferences['useWebauthnOnly'] = false;
$request->user()->save(); $request->user()->save();
Log::notice(sprintf('No more Webauthn credential for user ID #%s, user Webauthn options reset to default', $user->id));
} }
Log::info('Security device deleted'); Log::info(sprintf('User ID #%s revoked a security device', $user->id));
return response()->json(null, 204); return response()->json(null, 204);
} }

View File

@ -10,6 +10,7 @@ use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Password; use Illuminate\Support\Facades\Password;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
@ -53,6 +54,7 @@ class WebAuthnRecoveryController extends Controller
} }
$user->preferences['useWebauthnOnly'] = false; $user->preferences['useWebauthnOnly'] = false;
$user->save(); $user->save();
Log::notice(sprintf('Legacy login restored for user ID #%s', $user->id));
} else { } else {
throw new AuthenticationException(); throw new AuthenticationException();
} }

View File

@ -5,6 +5,7 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Contracts\Support\Responsable; use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;
use Laragear\WebAuthn\Http\Requests\AttestationRequest; use Laragear\WebAuthn\Http\Requests\AttestationRequest;
use Laragear\WebAuthn\Http\Requests\AttestedRequest; use Laragear\WebAuthn\Http\Requests\AttestedRequest;
use Laragear\WebAuthn\WebAuthn; use Laragear\WebAuthn\WebAuthn;
@ -43,6 +44,8 @@ class WebAuthnRegisterController extends Controller
public function register(AttestedRequest $request) : Response public function register(AttestedRequest $request) : Response
{ {
$request->save(); $request->save();
Log::info(sprintf('User ID #%s registered a new security device', $request->user()->id));
return response()->noContent(); return response()->noContent();
} }

View File

@ -86,7 +86,7 @@ class SettingService
foreach ($settings as $setting => $value) { foreach ($settings as $setting => $value) {
Option::updateOrCreate(['key' => $setting], ['value' => $value]); Option::updateOrCreate(['key' => $setting], ['value' => $value]);
Log::info(sprintf('Setting %s is now %s', var_export($setting, true), var_export($this->restoreType($value), true))); Log::notice(sprintf('App setting %s set to %s', var_export($setting, true), var_export($this->restoreType($value), true)));
} }
self::buildAndCache(); self::buildAndCache();
@ -100,7 +100,7 @@ class SettingService
public function delete(string $name) : void public function delete(string $name) : void
{ {
Option::where('key', $name)->delete(); Option::where('key', $name)->delete();
Log::info(sprintf('Setting %s deleted', var_export($name, true))); Log::notice(sprintf('App setting %s reset to default', var_export($name, true)));
self::buildAndCache(); self::buildAndCache();
} }

View File

@ -4,6 +4,7 @@ namespace Tests\Feature\Http\Auth;
use App\Models\User; use App\Models\User;
use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
use Laragear\WebAuthn\Http\Requests\AttestationRequest; use Laragear\WebAuthn\Http\Requests\AttestationRequest;
use Laragear\WebAuthn\Http\Requests\AttestedRequest; use Laragear\WebAuthn\Http\Requests\AttestedRequest;
use Laragear\WebAuthn\JsonTransport; use Laragear\WebAuthn\JsonTransport;
@ -69,7 +70,10 @@ class WebAuthnRegisterControllerTest extends FeatureTestCase
*/ */
public function test_register_uses_attested_request() : void public function test_register_uses_attested_request() : void
{ {
$this->mock(AttestedRequest::class)->expects('save')->andReturn(); $request = $this->mock(AttestedRequest::class);
$request->expects('save')->andReturn();
$request->expects('user')->andReturn($this->user);
$this->actingAs($this->user, 'web-guard') $this->actingAs($this->user, 'web-guard')
->json('POST', '/webauthn/register') ->json('POST', '/webauthn/register')