HttpServletRequest#logout doesn't fully clear security context
--------------------------------------------------------------
Key: WFLY-4602
URL:
https://issues.jboss.org/browse/WFLY-4602
Project: WildFly
Issue Type: Bug
Components: Web (Undertow)
Affects Versions: 9.0.0.CR1
Reporter: Arjan t
Assignee: Stuart Douglas
Labels: authentication, security, security-context
Fix For: 9.0.0.CR2, 10.0.0.Alpha1
After having authenticated (via JASPIC or otherwise), calling
{{HttpServletRequest#logout}} and then requesting the caller/user principal (all within
the same request), Undertow (via e.g. WildFly 8.2 or 9.0rc1) will correctly clear out the
principal for the web context, but will NOT clear out the principal for the EJB context.
The problem seems to be that {{io.undertow.security.impl.SecurityContextImpl.logout()}}
doesn't do anything with the security context that is used by the EJB container among
others.
It now just contains the following:
{code:java}
this.account = null;
this.mechanismName = null;
this.authenticationState = AuthenticationState.NOT_ATTEMPTED;
{code}
Added the following code just before this seems to work:
{code:java}
// Clear old context
SecurityContextAssociation.clearSecurityContext();
SecurityRolesAssociation.setSecurityRoles(null);
// Set a new one in case re-authentication is done within the same thread
SecurityContext securityContext =
SecurityContextFactory.createSecurityContext("other");
exchange.putAttachment(SECURITY_CONTEXT_ATTACHMENT, securityContext);
SecurityContextAssociation.setSecurityContext(securityContext);
// (existing clearing code)
this.account = null;
this.mechanismName = null;
this.authenticationState = AuthenticationState.NOT_ATTEMPTED;
{code}
Do note that this code uses the hardcoded domain "other". Except by using
reflection I couldn't obtain the actual domain name at this point. The reflective code
I used was:
{code:java}
String securityDomain = "other";
if (identityManager instanceof JAASIdentityManagerImpl) {
try {
Field securityDomainContextField =
JAASIdentityManagerImpl.class.getDeclaredField("securityDomainContext");
securityDomainContextField.setAccessible(true);
SecurityDomainContext securityDomainContext = (SecurityDomainContext)
securityDomainContextField.get(identityManager);
securityDomain =
securityDomainContext.getAuthenticationManager().getSecurityDomain();
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException |
IllegalAccessException e) {
logger.log(Level.SEVERE, "Can't obtain name of security domain, using
'other' now", e);
}
}
{code}