【问题标题】:Lock Active Directory accounts programmatically以编程方式锁定 Active Directory 帐户
【发布时间】:2008-10-07 14:33:00
【问题描述】:

我必须在 C# 中以编程方式锁定 Active Directory 中的用户帐户。

不幸的是,它不能通过 userAccountControl 属性起作用。每次我将 userAccountControl 设置为 528(=带有锁定标志的普通帐户)时,Active Directory 都不会接受该值并将其重置为 512(=普通帐户),而不另行通知。

现在我尝试通过提供不正确的凭据来锁定帐户(见下文),但这也不起作用。

int retries = 0;
while (!adsUser.IsAccountLocked && retries < MAX_LOCK_RETRIES)
{
     retries++;

    try
    {  
        new DirectoryEntry(userPath, logonName, incorrectPassword).RefreshCache();
    }
    catch (Exception)
    { 
        /* ... */ 
    }
    adsUser.GetInfo();
}

有什么想法吗?

【问题讨论】:

    标签: c# active-directory


    【解决方案1】:

    确保您用来禁用帐户的帐户具有足够的权限来禁用帐户。请参阅 Microsoft 的 this example

    【讨论】:

      【解决方案2】:

      此代码将用于在 AD 中锁定用户

      /// <summary>
      /// Locks a user account
      /// </summary>
      /// <param name="userName">The name of the user whose account you want to unlock</param>
      /// <remarks>
      /// This actually trys to log the user in with a wrong password. 
      /// This in turn will lock the user out
      /// </remarks>
      public void LockAccount(string userName)
      {
          DirectoryEntry user = GetUser(userName);
          string path = user.Path;
          string badPassword = "SomeBadPassword";
          int maxLoginAttempts = 10;
      
          for (int i = 0; i &lt maxLoginAttempts; i++)
          {
              try
              {
                  new DirectoryEntry(path, userName, badPassword).RefreshCache();
              }
              catch (Exception e)
              {
      
              }
          }
          user.Close();
      }
      

      【讨论】:

      • 这对我有用。不过,我必须自己实现 GetUser(userName) 方法。我在结果对象上使用了pc = PrincipalContext(ContextType.Domain)UserPrincipal.FindByIdentity(pc, userName).GetUnderlyingObject() 的组合(转换为DirectoryInfo)。不要忘记空检查;-)
      【解决方案3】:

      根据您的 Active Directory 策略,可能需要交互式登录尝试才能锁定帐户。您可以使用LogonUser method of advapi32.dll 模拟那些。在我的测试中,我发现运行此循环 100 次并不能保证在域控制器上尝试 100 次错误密码,因此您应该check the user is locked out 并在必要时进行更多尝试。

      这样做的底线是您应该禁用帐户而不是尝试锁定它。有no functional difference between locked and disabled accounts。下面的代码是一个 hack。

      using System;
      using System.Runtime.InteropServices;
      
      namespace Test
      {
          class Program
          {
              static void Main(string[] args)
              {
                  IntPtr token = IntPtr.Zero;
                  string userPrincipalName = "userID@domain.com";
                  string authority = null; // Can be null when using UPN (user principal name)
                  string badPassword = "bad";
      
                  int maxTries = 100;
                  bool res = false;
      
                  for (var i = 0; i < maxTries; i++)
                  {
                      res = LogonUser(userPrincipalName, authority, badPassword, LogonSessionType.Interactive, LogonProvider.Default, out token);
                      CloseHandle(token);
                  }
              }
      
              [DllImport("advapi32.dll", SetLastError = true)]
              static extern bool LogonUser(
                string principal,
                string authority,
                string password,
                LogonSessionType logonType,
                LogonProvider logonProvider,
                out IntPtr token);
      
              [DllImport("kernel32.dll", SetLastError = true)]
              static extern bool CloseHandle(IntPtr handle);
              enum LogonSessionType : uint
              {
                  Interactive = 2,
                  Network,
                  Batch,
                  Service,
                  NetworkCleartext = 8,
                  NewCredentials
              }
      
              enum LogonProvider : uint
              {
                  Default = 0, // default for platform (use this!)
                  WinNT35,     // sends smoke signals to authority
                  WinNT40,     // uses NTLM
                  WinNT50      // negotiates Kerb or NTLM
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

        一旦你有了目录条目对象,这将起作用。

        DirectoryEntry de = result.GetDirectoryEntry();
        int val = (int)de.Properties["userAccountControl"].Value;
        de.Properties["userAccountControl"].Value = val | 0x0002;
        

        【讨论】:

        • 这会禁用帐户,但不会锁定它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多