April 3, 2013 at 4:05 PM

Some months ago, I was asked for an intervention regarding a SSL client certificate issue. There was a problem related to the setup of transport security (SSL) of a WCF service hosted in IIS 7.0, using client certificates that are mapped to a local account.  Let’s have a look.

 

The Setup

Server Setup

  • Wild card server certificate is installed in IIS (server level). Wild card is required, because we’re using multiple host names are configured.

          image

        image

 

  • The Certificate Authority is added to the Trusted Root Certification Authorities store (Local Machine)

        image

 

  • Website binding is configured to use https with the server certificate for SSL

        image

 

  • Website is configured to require SSL and to require client certificates

       image

 

  • Client certificate mapping is configured in order to map an individual client certificate to a specific Windows account. Configurable via this extension.

         image

       image

 

       This extension actually changes this configuration:

      image

 

  • An Allow authorization rule is configured for this Windows account

        image

 

  • Anonymous Authentication is enabled (Client Certificate is anonymous authentication)

        image

 

  • WCF service is configured for transport security

          image

 

Client Setup

  • The Certificate Authority is added to the Trusted Root Certification Authorities store (Local Machine)

           image

 

  • Client Certificate (containing private key) is added to the Personal certificate store (Local Machine).  This is required for the WCF client

          image

 

  • Client Certificate (containing private key) is added to the Personal certificate store (Current User).  This is required for browsing to the service via IE

         image

 

  • WCF Client is configured for transport security, providing Client Certificates:

          image

 

Problem Solving

The issue

When browsing to the service, for a particular web server, we’re not prompted to select a client certificate. Instead, we get this exception:

The page you are attempting to access requires your browser to have a Secure Sockets Layer (SSL) client certificate that the Web Server recognizes.

image

 

Troubleshooting

We configured another web server with exactly the same setup, which worked fine.  But still it didn’t work on that particular web server. Handy tools / commands during troubleshooting:

  • netsh http show sslcert
  • SSL Diagnostics

 

At the end, a warning in the System Event Log gave the solution. This entry is only written to the Event Log for the first call after the IIS service is restarted. That’s why we didn’t discover this Event Log warning earlier.

When asking for client authentication, this server sends a list of trusted certificate authorities to the client.  The client uses this list to choose a client certificate that is trusted by the server.  Currently, this server trusts so many certificate authorities that the list has grown too long.  This list has thus been truncated.

image

 

Root cause

During the handshake protocol for client certificate authorization, the server sends a list of Trusted Root Certification Authorities to the client.  The client will in this case only provide Client Certificates, issued by one of these Trusted Root Certification Authorities.  The problem was that the Trusted Root Certification Authorities list was too long on that particular server, so it was truncated before sent to the client.  Unluckily, our Root Certificate Authority was truncated from the list, so the handshake failed.

 

Solutions

There are two solutions to solve this issue:

  • The first solution is to clean up the Trusted Root Certification Authorities store (Local Machine) and remove all unnecessary certificates. Be aware that you don’t remove certificates that are required by Windows.

 

  • A second solution is to configure Schannel to no longer send the list of trusted root certification authorities during the TLS/SSL handshake process.  This can be done by adding this registry entry on the web server:

        HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL

        Value name: SendTrustedIssuerList
        Value type: REG_DWORD
        Value data: 0 (False)

 

Result

When browsing to the service, we’re now promoted for our Client Certificate. Now we can access the service:

         image

         image

Posted in: IIS | Security | SSL

Tags: , , ,


July 2, 2012 at 4:22 PM

The out-of-the-box BizTalk Server Operators group has limited access to the BizTalk environment. An extract from MSDN:


Members of the BizTalk Server Operators group can do the following:

  • View service state and message flow
  • Start or stop applications
  • Start or stop orchestrations
  • Start or stop send ports or send port groups
  • Enable or disable receive locations
  • Terminate and resume service instances

 

Members of the BizTalk Server Operators group can do the following:

  • Modify the configuration for BizTalk Server
  • View message context properties classified as Personally Identifiable Information (PII) or message bodies.
  • Modify the course of message routing, such as removing or adding new subscriptions to the running system, including the ability to publish messages into the BizTalk Server runtime.

 

Lately, I had a request to elevate the permissions for BizTalk Operators, so they were able to see the tracked message bodies.  The content of a message is often needed for a decent troubleshooting.  Because BizTalk security is actually based on SQL Server security, it was pretty easy to implement this request.  It’s sufficient to give the database role “BTS_OPERATORS” additional EXECUTE rights on specific BizTalk stored procedures, which are related to the retrieval of BizTalk message bodies.  All details can be found in the script below:

USE BizTalkDTADb; 
	GRANT EXECUTE ON OBJECT::bts_GetTrackedMessage
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::bts_GetTrackedMessageFragments
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::bts_GetTrackedMessageParts
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedMessageContext
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedMessages
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedPart
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedPartByID
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedPartFragment
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedPartNames
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedParts
		TO BTS_OPERATORS;
GO 

USE BizTalkMsgBoxDb;
	GRANT EXECUTE ON OBJECT::bts_GetTrackedMessage
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::bts_GetTrackedMessageFragments
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::bts_GetTrackedMessageParts
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadMessageContext
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadMessages
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadPart
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadPartFragment
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadPartNames
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadParts
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedMessageContext
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedMessages
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedPart
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedPartByID
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedPartFragment
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedPartNames
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::ops_LoadTrackedParts
		TO BTS_OPERATORS;
GO 

USE BizTalkMgmtDb;
	GRANT EXECUTE ON OBJECT::dpl_MessageType_Part_Save
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::dpl_MessageType_Save
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::dpl_Operation_MsgType_Save
		TO BTS_OPERATORS;
	GRANT EXECUTE ON OBJECT::dpl_SaveItem
		TO BTS_OPERATORS;
