Three Is It

Because two isn't enough and four is just too many

Evil men, obsessed with ambition and unburdened by conscience, must be taken very seriously--and we must stop them before their crimes can multiply.
George W. Bush, Nov. 2005
Home Blogs Genealogy Brad's Bookshelf Subscriptions Contact Sign in
 

About the author

Brad Butts is a .NET developer and architect. He is married with children and enjoys reading, working out, and genealogy is his five minutes of spare time.
E-mail me Send mail
National Debt Clock

Recent comments

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

WCF, Interop, and the elusive BinarySecurityToken

If you plan to write WCF services that will be consumed by clients of technologies other than .NET--and would like to include some level of security, like message signing (via X.509 certificates)--chances are you'll have to find some way to emit a BinarySecurityToken value in your responses.

When I first configured the security of my service, I went with a custom binding and a configuration like this:

<binding name="CustomBindingForX509">
<textMessageEncoding messageVersion="Soap11" />
<security allowSerializedSigningTokenOnReply="true" authenticationMode="MutualCertificate"
requireDerivedKeys="false" securityHeaderLayout="Lax" messageProtectionOrder="EncryptBeforeSign"
messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<localClientSettings detectReplays="false" />
<localServiceSettings detectReplays="false" />
<secureConversationBootstrap />
</security>
<httpTransport />
</binding>


