Search before asking
Environment
Any application using a ModularRealmAuthenticator with more than one realm, where at least one realm uses AllowAllCredentialsMatcher (i.e. the realm verifies credentials elsewhere — token/SSO validation, an LDAP bind, or implicit trust — and returns null from doGetAuthenticationInfo for principals it doesn't own). Reproduced on JDK 21; doesn't appear to be OS- or app-server-specific.
Shiro version
2.1.0. It looks like this surfaces from 2.0.7 onwards, when simulateFailedLogin/createSimulatedCredentials were introduced (the fix for CVE-2026-23901, user-enumeration timing).
What was the actual outcome?
When an AllowAllCredentialsMatcher realm is asked about a principal it doesn't own, AuthenticatingRealm logs an ERROR with an IncorrectCredentialsException stack trace ("…matched the simulated credentials. This indicates a misconfiguration of the realm's CredentialsMatcher or simulated credentials."). In a multi-realm setup this happens on every login that another realm handles, so it can produce a lot of log noise even though authentication itself works fine (the exception is caught internally).
I think this comes from an interaction between AllowAllCredentialsMatcher and simulateFailedLogin:
-
When doGetAuthenticationInfo returns null, getAuthenticationInfo calls simulateFailedLogin(token), which matches the submitted token against the decoy from createSimulatedCredentials() and treats a match as a misconfiguration:
// AuthenticatingRealm
AuthenticationInfo simulated = ensureSimulatedAuthenticationInfo();
if (simulated != null && assertCredentialsMatchWithoutException(token, simulated)) {
throw new IncorrectCredentialsException("... matched the simulated credentials ...");
}
-
AllowAllCredentialsMatcher matches everything and also supplies a non-empty decoy:
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { return true; }
@Override
public Optional<AuthenticationInfo> createSimulatedCredentials() {
return Optional.of(new SimpleAuthenticationInfo("user", "password", "realm"));
}
Since createSimulatedCredentials() is meant to provide a decoy that doCredentialsMatch will not match, an always-matching matcher can't really satisfy that, so the check is always taken and the error logged.
What was the expected outcome?
Ideally a realm that intentionally trusts credentials via AllowAllCredentialsMatcher wouldn't log a misconfiguration error just because it found no account for a principal. One option is for the matcher to return Optional.empty() from createSimulatedCredentials(); the only snag is that ensureSimulatedAuthenticationInfo then logs a WARN ("CredentialsMatcher … did not supply simulated credentials") on each call, so it'd be nice if that warning were emitted once (or skipped for matchers that opt out) too. Happy to open a PR along these lines if that direction sounds reasonable.
How to reproduce
- Configure a realm whose
doGetAuthenticationInfo returns null for unknown principals, with setCredentialsMatcher(new AllowAllCredentialsMatcher()).
- Call
realm.getAuthenticationInfo(token) with a token for a principal that realm doesn't own (the usual case in a multi-realm ModularRealmAuthenticator, e.g. a native user when an SSO realm is also configured).
- Observe an
ERROR from org.apache.shiro.realm.AuthenticatingRealm on each such call.
Minimal sketch:
AuthenticatingRealm realm = new AuthenticatingRealm() {
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken t) { return null; }
};
realm.setCredentialsMatcher(new AllowAllCredentialsMatcher());
realm.getAuthenticationInfo(new UsernamePasswordToken("alice", "secret")); // logs the ERROR
Debug logs
Debug logs
ERROR CredentialsMatcher [org.apache.shiro.authc.credential.AllowAllCredentialsMatcher@20d5fd1e] threw exception on method 'doCredentialsMatch'
org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [{ ... principal='alice' ... }] matched the simulated credentials. This indicates a misconfiguration of the realm's CredentialsMatcher or simulated credentials. Please review your configuration.
at org.apache.shiro.realm.AuthenticatingRealm.simulateFailedLogin(AuthenticatingRealm.java:601)
at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:588)
at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doMultiRealmAuthentication(ModularRealmAuthenticator.java:227)
at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:277)
at org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198)
...
Search before asking
Environment
Any application using a
ModularRealmAuthenticatorwith more than one realm, where at least one realm usesAllowAllCredentialsMatcher(i.e. the realm verifies credentials elsewhere — token/SSO validation, an LDAP bind, or implicit trust — and returnsnullfromdoGetAuthenticationInfofor principals it doesn't own). Reproduced on JDK 21; doesn't appear to be OS- or app-server-specific.Shiro version
2.1.0. It looks like this surfaces from 2.0.7 onwards, when
simulateFailedLogin/createSimulatedCredentialswere introduced (the fix for CVE-2026-23901, user-enumeration timing).What was the actual outcome?
When an
AllowAllCredentialsMatcherrealm is asked about a principal it doesn't own,AuthenticatingRealmlogs anERRORwith anIncorrectCredentialsExceptionstack trace ("…matched the simulated credentials. This indicates a misconfiguration of the realm's CredentialsMatcher or simulated credentials."). In a multi-realm setup this happens on every login that another realm handles, so it can produce a lot of log noise even though authentication itself works fine (the exception is caught internally).I think this comes from an interaction between
AllowAllCredentialsMatcherandsimulateFailedLogin:When
doGetAuthenticationInforeturnsnull,getAuthenticationInfocallssimulateFailedLogin(token), which matches the submitted token against the decoy fromcreateSimulatedCredentials()and treats a match as a misconfiguration:AllowAllCredentialsMatchermatches everything and also supplies a non-empty decoy:Since
createSimulatedCredentials()is meant to provide a decoy thatdoCredentialsMatchwill not match, an always-matching matcher can't really satisfy that, so the check is always taken and the error logged.What was the expected outcome?
Ideally a realm that intentionally trusts credentials via
AllowAllCredentialsMatcherwouldn't log a misconfiguration error just because it found no account for a principal. One option is for the matcher to returnOptional.empty()fromcreateSimulatedCredentials(); the only snag is thatensureSimulatedAuthenticationInfothen logs aWARN("CredentialsMatcher … did not supply simulated credentials") on each call, so it'd be nice if that warning were emitted once (or skipped for matchers that opt out) too. Happy to open a PR along these lines if that direction sounds reasonable.How to reproduce
doGetAuthenticationInforeturnsnullfor unknown principals, withsetCredentialsMatcher(new AllowAllCredentialsMatcher()).realm.getAuthenticationInfo(token)with a token for a principal that realm doesn't own (the usual case in a multi-realmModularRealmAuthenticator, e.g. a native user when an SSO realm is also configured).ERRORfromorg.apache.shiro.realm.AuthenticatingRealmon each such call.Minimal sketch:
Debug logs
Debug logs