/**
* WS-Attacker - A Modular Web Services Penetration Testing Framework Copyright
* (C) 2013 Christian Mainka
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package wsattacker.library.schemaanalyzer;
import java.util.*;
import javax.xml.namespace.QName;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import static wsattacker.library.schemaanalyzer.TestfilePath.*;
import wsattacker.library.xmlutilities.dom.DomUtilities;
import static wsattacker.library.xmlutilities.namespace.NamespaceConstants.PREFIX_NS_SAMLP;
import static wsattacker.library.xmlutilities.namespace.NamespaceConstants.PREFIX_NS_SOAP_1_1;
import static wsattacker.library.xmlutilities.namespace.NamespaceConstants.PREFIX_NS_SOAP_1_2;
import static wsattacker.library.xmlutilities.namespace.NamespaceConstants.URI_NS_DS;
import static wsattacker.library.xmlutilities.namespace.NamespaceConstants.URI_NS_SAML20;
import static wsattacker.library.xmlutilities.namespace.NamespaceConstants.URI_NS_SAML20P;
import static wsattacker.library.xmlutilities.namespace.NamespaceConstants.URI_NS_SOAP_1_1;
import static wsattacker.library.xmlutilities.namespace.NamespaceConstants.URI_NS_SOAP_1_2;
/**
* @author christian
*/
public class SchemaAnalyzerTest
{
private static Document DOC_SAML20, DOC_SAML20P, DOC_SOAP11, DOC_SOAP12, DOC_DS, DOC_XPATH, DOC_WSSE10, DOC_WSSE11;
public SchemaAnalyzerTest()
{
}
@BeforeClass
public static void setUpClass()
throws Exception
{
DOC_SAML20 = SchemaAnalyzerFactory.getSchemaDocument( "saml20.xsd" );
DOC_SAML20P = SchemaAnalyzerFactory.getSchemaDocument( "saml20p.xsd" );
DOC_SOAP11 = SchemaAnalyzerFactory.getSchemaDocument( "soap11.xsd" );
DOC_SOAP12 = SchemaAnalyzerFactory.getSchemaDocument( "soap12.xsd" );
DOC_DS = SchemaAnalyzerFactory.getSchemaDocument( "xmldsig-core-schema.xsd" );
DOC_XPATH = SchemaAnalyzerFactory.getSchemaDocument( "xmldsig-filter2.xsd" );
DOC_WSSE10 = SchemaAnalyzerFactory.getSchemaDocument( "wssec-1.0.xsd" );
DOC_WSSE11 = SchemaAnalyzerFactory.getSchemaDocument( "wssec-1.1.xsd" );
}
@Before
public void setUp()
{
}
/**
* Test of getExpandedAnalyzingDocument method, of class SchemaAnalyzerImpl.
*/
@Test
public void testGetExpandedAnalyzingDocument()
throws Exception
{
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SOAP11 );
Document expResult = DomUtilities.readDocument( SOAP11_PATH_TO_EXPANDED_XML );
Document toTest = DomUtilities.readDocument( SOAP11_PATH_TO_ENVELOPE_ELEMENT_XML );
String toTestAsString = DomUtilities.domToString( toTest );
instance.findExpansionPoint( toTest.getDocumentElement() );
Document result = instance.getExpandedAnalyzingDocument();
assertEquals( "Did not get expected expanded document", DomUtilities.domToString( expResult, false ),
DomUtilities.domToString( result, false ) );
assertEquals( "Analysing Document should not be touched", toTestAsString,
DomUtilities.domToString( toTest, false ) );
}
/**
* Test of getAnalyzingDocument method, of class SchemaAnalyzerImpl.
*/
@Test
public void testGetAnalyzingDocument()
throws Exception
{
Document doc = DomUtilities.readDocument( SOAP11_PATH_TO_ENVELOPE_ELEMENT_XML );
Element envelope = doc.getDocumentElement();
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.findExpansionPoint( envelope );
assertEquals( doc, instance.getAnalyzingDocument() );
}
/**
* Test of appendSchema method, of class SchemaAnalyzerImpl.
*/
@Test
public void testAppendSchemaAndClearSchema()
throws Exception
{
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
assertEquals( 0, instance.schemaMap.size() );
Document newSchema;
newSchema = SchemaAnalyzerFactory.getSchemaDocument( "saml20.xsd" );
instance.appendSchema( newSchema );
assertEquals( 1, instance.schemaMap.size() );
assertTrue( instance.schemaMap.containsValue( newSchema ) );
assertTrue( instance.schemaMap.containsKey( URI_NS_SAML20 ) );
newSchema = SchemaAnalyzerFactory.getSchemaDocument( "saml20.xsd" );
instance.appendSchema( newSchema );
assertEquals( 1, instance.schemaMap.size() );
newSchema = SchemaAnalyzerFactory.getSchemaDocument( "saml20p.xsd" );
instance.appendSchema( newSchema );
assertEquals( 2, instance.schemaMap.size() );
assertTrue( instance.schemaMap.containsValue( newSchema ) );
assertTrue( instance.schemaMap.containsKey( URI_NS_SAML20P ) );
instance.clearSchemas();
assertEquals( 0, instance.schemaMap.size() );
}
/**
* Test of isInCurrentAnalysis method, of class SchemaAnalyzerImpl.
*/
@Test
public void testIsInCurrentAnalysis()
throws Exception
{
Document doc = DomUtilities.readDocument( SOAP11_PATH_TO_EXPANDED_XML );
Element envelope = doc.getDocumentElement();
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.findExpansionPoint( envelope );
assertTrue( instance.isInCurrentAnalysis( envelope ) );
doc = DomUtilities.readDocument( SOAP11_PATH_TO_EXPANDED_XML );
envelope = doc.getDocumentElement();
assertTrue( instance.isInCurrentAnalysis( envelope ) );
doc = DomUtilities.readDocument( SOAP12_PATH_TO_EXPANDED_XML );
envelope = doc.getDocumentElement();
assertFalse( instance.isInCurrentAnalysis( envelope ) );
}
/**
* Test of findExpansionPoint method, of class SchemaAnalyzerImpl.
*/
@Test
public void testFindExpansionPoint_Soap11()
throws Exception
{
// SoapTestDocument soap = new SoapTestDocument(URI_NS_SOAP_1_1);
// Element fromHere = soap.getEnvelope();
Element fromHere =
DomUtilities.stringToDom( "<" + PREFIX_NS_SOAP_1_1 + ":Envelope xmlns:" + PREFIX_NS_SOAP_1_1 + "=\""
+ URI_NS_SOAP_1_1 + "\"></" + PREFIX_NS_SOAP_1_1 + ":Envelope>" ).getDocumentElement();
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SOAP11 );
Set<AnyElementProperties> result = instance.findExpansionPoint( fromHere );
Set<String> expectedResult = new HashSet<String>();
expectedResult.add( URI_NS_SOAP_1_1 + ":" + PREFIX_NS_SOAP_1_1 + ":" + "Envelope" );
expectedResult.add( URI_NS_SOAP_1_1 + ":" + PREFIX_NS_SOAP_1_1 + ":" + "Body" );
expectedResult.add( URI_NS_SOAP_1_1 + ":" + PREFIX_NS_SOAP_1_1 + ":" + "Header" );
assertEquals( expectedResult.size(), result.size() );
Set<String> gotResult = new HashSet<String>();
for ( AnyElementProperties any : result )
{
Element extensionPoint = any.getDocumentElement();
gotResult.add( extensionPoint.getNamespaceURI() + ":" + extensionPoint.getNodeName() );
}
assertEquals( expectedResult, gotResult );
}
/**
* Test of findExpansionPoint method, of class SchemaAnalyzerImpl.
*/
@Test
public void testFindExpansionPoint_Soap12()
throws Exception
{
// SoapTestDocument soap = new SoapTestDocument(URI_NS_SOAP_1_1);
// Element fromHere = soap.getEnvelope();
Element fromHere =
DomUtilities.stringToDom( "<" + PREFIX_NS_SOAP_1_2 + ":Envelope xmlns:" + PREFIX_NS_SOAP_1_2 + "=\""
+ URI_NS_SOAP_1_2 + "\"></" + PREFIX_NS_SOAP_1_2 + ":Envelope>" ).getDocumentElement();
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SOAP12 );
Set<AnyElementProperties> result = instance.findExpansionPoint( fromHere );
Set<String> expectedResult = new HashSet<String>();
expectedResult.add( URI_NS_SOAP_1_2 + ":" + PREFIX_NS_SOAP_1_2 + ":" + "Body" );
expectedResult.add( URI_NS_SOAP_1_2 + ":" + PREFIX_NS_SOAP_1_2 + ":" + "Header" );
assertEquals( expectedResult.size(), result.size() );
Set<String> gotResult = new HashSet<String>();
for ( AnyElementProperties any : result )
{
Element extensionPoint = any.getDocumentElement();
gotResult.add( extensionPoint.getNamespaceURI() + ":" + extensionPoint.getNodeName() );
}
assertEquals( expectedResult, gotResult );
}
@Test
public void testFindExpansionPoint()
throws Exception
{
SchemaAnalyzerImpl sa = new SchemaAnalyzerImpl();
sa.appendSchema( DOC_SOAP11 );
sa.appendSchema( DOC_SOAP12 );
sa.appendSchema( DOC_DS );
sa.appendSchema( DOC_XPATH );
sa.appendSchema( DOC_WSSE10 );
sa.appendSchema( DOC_WSSE11 );
Set<AnyElementProperties> result;
List<String> cmp;
List<QName> filterList;
Document doc = DomUtilities.readDocument( SOAP11_PATH_TO_EXPANDED_XML );
Element envelope = doc.getDocumentElement();
Element body = DomUtilities.getFirstChildElementByNames( envelope, "Body" );
Element header = DomUtilities.getFirstChildElementByNames( envelope, "Header" );
cmp = new ArrayList<String>();
cmp.add( envelope.getNodeName() );
cmp.add( body.getNodeName() );
cmp.add( header.getNodeName() );
assertFalse( "New Analysing Doc must be created", sa.isInCurrentAnalysis( envelope ) );
result = sa.findExpansionPoint( envelope );
// Compare results
assertEquals( cmp.size(), result.size() ); // same size
for ( AnyElementProperties prop : result )
{
assertTrue( cmp.contains( prop.getDocumentElement().getNodeName() ) ); // all
// elements
// contained
}
doc = DomUtilities.readDocument( SOAP12_PATH_TO_EXPANDED_XML );
envelope = doc.getDocumentElement();
body = DomUtilities.getFirstChildElementByNames( envelope, "Body" );
header = DomUtilities.getFirstChildElementByNames( envelope, "Header" );
cmp = new ArrayList<String>();
cmp.add( body.getNodeName() );
cmp.add( header.getNodeName() );
assertFalse( "New Analysing Doc must be created", sa.isInCurrentAnalysis( envelope ) );
result = sa.findExpansionPoint( envelope );
// Compare results
assertEquals( cmp.size(), result.size() ); // same size
for ( AnyElementProperties prop : result )
{
assertTrue( cmp.contains( prop.getDocumentElement().getNodeName() ) ); // all
// elements
// contained
}
doc = DomUtilities.readDocument( SOAP12_PATH_TO_SIGNED_XML );
envelope = doc.getDocumentElement();
body = DomUtilities.getFirstChildElementByNames( envelope, "Body" );
header = DomUtilities.getFirstChildElementByNames( envelope, "Header" );
cmp = new ArrayList<String>();
cmp.add( body.getNodeName() );
cmp.add( header.getNodeName() );
cmp.add( "ds:Object" );
cmp.add( "wsse:Security" );
Element signature = DomUtilities.getFirstChildElementByNames( envelope, "Header", "Security", "Signature" );
filterList = new ArrayList<QName>();
sa.setFilterList( filterList );
filterList.add( new QName( URI_NS_DS, "SignedInfo" ) );
filterList.add( new QName( URI_NS_DS, "KeyInfo" ) );
filterList.add( new QName( URI_NS_DS, "SignatureValue" ) );
assertFalse( "New Analysing Doc must be created", sa.isInCurrentAnalysis( envelope ) );
result = sa.findExpansionPoint( envelope );
assertTrue( "No new Analysing Doc must be created", sa.isInCurrentAnalysis( envelope ) );
result = sa.findExpansionPoint( envelope ); // Double Test
// Compare results
assertEquals( "Not all expected elements contained: " + result.toString(), cmp.size(), result.size() ); // same
// size
for ( AnyElementProperties prop : result )
{
assertTrue( cmp.contains( prop.getDocumentElement().getNodeName() ) ); // all
// elements
// contained
}
sa.setFilterList( new ArrayList<QName>() ); // no filter
// Same Test as above, just because last test reused old Document
doc = DomUtilities.readDocument( SOAP11_PATH_TO_EXPANDED_XML ); // Soap11
envelope = doc.getDocumentElement();
body = DomUtilities.getFirstChildElementByNames( envelope, "Body" );
header = DomUtilities.getFirstChildElementByNames( envelope, "Header" );
cmp = new ArrayList<String>();
cmp.add( envelope.getNodeName() );
cmp.add( body.getNodeName() );
cmp.add( header.getNodeName() );
assertFalse( "New Analysing Doc must be created", sa.isInCurrentAnalysis( envelope ) );
result = sa.findExpansionPoint( envelope );
// Compare results
assertEquals( cmp.size(), result.size() ); // same size
for ( AnyElementProperties prop : result )
{
assertTrue( cmp.contains( prop.getDocumentElement().getNodeName() ) ); // all
// elements
// contained
}
}
/**
* Test of findPossibleChildElements method, of class SchemaAnalyzerImpl.
*/
@Test
public void testFindPossibleChildElements_Element()
throws Exception
{
Document doc = DomUtilities.readDocument( SOAP11_PATH_TO_EXPANDED_XML );
Element envelope = doc.getDocumentElement();
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SOAP11 );
List<Element> expectedResult;
expectedResult =
(List<Element>) DomUtilities.evaluateXPath( DOC_SOAP11,
"//*[local-name()='complexType' and @name='Envelope']//*[local-name()='any']" );
expectedResult.addAll( (List<Element>) DomUtilities.evaluateXPath( DOC_SOAP11,
"//*[local-name()='element'][@name='Header' or @name='Body']" ) );
List<Element> foundResult = instance.findPossibleChildElements( envelope );
assertEquals( expectedResult, foundResult );
}
/**
* Test of findPossibleChildElements method, of class SchemaAnalyzerImpl.
*/
@Test
public void testFindPossibleChildElements_Envelope11()
throws Exception
{
String namespaceURI = URI_NS_SOAP_1_1;
String localName = "Envelope";
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SOAP11 );
List<Element> expectedResult;
expectedResult =
(List<Element>) DomUtilities.evaluateXPath( DOC_SOAP11,
"//*[local-name()='complexType' and @name='Envelope']//*[local-name()='any']" );
expectedResult.addAll( (List<Element>) DomUtilities.evaluateXPath( DOC_SOAP11,
"//*[local-name()='element'][@name='Header' or @name='Body']" ) );
List<Element> foundResult = instance.findPossibleChildElements( namespaceURI, localName );
assertEquals( expectedResult, foundResult );
}
@Test
public void testFindPossibleChildElements_SAML20()
throws Exception
{
String namespaceURI = URI_NS_SAML20P;
String localName = "Response";
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SAML20P );
instance.appendSchema( DOC_SAML20 );
List<Element> expectedResult;
expectedResult =
(List<Element>) DomUtilities.evaluateXPath( DOC_SAML20,
"//*[local-name()='element'][@name='Assertion' or @name='EncryptedAssertion']" );
List<Element> foundResult = instance.findPossibleChildElements( namespaceURI, localName );
assertEquals( expectedResult, foundResult );
}
/**
* Test of findComplexTypeInSchema method, of class SchemaAnalyzerImpl.
*/
@Test
public void testFindComplexTypeInSchema()
throws Exception
{
String namespaceURI = URI_NS_SAML20P;
String elementTypeLocalName = "ResponseType";
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SAML20 );
instance.appendSchema( DOC_SAML20P );
Element expResult =
(Element) DomUtilities.evaluateXPath( DOC_SAML20P,
"/*[local-name()='schema']/*[local-name()='complexType' and @name='ResponseType']" ).get( 0 );
Element result = instance.findComplexTypeInSchema( namespaceURI, elementTypeLocalName );
assertEquals( expResult, result );
}
/**
* Test of findElementInSchema method, of class SchemaAnalyzerImpl.
*/
@Test
public void testFindElementInSchema()
throws Exception
{
String namespaceURI = URI_NS_SAML20P;
String localName = "Response";
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SAML20 );
instance.appendSchema( DOC_SAML20P );
assertEquals( 2, instance.schemaMap.size() );
assertTrue( instance.schemaMap.containsValue( DOC_SAML20 ) );
assertTrue( instance.schemaMap.containsKey( URI_NS_SAML20 ) );
Element expResult =
(Element) DomUtilities.evaluateXPath( DOC_SAML20P,
"/*[local-name()='schema']/*[local-name()='element' and @name='Response']" ).get( 0 );
Element result = instance.findElementInSchema( namespaceURI, localName );
assertEquals( expResult, result );
}
/**
* Test of dereferenceElement method, of class SchemaAnalyzerImpl.
*/
@Test
public void testDereferenceElement()
throws Exception
{
Element referringElement =
(Element) DomUtilities.evaluateXPath( DOC_SAML20P, "//*[local-name()='element' and @ref='saml:Assertion']" ).get( 0 );
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SAML20P );
instance.appendSchema( DOC_SAML20 );
Element expResult =
(Element) DomUtilities.evaluateXPath( DOC_SAML20, "//*[local-name()='element' and @name='Assertion']" ).get( 0 );
Element result = instance.dereferenceElement( referringElement );
assertEquals( expResult, result );
}
/**
* Test of findComplexTypeForElement method, of class SchemaAnalyzerImpl.
*/
@Test
public void testFindComplexTypeForElement()
throws Exception
{
Element elementSchema =
(Element) DomUtilities.evaluateXPath( DOC_SAML20P,
"/*[local-name()='schema']/*[local-name()='element' and @name='Response']" ).get( 0 );
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SAML20P );
Element expResult =
(Element) DomUtilities.evaluateXPath( DOC_SAML20P,
"/*[local-name()='schema']/*[local-name()='complexType' and @name='ResponseType']" ).get( 0 );
Element result = instance.findComplexTypeForElement( elementSchema );
assertEquals( expResult, result );
}
/**
* Test of getTargetNamespace method, of class SchemaAnalyzerImpl.
*/
@Test
public void testGetTargetNamespace()
throws Exception
{
Element x =
(Element) DomUtilities.evaluateXPath( DOC_SAML20P,
"/*[local-name()='schema']/*[local-name()='element' and @name='Response']" ).get( 0 );
SchemaAnalyzerImpl instance = new SchemaAnalyzerImpl();
instance.appendSchema( DOC_SAML20P );
String[] expResult = { PREFIX_NS_SAMLP, URI_NS_SAML20P };
String[] result = instance.getTargetNamespace( x );
assertArrayEquals( expResult, result );
}
private static Map<String, String> elementToMap( List<Element> elementList )
{
Map<String, String> returnedList = new HashMap<String, String>();
for ( Element ele : elementList )
{
returnedList.put( ele.getNamespaceURI(), ele.getLocalName() );
}
return returnedList;
}
}