mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 17:22:13 +00:00
SEC-1695: Allow customization of the session key under which the SecurityContext is stored.
This commit is contained in:
parent
42e0e158b4
commit
6d04670f87
@ -17,9 +17,7 @@ package org.springframework.security.authentication.jaas;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.security.auth.callback.Callback;
|
import javax.security.auth.callback.Callback;
|
||||||
import javax.security.auth.callback.CallbackHandler;
|
import javax.security.auth.callback.CallbackHandler;
|
||||||
@ -54,7 +52,7 @@ import org.springframework.util.ObjectUtils;
|
|||||||
* <p>This implementation is backed by a <a
|
* <p>This implementation is backed by a <a
|
||||||
* href="http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/JAASRefGuide.html">JAAS</a> configuration that is provided by
|
* href="http://java.sun.com/j2se/1.5.0/docs/guide/security/jaas/JAASRefGuide.html">JAAS</a> configuration that is provided by
|
||||||
* a subclass's implementation of {@link #createLoginContext(CallbackHandler)}.
|
* a subclass's implementation of {@link #createLoginContext(CallbackHandler)}.
|
||||||
*
|
*
|
||||||
* <p>When using JAAS login modules as the authentication source, sometimes the
|
* <p>When using JAAS login modules as the authentication source, sometimes the
|
||||||
* <a href="http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/LoginContext.html">LoginContext</a> will
|
* <a href="http://java.sun.com/j2se/1.5.0/docs/api/javax/security/auth/login/LoginContext.html">LoginContext</a> will
|
||||||
* require <i>CallbackHandler</i>s. The AbstractJaasAuthenticationProvider uses an internal
|
* require <i>CallbackHandler</i>s. The AbstractJaasAuthenticationProvider uses an internal
|
||||||
@ -91,7 +89,7 @@ import org.springframework.util.ObjectUtils;
|
|||||||
* </list>
|
* </list>
|
||||||
* </property>
|
* </property>
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author Ray Krueger
|
* @author Ray Krueger
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
*/
|
*/
|
||||||
@ -190,7 +188,7 @@ ApplicationEventPublisherAware, InitializingBean, ApplicationListener<SessionDes
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the LoginContext to be used for authentication.
|
* Creates the LoginContext to be used for authentication.
|
||||||
*
|
*
|
||||||
* @param handler The CallbackHandler that should be used for the LoginContext (never <code>null</code>).
|
* @param handler The CallbackHandler that should be used for the LoginContext (never <code>null</code>).
|
||||||
* @return the LoginContext to use for authentication.
|
* @return the LoginContext to use for authentication.
|
||||||
* @throws LoginException
|
* @throws LoginException
|
||||||
@ -198,39 +196,42 @@ ApplicationEventPublisherAware, InitializingBean, ApplicationListener<SessionDes
|
|||||||
protected abstract LoginContext createLoginContext(CallbackHandler handler) throws LoginException;
|
protected abstract LoginContext createLoginContext(CallbackHandler handler) throws LoginException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the logout by getting the SecurityContext for the session that was destroyed. <b>MUST NOT use
|
* Handles the logout by getting the security contexts for the destroyed session and invoking
|
||||||
* SecurityContextHolder as we are logging out a session that is not related to the current user.</b>
|
* {@code LoginContext.logout()} for any which contain a {@code JaasAuthenticationToken}.
|
||||||
*
|
*
|
||||||
* @param event
|
*
|
||||||
|
* @param event the session event which contains the current session
|
||||||
*/
|
*/
|
||||||
protected void handleLogout(SessionDestroyedEvent event) {
|
protected void handleLogout(SessionDestroyedEvent event) {
|
||||||
SecurityContext context = event.getSecurityContext();
|
List<SecurityContext> contexts = event.getSecurityContexts();
|
||||||
|
|
||||||
if (context == null) {
|
if (contexts.isEmpty()) {
|
||||||
log.debug("The destroyed session has no SecurityContext");
|
log.debug("The destroyed session has no SecurityContexts");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Authentication auth = context.getAuthentication();
|
for(SecurityContext context : contexts) {
|
||||||
|
Authentication auth = context.getAuthentication();
|
||||||
|
|
||||||
if ((auth != null) && (auth instanceof JaasAuthenticationToken)) {
|
if ((auth != null) && (auth instanceof JaasAuthenticationToken)) {
|
||||||
JaasAuthenticationToken token = (JaasAuthenticationToken) auth;
|
JaasAuthenticationToken token = (JaasAuthenticationToken) auth;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
LoginContext loginContext = token.getLoginContext();
|
LoginContext loginContext = token.getLoginContext();
|
||||||
boolean debug = log.isDebugEnabled();
|
boolean debug = log.isDebugEnabled();
|
||||||
if (loginContext != null) {
|
if (loginContext != null) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
log.debug("Logging principal: [" + token.getPrincipal() + "] out of LoginContext");
|
log.debug("Logging principal: [" + token.getPrincipal() + "] out of LoginContext");
|
||||||
|
}
|
||||||
|
loginContext.logout();
|
||||||
|
} else if (debug) {
|
||||||
|
log.debug("Cannot logout principal: [" + token.getPrincipal() + "] from LoginContext. "
|
||||||
|
+ "The LoginContext is unavailable");
|
||||||
}
|
}
|
||||||
loginContext.logout();
|
} catch (LoginException e) {
|
||||||
} else if (debug) {
|
log.warn("Error error logging out of LoginContext", e);
|
||||||
log.debug("Cannot logout principal: [" + token.getPrincipal() + "] from LoginContext. "
|
|
||||||
+ "The LoginContext is unavailable");
|
|
||||||
}
|
}
|
||||||
} catch (LoginException e) {
|
|
||||||
log.warn("Error error logging out of LoginContext", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package org.springframework.security.core.session;
|
|||||||
import org.springframework.context.ApplicationEvent;
|
import org.springframework.context.ApplicationEvent;
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic "session termination" event which indicates that a session (potentially
|
* Generic "session termination" event which indicates that a session (potentially
|
||||||
* represented by a security context) has ended.
|
* represented by a security context) has ended.
|
||||||
@ -17,11 +19,13 @@ public abstract class SessionDestroyedEvent extends ApplicationEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the <tt>SecurityContext</tt> under which the session was running.
|
* Provides the {@code SecurityContext} instances which were associated with the destroyed session. Usually there
|
||||||
|
* will be only one security context per session.
|
||||||
*
|
*
|
||||||
* @return the <tt>SecurityContext</tt> associated with the session, or null if there is no context.
|
* @return the {@code SecurityContext} instances which were stored in the current session (an empty list if there
|
||||||
|
* are none).
|
||||||
*/
|
*/
|
||||||
public abstract SecurityContext getSecurityContext();
|
public abstract List<SecurityContext> getSecurityContexts();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the identifier associated with the destroyed session.
|
* @return the identifier associated with the destroyed session.
|
||||||
|
@ -27,7 +27,7 @@ import static org.mockito.Mockito.verify;
|
|||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
|
|
||||||
import javax.security.auth.login.AppConfigurationEntry;
|
import javax.security.auth.login.AppConfigurationEntry;
|
||||||
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
|
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
|
||||||
@ -136,13 +136,13 @@ public class DefaultJaasAuthenticationProviderTests {
|
|||||||
JaasAuthenticationToken token = mock(JaasAuthenticationToken.class);
|
JaasAuthenticationToken token = mock(JaasAuthenticationToken.class);
|
||||||
LoginContext context = mock(LoginContext.class);
|
LoginContext context = mock(LoginContext.class);
|
||||||
|
|
||||||
when(event.getSecurityContext()).thenReturn(securityContext);
|
when(event.getSecurityContexts()).thenReturn(Arrays.asList(securityContext));
|
||||||
when(securityContext.getAuthentication()).thenReturn(token);
|
when(securityContext.getAuthentication()).thenReturn(token);
|
||||||
when(token.getLoginContext()).thenReturn(context);
|
when(token.getLoginContext()).thenReturn(context);
|
||||||
|
|
||||||
provider.onApplicationEvent(event);
|
provider.onApplicationEvent(event);
|
||||||
|
|
||||||
verify(event).getSecurityContext();
|
verify(event).getSecurityContexts();
|
||||||
verify(securityContext).getAuthentication();
|
verify(securityContext).getAuthentication();
|
||||||
verify(token).getLoginContext();
|
verify(token).getLoginContext();
|
||||||
verify(context).logout();
|
verify(context).logout();
|
||||||
@ -155,7 +155,7 @@ public class DefaultJaasAuthenticationProviderTests {
|
|||||||
|
|
||||||
provider.handleLogout(event);
|
provider.handleLogout(event);
|
||||||
|
|
||||||
verify(event).getSecurityContext();
|
verify(event).getSecurityContexts();
|
||||||
verify(log).debug(anyString());
|
verify(log).debug(anyString());
|
||||||
verifyNoMoreInteractions(event);
|
verifyNoMoreInteractions(event);
|
||||||
}
|
}
|
||||||
@ -165,12 +165,12 @@ public class DefaultJaasAuthenticationProviderTests {
|
|||||||
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
||||||
SecurityContext securityContext = mock(SecurityContext.class);
|
SecurityContext securityContext = mock(SecurityContext.class);
|
||||||
|
|
||||||
when(event.getSecurityContext()).thenReturn(securityContext);
|
when(event.getSecurityContexts()).thenReturn(Arrays.asList(securityContext));
|
||||||
|
|
||||||
provider.handleLogout(event);
|
provider.handleLogout(event);
|
||||||
|
|
||||||
verify(event).getSecurityContext();
|
verify(event).getSecurityContexts();
|
||||||
verify(event).getSecurityContext();
|
verify(event).getSecurityContexts();
|
||||||
verify(securityContext).getAuthentication();
|
verify(securityContext).getAuthentication();
|
||||||
verifyNoMoreInteractions(event, securityContext);
|
verifyNoMoreInteractions(event, securityContext);
|
||||||
}
|
}
|
||||||
@ -180,13 +180,13 @@ public class DefaultJaasAuthenticationProviderTests {
|
|||||||
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
||||||
SecurityContext securityContext = mock(SecurityContext.class);
|
SecurityContext securityContext = mock(SecurityContext.class);
|
||||||
|
|
||||||
when(event.getSecurityContext()).thenReturn(securityContext);
|
when(event.getSecurityContexts()).thenReturn(Arrays.asList(securityContext));
|
||||||
when(securityContext.getAuthentication()).thenReturn(token);
|
when(securityContext.getAuthentication()).thenReturn(token);
|
||||||
|
|
||||||
provider.handleLogout(event);
|
provider.handleLogout(event);
|
||||||
|
|
||||||
verify(event).getSecurityContext();
|
verify(event).getSecurityContexts();
|
||||||
verify(event).getSecurityContext();
|
verify(event).getSecurityContexts();
|
||||||
verify(securityContext).getAuthentication();
|
verify(securityContext).getAuthentication();
|
||||||
verifyNoMoreInteractions(event, securityContext);
|
verifyNoMoreInteractions(event, securityContext);
|
||||||
}
|
}
|
||||||
@ -197,11 +197,11 @@ public class DefaultJaasAuthenticationProviderTests {
|
|||||||
SecurityContext securityContext = mock(SecurityContext.class);
|
SecurityContext securityContext = mock(SecurityContext.class);
|
||||||
JaasAuthenticationToken token = mock(JaasAuthenticationToken.class);
|
JaasAuthenticationToken token = mock(JaasAuthenticationToken.class);
|
||||||
|
|
||||||
when(event.getSecurityContext()).thenReturn(securityContext);
|
when(event.getSecurityContexts()).thenReturn(Arrays.asList(securityContext));
|
||||||
when(securityContext.getAuthentication()).thenReturn(token);
|
when(securityContext.getAuthentication()).thenReturn(token);
|
||||||
|
|
||||||
provider.onApplicationEvent(event);
|
provider.onApplicationEvent(event);
|
||||||
verify(event).getSecurityContext();
|
verify(event).getSecurityContexts();
|
||||||
verify(securityContext).getAuthentication();
|
verify(securityContext).getAuthentication();
|
||||||
verify(token).getLoginContext();
|
verify(token).getLoginContext();
|
||||||
|
|
||||||
@ -216,14 +216,14 @@ public class DefaultJaasAuthenticationProviderTests {
|
|||||||
LoginContext context = mock(LoginContext.class);
|
LoginContext context = mock(LoginContext.class);
|
||||||
LoginException loginException = new LoginException("Failed Login");
|
LoginException loginException = new LoginException("Failed Login");
|
||||||
|
|
||||||
when(event.getSecurityContext()).thenReturn(securityContext);
|
when(event.getSecurityContexts()).thenReturn(Arrays.asList(securityContext));
|
||||||
when(securityContext.getAuthentication()).thenReturn(token);
|
when(securityContext.getAuthentication()).thenReturn(token);
|
||||||
when(token.getLoginContext()).thenReturn(context);
|
when(token.getLoginContext()).thenReturn(context);
|
||||||
doThrow(loginException).when(context).logout();
|
doThrow(loginException).when(context).logout();
|
||||||
|
|
||||||
provider.onApplicationEvent(event);
|
provider.onApplicationEvent(event);
|
||||||
|
|
||||||
verify(event).getSecurityContext();
|
verify(event).getSecurityContexts();
|
||||||
verify(securityContext).getAuthentication();
|
verify(securityContext).getAuthentication();
|
||||||
verify(token).getLoginContext();
|
verify(token).getLoginContext();
|
||||||
verify(context).logout();
|
verify(context).logout();
|
||||||
|
@ -41,6 +41,8 @@ import org.springframework.security.core.AuthenticationException;
|
|||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.context.SecurityContextImpl;
|
import org.springframework.security.core.context.SecurityContextImpl;
|
||||||
import org.springframework.security.core.session.SessionDestroyedEvent;
|
import org.springframework.security.core.session.SessionDestroyedEvent;
|
||||||
|
|
||||||
@ -244,11 +246,11 @@ public class JaasAuthenticationProviderTests {
|
|||||||
|
|
||||||
JaasAuthenticationToken token = new JaasAuthenticationToken(null, null, loginContext);
|
JaasAuthenticationToken token = new JaasAuthenticationToken(null, null, loginContext);
|
||||||
|
|
||||||
SecurityContextImpl context = new SecurityContextImpl();
|
SecurityContext context = SecurityContextHolder.createEmptyContext();
|
||||||
context.setAuthentication(token);
|
context.setAuthentication(token);
|
||||||
|
|
||||||
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
SessionDestroyedEvent event = mock(SessionDestroyedEvent.class);
|
||||||
when(event.getSecurityContext()).thenReturn(context);
|
when(event.getSecurityContexts()).thenReturn(Arrays.asList(context));
|
||||||
|
|
||||||
jaasProvider.handleLogout(event);
|
jaasProvider.handleLogout(event);
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ public class SessionRegistryImplTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecurityContext getSecurityContext() {
|
public List<SecurityContext> getSecurityContexts() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -8,6 +8,7 @@ import org.springframework.security.core.Authentication;
|
|||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@ -19,7 +20,7 @@ import javax.servlet.http.HttpSession;
|
|||||||
* between requests.
|
* between requests.
|
||||||
* <p>
|
* <p>
|
||||||
* The {@code HttpSession} will be queried to retrieve the {@code SecurityContext} in the <tt>loadContext</tt>
|
* The {@code HttpSession} will be queried to retrieve the {@code SecurityContext} in the <tt>loadContext</tt>
|
||||||
* method (using the key {@link #SPRING_SECURITY_CONTEXT_KEY}). If a valid {@code SecurityContext} cannot be
|
* method (using the key {@link #SPRING_SECURITY_CONTEXT_KEY} by default). If a valid {@code SecurityContext} cannot be
|
||||||
* obtained from the {@code HttpSession} for whatever reason, a fresh {@code SecurityContext} will be created
|
* obtained from the {@code HttpSession} for whatever reason, a fresh {@code SecurityContext} will be created
|
||||||
* by calling by {@link SecurityContextHolder#createEmptyContext()} and this instance will be returned instead.
|
* by calling by {@link SecurityContextHolder#createEmptyContext()} and this instance will be returned instead.
|
||||||
* <p>
|
* <p>
|
||||||
@ -50,6 +51,9 @@ import javax.servlet.http.HttpSession;
|
|||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class HttpSessionSecurityContextRepository implements SecurityContextRepository {
|
public class HttpSessionSecurityContextRepository implements SecurityContextRepository {
|
||||||
|
/**
|
||||||
|
* The default key under which the security context will be stored in the session.
|
||||||
|
*/
|
||||||
public static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
|
public static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||||
@ -59,6 +63,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo
|
|||||||
private final Object contextObject = SecurityContextHolder.createEmptyContext();
|
private final Object contextObject = SecurityContextHolder.createEmptyContext();
|
||||||
private boolean allowSessionCreation = true;
|
private boolean allowSessionCreation = true;
|
||||||
private boolean disableUrlRewriting = false;
|
private boolean disableUrlRewriting = false;
|
||||||
|
private String springSecurityContextKey = SPRING_SECURITY_CONTEXT_KEY;
|
||||||
|
|
||||||
private final AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
private final AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
||||||
|
|
||||||
@ -108,7 +113,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return session.getAttribute(SPRING_SECURITY_CONTEXT_KEY) != null;
|
return session.getAttribute(springSecurityContextKey) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -128,7 +133,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo
|
|||||||
|
|
||||||
// Session exists, so try to obtain a context from it.
|
// Session exists, so try to obtain a context from it.
|
||||||
|
|
||||||
Object contextFromSession = httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY);
|
Object contextFromSession = httpSession.getAttribute(springSecurityContextKey);
|
||||||
|
|
||||||
if (contextFromSession == null) {
|
if (contextFromSession == null) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
@ -141,7 +146,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo
|
|||||||
// We now have the security context object from the session.
|
// We now have the security context object from the session.
|
||||||
if (!(contextFromSession instanceof SecurityContext)) {
|
if (!(contextFromSession instanceof SecurityContext)) {
|
||||||
if (logger.isWarnEnabled()) {
|
if (logger.isWarnEnabled()) {
|
||||||
logger.warn("SPRING_SECURITY_CONTEXT did not contain a SecurityContext but contained: '"
|
logger.warn(springSecurityContextKey + " did not contain a SecurityContext but contained: '"
|
||||||
+ contextFromSession + "'; are you improperly modifying the HttpSession directly "
|
+ contextFromSession + "'; are you improperly modifying the HttpSession directly "
|
||||||
+ "(you should always use SecurityContextHolder) or using the HttpSession attribute "
|
+ "(you should always use SecurityContextHolder) or using the HttpSession attribute "
|
||||||
+ "reserved for this class?");
|
+ "reserved for this class?");
|
||||||
@ -151,7 +156,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
logger.debug("Obtained a valid SecurityContext from SPRING_SECURITY_CONTEXT: '" + contextFromSession + "'");
|
logger.debug("Obtained a valid SecurityContext from " + springSecurityContextKey + ": '" + contextFromSession + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything OK. The only non-null return from this method.
|
// Everything OK. The only non-null return from this method.
|
||||||
@ -212,6 +217,17 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo
|
|||||||
this.disableUrlRewriting = disableUrlRewriting;
|
this.disableUrlRewriting = disableUrlRewriting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the session attribute name to be customized for this repository instance.
|
||||||
|
*
|
||||||
|
* @param springSecurityContextKey the key under which the security context will be stored. Defaults to
|
||||||
|
* {@link #SPRING_SECURITY_CONTEXT_KEY}.
|
||||||
|
*/
|
||||||
|
public void setSpringSecurityContextKey(String springSecurityContextKey) {
|
||||||
|
Assert.hasText(springSecurityContextKey, "springSecurityContextKey cannot be empty");
|
||||||
|
this.springSecurityContextKey = springSecurityContextKey;
|
||||||
|
}
|
||||||
|
|
||||||
//~ Inner Classes ==================================================================================================
|
//~ Inner Classes ==================================================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -273,7 +289,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo
|
|||||||
|
|
||||||
if (httpSession != null) {
|
if (httpSession != null) {
|
||||||
// SEC-1587 A non-anonymous context may still be in the session
|
// SEC-1587 A non-anonymous context may still be in the session
|
||||||
httpSession.removeAttribute(SPRING_SECURITY_CONTEXT_KEY);
|
httpSession.removeAttribute(springSecurityContextKey);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -286,8 +302,8 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo
|
|||||||
// actually changed in this thread (see SEC-37, SEC-1307, SEC-1528)
|
// actually changed in this thread (see SEC-37, SEC-1307, SEC-1528)
|
||||||
if (httpSession != null) {
|
if (httpSession != null) {
|
||||||
// We may have a new session, so check also whether the context attribute is set SEC-1561
|
// We may have a new session, so check also whether the context attribute is set SEC-1561
|
||||||
if (contextChanged(context) || httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) == null) {
|
if (contextChanged(context) || httpSession.getAttribute(springSecurityContextKey) == null) {
|
||||||
httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, context);
|
httpSession.setAttribute(springSecurityContextKey, context);
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("SecurityContext stored to HttpSession: '" + context + "'");
|
logger.debug("SecurityContext stored to HttpSession: '" + context + "'");
|
||||||
|
@ -17,10 +17,12 @@ package org.springframework.security.web.session;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
|
import com.sun.xml.internal.ws.encoding.ContentType;
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.session.SessionDestroyedEvent;
|
import org.springframework.security.core.session.SessionDestroyedEvent;
|
||||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Published by the {@link HttpSessionEventPublisher} when a HttpSession is created in the container
|
* Published by the {@link HttpSessionEventPublisher} when a HttpSession is created in the container
|
||||||
@ -39,9 +41,23 @@ public class HttpSessionDestroyedEvent extends SessionDestroyedEvent {
|
|||||||
return (HttpSession) getSource();
|
return (HttpSession) getSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public SecurityContext getSecurityContext() {
|
public List<SecurityContext> getSecurityContexts() {
|
||||||
return (SecurityContext) ((HttpSession)getSource()).getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
|
HttpSession session = (HttpSession)getSource();
|
||||||
|
|
||||||
|
Enumeration<String> attributes = session.getAttributeNames();
|
||||||
|
|
||||||
|
ArrayList<SecurityContext> contexts = new ArrayList<SecurityContext>();
|
||||||
|
|
||||||
|
while(attributes.hasMoreElements()) {
|
||||||
|
Object attribute = attributes.nextElement();
|
||||||
|
if (attribute instanceof SecurityContext) {
|
||||||
|
contexts.add((SecurityContext) attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contexts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,9 +47,10 @@ public class HttpSessionSecurityContextRepositoryTests {
|
|||||||
@Test
|
@Test
|
||||||
public void existingContextIsSuccessFullyLoadedFromSessionAndSavedBack() throws Exception {
|
public void existingContextIsSuccessFullyLoadedFromSessionAndSavedBack() throws Exception {
|
||||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||||
|
repo.setSpringSecurityContextKey("imTheContext");
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
SecurityContextHolder.getContext().setAuthentication(testToken);
|
SecurityContextHolder.getContext().setAuthentication(testToken);
|
||||||
request.getSession().setAttribute(SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
|
request.getSession().setAttribute("imTheContext", SecurityContextHolder.getContext());
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
|
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
|
||||||
SecurityContext context = repo.loadContext(holder);
|
SecurityContext context = repo.loadContext(holder);
|
||||||
@ -57,7 +58,7 @@ public class HttpSessionSecurityContextRepositoryTests {
|
|||||||
assertEquals(testToken, context.getAuthentication());
|
assertEquals(testToken, context.getAuthentication());
|
||||||
// Won't actually be saved as it hasn't changed, but go through the use case anyway
|
// Won't actually be saved as it hasn't changed, but go through the use case anyway
|
||||||
repo.saveContext(context, holder.getRequest(), holder.getResponse());
|
repo.saveContext(context, holder.getRequest(), holder.getResponse());
|
||||||
assertEquals(context, request.getSession().getAttribute(SPRING_SECURITY_CONTEXT_KEY));
|
assertEquals(context, request.getSession().getAttribute("imTheContext"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SEC-1528
|
// SEC-1528
|
||||||
@ -113,33 +114,35 @@ public class HttpSessionSecurityContextRepositoryTests {
|
|||||||
@Test
|
@Test
|
||||||
public void redirectCausesEarlySaveOfContext() throws Exception {
|
public void redirectCausesEarlySaveOfContext() throws Exception {
|
||||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||||
|
repo.setSpringSecurityContextKey("imTheContext");
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
|
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
|
||||||
SecurityContextHolder.setContext(repo.loadContext(holder));
|
SecurityContextHolder.setContext(repo.loadContext(holder));
|
||||||
SecurityContextHolder.getContext().setAuthentication(testToken);
|
SecurityContextHolder.getContext().setAuthentication(testToken);
|
||||||
holder.getResponse().sendRedirect("/doesntmatter");
|
holder.getResponse().sendRedirect("/doesntmatter");
|
||||||
assertEquals(SecurityContextHolder.getContext(), request.getSession().getAttribute(SPRING_SECURITY_CONTEXT_KEY));
|
assertEquals(SecurityContextHolder.getContext(), request.getSession().getAttribute("imTheContext"));
|
||||||
assertTrue(((SaveContextOnUpdateOrErrorResponseWrapper)holder.getResponse()).isContextSaved());
|
assertTrue(((SaveContextOnUpdateOrErrorResponseWrapper)holder.getResponse()).isContextSaved());
|
||||||
repo.saveContext(SecurityContextHolder.getContext(), holder.getRequest(), holder.getResponse());
|
repo.saveContext(SecurityContextHolder.getContext(), holder.getRequest(), holder.getResponse());
|
||||||
// Check it's still the same
|
// Check it's still the same
|
||||||
assertEquals(SecurityContextHolder.getContext(), request.getSession().getAttribute(SPRING_SECURITY_CONTEXT_KEY));
|
assertEquals(SecurityContextHolder.getContext(), request.getSession().getAttribute("imTheContext"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void sendErrorCausesEarlySaveOfContext() throws Exception {
|
public void sendErrorCausesEarlySaveOfContext() throws Exception {
|
||||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||||
|
repo.setSpringSecurityContextKey("imTheContext");
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
|
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
|
||||||
SecurityContextHolder.setContext(repo.loadContext(holder));
|
SecurityContextHolder.setContext(repo.loadContext(holder));
|
||||||
SecurityContextHolder.getContext().setAuthentication(testToken);
|
SecurityContextHolder.getContext().setAuthentication(testToken);
|
||||||
holder.getResponse().sendError(404);
|
holder.getResponse().sendError(404);
|
||||||
assertEquals(SecurityContextHolder.getContext(), request.getSession().getAttribute(SPRING_SECURITY_CONTEXT_KEY));
|
assertEquals(SecurityContextHolder.getContext(), request.getSession().getAttribute("imTheContext"));
|
||||||
assertTrue(((SaveContextOnUpdateOrErrorResponseWrapper)holder.getResponse()).isContextSaved());
|
assertTrue(((SaveContextOnUpdateOrErrorResponseWrapper)holder.getResponse()).isContextSaved());
|
||||||
repo.saveContext(SecurityContextHolder.getContext(), holder.getRequest(), holder.getResponse());
|
repo.saveContext(SecurityContextHolder.getContext(), holder.getRequest(), holder.getResponse());
|
||||||
// Check it's still the same
|
// Check it's still the same
|
||||||
assertEquals(SecurityContextHolder.getContext(), request.getSession().getAttribute(SPRING_SECURITY_CONTEXT_KEY));
|
assertEquals(SecurityContextHolder.getContext(), request.getSession().getAttribute("imTheContext"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -188,15 +191,16 @@ public class HttpSessionSecurityContextRepositoryTests {
|
|||||||
@Test
|
@Test
|
||||||
public void contextIsRemovedFromSessionIfCurrentContextIsEmpty() throws Exception {
|
public void contextIsRemovedFromSessionIfCurrentContextIsEmpty() throws Exception {
|
||||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||||
|
repo.setSpringSecurityContextKey("imTheContext");
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
SecurityContext ctxInSession = SecurityContextHolder.createEmptyContext();
|
SecurityContext ctxInSession = SecurityContextHolder.createEmptyContext();
|
||||||
ctxInSession.setAuthentication(testToken);
|
ctxInSession.setAuthentication(testToken);
|
||||||
request.getSession().setAttribute(SPRING_SECURITY_CONTEXT_KEY, ctxInSession);
|
request.getSession().setAttribute("imTheContext", ctxInSession);
|
||||||
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, new MockHttpServletResponse());
|
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, new MockHttpServletResponse());
|
||||||
repo.loadContext(holder);
|
repo.loadContext(holder);
|
||||||
// Save an empty context
|
// Save an empty context
|
||||||
repo.saveContext(SecurityContextHolder.getContext(), holder.getRequest(), holder.getResponse());
|
repo.saveContext(SecurityContextHolder.getContext(), holder.getRequest(), holder.getResponse());
|
||||||
assertNull(request.getSession().getAttribute(SPRING_SECURITY_CONTEXT_KEY));
|
assertNull(request.getSession().getAttribute("imTheContext"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user