GO

 

By executing this SQL Server script, you can easily grant them the rights to view BizTalk message bodies which allows easy debugging or follow up in different scenarios without having to change memberships.

 

Update:
Please note that the above method is not supported by Microsoft, so be sure to know what you are doing!
Also note that database schemas and security may vary depending on the version of BizTalk you are using.


February 19, 2012 at 12:26 PM

A while ago I had a little surprise with a demo project.
The project consists of a client application, a claims aware WCF service and AD FS as token issuer.

This demo was working fine until now...
Without changing anything, authentication always fails with this error message (see WIF tracing):

ID4175: The issuer of the security token was not recognized by the IssuerNameRegistry. To accept security tokens from this issuer, configure the IssuerNameRegistry to return a valid name for this issuer.

Offcourse my token issuer certificate was added to the 'trustedissuers' collection on the WCF service, so something must have changed in AD FS.

The signing certificate in AD FS shows this:

As you can see, there are two signing certificates (I had one before). The second signing certificate was created by AD FS automatically because my signing certificate was reaching it's expiration date. This feature - AD FS creating a new self-signed certificate when the old one nears expiration - is called Auto Certificate Rollover.

When using self-signed certificates, auto certificate rollover is on by default.
AF FS will use the signing certificate marked as 'Primary' to sign issued tokens.
The only thing I need to do is adding the new certificate to the trusted issuers collection as shown below:

 

Note: The reason why my sample failed is that I use the out-of-the box 'ConfigurationBasedIssuerNameRegistry' class to resolve the trusted issuer. This class uses the certificate thumbprint to match certificates. Obviously the certificate thumbprint changed when auto certificate rollover issued a new signing certificate. You can avoid this by implementing you own class and for example use the subject name to match issuers.

After adding the thumbprint of the new signing certificate to the trustedIssuers section, the sample should work again ... unless ...

My signing certificate is a self-signed certificate, but the newly created certificate is not trusted on the WCF machine. This results in this error:

ID4257: X.509 certificate 'CN=ADFS Signing - WIN-BEJU5AI4TP7.pbdev.CODit.eu' validation failed by the token handler.

The self-signed signing certificate should be added to the trusted root store of the WCF machine. The action you need to take to make sure the certificate passes validation depends on the certificateValidation mode you use. Mine was set on chaintrust, so adding it to trusted root will do. If you use peertrust, add the certificate to the trusted people store. If you use custom it depends on your implementation.

 

Peter Borremans

Posted in: Security | WCF | WIF

Tags: , , , ,


February 10, 2012 at 9:20 PM

When developing applications that make use of Windows Identity Foundation - WIF (Microsoft's technology to deal with claims-based security in your services) you can encounter exceptions that are not very precise/clear.

In this blog post I will show the difference between WCF tracing and WIF tracing based upon a sample application that is made to fail. The sample application consists of a client calling a service by first obtaining a security token from AD FS 2.0 and then asking the service to enumerate the claims present in the security token. The client will show the claims enumeration as received from the service. 

When I run my application (both the host and the client) this is the result:

 

The window in the background is my ServiceHost, the window in the front is the client. When the client calls the service over transport security the presented claims are enumerated as expected, when doing the same over message security the communication fails.

We will try to find the root cause of the problem by looking into WCF and WIF tracing.

The first thing the seasoned .NET developer will think of is to go in the .config file of your service and enable WCF Tracing:

 

Let's have a look what helpful information we can find in the WCF tracelog and WCF message log after running the sample.

The trace log shows this exception:

 

The message log shows this SOAP fault:

 

Although we have some useful information, "Message security verification failed" and "Security token could not be authenticated" can have a lot of reasons. We are interested in more detailed information about what goes wrong in the communication between clients, AD FS 2.0 and the service.

To find more detailed information we can enable WIF Tracing. WIF tracing cannot be enabled by clicking 'enable' in the Service Configuration Editor tool like we did for WCF Trace. However the idea is similar.

We only need to add two things to our config file (can also be done via the Service Configuration Editor tool):
- A diagnostics source: Microsoft.IdentityModel
- A listener (shared or not)

 The Xml representation looks like this: 

<system.diagnostics>
    <sources>
...
      <source name="Microsoft.IdentityModel" switchValue="Verbose">
         <listeners>
           <add name="WIFListener" />
         </listeners>
      </source>
...
    </sources>
    <sharedListeners>
...
      <add initializeData="c:\...\wif.svclog" type ="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="WIFListener" />
    </sharedListeners>
</system.diagnostics>

The Service Configuration Editor tool view looks like this:

 

That't all you need to do to enable WIF tracing.

Let's re-run the sample app with WIF tracing enabled and hit against the same exception...

After opening the WIF trace-file, I can see this information:

 

As you can see, WIF Tracing gives us a much clearer exception message:

"ID1038: The AudienceRestrictionCondition was not valid because the specified Audience is not present in AudienceUris.
Audience: 'http://localhost:8733/ClaimsEnumeratorService/'"

After checking the service config file, I can see that WIF is exaclty right :)

The audienceUri for my endpoint that uses message security is commented out.
Thanks to WIF tracing I can troubleshoot problems like this in a reasonable time, with only WCF tracing the exception details are just not enough to point you to the right direction.

Both WCF and WIF tracing are priceless for .NET developers...

 

Peter Borremans

Posted in: Security | WCF | WIF

Tags:


November 10, 2009 at 11:12 AM

Peter Borremans, CODit Integration architect, wrote a detailed document on how to use certificates to enable message security on a BizTalk WCF receive location.  This document was published by Microsoft.

Posted in: BizTalk | Security | WCF

Tags: , , , ,