Finding Windows User IDs in C #

Context

The first context - the problems I'm trying to solve are listed below.

[EDIT] The questions app is built on .NET 3.5 SP1.

One of our customers asked us to indicate how long it will take us to improve one of our applications. This application currently provides basic user authentication in the form of username and password combinations. This client would like their employees to be able to log in using information about which Windows user account is currently logged on when the application starts.

This is not a transaction breaker unless I tell them, but the client may wish to pay development costs to add this feature to the application. It is worth a look.

Based on my hunt, it seems that saving user data to enter a domain with the name \ username will be problematic if these details are changed. But the Windows SID SID should not change at all. I got the impression that it would be best to record Windows users by SID - feel free to release me if I'm wrong.

I had a fiddle with some Windows API calls. From within C #, capturing the user's current SID is quite simple. I can already use any user SID and process it using LookupAccountSid to get the username and domain to display. For those interested, my code for this is at the end of this post.

That's just the tip of the iceberg. The two questions below are completely outside my experience. I not only don’t know how to implement them - I don’t even know how to find out how to implement them, or what happens in different systems.

Any help aimed in the right direction would be greatly appreciated.

Problem 1)

Holding a local user at run time does not make sense if that user was not granted access to the application. We need to add a new section to the admin console to add Windows users (or groups) and assign permissions within the application for these users.

Something like the “Add Windows User User” button, which will bring up a pop-up window that allows the user to search for available Windows user accounts on the network (and not just on the local computer) to add to the list of available application logins.

If there is already a component in .NET or Windows that I can do for me, this will make me a very happy person.

Problem 2)

I also want to know how to take a given SID for a Windows user and check it for a given group of Windows users (probably taken from a database). I am not sure how to get started with this, although I expect it to be easier than the problem above.

For the user

[STAThread] static void Main(string[] args) { MessageBox.Show(WindowsUserManager.GetAccountNameFromSID(WindowsIdentity.GetCurrent().User.Value)); MessageBox.Show(WindowsUserManager.GetAccountNameFromSID("S-1-5-21-57989841-842925246-1957994488-1003")); } public static class WindowsUserManager { public static string GetAccountNameFromSID(string SID) { try { StringBuilder name = new StringBuilder(); uint cchName = (uint)name.Capacity; StringBuilder referencedDomainName = new StringBuilder(); uint cchReferencedDomainName = (uint)referencedDomainName.Capacity; WindowsUserManager.SID_NAME_USE sidUse; int err = (int)ESystemError.ERROR_SUCCESS; if (!WindowsUserManager.LookupAccountSid(null, SID, name, ref cchName, referencedDomainName, ref cchReferencedDomainName, out sidUse)) { err = Marshal.GetLastWin32Error(); if (err == (int)ESystemError.ERROR_INSUFFICIENT_BUFFER) { name.EnsureCapacity((int)cchName); referencedDomainName.EnsureCapacity((int)cchReferencedDomainName); err = WindowsUserManager.LookupAccountSid(null, SID, name, ref cchName, referencedDomainName, ref cchReferencedDomainName, out sidUse) ? (int)ESystemError.ERROR_SUCCESS : Marshal.GetLastWin32Error(); } } if (err != (int)ESystemError.ERROR_SUCCESS) throw new ApplicationException(String.Format("Could not retrieve acount name from SID. {0}", SystemExceptionManager.GetDescription(err))); return String.Format(@"{0}\{1}", referencedDomainName.ToString(), name.ToString()); } catch (Exception ex) { if (ex is ApplicationException) throw ex; throw new ApplicationException("Could not retrieve acount name from SID", ex); } } private enum SID_NAME_USE { SidTypeUser = 1, SidTypeGroup, SidTypeDomain, SidTypeAlias, SidTypeWellKnownGroup, SidTypeDeletedAccount, SidTypeInvalid, SidTypeUnknown, SidTypeComputer } [DllImport("advapi32.dll", EntryPoint = "GetLengthSid", CharSet = CharSet.Auto)] private static extern int GetLengthSid(IntPtr pSID); [DllImport("advapi32.dll", SetLastError = true)] private static extern bool ConvertStringSidToSid( string StringSid, out IntPtr ptrSid); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool LookupAccountSid( string lpSystemName, [MarshalAs(UnmanagedType.LPArray)] byte[] Sid, StringBuilder lpName, ref uint cchName, StringBuilder ReferencedDomainName, ref uint cchReferencedDomainName, out SID_NAME_USE peUse); private static bool LookupAccountSid( string lpSystemName, string stringSid, StringBuilder lpName, ref uint cchName, StringBuilder ReferencedDomainName, ref uint cchReferencedDomainName, out SID_NAME_USE peUse) { byte[] SID = null; IntPtr SID_ptr = IntPtr.Zero; try { WindowsUserManager.ConvertStringSidToSid(stringSid, out SID_ptr); int err = SID_ptr == IntPtr.Zero ? Marshal.GetLastWin32Error() : (int)ESystemError.ERROR_SUCCESS; if (SID_ptr == IntPtr.Zero || err != (int)ESystemError.ERROR_SUCCESS) throw new ApplicationException(String.Format("'{0}' could not be converted to a SID byte array. {1}", stringSid, SystemExceptionManager.GetDescription(err))); int size = (int)GetLengthSid(SID_ptr); SID = new byte[size]; Marshal.Copy(SID_ptr, SID, 0, size); } catch (Exception ex) { if (ex is ApplicationException) throw ex; throw new ApplicationException(String.Format("'{0}' could not be converted to a SID byte array. {1}.", stringSid, ex.Message), ex); } finally { // Always want to release the SID_ptr (if it exists) to avoid memory leaks. if (SID_ptr != IntPtr.Zero) Marshal.FreeHGlobal(SID_ptr); } return WindowsUserManager.LookupAccountSid(lpSystemName, SID, lpName, ref cchName, ReferencedDomainName, ref cchReferencedDomainName, out peUse); } } 
+4
source share
1 answer

If you are using version 3.5 of the framework, you really want to see System.DirectoryServices.AccountManagement . I used it before to provide an AD account lookup, and it's much easier than writing my own class. He will also solve your issue # 2. I don’t have the code at hand, but if you need it, I can always find it.

+3
source

Source: https://habr.com/ru/post/1308825/


All Articles