none
How to build https WCF server/client with Windows authentication? RRS feed

  • Question

  • I need to build a Windows service/client using https protocol. The user should be authenticated on the server using username/password, provided on the client side. I use Transport level protection with TLS encryption. The service is self-hosted (no IIS). Documentation is very vague and most description just repeats the name of the variable with no explanations. Also I was not able to find a functioning example.

    My code is distributed across multiple functions. For simplicity reasons, below are some code snippets that I think relevant to the question. Feel free to ask for more details.

    Server:

    private static Binding CreateWebHttpBinding() { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; var binding = new WebHttpBinding(WebHttpSecurityMode.Transport) { ReaderQuotas = _readerQuotas, MaxReceivedMessageSize = 2147483647, OpenTimeout = TimeSpan.MaxValue, CloseTimeout = TimeSpan.MaxValue, SendTimeout = TimeSpan.MaxValue, ReceiveTimeout = TimeSpan.MaxValue, TransferMode = TransferMode.Buffered }; binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows; // I have no idea what Windows actually means - is it the client Windows system or the server Windows?

    return binding; }


                var address = new Uri[] {   new Uri($"https://localhost:443/MyApp/{serviceName}.svc") };
                var host = new ServiceHost(serviceType, address);
                    var endpoint = host.AddServiceEndpoint(serviceContract, CreateWebHttpBinding(), "");
                    endpoint.Behaviors.Add(new WebHttpBehavior { DefaultBodyStyle = WebMessageBodyStyle.Wrapped });
    
                host.Open();


    Client:

                    endpointAddress = $"https://{middlewareHost}:443/MyApp/{serviceName}.svc";
                    binding = CreateWebHttpBinding(); // same as for the server side
                    var channelFactory = new ChannelFactory<T>(binding, new EndpointAddress(new Uri(endpointAddress)));
                    if (channelFactory.Credentials != null)
                    {
                        channelFactory.Credentials.Windows.ClientCredential =
                            new NetworkCredential(userName, userPassword);
                        channelFactory.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
                        // Here is another totally mysterious setting ^
                    }
    
                    ClientCredentials clientCredentials = null;
                    foreach (var b in channelFactory.Endpoint.Behaviors)
                    {
                        clientCredentials = b as ClientCredentials;
                        if (clientCredentials != null)
                        {
                            break;
                        }
                    }
    
                    if (clientCredentials == null)
                    {
                        clientCredentials = new ClientCredentials();
                        channelFactory.Endpoint.Behaviors.Add(clientCredentials);
                    }
    
                    clientCredentials.UserName.UserName = userName;
                    clientCredentials.UserName.Password = userPassword;
    
                    channelFactory.Endpoint.Behaviors.Add(new WebHttpBehavior { DefaultBodyStyle = WebMessageBodyStyle.Wrapped });
    channelFactory.CreateChannel()

    I am working on it for two weeks and completely lost. When I try to use http and port 80 (Transport Security None), I get connected, but no authentication happens, when I use https and port 443 the client's request gets rejected with "An existing connection was forcibly closed by the remote host". It does not reach my server. I guess it is rejected by Windows system, but with absence of IIS I don't know - how to find a clue. There are so many settings with little or no documentation and no examples. Please help.

    And yes, I enabled http 80 and https 443 ports on the server side.

    Wednesday, April 3, 2019 12:24 PM

All replies

  • One more comment. There are examples that work with "WsHttpBinding", not with "WebHttpBinding". I actually tried "WsHttpBinding" and it forked just fine, except that "WsHttpBinding" requires a direct connection, which is not acceptable for use on the internet, where client computers may be located in a private network.

    The aforementioned example also says that I need to install a certificate:

    netsh http add sslcert ipport=0.0.0.0:8000 certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6 appid={00112233-4455-6677-8899-AABBCCDDEEFF}   
    

    But the article does not mention where I can get the "appid". Looks like there are comments here and there with some important information missing, which is very frustrating.

    Wednesday, April 3, 2019 1:17 PM
  • WCF issues can be addressed at the WCF forum,

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=wcf

    Wednesday, April 3, 2019 1:25 PM
  • Hi Aleksey Malyshev,

    Simply speaking, window authentication requires client provide credential which could be recognized by the server windows, namely that the window credential is server windows account. Besides, if the client end enables the Impersonation. it can access server resources, just like Windows users on the server (some files can only be read and written by specified users)
    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/delegation-and-impersonation-with-wcf?view=netframework-4.7.2
    As you know, https is http with SSL, namely that we are supposed to provide a certificate to encrypt and protect the communication between the client and server. when we host the service in console application, we should bind the certificate to the specified port by the following command.
    netsh http add sslcert ipport=0.0.0.0:11011 certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6 appid={00112233-4455-6677-8899-AABBCCDDEEFF}

    https://docs.microsoft.com/en-us/windows/desktop/http/add-sslcert
    https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate
    Execute CMD with administrator privileges and ensure that the certificate is installed on the local machine certificate store (certlm.msc). Certhash parameter specifies the thumbprint of the certificate. The appid parameter is a GUID that can be used to identify the owning application (located in the project.csproj file)
    <ProjectGuid>{56FDE5B9-3821-49DB-82D3-9DCE376D950A}</ProjectGuid>

    Feel free to let me know if there is anything I can help with.
    Best Regards
    Abraham
    Thursday, April 4, 2019 3:18 AM
    Moderator
  • Thank you very much. I actually tried to post one of those links, but could not insert it because of forum restrictions. The main bummer for me was that appid, because the article does not say how to find it. As you rightly pointed out ProjectGuid seems to be the right one. I'll see if I can work from here.
    Thursday, April 4, 2019 12:08 PM
  • Hi Aleksey Malyshev,

    Have you found the APPID and solved the problem? I would like that you could post the answer to the thread instead of it turned out to be a meaningless discussion, so it can help others whoever encounter a similar question.

    Best Regards

    Abraham

    Monday, April 15, 2019 1:38 AM
    Moderator