繁体   English   中英

通过登录名c#获得另一用户的文件许可

[英]Get permission to a file for another user by login name c#

如何确定其他用户(按登录名)是否有权读取文件?

这是否要求我必须使用DirectoryInfo.GetAccessControl()。GetAccessRules(...)来获取特定文件的访问控制列表,然后在AD中查询目标用户的AD组成员身份的完整列表(直接或间接)然后比较是否有与目标文件关联的匹配组?

还有其他方法吗? 由于用户可能拥有庞大的组成员身份,因此其中一些AD查询需要30秒。

如果登录的用户可以访问文件,则Windows可以非常快速地解决问题。 如果有人可以了解它的执行方式,那么我可以进行相同的方法调用来检查其他用户是否具有访问权限,那么请告诉我。

我需要执行此操作的原因是因为我在网页上具有链接以从网络驱动器返回文件。 某些浏览器(例如chrome)无法重定向到UNC路径,因此它们被重定向到使用模拟的.NET处理程序/页面。 由于两次跳转,处理程序无法以.NET模拟用户的身份访问UNC路径,因此,我需要使用服务帐户,但是它需要确定是否允许通过登录的特定用户在读取文件之前归还它。

任何替代方案都欢迎。

Windows提供了AccessCheck功能,请注意,被检查的用户由令牌表示。 正如NetMage所说,组成员资格仅在令牌创建期间从AD中提取并缓存,因此不必为每次安全检查重复。

具有类似功能但接口更简单的函数是GetEffectiveRightsFromAcl

我不知道是否有使用.NET SecurityPrincipal进行此操作的托管API。 可能是您必须p /调用AccessCheck 绝对不建议尝试复制用于检查ACL的逻辑。

对于其他需要这样做的人。 这就是我所做的。

    [DllImport("advapi32.dll")]
    private static extern uint GetEffectiveRightsFromAcl(byte[] pacl, ref TRUSTEE pTrustee, ref uint pAccessRights);

    private enum MULTIPLE_TRUSTEE_OPERATION
    {
        NO_MULTIPLE_TRUSTEE,
        TRUSTEE_IS_IMPERSONATE
    }

    private enum TRUSTEE_FORM
    {
        TRUSTEE_IS_SID,
        TRUSTEE_IS_NAME,
        TRUSTEE_BAD_FORM,
        TRUSTEE_IS_OBJECTS_AND_SID,
        TRUSTEE_IS_OBJECTS_AND_NAME
    }

    private enum TRUSTEE_TYPE
    {
        TRUSTEE_IS_UNKNOWN,
        TRUSTEE_IS_USER,
        TRUSTEE_IS_GROUP,
        TRUSTEE_IS_DOMAIN,
        TRUSTEE_IS_ALIAS,
        TRUSTEE_IS_WELL_KNOWN_GROUP,
        TRUSTEE_IS_DELETED,
        TRUSTEE_IS_INVALID,
        TRUSTEE_IS_COMPUTER
    }

    private struct TRUSTEE
    {
        public IntPtr pMultipleTrustee;
        public MULTIPLE_TRUSTEE_OPERATION MultipleTrusteeOperation;
        public TRUSTEE_FORM TrusteeForm;
        public TRUSTEE_TYPE TrusteeType;
        public IntPtr ptstrName;
    }

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern void BuildTrusteeWithSid(
        ref TRUSTEE pTrustee,
        byte[] sid
    );

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool QueryServiceObjectSecurity(SafeHandle serviceHandle, System.Security.AccessControl.SecurityInfos secInfo, byte[] lpSecDesrBuf, uint bufSize, out uint bufSizeNeeded);

    // Reference for these flags: https://msdn.microsoft.com/en-us/library/system.directoryservices.activedirectoryrights(v=vs.110).aspx
    [System.FlagsAttribute]
    public enum ServiceAccessFlags : uint
    {
        QueryConfig = 1,
        ChangeConfig = 2,
        QueryStatus = 4,
        EnumerateDependents = 8,
        Start = 16,
        Stop = 32,
        PauseContinue = 64,
        Interrogate = 128,
        UserDefinedControl = 256,
        Delete = 65536,
        ReadControl = 131072,
        WriteDac = 262144,
        WriteOwner = 524288,
        Synchronize = 1048576,
        AccessSystemSecurity = 16777216,
        GenericAll = 268435456,
        GenericExecute = 536870912,
        GenericWrite = 1073741824,
        GenericRead = 2147483648
    }

    public enum EXTENDED_NAME_FORMAT
    {
        NameUnknown = 0,
        NameFullyQualifiedDN = 1,
        NameSamCompatible = 2,
        NameDisplay = 3,
        NameUniqueId = 6,
        NameCanonical = 7,
        NameUserPrincipal = 8,
        NameCanonicalEx = 9,
        NameServicePrincipal = 10,
        NameDnsDomain = 12
    }

    [DllImport("secur32.dll", CharSet = CharSet.Auto)]
    public static extern int GetUserNameEx(int nameFormat, StringBuilder userName, ref int userNameSize);

    public static string GetUserUpn()
    {
        string upn = null;
        StringBuilder userName = new StringBuilder(1024);
        int userNameSize = userName.Capacity;
        if (GetUserNameEx((int)EXTENDED_NAME_FORMAT.NameUserPrincipal, userName, ref userNameSize) != 0)
        {
            upn = userName.ToString();
        }
        return upn;
    }

    /// <summary>
    /// Returns the user access flags by path and UPN. This can be used to determine the level of access another user has to a file.
    /// </summary>
    public static ServiceAccessFlags? GetUserPermission(string path, string upn)
    {
        WindowsIdentity windowsIdentity = new WindowsIdentity(upn);

        DirectoryInfo di = new DirectoryInfo(path);
        DirectorySecurity ds = di.GetAccessControl();

        RawSecurityDescriptor rsd = new RawSecurityDescriptor(ds.GetSecurityDescriptorBinaryForm(), 0);
        RawAcl racl = rsd.DiscretionaryAcl;
        DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, racl);

        byte[] daclBuffer = new byte[dacl.BinaryLength];
        dacl.GetBinaryForm(daclBuffer, 0);

        SecurityIdentifier sid = windowsIdentity.User;
        byte[] sidBuffer = new byte[sid.BinaryLength];
        sid.GetBinaryForm(sidBuffer, 0);

        TRUSTEE t = new TRUSTEE();
        BuildTrusteeWithSid(ref t, sidBuffer);

        uint access = 0;
        uint hr = GetEffectiveRightsFromAcl(daclBuffer, ref t, ref access);

        ServiceAccessFlags serviceAccess = (ServiceAccessFlags)access;

        int i = Marshal.Release(t.ptstrName);

        return serviceAccess;
    }

用法示例:

FileService.ServiceAccessFlags? flags = null;
try { flags = FileService.GetUserPermission(uncFilePath, upn); } 
catch (DirectoryNotFoundException ex)
{
    LogWarning("Could not resolve permission because the file was not found as the service account (" + FileService.GetUserUpn() + ")");
}
catch (Exception ex)
{
    LogWarning("Could not resolve permission on this file (" + FileService.GetUserUpn() + "): " + ex.Message);
}
if (flags.HasValue)
{
    // Check for Read access
    if ((flags.Value & FileService.ServiceAccessFlags.ReadControl) == FileService.ServiceAccessFlags.ReadControl)
    {
        hasPermission = true;
        LogMessage("User has access (upn: " + upn + "): " + flags.ToString());
    }
    else
    {
        hasPermission = false;
        LogError("User does not have read access to file (upn: " + upn + "): " + flags.ToString());
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM