Доступ WCF запрещен при открытии канала именованного канала из приложения IIS - PullRequest
0 голосов
/ 06 мая 2018

У нас есть некоторый устаревший код веб-приложения, который мы обновляем и переносим в среду выполнения .NET 4.0.

Код находится в библиотеке классов и подключается к конечной точке именованного канала с использованием WCF.

Когда я инициирую соединение из консольного приложения, все работает нормально.

Когда я инициирую соединение из веб-приложения, я получаю исключение:

Access is denied
Server stack trace:
  at System.ServiceModel.Channels.AppContainerInfo.GetCurrentProcessToken()
  at System.ServiceModel.Channels.AppContainerInfo.RunningInAppContainer()
  at System.ServiceModel.Channels.AppContainerInfo.get_IsRunningInAppContainer()
  at System.ServiceModel.Channels.PipeSharedMemory.BuildPipeName(String pipeGuid)
  at System.ServiceModel.Channels.PipeSharedMemory.get_PipeName()
  at System.ServiceModel.Channels.PipeConnectionInitiator.GetPipeName(Uri uri, IPipeTransportFact… Object[] , Object[] )
  at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
  at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
  at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
  at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
  at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

Ошибка возникает на границе между управляемым кодом и неуправляемым кодом, когда происходит вызов в advapi32.dll:

[SecurityCritical]
private static SafeCloseHandle GetCurrentProcessToken()
{
  SafeCloseHandle TokenHandle = (SafeCloseHandle) null;
  if (!UnsafeNativeMethods.OpenProcessToken(UnsafeNativeMethods.GetCurrentProcess(), TokenAccessLevels.Query, out TokenHandle))
    throw System.ServiceModel.FxTrace.Exception.AsError((Exception) new Win32Exception(Marshal.GetLastWin32Error()));
  return TokenHandle;
}

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr ProcessHandle, TokenAccessLevels DesiredAccess, out SafeCloseHandle TokenHandle);

Различные темы в Интернете предлагают удалить элемент или параметр impersonate="false":

<system.web>
  <identity impersonate="true"/>
</system.web>

И действительно, это работает, чтобы исправить мою проблему. Однако я не уверен, какие побочные эффекты это может оказать на приложение (SharePoint 2016), поэтому я не хочу просто удалять этот атрибут.

Атрибут SecurityCritical дал мне несколько советов о том, что, возможно, это связано с изменением модели CAS между .NET 2.0 и .NET 4.0. Код установлен в GAC, поэтому он уже должен работать с полным доверием, но я все равно попробовал.

Я также пытался добавить [SecuritySafeCritical] к методу и классу, который вызывает IChannel.Open() безрезультатно.

Я также попытался добавить [assembly: SecurityRules(SecurityRuleSet.Level1)] в сборку, так как это должно заблокировать правила безопасности .NET Framework 2.0.

Я ищу какие-либо дополнительные сведения и другие способы, чтобы попытаться решить эту проблему.

Существует некоторое сходство с этим другим постом в стеке: Как вызывать службы WCF net.pipe (именованный канал) при олицетворении в службе Windows , за исключением того, что не происходит явного олицетворения, поэтому я не уверен, что исправление будет применяться.

Дополнительное замечание: при попытке вызвать System.Diagnostics.Process.GetCurrentProcess() выдается та же ошибка. Ошибка также возникает при попытке получить дескриптор текущего выполняющегося процесса.

1 Ответ

0 голосов
/ 07 мая 2018

Я пришел к выводу, что эта проблема связана с внутренними компонентами System.ServiceModel в .NET 4.0.

Изначально я думал, что это может быть связано с настройками среды выполнения веб-приложения UAC Server или .NET 4.0 / IIS 10 (например, модели .NET 2.0 и .NET 4.0 CAS). Я создал простое веб-приложение в .NET 3.5 и попытался вызвать Process.GetCurrentProcess().Handle. Я запустил это на новом сервере, и это не удалось с той же ошибкой «Доступ запрещен».

Я взял это на старый сервер (Windows Server 2008 R2, .NET 3.5) и запустил там, ожидая, что это сработает, и вот, это тоже не сработало. Поэтому я просмотрел источник для System.ServiceModel в 3.5 и обнаружил, что AppContainerInfo нет, и, таким образом, вполне вероятно, что код 3.5 вообще не выполняет те же вызовы уровня Win32 API.

Мой вывод заключается в том, что мы не сталкивались с этой ошибкой раньше, поскольку старые библиотеки 3.0 не нуждались в вызове API-интерфейсов из advapi32.dll или имели какой-то другой механизм для создания имени канала.

Действительно, вот первые несколько строк реализации из PipeConnectionInitiator.GetPipeName в 3.0 ":

internal static string GetPipeName(Uri uri)
{
  string[] strArray = new string[3]
  {
    "+",
    uri.Host,
    "*"
  };
  bool[] flagArray = new bool[2]{ true, false };
  for (int index1 = 0; index1 < strArray.Length; ++index1)
  {
    for (int index2 = 0; index2 < flagArray.Length; ++index2)
    {

А вот первые несколько строк в 4.0:

internal static string GetPipeName(Uri uri, IPipeTransportFactorySettings transportFactorySettings)
{
  AppContainerInfo appContainerInfo = PipeConnectionInitiator.GetAppContainerInfo(transportFactorySettings);
  string[] strArray = new string[3]
  {
    "+",
    uri.Host,
    "*"
  };
  bool[] flagArray = new bool[2]{ true, false };
  string str1 = string.Empty;
  string str2 = (string) null;
  for (int index1 = 0; index1 < strArray.Length; ++index1)
  {
    for (int index2 = 0; index2 < flagArray.Length; ++index2)
    {
      if (appContainerInfo == null || !flagArray[index2])

Таким образом, реализация 4.0 требует доступа для выполнения OpenProcessToken.

Одним из вариантов, если код достаточно изолирован, является использование перенаправления привязки сборки:

<runtime>
  <assemblyBinding>
    <dependentAssembly>
      <assemblyIdentity name="System.ServiceProcess" publicKeyToken="b77a5c561934e089" culture="neutral" />
      <bindingRedirect oldVersion="4.0.0.0" newVersion="3.0.0.0" />
    </dependentAssembly>            
  </assemblyBinding>
</runtime>

И просто принудительно связывайте среду выполнения со старыми версиями.

К сожалению, приложение имеет некоторые зависимости от System.ServiceModel 4.0, поэтому мне не так просто переключиться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...