46
46
*/
47
47
class AuthenticatorManager implements AuthenticatorManagerInterface, UserAuthenticatorInterface
48
48
{
49
+ private ExposeSecurityLevel $ exposeSecurityErrors ;
50
+
49
51
/**
50
52
* @param iterable<mixed, AuthenticatorInterface> $authenticators
51
53
*/
@@ -56,9 +58,17 @@ public function __construct(
56
58
private string $ firewallName ,
57
59
private ?LoggerInterface $ logger = null ,
58
60
private bool $ eraseCredentials = true ,
59
- private bool $ hideUserNotFoundExceptions = true ,
61
+ ExposeSecurityLevel | bool $ exposeSecurityErrors = ExposeSecurityLevel::None ,
60
62
private array $ requiredBadges = [],
61
63
) {
64
+ if (\is_bool ($ exposeSecurityErrors )) {
65
+ trigger_deprecation ('symfony/security-http ' , '7.3 ' , 'Passing a boolean as "exposeSecurityErrors" parameter is deprecated, use %s value instead. ' , ExposeSecurityLevel::class);
66
+
67
+ // The old parameter had an inverted meaning ($hideUserNotFoundExceptions), for that reason the current name does not reflect the behavior
68
+ $ exposeSecurityErrors = $ exposeSecurityErrors ? ExposeSecurityLevel::None : ExposeSecurityLevel::All;
69
+ }
70
+
71
+ $ this ->exposeSecurityErrors = $ exposeSecurityErrors ;
62
72
}
63
73
64
74
/**
@@ -250,7 +260,7 @@ private function handleAuthenticationFailure(AuthenticationException $authentica
250
260
251
261
// Avoid leaking error details in case of invalid user (e.g. user not found or invalid account status)
252
262
// to prevent user enumeration via response content comparison
253
- if ($ this ->hideUserNotFoundExceptions && ($ authenticationException instanceof UserNotFoundException || ( $ authenticationException instanceof AccountStatusException && ! $ authenticationException instanceof CustomUserMessageAccountStatusException) )) {
263
+ if ($ this ->isSensitiveException ($ authenticationException )) {
254
264
$ authenticationException = new BadCredentialsException ('Bad credentials. ' , 0 , $ authenticationException );
255
265
}
256
266
@@ -264,4 +274,17 @@ private function handleAuthenticationFailure(AuthenticationException $authentica
264
274
// returning null is ok, it means they want the request to continue
265
275
return $ loginFailureEvent ->getResponse ();
266
276
}
277
+
278
+ private function isSensitiveException (AuthenticationException $ exception ): bool
279
+ {
280
+ if (ExposeSecurityLevel::All !== $ this ->exposeSecurityErrors && $ exception instanceof UserNotFoundException) {
281
+ return true ;
282
+ }
283
+
284
+ if (ExposeSecurityLevel::None === $ this ->exposeSecurityErrors && $ exception instanceof AccountStatusException && !$ exception instanceof CustomUserMessageAccountStatusException) {
285
+ return true ;
286
+ }
287
+
288
+ return false ;
289
+ }
267
290
}
0 commit comments