【问题标题】:Determine User Active Directory Groups from Local Machine off Network从网络外的本地计算机确定用户 Active Directory 组
【发布时间】:2013-07-16 21:14:51
【问题描述】:

我当前的项目要求我根据 Active Directory 组验证用户。问题是,计算机可能并不总是连接到域,但用户可能仍需要运行该工具。我了解在未连接时无法查询 Active Directory,而是尝试查询机器 SAM (MSAM)。

当我与网络断开连接时,我无法确定当前用户。这是我正在使用的:

PrincipalContext principalctx = new PrincipalContext(ContextType.Machine);
UserPrincipal uprincipal = new UserPrincipal(principalctx);

从这点来说,如何询问当前登录到本机的是谁。

连接到域后,我可以使用UserPrincipal.Current 进行查询。如果我没有连接到域,它将失败说"The server could not be contacted"。注意:使用上面的代码这个方法是不可用的,我可以放弃PrincipalContext,直接查询当前用户。识别出当前用户后,我可以查询 GetGroups() 并确定他们是否属于所需的组之一。

另外,有人可以描述三个ContextType 选项ApplicationDirectory, Domain, Machine。恐怕我没有完全理解每个选项,因此可能会错误地使用它。

【问题讨论】:

    标签: c# .net authentication active-directory


    【解决方案1】:

    从上到下:

    我当前的项目要求我针对 Active 验证用户 目录组。问题是,计算机可能并不总是 已连接到域,但用户可能仍需要运行该工具。

    此时,您因此必须接受攻击者能够绕过任何强制执行的安全性,因为它完全在客户端上强制执行。不完全是解决方案的一部分,但请记住。

    我了解我无法查询 Active Directory 已连接,而是尝试查询机器 SAM (MSAM)。

    Security Accounts Manager 仅存储本地帐户(MACHINENAME\Administrator 等)。它没有域用户凭据。您正在考虑 LSA cache,它会记住最后 N 个域登录的凭据(其中 N 是由组策略配置的从 0 到 50 的数字)和最后 N 个 SID 到名称的映射(默认为 128,configurable via registry) .安全帐户管理器仅将域帐户存储在域控制器上。

    我在确定当前用户时遇到问题 与网络断开连接。这是我正在使用的: PrincipalContext principalctx = new PrincipalContext(ContextType.Machine); UserPrincipal uprincipal = new UserPrincipal(principalctx);

    另外,有人可以描述三个 ContextType 选项吗 应用程序目录、域、机器。恐怕我没有完全 了解每个选项,因此可能会错误地使用它。

    如上所述,信息没有被缓存,但是ContextType枚举可以这样描述:

    来自 MSDN:

    • 域: 域存储。这表示 AD DS 存储。 (正如它所说,这是针对域帐户,如 Active Directory 的 LDAP 目录访问 - 这需要网络访问)
    • ApplicationDirectory: 应用程序目录存储。这代表 AD LDS 存储。 AD Lightweight Directory Services(以前称为 ADAM)是 Active Directory 的较小版本,旨在存储单个应用程序的凭据。它与本次讨论无关,但也使用 LDAP。)
    • 机器:电脑商店。这代表 SAM 存储。 (仅枚举本地帐户)

    从这一点来说,如何询问当前登录到本地的是谁 机器。

    您始终可以通过调用WindowsIdentity.GetCurrent() 检查登录用户。这将返回登录用户的 SID 和组 SID,如果登录发生在离线时,可能会被缓存。

    连接到域后,我可以使用 UserPrincipal.Current 进行查询。 如果我没有连接到域,它将失败说“服务器 无法联系”。注意:此方法不适用于使用 上面的代码,我可以直接放弃 PrincipalContext 查询当前用户。识别出当前用户后,我可以查询 GetGroups() 并确定它们是否在所需的组之一中。

    要确定组成员身份,请检查您想要的组的 SID 是否在 WindowsIdentity.GetCurrent 返回的标识中。如果您没有在访问控制系统中使用 SID,您可以通过调用 SecurityIdentifier.Translate 将名称转换为 SID。您需要在线翻译它,然后将其缓存以供离线使用。它可以以字符串或二进制形式存储,因此两者都适合注册表。

    // while we are online, translate the Group to SID
    // Obviously, administrators would be a bad example as it is a well known SID...
    var admins = new NTAccount("Administrators");
    var adminSid = (SecurityIdentifier)admins.Translate(typeof(SecurityIdentifier));
    
    // store the sid as a byte array on disk somewhere 
    byte[] adminSIDbytes = new byte[adminSid.BinaryLength];
    adminSid.GetBinaryForm(adminSIDbytes, 0);
    
    // at time of check, retrieve the sid and check membership
    var sidToCheck = new SecurityIdentifier(adminSIDbytes, 0);
    if (!wi.Groups.Contains(sidToCheck))
        throw new UnauthorizedAccessException("User is not a member of required group");
    

    【讨论】:

    • 感谢您的快速回复。这是一个惊人的细节。这为我解决了我的问题!
    【解决方案2】:

    另一种情况:

    • 如果您想使用 PrincipalContext 获取网络域名,请确保您已验证身份验证和授权。如下:get Network Domain name

    【讨论】:

      猜你喜欢
      • 2018-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-21
      • 2020-01-07
      • 1970-01-01
      • 1970-01-01
      • 2018-11-28
      相关资源
      最近更新 更多