diff --git a/core/src/main/java/org/springframework/security/util/FieldUtils.java b/core/src/main/java/org/springframework/security/util/FieldUtils.java
index c76b40e2b7..81433a1040 100644
--- a/core/src/main/java/org/springframework/security/util/FieldUtils.java
+++ b/core/src/main/java/org/springframework/security/util/FieldUtils.java
@@ -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");
diff --git a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc
index 846d3514c1..1bbfb1fa46 100644
--- a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc
+++ b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.rnc
@@ -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 =
diff --git a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd
index 457e1f1fe4..b5cce75f31 100644
--- a/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd
+++ b/core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd
@@ -144,6 +144,12 @@
+
+
+
+
+
+
Defines an LDAP server location or starts an embedded server. The url
@@ -609,7 +615,7 @@
-
+
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".
-
-
-
-
-
-
@@ -650,30 +650,18 @@
-
+
Whether test URLs should be converted to lower case prior to comparing
with defined path patterns. If unspecified, defaults to "true".
-
-
-
-
-
-
-
+
Provides versions of HttpServletRequest security methods such as
isUserInRole() and getPrincipal() which are implemented by accessing the Spring
SecurityContext. Defaults to "true".
-
-
-
-
-
-
@@ -710,17 +698,17 @@
used.
-
+
Corresponds to the observeOncePerRequest property of
FilterSecurityInterceptor. Defaults to "false"
-
-
-
-
-
-
+
+
+
+ Allows the access denied page to be set (the user will be redirected here
+ if an AccessDeniedException is raised).
+
@@ -794,17 +782,11 @@
specified, defaults to /.
-
+
Specifies whether a logout also causes HttpSession invalidation, which is
generally desirable. If unspecified, defaults to true.
-
-
-
-
-
-
@@ -914,16 +896,10 @@
context.
-
+
as for http element
-
-
-
-
-
-
@@ -942,14 +918,7 @@
-
-
-
-
-
-
-
-
+
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"
-
+
Can be set to "true" to mark an account as locked and
unusable.
-
-
-
-
-
-
diff --git a/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java b/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java
index 63aae7bc47..336141076a 100644
--- a/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java
+++ b/core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java
@@ -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("" + 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);
}