SEC-1168: Added filter-security-metadat-source to namespace.

This commit is contained in:
Luke Taylor 2009-06-08 12:59:13 +00:00
parent b50d37fa66
commit 66f7e8bcc8
14 changed files with 2001 additions and 2056 deletions

View File

@ -44,6 +44,8 @@ public abstract class Elements {
public static final String CUSTOM_AUTH_PROVIDER = "custom-authentication-provider";
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
public static final String X509 = "x509";
public static final String FILTER_SECURITY_METADATA_SOURCE = "filter-security-metadata-source";
@Deprecated
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
}

View File

@ -409,8 +409,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
new DefaultFilterInvocationSecurityMetadataSource(matcher, channelRequestMap);
channelFilterInvDefSource.setStripQueryStringFromUrls(matcher instanceof AntUrlPathMatcher);
channelFilter.getPropertyValues().addPropertyValue("filterInvocationSecurityMetadataSource",
channelFilterInvDefSource);
channelFilter.getPropertyValues().addPropertyValue("securityMetadataSource", channelFilterInvDefSource);
RootBeanDefinition channelDecisionManager = new RootBeanDefinition(ChannelDecisionManagerImpl.class);
ManagedList channelProcessors = new ManagedList(3);
RootBeanDefinition secureChannelProcessor = new RootBeanDefinition(SecureChannelProcessor.class);

View File

@ -12,6 +12,7 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
*/
public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
@SuppressWarnings("deprecation")
public void init() {
// Parsers
registerBeanDefinitionParser(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());
@ -24,12 +25,13 @@ public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
registerBeanDefinitionParser(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
registerBeanDefinitionParser(Elements.FILTER_INVOCATION_DEFINITION_SOURCE, new FilterInvocationSecurityMetadataSourceBeanDefinitionParser());
registerBeanDefinitionParser(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceBeanDefinitionParser());
// Decorators
registerBeanDefinitionDecorator(Elements.INTERCEPT_METHODS, new InterceptMethodsBeanDefinitionDecorator());
registerBeanDefinitionDecorator(Elements.FILTER_CHAIN_MAP, new FilterChainMapBeanDefinitionDecorator());
registerBeanDefinitionDecorator(Elements.CUSTOM_FILTER, new OrderedFilterBeanDefinitionDecorator());
registerBeanDefinitionDecorator(Elements.CUSTOM_AUTH_PROVIDER, new CustomAuthenticationProviderBeanDefinitionDecorator());
registerBeanDefinitionDecorator(Elements.CUSTOM_AFTER_INVOCATION_PROVIDER, new CustomAfterInvocationProviderBeanDefinitionDecorator());
registerBeanDefinitionDecorator(Elements.CUSTOM_AFTER_INVOCATION_PROVIDER, new CustomAfterInvocationProviderBeanDefinitionDecorator());
}
}

View File

@ -367,20 +367,24 @@ filter-chain.attlist &=
filter-chain.attlist &=
attribute filters {xsd:token}
filter-invocation-definition-source =
## Used to explicitly configure a FilterInvocationDefinitionSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
element filter-invocation-definition-source {fids.attlist, intercept-url+}
fids.attlist &=
filter-security-metadata-source =
## Used to explicitly configure a FilterSecurityMetadataSource bean for use with a FilterSecurityInterceptor. Usually only needed if you are configuring a FilterChainProxy explicitly, rather than using the <http> element. The intercept-url elements used should only contain pattern, method and access attributes. Any others will result in a configuration error.
element filter-security-metadata-source {fsmds.attlist, intercept-url+}
fsmds.attlist &=
use-expressions?
fids.attlist &=
fsmds.attlist &=
id?
fids.attlist &=
fsmds.attlist &=
## as for http element
attribute lowercase-comparisons {boolean}?
fids.attlist &=
fsmds.attlist &=
## as for http element
path-type?
filter-invocation-definition-source =
## Deprecated synonym for filter-security-metadata-source
element filter-invocation-definition-source {fsmds.attlist, intercept-url+}
http-basic =
## Adds support for basic authentication (this is an element to permit future expansion, such as supporting an "ignoreFailure" attribute)
element http-basic {empty}

View File

@ -10,7 +10,7 @@
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="elts-to-inline">
<xsl:text>,access-denied-handler,anonymous,concurrent-session-control,filter-chain,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,pre-post-annotation-handling,pre-invocation-advice,post-invocation-advice,invocation-attribute-factory,remember-me,salt-source,x509,</xsl:text>
<xsl:text>,access-denied-handler,anonymous,concurrent-session-control,user,port-mapping,openid-login,expression-handler,filter-chain,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,pre-post-annotation-handling,pre-invocation-advice,post-invocation-advice,invocation-attribute-factory,remember-me,salt-source,x509,</xsl:text>
</xsl:variable>
<xsl:template match="xs:element">

View File

@ -23,7 +23,7 @@ import org.w3c.dom.Element;
* @author Luke Taylor
* @version $Id$
*/
public class FilterInvocationSecurityMetadataSourceBeanDefinitionParserTests {
public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
private AbstractXmlApplicationContext appContext;
@After
@ -46,9 +46,9 @@ public class FilterInvocationSecurityMetadataSourceBeanDefinitionParserTests {
@Test
public void parsingMinimalConfigurationIsSuccessful() {
setContext(
"<filter-invocation-definition-source id='fids'>" +
"<filter-security-metadata-source id='fids'>" +
" <intercept-url pattern='/**' access='ROLE_A'/>" +
"</filter-invocation-definition-source>");
"</filter-security-metadata-source>");
DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) appContext.getBean("fids");
List<? extends ConfigAttribute> cad = fids.getAttributes(createFilterInvocation("/anything", "GET"));
assertNotNull(cad);
@ -61,11 +61,11 @@ public class FilterInvocationSecurityMetadataSourceBeanDefinitionParserTests {
"<http auto-config='true'/>" +
"<b:bean id='fsi' class='org.springframework.security.web.access.intercept.FilterSecurityInterceptor' autowire='byType'>" +
" <b:property name='securityMetadataSource'>" +
" <filter-invocation-definition-source>" +
" <filter-security-metadata-source>" +
" <intercept-url pattern='/secure/extreme/**' access='ROLE_SUPERVISOR'/>" +
" <intercept-url pattern='/secure/**' access='ROLE_USER'/>" +
" <intercept-url pattern='/**' access='ROLE_USER'/>" +
" </filter-invocation-definition-source>" +
" </filter-security-metadata-source>" +
" </b:property>" +
"</b:bean>" + ConfigTestUtils.AUTH_PROVIDER_XML);

View File

@ -16,10 +16,17 @@
<global-method-security run-as-manager-ref="myRunAsManager">
<pre-post-annotation-handling>
<
<invocation-attribute-factory ref=""/>
<pre-invocation-advice ref=""/>
<post-invocation-advice ref=""/>
</pre-post-annotation-handling>
</global-method-security>
<filter-security-metadata-source>
<intercept-url pattern=""/>
</filter-security-metadata-source>
<http>
<access-denied-handler error-page="/go-away.html"/>
<intercept-url pattern="/**" access="ROLE_USER" />

View File

@ -1,47 +1,41 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="anonymous">
<info><title>Anonymous Authentication</title></info>
<section xml:id="anonymous-overview">
<info><title>Overview</title></info>
<para>Particularly in the case of web request URI security, sometimes
it is more convenient to assign configuration attributes against every
possible secure object invocation. Put differently, sometimes it is
nice to say <literal>ROLE_SOMETHING</literal> is required by default
and only allow certain exceptions to this rule, such as for login,
logout and home pages of an application. There are also other
situations where anonymous authentication would be desired, such as
when an auditing interceptor queries the
<classname>SecurityContextHolder</classname> to identify which principal
was responsible for a given operation. Such classes can be authored
with more robustness if they know the
<classname>SecurityContextHolder</classname> always contains an
<interfacename>Authentication</interfacename> object, and never
<literal>null</literal>.</para>
</section>
<section xml:id="anonymous-config">
<info><title>Configuration</title></info>
<para>Spring Security provides three classes that together provide an
anonymous authentication feature.
<literal>AnonymousAuthenticationToken</literal> is an implementation
of <interfacename>Authentication</interfacename>, and stores the
<interfacename>GrantedAuthority</interfacename>[]s which apply to the anonymous
principal. There is a corresponding
<literal>AnonymousAuthenticationProvider</literal>, which is chained
into the <literal>ProviderManager</literal> so that
<literal>AnonymousAuthenticationTokens</literal> are accepted.
Finally, there is an AnonymousProcessingFilter, which is chained after
the normal authentication mechanisms and automatically add an
<literal>AnonymousAuthenticationToken</literal> to the
<classname>SecurityContextHolder</classname> if there is no existing
<interfacename>Authentication</interfacename> held there. The definition of the
filter and authentication provider appears as follows:</para>
<para><programlisting>
<info>
<title>Anonymous Authentication</title>
</info>
<section xml:id="anonymous-overview">
<info>
<title>Overview</title>
</info>
<para>Particularly in the case of web request URI security, sometimes it is more convenient
to assign configuration attributes against every possible secure object invocation. Put
differently, sometimes it is nice to say <literal>ROLE_SOMETHING</literal> is required
by default and only allow certain exceptions to this rule, such as for login, logout and
home pages of an application. There are also other situations where anonymous
authentication would be desired, such as when an auditing interceptor queries the
<classname>SecurityContextHolder</classname> to identify which principal was
responsible for a given operation. Such classes can be authored with more robustness if
they know the <classname>SecurityContextHolder</classname> always contains an
<interfacename>Authentication</interfacename> object, and never
<literal>null</literal>.</para>
</section>
<section xml:id="anonymous-config">
<info>
<title>Configuration</title>
</info>
<para>Spring Security provides three classes that together provide an anonymous
authentication feature. <literal>AnonymousAuthenticationToken</literal> is an
implementation of <interfacename>Authentication</interfacename>, and stores the
<interfacename>GrantedAuthority</interfacename>[]s which apply to the anonymous
principal. There is a corresponding <literal>AnonymousAuthenticationProvider</literal>,
which is chained into the <literal>ProviderManager</literal> so that
<literal>AnonymousAuthenticationTokens</literal> are accepted. Finally, there is an
AnonymousProcessingFilter, which is chained after the normal authentication mechanisms
and automatically add an <literal>AnonymousAuthenticationToken</literal> to the
<classname>SecurityContextHolder</classname> if there is no existing
<interfacename>Authentication</interfacename> held there. The definition of the
filter and authentication provider appears as follows:</para>
<para>
<programlisting>
<![CDATA[
<bean id="anonymousProcessingFilter"
class="org.springframework.security.web.authentication.AnonymousProcessingFilter">
@ -53,53 +47,44 @@
class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="foobar"/>
</bean>]]>
</programlisting></para>
<para>The <literal>key</literal> is shared between the filter and
authentication provider, so that tokens created by the former are
accepted by the latter. The <literal>userAttribute</literal> is
expressed in the form of
<literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>.
This is the same syntax as used after the equals sign for
<literal>InMemoryDaoImpl</literal>'s <literal>userMap</literal>
property.</para>
<para>As explained earlier, the benefit of anonymous authentication is
that all URI patterns can have security applied to them. For
example:</para>
<para><programlisting>
</programlisting>
</para>
<para>The <literal>key</literal> is shared between the filter and authentication provider,
so that tokens created by the former are accepted by the latter. The
<literal>userAttribute</literal> is expressed in the form of
<literal>usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]</literal>.
This is the same syntax as used after the equals sign for
<literal>InMemoryDaoImpl</literal>'s <literal>userMap</literal> property.</para>
<para>As explained earlier, the benefit of anonymous authentication is that all URI patterns
can have security applied to them. For example:</para>
<para><programlisting>
<![CDATA[
<bean id="filterInvocationInterceptor"
class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
<property name="objectDefinitionSource">
<security:filter-invocation-definition-source>
<property name="securityMetadata">
<security:filter-security-metadata-source>
<security:intercept-url pattern='/index.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/hello.htm' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/logoff.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/login.jsp' access='ROLE_ANONYMOUS,ROLE_USER'/>
<security:intercept-url pattern='/**' access='ROLE_USER'/>
</security:filter-invocation-definition-source>" +
</security:filter-security-metadata-source>" +
</property>
</bean>]]>
</programlisting>Rounding out the anonymous authentication discussion
is the <literal>AuthenticationTrustResolver</literal> interface, with
its corresponding <literal>AuthenticationTrustResolverImpl</literal>
implementation. This interface provides an
<literal>isAnonymous(Authentication)</literal> method, which allows
interested classes to take into account this special type of
authentication status. The
<classname>ExceptionTranslationFilter</classname> uses this interface in
processing <literal>AccessDeniedException</literal>s. If an
<literal>AccessDeniedException</literal> is thrown, and the
authentication is of an anonymous type, instead of throwing a 403
(forbidden) response, the filter will instead commence the
<interfacename>AuthenticationEntryPoint</interfacename> so the principal can
authenticate properly. This is a necessary distinction, otherwise
principals would always be deemed "authenticated" and never be given
an opportunity to login via form, basic, digest or some other normal
authentication mechanism</para>
</section>
</programlisting>Rounding out the anonymous authentication discussion is the
<literal>AuthenticationTrustResolver</literal> interface, with its corresponding
<literal>AuthenticationTrustResolverImpl</literal> implementation. This interface
provides an <literal>isAnonymous(Authentication)</literal> method, which allows
interested classes to take into account this special type of authentication status. The
<classname>ExceptionTranslationFilter</classname> uses this interface in processing
<literal>AccessDeniedException</literal>s. If an
<literal>AccessDeniedException</literal> is thrown, and the authentication is of an
anonymous type, instead of throwing a 403 (forbidden) response, the filter will instead
commence the <interfacename>AuthenticationEntryPoint</interfacename> so the principal
can authenticate properly. This is a necessary distinction, otherwise principals would
always be deemed "authenticated" and never be given an opportunity to login via form,
basic, digest or some other normal authentication mechanism</para>
</section>
</chapter>

