0% found this document useful (0 votes)
64 views11 pages

WCF and WS-Security Updated

This document discusses securing communications between a Windows Communication Foundation (WCF) service and clients using WS-Security. It describes creating a simple WCF service, hosting it, and generating a client proxy to call the service. It then adds WS-Security by configuring the service and client to use username and password authentication over encrypted messages.

Uploaded by

Andres Triana
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
64 views11 pages

WCF and WS-Security Updated

This document discusses securing communications between a Windows Communication Foundation (WCF) service and clients using WS-Security. It describes creating a simple WCF service, hosting it, and generating a client proxy to call the service. It then adds WS-Security by configuring the service and client to use username and password authentication over encrypted messages.

Uploaded by

Andres Triana
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 11

WS-Security with Windows Communication Foundation

Author
Chris Seary is a security specialist and MVP at IT and management consultancy,
Charteris plc. He has worked with many different Microsoft technologies, and for the last
few years has specialised in the security aspects of enterprise-level .NET systems.
Technology
.Net Framework 3.0
Visual Studio 2.0
Summary
Windows Communication Foundation is the new Microsoft technology for
communicating between distributed services. This article will focus on communication
protected by WS-Security.
Introduction - What is WS-Security?
Microsoft, IBM and a number of other vendors and organisations have created standards
for protection of communications at the message level. These standards cover many
aspects of security, including digital signatures, authentication and encryption of SOAP
messages. The generic name for the standards is WS-*, and includes WS-Security, WSTrust and WS-SecureConversation.
Windows Communication Foundation
There are three aspects of a service created with the Windows Communication
Foundation - Address, Binding and Contract. Address is the URI of the service, Binding
is the method of communication, and contract is the definition of the service methods.
Creating the service
The physical implementation of a contract is an interface. Heres the interface for our
service, called IMyService:
[ServiceContract]
public interface IMyService
{
[OperationContract]
string GetData(string val);
}

The interface has one method, which is GetData (string val). The ServiceContract
attribute is added to the interface definition, and the OperationContract attribute is added
to the method.
Our service will implement this interface:
namespace MyServiceHost
{
[ServiceContract]
public interface IMyService
{
[OperationContract]
string GetData(string val);
}
public class MyService : IMyService
{
string IMyService.GetData(string val)
{
string s = System.ServiceModel.ServiceSecurityContext
.Current.PrimaryIdentity.Name;
return "You sent the text:" + val +
Environment.NewLine + s;
}
}
}
This is a very simple service, which simply returns the parameter passed and the identity
of the user who is authenticated with the credentials supplied.
This service is hosted in a Windows Forms application. A reference to
System.ServiceModel is required.
The Load event instantiates the service:
private void ServiceForm_Load(object sender, EventArgs e)
{
try
{
sh = new System.ServiceModel.ServiceHost(typeof(MyService));
sh.Open();
}

catch (Exception ex)


{
MessageBox.Show(ex.ToString());
}
}
Next we must publish the web service, so that clients can call it. The application
configuration file for the Windows application needs a section added for ServiceModel
related configuration:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name ="MyServiceHost.MyService"
behaviorConfiguration="metadataSupport">
<endpoint
address ="http://localhost:9091/DataService"
binding ="wsHttpBinding"
contract="MyServiceHost.IMyService"
/>
<endpoint
address="http://localhost:9091/DataService/mex"
binding="mexHttpBinding"
contract="IMetadataExchange"
/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="metadataSupport" >
<serviceMetadata/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
The <service> element applies to the class specified in the name attribute, which is
loaded in the Load event in the preceding example. Endpoints are added using the
<endpoint> element, with the address for the service configured using the address
attribute. Here, the address is shown as Http://localhost:9091/DataService. This is the uri
that must be used when calling the service. The binding is the way that communication
will take place in this case the wsHttpBinding, which allows us to use WS-Security.
The contract attribute refers to the interface we defined earlier.

The second endpoint, http://localhost:9091/DataService/mex, has a different binding type,


mexHttpBinding. This endpoint is configured to publish metadata so a client can generate
a proxy for calling the service. The behavior metadataSupport specifies that the
endpoint supplies service metadata.

Creating the client


The WSE plugin for Visual Studio generates a proxy for using WSE web services. How
do we create this proxy when using Windows Communication Foundation?
We need to use the svcutil.exe application to create our WCF proxy. Its called from the
Windows SDK Command Prompt:
Svcutil.exe "http://localhost:9091/DataService/mex" /out:c:\Docs\MyService.cs
This call creates a proxy class that exposes all of the necessary methods for calling the
web service using WS-Security. Simply add the class to the client application project.
Remember adding the http://localhost:9091/DataService/mex endpoint to publish the
metadata? This was why you did it it allows svcutil.exe to discover the information
needed to create the proxy.
The class we just created was added to a Windows Forms application. The application has
a text box to show the result of the service call. Here is the button click event that calls
the service.
private void btnGetData_Click(object sender, EventArgs e)
{
try
{
MyServiceClient msc = new MyServiceClient();
string s = msc.GetData("stuff");
txtRes.Text = s;
}
catch (Exception ex)
{
txtRes.Text = ex.ToString();
}

All thats needed is some configuration for the clients App.Config.


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint
address ="http://localhost:9091/DataService"
binding ="wsHttpBinding"
contract="IMyService"
/>
</client>
</system.serviceModel>
</configuration>
Thats it when clicking the button on the Windows application, we call the service!
Adding username and password to the web service call
Now were going to add a username and password token to the SOAP message, and have
Windows authenticate it. Firstly, well alter the config file for the application hosting the
WCF web service.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name ="MyServiceHost.MyService"
behaviorConfiguration="serviceBehave">
<endpoint
address ="http://localhost:9091/DataService"
binding ="wsHttpBinding"
contract="MyServiceHost.IMyService"
bindingConfiguration ="serviceConfig"
/>
</service>

</services>
<bindings>
<wsHttpBinding>
<binding name="serviceConfig">
<security mode = "Message" >
<message
clientCredentialType="UserName"
negotiateServiceCredential ="False"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehave" >
<serviceCredentials>
<serviceCertificate
x509FindType="FindBySubjectName"
storeLocation="LocalMachine"
storeName="My"
findValue="localhost" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Weve got rid of the metadata endpoint here, as the proxy has already been generated.
First, lets look at the endpoint element:
<endpoint
address ="http://localhost:9091/DataService"
binding ="wsHttpBinding"
contract="MyServiceHost.IMyService"
bindingConfiguration ="serviceConfig"
/>
This endpoint has a bindingConfiguration attribute called serviceConfig. Lets look at
this configuration:
<bindings>
<wsHttpBinding>
<binding name="serviceConfig">
<security mode = "Message" >
<message

clientCredentialType="UserName"
negotiateServiceCredential ="False"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
Here, we can see that the security mode is set to Message. This means that security is
being applied to the SOAP. Username and password is added to the XML passed to the
web service, rather than via the HTTP variables.
In the <message> element, the clientCredentialType is set to UserName, which means
that the username and password are passed in the SOAP the alternative could be
Windows, X509 certificate, None or a custom issued token. The
negotiateServiceCredential is set to false, as were not obtaining a credential through
negotiation (as we would if we were using WS-SecureConversation).
Now, its not advisable to pass a username and password in the clear, as this could be
picked up by a network monitoring tool such as Ethereal. Dont forget, were not relying
on network security here (such as HTTPS or IPSec). Its necessary to encrypt the
credentials, and for this a certificate is used. Here is the configuration information that is
referred to in the <service> element:
<behavior name="serviceBehave" >
<serviceCredentials>
<serviceCertificate
x509FindType="FindBySubjectName"
storeLocation="LocalMachine"
storeName="My"
findValue="localhost" />
</serviceCredentials>
</behavior>
This specifies that a certificate from the local machine store with the subject name
localhost is to be used. The public key from the certificate will be used to encrypt, and
only the owner of the private key will be able to read the username and password.
Now we need to configure the client to speak to this newly secured service.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint
address ="http://localhost:9091/DataService"
binding ="wsHttpBinding"
contract="IMyService"

bindingConfiguration ="clientConfig"
/>
</client>
<bindings>
<wsHttpBinding>
<binding name="clientConfig">
<security mode="Message">
<message
clientCredentialType="UserName"
negotiateServiceCredential="False"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
All that weve added is a bindingConfiguration that specifies the security mode and what
sort of credentials are passed. In the client code, we can specify the certificate and
credentials passed. Heres the code from the button click event that calls the service:
private void btnGetData_Click(object sender, EventArgs e)
{
try
{
MyServiceClient msc = new MyServiceClient();
msc.ClientCredentials.UserName.UserName = @"wseuser";
msc.ClientCredentials.UserName.Password = "Spotlight1";
msc.ClientCredentials.ServiceCertificate.SetDefaultCertificate(
System.Security.Cryptography.X509Certificates
.StoreLocation.CurrentUser,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType
.FindBySubjectName,
"localhost");
string s = msc.GetData("stuff");
txtRes.Text = s;
}
catch (Exception ex)
{
txtRes.Text = ex.ToString();

}
}
First, the client credentials are set:
msc.ClientCredentials.UserName.UserName = @"wseuser";
msc.ClientCredentials.UserName.Password = "Spotlight1";

Then the certificate is chosen from the Current User store by calling the
SetDefaultCertificate method of the proxy:
msc.ClientCredentials.ServiceCertificate.SetDefaultCertificate(
System.Security.Cryptography.X509Certificates
.StoreLocation.CurrentUser,
System.Security.Cryptography.X509Certificates.StoreName.My,
System.Security.Cryptography.X509Certificates.X509FindType
.FindBySubjectName,
"localhost");
The public key from the certificate is used by the client to encrypt the credentials. The
credentials are authenticated by Windows when they reach the service.
Its possible to use other methods of verifying these credentials for instance, a custom
uername token manager can be written which plugs into ASP.Net Membership
functionality. This is one of the ways where WS-Security is really useful youre not
restricted to using Windows LDAP directories for storing security principals.
Logging Messages
To log the messages produced by the WCF service, we add a system.diagnostics section
to the App.Config:
<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging" >
<listeners>
<add name="messages"
type ="System.Diagnostics.XmlWriterTraceListener"
initializeData="C:\WCFTest\ServiceMessages.xml" />
</listeners>
</source>
</sources>

</system.diagnostics>
.
.
</configuration>
This sets up a listener to write out the log entries that are generated. At the end of the
config file, we configure the listener:
<configuration>
.
.
<diagnostics>
<messageLogging
logEntireMessage="true"
logMalformedMessages="false"
logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="false"
maxMessagesToLog="3000"
maxSizeOfMessageToLog="4000" />
</diagnostics>
</system.serviceModel>
</configuration>
The service is now logging the entire message at the service level.
How do we examine the log file? The Windows SDK provides a tool called the Service
Trace Viewer, which can be used to examine the log. This tool allows a user to view and
filter log entries.

10

Summary
Windows Communication Foundation provides a solid, configurable framework for
creating distributed services. WS-Security is a rapidly evolving security interface which
allows a common mechanism for securing communications.
The wsHttpBinding allows integration of WS-Security within WCF, giving a security
model which is both platform independent and extensible.

11

You might also like