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
