How to: Secure a Service with an X.509 Certificate
Securing a service with an X.509 certificate is a basic technique that most bindings in Windows Communication Foundation (WCF) use. This topic walks through the steps of configuring a self-hosted service with an X.509 certificate.
A prerequisite is a valid certificate that can be used to authenticate the server. The certificate must be issued to the server by a trusted certificate authority. If the certificate is not valid, any client trying to use the service will not trust the service, and consequently no connection will be made. For more information about using certificates, see Working with Certificates.
To configure a service with a certificate using code
Create the service contract and the implemented service. For more information, see Designing and Implementing Services.
Create an instance of the WSHttpBinding class and set its security mode to Message, as shown in the following code.
// Create a binding and set the security mode to Message. WSHttpBinding b = new WSHttpBinding(SecurityMode.Message);
' Create a binding and set the security mode to Message. Dim b As New WSHttpBinding(SecurityMode.Message)
Create two Type variables, one each for the contract type and the implemented contract, as shown in the following code.
Type contractType = typeof(ICalculator); Type implementedContract = typeof(Calculator);
Dim contractType = GetType(ICalculator) Dim implementedContract = GetType(Calculator)
Create an instance of the Uri class for the base address of the service. Because the
WSHttpBinding
uses the HTTP transport, the Uniform Resource Identifier (URI) must begin with that schema, or Windows Communication Foundation (WCF) will throw an exception when the service is opened.Uri baseAddress = new Uri("http://localhost:8044/base");
Dim baseAddress As New Uri("http://localhost:8044/base")
Create a new instance of the ServiceHost class with the implemented contract type variable and the URI.
ServiceHost sh = new ServiceHost(implementedContract, baseAddress);
Dim sh As New ServiceHost(implementedContract, baseAddress)
Add a ServiceEndpoint to the service using the AddServiceEndpoint method. Pass the contract, binding, and an endpoint address to the constructor, as shown in the following code.
sh.AddServiceEndpoint(contractType, b, "Calculator");
sh.AddServiceEndpoint(contractType, b, "Calculator")
Optional. To retrieve metadata from the service, create a new ServiceMetadataBehavior object and set the HttpGetEnabled property to
true
.ServiceMetadataBehavior sm = new ServiceMetadataBehavior(); sm.HttpGetEnabled = true; sh.Description.Behaviors.Add(sm);
Dim sm As New ServiceMetadataBehavior() sm.HttpGetEnabled = True With sh .Description.Behaviors.Add(sm)
Use the SetCertificate method of the X509CertificateRecipientServiceCredential class to add the valid certificate to the service. The method can use one of several methods to find a certificate. This example uses the FindBySubjectName enumeration. The enumeration specifies that the supplied value is the name of the entity that the certificate was issued to.
sh.Credentials.ServiceCertificate.SetCertificate( StoreLocation.LocalMachine ,StoreName.My, X509FindType.FindBySubjectName ,"localhost");
.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, _ StoreName.My, _ X509FindType.FindBySubjectName, _ "localhost")
Call the Open method to start the service listening. If you are creating a console application, call the ReadLine method to keep the service in the listening state.
sh.Open(); Console.WriteLine("Listening"); Console.ReadLine();
.Open() Console.WriteLine("Listening") Console.ReadLine()
Example
The following example uses the SetCertificate method to configure a service with an X.509 certificate.
// Create a binding and set the security mode to Message.
WSHttpBinding b = new WSHttpBinding(SecurityMode.Message);
Type contractType = typeof(ICalculator);
Type implementedContract = typeof(Calculator);
Uri baseAddress = new Uri("http://localhost:8044/base");
ServiceHost sh = new ServiceHost(implementedContract, baseAddress);
sh.AddServiceEndpoint(contractType, b, "Calculator");
ServiceMetadataBehavior sm = new ServiceMetadataBehavior();
sm.HttpGetEnabled = true;
sh.Description.Behaviors.Add(sm);
sh.Credentials.ServiceCertificate.SetCertificate(
StoreLocation.LocalMachine ,StoreName.My,
X509FindType.FindBySubjectName ,"localhost");
sh.Open();
Console.WriteLine("Listening");
Console.ReadLine();
sh.Close();
' Create a binding and set the security mode to Message.
Dim b As New WSHttpBinding(SecurityMode.Message)
Dim contractType = GetType(ICalculator)
Dim implementedContract = GetType(Calculator)
Dim baseAddress As New Uri("http://localhost:8044/base")
Dim sh As New ServiceHost(implementedContract, baseAddress)
sh.AddServiceEndpoint(contractType, b, "Calculator")
Dim sm As New ServiceMetadataBehavior()
sm.HttpGetEnabled = True
With sh
.Description.Behaviors.Add(sm)
.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, _
StoreName.My, _
X509FindType.FindBySubjectName, _
"localhost")
.Open()
Console.WriteLine("Listening")
Console.ReadLine()
.Close()
End With
Compiling the Code
The following namespaces are required to compile the code: