Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WFLY-4101 Make sure HttpServletRequest.logout() and Session.invalidate()... #6977

Merged
merged 1 commit into from Dec 6, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -25,33 +25,37 @@
import io.undertow.security.api.NotificationReceiver;
import io.undertow.security.api.SecurityNotification;
import io.undertow.security.idm.Account;
import org.jboss.security.CacheableManager;
import org.jboss.security.AuthenticationManager;
import org.wildfly.extension.undertow.security.AccountImpl;

import java.security.Principal;

import javax.security.auth.Subject;

/**
* Undertow security listener that invalidates the cache on logout
* Undertow security listener that invokes {@code AuthenticationManager.logout()} on logout, flushing the principal from
* the cache if a security cache is being used.
*
* @author Stuart Douglas
*/
public class CacheInvalidationNotificationReceiver implements NotificationReceiver {
public class LogoutNotificationReceiver implements NotificationReceiver {

private final CacheableManager<?, Principal> cm;
private final AuthenticationManager manager;

public CacheInvalidationNotificationReceiver(CacheableManager<?, Principal> cm) {
this.cm = cm;
public LogoutNotificationReceiver(AuthenticationManager manager) {
this.manager = manager;
}

@Override
public void handleNotification(SecurityNotification notification) {
if (notification.getEventType() == SecurityNotification.EventType.LOGGED_OUT) {
Account account = notification.getAccount();
if(account instanceof AccountImpl) {
cm.flushCache(((AccountImpl)account).getOriginalPrincipal());
}
if(account != null) {
cm.flushCache(account.getPrincipal());
Principal principal = (account instanceof AccountImpl) ? ((AccountImpl) account).getOriginalPrincipal() :
account.getPrincipal();
if (principal != null) {
// perform the logout of the principal using the subject currently set in the security context.
Subject subject = SecurityActions.getSubject();
this.manager.logout(principal, subject);
}
}
}
Expand Down
Expand Up @@ -28,27 +28,29 @@
import io.undertow.servlet.handlers.ServletRequestContext;
import io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler;
import io.undertow.servlet.spec.HttpSessionImpl;
import org.jboss.security.CacheableManager;
import org.jboss.security.AuthenticationManager;
import org.wildfly.extension.undertow.security.AccountImpl;
import org.wildfly.security.manager.WildFlySecurityManager;

import javax.security.auth.Subject;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.security.Principal;
import java.security.PrivilegedAction;

/**
* Undertow session listener that flushes the authentication cache on session invalidation
* Undertow session listener that performs logout on session invalidation. The {@code AuthenticationManager} logout
* takes care of flushing the principal from cache if a security cache is in use.
*
*
* @author Stuart Douglas
*/
public class CacheInvalidationSessionListener implements HttpSessionListener {
public class LogoutSessionListener implements HttpSessionListener {

private final CacheableManager<?, Principal> cm;
private final AuthenticationManager manager;

public CacheInvalidationSessionListener(CacheableManager<?, Principal> cm) {
this.cm = cm;
public LogoutSessionListener(AuthenticationManager manager) {
this.manager = manager;
}

@Override
Expand All @@ -62,10 +64,11 @@ public void sessionDestroyed(HttpSessionEvent se) {
//or we can look for the account that has been saved in the session
//for maximum compatibility we do both
ServletRequestContext src = ServletRequestContext.current();
Account requestAccount = null;
if (src != null) {
Account account = src.getExchange().getSecurityContext().getAuthenticatedAccount();
if (account != null) {
clearAccount(account);
requestAccount = src.getExchange().getSecurityContext().getAuthenticatedAccount();
if (requestAccount != null) {
clearAccount(requestAccount);
}
}
if (se.getSession() instanceof HttpSessionImpl) {
Expand All @@ -84,18 +87,22 @@ public Session run() {
if (session != null) {
AuthenticatedSessionManager.AuthenticatedSession authenticatedSession = (AuthenticatedSessionManager.AuthenticatedSession) session.getAttribute(CachedAuthenticatedSessionHandler.class.getName() + ".AuthenticatedSession");
if(authenticatedSession != null) {
clearAccount(authenticatedSession.getAccount());
Account sessionAccount = authenticatedSession.getAccount();
if (sessionAccount != null && !sessionAccount.equals(requestAccount)) {
clearAccount(sessionAccount);
}
}
}
}
}

private void clearAccount(Account account) {
if (account instanceof AccountImpl) {
cm.flushCache(((AccountImpl) account).getOriginalPrincipal());
}
if (account != null) {
cm.flushCache(account.getPrincipal());
Principal principal = (account instanceof AccountImpl) ? ((AccountImpl) account).getOriginalPrincipal() :
account.getPrincipal();
if (principal != null) {
// perform the logout of the principal using the subject currently set in the security context.
Subject subject = SecurityActions.getSubject();
this.manager.logout(principal, subject);
}
}
}
@@ -0,0 +1,73 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2010, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.wildfly.extension.undertow.deployment;

import java.security.PrivilegedAction;

import org.jboss.security.SecurityContext;
import org.jboss.security.SecurityContextAssociation;
import org.wildfly.security.manager.WildFlySecurityManager;

import static java.security.AccessController.doPrivileged;

import javax.security.auth.Subject;

/**
* Privileged blocks for this package
*/
class SecurityActions {

static SecurityContext getSecurityContext() {
if (WildFlySecurityManager.isChecking()) {
return doPrivileged(new PrivilegedAction<SecurityContext>() {
public SecurityContext run() {
return SecurityContextAssociation.getSecurityContext();
}
});
} else {
return SecurityContextAssociation.getSecurityContext();
}
}

static Subject getSubject() {
if (WildFlySecurityManager.isChecking()) {
return doPrivileged(new PrivilegedAction<Subject>() {
public Subject run() {
Subject subject = null;
SecurityContext sc = getSecurityContext();
if (sc != null) {
subject = sc.getUtil().getSubject();
}
return subject;
}
});
} else {
Subject subject = null;
SecurityContext sc = getSecurityContext();
if (sc != null) {
subject = sc.getUtil().getSubject();
}
return subject;
}
}
}
Expand Up @@ -118,7 +118,6 @@
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;
import org.jboss.security.CacheableManager;
import org.jboss.security.audit.AuditManager;
import org.jboss.security.auth.login.JASPIAuthenticationInfo;
import org.jboss.security.authorization.config.AuthorizationModuleEntry;
Expand Down Expand Up @@ -268,7 +267,7 @@ public synchronized void start(final StartContext startContext) throws StartExce
handleJACCAuthorization
(deploymentInfo);
handleAdditionalAuthenticationMechanisms(deploymentInfo);
handleSecurityCache(deploymentInfo, mergedMetaData);
handleAuthManagerLogout(deploymentInfo, mergedMetaData);

if(mergedMetaData.isUseJBossAuthorization()) {
deploymentInfo.setAuthorizationManager(new JbossAuthorizationManager(deploymentInfo.getAuthorizationManager()));
Expand Down Expand Up @@ -398,14 +397,12 @@ public synchronized void start(final StartContext startContext) throws StartExce

}

private void handleSecurityCache(DeploymentInfo deploymentInfo, JBossWebMetaData mergedMetaData) {
private void handleAuthManagerLogout(DeploymentInfo deploymentInfo, JBossWebMetaData mergedMetaData) {
AuthenticationManager manager = securityDomainContextValue.getValue().getAuthenticationManager();
if(manager instanceof CacheableManager) {
deploymentInfo.addNotificationReceiver(new CacheInvalidationNotificationReceiver((CacheableManager<?, java.security.Principal>) manager));
if(mergedMetaData.isFlushOnSessionInvalidation()) {
CacheInvalidationSessionListener listener = new CacheInvalidationSessionListener((CacheableManager<?, java.security.Principal>) manager);
deploymentInfo.addListener(Servlets.listener(CacheInvalidationSessionListener.class, new ImmediateInstanceFactory<EventListener>(listener)));
}
deploymentInfo.addNotificationReceiver(new LogoutNotificationReceiver(manager));
if(mergedMetaData.isFlushOnSessionInvalidation()) {
LogoutSessionListener listener = new LogoutSessionListener(manager);
deploymentInfo.addListener(Servlets.listener(LogoutSessionListener.class, new ImmediateInstanceFactory<EventListener>(listener)));
}
}

Expand Down