SEC-1100: Added support for <access-denied-handler> element which can take a ref or an error-page attribute.
This commit is contained in:
parent
6db9a3facc
commit
90b849c271
|
@ -8,6 +8,7 @@ package org.springframework.security.config;
|
|||
*/
|
||||
public abstract class Elements {
|
||||
|
||||
public static final String ACCESS_DENIED_HANDLER = "access-denied-handler";
|
||||
public static final String AUTHENTICATION_MANAGER = "authentication-manager";
|
||||
public static final String USER_SERVICE = "user-service";
|
||||
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.Map;
|
|||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
|
@ -99,6 +100,7 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
private static final String ATT_ENTRY_POINT_REF = "entry-point-ref";
|
||||
private static final String ATT_ONCE_PER_REQUEST = "once-per-request";
|
||||
private static final String ATT_ACCESS_DENIED_PAGE = "access-denied-page";
|
||||
private static final String ATT_ACCESS_DENIED_ERROR_PAGE = "error-page";
|
||||
|
||||
private static final String ATT_USE_EXPRESSIONS = "use-expressions";
|
||||
|
||||
|
@ -336,22 +338,51 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
}
|
||||
|
||||
private void registerExceptionTranslationFilter(Element element, ParserContext pc, boolean allowSessionCreation) {
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
BeanDefinitionBuilder exceptionTranslationFilterBuilder
|
||||
= BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("createSessionAllowed", new Boolean(allowSessionCreation));
|
||||
|
||||
if (StringUtils.hasText(accessDeniedPage)) {
|
||||
BeanDefinition accessDeniedHandler = new RootBeanDefinition(AccessDeniedHandlerImpl.class);
|
||||
accessDeniedHandler.getPropertyValues().addPropertyValue("errorPage", accessDeniedPage);
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", accessDeniedHandler);
|
||||
}
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("createSessionAllowed", Boolean.valueOf(allowSessionCreation));
|
||||
exceptionTranslationFilterBuilder.addPropertyValue("accessDeniedHandler", createAccessDeniedHandler(element, pc));
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(BeanIds.EXCEPTION_TRANSLATION_FILTER, exceptionTranslationFilterBuilder.getBeanDefinition());
|
||||
ConfigUtils.addHttpFilter(pc, new RuntimeBeanReference(BeanIds.EXCEPTION_TRANSLATION_FILTER));
|
||||
}
|
||||
|
||||
private BeanMetadataElement createAccessDeniedHandler(Element element, ParserContext pc) {
|
||||
String accessDeniedPage = element.getAttribute(ATT_ACCESS_DENIED_PAGE);
|
||||
ConfigUtils.validateHttpRedirect(accessDeniedPage, pc, pc.extractSource(element));
|
||||
Element accessDeniedElt = DomUtils.getChildElementByTagName(element, Elements.ACCESS_DENIED_HANDLER);
|
||||
BeanDefinitionBuilder accessDeniedHandler = BeanDefinitionBuilder.rootBeanDefinition(AccessDeniedHandlerImpl.class);
|
||||
|
||||
if (StringUtils.hasText(accessDeniedPage)) {
|
||||
if (accessDeniedElt != null) {
|
||||
pc.getReaderContext().error("The attribute " + ATT_ACCESS_DENIED_PAGE +
|
||||
" cannot be used with <" + Elements.ACCESS_DENIED_HANDLER + ">", pc.extractSource(accessDeniedElt));
|
||||
}
|
||||
|
||||
accessDeniedHandler.addPropertyValue("errorPage", accessDeniedPage);
|
||||
}
|
||||
|
||||
if (accessDeniedElt != null) {
|
||||
String errorPage = accessDeniedElt.getAttribute("error-page");
|
||||
String ref = accessDeniedElt.getAttribute("ref");
|
||||
|
||||
if (StringUtils.hasText(errorPage)) {
|
||||
if (StringUtils.hasText(ref)) {
|
||||
pc.getReaderContext().error("The attribute " + ATT_ACCESS_DENIED_ERROR_PAGE +
|
||||
" cannot be used together with the 'ref' attribute within <" +
|
||||
Elements.ACCESS_DENIED_HANDLER + ">", pc.extractSource(accessDeniedElt));
|
||||
|
||||
}
|
||||
accessDeniedHandler.addPropertyValue("errorPage", errorPage);
|
||||
} else if (StringUtils.hasText(ref)) {
|
||||
return new RuntimeBeanReference(ref);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return accessDeniedHandler.getBeanDefinition();
|
||||
}
|
||||
|
||||
private void registerFilterSecurityInterceptor(Element element, ParserContext pc, String accessManagerId,
|
||||
BeanDefinition fids) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-2.5.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security.xsd=org/springframework/security/config/spring-security-3.0.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.xsd=org/springframework/security/config/spring-security-2.0.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.1.xsd=org/springframework/security/config/spring-security-2.0.1.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.2.xsd=org/springframework/security/config/spring-security-2.0.2.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.0.4.xsd=org/springframework/security/config/spring-security-2.0.4.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-2.5.xsd=org/springframework/security/config/spring-security-2.5.xsd
|
||||
http\://www.springframework.org/schema/security/spring-security-3.0.xsd=org/springframework/security/config/spring-security-3.0.xsd
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -219,7 +219,7 @@ protect-pointcut.attlist &=
|
|||
|
||||
http =
|
||||
## Container element for HTTP security configuration
|
||||
element http {http.attlist, (intercept-url+ & form-login? & openid-login & x509? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous? & port-mappings) }
|
||||
element http {http.attlist, (intercept-url+ & access-denied-handler? & form-login? & openid-login? & x509? & http-basic? & logout? & concurrent-session-control? & remember-me? & anonymous? & port-mappings) }
|
||||
http.attlist &=
|
||||
## Automatically registers a login form, BASIC authentication, anonymous authentication, logout services, remember-me and servlet-api-integration. If set to "true", all of these capabilities are added (although you can still customize the configuration of each by providing the respective element). If unspecified, defaults to "false".
|
||||
attribute auto-config {boolean}?
|
||||
|
@ -229,7 +229,7 @@ http.attlist &=
|
|||
## Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired". Note that if a custom SecurityContextRepository is set using security-context-repository-ref, then the only value which can be set is "always". Otherwise the session creation behaviour will be determined by the repository bean implementation.
|
||||
attribute create-session {"ifRequired" | "always" | "never" }?
|
||||
http.attlist &=
|
||||
## A reference to a SecurityContextRepository bean. This can be used to customize the way the SecurityContext is stored between requests.
|
||||
## A reference to a SecurityContextRepository bean. This can be used to customize how the SecurityContext is stored between requests.
|
||||
attribute security-context-repository-ref {xsd:string}?
|
||||
http.attlist &=
|
||||
## The path format used to define the paths in child elements.
|
||||
|
@ -256,12 +256,20 @@ http.attlist &=
|
|||
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "true"
|
||||
attribute once-per-request {boolean}?
|
||||
http.attlist &=
|
||||
## Allows the access denied page to be set (the user will be redirected here if an AccessDeniedException is raised).
|
||||
## Deprecated in favour of the access-denied-handler element.
|
||||
attribute access-denied-page {xsd:string}?
|
||||
http.attlist &=
|
||||
##
|
||||
attribute disable-url-rewriting {boolean}?
|
||||
attribute disable-url-rewriting {boolean}?
|
||||
|
||||
access-denied-handler =
|
||||
## Defines the access-denied strategy that should be used. An access denied page can be defined or a reference to an AccessDeniedHandler instance.
|
||||
element access-denied-handler {access-denied-handler.attlist, empty}
|
||||
access-denied-handler.attlist &= (ref | access-denied-handler-page)
|
||||
|
||||
access-denied-handler-page =
|
||||
## The access denied page that an authenticated user will be redirected to if they request a page which they don't have the authority to access.
|
||||
attribute error-page {xsd:string}
|
||||
|
||||
intercept-url =
|
||||
## Specifies the access attributes and/or filter list for a particular set of URLs.
|
File diff suppressed because it is too large
Load Diff
|
@ -10,7 +10,7 @@
|
|||
<xsl:output method="xml" indent="yes"/>
|
||||
|
||||
<xsl:variable name="elts-to-inline">
|
||||
<xsl:text>,anonymous,concurrent-session-control,filter-chain,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,remember-me,salt-source,x509,</xsl:text>
|
||||
<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,remember-me,salt-source,x509,</xsl:text>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:template match="xs:element">
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
|||
import org.springframework.security.openid.OpenIDAuthenticationProcessingFilter;
|
||||
import org.springframework.security.openid.OpenIDAuthenticationProvider;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.security.web.AccessDeniedHandlerImpl;
|
||||
import org.springframework.security.web.ExceptionTranslationFilter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.FilterInvocation;
|
||||
|
@ -351,6 +352,49 @@ public class HttpSecurityBeanDefinitionParserTests {
|
|||
assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessDeniedHandlerPageIsSetCorectly() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true'>" +
|
||||
" <access-denied-handler error-page='/go-away'/>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessDeniedHandlerIsSetCorectly() throws Exception {
|
||||
setContext(
|
||||
" <b:bean id='adh' class='" + AccessDeniedHandlerImpl.class.getName() + "'/>" +
|
||||
" <http auto-config='true'>" +
|
||||
" <access-denied-handler ref='adh'/>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
AccessDeniedHandlerImpl adh = (AccessDeniedHandlerImpl) appContext.getBean("adh");
|
||||
assertSame(adh, FieldUtils.getFieldValue(filter, "accessDeniedHandler"));
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void accessDeniedHandlerAndAccessDeniedHandlerAreMutuallyExclusive() throws Exception {
|
||||
setContext(
|
||||
" <http auto-config='true' access-denied-page='/go-away'>" +
|
||||
" <access-denied-handler error-page='/go-away'/>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void accessDeniedHandlerPageAndRefAreMutuallyExclusive() throws Exception {
|
||||
setContext(
|
||||
" <b:bean id='adh' class='" + AccessDeniedHandlerImpl.class.getName() + "'/>" +
|
||||
" <http auto-config='true'>" +
|
||||
" <access-denied-handler error-page='/go-away' ref='adh'/>" +
|
||||
" </http>" + AUTH_PROVIDER_XML);
|
||||
ExceptionTranslationFilter filter = (ExceptionTranslationFilter) appContext.getBean(BeanIds.EXCEPTION_TRANSLATION_FILTER);
|
||||
assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalFiltersAreTreatedCorrectly() throws Exception {
|
||||
// Decorated user-filters should be added to stack. The others should be ignored.
|
||||
|
|
|
@ -16,7 +16,7 @@ public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext
|
|||
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n" +
|
||||
" xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\n" +
|
||||
"http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd\n" +
|
||||
"http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.5.xsd'>\n";
|
||||
"http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd'>\n";
|
||||
private static final String BEANS_CLOSE = "</b:beans>\n";
|
||||
|
||||
Resource inMemoryXml;
|
||||
|
|
Loading…
Reference in New Issue