从其他域获取用户AD组

时间:2011-02-15 14:41:56

标签: c# .net authentication active-directory

我遇到UserPrincipal.GetGroups()和GetAuthorizationGroups()方法的问题。有时它有效,有时不行。问题是在不成功的情况下,该方法接触不良的AD域。我的开发PC与公司有关 域和我想在其他PC测试域中获取用户组。

我的代码:

var ctx = new PrincipalContext(ContextType.Domain, "test.int", "user1@test.int", "pwd123");
ctx.ValidateCredentials("user1@test.int", "pwd123"); //returns always true
var adUser = UserPrincipal.FindByIdentity(ctx, IdentityType.UserPrincipalName, "user1@test.int");
var groups = adUser.GetAuthorizationGroups(); //sometimes exception...

它引发了ActiveDirectoryServerDownException - RPC服务器不可用。这是因为 在这种情况下,方法调用想要与公司DC服务器通信,而不是与 测试域!

我的开发环境: - 服务器:DC + DNS服务器W2003,单DC域“test.int”,DNS有“company.int”DNS作为其转发器,但同样的问题,如果转发器被禁用。

  • 我的电脑:连接到“company.int”域,只使用测试DC的DNS服务器,与服务器相同的LAN网络

我没找到方法,如何强制连接到测试DC服务器。

2 个答案:

答案 0 :(得分:2)

如果您来自不受信任的域,

GetAuthroizationGroups()将无效。这是因为它正在调用Authz.dll。我只是在我的两个测试域中尝试了它而没有信任。它失败并使用以下callstack抛出异常

at System.DirectoryServices.AccountManagement.AuthZSet..ctor(Byte[] userSid, NetCred credentials, ContextOptions contextOptions, String flatUserAuthority, StoreCtx userStoreCtx, Object userCtxBase)
at System.DirectoryServices.AccountManagement.ADStoreCtx.GetGroupsMemberOfAZ(Principal p)
at System.DirectoryServices.AccountManagement.UserPrincipal.GetAuthorizationGroupsHelper()
at System.DirectoryServices.AccountManagement.UserPrincipal.GetAuthorizationGroups()
at TestDomain.Form1.Form1_Load(Object sender, EventArgs e) in C:\Testbench\TestDomain\TestDomain\Form1.cs:line 69

我反汇编System.DirectoryServices.AccountManagement.dll。这是代码。我认为它在AuthzInitializeContextFromSid失败了。

[SecurityCritical]
internal AuthZSet(byte[] userSid, NetCred credentials, ContextOptions contextOptions, string flatUserAuthority, StoreCtx userStoreCtx, object userCtxBase)
{
    this.currentGroup = -1;
    this.contexts = new Hashtable();
    this.localMachineIsDC = null;
    this.userType = userStoreCtx.OwningContext.ContextType;
    this.userCtxBase = userCtxBase;
    this.userStoreCtx = userStoreCtx;
    this.credentials = credentials;
    this.contextOptions = contextOptions;
    this.flatUserAuthority = flatUserAuthority;
    this.contexts[flatUserAuthority] = userStoreCtx.OwningContext;
    IntPtr zero = IntPtr.Zero;
    IntPtr rm = IntPtr.Zero;
    IntPtr buffer = IntPtr.Zero;
    try
    {
        UnsafeNativeMethods.LUID identitifier = new UnsafeNativeMethods.LUID();
        identitifier.low = 0;
        identitifier.high = 0;
        this.psMachineSid = new SafeMemoryPtr(Utils.GetMachineDomainSid());
        this.psUserSid = new SafeMemoryPtr(Utils.ConvertByteArrayToIntPtr(userSid));
        int num = 0;
        bool flag = UnsafeNativeMethods.AuthzInitializeResourceManager(UnsafeNativeMethods.AUTHZ_RM_FLAG.AUTHZ_RM_FLAG_NO_AUDIT, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, null, out rm);
        if (flag)
        {
            flag = UnsafeNativeMethods.AuthzInitializeContextFromSid(0, this.psUserSid.DangerousGetHandle(), rm, IntPtr.Zero, identitifier, IntPtr.Zero, out zero);
            if (flag)
            {
                int pSizeRequired = 0;
                flag = UnsafeNativeMethods.AuthzGetInformationFromContext(zero, 2, 0, out pSizeRequired, IntPtr.Zero);
                if ((!flag && (pSizeRequired > 0)) && (Marshal.GetLastWin32Error() == 0x7a))
                {
                    buffer = Marshal.AllocHGlobal(pSizeRequired);

正如您在上面所看到的那样,NetCred credentials被传入并且从未使用过。它正在呼叫AuthzInitializeContextFromSid。如果您查看MSDN,他们有以下免责声明。

  

重要应用程序不应该   假设调用上下文有   允许使用此功能。

我无法解释为什么它有时适用于您的环境,有时却不适用。它始终不适用于我的环境。我想一个可能的原因是你从工作站访问了不受信任的域控制器并按下了“存储的凭据”。这将存储网络凭据,每当您联系该特定计算机时,Windows将自动为您使用存储的凭据。另一个可能的原因是您在这两个域中使用相同用户名的相同密码。

要解决此问题,我只需对用户使用GetGroups(),然后在其所有组上调用GetGroups()即可。重复它直到您到达顶级组。您可能还想检查它是否是安全组。您可能只想跳过所有通讯组。 GetGroup()方法返回安全组和通讯组。

答案 1 :(得分:0)

据我所知,你必须使用PrincipalContext上的 NetBIOS 域名 - 而不是任何DNS风格的域名。

所以改变这个:

var ctx = new PrincipalContext(ContextType.Domain, "test.int", "user1@test.int", "pwd123");
                                                   *********** 

类似于:

var ctx = new PrincipalContext(ContextType.Domain, "INTTEST", "user1@test.int", "pwd123");
                                                   ***********