/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package ddf.security.assertion.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.InputStream; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import javax.xml.bind.DatatypeConverter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.cxf.helpers.DOMUtils; import org.apache.cxf.ws.security.tokenstore.SecurityToken; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; public class SecurityAssertionImplTest { public static final String SAML_CONDITION_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; public static final String BEFORE = "2013-04-23T23:39:54.788Z"; public static final String AFTER = "2113-04-24T00:09:54.788Z"; private static final String ISSUER = "tokenissuer"; private static final String PRINCIPAL = "CN=client,OU=I4CE,O=Lockheed Martin,L=Goodyear,ST=Arizona,C=US"; private static final int NUM_ATTRIBUTES = 1; private static final int NUM_NAUTH = 1; private static final int NUM_AUTHZ = 0; public static Document readXml(InputStream is) throws SAXException, IOException, ParserConfigurationException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setValidating(false); dbf.setIgnoringComments(false); dbf.setIgnoringElementContentWhitespace(true); dbf.setNamespaceAware(true); // dbf.setCoalescing(true); // dbf.setExpandEntityReferences(true); DocumentBuilder db = dbf.newDocumentBuilder(); db.setEntityResolver(new DOMUtils.NullResolver()); // db.setErrorHandler( new MyErrorHandler()); return db.parse(is); } @Test public void testEmptyAssertion() { SecurityAssertionImpl assertion = new SecurityAssertionImpl(); assertNull(assertion.getIssuer()); assertEquals(0, assertion.getAttributeStatements() .size()); assertEquals(0, assertion.getAuthnStatements() .size()); assertEquals(0, assertion.getAuthzDecisionStatements() .size()); assertNull(assertion.getPrincipal()); assertNull(assertion.getNotBefore()); assertNull(assertion.getNotOnOrAfter()); assertTrue(assertion.isPresentlyValid()); } @Test public void testSampleAssertion() throws Exception { Element issuedAssertion = this.readDocument("/saml.xml") .getDocumentElement(); String assertionId = issuedAssertion.getAttributeNodeNS(null, "ID") .getNodeValue(); SecurityToken token = new SecurityToken(assertionId, issuedAssertion, null); SecurityAssertionImpl assertion = new SecurityAssertionImpl(token); assertNotNull(assertion.getSecurityToken()); assertEquals(token, assertion.getSecurityToken()); assertEquals(ISSUER, assertion.getIssuer()); assertEquals(PRINCIPAL, assertion.getPrincipal() .getName()); assertEquals(PRINCIPAL, assertion.getPrincipal() .toString()); assertEquals(NUM_ATTRIBUTES, assertion.getAttributeStatements() .size()); assertEquals(NUM_NAUTH, assertion.getAuthnStatements() .size()); assertEquals(DatatypeConverter.parseDateTime(BEFORE) .getTimeInMillis(), assertion.getNotBefore() .getTime()); assertEquals(DatatypeConverter.parseDateTime(AFTER) .getTimeInMillis(), assertion.getNotOnOrAfter() .getTime()); //we don't currently parse these // assertEquals(NUM_AUTHZ, assertion.getAuthzDecisionStatements().size()); assertNotNull(assertion.toString()); assertTrue(assertion.isPresentlyValid()); } @Test public void testIsPresentlyValidWithNullBounds() throws Exception { Element issuedAssertion = this.readDocument("/saml.xml") .getDocumentElement(); //Remove Time Bounds issuedAssertion.getElementsByTagName("saml2:Conditions") .item(0) .getAttributes() .removeNamedItem("NotBefore"); issuedAssertion.getElementsByTagName("saml2:Conditions") .item(0) .getAttributes() .removeNamedItem("NotOnOrAfter"); SecurityAssertionImpl assertion = getSecurityAssertion(issuedAssertion); assertTrue(assertion.isPresentlyValid()); } @Test public void testIsPresentlyValidWithNullNotBefore() throws Exception { Element issuedAssertion = this.readDocument("/saml.xml") .getDocumentElement(); //Remove NotBefore issuedAssertion.getElementsByTagName("saml2:Conditions") .item(0) .getAttributes() .removeNamedItem("NotBefore"); SecurityAssertionImpl assertion = getSecurityAssertion(issuedAssertion); assertTrue(assertion.isPresentlyValid()); } @Test public void testIsPresentlyValidWithNullNotOnOrAfter() throws Exception { Element issuedAssertion = this.readDocument("/saml.xml") .getDocumentElement(); //Remove NotOnOrAfter issuedAssertion.getElementsByTagName("saml2:Conditions") .item(0) .getAttributes() .removeNamedItem("NotOnOrAfter"); SecurityAssertionImpl assertion = getSecurityAssertion(issuedAssertion); assertTrue(assertion.isPresentlyValid()); } @Test public void testIsPresentlyValidBeforeNotBefore() throws Exception { Element issuedAssertion = this.readDocument("/saml.xml") .getDocumentElement(); //Change the NotBefore Date on the SAML Assertion to be after "now" issuedAssertion.getElementsByTagName("saml2:Conditions") .item(0) .getAttributes() .getNamedItem("NotBefore") .setNodeValue(getNowWithOffset(1)); SecurityAssertionImpl assertion = getSecurityAssertion(issuedAssertion); assertFalse(assertion.isPresentlyValid()); } @Test public void testIsPresentlyValidAfterNotOnOrAfter() throws Exception { Element issuedAssertion = this.readDocument("/saml.xml") .getDocumentElement(); //Change the NotOnOrAfter Date on the SAML Assertion to be before "now" issuedAssertion.getElementsByTagName("saml2:Conditions") .item(0) .getAttributes() .getNamedItem("NotOnOrAfter") .setNodeValue(getNowWithOffset(-1)); SecurityAssertionImpl assertion = getSecurityAssertion(issuedAssertion); assertFalse(assertion.isPresentlyValid()); } /** * Reads a classpath resource into a Document. * * @param name the name of the classpath resource */ protected Document readDocument(String name) throws SAXException, IOException, ParserConfigurationException { InputStream inStream = getClass().getResourceAsStream(name); return readXml(inStream); } private SecurityAssertionImpl getSecurityAssertion(Element issuedAssertion) { String assertionId = issuedAssertion.getAttributeNodeNS(null, "ID") .getNodeValue(); SecurityToken token = new SecurityToken(assertionId, issuedAssertion, null); return new SecurityAssertionImpl(token); } private String getNowWithOffset(int offset) { Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); calendar.add(Calendar.SECOND, offset); Date offsetNow = calendar.getTime(); DateFormat dateFormat = new SimpleDateFormat(SAML_CONDITION_DATE_FORMAT); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); return dateFormat.format(offsetNow); } }