Custom tags with spyne - soap

Im trying to set up a small SOAP 1.1 server with twisted and spyne, but I can't seem to find anything on how to create custom tags(body), namespaces, or headers for my responses. Is there a better way to do this than creating my own ProtocolBase?
The goal is to have soap responses that look like this:
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cwmp="urn:dslforum-org:cwmp-1-2">
<SOAP-ENV:Header>
<cwmp:ID SOAP-ENV:mustUnderstand="1">123456789</cwmp:ID>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cwmp:SetParameterValues>
<ParameterList SOAP-ENC:arrayType="cwmp:ParameterValueStruct[1]">
<ParameterValueStruct>
<Name>MY.NAME</Name>
<Value xsi:type="xsd:unsignedInt">4000</Value>
</ParameterValueStruct>
</ParameterList>
<ParameterKey>Axess Update parameters</ParameterKey>
</cwmp:SetParameterValues>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Im able to produce what I'm looking for by creating my own protocol for which I hand a string of xml similar to below.
class spyne(ServiceBase):
isLeaf = TwistedWebResource
#rpc(AnyDict, AnyDict, _returns=Unicode)
def my_rpc(ctx, DeviceId, ParameterList):
out_document = etree.parse('data.xml')
return etree.tostring(out_document, pretty_print=True,
encoding='utf8', xml_declaration=False)
class my_protocol(XmlDocument):
mime_type = 'text/xml; charset=utf-8'
type = set(XmlDocument.type)
type.update(('soap', 'soap11'))
def __init__(self, *args, **kwargs):
super(TR_069_SOAP, self).__init__(*args, **kwargs)
def serialize(self, ctx, message):
ctx.out_document = ctx.out_object[0]
def create_out_string(self, ctx, charset=None):
ctx.out_string = [ctx.out_document]
I'm not sure if there is a better way to be doing this.

Spyne does not support serializing array using the SOAP-ENC:arrayType="cwmp:ParameterValueStruct[1]" style, whatever that means.
You don't need your own protocol but you do need to override XmlDocument's complex_to_parent in Soap11 and add special handling for arrays that have, say, Array(SomeType, array_type="cwmp:ParameterValueStruct[1]").
You can either patch Spyne itself and send a pull request my way or create a Soap11 subclass (NOT XmlDocument subclass) of your own and write overriding code there.
Chime in at http://lists.spyne.io/listinfo/people if you wish to proceed either way.

Related

How do I pass username and password in SecuredAuthenticationSoapHeader using PowerShell?

I have a SOAP method called AuthenticateUser() that is defined in C# like this
[WebMethod(Description = "Returns a token string given a username and password.")]
[System.Web.Services.Protocols.SoapHeader(nameof(AuthenticationHeader))]
public AuthenticationResponse AuthenticateUser()
{
...
}
where AuthenticationHeader is type
public SecuredAuthenticationSoapHeader AuthenticationHeader;
I'm trying to make a call to this method to get a token so I can use the token to make calls to other methods in the webservice.
When I make this call in SOAP-UI the XML looks like this
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:web="https://www.example.com/webservices">
<soap:Header>
<web:SecuredAuthenticationSoapHeader>
<web:UserName>myusername</web:UserName>
<web:Password>mypassword</web:Password>
</web:SecuredAuthenticationSoapHeader>
</soap:Header>
<soap:Body>
<web:AuthenticateUser/>
</soap:Body>
</soap:Envelope>
However how can I do this in PowerSHell using Invoke-WebRequest or New-WebServiceProxy?
Is there an alternative way in which I just pass the XML as I do in SOAP-UI?

WSO2 MSF4J receive large data in #Post

