Права доступа к файлу с FileSystemObject - CScript.exe говорит одно, классический ASP - другое - PullRequest
6 голосов
/ 07 мая 2010

У меня есть классическая страница ASP, написанная на JScript, в которой используется Scripting.FileSystemObject для сохранения файлов в сетевой папке - и она не работает. («В доступе отказано»)

Страница ASP работает под IIS с использованием аутентификации Windows с включенным олицетворением.

Если я запускаю следующий блок кода локально через CScript.exe:

var objNet = new ActiveXObject("WScript.Network");
WScript.Echo(objNet.ComputerName);
WScript.Echo(objNet.UserName);
WScript.Echo(objNet.UserDomain);

var fso = new ActiveXObject("Scripting.FileSystemObject");
var path = "\\\\myserver\\my_share\\some_path";
if (fso.FolderExists(path)) {
    WScript.Echo("Yes");
} else {
    WScript.Echo("No");
}

Я получаю (ожидаемый) вывод:

MY_COMPUTER
dylan.beattie
MYDOMAIN
Yes

Если я запускаю тот же код, что и часть страницы .ASP, заменяя Response.Write на WScript.Echo, я получаю следующий вывод:

MY_COMPUTER
dylan.beattie
MYDOMAIN
No

Теперь, насколько я понимаю, объект WScript.Network будет извлекать текущие учетные данные безопасности потока, который фактически выполняет код. Если это правильно, то почему один и тот же пользователь в одном домене получает разные результаты от CScript.exe против ASP? Если мой ASP-код работает как dylan.beattie, то почему я не вижу сетевой ресурс? И если он не работает как dylan.beattie, почему WScript.Network так считает?

Ответы [ 2 ]

4 голосов
/ 10 мая 2010

