如何使用admin creds运行c#应用程序?

我编写了一个C#应用程序,可以在用户被锁定帐户(Active Directory)时解锁用户。 应用程序搜索特定OU中的用户,并在ComboBox中列出已锁定的用户。 然后从ComboBox中选择该用户并选择解锁。

如果您以管理员身份登录,则可以完美运行。 如果你是普通用户没有。

我想用admin creds运行我的应用程序,但在普通用户下也尽可能安全。

我正在阅读那可能是一个Windows服务程序,但我不清楚如何编程我的应用程序安装,作为服务运行,并在管理员信任下运行。

看起来你想冒充管理员用户。 这是一篇文章和演示 。 看起来是用.Net 1写的,但应该让你入门。 另请查看WindowsIdentity类。

这个应用程序背后的目标让我感到错误。 您基本上是在尝试创建一种允许非管理员用户解锁帐户的方法……这是有充分理由的普通用户无法使用的function。

您不必使用Windows服务来执行其他操作。 您可以使用模拟以另一个用户身份登录以进行实际切换。 这是我发现使用windows dll“advapi32.dll”登录的一个例子。

从页面底部抓取示例代码。 我不想在这里复制他的代码。

http://csharptuning.blogspot.com/2007/06/impersonation-in-c.html

然而,模拟的一个问题是,进行模拟的计算机需要与您模仿的用户位于同一个域中。

这是我用于在Windows 2000上运行的ASP.NET 2.0网站上执行模拟的类。

用法示例:

if (iu.impersonateValidUser("AdminUserName", "DomainName", "AdminPassword")) { // Do Something Under Other Users Security Context iu.undoImpersonation(); } 

就是这样……下面的完整课程。

 using System; using System.Runtime.InteropServices; using System.Security.Principal; public class ImpersonateUser { public const int LOGON32_LOGON_INTERACTIVE = 2; public const int LOGON32_PROVIDER_DEFAULT = 0; WindowsImpersonationContext impersonationContext; [DllImport("advapi32.dll")] public static extern int LogonUserA(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool RevertToSelf(); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public static extern bool CloseHandle(IntPtr handle); public bool impersonateValidUser(String userName, String domain, String password) { WindowsIdentity tempWindowsIdentity; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; if (RevertToSelf()) { if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0) { if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) { tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); impersonationContext = tempWindowsIdentity.Impersonate(); if (impersonationContext != null) { CloseHandle(token); CloseHandle(tokenDuplicate); return true; } } } } if (token != IntPtr.Zero) CloseHandle(token); if (tokenDuplicate != IntPtr.Zero) CloseHandle(tokenDuplicate); return false; } public void undoImpersonation() { impersonationContext.Undo(); } } 

您无法使用Windows服务(轻松),因为Windows服务无法使用GUI。 作为服务执行此操作的唯一方法是安装服务,然后创建一个使用IPC将请求传达给服务的GUI应用程序。 但这会打开潜在的漏洞。

如果您在Vista上运行,一个很好的选择是编辑清单文件并添加requireAdministrator。


编辑:

这听起来像我的第一个建议可能是你想要的……为此,基本过程是:

  • 使您的应用程序成为Windows服务。 这个过程在MSDN上有一个演练 。
  • 让您的服务响应某种forms的IPC。 您可以使用套接字,管道或任何其他forms的通信。 该服务将“监听”取消阻止用户的请求,然后执行此操作。
  • 在机器上安装服务。 这将使其以管理员身份运行,并始终开启。
  • 制作第二个应用程序以充当客户端。 使用相同的IPC技术与服务器通信。 这将发送请求以取消阻止客户端到服务。

然后,您可以作为普通用户运行客户端(因为它只需要与服务通信,它不会执行任何需要权限的操作)。

我的内部网站点上有一个非常相似的小部件,因此位于不同时区的IT部门的成员可以处理密码重置,当西海岸的域管理员不可用时,还会执行帐户解锁。 这是一个非常简单的任务,除了我是如何做到这一点之外……

  using System.DirectoryServices; // Impersonate the Admin to Reset the Password / Unlock Account // // Change variables below. ImpersonateUser iu = new ImpersonateUser(); if (iu.impersonateValidUser("AdminUserName", "DomainName", "AdminPassword")) { resetPassword("AdminUserName", "AdminPassword", UserToReset, "NewPassword"); iu.undoImpersonation(); } // Perform the Reset / Unlock // public void resetPassword(string username, string password, string acct, string newpassword) { string Path = // LDAP Connection String string Username = username; string Password = password; string Domain = "DomainName\\"; // Change to your domain name DirectoryEntry de = new DirectoryEntry(Path, Domain + Username, Password, AuthenticationTypes.Secure); DirectorySearcher ds = new DirectorySearcher(de); ds.Filter = "(&(objectClass=user)(|(sAMAccountName=" + acct + ")))"; ds.PropertiesToLoad.Add("displayName"); ds.PropertiesToLoad.Add("sAMAccountName"); ds.PropertiesToLoad.Add("DistinguishedName"); ds.PropertiesToLoad.Add("CN"); SearchResult result = ds.FindOne(); string dn = result.Properties["DistinguishedName"][0].ToString(); DirectoryEntry uEntry = new DirectoryEntry("LDAP://" + dn, username, password); uEntry.Invoke("SetPassword", new object[] { newpassword }); uEntry.Properties["LockOutTime"].Value = 0; uEntry.CommitChanges(); uEntry.Close(); } 

我非常同意这可能导致安全问题,如果使用不当,我们会记录每个更改并通过电子邮件发送给域管理员(因此他们在循环中),我们会自动生成密码。 这对我们的小型IT部门来说是一个巨大的帮助,因为管理员不再需要在凌晨4点醒来重置密码。

此代码将允许您调用另一个可执行文件并运行它是管理员。

 try { path = path_to_your_executable; ProcessStartInfo myProcess = new ProcessStartInfo(path); myProcess.Domain = domain; myProcess.UserName = username; myProcess.Password = password; myProcess.UseShellExecute = false; Process.Start(myProcess); } catch (Exception myException) { // error handling } 

不完全是你想要的,但它是一个可能的解决方案。