SEC-583: Implementation of namespace config for concurrent session support.

Also some minor adjustments to ordering of different http features in schema.
This commit is contained in:
Luke Taylor 2007-10-27 00:28:24 +00:00
parent 334d55b12e
commit d3b165749f
8 changed files with 167 additions and 50 deletions

View File

@ -0,0 +1,70 @@
package org.springframework.security.config;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.concurrent.ConcurrentSessionControllerImpl;
import org.springframework.security.concurrent.ConcurrentSessionFilter;
import org.springframework.security.concurrent.SessionRegistryImpl;
import org.springframework.security.providers.ProviderManager;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Sets up support for concurrent session support control, creating {@link ConcurrentSessionFilter},
* {@link SessionRegistryImpl} and {@link ConcurrentSessionControllerImpl}. The session controller is also registered
* with the default {@link ProviderManager} (which is automatically registered during namespace configuration).
*
* @author Luke Taylor
* @version $Id$
*/
public class ConcurrentSessionsBeanDefinitionParser implements BeanDefinitionParser {
static final String DEFAULT_SESSION_REGISTRY_ID = "_sessionRegistry";
static final String DEFAULT_CONCURRENT_SESSION_FILTER_ID = "_concurrentSessionFilter";
static final String DEFAULT_SESSION_CONTROLLER_ID = "_concurrentSessionController";
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionRegistry beanRegistry = parserContext.getRegistry();
RootBeanDefinition sessionRegistry = new RootBeanDefinition(SessionRegistryImpl.class);
BeanDefinitionBuilder filterBuilder =
BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionFilter.class);
BeanDefinitionBuilder controllerBuilder
= BeanDefinitionBuilder.rootBeanDefinition(ConcurrentSessionControllerImpl.class);
controllerBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(DEFAULT_SESSION_REGISTRY_ID));
filterBuilder.addPropertyValue("sessionRegistry", new RuntimeBeanReference(DEFAULT_SESSION_REGISTRY_ID));
String expiryUrl = element.getAttribute("expiryUrl");
if (StringUtils.hasText(expiryUrl)) {
filterBuilder.addPropertyValue("expiryUrl", expiryUrl);
}
String maxSessions = element.getAttribute("maxSessions");
if (StringUtils.hasText(expiryUrl)) {
controllerBuilder.addPropertyValue("maximumSessions", maxSessions);
}
String exceptionIfMaximumExceeded = element.getAttribute("exceptionIfMaximumExceeded");
if (StringUtils.hasText(expiryUrl)) {
controllerBuilder.addPropertyValue("exceptionIfMaximumExceeded", exceptionIfMaximumExceeded);
}
BeanDefinition controller = controllerBuilder.getBeanDefinition();
beanRegistry.registerBeanDefinition(DEFAULT_SESSION_REGISTRY_ID, sessionRegistry);
beanRegistry.registerBeanDefinition(DEFAULT_SESSION_CONTROLLER_ID, controller);
beanRegistry.registerBeanDefinition(DEFAULT_CONCURRENT_SESSION_FILTER_ID, filterBuilder.getBeanDefinition());
BeanDefinition providerManager = ConfigUtils.registerProviderManagerIfNecessary(parserContext);
providerManager.getPropertyValues().addPropertyValue("sessionController", controller);
return null;
}
}

View File

