SEC-746: impossible to specify errorPage for the AccessDeniedHandlerImp when using namespace based configuration

http://jira.springframework.org/browse/SEC-746. Added access-denied-page to http element.
This commit is contained in:
Luke Taylor 2008-04-07 22:17:09 +00:00
parent f57ba43780
commit 243b5f4a2a
4 changed files with 74 additions and 79 deletions

View File

@ -17,6 +17,7 @@ package org.springframework.security.util;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
@ -56,8 +57,7 @@ public final class FieldUtils {
*
* @throws IllegalStateException if field could not be found
*/
public static Field getField(Class clazz, String fieldName)
throws IllegalStateException {
public static Field getField(Class clazz, String fieldName) throws IllegalStateException {
Assert.notNull(clazz, "Class required");
Assert.hasText(fieldName, "Field name required");
@ -72,6 +72,31 @@ public final class FieldUtils {
throw new IllegalStateException("Could not locate field '" + fieldName + "' on class " + clazz);
}
}
/**
* Returns the value of a (nested) field on a bean. Intended for testing.
* @param bean the object
* @param fieldName the field name, with "." separating nested properties
* @return the value of the nested field
*/
public static Object getFieldValue(Object bean, String fieldName) throws IllegalAccessException {
Assert.notNull(bean, "Bean cannot be null");
Assert.hasText(fieldName, "Field name required");
String[] nestedFields = StringUtils.tokenizeToStringArray(fieldName, ".");
Class componentClass = bean.getClass();
Field field = null;
Object value = bean;
for (int i=0; i < nestedFields.length; i++) {
field = getField(componentClass, nestedFields[i]);
field.setAccessible(true);
value = field.get(value);
componentClass = value.getClass();
}
return value;
}
public static String getMutatorName(String fieldName) {
Assert.hasText(fieldName, "FieldName required");

View File

@ -1,12 +1,9 @@
namespace beans = "http://www.springframework.org/schema/beans"
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"
default namespace = "http://www.springframework.org/schema/security"
start = http | ldap-server | authentication-provider | ldap-authentication-provider | user-service
start = http | ldap-server | authentication-provider | ldap-authentication-provider | any-user-service | ldap-server | ldap-authentication-provider
hash =
## Defines the hashing algorithm used on user passwords. We recommend strongly against using MD4, as it is a very weak hashing algorithm.
@ -52,6 +49,8 @@ user-property =
system-wide =
## A single value that will be used as the salt for a password encoder.
attribute system-wide {xsd:string}
boolean = "true" | "false"
ldap-server =
@ -189,7 +188,7 @@ http =
element http {http.attlist, (intercept-url+ & 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 {"true" | "false" }?
attribute auto-config {boolean}?
http.attlist &=
## Controls the eagerness with which an HTTP session is created. If not set, defaults to "ifRequired".
attribute create-session {"ifRequired" | "always" | "never" }?
@ -198,10 +197,10 @@ http.attlist &=
path-type?
http.attlist &=
## Whether test URLs should be converted to lower case prior to comparing with defined path patterns. If unspecified, defaults to "true".
attribute lowercase-comparisons {"true" | "false"}?
attribute lowercase-comparisons {boolean}?
http.attlist &=
## Provides versions of HttpServletRequest security methods such as isUserInRole() and getPrincipal() which are implemented by accessing the Spring SecurityContext. Defaults to "true".
attribute servlet-api-provision {"true" | "false"}?
attribute servlet-api-provision {boolean}?
http.attlist &=
## Optional attribute specifying the ID of the AccessDecisionManager implementation which should be used for authorizing HTTP requests.
attribute access-decision-manager-ref {xsd:string}?
@ -216,8 +215,10 @@ http.attlist &=
attribute entry-point-ref {xsd:string}?
http.attlist &=
## Corresponds to the observeOncePerRequest property of FilterSecurityInterceptor. Defaults to "false"
attribute once-per-request {"true" | "false"}?
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).
attribute access-denied-page {xsd:string}?
intercept-url =
## Specifies the access attributes and/or filter list for a particular set of URLs.
@ -250,7 +251,7 @@ logout.attlist &=
attribute logout-success-url {xsd:string}?
logout.attlist &=
## Specifies whether a logout also causes HttpSession invalidation, which is generally desirable. If unspecified, defaults to true.
attribute invalidate-session {"true" | "false"}?
attribute invalidate-session {boolean}?
form-login =
## Sets up a form login configuration for authentication with a username and password
@ -294,7 +295,7 @@ fids.attlist &=
id?
fids.attlist &=
## as for http element
attribute lowercase-comparisons {"true" | "false"}?
attribute lowercase-comparisons {boolean}?
fids.attlist &=
## as for http element
path-type?
@ -312,7 +313,7 @@ concurrent-sessions.attlist &=
concurrent-sessions.attlist &=
attribute expired-url {xsd:string}?
concurrent-sessions.attlist &=
attribute exception-if-maximum-exceeded {"true" | "false"}?
attribute exception-if-maximum-exceeded {boolean}?
concurrent-sessions.attlist &=
## Allows you to define an alias for the SessionRegistry bean in order to access it in your own configuration
attribute session-registry-alias {xsd:string}?
@ -400,7 +401,7 @@ user.attlist &=
attribute authorities {xsd:string}
user.attlist &=
## Can be set to "true" to mark an account as locked and unusable.
attribute locked {"true" | "false"}?
attribute locked {boolean}?
jdbc-user-service =

View File

@ -144,6 +144,12 @@
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:simpleType name="boolean">
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="ldap-server">
<xs:annotation>
<xs:documentation>Defines an LDAP server location or starts an embedded server. The url
@ -609,7 +615,7 @@
</xs:complexType>
</xs:element>
<xs:attributeGroup name="http.attlist">
<xs:attribute name="auto-config">
<xs:attribute name="auto-config" type="security:boolean">
<xs:annotation>
<xs:documentation>Automatically registers a login form, BASIC authentication, anonymous
authentication, logout services, remember-me and servlet-api-integration. If set to
@ -617,12 +623,6 @@
configuration of each by providing the respective element). If unspecified, defaults to
"false".</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="create-session">
<xs:annotation>
@ -650,30 +650,18 @@
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="lowercase-comparisons">
<xs:attribute name="lowercase-comparisons" type="security:boolean">
<xs:annotation>
<xs:documentation>Whether test URLs should be converted to lower case prior to comparing
with defined path patterns. If unspecified, defaults to "true".</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="servlet-api-provision">
<xs:attribute name="servlet-api-provision" type="security:boolean">
<xs:annotation>
<xs:documentation>Provides versions of HttpServletRequest security methods such as
isUserInRole() and getPrincipal() which are implemented by accessing the Spring
SecurityContext. Defaults to "true".</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="access-decision-manager-ref" type="xs:string">
<xs:annotation>
@ -710,17 +698,17 @@
used.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="once-per-request">
<xs:attribute name="once-per-request" type="security:boolean">
<xs:annotation>
<xs:documentation>Corresponds to the observeOncePerRequest property of
FilterSecurityInterceptor. Defaults to "false"</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="access-denied-page" type="xs:string">
<xs:annotation>
<xs:documentation>Allows the access denied page to be set (the user will be redirected here
if an AccessDeniedException is raised).</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:attributeGroup name="intercept-url.attlist">
@ -794,17 +782,11 @@
specified, defaults to /.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="invalidate-session">
<xs:attribute name="invalidate-session" type="security:boolean">
<xs:annotation>
<xs:documentation>Specifies whether a logout also causes HttpSession invalidation, which is
generally desirable. If unspecified, defaults to true.</xs:documentation>
</xs:annotation>
<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 name="form-login.attlist">
@ -914,16 +896,10 @@
context.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="lowercase-comparisons">
<xs:attribute name="lowercase-comparisons" type="security:boolean">
<xs:annotation>
<xs:documentation>as for http element</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="path-type">
<xs:annotation>
@ -942,14 +918,7 @@
<xs:attributeGroup name="concurrent-sessions.attlist">
<xs:attribute name="max-sessions" type="xs:positiveInteger"/>
<xs:attribute name="expired-url" type="xs:string"/>
<xs:attribute name="exception-if-maximum-exceeded">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name="exception-if-maximum-exceeded" type="security:boolean"/>
<xs:attribute name="session-registry-alias" type="xs:string">
<xs:annotation>
<xs:documentation>Allows you to define an alias for the SessionRegistry bean in order to
@ -1136,17 +1105,11 @@
comma (but no space). For example, "ROLE_USER,ROLE_ADMINISTRATOR"</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="locked">
<xs:attribute name="locked" type="security:boolean">
<xs:annotation>
<xs:documentation>Can be set to "true" to mark an account as locked and
unusable.</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="true"/>
<xs:enumeration value="false"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="jdbc-user-service" substitutionGroup="security:any-user-service">

View File

@ -1,10 +1,6 @@
package org.springframework.security.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;
import java.util.Iterator;
import java.util.List;
@ -35,11 +31,11 @@ import org.springframework.security.ui.WebAuthenticationDetails;
import org.springframework.security.ui.basicauth.BasicProcessingFilter;
import org.springframework.security.ui.logout.LogoutFilter;
import org.springframework.security.ui.preauth.x509.X509PreAuthenticatedProcessingFilter;
import org.springframework.security.ui.rememberme.AbstractRememberMeServices;
import org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices;
import org.springframework.security.ui.rememberme.RememberMeProcessingFilter;
import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
import org.springframework.security.ui.webapp.DefaultLoginPageGeneratingFilter;
import org.springframework.security.util.FieldUtils;
import org.springframework.security.util.FilterChainProxy;
import org.springframework.security.util.InMemoryXmlApplicationContext;
import org.springframework.security.util.PortMapperImpl;
@ -198,6 +194,17 @@ public class HttpSecurityBeanDefinitionParserTests {
FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) filters.get(filters.size() - 1);
assertTrue(fsi.isObserveOncePerRequest());
}
@Test
public void accessDeniedPageAttributeIsSupported() throws Exception {
setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
FilterChainProxy filterChainProxy = getFilterChainProxy();
List filters = filterChainProxy.getFilters("/someurl");
ExceptionTranslationFilter etf = (ExceptionTranslationFilter) filters.get(filters.size() - 2);
assertEquals("/access-denied", FieldUtils.getFieldValue(etf, "accessDeniedHandler.errorPage"));
}
@Test
@ -376,7 +383,6 @@ public class HttpSecurityBeanDefinitionParserTests {
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}