我使用ActiveDirectory服务器查询用户所属的组。我想获取用户所属的所有群组,但使用网络API的Network Management funcions。
我意识到已存在一个名为NetUserGetGroups的函数,但遗憾的是,此函数不包含成员间接所属的组。
例如,如果我有以下结构:
MyGroup1
|_ MyGroup2
|_ MyUser
MyGroup2
public static List<string> GetUserGroupsAD(string dc, string userName)
{
var result = new List<string>();
try
{
using (var context = new PrincipalContext(
ContextType.Domain, dc.Replace("\\", "")))
{
var user = UserPrincipal.FindByIdentity(context, userName);
var groups = user.GetAuthorizationGroups();
foreach (Principal p in groups2)
result.Add(p.Name);
}
}
catch (Exception ex)
{
Console.WriteLine("An error happened in GetUserGroups", ex);
}
return result;
}
此代码返回:
MyGroup1 <-- this is what I need, loading the indirect groups!
MyGroup2
(and others)
问题是我使用.NET2 ,我无法访问System.DirectoryServices。我只能访问NetworkAPI。
有人知道如何使用NetworkAPI实现user.GetAuthorizationGroups()
调用?
答案 0 :(得分:5)
解决方案是使用AuthzAPI。以下代码加载给定用户SID的用户组。结果与user.GetAuthorizationGroups()
调用检索的结果相同:
static List<string> GetSidGroupsFromSid(sbyte[] sid_bytes)
{
List<string> result = new List<string>();
IntPtr clientContext = IntPtr.Zero;
IntPtr resourceManager = IntPtr.Zero;
IntPtr buffer = IntPtr.Zero;
LUID unusedLuid = new LUID();
bool success;
try
{
success = AuthzInitializeResourceManager(
(int)AuthzResourceManagerFlags.NO_AUDIT,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
string.Empty,
out resourceManager);
ThrowLastError(success);
success = AuthzInitializeContextFromSid(
(int)AuthzContextFlags.NONE,
sid_bytes, resourceManager,
IntPtr.Zero, unusedLuid,
IntPtr.Zero,
out clientContext);
ThrowLastError(success);
int pSizeRequired = 0;
success = AuthzGetInformationFromContext(
clientContext,
(int)AuthContextInformation.AuthzContextInfoGroupsSids,
0,
out pSizeRequired,
IntPtr.Zero);
if (!success && pSizeRequired > 0 && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
{
buffer = Marshal.AllocHGlobal(pSizeRequired);
success = AuthzGetInformationFromContext(clientContext, 2, pSizeRequired, out pSizeRequired, buffer);
ThrowLastError(success);
TOKEN_GROUPS groups = ((TOKEN_GROUPS)Marshal.PtrToStructure(buffer, typeof(TOKEN_GROUPS)));
IntPtr ptr = new IntPtr(buffer.ToInt64() + (long)Marshal.SizeOf(typeof(TOKEN_GROUPS)) - (long)Marshal.SizeOf(typeof(IntPtr)));
for (int index = 0; index < groups.groupCount; ++index)
{
SID_AND_ATTR currentSid = (SID_AND_ATTR)Marshal.PtrToStructure(ptr, typeof(SID_AND_ATTR));
ptr = new IntPtr(ptr.ToInt64() + (long)Marshal.SizeOf(typeof(SID_AND_ATTR)));
string sidString = "";
NetWorkAPI.ConvertSidToStringSid(currentSid.pSid, ref sidString);
result.Add(sidString);
}
}
}
finally
{
if (clientContext != IntPtr.Zero)
{
success = AuthzFreeContext(clientContext);
ThrowLastError(success);
}
if (resourceManager != IntPtr.Zero)
{
success = AuthzFreeResourceManager(resourceManager);
ThrowLastError(success);
}
if (buffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(buffer);
}
}
return result;
}
static void ThrowLastError(bool success)
{
if (success)
return;
int err = Marshal.GetLastWin32Error();
Win32Exception win32Exception = new Win32Exception(err);
throw new Exception("Authz error " + err + ": " + win32Exception.Message);
}
const int ERROR_INSUFFICIENT_BUFFER = 122;
[Flags]
enum AuthzResourceManagerFlags : int
{
NONE = 0,
NO_AUDIT = 0x1,
INITIALIZE_UNDER_IMPERSONATION = 0x2,
VALID_INIT_FLAGS = (NO_AUDIT | INITIALIZE_UNDER_IMPERSONATION),
};
[Flags]
enum AuthzContextFlags : int
{
NONE = 0,
SKIP_TOKEN_GROUPS = 0x2,
REQUIRE_S4U_LOGON = 0x4,
COMPUTE_PRIVILEGES = 0x8
};
[StructLayout(LayoutKind.Sequential)]
struct LUID
{
public uint LowPart;
public int HighPart;
};
enum AuthContextInformation : int
{
AuthzContextInfoUserSid = 1,
AuthzContextInfoGroupsSids = 2
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
sealed class TOKEN_GROUPS
{
public int groupCount;
public IntPtr groups = IntPtr.Zero;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
sealed class SID_AND_ATTR
{
public IntPtr pSid = IntPtr.Zero;
public int attrs;
}
[DllImport(
"authz.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
static extern bool AuthzInitializeResourceManager(
int flags,
IntPtr pfnAccessCheck,
IntPtr pfnComputeDynamicGroups,
IntPtr pfnFreeDynamicGroups,
string name,
out IntPtr rm);
[DllImport(
"authz.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
static extern bool AuthzInitializeContextFromSid(
int Flags,
sbyte[] userSid,
IntPtr AuthzResourceManager,
IntPtr pExpirationTime,
LUID Identitifier,
IntPtr DynamicGroupArgs,
out IntPtr pAuthzClientContext);
[DllImport(
"authz.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall,
SetLastError = true)]
static extern bool AuthzGetInformationFromContext(
IntPtr hAuthzClientContext,
int InfoClass,
int BufferSize,
out int pSizeRequired,
IntPtr Buffer);
[DllImport(
"authz.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall)]
static extern bool AuthzFreeContext(
IntPtr AuthzClientContext);
[DllImport(
"authz.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall)]
static extern bool AuthzFreeResourceManager(IntPtr rm);