Skip to content

Commit

Permalink
Merge branch 'DigDes:develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
andersjonsson authored Oct 3, 2024
2 parents 9021db8 + 6f49042 commit ac66154
Show file tree
Hide file tree
Showing 12 changed files with 353 additions and 15 deletions.
35 changes: 35 additions & 0 deletions src/SoapCore.Tests/MessageFilter/WsMessageFilterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ public async Task IncorrectCredentialsNotAuthrorized()
await filter.OnRequestExecuting(CreateMessage(usernameToken));
}

[TestMethod]
[ExpectedException(typeof(InvalidCredentialException))]
public async Task IncorrectCredentialsWithTimestampNotAuthrorized()
{
var usernameToken = new XElement(
_wsse + "UsernameToken",
new XElement(_wsse + "Username", "INVALID_USERNAME"),
new XElement(_wsse + "Password", "INAVLID_PASSWORD"));

var filter = new WsMessageFilter("yourusername", "yourpassword");
await filter.OnRequestExecuting(CreateMessageWithTimestamp(usernameToken));
}

[TestMethod]
public async Task PasswordIsOptional()
{
Expand Down Expand Up @@ -166,5 +179,27 @@ private static Message CreateMessage(XNode usernameToken)
var doc = new XDocument(envelope);
return Message.CreateMessage(doc.CreateReader(), int.MaxValue, MessageVersion.Soap11);
}

private static Message CreateMessageWithTimestamp(XNode usernameToken)
{
var envelope = new XElement(
_soapenv11 + "Envelope",
new XAttribute(XNamespace.Xmlns + "wsse", _wsse.NamespaceName),
new XAttribute(XNamespace.Xmlns + "soap", _soapenv11.NamespaceName),
new XElement(
_soapenv11 + "Header",
new XElement(
_wsse + "Security",
new XElement(_wsse + "Timestamp", new XElement(_wsse + "Created"), new XElement(_wsse + "Expires")),
usernameToken)),
new XElement(
_soapenv11 + "Body",
new XElement(
XName.Get("Ping", "http://tempuri.org/"),
"abc")));

var doc = new XDocument(envelope);
return Message.CreateMessage(doc.CreateReader(), int.MaxValue, MessageVersion.Soap11);
}
}
}
25 changes: 25 additions & 0 deletions src/SoapCore.Tests/Wsdl/Services/ComplexTypeAnonymous.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace SoapCore.Tests.Wsdl.Services
{
[XmlType(AnonymousType = true)]
public class ComplexTypeAnonymous
{
public int IntProperty { get; set; }
[XmlElement(ElementName = "stringprop")]
public string StringProperty { get; set; }
[XmlElement(ElementName = "mybytes")]
public byte[] ByteArrayProperty { get; set; }

public Guid MyGuid { get; set; }

public List<string> StringList { get; set; }

public List<int> IntList { get; set; }
}
}
21 changes: 21 additions & 0 deletions src/SoapCore.Tests/Wsdl/Services/IComplexAnonymousListService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace SoapCore.Tests.Wsdl.Services
{
[ServiceContract]
public interface IComplexAnonymousListService
{
[OperationContract]
List<ComplexTypeAnonymous> Test();
}

public class ComplexAnonymousListService : IComplexAnonymousListService
{
public List<ComplexTypeAnonymous> Test() => throw new NotImplementedException();
}
}
35 changes: 35 additions & 0 deletions src/SoapCore.Tests/Wsdl/Services/IServiceWithSoapHeaders.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using SoapCore.ServiceModel;
#pragma warning disable SA1401 // Fields should be private

namespace SoapCore.Tests.Wsdl.Services;
[ServiceContract]
public interface IServiceWithSoapHeaders
{
[OperationContract]
[AuthenticationContextSoapHeader]
public void Method();
}

public class ServiceWithSoapHeaders : IServiceWithSoapHeaders
{
public void Method()
{
}
}

public sealed class AuthenticationContextSoapHeader : SoapHeaderAttribute
{
[XmlAnyAttribute]
public XmlAttribute[] XAttributes;

public string OperatorCode { get; set; }
public string Password { get; set; }
}
20 changes: 20 additions & 0 deletions src/SoapCore.Tests/Wsdl/Services/ISystemImportService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.ServiceModel;

