The patterns & practices team at Microsoft has put together their first release of guidance for WCF security. They've included how-to guides and videos that walk you through a number of security tasks, such as working with certificates and configuring role providers. The overall guide is still under development so these represent individual modules that are being published as they're completed.
Here's what's currently available:
How do I use username credentials with IPSec? I'm told that I need to turn on security but my connection is already secure.
WCF only permits username tokens to be transmitted over a binding that's secure. If a username and password are transmitted without some way of obscuring their values, then that essentially allows anyone that can read the message to steal those credentials. There are many meanings that could be applied to the word secure, but in this case the definition of secure is only that the binding promises to protect the data that's transmitted by providing confidentiality. IPSec is a way to provide security that's external to service. It can be used together with a binding that doesn’t ordinarily provide security, but the binding has no way of knowing that its security has been upgraded.
The mechanism for making security promises on a binding is ISecurityCapabilities. This interface defines the supported protection levels for transmitting messages as well as various other security properties. When security is externally provided, you can use this interface to pretend like the binding is more secure than it really is so that the security capabilities match the actual environment.
When using IPSec, requests and responses can be confidential and tamper-proof. This corresponds to a protection level of EncryptAndSign. This is implemented by wrapping the channel to provide a custom set of security capabilities from GetProperty. You'll want to get the ISecurityCapabilities from the underlying channel and then take the maximum of those capabilities together with the capabilities of your external security.
Next time: The Pipe DACL
I hadn't seen this before, but the training kit for Visual Studio 2008 and .NET Framework 3.5 was updated a few weeks ago. This kit includes demos, presentations, and labs to go through self-directed and at your own pace. If you've got a copy of Visual Studio 2008, this training kit will help you get up to speed on the changes and new technologies in this product generation.
Now that MIX is over, the presentation goes on the road. There are actually two different formats for the road shows. MIX Essentials is a one day event that covers the highlights of the conference with local keynote speakers added in. ReMIX is a multi-day event that provides sessions for a broader range of topics. You can get the overall calendar of planned events plus more details as they're available at the MIX world site.
Why doesn't validation catch when the two sides of a reliable connection disagree about whether the session is ordered?
It doesn't actually matter to the sender whether the session is supposed to be ordered, and so it doesn't actually matter whether the two sides agree. The sender has a direct and perfectly reliable view of the messages in the sequence as they're generated. In essence, the order of the messages is whatever order the sender chose to send them in. On the other hand, the receiver has an unreliable view of the message sequence. The purpose of a reliable messaging protocol is to reconstruct a reliable view from that unreliable view. Therefore, the receiver actually has a choice about whether the original sender order is important and should be reconstructed.
This is different than saying that ordering is useless on the client. Client and server are ideas about the organization of a system; sender and receiver are particular roles in a protocol. A client could be both sending and receiving messages.
Next time: Overriding Protection for IPSec
I'm trying to connect to a service on the same machine using Windows credentials and getting an authentication error. I can connect to the service from other machines. I can also connect to the service if I set up an endpoint that listens on the loopback address. What's going on here?
These symptoms suggest that the client on the local machine is being rejected by a security check in Windows on the loopback address. This check prevents you from connecting on a loopback address unless the service was specifically configured to listen on the loopback address. The reason for this check is to stop a security attack called a reflection attack. A reflection attack redirects a security challenge back to the same machine in hopes of getting the machine to answer its own challenge.
Since the security check is in Windows rather than in WCF you shouldn't expect a simple knob on your service to fix this. However, you can try configuring the client with a user principal name for the service. Having a UPN helps you pass the check because in some cases it allows Windows to recognize that an attack is not taking place. For help configuring Windows, including some workarounds that I'm not sure I'd recommend, check out this KB article related to the loopback check.
Next time: Why Ordering is Ignored
If you didn't attend MIX you missed out on getting the Silverlight 2 developer's poster. However, Brad Abrams has posted the high-quality images so you can make your own. Now you can prove to your friends that WCF is in Silverlight: it takes up half of the outer ring under both communication foundation and data framework.
My application needs to process messages from a queue in-order but multiple messages are being read at once. How do I make the service only use a single reader?
There are two modes that control how many requests a service can process at once. InstanceContextMode controls when a new instance of your service is created; ConcurrencyMode controls the threading model for the service.
When the InstanceContextMode is PerCall (or PerSession- the two are the same if you don't actually have a session), multiple instances of your service will be created with their own reader thread, up to a limit on the number of simultaneous instances.
When the ConcurrencyMode is Multiple, multiple reader threads will be passing messages to a service instance, up to a limit on the number of simultaneous calls.
If you want your service to be sequentially invoked with each of the messages in the queue, then you need to set both InstanceContextMode and ConcurrencyMode to Single.
Next time: Getting Caught by Loopback
The other day I talked about the built-in service validation behaviors but these behaviors are only a part of the overall validation story. Today I've got more of an end-to-end overview of behavior validation. Although validation is similar whether you're building a client or service (remember that client proxies have behaviors too) I'll also point out where the differences take place.
How a service performs behavior validation:
How a client performs behavior validation:
If more than one endpoint shares a contract, then the contract behaviors will run again and again while the operation behaviors will only run once. That's because an IContractBehavior operates on the contract and endpoint while an IOperationBehavior operates on the operation and contract.
Next time: Single Reader for MSMQ
Why do the messages logged by my service show addressing headers but those headers disappear when the message is sent?
This is easy to explain once you actually look at the messages. Here's a quick test program that generates some SOAP 1.1 messages with all of the different addressing permutations.
using System;using System.Collections.Generic;using System.ServiceModel.Channels;using System.Xml;class MyBodyWriter : BodyWriter{ public MyBodyWriter() : base(true) { } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { }}class Program{ static IEnumerable<MessageVersion> Versions { get { yield return MessageVersion.Soap11; yield return MessageVersion.Soap11WSAddressing10; yield return MessageVersion.Soap11WSAddressingAugust2004; } } static void Main(string[] args) { foreach (MessageVersion version in Versions) { Message m = Message.CreateMessage(version, "http://MyApplication/Action", new MyBodyWriter()); m.Headers.To = new Uri("http://localhost/service"); Console.WriteLine("MessageVersion: {0}\n{1}\n", version, m.ToString()); } Console.ReadLine(); }}
That generates the following set of messages:
MessageVersion: Soap11 (http://schemas.xmlsoap.org/soap/envelope/) AddressingNone (http://schemas.microsoft.com/ws/2005/05/addressing/none)
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header> <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://MyApplication/Action</Action> <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost/service</To> </s:Header> <s:Body /></s:Envelope>
MessageVersion: Soap11 (http://schemas.xmlsoap.org/soap/envelope/) Addressing10 (http://www.w3.org/2005/08/addressing)
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header> <a:Action s:mustUnderstand="1">http://MyApplication/Action</a:Action> <a:To s:mustUnderstand="1">http://localhost/service</a:To> </s:Header> <s:Body /></s:Envelope>
MessageVersion: Soap11 (http://schemas.xmlsoap.org/soap/envelope/) Addressing200408 (http://schemas.xmlsoap.org/ws/2004/08/addressing)
<s:Envelope xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Header> <a:Action s:mustUnderstand="1">http://MyApplication/Action</a:Action> <a:To s:mustUnderstand="1">http://localhost/service</a:To> </s:Header> <s:Body /></s:Envelope>
Notice how the addressing headers in each message have a different namespace, and that that namespace matches the one in the MessageVersion? The headers that you see printed out reflect the in-memory representation of the message. The wire representation of the message will be constructed as the message is written out and some of those headers are in a namespace that has no wire representation. In particular, the To and Action headers you see in the http://schemas.microsoft.com/ws/2005/05/addressing/none namespace when not using addressing exist in memory but don't have any substance when the message is transmitted.
Next time: Validation Behaviors for Client and Service
There are many ways to get help with WCF, ranging from the free but not particularly reliable to the highly reliable but not particularly free. With paid options, such as Microsoft product support, you're generally trading money to get some kind of guarantee (for example, a guarantee that someone will look at your problem and try to give you a solution within a certain amount of time). I don't provide recommendations for paid services. However, if your problem is urgent and not having a solution is costing you money, then you want to be looking at paid services.
Since you're still reading this, I'm assuming that you're instead looking for free services. Free services have a tremendous advantage (being free) at some expense (sometimes being not particularly helpful). Here are the various classes of options:
Yesterday I talked about the validation done on bindings for partial trust. Partial trust validation gets run very early when the service host is opened using a service behavior. There are actually several of these service behaviors that run up front. Afterwards, Validate is called on each of your service behaviors to perform the user-extensible part of validation. Here is what those built in validation behaviors do:
Next time: Mystery of the Disappearing Addressing Headers
Partial trust support in WCF is an Orcas feature that allows clients and services to be run in an environment with restricted permissions. WCF is part of a fully trusted installation, so by default partially trusted callers are not allowed to call into the assembly. However, there is a standard mechanism to change that, which is to mark the assembly with the AllowPartiallyTrustedCallers attribute. Once an assembly is marked, it is then the responsibility of that code to make sure that partially trusted callers can't do bad things through the exposed API of the fully-trusted assembly.
To implement this restriction, one of the things that WCF does is limit the bindings that you can build using the out-of-the-box components (custom components would have to join into this same security model and do their own validation before they could be used). There are two rounds of checks, first to knock out the bindings that are not safe for partially trusted callers and then to knock out the binding elements.
WCF ships with 15 bindings (plus custom binding) in the box for Orcas. Of these, eight immediately get knocked out:
Then, any binding that contains one of these binding elements gets knocked out:
That basically allows for the following standard bindings to operate: BasicHttpBinding, BasicHttpContextBinding, WebHttpBinding, WSHttpBinding, WSHttpContextBinding, and WS2007HttpBinding. The WSHttp bindings will be quite limited because many of their features are blocked by the binding element checks.
Now you can figure out all of the supported binding configurations if you still haven't read the partial trust feature compatibility guide.
Next time: Built In ServiceHost Validation Behaviors
As part of the MySpace session at MIX they've put online the code for a sample called RESTchess. RESTchess is a WCF REST application that mimics a lot of the developments behind the WCF implementation of the MySpace developer API. If you're interested in getting details, then Vittorio Bertocci has a more extensive description of RESTchess. If you're just interested in poking at the code, then the link above is all you need to get started together with the MIX session videos I posted earlier.
The full video collection for MIX 2008 is available now (along with much of the content from the previous two years). I've pulled out some of the direct links for videos of interest to WCF developers. Feel free to suggest other sessions that you've watched and think should be included in this list as well.
Creating a RESTful API with WCF
Speaker(s): Aaron Sloman, Haider Sabri
Learn how MySpace used Windows Communication Foundation and .NET 3.5 to rapidly scale up a massive RESTful API infrastructure that process millions of requests a day.
Working with Data and Web Services in Microsoft Silverlight 2
Speaker(s): Eugene Osovetsky
Learn how easy it is to utilize POX, REST, RSS, ATOM, JSON, and SOAP in your Microsoft Silverlight mashup applications. Also learn how to easily access and display data with Silverlight using LINQ and databinding.
Building Applications and Services with .NET Framework 3.5
Speaker(s): Justin Smith
Come see how the new Web-friendly features in .NET 3.5 Windows Communication Foundation extend the reach of your services to simple clients like Web browsers and RSS aggregators.
Using an Internet Service Bus to Build Next Generation Applications and Services
Learn how using Microsoft's Internet Service Bus technologies including pub/sub, message transformation, and hosted workflow enables you to easily and quickly build complex applications and services that require reach, scale, and access control.
Next time: Partial Trust Binding Black List
Is it possible to configure the protection level for message parts at runtime?
Only certain configurations make doing this particularly easy. When using transport security with Windows credentials, the WindowsStreamSecurityBindingElement allows you to directly set the protection level (changing the protection level when using SSL doesn't make as much sense due to the way SSL works). On the other hand, there's no equivalent facility for message security, which will always give you both encryption and signing if you haven't explicitly set the protection level on the contract.
There are a few ways to attack this lack of configurability:
The first approach is a very indiscriminate way to get the job done. Modifying the entire service is almost certainly not what you want to do, so you'd need some way to describe the scope of specific message parts that you want to modify. Behaviors can be much more targeted.
The second approach has the hidden downside that modifying the contract description at one endpoint can potentially (depending on order of execution) modify the contract description for other endpoints. This also is almost certainly not what you want to do.
Finally, both the second and third approaches have downsides due to being implemented with behaviors. User behaviors are executed after the security validation behavior that is run as part of the service start up. This means that you're unable to declare a protection level on the contract and then later reduce it in the behavior unless the binding is capable of supporting the originally specified protection level. Also, the results of modifying a contract in a behavior don't get reflected in metadata, which makes a variety of tasks harder.
In short, none of these options are particularly good. The third approach is probably the most workable although it does suffer a number of downsides. You can base this approach on the following bit of code.
public class ProtectionLevelEndpointBehavior : IEndpointBehavior{ public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { ChannelProtectionRequirements requirements = bindingParameters.Find<ChannelProtectionRequirements>(); // reconfigure the requirements that are being passed down } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { }}
However, I'd recommend trying to avoid this sort of dynamic protection level configuration if possible.
Next time: MIX Video Wrap Up
How do I customize the exception text sent back from a custom password validator?
If you've looked at the documentation for UserNamePasswordValidator, then the instructions tell you to implement the validator by overriding the Validate method and throwing a SecurityTokenValidationException if you don't like the username and password pair that was provided. A failed validation attempt results in an exception back on the client that is fairly generic.
An error occurred when processing the security tokens in the message.
Being generic is the correct thing to do most of the time because you don't want to volunteer unnecessary information in your security responses. Subtle differences in how the application behaves can give an attacker hints about the parts of their input that passed validation and the parts of their input that failed validation. However, if an attacker can't use the diagnostic information to their advantage, then you may want to provide more information to make debugging easier.
Changing this exception message is relatively easy to do although hard to discover. In your Validate method, rather than throwing a security exception, you can instead throw a FaultException with a custom message. That custom message will be passed back to the client application although the details of the fault will not.
public class MyUserNameValidator : UserNamePasswordValidator{ public override void Validate(string userName, string password) { // validation logic if (validationFailed) { throw new FaultException("Here's a description of why validation failed"); } }}
Next time: Configuring Protection Level
If you didn't watch the MIX keynote yesterday then you missed out on the debut of Silverlight 2. You can still go back and watch the Day 1 Keynote or carry on with these resources.
You'll also want to take advantage of the early documentation that's available for Silverlight 2. Since Silverlight 2 is a subset of the full .NET Framework, for the most part you can jump back to the Orcas documentation when details are missing.
More content will be coming online from MIX today, including the Day 2 Keynote and all of the technical sessions from Day 1.
If you're not at MIX you can still join in on the action starting from today. The keynote sessions will be streamed live from the event and the regular technical sessions will be streamed with a 24 hour delay (meaning that you'll be able to see today's sessions starting tomorrow, and so on).
The two keynotes are:
The MIX web site will hopefully have details and links by the time you read this.
An invention that now seems to be ubiquitous turns out to only be 20 years old. RFC 1049 introduced the notion of a standardized Content-type field that message processors could use to automatically identify the type of a structured message and interpret it appropriately. This same convention went on to show up in the Multipurpose Internet Mail Extensions (MIME) message format, HTTP, and other later protocols. It commonly continues to appear with its original name, content type, although you'll sometimes hear other phrases used instead, such as MIME type or media type.
The original content type had a set of seven supported values.
What are the rules for when a client needs to support Active Directory integration for sending to an MSMQ queue?
The circumstances may seen mysterious for when you need the client to be joined to a domain to take advantage of Active Directory integration, but the rules turn out to actually be pretty simple. This should help you avoid seeing errors like the following:
Binding validation failed because the binding's MsmqAuthenticationMode property is set to WindowsDomain but MSMQ is installed with Active Directory integration disabled. The channel factory or service host cannot be opened.
The authentication mode of the MSMQ transport and the protection level of the message are interrelated, and these both are related to when you need to be using Active Directory. Rather than making you assemble the various combinations as a logic puzzle, I've digested the results into a table explaining when Active Directory is required to pass validation.
Protection None
Protection Sign
Protection EncryptAndSign
Authentication None
Not required
Not supported
Authentication Certificate
Required
Authentication WindowsDomain
The same rules apply to both sides so you're covered for the explanation of the service as well.
Next time: Customizing Exceptions for Validation