You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2014/07/23 18:24:06 UTC

[2/4] Adding unit tests for SAML SSO

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/617fd4e9/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/SAMLTokenValidatorOldTest.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/SAMLTokenValidatorOldTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/SAMLTokenValidatorOldTest.java
new file mode 100644
index 0000000..fb21c21
--- /dev/null
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/federation/SAMLTokenValidatorOldTest.java
@@ -0,0 +1,399 @@
+/**
+ * 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.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.apache.cxf.fediz.common.STSUtil;
+import org.apache.cxf.fediz.common.SecurityTestUtil;
+import org.apache.cxf.fediz.core.AbstractSAMLCallbackHandler;
+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.SAML1CallbackHandler;
+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.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.SAML1Constants;
+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;
+
+
+// This testcases tests the encoding implemented before CXF-4484
+public class SAMLTokenValidatorOldTest {
+    static final String TEST_USER = "alice";
+    static final String TEST_RSTR_ISSUER = "FedizSTSIssuer";
+    static final String TEST_AUDIENCE = "https://localhost/fedizhelloworld";
+    
+    private static final String CONFIG_FILE = "fediz_test_config.xml";
+    
+    private static Crypto crypto;
+    private static CallbackHandler cbPasswordHandler;
+    private static FedizConfigurator configurator;
+    
+    
+    @BeforeClass
+    public static void init() {
+        try {
+            crypto = CryptoFactory.getInstance("signature.properties");
+            cbPasswordHandler = new KeystoreCallbackHandler();
+            getFederationConfigurator();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        Assert.assertNotNull(configurator);
+
+    }
+    
+    @AfterClass
+    public static void cleanup() {
+        SecurityTestUtil.cleanup();
+    }
+    
+
+    private static FedizConfigurator getFederationConfigurator() {
+        if (configurator != null) {
+            return configurator;
+        }
+        try {
+            configurator = new FedizConfigurator();
+            final URL resource = Thread.currentThread().getContextClassLoader()
+                    .getResource(CONFIG_FILE);
+            File f = new File(resource.toURI());
+            configurator.loadConfig(f);
+            return configurator;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+    
+    /**
+     * Validate SAML 2 token which includes the role attribute with 2 values
+     * Roles are encoded as a multi-value saml attribute
+     */
+    @org.junit.Test
+    public void validateSAML2Token() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+        callbackHandler.setCountryClaimName("country");
+        callbackHandler.setRoleAttributeName("role");
+        
+        ConditionsBean cp = new ConditionsBean();
+        AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean();
+        audienceRestriction.getAudienceURIs().add(TEST_AUDIENCE);
+        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);
+        
+        configurator = null;
+        FedizContext config = getFederationConfigurator().getFedizContext("ROOT");
+        
+        FedizProcessor wfProc = new FederationProcessorImpl();
+        FedizResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER,
+                            wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
+                            .size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), callbackHandler.getRoleAttributeName());
+        
+    }
+    
+    /**
+     * Validate SAML 2 token where role information is provided
+     * within another SAML attribute
+     */
+    @org.junit.Test
+    public void validateSAML2TokenDifferentRoleURI() throws Exception {
+        SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
+        callbackHandler.setStatement(SAML2CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+        callbackHandler.setCountryClaimName("country");
+        callbackHandler.setRoleAttributeName("http://schemas.mycompany.com/claims/role");
+        
+        ConditionsBean cp = new ConditionsBean();
+        AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean();
+        audienceRestriction.getAudienceURIs().add(TEST_AUDIENCE);
+        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);
+        
+        configurator = null;
+        FedizContext config = getFederationConfigurator().getFedizContext("CUSTOMROLEURI");
+        
+        FedizProcessor wfProc = new FederationProcessorImpl();
+        FedizResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER, wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles().size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), callbackHandler.getRoleAttributeName());
+    }
+    
+    /**
+     * Validate SAML 2 token where role information is provided
+     * within another SAML attribute
+     */
+    @org.junit.Test
+    public void validateSAML1TokenDifferentRoleURI() throws Exception {
+        SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
+        callbackHandler.setStatement(SAML1CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML2Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        callbackHandler.setUseNameFormatAsNamespace(true);
+        callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+        callbackHandler.setRoleAttributeName("http://schemas.mycompany.com/claims/role");
+        ConditionsBean cp = new ConditionsBean();
+        AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean();
+        audienceRestriction.getAudienceURIs().add(TEST_AUDIENCE);
+        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);
+        
+        configurator = null;
+        FedizContext config = getFederationConfigurator().getFedizContext("CUSTOMROLEURI");
+        
+        FedizProcessor wfProc = new FederationProcessorImpl();
+        FedizResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER, wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles().size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), callbackHandler.getRoleAttributeName());
+    }
+    
+    /**
+     * Validate SAML 1.1 token which includes the role attribute with 2 values
+     * Roles are encoded as a multi-value saml attribute
+     */
+    @org.junit.Test
+    public void validateSAML1Token() throws Exception {
+        SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
+        callbackHandler.setStatement(SAML1CallbackHandler.Statement.ATTR);
+        callbackHandler.setConfirmationMethod(SAML1Constants.CONF_BEARER);
+        callbackHandler.setIssuer(TEST_RSTR_ISSUER);
+        callbackHandler.setSubjectName(TEST_USER);
+        callbackHandler.setUseNameFormatAsNamespace(true);
+        callbackHandler.setAttributeNameFormat(ClaimTypes.URI_BASE.toString());
+        callbackHandler.setRoleAttributeName("role");
+        
+        ConditionsBean cp = new ConditionsBean();
+        AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean();
+        audienceRestriction.getAudienceURIs().add(TEST_AUDIENCE);
+        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);
+        
+        configurator = null;
+        FedizContext config = getFederationConfigurator().getFedizContext("ROOT");
+        
+        FedizProcessor wfProc = new FederationProcessorImpl();
+        FedizResponse wfRes = wfProc.processRequest(wfReq, config);
+        
+        Assert.assertEquals("Principal name wrong", TEST_USER,
+                            wfRes.getUsername());
+        Assert.assertEquals("Issuer wrong", TEST_RSTR_ISSUER, wfRes.getIssuer());
+        Assert.assertEquals("Two roles must be found", 2, wfRes.getRoles()
+                            .size());
+        Assert.assertEquals("Audience wrong", TEST_AUDIENCE, wfRes.getAudience());
+        assertClaims(wfRes.getClaims(), callbackHandler.getRoleAttributeName());
+    }
+    
+    
+    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);
+    }
+    
+
+    
+    
+    /**
+     * Returns the first element that matches <code>name</code> and
+     * <code>namespace</code>. <p/> This is a replacement for a XPath lookup
+     * <code>//name</code> with the given namespace. It's somewhat faster than
+     * XPath, and we do not deal with prefixes, just with the real namespace URI
+     * 
+     * @param startNode Where to start the search
+     * @param name Local name of the element
+     * @param namespace Namespace URI of the element
+     * @return The found element or <code>null</code>
+     */
+    public static Element findElement(Node startNode, String name, String namespace) {
+        //
+        // Replace the formerly recursive implementation with a depth-first-loop
+        // lookup
+        //
+        if (startNode == null) {
+            return null;
+        }
+        Node startParent = startNode.getParentNode();
+        Node processedNode = null;
+
+        while (startNode != null) {
+            // start node processing at this point
+            if (startNode.getNodeType() == Node.ELEMENT_NODE
+                && startNode.getLocalName().equals(name)) {
+                String ns = startNode.getNamespaceURI();
+                if (ns != null && ns.equals(namespace)) {
+                    return (Element)startNode;
+                }
+
+                if ((namespace == null || namespace.length() == 0)
+                    && (ns == null || ns.length() == 0)) {
+                    return (Element)startNode;
+                }
+            }
+            processedNode = startNode;
+            startNode = startNode.getFirstChild();
+
+            // no child, this node is done.
+            if (startNode == null) {
+                // close node processing, get sibling
+                startNode = processedNode.getNextSibling();
+            }
+            // no more siblings, get parent, all children
+            // of parent are processed.
+            while (startNode == null) {
+                processedNode = processedNode.getParentNode();
+                if (processedNode == startParent) {
+                    return null;
+                }
+                // close parent node processing (processed node now)
+                startNode = processedNode.getNextSibling();
+            }
+        }
+        return null;
+    }
+    
+    private void assertClaims(List<Claim> claims, String roleClaimType) {
+        for (Claim c : claims) {
+            Assert.assertTrue("Invalid ClaimType URI: " + c.getClaimType(), 
+                              c.getClaimType().equals(roleClaimType)
+                              || c.getClaimType().equals(ClaimTypes.COUNTRY)
+                              || c.getClaimType().equals(AbstractSAMLCallbackHandler.CLAIM_TYPE_LANGUAGE)
+                              );
+        }
+    }
+
+
+    
+
+}

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/617fd4e9/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAML2PResponseComponentBuilder.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAML2PResponseComponentBuilder.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAML2PResponseComponentBuilder.java
new file mode 100644
index 0000000..ffaade7
--- /dev/null
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAML2PResponseComponentBuilder.java
@@ -0,0 +1,126 @@
+/**
+ * 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.samlsso;
+
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.opensaml.Configuration;
+import org.opensaml.common.SAMLObjectBuilder;
+import org.opensaml.common.SAMLVersion;
+import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.Response;
+import org.opensaml.saml2.core.Status;
+import org.opensaml.saml2.core.StatusCode;
+import org.opensaml.saml2.core.StatusMessage;
+import org.opensaml.xml.XMLObjectBuilderFactory;
+
+/**
+* A (basic) set of utility methods to construct SAML 2.0 Protocol Response statements
+*/
+public final class SAML2PResponseComponentBuilder {
+    
+    private static SAMLObjectBuilder<Response> responseBuilder;
+    
+    private static SAMLObjectBuilder<Issuer> issuerBuilder;
+    
+    private static SAMLObjectBuilder<Status> statusBuilder;
+    
+    private static SAMLObjectBuilder<StatusCode> statusCodeBuilder;
+    
+    private static SAMLObjectBuilder<StatusMessage> statusMessageBuilder;
+    
+    private static XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
+    
+    private SAML2PResponseComponentBuilder() {
+        
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static Response createSAMLResponse(
+        String inResponseTo,
+        String issuer,
+        Status status
+    ) {
+        if (responseBuilder == null) {
+            responseBuilder = (SAMLObjectBuilder<Response>)
+                builderFactory.getBuilder(Response.DEFAULT_ELEMENT_NAME);
+        }
+        Response response = responseBuilder.buildObject();
+        
+        response.setID(UUID.randomUUID().toString());
+        response.setIssueInstant(new DateTime());
+        response.setInResponseTo(inResponseTo);
+        response.setIssuer(createIssuer(issuer));
+        response.setStatus(status);
+        response.setVersion(SAMLVersion.VERSION_20);
+        
+        return response;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static Issuer createIssuer(
+        String issuerValue
+    ) {
+        if (issuerBuilder == null) {
+            issuerBuilder = (SAMLObjectBuilder<Issuer>)
+                builderFactory.getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
+        }
+        Issuer issuer = issuerBuilder.buildObject();
+        issuer.setValue(issuerValue);
+        
+        return issuer;
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static Status createStatus(
+        String statusCodeValue,
+        String statusMessage
+    ) {
+        if (statusBuilder == null) {
+            statusBuilder = (SAMLObjectBuilder<Status>)
+                builderFactory.getBuilder(Status.DEFAULT_ELEMENT_NAME);
+        }
+        if (statusCodeBuilder == null) {
+            statusCodeBuilder = (SAMLObjectBuilder<StatusCode>)
+                builderFactory.getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
+        }
+        if (statusMessageBuilder == null) {
+            statusMessageBuilder = (SAMLObjectBuilder<StatusMessage>)
+                builderFactory.getBuilder(StatusMessage.DEFAULT_ELEMENT_NAME);
+        }
+        
+        Status status = statusBuilder.buildObject();
+        
+        StatusCode statusCode = statusCodeBuilder.buildObject();
+        statusCode.setValue(statusCodeValue);
+        status.setStatusCode(statusCode);
+        
+        if (statusMessage != null) {
+            StatusMessage statusMessageObject = statusMessageBuilder.buildObject();
+            statusMessageObject.setMessage(statusMessage);
+            status.setStatusMessage(statusMessageObject);
+        }
+        
+        return status;
+    }
+    
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cxf-fediz/blob/617fd4e9/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAMLRequestTest.java
----------------------------------------------------------------------
diff --git a/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAMLRequestTest.java b/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAMLRequestTest.java
new file mode 100644
index 0000000..cfbc8d2
--- /dev/null
+++ b/plugins/core/src/test/java/org/apache/cxf/fediz/core/samlsso/SAMLRequestTest.java
@@ -0,0 +1,205 @@
+/**
+ * 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.samlsso;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+
+import org.apache.cxf.fediz.common.SecurityTestUtil;
+import org.apache.cxf.fediz.core.config.FedizConfigurator;
+import org.apache.cxf.fediz.core.config.FedizContext;
+import org.apache.cxf.fediz.core.config.SAMLProtocol;
+import org.apache.cxf.fediz.core.processor.FedizProcessor;
+import org.apache.cxf.fediz.core.processor.RedirectionResponse;
+import org.apache.cxf.fediz.core.processor.SAMLProcessorImpl;
+import org.apache.cxf.fediz.core.util.DOMUtils;
+import org.apache.wss4j.common.saml.OpenSAMLUtil;
+import org.apache.xml.security.utils.Base64;
+import org.easymock.EasyMock;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.opensaml.saml2.core.AuthnRequest;
+
+/**
+ * Some tests for creating SAMLRequests using the SAMLProcessorImpl
+ */
+public class SAMLRequestTest {
+    static final String TEST_USER = "alice";
+    static final String TEST_REQUEST_URL = "https://localhost/fedizhelloworld/";
+    static final String TEST_REQUEST_URI = "/fedizhelloworld";
+    static final String TEST_IDP_ISSUER = "http://url_to_the_issuer";
+    static final String TEST_CLIENT_ADDRESS = "https://127.0.0.1";
+    
+    private static final String CONFIG_FILE = "fediz_test_config_saml.xml";
+    
+    private static FedizConfigurator configurator;
+    private static DocumentBuilderFactory docBuilderFactory;
+    
+    static {
+        docBuilderFactory = DocumentBuilderFactory.newInstance();
+        docBuilderFactory.setNamespaceAware(true);
+    }
+    
+    
+    @BeforeClass
+    public static void init() {
+        getFederationConfigurator();
+        Assert.assertNotNull(configurator);
+    }
+    
+    @AfterClass
+    public static void cleanup() {
+        SecurityTestUtil.cleanup();
+    }
+    
+
+    private static FedizConfigurator getFederationConfigurator() {
+        if (configurator != null) {
+            return configurator;
+        }
+        try {
+            configurator = new FedizConfigurator();
+            final URL resource = Thread.currentThread().getContextClassLoader()
+                    .getResource(CONFIG_FILE);
+            File f = new File(resource.toURI());
+            configurator.loadConfig(f);
+            return configurator;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+    
+    @org.junit.Test
+    public void createSAMLRequest() throws Exception {
+        // Mock up a Request
+        FedizContext config = getFederationConfigurator().getFedizContext("ROOT");
+        
+        HttpServletRequest req = EasyMock.createMock(HttpServletRequest.class);
+        EasyMock.expect(req.getRequestURL()).andReturn(new StringBuffer(TEST_REQUEST_URL)).times(1, 2);
+        EasyMock.expect(req.getContextPath()).andReturn(TEST_REQUEST_URI);
+        EasyMock.expect(req.getRequestURI()).andReturn(TEST_REQUEST_URI).times(1, 2);
+        EasyMock.replay(req);
+        
+        FedizProcessor wfProc = new SAMLProcessorImpl();
+        RedirectionResponse response = wfProc.createSignInRequest(req, config);
+        
+        String redirectionURL = response.getRedirectionURL();
+        Assert.assertTrue(redirectionURL.startsWith(TEST_IDP_ISSUER));
+        Assert.assertTrue(redirectionURL.contains("SAMLRequest="));
+        Assert.assertTrue(redirectionURL.contains("RelayState="));
+        
+        Map<String, String> headers = response.getHeaders();
+        Assert.assertNotNull(headers);
+        Assert.assertFalse(headers.isEmpty());
+        Assert.assertTrue(headers.containsKey("Set-Cookie"));
+        Assert.assertTrue("no-cache, no-store".equals(headers.get("Cache-Control")));
+        Assert.assertTrue("no-cache".equals(headers.get("Pragma")));
+    }
+    
+    @org.junit.Test
+    public void testRelayState() throws Exception {
+        // Mock up a Request
+        FedizContext config = getFederationConfigurator().getFedizContext("ROOT");
+        
+        HttpServletRequest req = EasyMock.createMock(HttpServletRequest.class);
+        EasyMock.expect(req.getRequestURL()).andReturn(new StringBuffer(TEST_REQUEST_URL)).times(1, 2);
+        EasyMock.expect(req.getContextPath()).andReturn(TEST_REQUEST_URI);
+        EasyMock.expect(req.getRequestURI()).andReturn(TEST_REQUEST_URI).times(1, 2);
+        EasyMock.replay(req);
+        
+        FedizProcessor wfProc = new SAMLProcessorImpl();
+        RedirectionResponse response = wfProc.createSignInRequest(req, config);
+        
+        String redirectionURL = response.getRedirectionURL();
+        String relayState = 
+            redirectionURL.substring(redirectionURL.indexOf("RelayState=") + "RelayState=".length());
+        
+        // Now retrieve the RequestState corresponding to the RelayState
+        RequestState requestState = 
+            ((SAMLProtocol)config.getProtocol()).getStateManager().removeRequestState(relayState);
+        Assert.assertNotNull(requestState);
+        
+        Assert.assertEquals(TEST_IDP_ISSUER, requestState.getIdpServiceAddress());
+        Assert.assertEquals(TEST_REQUEST_URL, requestState.getIssuerId());
+        Assert.assertEquals(TEST_REQUEST_URL, requestState.getTargetAddress());
+    }
+    
+    @org.junit.Test
+    public void testSAMLRequest() throws Exception {
+        // Mock up a Request
+        FedizContext config = getFederationConfigurator().getFedizContext("ROOT");
+        
+        HttpServletRequest req = EasyMock.createMock(HttpServletRequest.class);
+        EasyMock.expect(req.getRequestURL()).andReturn(new StringBuffer(TEST_REQUEST_URL)).times(1, 2);
+        EasyMock.expect(req.getContextPath()).andReturn(TEST_REQUEST_URI);
+        EasyMock.expect(req.getRequestURI()).andReturn(TEST_REQUEST_URI).times(1, 2);
+        EasyMock.replay(req);
+        
+        FedizProcessor wfProc = new SAMLProcessorImpl();
+        RedirectionResponse response = wfProc.createSignInRequest(req, config);
+        
+        String redirectionURL = response.getRedirectionURL();
+        String samlRequest = 
+            redirectionURL.substring(redirectionURL.indexOf("SAMLRequest=") + "SAMLRequest=".length(),
+                                     redirectionURL.indexOf("RelayState=") - 1);
+        
+        byte[] deflatedToken = Base64.decode(URLDecoder.decode(samlRequest, "UTF-8"));
+        InputStream tokenStream = CompressionUtils.inflate(deflatedToken);
+
+        Document requestDoc = DOMUtils.readXml(new InputStreamReader(tokenStream, "UTF-8"));
+        AuthnRequest request =
+            (AuthnRequest)OpenSAMLUtil.fromDom(requestDoc.getDocumentElement());
+
+        Assert.assertEquals(TEST_REQUEST_URL, request.getIssuer().getValue());
+        Assert.assertEquals(TEST_REQUEST_URL, request.getAssertionConsumerServiceURL());
+    }
+    
+    @org.junit.Test
+    public void testSignedSAMLRequest() throws Exception {
+        // Mock up a Request
+        FedizContext config = getFederationConfigurator().getFedizContext("SIGNED_ROOT");
+        
+        HttpServletRequest req = EasyMock.createMock(HttpServletRequest.class);
+        EasyMock.expect(req.getRequestURL()).andReturn(new StringBuffer(TEST_REQUEST_URL)).times(1, 2);
+        EasyMock.expect(req.getContextPath()).andReturn(TEST_REQUEST_URI);
+        EasyMock.expect(req.getRequestURI()).andReturn(TEST_REQUEST_URI).times(1, 2);
+        EasyMock.replay(req);
+        
+        FedizProcessor wfProc = new SAMLProcessorImpl();
+        RedirectionResponse response = wfProc.createSignInRequest(req, config);
+        
+        String redirectionURL = response.getRedirectionURL();
+        String signature = 
+            redirectionURL.substring(redirectionURL.indexOf("Signature=") + "Signature=".length());
+        Assert.assertTrue(signature != null && signature.length() > 0);
+    }
+    
+}
\ No newline at end of file