How to get UPN for authenticated user in .NET web application, without querying Active Directory

11.5k views Asked by At

(This question is similar to Get UPN or email for logged in user in a .NET web application, but not quite.)

In a .NET (C#) web application using Windows authentication, I'd like to find the UPN of the signed-in user.

I know how to do this by querying Active Directory: take the 'DOMAINNAME\userName' from HttpContext.Current.User.Identity as WindowsIdentity; look up DOMAINNAME under the ldap://RootDSE and find its dnsRoot; query for (&(objectCategory=person)(objectClass=user)(sAMAccountName=...userName...)) under ldap://...dnsRoot...; get this entry's userPrincipalName property. (More detail is in answer https://stackoverflow.com/a/513668/223837).

My question: Can the UPN be found without a call to Active Directory? Given Microsoft's focus on using UPNs everywhere, isn't the UPN already stored somewhere in the token which is created when the user authenticates to the web server?

(Supporting observation: If I run whoami /upn on Windows 7, then Wireshark does not show any Active Directory connections.)

(If it makes any difference: note that our web application does not use impersonation, i.e., our web app does not run under the user identity.)

2

There are 2 answers

4
moribvndvs On BEST ANSWER

Try System.DirectoryServices.AccountManagement.UserPrincipal.Current, which has the property UserPrincipalName. Of course, that would require the application to be running under Windows authentication.

Edit Meh, it looks like this API still performs a directory lookup.

1
Jack A. On

I was having issues with the Active Directory query when using System.DirectoryServices.AccountManagement.UserPrincipal.Current, so I resorted to using GetUserNameEx with the NameUserPrincipal format.

This function gets the information about the current user, so it does require that you impersonate if you are not already. In C# it can be done by importing the function:

public enum EXTENDED_NAME_FORMAT
{
    NameUnknown = 0,
    NameFullyQualifiedDN = 1,
    NameSamCompatible = 2,
    NameDisplay = 3,
    NameUniqueId = 6,
    NameCanonical = 7,
    NameUserPrincipal = 8,
    NameCanonicalEx = 9,
    NameServicePrincipal = 10,
    NameDnsDomain = 12
}

[DllImport("secur32.dll", CharSet = CharSet.Auto)]
public static extern int GetUserNameEx(int nameFormat, StringBuilder userName, ref int userNameSize);

Then calling it like this:

string upn = null;
StringBuilder userName = new StringBuilder(1024);
int userNameSize = userName.Capacity;
if (GetUserNameEx((int)EXTENDED_NAME_FORMAT.NameUserPrincipal, userName, ref userNameSize) != 0)
{
    upn = userName.ToString();
}