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>