We are using wso2 microservice engine as middleware between WSO2 EI and DB. The target chain MQ->WSO EI->msf4j->DB. DTO which is transfered - formatted xml string which basically shouldn't be parsed till msf4j layer. So, for all this is just string. Sometimes this is a big string.
Our code
#Path("/accountdao")
public class AccountDaoService implements Microservice {
#POST
#Path("/getbyparam")
#Produces(MediaType.TEXT_PLAIN)
public String getAllAccounts(#QueryParam("commandText") String commandText) {
Previously we tested it in GET's style calls, I mean smth like
URL url = new URL(serverURL + requestURL + "/?commandText=" +
URLEncoder.encode(request,"UTF-8"));
Cause in all other styles, using let's say HttpClient from commons, we didn't receive data in commandText.
And I've found, that I don't know how to pass large data using SoapUI or just clear java client..
With small text blocks(like 200-300 chars) is all ok, but with 6k lenght this is already problem.
Is it possible to handle in msf4j large strings or we should use for it smth else?
thanks.
ps
probably we should use #FormParam & multipart/form-data?
UPDATE 1
<payloadFactory media-type="xml">
<format>
<uri.var.commandText xmlns="">$1</uri.var.commandText>
</format>
<args>
<arg evaluator="xml" expression="get-property('uri.var.commandText')"/>
</args>
</payloadFactory>
<call blocking="true" description="">
<endpoint key="microserviceEP"/>
</call>
and microservice code
#POST
#Path("/getclientcontract")
#Produces(MediaType.TEXT_PLAIN)
public String getClientContract(#Context Request request) {
List<ByteBuffer> fullMessageBody = request.getFullMessageBody();
StringBuilder sb = new StringBuilder();
for (ByteBuffer byteBuffer : fullMessageBody) {
sb.append(StandardCharsets.UTF_8.decode(byteBuffer).toString());
}
String commandText = sb.toString();
is it ok, or there is possible more correct way?

XSD2Code namespace issue

I am using XSD2Code to generate C# class from XSD file.
I got stuck with the following problem.
XML file looks something like
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Notification xmlns="http://message.domain.com">
<Object xmlns="http://type.domain.com" ID="97440" />
</Notification>
XML gets succefsully deserialized when xmls for Object is empty. But when there is a value like in the sample above, I get an error "Object reference not set to an instance of an object".
What could cause this error?
you have to change the Serializer to something like that
private static System.Xml.Serialization.XmlSerializer Serializer
{
get
{
if ((serializer == null))
{
serializer = new System.Xml.Serialization.XmlSerializer(typeof(Notification), "http://message.domain.com");
}
return serializer;
}
}
To turn off encoding, disable encoding on the Serialization tab

Mule ESB: how to filter emails based on subject or sender?

I am new to Mule 3.3 and I am trying to use it to retrieve emails from a POP3 server and download the CSV attachments if the sender field and subject field contain certain keywords. I have used the example provided on Mulesoft website and I have successfully managed to scan my inbox for new emails and only download CSV attachments. However, I am now stuck because I can't figure out how to filter emails by subject and sender fields.
Doing some research I have come across a message-property-filter pattern tag that can be applied to an endpoint, but I am not sure exactly to which endpoint to apply it, incoming or outgoing. Neither approach seems to work and I can't find a decent example showing how to use this tag. The basic algorithm I want to implement is as follows:
if email is from "Bob"
if attachment of type "CSV"
then download CSV attachment
if email subject field contains "keyword"
if attachment of type CSV
then download CSV attachment
Here's the Mule xml I have so far:
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:file="http://www.mulesoft.org/schema/mule/file" xmlns:pop3s="http://www.mulesoft.org/schema/mule/pop3s" xmlns:pop3="http://www.mulesoft.org/schema/mule/pop3"
xmlns="http://www.mulesoft.org/schema/mule/core"
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" version="CE-3.3.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/pop3s http://www.mulesoft.org/schema/mule/pop3s/current/mule-pop3s.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/pop3 http://www.mulesoft.org/schema/mule/pop3/current/mule-pop3.xsd ">
<expression-transformer expression="#[attachments-list:*.csv]"
name="returnAttachments" doc:name="Expression">
</expression-transformer>
<pop3s:connector name="POP3Connector"
checkFrequency="5000"
deleteReadMessages="false"
defaultProcessMessageAction="RECENT"
doc:name="POP3"
validateConnections="true">
</pop3s:connector>
<file:connector name="fileName" doc:name="File">
<file:expression-filename-parser />
</file:connector>
<flow name="incoming-orders" doc:name="incoming-orders">
<pop3s:inbound-endpoint user="my_username"
password="my_password"
host="pop.gmail.com"
port="995"
transformer-refs="returnAttachments"
doc:name="GetMail"
connector-ref="POP3Connector"
responseTimeout="10000"/>
<collection-splitter doc:name="Collection Splitter"/>
<echo-component doc:name="Echo"/>
<file:outbound-endpoint path="/attachments"
outputPattern="#[function:datestamp].csv"
doc:name="File" responseTimeout="10000">
<expression-transformer expression="payload.inputStream"/>
<message-property-filter pattern="from=(.*)(bob#email.com)(.*)" caseSensitive="false"/>
</file:outbound-endpoint>
</flow>
What is the best way to tackle this problem?
Thanks in advance.
To help you, here are two configuration bits:
The following filter accepts only messages where fromAddress is 'Bob' and where subject contains 'keyword':
<expression-filter
expression="#[message.inboundProperties.fromAddress == 'Bob' || message.inboundProperties.subject contains 'keyword']" />
The following transformer extracts all the attachments whose names end with '.csv':
<expression-transformer
expression="#[($.value in message.inboundAttachments.entrySet() if $.key ~= '.*\\.csv')]" />
Welcome to Mule! A few month ago I implemented a similar proejct for a customer. I take a look at your flow, let´s start refactoring.
Remove the transformer-refs="returnAttachments" from inbound-endpoint
Add the following elements to your flow
<pop3:inbound-endpoint ... />
<custom-filter class="com.benasmussen.mail.filter.RecipientFilter">
<spring:property name="regex" value=".*bob.bent#.*" />
</custom-filter>
<expression-transformer>
<return-argument expression="*.csv" evaluator="attachments-list" />
</expression-transformer>
<collection-splitter doc:name="Collection Splitter" />
Add my RecipientFilter as java class to your project. All messages will be discard if they don't match to the regex pattern.
package com.benasmussen.mail.filter;
import java.util.Collection;
import java.util.Set;
import java.util.regex.Pattern;
import org.mule.api.MuleMessage;
import org.mule.api.lifecycle.Initialisable;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.routing.filter.Filter;
import org.mule.config.i18n.CoreMessages;
import org.mule.transport.email.MailProperties;
public class RecipientFilter implements Filter, Initialisable
{
private String regex;
private Pattern pattern;
public boolean accept(MuleMessage message)
{
String from = message.findPropertyInAnyScope(MailProperties.FROM_ADDRESS_PROPERTY, null);
return isMatch(from);
}
public void initialise() throws InitialisationException
{
if (regex == null)
{
throw new InitialisationException(CoreMessages.createStaticMessage("Property regex is not set"), this);
}
pattern = Pattern.compile(regex);
}
public boolean isMatch(String from)
{
return pattern.matcher(from).matches();
}
public void setRegex(String regex)
{
this.regex = regex;
}
}
The mule expression framework is powerful, but in some use cases I prefer my own business logic.
Improvment
Use application properties (mule-app.properties) > mule documentation
Documentation
MailProperties shows you all available message properties (EMail)
Take a look at the mule schema doc to see all available elements
Incoming payload (mails, etc) are transported by an DefaultMuleMessage (Payload, Properties, Attachments)

Can XmlSerializer deserialize into a Nullable<int>?

I wanted to deserialize an XML message containing an element that can be marked nil="true" into a class with a property of type int?. The only way I could get it to work was to write my own NullableInt type which implements IXmlSerializable. Is there a better way to do it?
I wrote up the full problem and the way I solved it on my blog.
I think you need to prefix the nil="true" with a namespace in order for XmlSerializer to deserialise to null.
MSDN on xsi:nil
<?xml version="1.0" encoding="UTF-8"?>
<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="array">
<entity>
<id xsi:type="integer">1</id>
<name>Foo</name>
<parent-id xsi:type="integer" xsi:nil="true"/>
My fix is to pre-process the nodes, fixing any "nil" attributes:
public static void FixNilAttributeName(this XmlNode #this)
{
XmlAttribute nilAttribute = #this.Attributes["nil"];
if (nilAttribute == null)
{
return;
}
XmlAttribute newNil = #this.OwnerDocument.CreateAttribute("xsi", "nil", "http://www.w3.org/2001/XMLSchema-instance");
newNil.Value = nilAttribute.Value;
#this.Attributes.Remove(nilAttribute);
#this.Attributes.Append(newNil);
}
I couple this with a recursive search for child nodes, so that for any given XmlNode (or XmlDocument), I can issue a single call before deserialization. If you want to keep the original in-memory structure unmodified, work with a Clone() of the XmlNode.
The exceptionally lazy way to do it. It's fragile for a number of reasons but my XML is simple enough to warrant such a quick and dirty fix.
xmlStr = Regex.Replace(xmlStr, "nil=\"true\"", "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"");