Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connect to SSL SOAP Host via "Service Reference" and pass Security Header

I am trying to connect to a SSL SOAP service host by C# using Service Reference. This is my request message:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo/zwMmtdsVhFsAVDkQbiV/4AAAAA1zXtnc72UEm+4tlKzvCxsvN6OC2prvRIljIX4XzHKEYACQAA</VsDebuggerCausalityData>
        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <u:Timestamp u:Id="_0">
                <u:Created>2016-03-18T12:45:27.558Z</u:Created>
                <u:Expires>2016-03-18T12:50:27.558Z</u:Expires>
            </u:Timestamp>
            <o:UsernameToken u:Id="uuid-2c7986ba-eee5-4411-90a9-a02b625c55ff-1">
                <o:Username>MyUserName</o:Username>
                <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">MyPlainPassword</o:Password>
            </o:UsernameToken>
        </o:Security>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <generateId xmlns="http://com.vedaadvantage/dp3/Enterprise/StandardTradeCreditCommercial/IndividualCommercialService"/>
    </s:Body>
</s:Envelope>

This is the message that my service sends to the host. But the host returns as below:

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.

This is my config file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <system.serviceModel>

    <bindings>
      <customBinding>
        <binding name="myBinding">
          <textMessageEncoding messageVersion="Soap11" />
          <security  authenticationMode="UserNameOverTransport"
                     messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10" >
          </security>

          <httpsTransport />
        </binding>
      </customBinding>
    </bindings>
    <client>
      <endpoint address="https://{URL}"
        binding="customBinding"
                bindingConfiguration="myBinding"
        contract="ServiceReference2.MyService"
                name="IndividualCommercialService" />
    </client>
  </system.serviceModel>
</configuration>

Although when I send the same XML via SOAPUI or other HTTP Post methods it works fine.

I also extract and attached the certificate and user/pass as below:

private static X509Certificate2 DownloadSslCertificate(string strDNSEntry)
        {

            X509Certificate2 cert = null;
            using (TcpClient client = new TcpClient())
            {
                //ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;           
                client.Connect(strDNSEntry, 443);

                SslStream ssl = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
                try
                {
                    ssl.AuthenticateAsClient(strDNSEntry);
                }
                catch (AuthenticationException e)
                {
                    //log.Debug(e.Message);
                    ssl.Close();
                    client.Close();
                    return cert;
                }
                catch (Exception e)
                {
                    //log.Debug(e.Message);
                    ssl.Close();
                    client.Close();
                    return cert;
                }
                cert = new X509Certificate2(ssl.RemoteCertificate);
                ssl.Close();
                client.Close();
                return cert;
            }
        }

        private static void Main(string[] args){
                var proxy = new MyService();

                var uri = proxy.Endpoint.Address.Uri;
                var cer = DownloadSslCertificate(uri.DnsSafeHost);

                EndpointIdentity identity = EndpointIdentity.CreateDnsIdentity(cer.Subject.Replace("CN=", ""));
                EndpointAddress address = new EndpointAddress(proxy.Endpoint.Address.Uri, identity);

                proxy.Endpoint.Address = address;

                proxy.ClientCredentials.UserName.UserName = "MyUserName";
                proxy.ClientCredentials.UserName.Password = "MyPlainPassword";
                proxy.ClientCredentials.ServiceCertificate.DefaultCertificate = cer;

                proxy.HellowWorld();
          }

I am not sure whether the method that I am getting the certificate is correct or not and also why HTTP Post works but my Service Reference Call does not.

Thanks in advance for your help.

Cheers

like image 234
Barsham Avatar asked Nov 09 '22 18:11

Barsham


1 Answers

Try to look inside WSDL (Service References) in order to see hidden files first select Show All Files in Solution explorer. You`ll se inside service reference Reference.svcmap -> Reference.cs, and inside of this file add ProtectionLevel = System.Net.Security.ProtectionLevel.Sign as shown below

[System.ServiceModel.ServiceContractAttribute(Namespace = "http://www.your.url/Service/", ConfigurationName = "Service.Service", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)]

that should help you. Usually it`s really bad idea to modify autogenerated proxy, but seems like that is the only option.

like image 197
Vladimir Avatar answered Nov 14 '22 23:11

Vladimir