How can I convert from a SID to an account name in C#

此生再无相见时 提交于 2019-11-27 06:47:52

The SecurityReference object's Translate method does work on non-local SIDs but only for domain accounts. For accounts local to another machine or in a non-domain setup you would need to PInvoke the function LookupAccountSid specifying the specific machine name on which the look up needs to be performed.

Chris

See here for a good answer:

The best way to resolve display username by SID?

The gist of it is this bit:

string sid="S-1-5-21-789336058-507921405-854245398-9938";
string account = new System.Security.Principal.SecurityIdentifier(sid).Translate(typeof(System.Security.Principal.NTAccount)).ToString();

This approach works for me for non-local SID's over the active directory.

Bakanekobrain

System.DirectoryServices.AccountManagement.UserPrincipal class (msdn link) has a static function FindByIdentity to convert an SID to a User object. It should be able to work both against the local machine or an LDAP/Active Directory server. I have only used it against active directory.

Here is an example that I have used in IIS:

// Set the search context to a specific domain in active directory
var searchContext = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", "OU=SomeOU,DC=YourCompany,DC=com");
// get the currently logged in user from IIS
MembershipUser aspUser = Membership.GetUser();
// get the SID of the user (stored in the SecurityIdentifier class)
var sid = aspUser.ProviderUserKey as System.Security.Principal.SecurityIdentifier;
// get the ActiveDirectory user object using the SID (sid.Value returns the SID in string form)
var adUser = UserPrincipal.FindByIdentity(searchContext, IdentityType.Sid, sid.Value);
// do stuff to user, look up group membership, etc.

In C#, get the user SID and assign it to a string variable through:

string strUser = System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString();

You will need to use string because the ability to resolve to the UserName supports string. In other words, using var varUser will result in a namespace error.

string strUserName = new System.Security.Principal.SecurityIdentifier(strUser).Translate(typeof(System.Security.Principal.NTAccount)).ToString();

Ooh, then it's possible that the LDAP call is not working because you might not be in an Active Directory environment. If this is the case, then each of your machines is responsible for its own identity store. And your first code sample is not working across the network because the machine on which you are executing your code does not know how to resolve the SID that only makes sense on the remote machine.

You really should check if your machines are a part of an Active Directory. You would know this during the logon process. Or you can check by right clicking on "My Computer", select "Properties", the "Computer Name" tab, then see if your computer is part of a domain.

Great. I cribbed some LookupAccountSid() code from here:

http://www.pinvoke.net/default.aspx/advapi32.LookupAccountSid

And that worked, though I had to provide the host name myself. In the case of a UNC path I can just take the first component of it. When it's a mapped drive, I use this code to convert the path to a UNC one:

http://www.wiredprairie.us/blog/index.php/archives/22

It seems to work, so that's how I'll do it, unless someone comes up with a situation in which the first component of a UNC path isn't the host name...

Thank you all for your help.

You can also get account name of special accounts like "Everyone" with code like this that will work regardless of user's language settings:

   SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
   string everyone = everyoneSid.Translate(typeof(System.Security.Principal.NTAccount)).ToString();

This one is a stumper. You are in an Active Directory environment right? Just checking:)

Anyhow, instead of binding with sid.Value,

string str = "LDAP://<SID=" + sid.Value + ">";

I would try converting the SID's byte array to an Octet String and bind with that instead.

There is a sweet example here on page 78. This will get you closer. To be honest, I've not tried binding with a SID before. But I've had success binding with a user's GUID though :)

Good luck and let me know how it goes.

Get the current domain:

System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain();

Get a directory entry from ldap and the domain name:

DirectoryEntry de = new DirectoryEntry(string.Format("LDAP://{0}", domain));

Get the sid from an ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser:

ActiveDirectoryMembershipUser user = (ActiveDirectoryMembershipUser)Membership.GetUser();
var sid = (SecurityIdentifier)user.ProviderUserKey;

Get the username from the SecurityIdentifier:

(NTAccount)sid.Translate(typeof(NTAccount));

Get directory search done on an activedirectory with the domain directory entry and username:

DirectorySearcher search = new DirectorySearcher(entry);
        search.Filter = string.Format("(SAMAccountName={0})", username);
        search.PropertiesToLoad.Add("Name");
        search.PropertiesToLoad.Add("displayName");
        search.PropertiesToLoad.Add("company");
        search.PropertiesToLoad.Add("homePhone");
        search.PropertiesToLoad.Add("mail");
        search.PropertiesToLoad.Add("givenName");
        search.PropertiesToLoad.Add("lastLogon");
        search.PropertiesToLoad.Add("userPrincipalName");
        search.PropertiesToLoad.Add("st");
        search.PropertiesToLoad.Add("sn");
        search.PropertiesToLoad.Add("telephoneNumber");
        search.PropertiesToLoad.Add("postalCode");
        SearchResult result = search.FindOne();
        if (result != null)
        {
            foreach (string key in result.Properties.PropertyNames)
            {
                // Each property contains a collection of its own
                // that may contain multiple values
                foreach (Object propValue in result.Properties[key])
                {
                    outputString += key + " = " + propValue + ".<br/>";
                }
            }
        }

Depending on the data in your active directory, you will get a varied response in the output.

Here is a site that has all the user properties I needed:

driis

I am quite sure you will be able to use the accepted answer from here: Determine the LocalSystem account name using C#

Basically, you can translate an instance of the SecurityIdentifier class to type NTAccount, from which you can get the user name. In code:

using System.Security.Principal;

SecurityIdentifier sid = new SecurityIdentifier("S-1-5-18");
NTAccount acct = (NTAccount)sid.Translate(typeof(NTAccount));
Console.WriteLine(acct.Value);
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!