FEDIZ-169 - Enforce mandatory requested claims on the RP side
diff --git a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
index cc94fee..1695f57 100644
--- a/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
+++ b/plugins/core/src/main/java/org/apache/cxf/fediz/core/processor/FederationProcessorImpl.java
@@ -203,6 +203,10 @@
expires = validatorResponse.getExpires();
}
testForReplayAttack(validatorResponse.getUniqueTokenId(), config, expires);
+ testForMandatoryClaims(((FederationProtocol)config.getProtocol()).getRoleURI(),
+ ((FederationProtocol)config.getProtocol()).getClaimTypesRequested(),
+ validatorResponse.getClaims(),
+ validatorResponse.getRoles() != null && !validatorResponse.getRoles().isEmpty());
Date created = validatorResponse.getCreated();
if (lifeTime != null && lifeTime.getCreated() != null) {
@@ -637,6 +641,35 @@
}
return wReq;
}
+
+ private void testForMandatoryClaims(String roleURI,
+ List<org.apache.cxf.fediz.core.config.Claim> requestedClaims,
+ List<org.apache.cxf.fediz.core.Claim> receivedClaims,
+ boolean foundRoles
+ ) throws ProcessingException {
+ if (requestedClaims != null) {
+ for (org.apache.cxf.fediz.core.config.Claim requestedClaim : requestedClaims) {
+ if (!requestedClaim.isOptional()) {
+ boolean found = false;
+ for (org.apache.cxf.fediz.core.Claim receivedClaim : receivedClaims) {
+ if (requestedClaim.getType().equals(receivedClaim.getClaimType().toString())) {
+ found = true;
+ break;
+ }
+ }
+ if (!found && foundRoles && roleURI != null && roleURI.equals(requestedClaim.getType())) {
+ // Maybe the requested claim is a role, which has already been removed
+ // from the claims collection
+ found = true;
+ }
+ if (!found) {
+ LOG.warn("Mandatory claim {} not found in token", requestedClaim.getType());
+ throw new ProcessingException("Mandatory claim not found in token", TYPE.INVALID_REQUEST);
+ }
+ }
+ }
+ }
+ }
private static class DecryptionCallbackHandler implements CallbackHandler {
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
index 1c7d693..bd69b14 100644
--- a/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/AbstractSAMLCallbackHandler.java
@@ -354,7 +354,13 @@
attributeBean2.setQualifiedName(this.customClaimName);
attributeBean2.setNameFormat(this.getAttributeNameFormat());
}
- attributeBean2.addAttributeValue("CH");
+ if (customAttributeValues != null && !customAttributeValues.isEmpty()) {
+ for (Object obj : customAttributeValues) {
+ attributeBean2.addAttributeValue(obj);
+ }
+ } else {
+ attributeBean2.addAttributeValue("CH");
+ }
attributeList.add(attributeBean2);
attrStateBean.setSamlAttributes(attributeList);
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/RequestedClaimsTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/RequestedClaimsTest.java
new file mode 100644
index 0000000..79c836c
--- /dev/null
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/RequestedClaimsTest.java
@@ -0,0 +1,336 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.fediz.core.federation;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.util.Collections;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import org.apache.cxf.fediz.common.STSUtil;
+import org.apache.cxf.fediz.common.SecurityTestUtil;
+import org.apache.cxf.fediz.core.Claim;
+import org.apache.cxf.fediz.core.ClaimTypes;
+import org.apache.cxf.fediz.core.FederationConstants;
+import org.apache.cxf.fediz.core.KeystoreCallbackHandler;
+import org.apache.cxf.fediz.core.SAML2CallbackHandler;
+import org.apache.cxf.fediz.core.config.FedizConfigurator;
+import org.apache.cxf.fediz.core.config.FedizContext;
+import org.apache.cxf.fediz.core.config.jaxb.ArgumentType;
+import org.apache.cxf.fediz.core.config.jaxb.AudienceUris;
+import org.apache.cxf.fediz.core.config.jaxb.CallbackType;
+import org.apache.cxf.fediz.core.config.jaxb.CertificateStores;
+import org.apache.cxf.fediz.core.config.jaxb.ClaimType;
+import org.apache.cxf.fediz.core.config.jaxb.ClaimTypesRequested;
+import org.apache.cxf.fediz.core.config.jaxb.ContextConfig;
+import org.apache.cxf.fediz.core.config.jaxb.FederationProtocolType;
+import org.apache.cxf.fediz.core.config.jaxb.FedizConfig;
+import org.apache.cxf.fediz.core.config.jaxb.KeyStoreType;
+import org.apache.cxf.fediz.core.config.jaxb.ProtocolType;
+import org.apache.cxf.fediz.core.config.jaxb.TrustManagersType;
+import org.apache.cxf.fediz.core.config.jaxb.TrustedIssuerType;
+import org.apache.cxf.fediz.core.config.jaxb.TrustedIssuers;
+import org.apache.cxf.fediz.core.config.jaxb.ValidationType;
+import org.apache.cxf.fediz.core.exception.ProcessingException;
+import org.apache.cxf.fediz.core.processor.FederationProcessorImpl;
+import org.apache.cxf.fediz.core.processor.FedizProcessor;
+import org.apache.cxf.fediz.core.processor.FedizRequest;
+import org.apache.cxf.fediz.core.processor.FedizResponse;
+import org.apache.wss4j.common.crypto.Crypto;
+import org.apache.wss4j.common.crypto.CryptoFactory;
+import org.apache.wss4j.common.ext.WSPasswordCallback;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.saml.SAMLCallback;
+import org.apache.wss4j.common.saml.SAMLUtil;
+import org.apache.wss4j.common.saml.SamlAssertionWrapper;
+import org.apache.wss4j.common.saml.bean.AudienceRestrictionBean;
+import org.apache.wss4j.common.saml.bean.ConditionsBean;
+import org.apache.wss4j.common.saml.builder.SAML2Constants;
+import org.apache.wss4j.common.util.DOM2Writer;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+
+/**
+ * Test for requested claims
+ */
+public class RequestedClaimsTest {
+
+ private static final String ISSUER = "FedizSTSIssuer";
+ private static final String PROTOCOL_VERSION = "1.0.0";
+ //private static final String REQUEST = "request value";
+ private static final String REPLY = "reply value";
+ private static final String TARGET_REALM = "target realm";
+ private static final String HOME_REALM_CLASS = "org.apache.fediz.realm.MyHomeRealm.class";
+ private static final String FRESHNESS_VALUE = "10000";
+
+ private static final String CONFIG_NAME = "ROOT";
+ private static final String CLOCK_SKEW = "1000";
+
+ private static final String AUTH_TYPE_VALUE = "some auth type";
+
+ private static final String AUDIENCE_URI_1 = "http://host_one:port/url";
+
+ private static final String ROLE_DELIMITER = ";";
+ private static final String ROLE_URI = "http://someserver:8080/path/roles.uri";
+ private static final String CLAIM_TYPE_1 = ClaimTypes.FIRSTNAME.toString();
+ private static final String CLAIM_TYPE_2 = ClaimTypes.LASTNAME.toString();
+
+ private static Crypto crypto;
+ private static CallbackHandler cbPasswordHandler = new KeystoreCallbackHandler();
+
+ @BeforeClass
+ public static void init() {
+ try {
+ crypto = CryptoFactory.getInstance("signature.properties");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @AfterClass
+ public static void cleanup() {
+ SecurityTestUtil.cleanup();
+ }
+
+ //CHECKSTYLE:OFF
+ private FedizConfig createConfiguration() throws JAXBException {
+
+ FedizConfig rootConfig = new FedizConfig();
+ ContextConfig config = new ContextConfig();
+ rootConfig.getContextConfig().add(config);
+
+ config.setName(CONFIG_NAME);
+ config.setMaximumClockSkew(new BigInteger(CLOCK_SKEW));
+
+ CertificateStores certStores = new CertificateStores();
+
+ TrustManagersType tm0 = new TrustManagersType();
+ KeyStoreType ks0 = new KeyStoreType();
+ ks0.setType("JKS");
+ ks0.setPassword("storepass");
+ ks0.setFile("ststrust.jks");
+ tm0.setKeyStore(ks0);
+
+ certStores.getTrustManager().add(tm0);
+
+ config.setCertificateStores(certStores);
+
+ TrustedIssuers trustedIssuers = new TrustedIssuers();
+
+ TrustedIssuerType ti0 = new TrustedIssuerType();
+ ti0.setCertificateValidation(ValidationType.PEER_TRUST);
+ trustedIssuers.getIssuer().add(ti0);
+
+ config.setTrustedIssuers(trustedIssuers);
+
+ ProtocolType protocol = new FederationProtocolType();
+
+ CallbackType authType = new CallbackType();
+ authType.setType(ArgumentType.STRING);
+ authType.setValue(AUTH_TYPE_VALUE);
+ ((FederationProtocolType)protocol).setAuthenticationType(authType);
+
+ CallbackType freshness = new CallbackType();
+ freshness.setValue(FRESHNESS_VALUE);
+ ((FederationProtocolType)protocol).setFreshness(freshness);
+
+ CallbackType homeRealm = new CallbackType();
+ homeRealm.setType(ArgumentType.CLASS);
+ homeRealm.setValue(HOME_REALM_CLASS);
+ ((FederationProtocolType)protocol).setHomeRealm(homeRealm);
+
+ ((FederationProtocolType)protocol).setReply(REPLY);
+ ((FederationProtocolType)protocol).setVersion(PROTOCOL_VERSION);
+
+ config.setProtocol(protocol);
+
+ AudienceUris audienceUris = new AudienceUris();
+ audienceUris.getAudienceItem().add(AUDIENCE_URI_1);
+ config.setAudienceUris(audienceUris);
+
+ protocol.setRoleDelimiter(ROLE_DELIMITER);
+ protocol.setRoleURI(ROLE_URI);
+
+ ClaimTypesRequested claimTypeReq = new ClaimTypesRequested();
+ ClaimType claimType = new ClaimType();
+ claimType.setOptional(false);
+ claimType.setType(CLAIM_TYPE_1);
+ claimTypeReq.getClaimType().add(claimType);
+
+ ClaimType claimType2 = new ClaimType();
+ claimType2.setOptional(true);
+ claimType2.setType(CLAIM_TYPE_2);
+ claimTypeReq.getClaimType().add(claimType2);
+
+ protocol.setClaimTypesRequested(claimTypeReq);
+
+ CallbackType realm = new CallbackType();
+ realm.setValue(TARGET_REALM);
+ protocol.setRealm(realm);
+
+ CallbackType issuer = new CallbackType();
+ issuer.setValue(ISSUER);
+ protocol.setIssuer(issuer);
+
+ return rootConfig;
+
+ }
+
+ @org.junit.Test
+ public void testRequiredClaimIncluded() throws Exception {
+ SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+ callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+ callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+ callbackHandler.setIssuer(ISSUER);
+ callbackHandler.setSubjectName("alice");
+ callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+ callbackHandler.setCountryClaimName("country");
+ callbackHandler.setRoleAttributeName("role");
+ callbackHandler.setCustomClaimName(CLAIM_TYPE_1);
+ callbackHandler.setCustomAttributeValues(Collections.singletonList("xyz"));
+
+ ConditionsBean cp = new ConditionsBean();
+ AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean();
+ audienceRestriction.getAudienceURIs().add(AUDIENCE_URI_1);
+ cp.setAudienceRestrictions(Collections.singletonList(audienceRestriction));
+ callbackHandler.setConditions(cp);
+
+ SAMLCallback samlCallback = new SAMLCallback();
+ SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
+ SamlAssertionWrapper assertion = new SamlAssertionWrapper(samlCallback);
+
+ String rstr = createSamlToken(assertion, "mystskey", true);
+
+ FedizRequest wfReq = new FedizRequest();
+ wfReq.setAction(FederationConstants.ACTION_SIGNIN);
+ wfReq.setResponseToken(rstr);
+
+ FedizConfig config = createConfiguration();
+ StringWriter writer = new StringWriter();
+ final JAXBContext jaxbContext = JAXBContext.newInstance(FedizConfig.class);
+ jaxbContext.createMarshaller().marshal(config, writer);
+ StringReader reader = new StringReader(writer.toString());
+
+ FedizConfigurator configurator = new FedizConfigurator();
+ configurator.loadConfig(reader);
+ FedizContext context = configurator.getFedizContext(CONFIG_NAME);
+
+ FedizProcessor wfProc = new FederationProcessorImpl();
+ FedizResponse wfRes = wfProc.processRequest(wfReq, context);
+
+ Object claimValue = null;
+ for (Claim c : wfRes.getClaims()) {
+ if (CLAIM_TYPE_1.equals(c.getClaimType().toString())) {
+ claimValue = c.getValue();
+ }
+ }
+
+ Assert.assertEquals("xyz", claimValue);
+ }
+
+ @org.junit.Test
+ public void testRequiredClaimNotIncluded() throws Exception {
+ SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+ callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+ callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+ callbackHandler.setIssuer(ISSUER);
+ callbackHandler.setSubjectName("alice");
+ callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+ callbackHandler.setCountryClaimName("country");
+ callbackHandler.setRoleAttributeName("role");
+ callbackHandler.setCustomClaimName(CLAIM_TYPE_2);
+ callbackHandler.setCustomAttributeValues(Collections.singletonList("xyz"));
+
+ ConditionsBean cp = new ConditionsBean();
+ AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean();
+ audienceRestriction.getAudienceURIs().add(AUDIENCE_URI_1);
+ cp.setAudienceRestrictions(Collections.singletonList(audienceRestriction));
+ callbackHandler.setConditions(cp);
+
+ SAMLCallback samlCallback = new SAMLCallback();
+ SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
+ SamlAssertionWrapper assertion = new SamlAssertionWrapper(samlCallback);
+
+ String rstr = createSamlToken(assertion, "mystskey", true);
+
+ FedizRequest wfReq = new FedizRequest();
+ wfReq.setAction(FederationConstants.ACTION_SIGNIN);
+ wfReq.setResponseToken(rstr);
+
+ FedizConfig config = createConfiguration();
+ StringWriter writer = new StringWriter();
+ final JAXBContext jaxbContext = JAXBContext.newInstance(FedizConfig.class);
+ jaxbContext.createMarshaller().marshal(config, writer);
+ StringReader reader = new StringReader(writer.toString());
+
+ FedizConfigurator configurator = new FedizConfigurator();
+ configurator.loadConfig(reader);
+ FedizContext context = configurator.getFedizContext(CONFIG_NAME);
+
+ FedizProcessor wfProc = new FederationProcessorImpl();
+ try {
+ wfProc.processRequest(wfReq, context);
+ Assert.fail("Failure expected on a mandatory claim not being included");
+ } catch (ProcessingException ex) {
+ // expected
+ }
+ }
+
+ private String createSamlToken(SamlAssertionWrapper assertion, String alias, boolean sign)
+ throws IOException, UnsupportedCallbackException, WSSecurityException, Exception {
+ return createSamlToken(assertion, alias, sign, STSUtil.SAMPLE_RSTR_COLL_MSG);
+ }
+
+ private String createSamlToken(SamlAssertionWrapper assertion, String alias, boolean sign, String rstr)
+ throws IOException, UnsupportedCallbackException, WSSecurityException, Exception {
+ WSPasswordCallback[] cb = {
+ new WSPasswordCallback(alias, WSPasswordCallback.SIGNATURE)
+ };
+ cbPasswordHandler.handle(cb);
+ String password = cb[0].getPassword();
+
+ if (sign) {
+ assertion.signAssertion(alias, password, crypto, false);
+ }
+ Document doc = STSUtil.toSOAPPart(rstr);
+ Element token = assertion.toDOM(doc);
+
+ Element e = SAMLTokenValidatorOldTest.findElement(doc, "RequestedSecurityToken",
+ FederationConstants.WS_TRUST_13_NS);
+ if (e == null) {
+ e = SAMLTokenValidatorOldTest.findElement(doc, "RequestedSecurityToken",
+ FederationConstants.WS_TRUST_2005_02_NS);
+ }
+ e.appendChild(token);
+ return DOM2Writer.nodeToString(doc);
+ }
+}
\ No newline at end of file
diff --git a/services/sts/src/main/webapp/WEB-INF/userClaims.xml b/services/sts/src/main/webapp/WEB-INF/userClaims.xml
index 1a2b12f..13bd37f 100644
--- a/services/sts/src/main/webapp/WEB-INF/userClaims.xml
+++ b/services/sts/src/main/webapp/WEB-INF/userClaims.xml
@@ -75,7 +75,7 @@
value="tcooper@realma.org" />
<entry
key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"
- value="" />
+ value="Secretary" />
</util:map>
<util:map id="userClaimsREALMB">
@@ -126,7 +126,7 @@
value="tcooper@realmb.org" />
<entry
key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"
- value="" />
+ value="Secretary" />
</util:map>
<util:list id="supportedClaims">
@@ -136,4 +136,4 @@
<value>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</value>
</util:list>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/services/sts/src/main/webapp/WEB-INF/userClaimsKerberos.xml b/services/sts/src/main/webapp/WEB-INF/userClaimsKerberos.xml
index 38ff27c..aa5faff 100644
--- a/services/sts/src/main/webapp/WEB-INF/userClaimsKerberos.xml
+++ b/services/sts/src/main/webapp/WEB-INF/userClaimsKerberos.xml
@@ -74,7 +74,7 @@
value="tcooper@realma.org" />
<entry
key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"
- value="" />
+ value="Secretary" />
</util:map>
<util:map id="userClaimsREALMB">
@@ -125,7 +125,7 @@
value="tcooper@realmb.org" />
<entry
key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"
- value="" />
+ value="Secretary" />
</util:map>
<util:list id="supportedClaims">
@@ -135,4 +135,4 @@
<value>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role</value>
</util:list>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/systests/oidc/src/test/resources/realma/entities-realma.xml b/systests/oidc/src/test/resources/realma/entities-realma.xml
index 20261ee..95a91eb 100644
--- a/systests/oidc/src/test/resources/realma/entities-realma.xml
+++ b/systests/oidc/src/test/resources/realma/entities-realma.xml
@@ -126,6 +126,11 @@
<property name="optional" value="false" />
</bean>
<bean class="org.apache.cxf.fediz.service.idp.service.jpa.ApplicationClaimEntity">
+ <property name="application" ref="srv-oidc" />
+ <property name="claim" ref="claim_role" />
+ <property name="optional" value="false" />
+ </bean>
+ <bean class="org.apache.cxf.fediz.service.idp.service.jpa.ApplicationClaimEntity">
<property name="application" ref="srv-fedizhelloworld" />
<property name="claim" ref="claim_givenname" />
<property name="optional" value="false" />
diff --git a/systests/webapps/cxfWebapp/src/main/java/org/apache/cxf/fediz/example/Service.java b/systests/webapps/cxfWebapp/src/main/java/org/apache/cxf/fediz/example/Service.java
index a82a8a4..21c88d5 100644
--- a/systests/webapps/cxfWebapp/src/main/java/org/apache/cxf/fediz/example/Service.java
+++ b/systests/webapps/cxfWebapp/src/main/java/org/apache/cxf/fediz/example/Service.java
@@ -64,7 +64,7 @@
}
@Path("/fedservlet")
- @RolesAllowed({ "User", "Admin", "Manager", "Authenticated" })
+ @RolesAllowed({ "User", "Admin", "Manager", "Authenticated", "Secretary" })
@GET
@Produces("text/html")
public String doGetSecure(@Context UriInfo uriInfo) throws Exception {
diff --git a/systests/webapps/simpleWebapp/src/main/webapp/WEB-INF/web.xml b/systests/webapps/simpleWebapp/src/main/webapp/WEB-INF/web.xml
index de8b046..33044a1 100644
--- a/systests/webapps/simpleWebapp/src/main/webapp/WEB-INF/web.xml
+++ b/systests/webapps/simpleWebapp/src/main/webapp/WEB-INF/web.xml
@@ -73,6 +73,9 @@
<security-role>
<role-name>Authenticated</role-name>
</security-role>
+ <security-role>
+ <role-name>Secretary</role-name>
+ </security-role>
<security-constraint>
<web-resource-collection>
diff --git a/systests/webapps/springPreauthWebapp/src/main/webapp/WEB-INF/applicationContext-security.xml b/systests/webapps/springPreauthWebapp/src/main/webapp/WEB-INF/applicationContext-security.xml
index 3f09691..ee5df2a 100644
--- a/systests/webapps/springPreauthWebapp/src/main/webapp/WEB-INF/applicationContext-security.xml
+++ b/systests/webapps/springPreauthWebapp/src/main/webapp/WEB-INF/applicationContext-security.xml
@@ -103,7 +103,7 @@
<sec:intercept-url pattern="/secure/manager/**" access="ROLE_MANAGER"/>
<sec:intercept-url pattern="/secure/admin/**" access="ROLE_ADMIN"/>
<sec:intercept-url pattern="/secure/user/**" access="ROLE_USER,ROLE_ADMIN,ROLE_MANAGER"/>
- <sec:intercept-url pattern="/secure/fedservlet" access="ROLE_USER,ROLE_ADMIN,ROLE_MANAGER,ROLE_AUTHENTICATED"/>
+ <sec:intercept-url pattern="/secure/fedservlet" access="ROLE_USER,ROLE_ADMIN,ROLE_MANAGER,ROLE_AUTHENTICATED,ROLE_SECRETARY"/>
</sec:filter-invocation-definition-source>
</property>
</bean>
diff --git a/systests/webapps/springPreauthWebapp/src/main/webapp/WEB-INF/web.xml b/systests/webapps/springPreauthWebapp/src/main/webapp/WEB-INF/web.xml
index 60a1b47..4cd996b 100644
--- a/systests/webapps/springPreauthWebapp/src/main/webapp/WEB-INF/web.xml
+++ b/systests/webapps/springPreauthWebapp/src/main/webapp/WEB-INF/web.xml
@@ -107,6 +107,9 @@
<security-role>
<role-name>Authenticated</role-name>
</security-role>
+ <security-role>
+ <role-name>Secretary</role-name>
+ </security-role>
<security-constraint>
<web-resource-collection>