4

The goal

I'm writing a class that abstracts various Windows user mechanics. My class knows about the user's account name and domain, if any. I am trying to hydrate a property that indicates whether the user has administrative privilege on either the domain or the local environment that it belongs to.

The problem

The WindowsPrincipal class provides that information via IsInRole, but it's constructor requires a WindowsIdentity, which I can't find a way to establish without a user principal name (UPN). The UserPrincipal.UserPrincipalName property is available for domain users, but null for local users. Is there another way to get a WindowsPrincipal from a UserPrincipal? Alternatively, is there another way to accomplish the goal without it?

The source

using (PrincipalContext principalContext = new PrincipalContext(PrincipalContextType, principalContextName))
{
    using (UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(principalContext, IdentityType.Name, Name))
    {
        // Capture additional information from the user principal.
        Certificates = userPrincipal.Certificates;
        DisplayName = userPrincipal.DisplayName;
        UserPrincipalName = userPrincipal.UserPrincipalName;

        // This constructor blows up because UserPrincipalName is null for local users.
        using (WindowsIdentity windowsIdentity = new WindowsIdentity(UserPrincipalName))
        {
            // Capture group membership information about the specified user.
            WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);

            // Determine if the user has administrative privilege on the domain or local machine.
            HasAdministrativePrivilege = windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
        }
    }
}

Thanks in advance.

AdamStone
  • 138
  • 1
  • 8
  • you can find out the use for example depending on where you are calling the above code, place something like this in your code `var userName = Convert.ToString(WindowsIdentity.GetCurrent().Name).Split('\\');` also I would change the `Identity.Type.Name` to use the following `var userFind = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, userName[1].ToString());` – MethodMan Feb 08 '16 at 17:18
  • is `UserPrincipal.SamAccountName` null for local users? – Scott Chamberlain Feb 08 '16 at 17:23
  • @MethodMan, this only works when evaluating the WindowsIdentity for the current process. I need to gather this information for a specified user, for which I know the domain name and user name. – AdamStone Feb 08 '16 at 18:19
  • @ScottChamberlain No, the SamAcountName is available for local users. What do you have in mind? :-) – AdamStone Feb 08 '16 at 18:23
  • @AdamStone the same thing can be done looking for a specific use I do this constantly on a daily basis.. – MethodMan Feb 08 '16 at 18:45
  • @MethodMan in your code above you're using `WindowsIdentity.GetCurrent()`, which is a precursor to establishing the `WindowsPrincipal` that contains the security information. How would you initialize or find a `WindowsIdentity` using a domain name and user name, rather than `WindowsIdentity.GetCurrent()`? Thanks. – AdamStone Feb 08 '16 at 18:52
  • I have a method on our corporate TFS that I have written this can be done I have written a method to do so.. and if you understand how PrincipalContext works.. you can also do the same. also there is a longer way to do it using some AD coding but I have implemented that in the `What and How` I do it as well – MethodMan Feb 08 '16 at 19:09
  • @AdamStone you said "The UserPrincipal.UserPrincipalName property is available for domain users, but null for local users" so I assumed that you had code working that used `UserPrincipalName` but only worked for domain users, just change that code to use `SamAcountName` instead. – Scott Chamberlain Feb 08 '16 at 19:17
  • @ScottChamberlain It doesn't work. The `WindowsIdentity` constructor wants a UPN. If I feed it `userPrincipal.SamAccountName` for a local user it complains "The name provided is not a properly formed account name." I'm exploring other options. – AdamStone Feb 08 '16 at 20:17
  • Well yea, you can't just give it the name by iself and expect it to be happy, you need to concat the domain name if it is a domain user or the machine name if it is a local user. – Scott Chamberlain Feb 08 '16 at 20:45
  • Oh, trust me. I've been messing with this for hours. If you give [this constructor](https://msdn.microsoft.com/en-us/library/td3046fc%28v=vs.110%29.aspx) a string like "MACHINENAME\\UserName" it will send back the same format message I mentioned above. If you feed it "UserName@MACHINENAME" it complains "There are currently no logon servers available to service the logon request." I think I need to use `UserPrincipal.GetAuthorizationGroups`. First I need to put together the domain `SecurityIdentifier`. Will let you know what happens. – AdamStone Feb 08 '16 at 20:58
  • If I modify your code above and use: IdentityType.SamAccountName I do find a user (I'm using trying this out using LINQPad in a corporate environment). My issue is I receive the error: **Logon failure: unknown user name or bad password.** from this line: `using (WindowsIdentity windowsIdentity = new WindowsIdentity(UserPrincipalName))` – jbizzle Feb 12 '16 at 23:16
  • I (finally) discovered that my issue is when trying to access credentials from a user in a different domain. Everything works fine for users in the same domain. – jbizzle Feb 12 '16 at 23:27

0 Answers0