namespace SoapCore.Tests.Wsdl.Services
{
[ServiceContract]
public interface ISystemImportService
{
[OperationContract]
ComplexType GetValue();
}

public class SystemImportService : ISystemImportService
{
public ComplexType GetValue()
{
throw new NotImplementedException();
}
}
}
123 changes: 123 additions & 0 deletions src/SoapCore.Tests/Wsdl/WsdlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,56 @@ public void CheckSystemTypes()
Assert.AreEqual(element.Attributes["type"]?.Value, "xs:anyURI");
}

[TestMethod]
public void CheckSystemAndArraysImport()
{
StartService(typeof(SystemImportService));
var wsdl = GetWsdl();
StopServer();

var root = new XmlDocument();
root.LoadXml(wsdl);

var nsmgr = new XmlNamespaceManager(root.NameTable);
nsmgr.AddNamespace("wsdl", "http://schemas.xmlsoap.org/wsdl/");
nsmgr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema");

var customNamespace = "http://schemas.datacontract.org/2004/07/SoapCore.Tests.Wsdl.Services";
var systemNamespace = "http://schemas.datacontract.org/2004/07/System";
var arraysNamespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays";

// Schema with custom target namespace
var schemaPath = $"/wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='{customNamespace}']";
var schemaElement = root.SelectSingleNode(schemaPath, nsmgr);
var systemImportElement = schemaElement.SelectSingleNode($"xs:import[@namespace='{systemNamespace}']", nsmgr);
var arraysImportElement = schemaElement.SelectSingleNode($"xs:import[@namespace='{arraysNamespace}']", nsmgr);

Assert.IsNotNull(schemaElement);
Assert.IsNotNull(systemImportElement);
Assert.IsNotNull(arraysImportElement);

// Schema with system target namespace
schemaPath =
$"/wsdl:definitions/wsdl:types" +
$"/xs:schema[@targetNamespace='{systemNamespace}']" +
$"/xs:complexType[@name='ArrayOfByte']" +
$"/..";

schemaElement = root.SelectSingleNode(schemaPath, nsmgr);
systemImportElement = schemaElement.SelectSingleNode($"xs:import[@namespace='{systemNamespace}']", nsmgr);
arraysImportElement = schemaElement.SelectSingleNode($"xs:import[@namespace='{arraysNamespace}']", nsmgr);

Assert.IsNull(systemImportElement);
Assert.IsNotNull(arraysImportElement);

// Schema with arrays target namespace
schemaPath = $"/wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='{arraysNamespace}']";
schemaElement = root.SelectSingleNode(schemaPath, nsmgr);
arraysImportElement = schemaElement.SelectSingleNode($"xs:import[@namespace='{arraysNamespace}']", nsmgr);

Assert.IsNull(arraysImportElement);
}

[TestMethod]
public void CheckStreamDeclaration()
{
Expand Down Expand Up @@ -847,6 +897,32 @@ public async Task CheckXmlAttributeSerialization(SoapSerializer soapSerializer)
Assert.IsNull(optionalIntAttribute.Attribute("use"));
}

[DataTestMethod]
[DataRow(SoapSerializer.XmlSerializer)]
public async Task CheckSoapHeaderTypes(SoapSerializer soapSerializer)
{
var wsdl = await GetWsdlFromMetaBodyWriter<ServiceWithSoapHeaders>(soapSerializer);
Trace.TraceInformation(wsdl);

var root = XElement.Parse(wsdl);
var nm = Namespaces.CreateDefaultXmlNamespaceManager(false);

var headerComplexType = root.XPathSelectElements("//xsd:complexType[@name='AuthenticationContextSoapHeader']", nm);
Assert.IsNotNull(headerComplexType);

var headerComplexTypePassword = root.XPathSelectElements("//xsd:complexType[@name='AuthenticationContextSoapHeader']/xsd:sequence/xsd:element[@name='OperatorCode' and @type='xsd:string' and not(@nillable) and @minOccurs=0 and @maxOccurs=1]", nm);
Assert.IsNotNull(headerComplexTypePassword);

var headerComplexTypeOperatorCode = root.XPathSelectElements("//xsd:complexType[@name='AuthenticationContextSoapHeader']/xsd:sequence/xsd:element[@name='Password' and @type='xsd:string' and not(@nillable) and @minOccurs=0 and @maxOccurs=1]", nm);
Assert.IsNotNull(headerComplexTypeOperatorCode);

var anyAttribute = root.XPathSelectElement("//xsd:complexType[@name='AuthenticationContextSoapHeader']/xsd:anyAttribute", nm);
Assert.IsNotNull(anyAttribute);

var headerElementOnOperation = root.XPathSelectElement("//wsdl:operation[@name='Method']/wsdl:input/soap:header[@message='tns:MethodAuthenticationContextSoapHeader' and @part='AuthenticationContextSoapHeader' and @use='literal']", nm);
Assert.IsNotNull(headerElementOnOperation);
}

