Аутентификация WCF Transport Windows с помощью NET.TCP работает только локально

У меня есть служба WCF, работающая локально, и клиент, работающий удаленно. Я сопоставил привязки с обеих сторон:

<binding name="TcpBindingConfiguration_2">
  <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
  <security mode="Transport">
    <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
    <message clientCredentialType="Windows"/>
  </security>
</binding>

У меня есть фиктивный метод, который просто возвращает Thread.CurrentPrincipal.Identity.Name, ServiceSecurityContext.Current.WindowsIdentity.Name и OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name, если они доступны.

При запуске клиента на той же машине, что и сервер, транспортный режим работает нормально, и доступны все три имени удостоверения. Однако при подключении к моей локальной машине с удаленного хоста (проверено на хостах как в одном, так и в разных доменах) я получаю ужасное сообщение «Сервер отклонил учетные данные клиента».

Если я изменю привязку на:

<binding name="TcpBindingConfiguration_1">
  <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
  <security mode="None"/>
</binding>

соединение установлено, и фиктивный метод не возвращает ни одного из имен (как я и предполагал).

Может ли кто-нибудь поделиться своей конфигурацией включения проверки подлинности Windows на разных хостах (а иногда и в разных доверенных доменах) с использованием привязки net.tcp? Я видел множество примеров, когда просто говорилось, что для режима безопасности установлено значение «Нет», и это хорошо, но я все же хочу определить, кто звонит.

Так что же дальше? Заставить режим = «Транспорт» работать? Использовать режим = «Нет» и реализовать другой тип авторизации? Перейти на другую привязку, которая успешно использует проверку подлинности Windows?

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

Обновление: это код, который я сейчас использую для создания своего клиента:

var endPointAddress = "net.tcp://" + remoteHost + ":8092/Marc/WcfService";
EndpointAddress address = new EndpointAddress(new Uri(endPointAddress), EndpointIdentity.CreateSpnIdentity("AppName/" + remoteHost), new AddressHeaderCollection());
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;

using (var remoteService = new RemoteService.GuestServiceClient(binding, address))
{
    try
    {
        MessageBox.Show(remoteService.Hello("Marc"));
        remoteService.Close();
    }
    catch (Exception ex)
    {
        remoteService.Abort();
        MessageBox.Show("Error occurred:\n\n" + ex.Source + "\n\n" + ex.Message, "Could not connect to " + remoteHost, MessageBoxButton.OK, MessageBoxImage.Error);
    }
}

remoteHost устанавливается на IP-адрес удаленной машины.

Должен ли я использовать каналы, прокси и прочее? Я видел другой код в другом месте, но этот простой экземпляр GuestServiceClient(), похоже, работает (по крайней мере, локально).


person Marc    schedule 23.05.2012    source источник


Ответы (1)


Обычно я настраиваю свои службы WCF в коде, поэтому я не уверен, как это отразится в файле конфигурации.

Из моего исследования, проведенного много лет назад, вам необходимо добавить имя субъекта-службы (SPN) как часть конечной точки клиента. Серверную часть менять не нужно.

В коде это выглядит так:

string endPointAddress = String.Format("net.tcp://{0}:1111/ServiceName", ServerAddress);
EndpointAddress address = new EndpointAddress(new Uri(endPointAddress), EndpointIdentity.CreateSpnIdentity("AppName/" + ServerAddress), new AddressHeaderCollection());
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Transport;

Вторая строка — это то, что добавляет SPN к информации о соединении. В EndpointIdentity.CreateSpnIdentity строка имеет формат AppName/ServerAddress. Часть «Имя приложения» может быть любой, но я рекомендую что-то уникальное для вашего приложения. Я обычно использую формат полного доменного имени (host.domain.com) для адреса.

Опять же, я не уверен, как это переводится в файл конфигурации. Я надеюсь, что это поможет вам начать с правильного пути.

person Joe Doyle    schedule 23.05.2012
comment
Я использую код для создания клиента, но конфиги для создания серверов. Не спрашивайте меня, почему, просто так получилось.. лол.. Все еще не получаю никакой радости, это код, который я использую на клиенте. Используете ли вы каналы или прокси или вы открываете клиент, как я выше? - person Marc; 23.05.2012
comment
Я откопаю код, который я сделал для другого проекта, и посмотрю, что я мог пропустить. - person Joe Doyle; 23.05.2012