WCF Soap Service Deserialization failed (unrecognized element was encountered) - wcf

I build a WCF selfhosted WS (basichttp-binding) with 2 methods. Then created a WSDL and delivered it to a customer. Now they are sending SOAP-requests to the service but one of my methods (PostSendeplatz) fails everytime with a null parameter. In the trace I see the following:
<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Verbose">
<TraceIdentifier>http://msdn.microsoft.com/de-DE/library/System.Runtime.Serialization..aspx</TraceIdentifier>
<Description>An unrecognized element was encountered in the XML during deserialization which was ignored.</Description>
<AppDomain>RabbitServerTopSelf.vshost.exe</AppDomain>
<ExtendedData xmlns="http://schemas.microsoft.com/2006/08/ServiceModel/StringTraceRecord">
<Element>http://plantri.de:sendeplatz</Element>
</ExtendedData>
</TraceRecord>
I checked my namespaces in DataContracts, ServiceContract and ServiceImplementation:
[ServiceContract(Namespace = "http://plantri.de")]
public interface IRabbitImportService {
[OperationContract]
bool PostSendung(Sendung sendung, out string errorMsg);
[OperationContract]
bool PostSendeplatz(Sendeplatz sendePlatz, out string errorMsg);
}
...
[DataContract(Namespace = "http://plantri.de")]
public class Sendeplatz : RabbitIdBase { ...
...
[DataContract(Namespace = "http://plantri.de")]
public class Sendung : RabbitIdBase { ...
...
[ServiceBehavior(Namespace="http://plantri.de")]
public class RabbitImportService : Log4NetLogWriter, IRabbitImportService {
...
public bool PostSendung(Sendung sendung, out string errorMsg) {
... do something and return success
}
public bool PostSendeplatz(Sendeplatz sendePlatz, out string errorMsg) {
errorMsg = String.Empty;
if (sendePlatz == null) {
Error("no Sendeplatz send!");
return false;
}
... never came until this point!!!!
}
Here is a part of the soap-envelope which isn't deserialized (from the trace):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://192.168.40.64:8800/RabbitImportService</To>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://plantri.de/IRabbitImportService/PostSendeplatz</Action>
</s:Header>
<soapenv:Body>
<PostSendeplatz xmlns="http://plantri.de">
<sendeplatz>
<Id>1258878</Id>
...
But the working envelope looks quite the same:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://192.168.40.64:8800/RabbitImportService</To>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://plantri.de/IRabbitImportService/PostSendung</Action>
</s:Header>
<soapenv:Body>
<PostSendung xmlns="http://plantri.de">
<sendung>
<Id>564589</Id>
...
I don't have a chance to change the client proxy which was writen by a customer (JAVA).
Did anyone have an idea to solve the problem?

But the working envelope looks quite the same: How?
<PostSendeplatz xmlns="http://plantri.de">
<sendeplatz>
<PostSendung xmlns="http://plantri.de">
<sendung>
I see these tag names differs.

Related

Security processor was unable to find a security header in the message.

In my many trials to debug this
Exception: `System.ServiceModel.Security.MessageSecurityException: Security processor was unable to find a security header in the message.
This might be because the message is an unsecured fault or because there is a
binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security`
How Do I debug a fault exception
I am not sure if this is why my response says 'Rejected by policy from client'
This is just a guess if it could be because of the additional junk which in soap header .
My code generated a soap header which looks like this
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<a:Action s:mustUnderstand="1" u:Id="_3"/>
<a:MessageID u:Id="_4">urn:uuid:9659b138-7fc0-4bb6-8c0a-bae00336ba78</a:MessageID>
<a:ReplyTo u:Id="_5">
<a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
</a:ReplyTo>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">
uIDPo/RnkzjA3fBPjgXUnYt8J3IAAAAAoMwUVXqfw0yigCfFtptf4RNq4s3l6eJLuuLNNdxRoH4ACQAA
</VsDebuggerCausalityData>
<a:To s:mustUnderstand="1" u:Id="_6">https://service100.emedny.org:9047/MHService</a:To>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<o:BinarySecurityToken u:Id="uuid-8d1465b7-c0fd-4137-9361-d0a818286435-53" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">
<!--Removed-->
</o:BinarySecurityToken>
<o:BinarySecurityToken u:Id="uuid-8d1465b7-c0fd-4137-9361-d0a818286435-52" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">
<!--Removed-->
</o:BinarySecurityToken>
</o:Security>
</s:Header>
...
</s:Envelope>
This is the sample soap request for vendor
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mhs="http://org/emedny/mhs/" xmlns:urn="urn:hl7-org:v3">
<soapenv:Header>
<wsse:Security soap:mustUnderstand="1" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:BinarySecurityToken ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-e00c8062-83d2-4f04-88fc-996218e7bb3d">MIICeDCC....(eMedNY signed user MLS cert).......</wsse:BinarySecurityToken>
<wsse:BinarySecurityToken ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-c0cc2cd4-cb77-4fa5-abfa-bd485afd1685">MIIDFj.....( eMedNY MLS web-service end-point public cert)........</wsse:BinarySecurityToken>
This is the additional stuff my client code generates
<a:Action s:mustUnderstand="1" u:Id="_3"/>
<a:MessageID u:Id="_4">urn:uuid:9659b138-7fc0-4bb6-8c0a-bae00336ba78</a:MessageID>
<a:ReplyTo u:Id="_5">
<a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address>
</a:ReplyTo>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">
uIDPo/RnkzjA3fBPjgXUnYt8J3IAAAAAoMwUVXqfw0yigCfFtptf4RNq4s3l6eJLuuLNNdxRoH4ACQAA
</VsDebuggerCausalityData>
<a:To s:mustUnderstand="1" u:Id="_6">https://service100.emedny.org:9047/MHService</a:To>
How would I remove this?
Internet recommends using Imessageinspector and custombehviour
public class CustomMessageInspector : IClientMessageInspector
{
#region IClientMessageInspector Members
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
request.Headers.RemoveAll("Action", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
request.Headers.RemoveAll("MessageID", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
request.Headers.RemoveAll("ReplyTo", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
request.Headers.RemoveAll("To", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
return null;
}
#endregion
}
public class CustomBehavior : IEndpointBehavior
{
<--removed some more classes-->
public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, System.ServiceModel.Dispatcher.ClientRuntime behavior)
{
//Add the inspector
behavior.MessageInspectors.Add(new CustomMessageInspector());
}
}
then finally in the call to the proxyclient
MHSClient proxy = new MHSClient(GetCustomBinding(),
new EndpointAddress(new Uri("https://service100.emedny.org:9047/MHService"),
EndpointIdentity.CreateDnsIdentity("DPMedsHistory"));
proxy.Endpoint.EndpointBehaviors.Add(new CustomBehavior());
private static Custombinding GetCustomBinding()
{
var b = new CustomBinding();
var sec = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10);
sec.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters());
sec.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
sec.MessageSecurityVersion =
MessageSecurityVersion.
WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
sec.IncludeTimestamp = false;
sec.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.EncryptBeforeSign;
TextMessageEncodingBindingElement textEncBE = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
HttpsTransportBindingElement httpsBE = new HttpsTransportBindingElement();
CustomBinding myBinding = new CustomBinding();
myBinding.Elements.Add(sec);
myBinding.Elements.Add(textEncBE);
myBinding.Elements.Add(httpsBE);
return myBinding;
}
THis doesn't work or rather gives me an error:
No signature message parts were specified for messages with the '' action.

RoR: Error when connecting affilinet web services (logon function) using savon (ruby on rails) -> Deserialization Failed

I try to logon at the affilinet web services via the provided logon function. I'm working in a Rails 3 environment (3.0.x). I utilize the ruby on rails gem Savon in version 2 which in turn uses soap to connect to affilinet.
The most current wsdl can be found here https://api.affili.net/V2.0/Logon.svc?wsdl.
My code looks like this:
client = Savon.client do
wsdl "https://api.affili.net/V2.0/Logon.svc?wsdl"
end
message = {'Username' => 'username', 'Password' => 'password', 'WebServiceType' => 'Publisher'}
response = client.call(:logon, :message => message)
The request generated by Savon:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="http://affilinet.framework.webservices/Svc" xmlns:ins3="http://schemas.microsoft.com/2003/10/Serialization/Arrays" xmlns:ins2="http://affilinet.framework.webservices/types" xmlns:ins1="http://schemas.datacontract.org/2004/07/Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF" xmlns:ins0="http://www.microsoft.com/practices/EnterpriseLibrary/2007/01/wcf/validation" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Body>
<tns:LogonRequestMsg>
<tns:Password>password</tns:Password>
<tns:WebServiceType>Publisher</tns:WebServiceType>
<tns:Username>username</tns:Username>
</tns:LogonRequestMsg>
</env:Body>
</env:Envelope>
When sending this request to the web service I get this (error) response:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:DeserializationFailed</faultcode>
<faultstring xml:lang="en-US">The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://affilinet.framework.webservices/Svc:LogonRequestMsg. The InnerException message was 'Error in line 1 position 775. 'EndElement' 'LogonRequestMsg' from namespace 'http://affilinet.framework.webservices/Svc' is not expected. Expecting element 'Username | Password | WebServiceType'.'. Please see InnerException for more details.</faultstring>
<detail>
<ExceptionDetail xmlns="http://schemas.datacontract.org/2004/07/System.ServiceModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<HelpLink i:nil="true"/>
<InnerException>
<HelpLink i:nil="true"/>
<InnerException i:nil="true"/>
<Message>Error in line 1 position 775. 'EndElement' 'LogonRequestMsg' from namespace 'http://affilinet.framework.webservices/Svc' is not expected. Expecting element 'Username | Password | WebServiceType'.</Message>
<StackTrace> at System.Runtime.Serialization.XmlObjectSerializerReadContext.ThrowRequiredMemberMissingException(XmlReaderDelegator xmlReader, Int32 memberIndex, Int32 requiredIndex, XmlDictionaryString[] memberNames)
 ... (loads more) ...
</StackTrace>
<Type>System.ServiceModel.Dispatcher.NetDispatcherFaultException</Type>
</ExceptionDetail>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
Any ideas what's wrong?
EDIT:
The request in soapUI looks like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:svc="http://affilinet.framework.webservices/Svc" xmlns:typ="http://affilinet.framework.webservices/types">
<soapenv:Header/>
<soapenv:Body>
<svc:LogonRequestMsg>
<!--Optional:-->
<typ:Username>username</typ:Username>
<!--Optional:-->
<typ:Password>password</typ:Password>
<typ:WebServiceType>Publisher</typ:WebServiceType>
<!--Optional:-->
<typ:DeveloperSettings>
<!--Optional:-->
<typ:SandboxPublisherID>?</typ:SandboxPublisherID>
</typ:DeveloperSettings>
<!--Optional:-->
<typ:ApplicationSettings>
<!--Optional:-->
<typ:ApplicationID>?</typ:ApplicationID>
<!--Optional:-->
<typ:DeveloperID>?</typ:DeveloperID>
</typ:ApplicationSettings>
</svc:LogonRequestMsg>
</soapenv:Body>
</soapenv:Envelope>
Maybe the differences in the requests (generated by Savon and by soapUI) are the key!? Especially the different namespaces: svc/typ vs. env/tns. Any ideas? How can I tell Savon to use the svc namespace for the LogonRequestMsg?
Looking into the WSDL of Affili.net it shows that username, password, WebserviceType etc have the wrong namespace.
EDITED for the namespace after another look into your example. Username, Password and WebServiceType are defined in the namespace ins2="http://affilinet.framework.webservices/types" which is tagged by "ins2" in your case.
The quick and dirty way to get over it is
client = Savon.client do
wsdl "https://api.affili.net/V2.0/Logon.svc?wsdl"
end
message = {'ins2:Username' => 'username',
'ins2:Password' => 'password',
'ins2:WebServiceType' => 'Publisher'}
response = client.call(:logon, :message => message)
i think the problem is with namespace order, after several request saw different order in namespace.
This code works for me (savod version 1), overwrite namespaces:
message = {
'ins0:Username' => 'XXXXXXX',
'ins0:Password' => 'XXXXXXX',
'ins0:WebServiceType' => 'XXXXXX',
:order! => ['ins0:Username', 'ins0:Password', 'ins0:WebServiceType']
}
#client.wsdl.document = 'https://api.affili.net/V2.0/Logon.svc?wsdl'
response = #client.request :logon do
soap.body = message
soap.namespaces["xmlns:ins0"] = "http://affilinet.framework.webservices/types"
soap.namespaces["xmlns:ins1"] = "http://schemas.microsoft.com/2003/10/Serialization/Arrays"
soap.namespaces["xmlns:ins2"] = "http://www.microsoft.com/practices/EnterpriseLibrary/2007/01/wcf/validation"
soap.namespaces["xmlns:ins3"] = "http://schemas.datacontract.org/2004/07/Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF"
end

JAX-WS ws-security UsernameToken authorization on server

I have created a web service in netbeans with METRO. I modified my web service wsit config for using Usernametoken authentication (without encryption).
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" name="NewWebService" targetNamespace="http://test.org/" xmlns:tns="http://test.org/" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:fi="http://java.sun.com/xml/ns/wsit/2006/09/policy/fastinfoset/service" xmlns:tcp="http://java.sun.com/xml/ns/wsit/2006/09/policy/soaptcp/service" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" xmlns:sc="http://schemas.sun.com/2006/03/wss/server" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy"
>
<message name="hello"/>
<message name="helloResponse"/>
<portType name="NewWebService">
<operation name="hello">
<input message="tns:hello"/>
<output message="tns:helloResponse"/>
</operation>
</portType>
<binding name="NewWebServicePortBinding" type="tns:NewWebService">
<wsp:PolicyReference xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" URI="#UsernameToken"/>
<operation name="hello">
<input></input>
<output></output>
</operation>
</binding>
<service name="NewWebService">
<port name="NewWebServicePort" binding="tns:NewWebServicePortBinding"/>
</service>
<!-- Policy for Username Token with plaintext password, sent from client to server only -->
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken=".../IncludeToken/AlwaysToRecipient"/>
</wsp:Policy>
</sp:SupportingTokens>
<wsss:ValidatorConfiguration wspp:visibility="private" xmlns:wsss="http://schemas.sun.com/2006/03/wss/server" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy">
<wsss:Validator name="usernameValidator" classname="org.test.MyAuth"/>
</wsss:ValidatorConfiguration>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
</definitions>
My PasswordValidator
package org.test;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidationException;
import com.sun.xml.wss.impl.callback.PasswordValidationCallback.Request;
public class MyAuth implements PasswordValidationCallback.PasswordValidator
{
#Override
public boolean validate(Request request) throws PasswordValidationException {
PasswordValidationCallback.PlainTextPasswordRequest ptreq
= (PasswordValidationCallback.PlainTextPasswordRequest)request;
//Database query
return CheckUserInDateBase(ptreq.getPassword(), ptreq.getUsername());
}
}
Now i need authorize user with his username and password and check his role (every method of web service has annotation RolesAllowed). I have created SOAP handler for my web service where I trying to get username and password from soap headers, but header doesnt contains this information (when i get this header in handler).
Actually SOAP message looks like
<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<S:Header>
<macAddress xmlns="http://ws.mkyong.com/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next">F8-D1-11-01-36-20</macAddress>
<wsse:Security S:mustUnderstand="1">
<wsse:UsernameToken xmlns:ns15="http://schemas.xmlsoap.org/ws/2006/02/addressingidentity" xmlns:ns14="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns13="http://www.w3.org/2003/05/soap-envelope" wsu:Id="uuid_48e60f1c-aea9-4bcc-897f-ef661fe2895b">
<wsse:Username>myusername</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">mypass</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</S:Header>
<S:Body>
<ns2:hello xmlns:ns2="http://test.org/">
<name>aaaa</name>
</ns2:hello>
</S:Body>
</S:Envelope>
When I trying to extract header's child elements I'm getting only macAddress header (my custom header)
#Override
public boolean handleMessage(SOAPMessageContext context) {
Iterator i = context.getMessage().getSOAPPart().getEnvelope().getHeader().getChildElements();
return true;
}
So. How can I access to wssecurity headers? Or maybe has another way to check user role before execution web service method?
Instead of checking at your validator, store the username and password using ThreadLocal then apply your authentication roles within the service implementation as below. In my case, I used this approach to throw a custom exception.
My Validator:
/**
* #author SaudAlajmi
*
*/
public class PasswordValidator implements PasswordValidationCallback.PasswordValidator {
/* I used this approach because they need to throw a custom exception in case of authentication failure, as far as I know there is no such way
* to do it especially since the validator does not have access to the WebServiceContext, but this way and it is safe because every thread has
* it is own copy and that's why I used ThreadLocal;
*/
private static final ThreadLocal<String> username = new ThreadLocal<String>();
private static final ThreadLocal<String> password = new ThreadLocal<String>();
public boolean validate(Request request) throws PasswordValidationException {
PasswordValidationCallback.PlainTextPasswordRequest ptreq = (PasswordValidationCallback.PlainTextPasswordRequest) request;
password.set(ptreq.getPassword());
username.set(ptreq.getUsername());
return true;
}
public static String getUsername() {
String user = username.get();
username.remove();
return user;
}
public static String getPassword() {
String pwd= password.get();
password.remove();
return pwd;
}
}
My Service Impl:
String username = PasswordValidator.getUsername();
String password = PasswordValidator.getPassword();
if(username == null || !"test".equals(username) || password == null ||!"test".equals(password)){
faultInfo = new CommonErrorStructure();
faultInfo.setCode("KFSH000401");
faultInfo.setErrorText("Username/Password is incorrect");
faultInfo.setRaisedBy("PatientRecordService");
throw new GetPatientRecordError("Authentication Failure", faultInfo);
}
Reference:
Retrieve plaintext WS-Security password at service endpoint with Metro + WSIT?

Wcf Backward compatibility issue - missing namespace on method parameter

we are hosted our WCF web service in windows service. We are using basicHttpBinding. We need preserve backward compatibility with Soap 1.1 Web service. Our problem is missing namespace on element EPTalkMessage in web method parameter. I searched a lot but I didn't find some way to add namespace to this element.
Soap from old web service is:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://aaa.sk/EPTalk/IssueDocument</Action>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<IssueDocument xmlns="http://aaa.sk/EPTalk">
<EPTalkMessage xmlns="http://aaa.sk/EPTalk/ToSignInput" />
</IssueDocument>
</s:Body>
</s:Envelope>
New generated soap is:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://aaa.sk/EPTalk/IssueDocument</Action>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<IssueDocument xmlns="http://aaa.sk/EPTalk">
<EPTalkMessage />
</IssueDocument >
</s:Body>
</s:Envelope>
Service signature is as follows:
[ServiceContract (Namespace = "http://aaa.sk/EPTalk")]
[XmlSerializerFormat(Use = OperationFormatUse.Literal, Style = OperationFormatStyle.Document)]
public interface IRegistryInputWebService
{
[OperationContract(Action = "http://aaa.sk/EPTalk/IssueDocument")]
RegistryServiceResult IssueDocument([MessageParameter(Name = "EPTalkMessage")]
UpvsPortalEmulator.ToSignInput.EPTalkMessage message);
}
Binding:
BasicHttpBinding
{
MaxReceivedMessageSize = 1024 * 1024 * 10,
MaxBufferSize = 1024 * 1024 * 10,
ReaderQuotas =
{
MaxArrayLength = 1024 * 1024 * 10,
MaxStringContentLength = 1024 * 1024 * 10
},
MessageEncoding = WSMessageEncoding.Text,
Security = new BasicHttpSecurity
{
Mode = BasicHttpSecurityMode.None
}
};
Edited: EPTalkMessage definition added.
[XmlType, XmlRoot (ElementName = "EPTalkMessage", Namespace = Declarations.SchemaVersion, IsNullable = false), Serializable]
public class EPTalkMessage
{
}
Thanks a lot for your help
After searching for a while, I resolved this issue with MessageContracts.

Invoke WCF service dynamically during runtime

I am trying to invoke WCF service dynamically. I am able connect to the service and invoke methods that do not require any parameters.
ChannelFactory<IRequestChannel> factory = new ChannelFactory<IRequestChannel>(this.ServiceBinding, this.EndPoint.Address);
IRequestChannel channel = factory.CreateChannel();
However, I am unable to invoke Operation Contracts that require composite Entity as a parameter.
The following code is used to instantiate the request Message:
Message requestMessage = Message.CreateMessage(this.ServiceBinding.MessageVersion, contractNameSpace, new SimpleMessageBody(value));
The value used in SimpleMessageBody class is serialized value of the entity using DataContractSerializer.
<Person xmlns="http://schemas.datacontract.org/2004/07/WcfService.Test.Service" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Name>John Smith</Name></Person>
Operation Contract
public string GetData(Person value)
{
using (MemoryStream ms = new MemoryStream())
{
value = new Person { Name = "John Smith" };
DataContractSerializer ser = new DataContractSerializer(typeof(Person));
ser.WriteObject(ms, value);
var result = UnicodeEncoding.UTF8.GetString(ms.ToArray());
}
return string.Format("You entered: {0}", value.Name);
}
Entity
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
}
The following SOAP message is generated from the above createmessage code:
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/IService1/GetData</a:Action>
<a:MessageID>urn:uuid:cf78d5b7-333b-40eb-a71c-d81cb9c37b5d</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://localhost:52724/Service1.svc</a:To>
</s:Header>
<s:Body><Person xmlns="http://schemas.datacontract.org/2004/07/WcfService.Test.Service" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Name>John Smith</Name></Person></s:Body>
</s:Envelope>
However, in order for the Person entity to be populated and the correct operation contract to be executed the SOAP has to be as follows:
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/IService1/GetData</a:Action>
<a:MessageID>urn:uuid:d49bd525-0f30-46fe-94fb-0248c2cb1ea2</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
</s:Header>
<s:Body>
<GetData xmlns="http://tempuri.org/">
<value xmlns:d4p1="http://schemas.datacontract.org/2004/07/WcfService.Test.Service" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:Name>John Smith</d4p1:Name>
</value>
</GetData>
</s:Body>
</s:Envelope>
Please NOTE the message body.
Thanks
I don't know why are you doing it this hard way but if you want to call the method expecting SOAP request you shown you must first provide message contract to your client:
[MessageContract(WrapperName="GetName")]
public class MessageContract
{
[MessageBodyMember(Name="value")]
public Person Person { get; set; }
}
And you will also need similar contract for response.
Default serialization uses wrappers inferred from operation contract names but because you are not providing service contract your serializer doesn't know about existing wrappers because of that you have to provide this additional knowledge manually or redefine your service so that it doesn't expect wrappers elements (it is also done with message contracts and setting their IsWrapped properties to false).