gary
gary

Reputation: 150

How to consuming the WSDL web service using Pkcs12 keystore certificate

I need to consume a third-party web service. I have a WSDL file and .pkcs12 Keystore file & password. Using that WSDL file I have added web reference in the project. read the Keystore file. Created a new instance of X509certificate2 class and imported the certificate after adding to the service class. I am trying to call method in my service

            service.mymethod(param1)--> (At this line its throwing error stating that ws-security header not found)

by googling the error I found StackOverflow link to add security header after following that link here is complete code

                //reading PCKS12 certificate
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
                var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Content\\myKeyStoreFile.pkcs12");
                var data = System.IO.File.ReadAllBytes(path);
                //Importing Certificate
                X509Certificate2 certificate = new X509Certificate2();
                certificate.Import(data, "password", X509KeyStorageFlags.DefaultKeySet);
                //adding WS-Security Headers
                UsernameToken token = new UsernameToken("keyname", "password", PasswordOption.SendHashed);
                service.RequestSoapContext.Security.Tokens.Add(token);
                //adding certificate to service
                service.ClientCertificates.Add(certificate);
                //calling proxy class(service method)
                service.methodname(param1);-->(its throwing System.web.service.protocols.soapheaderexception:'nested exception is org.apache.wss4j.common.ext.WSSSecurityException Original Exception was javax.security.auth.callback.unsupportedcallbackexception)

I have a java code(implemented in spring boot) for reference. Wss4jSecurityInterceptor securityInterceptor = new Wss4jSecurityInterceptor();

    //crypto varible contains .pkcs12 file path and password properties
    Crypto crypto = null;
    try {
        crypto = CryptoFactory.getInstance(cryptoPropertyFile);
    }catch(WSSecurityException e) {
        e.printStackTrace();}
    securityInterceptor.setSecurementActions("Encrypt Signature");
    securityInterceptor.setSecurementEncryptionUser(trustedCertKeyAlias);
    securityInterceptor.setSecurementEncryptionCrypto(crypto);
    securityInterceptor.setSecurementEncryptionParts("{Content {http://schemas.xmlsoap.org/soap/envelope/}Body");
    securityInterceptor.setSecurementUsername(privateKeyAlias);
    securityInterceptor.setSecurementPassword(privateKeyPassword);
    securityInterceptor.setSecurementSignatureCrypto(crypto);
securityInterceptor.setSecurementSignatureKeyIdentifier("DirectReference");
    securityInterceptor.setSecurementSignatureUser(privateKeyAlias);
    securityInterceptor.setSecurementSignatureParts("{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body");        
    securityInterceptor.setValidationActions("Encrypt");
    securityInterceptor.setValidationDecryptionCrypto(crypto);
    KeyStoreCallbackHandler keyStoreCallbackHandler = new KeyStoreCallbackHandler();
    keyStoreCallbackHandler.setPrivateKeyPassword(privateKeyPassword);
securityInterceptor.setValidationCallbackHandler(keyStoreCallbackHandler);
    LogHttpHeaderClientInterceptor logHttpHeaderClientInterceptor = new LogHttpHeaderClientInterceptor();
    ClientInterceptor[] interceptors = {securityInterceptor, logHttpHeaderClientInterceptor};
    template.setInterceptors(interceptors);

Can any one please let me know how to add interceptors in dotnet. I have done some research but couldn't find any solution. Is there any thing that smilar to Wss4jSecurityInterceptor in dotnet.

Upvotes: 2

Views: 1086

Answers (1)

weichch
weichch

Reputation: 10035

IClientMessageInspector might be something you're after.

You need to create IEndpointBehavior and add IClientMessageInspector to your behavior, then add the behavior to the endpoint used to create ChannelFactory.

See: https://learn.microsoft.com/en-us/dotnet/framework/wcf/extending/how-to-inspect-or-modify-messages-on-the-client

Also see: https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.dispatcher.iclientmessageinspector?view=netframework-4.8

Example:

class MyEndpointBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(new MyMessageInspector());
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
    }

    public void Validate(ServiceEndpoint endpoint)
    {
    }
}

class MyMessageInspector : IClientMessageInspector
{
    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
    }

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        return null;
    }
}

Use message inspector:

var endpoint = new EndpointAddress("<your webservice uri>");
var binding = new BasicHttpBinding(); // Assume you are using HTTP binding
var channelFactory = new ChannelFactory<Soap>(binding, endpoint);
channelFactory.Endpoint.EndpointBehaviors.Add(new MyEndpointBehavior());
var client = channelFactory.CreateChannel();

Upvotes: 3

Related Questions