There is a security feature of WCF services hosted under IIS that I find poorly implemented. In all honesty, it appears to be broken and non-compliant with its intended purpose. If you’re developing services for use in the intranet environment, then it’s quite reasonable for you to expect that a service can impersonate your Windows identity while it performs its work. After all, security personnel have no doubt already established your intranet authentication and authorization policies for corporate assets, and internal service security should be able to fit within this established paradigm.
Unfortunately, WCF will throw an erroneously worded exception about your attempt to use anonymous access when the IIS hosted service that performs caller impersonation is set to require a Windows identity (presumably a bug of assuming that “not equal to 1” identity means “equal to 0” identities). The reason why you likely had to read the first sentence more than once is that the error message complains about your use of Anonymous when you turn Windows security on, but turning Windows off and Anonymous on makes the error about using Anonymous go away! Confused by the apparent contradiction? Well, so was I when I first encountered it.
In my opinion, the recommendations from Microsoft for working around this limitation are completely idealized and wholly unrealistic. Thanks very much to Wenlong Dong for explaining the problem in his blog entry “Impersonation with Double Identities”; unfortunately, his blog post never addresses the fact that the two identities should be being used for different work in the transportation and consumption of a message (or perhaps he simply disagrees with my assertions).
Here’s the logic for my assertions:
When a postal employee delivers a letter we can make some reasonable assumptions about the security of the letter’s transportation. It is safe to assume that the post office took measures to ensure that our letter was not stolen, snooped, or tampered with during their possession. This is transport security.
Now the postal person has his or her own identity. My postal delivery person’s name is Ralph (a pseudonym I’m using to protect Ralph’s true nefarious identity). I have my own identity, and my name is Paul (which is not a pseudonym, just in case you were wondering). Although Ralph seems like an okay person to me, I’m not ready to invite him into my home whenever he delivers letters addressed to me. I just want Ralph to leave my letters and then go on to his next delivery as quickly as he can. I would be extremely irritated (you might even say that I would “go postal”) if Ralph routinely handcuffed himself to my letters and insisted upon helping me open them.
My friend Russ, (a character I borrowed from Justin Smith’s WCF book), waits in line at a very busy U.S. Post Office. It’s the holiday season and he tires quickly of waiting so long so he decides to send my letter via UPS instead. While driving to the UPS office, Russ discovers that there is a Federal Express office on the way with no waiting line! Russ changes his mind again and immediately decides to send it to me via FedEx. No matter which carrier Russ decides to use, he reasonably expects that his letter to me will be secured until it can be delivered. To differentiate themselves from their competitors, some carriers may have stronger security than others; however, they all perform the same generic service of transportation.
It turns out that Russ is somewhat paranoid that the Department of Homeland Security might be interested in reading his private messages about family protected secret soup recipes and he decides to send his letter to me using some very strong public-private key encryption so that only I can read his message. Russ can now feel confident that if his letter is somehow intercepted that its contents for cooking a very delicious mulagatani will remain confidential. In short, Russ has applied message level security to his communication with me, while the mail carrier has applied transportation security.
If you agree with my analogies then you’re almost certainly hungry. You also likely agree that there are two separate and distinct identities that perform work during the lifetime of a message. There is the identity of the letter transportation carrier (e.g. Federal Express, U.P.S., or U.S.P.S.) and there is the identity of the message recipient. Both identities are responsible for their own distinct roles, and neither is responsible for accomplishing the work of the other.
Wenlong’s blogged solutions do not make a distinction between the postal worker’s identity and the recipient’s identity—they are just two non-descript identities stuffed into a single container and WCF cannot seem to figure out which one it should use for the message security.
The number one recommendation in Wenlong’s blog is to forget the entire matter altogether, and change your IIS security settings to “Anonymous”. In simple terms, Microsoft is asking us to turn transport security off and then depend entirely on message security (or no security). When making this decision, keep in mind that your network administrator cannot easily monitor or prove that message security actually exists or immediately prove its absence if it inadvertently gets turned off. Message security also does not protect the host from malicious anonymous traffic. Administrators likely won’t agree to this, and they may come along at some future time and lock your sweet little anonymous service down as a non-compliant and potentially hazardous risk to their corporate assets. As developers generally do not have carte blanche in networks to do whatever they want, and network administrators already have established security policies which work well for existing internal “asmx” web services, the “solution” of using anonymous is simply dead-on-arrival. Wenlong warns that Microsoft recommends against our use of multiple identities; however, I would argue that good security is generally layered and it certainly makes good sense to me that we would want to secure both our transports and our messages.
The second recommendation for working around this limitation is to have the service impersonate its own account instead of the caller’s account (as if the two could somehow be considered equivalent). Of course, impersonating the user of the service and impersonating the same account for all users of a service are entirely different security models, and it’s unlikely that such a solution would make the network administrators much happier than the “message security only” approach.
This leaves us with the last proposed solution of removing the transport identity from the evaluationContext.Properties[“Identities”] collection. Ah… but there are two identities in the collection and you have a 50/50 chance of removing the right one! The problem here is that placing the two identities into the same collection without any way to determine the role that the identities are supposed to play is completely silly. Creating a production application that has to guess which identity to use seems like a very brittle and potentially hazardous approach to security—but it’s the only one we seem to have available when impersonation of a Windows caller is a requirement. In point of fact, why do we have a collection of identities anyway if we have no way of determining the purposes of the collection’s occupants?
This “double identity” problem existed with the .net 3.0 framework, and I’m sorry to report that it still remains in 3.5. If your network administrators aren’t too concerned about an IIS endpoint being set to allow anonymous access, Sanjay Antony’s blog entry may be useful.