View File

@ -1,52 +1,49 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="channel-security" xmlns:xlink="http://www.w3.org/1999/xlink">
<info><title>Channel Security</title></info>
<section xml:id="channel-security-overview">
<info><title>Overview</title></info>
<para>In addition to coordinating the authentication and authorization
requirements of your application, Spring Security is also able to
ensure unauthenticated web requests have certain properties. These
properties may include being of a particular transport type, having a
particular <literal>HttpSession</literal> attribute set and so on. The
most common requirement is for your web requests to be received using
a particular transport protocol, such as HTTPS.</para>
<para>An important issue in considering transport security is that of
session hijacking. Your web container manages a
<literal>HttpSession</literal> by reference to a
<literal>jsessionid</literal> that is sent to user agents either via a
cookie or URL rewriting. If the <literal>jsessionid</literal> is ever
sent over HTTP, there is a possibility that session identifier can be
intercepted and used to impersonate the user after they complete the
authentication process. This is because most web containers maintain
the same session identifier for a given user, even after they switch
from HTTP to HTTPS pages.</para>
<para>If session hijacking is considered too significant a risk for
your particular application, the only option is to use HTTPS for every
request. This means the <literal>jsessionid</literal> is never sent
across an insecure channel. You will need to ensure your
<literal>web.xml</literal>-defined
<literal>&lt;welcome-file&gt;</literal> points to an HTTPS location,
and the application never directs the user to an HTTP location. Spring
Security provides a solution to assist with the latter.</para>
</section>
<section xml:id="channel-security-config">
<info><title>Configuration</title></info>
<para>Channel security is supported by the <link xlink:href="#ns-requires-channel">security namespace</link>
by means of the <literal>requires-channel</literal> attribute on the <literal>&lt;intercept-url&gt;</literal>
element and this is the simplest (and recommended approach).</para>
<para>To confiure channel security explicitly, you would define the following the filter in your application
context:
<programlisting><![CDATA[
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="channel-security"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Channel Security</title>
</info>
<section xml:id="channel-security-overview">
<info>
<title>Overview</title>
</info>
<para>In addition to coordinating the authentication and authorization requirements of your
application, Spring Security is also able to ensure unauthenticated web requests have
certain properties. These properties may include being of a particular transport type,
having a particular <literal>HttpSession</literal> attribute set and so on. The most
common requirement is for your web requests to be received using a particular transport
protocol, such as HTTPS.</para>
<para>An important issue in considering transport security is that of session hijacking.
Your web container manages a <literal>HttpSession</literal> by reference to a
<literal>jsessionid</literal> that is sent to user agents either via a cookie or URL
rewriting. If the <literal>jsessionid</literal> is ever sent over HTTP, there is a
possibility that session identifier can be intercepted and used to impersonate the user
after they complete the authentication process. This is because most web containers
maintain the same session identifier for a given user, even after they switch from HTTP
to HTTPS pages.</para>
<para>If session hijacking is considered too significant a risk for your particular
application, the only option is to use HTTPS for every request. This means the
<literal>jsessionid</literal> is never sent across an insecure channel. You will
need to ensure your <literal>web.xml</literal>-defined
<literal>&lt;welcome-file&gt;</literal> points to an HTTPS location, and the
application never directs the user to an HTTP location. Spring Security provides a
solution to assist with the latter.</para>
</section>
<section xml:id="channel-security-config">
<info>
<title>Configuration</title>
</info>
<para>Channel security is supported by the <link xlink:href="#ns-requires-channel">security
namespace</link> by means of the <literal>requires-channel</literal> attribute on
the <literal>&lt;intercept-url&gt;</literal> element and this is the simplest (and
recommended approach).</para>
<para>To confiure channel security explicitly, you would define the following the filter in
your application context: <programlisting><![CDATA[
<bean id="channelProcessingFilter"
class="org.springframework.security.web.access.channel.ChannelProcessingFilter">
<property name="channelDecisionManager" ref="channelDecisionManager"/>
<property name="filterInvocationSecurityMetadataSource">
<security:filter-invocation-definition-source path-type="regex">
<property name="securityMetadataSource">
<security:filter-security-metadata-source path-type="regex">
<security:intercept-url pattern="\A/secure/.*\Z"
access="REQUIRES_SECURE_CHANNEL"/>
<security:intercept-url pattern="\A/acegilogin.jsp.*\Z"
@ -54,7 +51,7 @@
<security:intercept-url pattern="\A/j_spring_security_check.*\Z"
access="REQUIRES_SECURE_CHANNEL"/>
<security:intercept-url pattern="\A/.*\Z" access="ANY_CHANNEL"/>
</security:filter-invocation-definition-source>
</security:filter-security-metadata-source>
</property>
</bean>
@ -73,95 +70,73 @@
<bean id="insecureChannelProcessor"
class="org.springframework.security.access.channel.InsecureChannelProcessor"/>]]>
</programlisting>
Like <classname>FilterSecurityInterceptor</classname>, Apache Ant
style paths are also supported by the
<literal>ChannelProcessingFilter</literal>.</para>
<para>The <literal>ChannelProcessingFilter</literal> operates by
filtering all web requests and determining the configuration
attributes that apply. It then delegates to the
<literal>ChannelDecisionManager</literal>. The default implementation,
<literal>ChannelDecisionManagerImpl</literal>, should suffice in most
cases. It simply delegates to the list of configured
<literal>ChannelProcessor</literal> instances. The attribute <literal>ANY_CHANNEL</literal>
can be used to override this behaviour and skip a particular URL. Otherwise, a
<literal>ChannelProcessor</literal> will review the request, and if it
is unhappy with the request (e.g. if it was received across the incorrect
transport protocol), it will perform a redirect, throw an exception or
take whatever other action is appropriate.</para>
<para>Included with Spring Security are two concrete
<literal>ChannelProcessor</literal> implementations:
<literal>SecureChannelProcessor</literal> ensures requests with a
configuration attribute of <literal>REQUIRES_SECURE_CHANNEL</literal>
are received over HTTPS, whilst
<literal>InsecureChannelProcessor</literal> ensures requests with a
configuration attribute of
<literal>REQUIRES_INSECURE_CHANNEL</literal> are received over HTTP.
Both implementations delegate to a
<literal>ChannelEntryPoint</literal> if the required transport
protocol is not used. The two <literal>ChannelEntryPoint</literal>
implementations included with Spring Security simply redirect the
request to HTTP and HTTPS as appropriate. Appropriate defaults are
assigned to the <literal>ChannelProcessor</literal> implementations
for the configuration attribute keywords they respond to and the
<interfacename>ChannelEntryPoint</interfacename> they delegate to, although you
have the ability to override these using the application
context.</para>
<para>Note that the redirections are absolute (eg
<literal>http://www.company.com:8080/app/page</literal>), not relative
(eg <literal>/app/page</literal>). During testing it was discovered
that Internet Explorer 6 Service Pack 1 has a bug whereby it does not
respond correctly to a redirection instruction which also changes the
port to use. Accordingly, absolute URLs are used in conjunction with
bug detection logic in the <classname>PortResolverImpl</classname> that is
wired up by default to many Spring Security beans. Please refer to the
JavaDocs for <classname>PortResolverImpl</classname> for further
details.</para>
<para>You should note that using a secure channel is recommended if
usernames and passwords are to be kept secure during the login
process. If you do decide to use
<classname>ChannelProcessingFilter</classname> with form-based login,
please ensure that your login page is set to
<literal>REQUIRES_SECURE_CHANNEL</literal>, and that the
<literal>LoginUrlAuthenticationEntryPoint.forceHttps</literal>
property is <literal>true</literal>.</para>
</section>
<section xml:id="channel-security-conclusion">
<info><title>Conclusion</title></info>
<para>Once configured, using the channel security filter is very easy.
Simply request pages without regard to the protocol (ie HTTP or HTTPS)
or port (eg 80, 8080, 443, 8443 etc). Obviously you'll still need a
way of making the initial request (probably via the
<literal>web.xml</literal> <literal>&lt;welcome-file&gt;</literal> or
a well-known home page URL), but once this is done the filter will
perform redirects as defined by your application context.</para>
<para>You can also add your own <literal>ChannelProcessor</literal>
implementations to the <literal>ChannelDecisionManagerImpl</literal>.
For example, you might set a <literal>HttpSession</literal> attribute
when a human user is detected via a "enter the contents of this
graphic" procedure. Your <literal>ChannelProcessor</literal> would
respond to say <literal>REQUIRES_HUMAN_USER</literal> configuration
attributes and redirect to an appropriate entry point to start the
human user validation process if the <literal>HttpSession</literal>
attribute is not currently set.</para>
<para>To decide whether a security check belongs in a
<literal>ChannelProcessor</literal> or an
<interfacename>AccessDecisionVoter</interfacename>, remember that the former is
designed to handle unauthenticated requests, whilst the latter is
designed to handle authenticated requests. The latter therefore has
access to the granted authorities of the authenticated principal. In
addition, problems detected by a <literal>ChannelProcessor</literal>
will generally cause an HTTP/HTTPS redirection so its requirements can
be met, whilst problems detected by an
<interfacename>AccessDecisionVoter</interfacename> will ultimately result in an
<literal>AccessDeniedException</literal> (depending on the governing
<interfacename>AccessDecisionManager</interfacename>).</para>
</section>
</chapter>
Like <classname>FilterSecurityInterceptor</classname>, Apache Ant style paths are also
supported by the <literal>ChannelProcessingFilter</literal>.</para>
<para>The <literal>ChannelProcessingFilter</literal> operates by filtering all web requests
and determining the configuration attributes that apply. It then delegates to the
<literal>ChannelDecisionManager</literal>. The default implementation,
<literal>ChannelDecisionManagerImpl</literal>, should suffice in most cases. It
simply delegates to the list of configured <literal>ChannelProcessor</literal>
instances. The attribute <literal>ANY_CHANNEL</literal> can be used to override this
behaviour and skip a particular URL. Otherwise, a <literal>ChannelProcessor</literal>
will review the request, and if it is unhappy with the request (e.g. if it was received
across the incorrect transport protocol), it will perform a redirect, throw an exception
or take whatever other action is appropriate.</para>
<para>Included with Spring Security are two concrete <literal>ChannelProcessor</literal>
implementations: <literal>SecureChannelProcessor</literal> ensures requests with a
configuration attribute of <literal>REQUIRES_SECURE_CHANNEL</literal> are received over
HTTPS, whilst <literal>InsecureChannelProcessor</literal> ensures requests with a
configuration attribute of <literal>REQUIRES_INSECURE_CHANNEL</literal> are received
over HTTP. Both implementations delegate to a <literal>ChannelEntryPoint</literal> if
the required transport protocol is not used. The two
<literal>ChannelEntryPoint</literal> implementations included with Spring Security
simply redirect the request to HTTP and HTTPS as appropriate. Appropriate defaults are
assigned to the <literal>ChannelProcessor</literal> implementations for the
configuration attribute keywords they respond to and the
<interfacename>ChannelEntryPoint</interfacename> they delegate to, although you have
the ability to override these using the application context.</para>
<para>Note that the redirections are absolute (eg
<literal>http://www.company.com:8080/app/page</literal>), not relative (eg
<literal>/app/page</literal>). During testing it was discovered that Internet
Explorer 6 Service Pack 1 has a bug whereby it does not respond correctly to a
redirection instruction which also changes the port to use. Accordingly, absolute URLs
are used in conjunction with bug detection logic in the
<classname>PortResolverImpl</classname> that is wired up by default to many Spring
Security beans. Please refer to the JavaDocs for <classname>PortResolverImpl</classname>
for further details.</para>
<para>You should note that using a secure channel is recommended if usernames and passwords
are to be kept secure during the login process. If you do decide to use
<classname>ChannelProcessingFilter</classname> with form-based login, please ensure
that your login page is set to <literal>REQUIRES_SECURE_CHANNEL</literal>, and that the
<literal>LoginUrlAuthenticationEntryPoint.forceHttps</literal> property is
<literal>true</literal>.</para>
</section>
<section xml:id="channel-security-conclusion">
<info>
<title>Conclusion</title>
</info>
<para>Once configured, using the channel security filter is very easy. Simply request pages
without regard to the protocol (ie HTTP or HTTPS) or port (eg 80, 8080, 443, 8443 etc).
Obviously you'll still need a way of making the initial request (probably via the
<literal>web.xml</literal>
<literal>&lt;welcome-file&gt;</literal> or a well-known home page URL), but once this is
done the filter will perform redirects as defined by your application context.</para>
<para>You can also add your own <literal>ChannelProcessor</literal> implementations to the
<literal>ChannelDecisionManagerImpl</literal>. For example, you might set a
<literal>HttpSession</literal> attribute when a human user is detected via a "enter
the contents of this graphic" procedure. Your <literal>ChannelProcessor</literal> would
respond to say <literal>REQUIRES_HUMAN_USER</literal> configuration attributes and
redirect to an appropriate entry point to start the human user validation process if the
<literal>HttpSession</literal> attribute is not currently set.</para>
<para>To decide whether a security check belongs in a <literal>ChannelProcessor</literal> or
an <interfacename>AccessDecisionVoter</interfacename>, remember that the former is
designed to handle unauthenticated requests, whilst the latter is designed to handle
authenticated requests. The latter therefore has access to the granted authorities of
the authenticated principal. In addition, problems detected by a
<literal>ChannelProcessor</literal> will generally cause an HTTP/HTTPS redirection
so its requirements can be met, whilst problems detected by an
<interfacename>AccessDecisionVoter</interfacename> will ultimately result in an
<literal>AccessDeniedException</literal> (depending on the governing
<interfacename>AccessDecisionManager</interfacename>).</para>
</section>
</chapter>

View File

@ -1,36 +1,32 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="secure-object-impls" xmlns:xlink="http://www.w3.org/1999/xlink">
<info><title>Secure Object Implementations</title></info>
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="secure-object-impls"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Secure Object Implementations</title>
</info>
<section xml:id="aop-alliance">
<info>
<title>AOP Alliance (MethodInvocation) Security Interceptor</title>
</info>
<para>
Prior to Spring Security 2.0, securing <classname>MethodInvocation</classname>s needed quite a
lot of boiler plate configuration. Now the recommended approach for method security
is to use <link xlink:href="#ns-method-security">namespace configuration</link>.
This way the method security infrastructure beans are configured automatically for you so you don't really need to
know about the implementation classes. We'll just provide a quick overview of the classes that are involved here.
</para>
<para>
Method security in enforced using a <classname>MethodSecurityInterceptor</classname>, which secures
<classname>MethodInvocation</classname>s. Depending on the configuration approach, an interceptor may be specific to a single
bean or shared between multiple beans. The interceptor uses a <interfacename>MethodDefinitionSource</interfacename>
instance to obtain the configuration attributes that apply to a particular method invocation.
<classname>MapBasedMethodDefinitionSource</classname> is used to store configuration attributes keyed by method names
(which can be wildcarded) and will be used internally when the attributes are defined in the application context using
the <literal>&lt;intercept-methods&gt;</literal> or <literal>&lt;protect-point&gt;</literal> elements. Other implementations
will be used to handle annotation-based configuration.
</para>
<para> Prior to Spring Security 2.0, securing <classname>MethodInvocation</classname>s needed
quite a lot of boiler plate configuration. Now the recommended approach for method security is
to use <link xlink:href="#ns-method-security">namespace configuration</link>. This way the
method security infrastructure beans are configured automatically for you so you don't really
need to know about the implementation classes. We'll just provide a quick overview of the
classes that are involved here. </para>
<para> Method security in enforced using a <classname>MethodSecurityInterceptor</classname>,
which secures <classname>MethodInvocation</classname>s. Depending on the configuration
approach, an interceptor may be specific to a single bean or shared between multiple beans.
The interceptor uses a <interfacename>MethodDefinitionSource</interfacename> instance to
obtain the configuration attributes that apply to a particular method invocation.
<classname>MapBasedMethodDefinitionSource</classname> is used to store configuration
attributes keyed by method names (which can be wildcarded) and will be used internally when
the attributes are defined in the application context using the
<literal>&lt;intercept-methods&gt;</literal> or <literal>&lt;protect-point&gt;</literal>
elements. Other implementations will be used to handle annotation-based configuration. </para>
<section>
<title>Explicit MethodSecurityIterceptor Configuration</title>
<para>
You can of course configure a <classname>MethodSecurityIterceptor</classname> directly in your application context
for use with one of Spring AOP's proxying mechanisms:
<programlisting><![CDATA[
<para> You can of course configure a <classname>MethodSecurityIterceptor</classname> directly
in your application context for use with one of Spring AOP's proxying mechanisms: <programlisting><![CDATA[
<bean id="bankManagerSecurity"
class="org.springframework.security.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
@ -43,37 +39,26 @@
</value>
</property>
</bean> ]]>
</programlisting>
</para>
</programlisting></para>
</section>
</section>
<section xml:id="aspectj">
<info>
<title>AspectJ (JoinPoint) Security Interceptor</title>
</info>
<para>The AspectJ security interceptor is very similar to the AOP
Alliance security interceptor discussed in the previous section.
Indeed we will only discuss the differences in this section.</para>
<para>The AspectJ interceptor is named
<literal>AspectJSecurityInterceptor</literal>. Unlike the AOP Alliance
security interceptor, which relies on the Spring application context
to weave in the security interceptor via proxying, the
<literal>AspectJSecurityInterceptor</literal> is weaved in via the
AspectJ compiler. It would not be uncommon to use both types of
security interceptors in the same application, with
<literal>AspectJSecurityInterceptor</literal> being used for domain
object instance security and the AOP Alliance
<classname>MethodSecurityInterceptor</classname> being used for services
layer security.</para>
<para>Let's first consider how the
<literal>AspectJSecurityInterceptor</literal> is configured in the
Spring application context:</para>
<para>The AspectJ security interceptor is very similar to the AOP Alliance security interceptor
discussed in the previous section. Indeed we will only discuss the differences in this
section.</para>
<para>The AspectJ interceptor is named <literal>AspectJSecurityInterceptor</literal>. Unlike the
AOP Alliance security interceptor, which relies on the Spring application context to weave in
the security interceptor via proxying, the <literal>AspectJSecurityInterceptor</literal> is
weaved in via the AspectJ compiler. It would not be uncommon to use both types of security
interceptors in the same application, with <literal>AspectJSecurityInterceptor</literal> being
used for domain object instance security and the AOP Alliance
<classname>MethodSecurityInterceptor</classname> being used for services layer
security.</para>
<para>Let's first consider how the <literal>AspectJSecurityInterceptor</literal> is configured
in the Spring application context:</para>
<programlisting><![CDATA[
<bean id="bankManagerSecurity"
class="org.springframework.security.intercept.aspectj.AspectJSecurityInterceptor">
@ -87,23 +72,18 @@
</value>
</property>
</bean>]]> </programlisting>
<para>As you can see, aside from the class name, the
<literal>AspectJSecurityInterceptor</literal> is exactly the same as
the AOP Alliance security interceptor. Indeed the two interceptors can
share the same <literal>securityMetadataSource</literal>, as the
<interfacename>SecurityMetadataSource</interfacename> works with
<literal>java.lang.reflect.Method</literal>s rather than an AOP
library-specific class. Of course, your access decisions have access
to the relevant AOP library-specific invocation (ie
<classname>MethodInvocation</classname> or <literal>JoinPoint</literal>)
and as such can consider a range of addition criteria when making
access decisions (such as method arguments).</para>
<para>Next you'll need to define an AspectJ <literal>aspect</literal>.
For example:</para>
<programlisting>
<literal>AspectJSecurityInterceptor</literal> is exactly the same as the AOP Alliance
security interceptor. Indeed the two interceptors can share the same
<literal>securityMetadataSource</literal>, as the
<interfacename>SecurityMetadataSource</interfacename> works with
<literal>java.lang.reflect.Method</literal>s rather than an AOP library-specific class. Of
course, your access decisions have access to the relevant AOP library-specific invocation (ie
<classname>MethodInvocation</classname> or <literal>JoinPoint</literal>) and as such can
consider a range of addition criteria when making access decisions (such as method
arguments).</para>
<para>Next you'll need to define an AspectJ <literal>aspect</literal>. For example:</para>
<programlisting language="java">
package org.springframework.security.samples.aspectj;
import org.springframework.security.intercept.aspectj.AspectJSecurityInterceptor;
@ -144,22 +124,16 @@ public void afterPropertiesSet() throws Exception {
throw new IllegalArgumentException("securityInterceptor required");
}
}</programlisting>
<para>In the above example, the security interceptor will be applied
to every instance of <literal>PersistableEntity</literal>, which is an
abstract class not shown (you can use any other class or
<literal>pointcut</literal> expression you like). For those curious,
<literal>AspectJCallback</literal> is needed because the
<literal>proceed();</literal> statement has special meaning only
within an <literal>around()</literal> body. The
<literal>AspectJSecurityInterceptor</literal> calls this anonymous
<literal>AspectJCallback</literal> class when it wants the target
object to continue.</para>
<para>You will need to configure Spring to load the aspect and wire it
with the <literal>AspectJSecurityInterceptor</literal>. A bean
declaration which achieves this is shown below:</para>
<para>In the above example, the security interceptor will be applied to every instance of
<literal>PersistableEntity</literal>, which is an abstract class not shown (you can use any
other class or <literal>pointcut</literal> expression you like). For those curious,
<literal>AspectJCallback</literal> is needed because the <literal>proceed();</literal>
statement has special meaning only within an <literal>around()</literal> body. The
<literal>AspectJSecurityInterceptor</literal> calls this anonymous
<literal>AspectJCallback</literal> class when it wants the target object to continue.</para>
<para>You will need to configure Spring to load the aspect and wire it with the
<literal>AspectJSecurityInterceptor</literal>. A bean declaration which achieves this is
shown below:</para>
<programlisting><![CDATA[
<bean id="domainObjectInstanceSecurityAspect"
class="org.springframework.security.samples.aspectj.DomainObjectInstanceSecurityAspect"
@ -167,23 +141,18 @@ public void afterPropertiesSet() throws Exception {
<property name="securityInterceptor" ref="aspectJSecurityInterceptor"/>
</bean>]]>
</programlisting>
<para>That's it! Now you can create your beans from anywhere within
your application, using whatever means you think fit (eg <literal>new
Person();</literal>) and they will have the security interceptor
applied.</para>
<para>That's it! Now you can create your beans from anywhere within your application, using
whatever means you think fit (eg <literal>new Person();</literal>) and they will have the
security interceptor applied.</para>
</section>
<section xml:id="filter-invocation-authorization">
<info><title>FilterInvocation Security Interceptor</title></info>
<para>To secure <classname>FilterInvocation</classname>s, developers need
to add a <classname>FilterSecurityInterceptor</classname> to their filter chain.
A typical configuration example is provided below:</para>
<para>In the application context you will need to configure three
beans:</para>
<info>
<title>FilterInvocation Security Interceptor</title>
</info>
<para>To secure <classname>FilterInvocation</classname>s, developers need to add a
<classname>FilterSecurityInterceptor</classname> to their filter chain. A typical
configuration example is provided below:</para>
<para>In the application context you will need to configure three beans:</para>
<programlisting>
<![CDATA[
<bean id="exceptionTranslationFilter"
@ -202,93 +171,69 @@ public void afterPropertiesSet() throws Exception {
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="securityMetadataSource">
<security:filter-invocation-definition-source>
<security:filter-security-metadata-source>
<security:intercept-url pattern="/secure/super/**" access="ROLE_WE_DONT_HAVE"/>
<security:intercept-url pattern="/secure/**" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
</security:filter-invocation-definition-source>
</security:filter-security-metadata-source>
</property>
</bean>]]> </programlisting>
<para>The <classname>ExceptionTranslationFilter</classname> provides
the bridge between Java exceptions and HTTP responses. It is solely
concerned with maintaining the user interface. This filter does not do
any actual security enforcement. If an
<exceptionname>AuthenticationException</exceptionname> is detected,
the filter will call the AuthenticationEntryPoint to commence the
authentication process (e.g. a user login).</para>
<para>The <interfacename>AuthenticationEntryPoint</interfacename> will be called
if the user requests a secure HTTP resource but they are not
authenticated. The class handles presenting the appropriate response
to the user so that authentication can begin. Three concrete
implementations are provided with Spring Security:
<classname>LoginUrlAuthenticationEntryPoint</classname> for
commencing a form-based authentication,
<literal>BasicProcessingFilterEntryPoint</literal> for commencing a
HTTP Basic authentication process, and
<literal>CasProcessingFilterEntryPoint</literal> for commencing a
JA-SIG Central Authentication Service (CAS) login. The
<classname>LoginUrlAuthenticationEntryPoint</classname> and
<literal>CasProcessingFilterEntryPoint</literal> have optional
properties related to forcing the use of HTTPS, so please refer to the
JavaDocs if you require this.</para>
<para><classname>FilterSecurityInterceptor</classname> is responsible for
handling the security of HTTP resources. Like any other security
interceptor, it requires a reference to an
<interfacename>AuthenticationManager</interfacename> and an
<interfacename>AccessDecisionManager</interfacename>, which are both discussed in
separate sections below. The
<classname>FilterSecurityInterceptor</classname> is also configured with
configuration attributes that apply to different HTTP URL requests. A
full discussion of configuration attributes is provided in the High
Level Design section of this document.</para>
<para>The <classname>FilterSecurityInterceptor</classname> can be
configured with configuration attributes in two ways. The first,
which is shown above, is using the <literal>&lt;filter-invocation-definition-source&gt;</literal>
namespace element. This is similar to the <literal>&lt;filter-chain-map&gt;</literal>
used to configure a <classname>FilterChainProxy</classname> but the <literal>&lt;intercept-url&gt;</literal>
child elements only use the <literal>pattern</literal> and <literal>access</literal> attributes.
The second is by writing your own
<interfacename>SecurityMetadataSource</interfacename>, although this is beyond the
scope of this document. Irrespective of the approach used, the
<interfacename>SecurityMetadataSource</interfacename> is responsible for returning
a <literal>List&lt;ConfigAttribute&gt;</literal> containing
all of the configuration attributes associated with a single secure
HTTP URL.</para>
<para>The <classname>ExceptionTranslationFilter</classname> provides the bridge between Java
exceptions and HTTP responses. It is solely concerned with maintaining the user interface.
This filter does not do any actual security enforcement. If an
<exceptionname>AuthenticationException</exceptionname> is detected, the filter will call the
AuthenticationEntryPoint to commence the authentication process (e.g. a user login).</para>
<para>The <interfacename>AuthenticationEntryPoint</interfacename> will be called if the user
requests a secure HTTP resource but they are not authenticated. The class handles presenting
the appropriate response to the user so that authentication can begin. Three concrete
implementations are provided with Spring Security:
<classname>LoginUrlAuthenticationEntryPoint</classname> for commencing a form-based
authentication, <literal>BasicProcessingFilterEntryPoint</literal> for commencing a HTTP Basic
authentication process, and <literal>CasProcessingFilterEntryPoint</literal> for commencing a
JA-SIG Central Authentication Service (CAS) login. The
<classname>LoginUrlAuthenticationEntryPoint</classname> and
<literal>CasProcessingFilterEntryPoint</literal> have optional properties related to forcing
the use of HTTPS, so please refer to the JavaDocs if you require this.</para>
<para><classname>FilterSecurityInterceptor</classname> is responsible for handling the security
of HTTP resources. Like any other security interceptor, it requires a reference to an
<interfacename>AuthenticationManager</interfacename> and an
<interfacename>AccessDecisionManager</interfacename>, which are both discussed in separate
sections below. The <classname>FilterSecurityInterceptor</classname> is also configured with
configuration attributes that apply to different HTTP URL requests. A full discussion of
configuration attributes is provided in the High Level Design section of this document.</para>
<para>The <classname>FilterSecurityInterceptor</classname> can be configured with configuration
attributes in two ways. The first, which is shown above, is using the
<literal>&lt;filter-security-metadata-source&gt;</literal> namespace element. This is
similar to the <literal>&lt;filter-chain-map&gt;</literal> used to configure a
<classname>FilterChainProxy</classname> but the <literal>&lt;intercept-url&gt;</literal>
child elements only use the <literal>pattern</literal> and <literal>access</literal>
attributes. The second is by writing your own
<interfacename>SecurityMetadataSource</interfacename>, although this is beyond the scope of
this document. Irrespective of the approach used, the
<interfacename>SecurityMetadataSource</interfacename> is responsible for returning a
<literal>List&lt;ConfigAttribute&gt;</literal> containing all of the configuration
attributes associated with a single secure HTTP URL.</para>
<para>It should be noted that the
<literal>FilterSecurityInterceptor.setSecurityMetadataSource()</literal>
method actually expects an instance of
<interfacename>FilterInvocationDefinitionSource</interfacename>. This is a marker
interface which subclasses <interfacename>SecurityMetadataSource</interfacename>.
It simply denotes the <interfacename>SecurityMetadataSource</interfacename>
understands <classname>FilterInvocation</classname>s. In the interests of
simplicity we'll continue to refer to the
<interfacename>FilterInvocationDefinitionSource</interfacename> as an
<interfacename>SecurityMetadataSource</interfacename>, as the distinction is of
little relevance to most users of the
<classname>FilterSecurityInterceptor</classname>.</para>
<para>When using the namespace option to configure the interceptor,
commas are used to delimit the different configuration
attributes that apply to each HTTP URL. Each configuration attribute
is assigned into its own <literal>SecurityConfig</literal> object. The
<literal>SecurityConfig</literal> object is discussed in the High
Level Design section. The <interfacename>SecurityMetadataSource</interfacename>
created by the property editor,
<interfacename>FilterInvocationDefinitionSource</interfacename>, matches
configuration attributes against <literal>FilterInvocations</literal>
based on expression evaluation of the request URL. Two standard
expression syntaxes are supported. The default is to treat all
expressions as Apache Ant paths and regular expressions are also supported
for ore complex cases. The <literal>path-type</literal> attribute is used
to specify the type of pattern being used. It is not possible to
mix expression syntaxes within the same definition. For example, the
previous configuration using regular expressions instead of Ant paths would be
written as follows:</para>
<literal>FilterSecurityInterceptor.setSecurityMetadataSource()</literal> method actually
expects an instance of <interfacename>FilterInvocationDefinitionSource</interfacename>. This
is a marker interface which subclasses <interfacename>SecurityMetadataSource</interfacename>.
It simply denotes the <interfacename>SecurityMetadataSource</interfacename> understands
<classname>FilterInvocation</classname>s. In the interests of simplicity we'll continue to
refer to the <interfacename>FilterInvocationDefinitionSource</interfacename> as an
<interfacename>SecurityMetadataSource</interfacename>, as the distinction is of little
relevance to most users of the <classname>FilterSecurityInterceptor</classname>.</para>
<para>When using the namespace option to configure the interceptor, commas are used to delimit
the different configuration attributes that apply to each HTTP URL. Each configuration
attribute is assigned into its own <literal>SecurityConfig</literal> object. The
<literal>SecurityConfig</literal> object is discussed in the High Level Design section. The
<interfacename>SecurityMetadataSource</interfacename> created by the property editor,
<interfacename>FilterInvocationDefinitionSource</interfacename>, matches configuration
attributes against <literal>FilterInvocations</literal> based on expression evaluation of the
request URL. Two standard expression syntaxes are supported. The default is to treat all
expressions as Apache Ant paths and regular expressions are also supported for ore complex
cases. The <literal>path-type</literal> attribute is used to specify the type of pattern being
used. It is not possible to mix expression syntaxes within the same definition. For example,
the previous configuration using regular expressions instead of Ant paths would be written as
follows:</para>
<programlisting><![CDATA[
<bean id="filterInvocationInterceptor"
class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
@ -296,32 +241,25 @@ public void afterPropertiesSet() throws Exception {
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="runAsManager" ref="runAsManager"/>
<property name="securityMetadataSource">
<security:filter-invocation-definition-source path-type="regex">
<security:filter-security-metadata-source path-type="regex">
<security:intercept-url pattern="\A/secure/super/.*\Z" access="ROLE_WE_DONT_HAVE"/>
<security:intercept-url pattern="\A/secure/.*\" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
</security:filter-invocation-definition-source>
</security:filter-security-metadata-source>
</property>
</bean>]]> </programlisting>
<para>Irrespective of the type of expression syntax used, expressions
are always evaluated in the order they are defined. Thus it is
important that more specific expressions are defined higher in the
list than less specific expressions. This is reflected in our example
above, where the more specific <literal>/secure/super/</literal>
pattern appears higher than the less specific
<literal>/secure/</literal> pattern. If they were reversed, the
<literal>/secure/</literal> pattern would always match and the
<literal>/secure/super/</literal> pattern would never be
evaluated.</para>
<para>As with other security interceptors, the
<literal>validateConfigAttributes</literal> property is observed. When
set to <literal>true</literal> (the default), at startup time the
<classname>FilterSecurityInterceptor</classname> will evaluate if the
provided configuration attributes are valid. It does this by checking
each configuration attribute can be processed by either the
<interfacename>AccessDecisionManager</interfacename> or the
<literal>RunAsManager</literal>. If neither of these can process a
given configuration attribute, an exception is thrown.</para>
<para>Irrespective of the type of expression syntax used, expressions are always evaluated in
the order they are defined. Thus it is important that more specific expressions are defined
higher in the list than less specific expressions. This is reflected in our example above,
where the more specific <literal>/secure/super/</literal> pattern appears higher than the less
specific <literal>/secure/</literal> pattern. If they were reversed, the
<literal>/secure/</literal> pattern would always match and the
<literal>/secure/super/</literal> pattern would never be evaluated.</para>
<para>As with other security interceptors, the <literal>validateConfigAttributes</literal>
property is observed. When set to <literal>true</literal> (the default), at startup time the
<classname>FilterSecurityInterceptor</classname> will evaluate if the provided configuration
attributes are valid. It does this by checking each configuration attribute can be processed
by either the <interfacename>AccessDecisionManager</interfacename> or the
<literal>RunAsManager</literal>. If neither of these can process a given configuration
attribute, an exception is thrown.</para>
</section>
</chapter>

View File

@ -92,11 +92,11 @@
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="securityMetadataSource">
<sec:filter-invocation-definition-source>
<sec:filter-security-metadata-source>
<sec:intercept-url pattern="/secure/extreme/**" access="ROLE_2"/>
<sec:intercept-url pattern="/secure/**" access="ROLE_1"/>
<sec:intercept-url pattern="/**" access="ROLE_0"/>
</sec:filter-invocation-definition-source>
</sec:filter-security-metadata-source>
</property>
</bean>

View File

@ -51,15 +51,15 @@ public class ChannelProcessingFilter extends SpringSecurityFilter implements Ini
//~ Instance fields ================================================================================================
private ChannelDecisionManager channelDecisionManager;
private FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource;
private FilterInvocationSecurityMetadataSource securityMetadataSource;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(filterInvocationSecurityMetadataSource, "filterInvocationSecurityMetadataSource must be specified");
Assert.notNull(securityMetadataSource, "securityMetadataSource must be specified");
Assert.notNull(channelDecisionManager, "channelDecisionManager must be specified");
Collection<ConfigAttribute> attrDefs = this.filterInvocationSecurityMetadataSource.getAllConfigAttributes();
Collection<ConfigAttribute> attrDefs = this.securityMetadataSource.getAllConfigAttributes();
if (attrDefs == null) {
if (logger.isWarnEnabled()) {
@ -91,7 +91,7 @@ public class ChannelProcessingFilter extends SpringSecurityFilter implements Ini
throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
List<ConfigAttribute> attr = this.filterInvocationSecurityMetadataSource.getAttributes(fi);
List<ConfigAttribute> attr = this.securityMetadataSource.getAttributes(fi);
if (attr != null) {
if (logger.isDebugEnabled()) {
@ -112,16 +112,16 @@ public class ChannelProcessingFilter extends SpringSecurityFilter implements Ini
return channelDecisionManager;
}
public FilterInvocationSecurityMetadataSource getFilterInvocationSecurityMetadataSource() {
return filterInvocationSecurityMetadataSource;
public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return securityMetadataSource;
}
public void setChannelDecisionManager(ChannelDecisionManager channelDecisionManager) {
this.channelDecisionManager = channelDecisionManager;
}
public void setFilterInvocationSecurityMetadataSource(FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource) {
this.filterInvocationSecurityMetadataSource = filterInvocationSecurityMetadataSource;
public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource) {
this.securityMetadataSource = filterInvocationSecurityMetadataSource;
}
public int getOrder() {

View File

@ -15,7 +15,7 @@
package org.springframework.security.web.access.channel;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import java.io.IOException;
@ -31,8 +31,6 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.channel.ChannelDecisionManager;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
@ -50,7 +48,7 @@ public class ChannelProcessingFilterTests {
ChannelProcessingFilter filter = new ChannelProcessingFilter();
MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", true, "MOCK");
filter.setFilterInvocationSecurityMetadataSource(fids);
filter.setSecurityMetadataSource(fids);
filter.afterPropertiesSet();
}
@ -69,7 +67,7 @@ public class ChannelProcessingFilterTests {
MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", true, "SUPPORTS_MOCK_ONLY");
filter.setFilterInvocationSecurityMetadataSource(fids);
filter.setSecurityMetadataSource(fids);
filter.afterPropertiesSet();
}
@ -81,7 +79,7 @@ public class ChannelProcessingFilterTests {
MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", true, "SUPPORTS_MOCK_ONLY", "INVALID_ATTRIBUTE");
filter.setFilterInvocationSecurityMetadataSource(fids);
filter.setSecurityMetadataSource(fids);
filter.afterPropertiesSet();
}
@ -92,7 +90,7 @@ public class ChannelProcessingFilterTests {
MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", true, "SOME_ATTRIBUTE");
filter.setFilterInvocationSecurityMetadataSource(fids);
filter.setSecurityMetadataSource(fids);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setQueryString("info=now");
@ -110,7 +108,7 @@ public class ChannelProcessingFilterTests {
MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", true, "SOME_ATTRIBUTE");
filter.setFilterInvocationSecurityMetadataSource(fids);
filter.setSecurityMetadataSource(fids);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setQueryString("info=now");
@ -129,7 +127,7 @@ public class ChannelProcessingFilterTests {
MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", true, "NOT_USED");
filter.setFilterInvocationSecurityMetadataSource(fids);
filter.setSecurityMetadataSource(fids);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setQueryString("info=now");
@ -148,8 +146,8 @@ public class ChannelProcessingFilterTests {
MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", false, "MOCK");
filter.setFilterInvocationSecurityMetadataSource(fids);
assertTrue(filter.getFilterInvocationSecurityMetadataSource() != null);
filter.setSecurityMetadataSource(fids);
assertSame(fids, filter.getSecurityMetadataSource());
filter.init(null);
filter.afterPropertiesSet();