This seemed to make sense (as far as WCF configuration can make sense, anyway): I was sharing certificates with my client (a Java Axis2 client), hence the MutualCertificate setting seemed appropriate.  I was also going for the lowest common denominator SOAP settings (as most folks in the interop space seem to recommend), so I went with those recommended SOAP settings.  This configuration had the effect of rendering my response to look as such (I only show the SOAP header section since it is what's relevant here):

<s:Header>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="uuid-5965cceb-61d9-4d3f-a503-c3f4dc7fe08a-3">
<u:Created>2008-07-17T20:33:42.153Z</u:Created>
<u:Expires>2008-07-17T20:38:42.153Z</u:Expires>
</u:Timestamp>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
<Reference URI="#_1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
<DigestValue>3dcC17frvtyzp8G+kR5otzreQf0=</DigestValue>
</Reference>
<Reference URI="#uuid-5965cceb-61d9-4d3f-a503-c3f4dc7fe08a-3">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
<DigestValue>h/DtKybbi4Q3RRtYKm26SGM2mcM=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>IRlfHoVu/JispcD5CdMCKnbHNZcSVVNNLBtXbnP3fcid+nPi1F4WNGVsHjkF6PnaIzKM/5j2Vhnxbkm1tTwFjeKelQipCHErrwXsxOKMaVKlP/2gjeiJ0K2kkEO7LIUIcmqQ9MNx/AfGr9zE4c6EPGrkbPJVYLvra5jUhypMAcM=</SignatureValue>
<KeyInfo>
<o:SecurityTokenReference>
<X509Data>
<X509IssuerSerial>
<X509IssuerName>CN=Sample Service, OU=Rampart, O=Apache, L=Colombo, S=Western, C=LK</X509IssuerName>
<X509SerialNumber>1187603713</X509SerialNumber>
</X509IssuerSerial>
</X509Data>
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
</o:Security>
</s:Header>


The problem is, my client didn't like these settings and kept throwing the error "The signature verification failed".  I suspect the client didn't like this response because the MutualCertificate setting seems to want the client to look up the certificate via distinguished name or serial number to verify that the message was signed appropriately.  Java clients, and apparently a few other technologies, don't seem to work that way.

So, what to do?  Well, eventually I found this post describing a similar problem between a WCF service and an SAP NetWeaver client.  Part III of the post describes what they did to resolve the signature verification problem: namely, get the WCF service to inject a BinarySecurityToken instead of the SecurityTokenReference (with issuer name and serial number).

I'm not totally fond of their implementation--they did the old school write-a-console-app-to-host-my-WCF-service approach--but this gave me an important clue to how to inject the BinarySecurityToken: use the AsymmetricSecurityBindingElement class!  Wow, why didn't I think of that?  That's fairly...uh...obvious.

Ok, so how do I use this AsymmetricSecurityBindingElement class?  I know I don't want to write a console app just to plug in this functionality--that's what IIS is for.  Guess I'll have to go to a custom BindingElement extension (see the attachment for the code and thanks to Scott, the Microsoft tech who wrote it--and helped me with this problem):

(excerpt from the client and service configurations)
<extensions>
<bindingElementExtensions>
<add name="MySecurityBindingElement" type="MySecurityBE.AsymetricSecurityBEExtentionElement, MySecurityBE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bindingElementExtensions>
</extensions>
<bindings>
<customBinding>
<binding name="MyCoolBinding">
<MySecurityBindingElement/>
<textMessageEncoding messageVersion="Soap11"/>
<httpTransport/>
</binding>
</customBinding>
</bindings>



But wait, there's more!  It turns out that you don't even need to write your own custom BindingElement.  It turns out that the authentication mode MutualCertificateDuplex makes use of the AsymmetricSecurityBindingElement class.  What?  Didn't you know that?  So, all you really have to do is expose an endpoint with this kind of binding and you're set.  So, this service configuration:

<binding name="CustomBindingForX509">
<security authenticationMode="MutualCertificateDuplex"
requireDerivedKeys="false"  messageProtectionOrder="EncryptBeforeSign"
messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"/>
<textMessageEncoding messageVersion="Soap11" />
<httpTransport  />
</binding>


Will render this response (again, I'm just including the header for brevity):

<s:Header>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="uuid-39531f92-c0d4-4129-b491-6222c06d3bf5-1">
<u:Created>2008-07-25T16:03:59.959Z</u:Created>
<u:Expires>2008-07-25T16:08:59.959Z</u:Expires>
</u:Timestamp>
<o:BinarySecurityToken>
<!-- Removed-->
</o:BinarySecurityToken>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
<Reference URI="#_1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
<DigestValue>2x4uPP0r/Zo7auuboFg+8h0k3Yo=</DigestValue>
</Reference>
<Reference URI="#uuid-39531f92-c0d4-4129-b491-6222c06d3bf5-1">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
<DigestValue>Z161SvyizqMC3alennK2c6FLiZg=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>EDpLDry/QuwxVuXe+/0LZrmrLkTcoZ1Ls45qvu+RebTRFfkq8HksKMN3Ip4T2begyDCLfGOTpEHfX/ohyMS7HIsxluyIwJ971kyLVt6nUZPfjqQ3iD3hCI2cCSRtNbC1p+aZDr3Tn/KbLxjWQ4aFfm7lRKbLGeVDEY5BJYyVCqY=</SignatureValue>
<KeyInfo>
<o:SecurityTokenReference>
<o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-f32fc9b9-695e-4542-98bb-acf40424321b-2"></o:Reference>
</o:SecurityTokenReference>
</KeyInfo>
</Signature>
</o:Security>
</s:Header>


Note that the response now includes the BinarySecurityToken and, ironically, has removed the x509 name and serial number data.  Don't worry about that "removed" comment, the binary token was sent to my client, it's just that WCF automatically removes privacy information from its logs--and I'm pulling this data from the log files.  For more info on privacy removal, see here.

Now, my non-.NET clients are happy, but I've just hosed my .NET clients.  From what I'm told, duplex mode is no walk in the park for .NET clients.  So, what to do?  Well, I'll tell you what I plan to do: just expose another endpoint.  If you're a .NET client, you'll get a traditional MutualCertificate binding endpoint.  If you're not a .NET client, you'll get the duplex endpoint.  The custom extension is nice, but not absolutely necessary at this point.

AsymExample.zip (899.63 kb)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: Technology Blog
Posted by Brad on Thursday, September 18, 2008 10:33 PM
Permalink | Comments (1) | Post RSSRSS comment feed

WCF Service Trace Viewer

Service tracing in WCF reminds me of the continuum transfunctioner--its a very mysterious and powerful device and it's mystery is exceeded only by it's power.

I had some WCF problems recently and ended up having to open up a ticket with Microsoft to resolve.  The first thing the tech did was send me an email with the following configuration:

    <system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Warning, ActivityTracing" >
<listeners>
<add name="xml" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging" switchValue="Warning">
<listeners>
<add name="xml" />
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml" type="System.Diagnostics.XmlWriterTraceListener" initializeData="Server.svclog" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>

and...

    <diagnostics>
<messageLogging maxMessagesToLog="30000"
logEntireMessage="true"
logMessagesAtServiceLevel="false"
logMalformedMessages="true"
logMessagesAtTransportLevel="true">
<filters>
<clear/>
</filters>
</messageLogging>
</diagnostics>

The first thing to note is, "wait a minute: there's two sets of configuration just to get trace logging going?" Why, yes, Timmy, that's right! The node system.diagnostics lives directly under the configuration document element while the node diagnostics lives under system.serviceModel. The second thing to note is, "hey, this looks like a much simpler diagnostics configuration than I'm used to!" Prior to my exchange with this Microsoft tech, I would just go in to the WCF Service Configuration Editor tool and just start click on different links in the Diagnostics page. I'd usually produce a configuration like this:

    <system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelMessageLoggingListener">
<filter type="" />
</add>
</listeners>
</source>
<source name="System.ServiceModel" switchValue="Warning,ActivityTracing"
propagateActivity="false">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelTraceListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="d:\somedir\tests\dummywcftests\wcfservice1\web_messages.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
<add initializeData="d:\somedir\tests\dummywcftests\wcfservice1\web_tracelog.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>

and...

    <diagnostics>
<messageLogging logMalformedMessages="true" logMessagesAtTransportLevel="true" />
</diagnostics>

The log file produced wasn't much help, either. As soon as I loaded this new configuration (sent to me by the tech), recreated my problem, and looked at the log in the Service Trace Viewer tool, I knew immediately what my problem was (it was even bolded and in red)! Fortunately (or maybe unfortunately), I had other problems with my service so I still made good use of the technical support.

One thing I really like about this new configuration is that all traces are dumped to the same XML listener. As far as I can tell, there's no way to route different trace sources to the same listener in the configuration tool. You'd have to drop out of the tool and edit the XML directly. The tools Microsoft provides are great: but you'll likely still need to edit the generated code/configuration at some point.

Currently rated 1.5 by 2 people

  • Currently 1.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:
Categories: Technology Blog
Posted by Brad on Wednesday, July 30, 2008 8:53 PM
Permalink | Comments (6) | Post RSSRSS comment feed

WCF Test Client

Previously, I posted about my problem getting the WCF Test Client tool to work.  Well, it works now on my new machine.  The solution is, as I noted in the update to that post, that I need the 6.0a SDK (the one that comes with Visual Studio 2008), not the 6.1 SDK.  Go figure.

Anyway, here are my notes on getting it all to work...

Step 1: go to the command line and execute wcftestclient.exe passing the URL to the WCF service you want to test (Note: if your service will be running under the ASP.NET Development Server, make sure that's running first before you try to run the test tool):


Step 2: after a few minutes, WCF Test Client will use svcutil.exe to generate a client proxy and display a UI that lets you test the various methods of your service:



Limitations I've noted:

  • I'm doing a lot of work with custom bindings and, on occasion, custom binding and behavior extensions.  Svcutil does not appear to generate a complete client config file under some of these circumstances.  I've written my own test clients, used svcutil to generate my proxy and config file, and still had to go in and copy/paste configuration settings from my service to my client to get the client to work successfully.  In these situations, I would say forget WCF Test Client and write your own.  I've not tried WCF Test Client with custom extensions, but I would imagine that, assuming svcutil can generate a correct config file to begin with, you'd have to copy your custom assemblies next to wcftestclient.exe so that it could use those extensions.
  • Can you edit the client config generated by WCF Test Client?  Interestingly, the tool lets you see the config right in the UI and will easily give you the file path to where it saved out the config, but I haven't been able to edit it and see that the tool discovers those changes.  So, no copy/pasting xml from your service config to your client config to make up for the misses on the part of svcutil.  (Not that I mean to disparage svcutil or anything--it's a great tool and one that I would certainly miss if it were to suddenly disappear.)
  • I've also had situations where I've had to go in and modify the proxy class that svcutil generated for me.  Specifically, I've had a situation where my requirement was to provide a signed, but cleartext, response message.  By default, WCF will transmit a signed and encrypted message body.  To change this behavior, you have to go into your proxy class and set the ProtectionLevel attribute accordingly.  Unfortunately, there appears to be no way to edit the proxy class used by the WCF Test Client for these kinds of situations--so, back to rolling your own test client.  For most mainstream scenarios, though, the test client seems to do the job.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:
Categories: Technology Blog
Posted by Brad on Wednesday, July 30, 2008 8:38 PM
Permalink | Comments (2) | Post RSSRSS comment feed

Problems with WCF tools

So, a few weeks ago, I was working on a WCF service and decided I was ready to test it.  My first inclination was to write a few unit tests.  Sorry, TDD folks--I know that should have been the first thing I did.  Well, I didn't get very far with my unit tests, which will probably be the subject of a later blog post.  So, on to Plan B.

Many months ago, I attended a session on WCF.  During the course of the session, the presenter brought up--as an aside--the WCF Test Client.  Instead of writing our lame console or winform apps to test our WCF services, Microsoft has provided us a tool to do all that work for us.  All we have to do is point the WCF Test Client at our service and it will generate a proxy and present us with a GUI where we can select whatever method we're interested in to test.  Easy, right?  What could possibly go wrong?

So, I fire the thing up by pointing it to my service and the first thing I get is this error: Unrecognized option "targetclientversion" specified.  Hmm.  What's going on here?

Well, a little digging around and I find out that WCF Test Client is trying to run the svcutil.exe utility and pass it some switch called "targetclientversion".  Ok.  Let's take a look at svcutil and see what it has to say.  By the way, where is svcutil anyway? 

So, looking at wcftestclient.exe in .NET Reflector, I can see that the tool is looking in the Registry for the filepath to a Microsoft SDK which should include the svcutil utility.  If no SDK filepath is present in the Registry, the tool will default to the v6.0 filepath.  [Credit to this forum post for walking me through this.]

So, what SDK version of svcutil is WCF Test Client trying to use?  Well, v6.0, of course (see the picture of my Registry)!  That must be the problem: I know there's a new version of the SDK out there, I installed it not long ago.  [Why did I install a 1.5 Gb SDK?  Because I needed the 100k ASP.NET merge utility contained therein.  No, I'm not bitter about that.]

Ok.  Let's change that Registry filepath to the new SDK and fire up the Test Client again.  It's gonna work this time, right? 

Wrong.  Enter in the next error: System.IO.FileLoadException: Could not load file or assembly 'svcutil, blah, blah, blah.'  I give you Exhibit A and Exhibit B.  It seems svcutil.exe in SDK v6.1 comes with added security features that didn't exist for svcutil in SDK v6.0.  This feature was reported during the Orcas beta, but I haven't seen it reported for SDK v6.1.  Fortunately, when I ran the fix suggested in that blog entry, I was able to resolve the problem and at least make svcutil viable again.

Ok, now where was I?  Let's see...I:

  1. Discovered that my older SDK install (v6.0) was being used for various Visual Studio operations.
  2. Fixed my Registry entry so that wcfTestClient, and presumably other tools, will point to the most recent version of the SDK installed on my machine (in this case, v6.1)
  3. Discovered that svcutil in SDK v6.1 has permission problems that have to be relaxed via sn.exe

Ah.  I'm ready to try the tool again...oh great.  Guess what?  I'm back to my original "targetclientversion" specified error.  Now what gives?  Well, some more digging with Reflector reveals that, indeed, wcfTestClient is trying to call svcutil with the command line switch "targetclientversion".  The bad news is, it doesn't appear that svcutil--neither the version in SDK v6.1 nor the one in SDK v6.0--support a switch called "targetclientversion".  (At least, I went to the command line and looked at the command line help and didn't see this switch listed for either version.)

I have no idea where this targetclientversion switch came from but it seems to me that, so long as it's not supported by a version of svcutil, the wcfTestClient tool is useless.  So, I guess it's back to our lame console apps to test our WCF services.  Sweet.

 

Update:
The plot thickens...I was looking at my Vista machine which runs Visual Studio 2008 and noticed that I have Windows SDK v6.0a installed on it.  The svcutil.exe utility in that SDK is called version 3.0.4506.648.  Looking at its command line help, I saw that it does include an argument named targetclientversion.  Ah-ha!  This version number is greater than the one found in SDK v6.1, even though one would assume that v6.1 is greater than v6.0a.  I haven't actually tried running wcfTestClient on my Vista machine, but I'm sure it will work now that it can find a svcutil that supports the targetclientversion switch.

 

Currently rated 3.0 by 1 people

  • Currently 3/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,
Categories: Technology Blog
Posted by Brad on Thursday, May 22, 2008 9:46 PM
Permalink | Comments (14) | Post RSSRSS comment feed