Show Changes Show Changes
Edit Edit
Print Print
Recent Changes Recent Changes
Subscriptions Subscriptions
Lost and Found Lost and Found
Find References Find References
Rename Rename
Search

History

1/25/2005 10:00:55 AM
List all versions List all versions
How To Deal With Unauthenticated Clients
.

If you’re writing a server application and you wish all of your clients to be authenticated, you should read WhatIsANullSession and WhatIsAGuestLogon to learn how to limit access to anonymous clients. One important approach is to avoid ever granting access to Everyone, preferring Authenticated Users when you want to grant a permission to all your clients.

If you want to provide service to unauthenticated users, and you won't be bothering to authenticate any of your clients, then you won’t be performing any authorization (since you don’t know the identity of any of your clients) and therefore this item doesn’t apply to you.

But if you want to service both authenticated and unauthenticated requests, then, if you're going to be using Windows security (accounts, ACLs, etc.) you'll want to use a null session token (WhatIsANullSession) to represent anonymous users. To grant permissions to all authenticated users, use the Authenticated Users SID. To grant permissions to all users, including unauthenticated users, further grant access to ANONYMOUS LOGON. Avoid granting access to Everyone because this SID won't always be present in a null session, as I detailed in WhatIsANullSession.

To get a null session token, you need to call a Win32 function called ImpersonateAnonymousToken. Figure 37.1 shows some sample code that uses this function to grab the anonymous token and wrap it in a WindowsIdentity. It's unfortunate that the only way to get this token is to impersonate (WhatIsImpersonation), because if you’re already impersonating, if you're not careful (as my sample below is), you'll clobber your existing impersonation token with the null session token.

 WindowsIdentity* AnonymousWindowsIdentity::GetAnonymousIdentity()
 {        
  HANDLE curThread = GetCurrentThread();
  HANDLE originalThreadToken;
  if (!OpenThreadToken(curThread, TOKEN_IMPERSONATE, TRUE,
                              &originalThreadToken)) {
    DWORD err = GetLastError();
    // only expected and acceptable error here is when
    // the thread has no impersonation token to begin with
    if (ERROR_NO_TOKEN == err) {
      // there's no thread token that needs replacing
      originalThreadToken = 0;
    }
    else {
      throwWin32Exception(S"OpenThreadToken", err);
    }
  }
  // it's really annoying that this is the only documented way
  // to get a null session token. I'd prefer a function like
  // GetAnonymousToken, Microsoft, in case you're reading ;-)
  if (!ImpersonateAnonymousToken(curThread)) {
    throwWin32Exception(S"ImpersonateAnonymousToken");
  }
  // I open this for MAXIMUM_ALLOWED,
  // because I've no idea how you plan on using the token
  HANDLE nullSessionToken;
  if (!OpenThreadToken(curThread, MAXIMUM_ALLOWED, TRUE,
                      &nullSessionToken)) {
    DWORD err = GetLastError();
    SetThreadToken(0, 0); // be sure to revert!
    throwWin32Exception(S"OpenThreadToken", err);
  }


  WindowsIdentity* id = 0;
  __try {
    // replace the original thread token
    // if there was none, this will simply stop impersonating
    if (!SetThreadToken(0, originalThreadToken)) {
      throwWin32Exception(S"SetThreadToken");
    }
    id = new WindowsIdentity(nullSessionToken, S"Anonymous",
                             WindowsAccountType::Normal, false);
  }
  __finally {
    // WindowsIdentity.ctor dups the handle, so we need to
    // close nullSessionToken before we leave
    CloseHandle(nullSessionToken);
  }
  return id;
 }

Figure 37.1 Creating a WindowsIdentity to wrap a null session token

Now, you might be wondering why I didn't suggest that you simply call WindowsIdentity.GetAnonymous. Well, sadly, this doesn't really get a token for the null session. It creates a WindowsIdentity object that doesn't have any token at all behind it, and it's completely useless as far as the Windows operating system is concerned. Avoid it.

You might also wonder why, when I created the WindowsIdentity object, I specified WindowsAccountType::Normal instead of WindowsAccountType::Anonymous. This is because of some (in my opinion, broken) code in WindowsIdentity that I've shown in Figure 37.2. If you call WindowsIdentity.Impersonate, it throws an exception if the identity object is flagged with WindowsAccountType::Anonymous, complaining that you aren't allowed to impersonate an anonymous user. Apparently whoever wrote this code knew nothing about the null session!

 if (acctType == WindowsAccountType.Anonymous) {
  throw new InvalidOperationException(...);
 }

Figure 37.2 Peering inside WindowsIdentity.Impersonate

The way my code is written, the resulting WindowsIdentity will return false from IIdentity.IsAuthenticated, (exactly what you want for an anonymous user). However, if you call WindowsIdentity.IsAnonymous, it will return false as well, but there's not much I can do about that 1. In any case, as long as you stick to the normal role-based security mechanisms that IPrincipal and IIdentity expose, which include PrincipalPermission, you’ll be fine. Impersonation will work as well. This will give you pretty much everything you need to represent an anonymous user in a natural way for the operating system.

Once you've gotten a WindowsIdentity for the anonymous user as I've detailed above, you can use it in a couple of ways. You can drop it in Thread.CurrentPrincipal and use the .NET Framework's role-based security infrastructure to do your own application-level access checks (WhatIsThreadDotCurrentPrincipal), you can impersonate it (WhatIsImpersonation) and access operating system resources that are protected with ACLs (including remote resources that allow null session access), or you can use a combination of the two!

1 Why does this property even exist, you must ask? You'd think that IIdentity.IsAuthenticated would be good enough!

PortedBy ChrisBurrows

PluralsightTraining

Keith's first book-in-a-wiki. If you would like to read the book online or order a physical copy to throw at annoying coworkers, surf to the HomePage. Please note that due to overwhelming wikispam, this particular wiki is no longer editable.

About FlexWiki.

Recent Topics