@ -40,6 +40,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
public static final String DEFAULT_EXCEPTION_TRANSLATION_FILTER_ID = "_exceptionTranslationFilter"; public static final String DEFAULT_EXCEPTION_TRANSLATION_FILTER_ID = "_exceptionTranslationFilter";
public static final String DEFAULT_FILTER_SECURITY_INTERCEPTOR_ID = "_filterSecurityInterceptor"; public static final String DEFAULT_FILTER_SECURITY_INTERCEPTOR_ID = "_filterSecurityInterceptor";
public static final String CONCURRENT_SESSIONS_ELEMENT = "concurrent-session-control";
public static final String LOGOUT_ELEMENT = "logout"; public static final String LOGOUT_ELEMENT = "logout";
public static final String FORM_LOGIN_ELEMENT = "form-login"; public static final String FORM_LOGIN_ELEMENT = "form-login";
public static final String BASIC_AUTH_ELEMENT = "http-basic"; public static final String BASIC_AUTH_ELEMENT = "http-basic";
@ -92,7 +93,12 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
parseInterceptUrls(DomUtils.getChildElementsByTagName(element, "intercept-url"), parseInterceptUrls(DomUtils.getChildElementsByTagName(element, "intercept-url"),
filterChainMap, interceptorFilterInvDefSource); filterChainMap, interceptorFilterInvDefSource);
// TODO: if empty, set a default set a default /**, omitting login url
Element sessionControlElt = DomUtils.getChildElementByTagName(element, CONCURRENT_SESSIONS_ELEMENT);
if (sessionControlElt != null) {
new ConcurrentSessionsBeanDefinitionParser().parse(sessionControlElt, parserContext);
}
BeanDefinitionRegistry registry = parserContext.getRegistry(); BeanDefinitionRegistry registry = parserContext.getRegistry();

View File

@ -1,16 +1,17 @@
namespace beans = "http://www.springframework.org/schema/beans" namespace beans = "http://www.springframework.org/schema/beans"
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0" namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
namespace security = "http://www.springframework.org/schema/security"
datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes" datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes"
#default namespace = "http://www.springframework.org/schema/security" default namespace = "http://www.springframework.org/schema/security"
# targetNamespace="http://www.springframework.org/schema/security"
path-type = path-type =
## Defines the type types of pattern used to specify URL paths. Defaults to "ant" ## Defines the type types of pattern used to specify URL paths. Defaults to "ant"
[ a:defaultValue = "ant" ] attribute pathType {"regex" | "ant"} [ a:defaultValue = "ant" ] attribute pathType {"regex" | "ant"}
autoconfig = autoconfig =
## Provides automatic security configration for a application ## Provides automatic security configration for a application
element autoconfig {autoconfig.attlist, empty} element autoconfig {autoconfig.attlist, empty}
@ -47,7 +48,7 @@ protect.attlist &=
http = http =
## Container element for HTTP security configuration ## Container element for HTTP security configuration
element http {http.attlist, intercept-url+, logout?, form-login?, http-basic? } element http {http.attlist, intercept-url+, form-login?, http-basic?, logout?, concurrent-session-control? }
http.attlist &= http.attlist &=
## Controls the eagerness with which an HTTP session is created. ## Controls the eagerness with which an HTTP session is created.
[ a:defaultValue = "ifRequired" ] attribute createSession {"ifRequired" | "always" | "never" }? [ a:defaultValue = "ifRequired" ] attribute createSession {"ifRequired" | "always" | "never" }?
@ -57,6 +58,11 @@ http.attlist &=
http.attlist &= http.attlist &=
## Whether test URLs should be converted to lower case prior to comparing with defined path patterns. ## Whether test URLs should be converted to lower case prior to comparing with defined path patterns.
[ a:defaultValue = "true" ] attribute lowerCaseComparisons {"true" | "false"}? [ a:defaultValue = "true" ] attribute lowerCaseComparisons {"true" | "false"}?
http.attlist &=
## Optional attribute specifying the ID of the AccessDecisionManager implementation which should be
## used for authorizing HTTP requests.
attribute accessDecisionManager {xsd:string}?
intercept-url = intercept-url =
## Specifies the access attributes and/or filter list for a particular set of URLs. ## Specifies the access attributes and/or filter list for a particular set of URLs.
@ -72,6 +78,9 @@ intercept-url.attlist &=
## The full filter stack (consisting of all defined filters, will be applied to any other paths). ## The full filter stack (consisting of all defined filters, will be applied to any other paths).
intercept-url.attlist &= intercept-url.attlist &=
attribute filters {"none"}? attribute filters {"none"}?
intercept-url.attlist &=
## Used to specify that a URL must be accessed over http or https
attribute requiresChannel {"http" | "https"}?
logout = logout =
element logout {logout.attlist, empty} element logout {logout.attlist, empty}
@ -115,13 +124,16 @@ http-basic =
http-basic.attlist &= http-basic.attlist &=
attribute realm {xsd:string} attribute realm {xsd:string}
concurrent-sessions = concurrent-session-control =
## Adds support for concurrent session control, allowing limits to be placed on the number of sessions a ## Adds support for concurrent session control, allowing limits to be placed on the number of sessions a
## user can have. ## user can have.
element concurrent-sessions {concurrent-sessions.attlist, empty} element concurrent-session-control {concurrent-sessions.attlist, empty}
concurrent-sessions.attlist &= concurrent-sessions.attlist &=
attribute maxSessions {xsd:positiveInteger}? attribute maxSessions {xsd:positiveInteger}?
concurrent-sessions.attlist &=
attribute expiredUrl {xsd:string}?
concurrent-sessions.attlist &=
attribute exceptionIfMaximumExceeded {"true" | "false"}?
authentication-provider = authentication-provider =
element authentication-provider {authentication-provider.attlist, (user-service | jdbc-user-service)} element authentication-provider {authentication-provider.attlist, (user-service | jdbc-user-service)}

