How to: Secure Metadata Endpoints
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.
To create a secure HTTPS GET metadata endpoint in code
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.
// Create a new metadata behavior object and set its properties to // create a secure endpoint. 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
To create a secure HTTPS GET metadata endpoint in configuration
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. Thename
attribute is required. The example below uses the valuemySvcBehavior
.Add a <serviceMetadata> to the
<behavior>
element.Set the
httpsGetEnabled
attribute of the<serviceMetadata>
element totrue
.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 schemehttps://
. 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>
Example
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;
// Create the Type instances for later use and the URI for
// the base address.
Type contractType = typeof(ICalculator);
Type serviceType = typeof(Calculator);
Uri baseAddress = new
Uri("http://localhost:8037/serviceModelSamples/");
// Create the ServiceHost and add an endpoint.
ServiceHost myServiceHost =
new ServiceHost(serviceType, baseAddress);
myServiceHost.AddServiceEndpoint
(contractType, myBinding, "secureCalculator");
// Create a new metadata behavior object and set its properties to
// create a secure endpoint.
ServiceMetadataBehavior sb = new ServiceMetadataBehavior();
sb.HttpsGetEnabled = true;
sb.HttpsGetUrl = new Uri("https://myMachineName:8036/myEndpoint");
myServiceHost.Description.Behaviors.Add(sb);
myServiceHost.Open();
// Use the GetHostEntry method to return the actual machine name.
string 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();
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()
Compiling the Code
The code example uses the following namespaces: