在Windows模拟上下文下的程序集绑定。如何防止FileLoadException错误?

5
我有一个应用程序需要进行大量的模拟操作,因为需要在受保护的网络共享中移动和创建许多文件。我创建了一个简单的静态类,其中包含一个方法,该方法接受用户、域、密码和一个委托,该委托包含需要在模拟上下文中运行的代码。
我遇到的问题是当CLR尝试在此上下文中绑定到引用的程序集时。会抛出一个'Access is denied'消息的FileLoadException异常。
我认为这是由于被模拟用户在文件系统下没有足够的权限访问*.DLL文件。例如,我可以在模拟块之前编写无害的代码,仅在上下文切换到模拟用户之前从问题程序集中加载类型,这样就可以解决问题!但是我并不认为这是一种优雅的解决方案 - 我需要开始担心在模拟下可以使用哪些类型,确保我先放置随机的typeof()语句吗?
更令人沮丧的是,在我的本地开发机器上没有遇到这个问题。只有当程序集被发送到测试环境时才会出现这个问题。而我无法访问测试环境的文件权限以尝试在我的本地机器上模仿它们。
无论如何,我尝试了这个解决方案:
// Defined above:
// System.Security.Principal.WindowsIdentity identity;
// System.Security.Principal.WindowsImpersonationContext context;

context = identity.Impersonate();

int tries = 0;
while ( true )
{
    try
    {
        contextAction();
    }
    catch ( FileLoadException ex )
    {
        if ( tries > MAX_TRIES )
        {
            // don't allow an infinite loop
            throw;
        }
        if ( String.IsNullOrEmpty( ex.FileName ) )
        {
            // if this is null/empty, we can't really recover
            throw;
        }
        context.Undo(); // return to current logon
        try
        {
            var assemblyName = new AssemblyName( ex.FileName );
            Assembly.Load( assemblyName );
            tries++;
            continue;
        }
        finally
        {
            context = identity.Impersonate(); // re-impersonate
        }
    }   
    finally
    {
        // return to your current windows logon
        context.Undo();
    }
}

没有用。我仍然会收到“访问被拒绝”的异常,只是现在是从以Assembly.Load开头的那一行开始。值得注意的是,我在构建服务器上也遇到了相同的异常。上面的解决方案可以在构建服务器上解决问题,但无法在我们的测试环境中解决。请问我错过了什么?谢谢。
4个回答

3
我遇到了同样的问题。似乎这是与模拟“会话”未被正确清理有关的问题。在调用逻辑之前加载有问题的程序集可以正常工作。在撤消和处理模拟身份和上下文后尝试加载程序集会导致另一个FileLoadException。 另一个线程显示了示例代码,其中他们关闭了令牌句柄,但在我的测试代码中这样做没有任何区别。 编辑 在模拟代码之前和之后调用System.Security.Principal.WindowsIdentity.GetCurrent()返回相同的信息,即使某些内容必须已更改以不再允许加载有问题的程序集。 编辑#2(现在具有100%的解决方案! 我们在网络应用程序中发现了一个严重的问题。创建身份和关闭句柄的过程不正确。我们在多线程应用程序中遇到了严重的问题,当所有句柄用完时,我们的网站最终停止了运行。经过与其他开发人员的讨论和在线研究(包括this thread中倒数第二篇文章中的提示),我改进了代码,使得令牌句柄得到正确清理。
这似乎也解决了我们在模拟上下文中加载程序集的问题。无论我如何尝试,都无法再次复现错误。我将在此处发布我们改进的模拟操作代码,以便您可以查看它是否适用于您的应用程序。请注意,在GetIdentity中的锁定块对于多线程应用程序非常重要。
// LogonType = 8        // LOGON32_LOGON_NETWORK_CLEARTEXT
// LogonProvider = 0    // LOGON32_PROVIDER_DEFAULT

[DllImport ( "advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true )]
private static extern bool LogonUser( string userName, string domain,
    string password, int logonType, int logonProvider, ref IntPtr accessToken );

[DllImport ( "kernel32.dll", SetLastError = true )]
private static extern bool CloseHandle( IntPtr handle );

private static readonly object Locker = new Object ();

private static WindowsIdentity GetIdentity( string username, string domain, string password )
{
    lock ( Locker )
    {
        IntPtr token = IntPtr.Zero;
        if ( LogonUser ( username, domain, password,
            (int) LogonType, (int) LogonProvider, ref token ) )
        {
            // using the token to create an instance of WindowsIdentity class
            var identity = new WindowsIdentity ( token );
            CloseHandle ( token ); // the WindowsIdentity object duplicates this token internally
            return identity;
        }

        throw new SecurityException ( string.Format (
            "Invalid username/password (domain: '{0}', username: '{1}')",
            domain, username ) );
    }
}

public static T ExecuteAction<T>( string username, string domain, string password,
    Func<T> contextAction )
{
    var identity = GetIdentity ( username, domain, password );
    var context = identity.Impersonate ();
    try
    {

        return contextAction ();
    }
    finally
    {
        context.Undo ();
        context.Dispose ();
    }
}

0
你可以将“有问题的”程序集放在 GAC 中。
或者,在模拟用户之前,动态添加可继承的“读取和执行”权限,以授予所要模拟的用户对包含那些程序集的目录的访问权限。我假设您可以控制这些有问题程序集的位置?

0

我遇到了一个类似的问题; 当我尝试加载一个库时,我会得到“拒绝访问”的错误。在我的情况下,我需要进入Windows资源管理器并授予我所模拟的用户对程序运行的整个文件夹的完全访问权限(出于某种原因,必须是整个文件夹,而不仅仅是我收到异常的特定DLL文件)。

我不确定这是否有助于您的具体问题,但希望这可以帮助未来遇到与我相同问题的读者。


0

我不确定问题出在哪里,但是当一个非管理员用户账户冒充管理员时,Windows模拟身份验证并不起作用。可能是因为你的最终用户是一个非管理员用户,当你尝试模拟身份验证时,它会失败导致文件访问错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接