[DataTestMethod]
[DataRow(SoapSerializer.XmlSerializer)]
[DataRow(SoapSerializer.DataContractSerializer)]
Expand Down Expand Up @@ -1239,6 +1315,52 @@ public void CheckComplexBaseTypeServiceWsdl()
Assert.IsNotNull(listDerivedType);
}

[DataTestMethod]
[DataRow(SoapSerializer.XmlSerializer)]
public async Task CheckComplexAnonymousTypeListWsdl(SoapSerializer soapSerializer)
{
var wsdl = await GetWsdlFromMetaBodyWriter<ComplexAnonymousListService>(soapSerializer);
Trace.TraceInformation(wsdl);
Assert.IsNotNull(wsdl);

var root = XElement.Parse(wsdl);

// Check complexType exists for xmlserializer meta
var testResultElement = GetElements(root, _xmlSchema + "element").SingleOrDefault(a => a.Attribute("type") != null && a.Attribute("name")?.Value.Equals("TestResult") == true);
Assert.IsNotNull(testResultElement);

// Now check if we can match the array type up with it's declaration
var split = testResultElement.Attribute("type").Value.Split(':');
var typeNamespace = testResultElement.GetNamespaceOfPrefix(split[0]);

var matchingSchema = GetElements(root, _xmlSchema + "schema").Where(schema => schema.Attribute("targetNamespace")?.Value.Equals(typeNamespace.NamespaceName) == true);
Assert.IsTrue(matchingSchema.Count() > 0);

var matched = false;
XElement matchingComplexType = null;
foreach (var schema in matchingSchema)
{
matchingComplexType = GetElements(schema, _xmlSchema + "complexType").SingleOrDefault(a => a.Attribute("name")?.Value.Equals(split[1]) == true);
if (matchingComplexType != null)
{
matched = true;
}
}

Assert.IsTrue(matched);

// The complex type is an array with a single element, which is an anonymous complex type
var arrayElement = matchingComplexType.Element(_xmlSchema + "sequence")?.Element(_xmlSchema + "element");
Assert.IsNotNull(arrayElement);

// The element needs a name and a complex type
var nameAttribute = arrayElement.Attribute("name");
Assert.IsFalse(string.IsNullOrEmpty(nameAttribute.Value));

var arrayElementType = arrayElement.Element(_xmlSchema + "complexType");
Assert.IsNotNull(arrayElementType);
}

[TestCleanup]
public void StopServer()
{
Expand Down Expand Up @@ -1281,6 +1403,7 @@ private async Task<string> GetWsdlFromMetaBodyWriter<T>(SoapSerializer serialize
var service = new ServiceDescription(typeof(T), false);
var baseUrl = "http://tempuri.org/";
var xmlNamespaceManager = Namespaces.CreateDefaultXmlNamespaceManager(useMicrosoftGuid);
xmlNamespaceManager.AddNamespace("tns", service.GeneralContract.Namespace);
var defaultBindingName = !string.IsNullOrWhiteSpace(bindingName) ? bindingName : "BasicHttpBinding";
var bodyWriter = serializer == SoapSerializer.DataContractSerializer
? new MetaWCFBodyWriter(service, baseUrl, defaultBindingName, false, new[] { new SoapBindingInfo(MessageVersion.None, bindingName, portName) }, new DefaultWsdlOperationNameGenerator()) as BodyWriter
Expand Down
Loading

0 comments on commit ac66154

Please sign in to comment.