Metadata for a service can contain sensitive information about your application that a malicious user can leverage. Consumers of your service may also require a secure mechanism for obtaining metadata about your service. Therefore, it is sometimes necessary to publish your metadata using a secure endpoint.
Metadata endpoints are generally secured using the standard security mechanisms defined in Windows Communication Foundation (WCF) for securing application endpoints. For more information, see Security Overview.
This topic walks through the steps to create an endpoint secured by a Secure Sockets Layer (SSL) certificate or, in other words, an HTTPS endpoint.
Configure a port with an appropriate X.509 certificate. The certificate must come from a trusted authority, and it must have an intended use of "Service Authorization." You must use the HttpCfg.exe tool to attach the certificate to the port. See How to: Configure a Port with an SSL Certificate.
Important
The subject of the certificate or its Domain Name System (DNS) must match the name of the computer. This is essential because one of the first steps the HTTPS mechanism performs is to check that the certificate is issued to the same Uniform Resource Identifier (URI) as the address upon which it is invoked.
Create a new instance of the ServiceMetadataBehavior class.
Set the HttpsGetEnabled property of the ServiceMetadataBehavior class to true
.
Set the HttpsGetUrl property to an appropriate URL. Note that if you specify an absolute address, the URL must begin with the scheme https://
. If you specify a relative address, you must supply an HTTPS base address for your service host. If this property is not set, the default address is "", or directly at the HTTPS base address for the service.
Add the instance to the behaviors collection that the Behaviors property of the ServiceDescription class returns, as shown in the following code.
ServiceMetadataBehavior sb = new ServiceMetadataBehavior();
sb.HttpsGetEnabled = true;
sb.HttpsGetUrl = new Uri("https://myMachineName:8036/myEndpoint");
myServiceHost.Description.Behaviors.Add(sb);
myServiceHost.Open();
' Create a new metadata behavior object and set its properties to
' create a secure endpoint.
Dim sb As New ServiceMetadataBehavior()
With sb
.HttpsGetEnabled = True
.HttpsGetUrl = New Uri("https://myMachineName:8036/myEndpoint")
End With
With myServiceHost
.Description.Behaviors.Add(sb)
.Open()
End With
Add a <behaviors> element to the <system.serviceModel> element of the configuration file for your service.
Add a <serviceBehaviors> element to the <behaviors> element.
Add a <behavior> element to the <serviceBehaviors>
element.
Set the name
attribute of the <behavior>
element to an appropriate value. The name
attribute is required. The example below uses the value mySvcBehavior
.
Add a <serviceMetadata> to the <behavior>
element.
Set the httpsGetEnabled
attribute of the <serviceMetadata>
element to true
.
Set the httpsGetUrl
attribute of the <serviceMetadata>
element to an appropriate value. Note that if you specify an absolute address, the URL must begin with the scheme https://
. If you specify a relative address, you must supply an HTTPS base address for your service host. If this property is not set, the default address is "", or directly at the HTTPS base address for the service.
To use the behavior with a service, set the behaviorConfiguration
attribute of the <service> element to the value of the name attribute of the behavior element. The following configuration code shows a complete example.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="mySvcBehavior">
<serviceMetadata httpsGetEnabled="true"
httpsGetUrl="https://localhost:8036/calcMetadata" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="mySvcBehavior"
name="Microsoft.Security.Samples.Calculator">
<endpoint address="http://localhost:8037/ServiceModelSamples/calculator"
binding="wsHttpBinding" bindingConfiguration=""
contract="Microsoft.Security.Samples.ICalculator" />
</service>
</services>
</system.serviceModel>
</configuration>
The following example creates an instance of a ServiceHost class and adds an endpoint. The code then creates an instance of the ServiceMetadataBehavior class and sets the properties to create a secure metadata exchange point.
WSHttpBinding myBinding = new WSHttpBinding();
myBinding.Security.Mode = SecurityMode.Message;
myBinding.Security.Message.ClientCredentialType =
MessageCredentialType.Windows;
Type contractType = typeof(ICalculator);
Type serviceType = typeof(Calculator);
Uri baseAddress = new
Uri("http://localhost:8037/serviceModelSamples/");
ServiceHost myServiceHost =
new ServiceHost(serviceType, baseAddress);
myServiceHost.AddServiceEndpoint
(contractType, myBinding, "secureCalculator");
ServiceMetadataBehavior sb = new ServiceMetadataBehavior();
sb.HttpsGetEnabled = true;
sb.HttpsGetUrl = new Uri("https://myMachineName:8036/myEndpoint");
myServiceHost.Description.Behaviors.Add(sb);
myServiceHost.Open();
string machineName = System.Net.Dns.GetHostEntry("").HostName ;
Console.WriteLine($"Listening @ {machineName}:8037/serviceModelSamples/");
Console.WriteLine("Press Enter to close the service");
Console.ReadLine();
myServiceHost.Close();
Dim myBinding As New WSHttpBinding()
With myBinding.Security
.Mode = SecurityMode.Message
.Message.ClientCredentialType = MessageCredentialType.Windows
End With
' Create the Type instances for later use and the URI for
' the base address.
Dim contractType = GetType(ICalculator)
Dim serviceType = GetType(Calculator)
Dim baseAddress As New Uri("http://localhost:8037/serviceModelSamples/")
' Create the ServiceHost and add an endpoint.
Dim myServiceHost As New ServiceHost(serviceType, baseAddress)
myServiceHost.AddServiceEndpoint(contractType, myBinding, "secureCalculator")
' Create a new metadata behavior object and set its properties to
' create a secure endpoint.
Dim sb As New ServiceMetadataBehavior()
With sb
.HttpsGetEnabled = True
.HttpsGetUrl = New Uri("https://myMachineName:8036/myEndpoint")
End With
With myServiceHost
.Description.Behaviors.Add(sb)
.Open()
End With
' Use the GetHostEntry method to return the actual machine name.
Dim machineName = System.Net.Dns.GetHostEntry("").HostName
Console.WriteLine("Listening @ {0}:8037/serviceModelSamples/", machineName)
Console.WriteLine("Press Enter to close the service")
Console.ReadLine()
myServiceHost.Close()
The code example uses the following namespaces: