SEC-821: Added support for eternal session registry and concurrent session controller to the 2.0.2 namespace.

This commit is contained in:
Luke Taylor 2008-05-27 13:14:21 +00:00
parent 8b5bbe3800
commit d63536cc0d
6 changed files with 164 additions and 49 deletions

View File

@ -3,28 +3,41 @@ package org.springframework.security.config;
import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext; import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.w3c.dom.Element; import org.w3c.dom.Element;
/** /**
* Just registers an alias name for the default ProviderManager used by the namespace * Registers an alias name for the default ProviderManager used by the namespace
* configuration, allowing users to reference it in their beans and clearly see where the name is * configuration, allowing users to reference it in their beans and clearly see where the name is
* coming from. * coming from. Also allows the ConcurrentSessionController to be set on the ProviderManager.
* *
* @author Luke Taylor * @author Luke Taylor
* @version $Id$ * @version $Id$
*/ */
public class AuthenticationManagerBeanDefinitionParser implements BeanDefinitionParser { public class AuthenticationManagerBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_SESSION_CONTROLLER_REF = "session-controller-ref";
private static final String ATT_ALIAS = "alias"; private static final String ATT_ALIAS = "alias";
public BeanDefinition parse(Element element, ParserContext parserContext) { public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinition authManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
String alias = element.getAttribute(ATT_ALIAS); String alias = element.getAttribute(ATT_ALIAS);
if (!StringUtils.hasText(alias)) { if (!StringUtils.hasText(alias)) {
parserContext.getReaderContext().error(ATT_ALIAS + " is required.", element ); parserContext.getReaderContext().error(ATT_ALIAS + " is required.", element );
} }
String sessionControllerRef = element.getAttribute(ATT_SESSION_CONTROLLER_REF);
if (StringUtils.hasText(sessionControllerRef)) {
ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext,
BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
authManager.getPropertyValues().addPropertyValue("sessionController",
new RuntimeBeanReference(sessionControllerRef));
}
parserContext.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias); parserContext.getRegistry().registerAlias(BeanIds.AUTHENTICATION_MANAGER, alias);
return null; return null;

View File

@ -30,6 +30,7 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
static final String ATT_MAX_SESSIONS = "max-sessions"; static final String ATT_MAX_SESSIONS = "max-sessions";
static final String ATT_EXCEPTION_IF_MAX_EXCEEDED = "exception-if-maximum-exceeded"; static final String ATT_EXCEPTION_IF_MAX_EXCEEDED = "exception-if-maximum-exceeded";
static final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias"; static final String ATT_SESSION_REGISTRY_ALIAS = "session-registry-alias";
static final String ATT_SESSION_REGISTRY_REF = "session-registry-ref";
public BeanDefinition parse(Element element, ParserContext parserContext) { public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef = CompositeComponentDefinition compositeDef =
@ -38,19 +39,30 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
BeanDefinitionRegistry beanRegistry = parserContext.getRegistry(); BeanDefinitionRegistry beanRegistry = parserContext.getRegistry();
String sessionRegistryId = element.getAttribute(ATT_SESSION_REGISTRY_REF);
if (!StringUtils.hasText(sessionRegistryId)) {
RootBeanDefinition sessionRegistry = new RootBeanDefinition(SessionRegistryImpl.class); RootBeanDefinition sessionRegistry = new RootBeanDefinition(SessionRegistryImpl.class);
beanRegistry.registerBeanDefinition(BeanIds.SESSION_REGISTRY, sessionRegistry);
parserContext.registerComponent(new BeanComponentDefinition(sessionRegistry, BeanIds.SESSION_REGISTRY));
sessionRegistryId = BeanIds.SESSION_REGISTRY;
} else {
// Register the default ID as an alias so that things like session fixation filter can access it
beanRegistry.registerAlias(sessionRegistryId, BeanIds.SESSION_REGISTRY);
}
String registryAlias = element.getAttribute(ATT_SESSION_REGISTRY_ALIAS);
if (StringUtils.hasText(registryAlias)) {
beanRegistry.registerAlias(sessionRegistryId, registryAlias);
}
BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder filterBuilder =
BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionFilter.class); BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionFilter.class);
BeanDefinitionBuilder controllerBuilder filterBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(sessionRegistryId));
= BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControllerImpl.class);
controllerBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(BeanIds.SESSION_REGISTRY));
filterBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(BeanIds.SESSION_REGISTRY));
Object source = parserContext.extractSource(element); Object source = parserContext.extractSource(element);
filterBuilder.setSource(source); filterBuilder.setSource(source);
filterBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); filterBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
controllerBuilder.setSource(source);
controllerBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String expiryUrl = element.getAttribute(ATT_EXPIRY_URL); String expiryUrl = element.getAttribute(ATT_EXPIRY_URL);
@ -59,6 +71,12 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
filterBuilder.addPropertyValue("expiredUrl", expiryUrl); filterBuilder.addPropertyValue("expiredUrl", expiryUrl);
} }
BeanDefinitionBuilder controllerBuilder
= BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControllerImpl.class);
controllerBuilder.setSource(source);
controllerBuilder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
controllerBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(sessionRegistryId));
String maxSessions = element.getAttribute(ATT_MAX_SESSIONS); String maxSessions = element.getAttribute(ATT_MAX_SESSIONS);
if (StringUtils.hasText(maxSessions)) { if (StringUtils.hasText(maxSessions)) {
@ -72,13 +90,6 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
} }
BeanDefinition controller = controllerBuilder.getBeanDefinition(); BeanDefinition controller = controllerBuilder.getBeanDefinition();
beanRegistry.registerBeanDefinition(BeanIds.SESSION_REGISTRY, sessionRegistry);
parserContext.registerComponent(new BeanComponentDefinition(sessionRegistry, BeanIds.SESSION_REGISTRY));
String registryAlias = element.getAttribute(ATT_SESSION_REGISTRY_ALIAS);
if (StringUtils.hasText(registryAlias)) {
beanRegistry.registerAlias(BeanIds.SESSION_REGISTRY, registryAlias);
}
beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_CONTROLLER, controller); beanRegistry.registerBeanDefinition(BeanIds.CONCURRENT_SESSION_CONTROLLER, controller);
parserContext.registerComponent(new BeanComponentDefinition(controller, BeanIds.CONCURRENT_SESSION_CONTROLLER)); parserContext.registerComponent(new BeanComponentDefinition(controller, BeanIds.CONCURRENT_SESSION_CONTROLLER));
@ -86,9 +97,7 @@ public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionPar
parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(), BeanIds.CONCURRENT_SESSION_FILTER)); parserContext.registerComponent(new BeanComponentDefinition(filterBuilder.getBeanDefinition(), BeanIds.CONCURRENT_SESSION_FILTER));
ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER)); ConfigUtils.addHttpFilter(parserContext, new RuntimeBeanReference(BeanIds.CONCURRENT_SESSION_FILTER));
BeanDefinition providerManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext); ConfigUtils.setSessionControllerOnAuthenticationManager(parserContext, BeanIds.CONCURRENT_SESSION_CONTROLLER, element);
providerManager.getPropertyValues().addPropertyValue("sessionController", controller);
parserContext.popAndRegisterContainingComponent(); parserContext.popAndRegisterContainingComponent();

View File

@ -7,6 +7,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.config.RuntimeBeanReference;
@ -22,6 +23,7 @@ import org.springframework.security.vote.AffirmativeBased;
import org.springframework.security.vote.AuthenticatedVoter; import org.springframework.security.vote.AuthenticatedVoter;
import org.springframework.security.vote.RoleVoter; import org.springframework.security.vote.RoleVoter;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/** /**
* Utility methods used internally by the Spring Security namespace configuration code. * Utility methods used internally by the Spring Security namespace configuration code.
@ -168,4 +170,17 @@ public abstract class ConfigUtils {
} }
pc.getReaderContext().warning(url + " is not a valid redirect URL (must start with '/' or http(s))", source); pc.getReaderContext().warning(url + " is not a valid redirect URL (must start with '/' or http(s))", source);
} }
static void setSessionControllerOnAuthenticationManager(ParserContext pc, String beanName, Element sourceElt) {
BeanDefinition authManager = registerProviderManagerIfNecessary(pc);
PropertyValue pv = authManager.getPropertyValues().getPropertyValue("sessionController");
if (pv != null && pv.getValue() != null) {
pc.getReaderContext().error("A session controller has already been set on the authentication manager. " +
"The <concurrent-session-control> element isn't compatible with a custom session controller",
pc.extractSource(sourceElt));
}
authManager.getPropertyValues().addPropertyValue("sessionController", new RuntimeBeanReference(beanName));
}
} }

View File

@ -335,13 +335,17 @@ concurrent-session-control =
concurrent-sessions.attlist &= concurrent-sessions.attlist &=
attribute max-sessions {xsd:positiveInteger}? attribute max-sessions {xsd:positiveInteger}?
concurrent-sessions.attlist &= concurrent-sessions.attlist &=
## The URL a user will be redirected to if they attempt to use a session which has been "expired" by the concurrent session controller.
attribute expired-url {xsd:string}? attribute expired-url {xsd:string}?
concurrent-sessions.attlist &= concurrent-sessions.attlist &=
## Specifies that an exception should be raised when a user attempts to login twice. The default behaviour is to expire the original session.
attribute exception-if-maximum-exceeded {boolean}? attribute exception-if-maximum-exceeded {boolean}?
concurrent-sessions.attlist &= concurrent-sessions.attlist &=
## Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration ## Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration
attribute session-registry-alias {xsd:string}? attribute session-registry-alias {xsd:string}?
concurrent-sessions.attlist &=
## A reference to an external SessionRegistry implementation which will be used in place of the standard one.
attribute session-registry-ref {xsd:string}?
remember-me = remember-me =
## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach. ## Sets up remember-me authentication. If used with the "key" attribute (or no attributes) the cookie-only implementation will be used. Specifying "token-repository-ref" or "remember-me-data-source-ref" will use the more secure, persisten token approach.
@ -408,11 +412,15 @@ x509.attlist &=
user-service-ref? user-service-ref?
authentication-manager = authentication-manager =
## If you are using namespace configuration with Spring Security, an AuthenticationManager will automatically be registered. This element simple allows you to define an alias to allow you to reference the authentication-manager in your own beans. ## If you are using namespace configuration with Spring Security, an AuthenticationManager will automatically be registered. This element allows you to define an alias to allow you to reference the authentication-manager in your own beans.
element authentication-manager {authman.attlist} element authentication-manager {authman.attlist}
## The alias you wish to use for the AuthenticationManager bean
authman.attlist &= authman.attlist &=
## The alias you wish to use for the AuthenticationManager bean
attribute alias {xsd:ID} attribute alias {xsd:ID}
authman.attlist &=
## Allows the session controller to be set on the internal AuthenticationManager. This should not be used with the <concurrent-session-control /> element
attribute session-controller-ref {xsd:string}?
authentication-provider = authentication-provider =
## Indicates that the contained user-service should be used as an authentication source. ## Indicates that the contained user-service should be used as an authentication source.

View File

@ -489,7 +489,16 @@
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element maxOccurs="unbounded" ref="security:protect"/> <xs:element maxOccurs="unbounded" name="protect">
<xs:annotation>
<xs:documentation>Defines a protected method and the access control configuration
attributes that apply to it. We strongly advise you NOT to mix "protect" declarations
with any services provided "global-method-security".</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="security:protect.attlist"/>
</xs:complexType>
</xs:element>
</xs:sequence> </xs:sequence>
<xs:attributeGroup ref="security:intercept-methods.attlist"/> <xs:attributeGroup ref="security:intercept-methods.attlist"/>
</xs:complexType> </xs:complexType>
@ -502,16 +511,6 @@
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="protect">
<xs:annotation>
<xs:documentation>Defines a protected method and the access control configuration attributes
that apply to it. We strongly advise you NOT to mix "protect" declarations with any services
provided "global-method-security".</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="security:protect.attlist"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="protect.attlist"> <xs:attributeGroup name="protect.attlist">
<xs:attribute name="method" use="required" type="xs:string"> <xs:attribute name="method" use="required" type="xs:string">
<xs:annotation> <xs:annotation>
@ -1014,14 +1013,30 @@
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="concurrent-sessions.attlist"> <xs:attributeGroup name="concurrent-sessions.attlist">
<xs:attribute name="max-sessions" type="xs:positiveInteger"/> <xs:attribute name="max-sessions" type="xs:positiveInteger"/>
<xs:attribute name="expired-url" type="xs:string"/> <xs:attribute name="expired-url" type="xs:string">
<xs:attribute name="exception-if-maximum-exceeded" type="security:boolean"/> <xs:annotation>
<xs:documentation>The URL a user will be redirected to if they attempt to use a session
which has been "expired" by the concurrent session controller.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="exception-if-maximum-exceeded" type="security:boolean">
<xs:annotation>
<xs:documentation>Specifies that an exception should be raised when a user attempts to login
twice. The default behaviour is to expire the original session.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="session-registry-alias" type="xs:string"> <xs:attribute name="session-registry-alias" type="xs:string">
<xs:annotation> <xs:annotation>
<xs:documentation>Allows you to define an alias for the SessionRegistry bean in order to <xs:documentation>Allows you to define an alias for the SessionRegistry bean in order to
access it in your own configuration</xs:documentation> access it in your own configuration</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
<xs:attribute name="session-registry-ref" type="xs:string">
<xs:annotation>
<xs:documentation>A reference to an external SessionRegistry implementation which will be
used in place of the standard one. </xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:attributeGroup name="remember-me.attlist"> <xs:attributeGroup name="remember-me.attlist">
<xs:attribute name="key" type="xs:string"> <xs:attribute name="key" type="xs:string">
@ -1130,8 +1145,8 @@
<xs:element name="authentication-manager"> <xs:element name="authentication-manager">
<xs:annotation> <xs:annotation>
<xs:documentation>If you are using namespace configuration with Spring Security, an <xs:documentation>If you are using namespace configuration with Spring Security, an
AuthenticationManager will automatically be registered. This element simple allows you to AuthenticationManager will automatically be registered. This element allows you to define an
define an alias to allow you to reference the authentication-manager in your own beans. alias to allow you to reference the authentication-manager in your own beans.
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
@ -1139,11 +1154,19 @@
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="authman.attlist"> <xs:attributeGroup name="authman.attlist">
<xs:attribute name="alias" use="required" type="xs:ID">
<xs:annotation> <xs:annotation>
<xs:documentation>The alias you wish to use for the AuthenticationManager <xs:documentation>The alias you wish to use for the AuthenticationManager
bean</xs:documentation> bean</xs:documentation>
</xs:annotation> </xs:annotation>
<xs:attribute name="alias" use="required" type="xs:ID"/> </xs:attribute>
<xs:attribute name="session-controller-ref" type="xs:string">
<xs:annotation>
<xs:documentation>Allows the session controller to be set on the internal
AuthenticationManager. This should not be used with the &lt;concurrent-session-control
/&gt; element</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="authentication-provider"> <xs:element name="authentication-provider">
<xs:annotation> <xs:annotation>

View File

@ -8,7 +8,6 @@ import java.util.List;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
@ -40,7 +39,6 @@ import org.springframework.security.ui.rememberme.NullRememberMeServices;
import org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices; import org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices;
import org.springframework.security.ui.rememberme.RememberMeProcessingFilter; import org.springframework.security.ui.rememberme.RememberMeProcessingFilter;
import org.springframework.security.ui.rememberme.RememberMeServices; import org.springframework.security.ui.rememberme.RememberMeServices;
import org.springframework.security.ui.rememberme.TokenBasedRememberMeServices;
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter; import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter; import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
import org.springframework.security.util.FieldUtils; import org.springframework.security.util.FieldUtils;
@ -413,6 +411,55 @@ public class HttpSecurityBeanDefinitionParserTests {
assertNotNull(appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER)); assertNotNull(appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER));
} }
@Test
public void externalSessionRegistryBeanIsConfiguredCorrectly() throws Exception {
setContext(
"<http auto-config='true'>" +
" <concurrent-session-control session-registry-ref='seshRegistry' />" +
"</http>" +
"<b:bean id='seshRegistry' class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
AUTH_PROVIDER_XML);
Object sessionRegistry = appContext.getBean("seshRegistry");
Object sessionRegistryFromFilter = FieldUtils.getFieldValue(
appContext.getBean(BeanIds.CONCURRENT_SESSION_FILTER),"sessionRegistry");
Object sessionRegistryFromController = FieldUtils.getFieldValue(
appContext.getBean(BeanIds.CONCURRENT_SESSION_CONTROLLER),"sessionRegistry");
Object sessionRegistryFromFixationFilter = FieldUtils.getFieldValue(
appContext.getBean(BeanIds.SESSION_FIXATION_PROTECTION_FILTER),"sessionRegistry");
assertSame(sessionRegistry, sessionRegistryFromFilter);
assertSame(sessionRegistry, sessionRegistryFromController);
assertSame(sessionRegistry, sessionRegistryFromFixationFilter);
}
@Test(expected=BeanDefinitionParsingException.class)
public void concurrentSessionSupportCantBeUsedWithIndependentControllerBean() throws Exception {
setContext(
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" +
"<http auto-config='true'>" +
" <concurrent-session-control session-registry-alias='seshRegistry' expired-url='/expired'/>" +
"</http>" +
"<b:bean id='sc' class='org.springframework.security.concurrent.ConcurrentSessionControllerImpl'>" +
" <b:property name='sessionRegistry'>" +
" <b:bean class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
" </b:property>" +
"</b:bean>" + AUTH_PROVIDER_XML);
}
@Test(expected=BeanDefinitionParsingException.class)
public void concurrentSessionSupportCantBeUsedWithIndependentControllerBean2() throws Exception {
setContext(
"<http auto-config='true'>" +
" <concurrent-session-control session-registry-alias='seshRegistry' expired-url='/expired'/>" +
"</http>" +
"<b:bean id='sc' class='org.springframework.security.concurrent.ConcurrentSessionControllerImpl'>" +
" <b:property name='sessionRegistry'>" +
" <b:bean class='org.springframework.security.concurrent.SessionRegistryImpl'/>" +
" </b:property>" +
"</b:bean>" +
"<authentication-manager alias='authManager' session-controller-ref='sc'/>" + AUTH_PROVIDER_XML);
}
@Test(expected=ConcurrentLoginException.class) @Test(expected=ConcurrentLoginException.class)
public void concurrentSessionMaxSessionsIsCorrectlyConfigured() throws Exception { public void concurrentSessionMaxSessionsIsCorrectlyConfigured() throws Exception {
setContext( setContext(