Inconspicuous SharePoint Quirks #4

Mystery of the Identity Impersonator

This one is not exactly a SharePoint quirk, but a SharePoint app led me to it. Which means its an IIS quirk. Or a .Net quirk. Or a Service Pack quirk. Or a Windows Server 2008 quirk. Or a Microsoft quirk. Or whatever…

My co-worker had written a form-based-authentication login page for a SharePoint application. The users are created in Active Directory and the usual frills of user account – login, security questions, change password, reset password et al.

The app worked fine in dev environment, was working fine in Stage but one fine Monday, broke in Stage. The user was created in the AD, but was set in a disabled state and returned an error back to the application. It was working in Dev fine though. The web.config, wsp solution, content databases are all exactly same between dev and stage. The only difference was the stage environment had Windows Server 2008 R2 SP1, while the Dev was not. We decided to backout SP1 from stage and lo, it started working again. Could it be the sheer gravitons of SP1 cause to distort the user creation in the Active Directory?

Since SP1 was causing the problem, we got the dev environment to the same SP1 patch level as stage. And yes, the user creation broke. Repeatable bugs are like flights crashing without casualties. Yeah, it crashed, but no one died. I started looking at the ULS and noticed there were no log statements. Coming from the Java world, I rely more on debug statements rather than run-time debugging. A friend of mine reminds me that in the .Net world programmers first put the solution in Debug mode, then start writing the code. But here the log statements were there in the code, yet were not written.

You can spot the issue here:

public static class ExceptionExtension {
public static string Unroll(this Exception ex) {
if (ex == null) return "";
string exStr = ex.Message + "\n" + ex.StackTrace;

if (ex.InnerException != null) {
exStr += "\n" + ex.InnerException.Unroll();

return exStr;

Test Usage:
PortalLog.LogString("ERROR: {0} || [{1}]", errorMessage, ExceptionExtension.Unroll(ex));

The above code wont work, because the correct usage of the extension is ex.Unroll(), not by a static method call. Once I fixed this, I could see the actual errors in ULS.

Here is how the account was being created usig LDAP:

entry = new DirectoryEntry(ldapPath, ldapUser, ldapPassword, AuthenticationTypes.Secure);
//create new user object and write into AD
user = entry.Children.Add("CN=" + samAccountName, "user");
user.Invoke("SetPassword", password);
user.Invoke("Put", new object[] { "userAccountControl", "512" });

System.DirectoryServices threw exception with an error code 0x80070005 (ACCESS_DENIED) while invoking SetPassword. I double checked that the ldapUser has identical permissions in dev and stage. How can the user be created but still access denied? More importantly, WHO is being denied? Certainly not the ldapUser.

I added the debug for WindowsIdentity.GetCurrent().GetName(). And it returned NT AUTHORITY\IUSR. In IIS, the anonymous access is enabled and in the web.config the identity tag is

<identity impersonator="true"/>

Obviously IUSR does not have permission to set the password. But why was it working in dev, before SP1? When I tried in another environment without SP1, the current Windows Identity was the same as the Application Pool user for that SharePoint Web Application and not the IUSR. Google-o! Er.. I mean, Bing-o!

Back to dev with SP1, I set the impersonator to false, and now I saw the current identity as the Application Pool user! W2k8 R2 without SP1 was not respecting the identity impersonator flag. Obviously without SP1, the IUSR anonymous user was having access to create an user in active directory, while SP1 prevented it. The impersonation is not required when you are creating user using the ldap service user and password, who already have access.

To me it looks like a security hole (pre-SP1). I could not find any online documentation or release notes mentioning about this. If you know of such documentation, please drop a comment!