How to make WCF Client conform to specific WS-Security - sign UsernameToken and SecurityTokenReference

前端 未结 2 666
野趣味
野趣味 2020-12-14 01:45

I need to create a wcf client to call a service that I have no control over.

I have been given a wsdl and a working soapui project.

The service uses both a

相关标签:
2条回答
  • 2020-12-14 02:19

    Maybe it's because your certificate is not publicly valid. Try this:

    System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(delegate { return true; });
    //...
    using (var client = new SrvClient())
    {
        client.ClientCredentials.UserName.UserName = "usr";
        client.ClientCredentials.UserName.Password = "psw";
        //...
    }
    
    0 讨论(0)
  • 2020-12-14 02:23

    Finally sorted the problem today. In terms of terminology, it is not the SecurityTokenReference that I need to sign, but the Binary Security Token.

    In order to do this I needed to hide the certificates for Initiator and Recipient and add a signed supporting token.

    I went back to using configuration to create and sign the message, rather than trying to add the signature manually.

    Other problem that would have stopped this from working is that I had an incorrect namespace on my custom 'Messaging' header, so be mindful of namespaces, I didn't think they would be as important as what they are.

    The code to create the binding follows

        private System.ServiceModel.Channels.Binding GetCustomBinding()
        {
            System.ServiceModel.Channels.AsymmetricSecurityBindingElement asbe = new AsymmetricSecurityBindingElement();
            asbe.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
    
            asbe.InitiatorTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.Never };
            asbe.RecipientTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.Never };
            asbe.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
    
            asbe.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
            asbe.EnableUnsecuredResponse = true;
            asbe.IncludeTimestamp = false;
            asbe.SetKeyDerivation(false);
            asbe.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128Rsa15;
            asbe.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
            asbe.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters());
    
            CustomBinding myBinding = new CustomBinding();
            myBinding.Elements.Add(asbe);
            myBinding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
    
            HttpsTransportBindingElement httpsBindingElement = new HttpsTransportBindingElement();
            httpsBindingElement.RequireClientCertificate = true;
            myBinding.Elements.Add(httpsBindingElement);
    
            return myBinding;
        }
    

    When using the binding, I set the ClientCredentials UserName, ServiceCertificate and ClientCertificate, and all works as expected.


    Using the code is as follows

    using (CredentialingService.SOAPPortTypeClient client = GetCredentialingClient())
    {
        client.Open();
        etc....
    }
    
    private static CredentialingService.SOAPPortTypeClient GetCredentialingClient()
    {
        CredentialingService.SOAPPortTypeClient client = new CredentialingService.SOAPPortTypeClient(GetCustomBinding(), new EndpointAddress(new Uri(Settings.AppSettings.B2BUrl), new DnsEndpointIdentity(Settings.AppSettings.B2BDNSEndpoint), new AddressHeaderCollection()));
        client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
        SetClientCredentialsSecurity(client.ClientCredentials);
    
        return client;
    }
    

    where GetCustomBinding is specified in my post

    SetClientCredentialsSecurity is where the certificate is set, and is as follows

    private static void SetClientCredentialsSecurity(ClientCredentials clientCredentials)
    {
        clientCredentials.UserName.UserName = Settings.AppSettings.B2BUserName;
        clientCredentials.UserName.Password = Settings.AppSettings.B2BPassword;
    
        string directoryName = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
        clientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(Path.Combine(directoryName, Settings.AppSettings.B2BServerCertificateName));
        clientCredentials.ClientCertificate.Certificate = new X509Certificate2(Path.Combine(directoryName, Settings.AppSettings.B2BClientCertificateName), Settings.AppSettings.B2BClientCertificatePassword);
    }
    

    Hopefully that makes it a bit clearer

    0 讨论(0)
提交回复
热议问题