Ваша проблема ясна.В текущей реализации у вас есть только олицетворение пользователей и отсутствие делегирования.Я не хочу повторять информацию, уже написанную Стивеном Мартином.Я только хочу добавить как минимум три решения.Классический способ делегирования, который предлагает Стивен Мартин, - это только один способ.Вы можете прочитать еще несколько способов здесь: http://msdn.microsoft.com/en-us/library/ff647404.aspx#paght000023_delegation. Я вижу три практических способа решения вашей проблемы:

  1. Преобразование токена олицетворения пользователя в токен с уровнем делегированияподражания или нового первичного токена.Вы можете сделать это в отношении DuplicateToken или DuplicateTokenEx.

  2. Использование S4U2Self (см. http://msdn.microsoft.com/en-us/magazine/cc188757.aspx и http://msdn.microsoft.com/en-us/library/ms998355.aspx)получить новый токен от старого в отношении одного простого оператора .NET WindowsIdentity wi = new WindowsIdentity(identity);

  3. Вы можете получить доступ к другому серверу относительно одной фиксированной учетной записи. Это может быть учетная запись компьютерадля учетной записи пула приложений IIS. Это может быть другая фиксированная определенная учетная запись, которая будет использоваться только для доступа к файловой системе.

Важно знать, какая версияWindows Server у вас на сервере, где работает IIS, и какой уровень функции домена у вас есть в Active Directory для вашего домена (вы увидите это в инструменте «Домены и доверительные отношения Active Directory», если вы выберете свой домен и выберете «Повысить функциональный уровень домена»).Интересно также узнать, под какой учетной записью запускается пул приложений IIS.

Первый и третий способ всегда будут работать. Третий способ может быть вреден для вашей электронной почты.окружение и для текущего разрешения в файловой системе.Второй очень элегантный.Это позволяет контролировать, какие серверы (файловый сервер) доступны из IIS.Этот способ имеет некоторые ограничения, и он требует некоторой работы в Active Directory.

Поскольку вы используете классический ASP, для поддержки вашей реализации необходимо создать небольшой программный компонент с поддержкой скриптов.

Каким образомвы предпочитаете?

ОБНОВЛЕНО на основе вопроса из комментария: поскольку вы используете классический ASP, вы не можете напрямую использовать Win32 API, но вы можете написать небольшой COM-компонент в VB6 или в.NET, которые используют API, которые вам нужны.В качестве примера вы можете использовать код из http://support.microsoft.com/kb/248187/en. Но вы должны сделать некоторые другие вещи внутри.Теперь я объясню, какой Win32 API может помочь вам сделать все, что вам нужно, с помощью токенов и олицетворения.

Прежде всего небольшое объяснение олицетворения.Все работает очень легко.Всегда есть один основной токен, под которым выполняется процесс.Любому потоку может быть назначен другой токен (токен потока).Для этого нужен токен пользователя hUserToken и вызов API ImpersonateLoggedOnUser(hUserToken);.

Чтобы вернуться к исходному токену процесса (только для текущего потока), вы можете вызвать функцию RevertToSelf().Маркер пользователя будет получен и выдан за вас для IIS, поскольку вы настроили свой веб-сайт.Чтобы вернуться к исходному токену процесса, вы должны реализовать вызов функции RevertToSelf() в своем пользовательском компоненте COM.Возможно, если вам больше ничего не нужно делать на странице ASP, этого будет достаточно, но я рекомендую вам быть более осторожным и сохранять токен текущих пользователей в переменной перед работой с файлами.Затем вы выполняете все операции с файловой системой и, в конце концов, переназначаете токен пользователя обратно в текущий поток.Вы можете назначить токен олицетворения потоку в отношении SetThreadToken(NULL,hUserToken);.Чтобы выдать (сохранить) токен текущего потока (токен пользователя в вашем случае), вы можете использовать OpenThreadToken API.Он должен работать.

ОБНОВЛЕНО 2: Возможно, использование RevertToSelf() function в конце одной страницы ASP для вас уже будет в порядке.Соответствующий код C # может быть таким:

Создать новый проект в C # типа «Библиотека классов» с именем LoginAdmin.Вставьте следующий код внутри

using System;
using System.Runtime.InteropServices;

namespace LoginAdmin {
    [InterfaceTypeAttribute (ComInterfaceType.InterfaceIsDual)]
    public interface IUserImpersonate {
        [DispId(1)]
        bool RevertToSelf ();
    }

    internal static class NativeMethods {
        [DllImport ("advapi32.dll", SetLastError = true)]
        internal static extern bool RevertToSelf ();
    }

    [ClassInterface (ClassInterfaceType.AutoDual)]
    public class UserImpersonate : IUserImpersonate {
        public UserImpersonate () { }

        public bool RevertToSelf () {
            return NativeMethods.RevertToSelf();
        }
    }
}

Проверьте свойства проекта в разделе «Сборка» «Регистрация для взаимодействия COM». В разделе «Подписание» проекта установите флажок «Подписать сборку» и в «Выберите файл ключа строгого имени» выберите <New...>, затем введите любое имя файла и пароль (или отметьте «защитить мой ключ ...»). В конце вы должны изменить строку из AssemblyInfo.cs в части Properties проекта:

[assembly: ComVisible (true)]

После компиляции этого проекта вы получаете два файла, LoginAdmin.dll и LoginAdmin.tlb. DLL уже зарегистрирована на текущем компьютере. Для регистрации на другом компьютере используйте RegAsm.exe .

Чтобы проверить эту COM DLL на странице ASP, вы можете сделать следующее

<%@ Language="javascript" %>
<html><body>
    <% var objNet = Server.CreateObject("WScript.Network");
       Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>");
       Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>");

       var objLoginAdmin = Server.CreateObject("LoginAdmin.UserImpersonate");
       var isOK = objLoginAdmin.RevertToSelf();
       if (isOK)
              Response.Write("RevertToSelf return true<br/>");
       else
              Response.Write("RevertToSelf return false<br/>");
       Response.Write("One more time after RevertToSelf()<br/>");
       Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>");
       Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>");

       var fso = Server.CreateObject("Scripting.FileSystemObject");
       var path = "\\\\mk01\\C\\Oleg";
       if (fso.FolderExists(path)) {
          Response.Write("Yes");
       } else {
          Response.Write("No");
       }%>
</body></html>

Если учетная запись, используемая для запуска пула приложений IIS, имеет доступ к соответствующему сетевому ресурсу, выходные данные будут выглядеть следующим образом

Current user: Oleg
Current user's domain: WORKGROUP
RevertToSelf return true
One more time after RevertToSelf()
Current user: DefaultAppPool
Current user's domain: WORKGROUP
Yes 
4 голосов
/ 10 мая 2010

Под олицетворением вы можете получить доступ только к защищаемым ресурсам на локальном компьютере, к которому вы не можете получить доступ к чему-либо по сети.

В Windows, когда вы работаете от имени другого пользователя, вы работаете под так называемым сетевым токеном. Этот токен имеет учетные данные пользователя для доступа к локальному компьютеру, но не имеет учетных данных для удаленного доступа. Поэтому, когда вы получаете доступ к общему сетевому ресурсу, вы фактически получаете к нему доступ как Анонимный пользователь.

Когда вы запускаете процесс на своем рабочем столе (например, CScript.exe), вы работаете под токеном «Интерактивный пользователь». Этот токен имеет полные учетные данные для локального и удаленного доступа, поэтому вы можете получить доступ к общей сетевой папке.

Чтобы получить доступ к удаленным ресурсам при олицетворении пользователя Windows, вы должны использовать делегирование, а не олицетворение. Это будет связано с некоторыми изменениями в вашем Active Directory, чтобы разрешить делегирование для компьютера и / или пользователей в вашем домене. Это может быть угрозой безопасности, поэтому ее следует внимательно изучить.

...