Archive
Retrieving the client certificate from an X509Identity in WCF
Please note: This article is merely a demonstration, I absolutely do not recommend relying on internal classes of the .Net framework in real applications.
WCF can be configured for two mayor modes of security:
- Transport security
- Message security
- (And you actually also have the in between TransportWithMessageCredential, but lets forget this for simplicity …)
In both of these modes WCF can be configured to use X509 certificates as client and service credentials. At the service side, WCF maps these credentials to an IIdentity instance that can be retrieved using the ServiceSecurityContext.
IIdentity identity = ServiceSecurityContext.Current.PrimaryIdentity;
The implementation type of this identity is the internal class System.IdentityModel.Claims.X509Identity. If we look at this type using reflector we can see the following:
The X509Identity contains the X509 client certificate inside a private variable “certificate”. Using reflection, we can easily retrieve this certificate:
private X509Certificate2 ClientCertificate
{
get
{
try
{
IIdentity identity = ServiceSecurityContext.Current.PrimaryIdentity;
// X509Identity is an internal class, so we cannot directly access it
Type x509IdentityType = identity.GetType();
// The certificate is stored inside a private field of this class
FieldInfo certificateField = x509IdentityType.GetField("certificate", BindingFlags.Instance | BindingFlags.NonPublic);
return (X509Certificate2)certificateField.GetValue(identity);
}
catch (Exception)
{
return null;
}
}
}
Using this property we can now retrieve the client certificate. This was not that difficult to do? ![]()
A few tips when you want to develop a WCF service with streamed transfer mode
This weekend I tried to develop a WCF service that uses the streamed transfer mode. Configuring this is very easy; you only have the change the “transferMode” property of the binding to Streamed (or StreamedResponse or StreamedRequest)
<system.serviceModel>
<services>
<service name="StreamingService.Upload">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="streamingBinding"
contract="StreamingService.IUpload"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="streamingBinding"
transferMode="Streamed"/>
</basicHttpBinding>
</bindings>
</system.serviceModel>
Simple and straightforward, but while doing this I discovered a few attention points:
- If want to use a http binding, you can only use the basicHttpBinding as the wsHttpBinding does not support the “transferMode” property.
- If you want to test this. You cannot run this using the integrated web server of Visual Studio 2010. I continuously received bad request error messages “ProtocolException: The remote server returned an unexpected response: (400) Bad Request.”. It was only after I switched to IIS that my service worked.
- The “transferMode” property is not part of the metadata for http bindings, so in case you do “Add Service Reference” in Visual Studio, you have to manually edit the app.config of web.config of your client application.
Not a big blog article this time, but I hope that you find it helpful.
Using the WCF service moniker with the WSDL of a service
Introduction
In a previous article I wrote about the WCF service moniker. This COM component allows legacy applications to communicate with their new .Net based siblings. In the previous article, I explained two of the three ways to use the WCF service moniker. In this article, I will explain you the third way: using a locally cached WSDL description of the web service. Using the locally cached WSDL has advantages; you don’t need to create a class library for your WCF service and it does not need to expose meta data. Not exposing meta data is in enterprise environments often required to increase the security of the service.
The demo WCF service
First we are going to create the same simple demo service as in my previous WCF moniker article. So start Visual Studio and create a new “WCF Service Application”.
Inside the project we create the following service contract:
[ServiceContract]
public interface IHelloName
{
[OperationContract]
string Hello(string name);
}
We implement the service as follows:
public class HelloName : IHelloName
{
public string Hello(string name)
{
return "Hello " + name;
}
}
The configuration for our service is the following (enter this in your web.config):
<system.serviceModel>
<services>
<service behaviorConfiguration="serviceBehavior"
name="HelloNameService.HelloName">
<endpoint binding="basicHttpBinding"
contract="HelloNameService.IHelloName" />
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
We are now done with our WCF service, so you can press F5 to start the WCF service.
Retrieving the WSDL
Before using the WCF service moniker, lets first look at the WSDL exposed by the WCF service. In order to do this, open your browser and enter the url “http://localhost:49170/HelloName.svc?wsdl”.
Please note that this URL will be probably be different on your system.
The first thing to notice is that the WSDL document is importing other documents. Because we want to call our web service by using a single file saved on disk, this behavior is not feasible. Luckily we were not the first .Net developers that wanted to have a “flat” WSDL. Other programming languages with less advanced web service stacks were having problems with this aspect of the WSDL generated by WCF, so Tomas Restrepo and Cristian Weyers came up with an alternative ServiceHostFactory that modifies the WCF stack to expose a flat WSDL. You can find this extension called “Flat WSDL” at
http://www.thinktecture.com/media/9297/flatwsdl.zip
Download it and add the class library “Thinktecture.ServiceModel.Extensions.Description.dll” as a reference to our WCF service project. We can now modify the svc file of our service to change the ServiceHostFactory that IIS or WAS will be using. To do this provide the value “Thinktecture.ServiceModel.Extensions.Description.FlatWsdlServiceHostFactory” for the “Factory” property.
If you now relaunch the WCF service and open the WSDL again, you will see that is has been “flattened”; it does not import any documents anymore. Save the WSDL to a file on your hard disk (I chose the path “c:\temp\IHelloName.wsdl”).
Creating the client application
For this demo, we are going to create a client application in VBA and Excel, but you can use the WCF service moniker from within every programming technology that supports COM.
Enter the following code in the VBA editor of Excel:
Sub ServiceMonikerCallWSDL()
Dim service As Object
Dim monString As String
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("c:\temp\IHelloName.wsdl", ForReading, False, TristateTrue)
wsdlContract = objFile.ReadAll
objFile.Close
On Error GoTo Exception:
monString = "service4:address='http://localhost:49170/HelloName.svc'" & _
", wsdl='" & wsdlContract & "'" & _
", binding=BasicHttpBinding_IHelloName, bindingNamespace=http://tempuri.org/" & _
", contract=IHelloName, contractNamespace=http://tempuri.org/"
Set service = GetObject(monString)
MsgBox (service.Hello("Excel WSDL"))
Exit Sub
Exception:
MsgBox Err.Description
End Sub
Remark: don’t forget to change the address of the service and the path of the WSDL file to the correct ones for your computer.
Before executing this code, we will first disable the publishing of metadata to prove that we can call the WCF service without using its exposed meta data. We can also remove the custom ServiceHostFactory in the svc file.
If we now restart the WCF service and execute the VBA code in Excel we get the following response:
Conclusion
As shown in this article, the WCF service moniker can relatively simple be used in combination with the WSDL of the service. This has the advantage that we can disable meta data publishing for services running in production and still be able to call it with the WCF service moniker. If you want to use this mode, don’t forget to ‘flatten’ the WSDL.
Extension method fun 2
Sometimes it is required to shuffle the elements of a collection. I have seen little algorithm monsters that did this, yet it can be done in c# and .Net in a very clean way using a Linq query. The key to understand my Linq query, is knowing that the orderby expression does not necessarily has to order the elements of your query.
public static class EnumerableExtensions
{
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> enumerable)
{
return from i in enumerable
orderby Guid.NewGuid()
select i;
}
}
A small test application:
static void Main(string[] args)
{
List<string> inputData = new List<string>() { "pieter", "bill", "steve" };
IEnumerable<string> shuffledData = inputData.Shuffle();
foreach (string item in shuffledData)
Console.WriteLine(item);
}