View File

@ -1,10 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.springframework.org/schema/security" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://www.springframework.org/schema/security" xmlns:security="http://www.springframework.org/schema/security">
xmlns:xs="http://www.w3.org/2001/XMLSchema" <!-- targetNamespace="http://www.springframework.org/schema/security" -->
targetNamespace="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<!-- default namespace = "http://www.springframework.org/schema/security" -->
<xs:attributeGroup name="path-type"> <xs:attributeGroup name="path-type">
<xs:attribute name="pathType" use="required"> <xs:attribute name="pathType" use="required">
<xs:annotation> <xs:annotation>
@ -29,7 +25,7 @@
<xs:documentation>Sets up an ldap authentication provider, optionally with an embedded ldap server</xs:documentation> <xs:documentation>Sets up an ldap authentication provider, optionally with an embedded ldap server</xs:documentation>
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="ldap.attlist"/> <xs:attributeGroup ref="security:ldap.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="ldap.attlist"> <xs:attributeGroup name="ldap.attlist">
@ -47,7 +43,7 @@
<xs:element name="intercept-methods"> <xs:element name="intercept-methods">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element maxOccurs="unbounded" ref="protect"/> <xs:element maxOccurs="unbounded" ref="security:protect"/>
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
@ -56,7 +52,7 @@
<xs:documentation>Defines a protected method and the access control configuration attributes that apply to it</xs:documentation> <xs:documentation>Defines a protected method and the access control configuration attributes that apply to it</xs:documentation>
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="protect.attlist"/> <xs:attributeGroup ref="security:protect.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="protect.attlist"> <xs:attributeGroup name="protect.attlist">
@ -77,12 +73,13 @@
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element maxOccurs="unbounded" ref="intercept-url"/> <xs:element maxOccurs="unbounded" ref="security:intercept-url"/>
<xs:element minOccurs="0" ref="logout"/> <xs:element minOccurs="0" ref="security:form-login"/>
<xs:element minOccurs="0" ref="form-login"/> <xs:element minOccurs="0" ref="security:http-basic"/>
<xs:element minOccurs="0" ref="http-basic"/> <xs:element minOccurs="0" ref="security:logout"/>
<xs:element minOccurs="0" ref="security:concurrent-session-control"/>
</xs:sequence> </xs:sequence>
<xs:attributeGroup ref="http.attlist"/> <xs:attributeGroup ref="security:http.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="http.attlist"> <xs:attributeGroup name="http.attlist">
@ -120,13 +117,14 @@
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:attribute> </xs:attribute>
<xs:attribute name="accessDecisionManager" type="xs:string"/>
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="intercept-url"> <xs:element name="intercept-url">
<xs:annotation> <xs:annotation>
<xs:documentation>Specifies the access attributes and/or filter list for a particular set of URLs.</xs:documentation> <xs:documentation>Specifies the access attributes and/or filter list for a particular set of URLs.</xs:documentation>
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="intercept-url.attlist"/> <xs:attributeGroup ref="security:intercept-url.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="intercept-url.attlist"> <xs:attributeGroup name="intercept-url.attlist">
@ -143,10 +141,21 @@
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:attribute> </xs:attribute>
<xs:attribute name="requiresChannel">
<xs:annotation>
<xs:documentation>Used to specify that a URL must be accessed over http or https</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="http"/>
<xs:enumeration value="https"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="logout"> <xs:element name="logout">
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="logout.attlist"/> <xs:attributeGroup ref="security:logout.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="logout.attlist"> <xs:attributeGroup name="logout.attlist">
@ -166,7 +175,7 @@
<xs:documentation>Sets up a form login configuration</xs:documentation> <xs:documentation>Sets up a form login configuration</xs:documentation>
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="form-login.attlist"/> <xs:attributeGroup ref="security:form-login.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="form-login.attlist"> <xs:attributeGroup name="form-login.attlist">
@ -187,17 +196,17 @@
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
<xs:element maxOccurs="unbounded" ref="filter-chain"/> <xs:element maxOccurs="unbounded" ref="security:filter-chain"/>
</xs:sequence> </xs:sequence>
<xs:attributeGroup ref="filter-chain-map.attlist"/> <xs:attributeGroup ref="security:filter-chain-map.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="filter-chain-map.attlist"> <xs:attributeGroup name="filter-chain-map.attlist">
<xs:attributeGroup ref="path-type"/> <xs:attributeGroup ref="security:path-type"/>
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="filter-chain"> <xs:element name="filter-chain">
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="filter-chain.attlist"/> <xs:attributeGroup ref="security:filter-chain.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="filter-chain.attlist"> <xs:attributeGroup name="filter-chain.attlist">
@ -209,35 +218,44 @@
<xs:documentation>Adds support for basic authentication</xs:documentation> <xs:documentation>Adds support for basic authentication</xs:documentation>
</xs:annotation> </xs:annotation>
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="http-basic.attlist"/> <xs:attributeGroup ref="security:http-basic.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="http-basic.attlist"> <xs:attributeGroup name="http-basic.attlist">
<xs:attribute name="realm" use="required" type="xs:string"/> <xs:attribute name="realm" use="required" type="xs:string"/>
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="concurrent-sessions"> <xs:element name="concurrent-session-control">
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="concurrent-sessions.attlist"/> <xs:attributeGroup ref="security:concurrent-sessions.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="concurrent-sessions.attlist"> <xs:attributeGroup name="concurrent-sessions.attlist">
<xs:attribute name="maxSessions" type="xs:positiveInteger"/> <xs:attribute name="maxSessions" type="xs:positiveInteger"/>
<xs:attribute name="expiredUrl" type="xs:string"/>
<xs:attribute name="exceptionIfMaximumExceeded">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="authentication-provider"> <xs:element name="authentication-provider">
<xs:complexType> <xs:complexType>
<xs:choice> <xs:choice>
<xs:element ref="user-service"/> <xs:element ref="security:user-service"/>
<xs:element ref="jdbc-user-service"/> <xs:element ref="security:jdbc-user-service"/>
</xs:choice> </xs:choice>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="user-service"> <xs:element name="user-service">
<xs:complexType> <xs:complexType>
<xs:choice> <xs:choice>
<xs:element minOccurs="0" maxOccurs="unbounded" ref="user"/> <xs:element minOccurs="0" maxOccurs="unbounded" ref="security:user"/>
<xs:element ref="jdbc-user-service"/> <xs:element ref="security:jdbc-user-service"/>
</xs:choice> </xs:choice>
<xs:attributeGroup ref="user-service.attlist"/> <xs:attributeGroup ref="security:user-service.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="user-service.attlist"> <xs:attributeGroup name="user-service.attlist">
@ -245,7 +263,7 @@
</xs:attributeGroup> </xs:attributeGroup>
<xs:element name="user"> <xs:element name="user">
<xs:complexType> <xs:complexType>
<xs:attributeGroup ref="user.attlist"/> <xs:attributeGroup ref="security:user.attlist"/>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:attributeGroup name="user.attlist"> <xs:attributeGroup name="user.attlist">

View File

@ -5,6 +5,7 @@ import static org.junit.Assert.assertTrue;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.concurrent.ConcurrentSessionFilter;
import org.springframework.security.context.HttpSessionContextIntegrationFilter; import org.springframework.security.context.HttpSessionContextIntegrationFilter;
import org.springframework.security.intercept.web.FilterSecurityInterceptor; import org.springframework.security.intercept.web.FilterSecurityInterceptor;
import org.springframework.security.ui.ExceptionTranslationFilter; import org.springframework.security.ui.ExceptionTranslationFilter;
@ -53,10 +54,11 @@ public class HttpSecurityBeanDefinitionParserTests {
List filterList = filterChainProxy.getFilters("/someurl"); List filterList = filterChainProxy.getFilters("/someurl");
assertTrue("Expected 7 filterList in chain", filterList.size() == 7); assertTrue("Expected 8 filters in chain", filterList.size() == 8);
Iterator filters = filterList.iterator(); Iterator filters = filterList.iterator();
assertTrue(filters.next() instanceof ConcurrentSessionFilter);
assertTrue(filters.next() instanceof HttpSessionContextIntegrationFilter); assertTrue(filters.next() instanceof HttpSessionContextIntegrationFilter);
assertTrue(filters.next() instanceof LogoutFilter); assertTrue(filters.next() instanceof LogoutFilter);
assertTrue(filters.next() instanceof AuthenticationProcessingFilter); assertTrue(filters.next() instanceof AuthenticationProcessingFilter);

View File

@ -11,14 +11,16 @@ http://www.springframework.org/schema/security http://www.springframework.org/sc
<security:intercept-url pattern="/somepath" access="ROLE_SPECIAL,ROLE_USER" /> <security:intercept-url pattern="/somepath" access="ROLE_SPECIAL,ROLE_USER" />
<security:intercept-url pattern="/**" access="ROLE_USER" /> <security:intercept-url pattern="/**" access="ROLE_USER" />
<!-- Default logout configuration -->
<security:logout logoutUrl="/j_spring_security_logout" logoutSuccessUrl="/" invalidateSession="true" />
<!-- Default form login configuration. Will create filter and entry point --> <!-- Default form login configuration. Will create filter and entry point -->
<security:form-login loginUrl="/j_spring_security_check" /> <security:form-login loginUrl="/j_spring_security_check" />
<!-- Default basic auth configuration. Will create filter and entry point --> <!-- Default basic auth configuration. Will create filter and entry point -->
<security:http-basic realm="NamespaceTestRealm" /> <security:http-basic realm="NamespaceTestRealm" />
<!-- Default logout configuration -->
<security:logout logoutUrl="/j_spring_security_logout" logoutSuccessUrl="/" invalidateSession="true" />
<security:concurrent-session-control maxSessions="1"/>
</security:http> </security:http>
<security:authentication-provider> <security:authentication-provider>

View File

@ -12,16 +12,15 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd"> http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
<security:autoconfig />
<security:http> <security:http>
<security:intercept-url pattern="/secure/extreme/**" access="ROLE_SUPERVISOR"/> <security:intercept-url pattern="/secure/extreme/**" access="ROLE_SUPERVISOR"/>
<security:intercept-url pattern="/secure/**" access="IS_AUTHENTICATED_REMEMBERED" /> <security:intercept-url pattern="/secure/**" access="IS_AUTHENTICATED_REMEMBERED" />
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" /> <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:logout />
<security:form-login /> <security:form-login />
<security:http-basic realm="SpringSecurityTutorialApp" /> <security:http-basic realm="SpringSecurityTutorialApp" />
<security:logout />
<security:concurrent-session-control maxSessions="1" exceptionIfMaximumExceeded="true"/>
</security:http> </security:http>

View File

@ -47,6 +47,14 @@
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> </listener>
<!--
- Publishes events for session creation and destruction through the application
- context. Optional unless concurrent session control is being used.
-->
<listener>
<listener-class>org.springframework.security.ui.session.HttpSessionEventPublisher</listener-class>
</listener>
<welcome-file-list> <welcome-file-list>
<welcome-file>index.jsp</welcome-file> <welcome-file>index.jsp</welcome-file>
</welcome-file-list> </welcome-file-list>