Подтвердить что ты не робот

WCF Net.tcp с sspi терпит неудачу, если клиент и сервер не используют одинаковые окна. Identity

У меня есть служба WCF, обслуживаемая службой Windows. Клиентское приложение удастся, если я запишусь на клиентскую машину, используя те же учетные данные, что и служба, работающая под ней, но она не работает с исключением, если я вошел в систему с любой другой действительной учетной записью домена.

У меня есть две учетные записи, с которыми я тестирую: одна - обычная учетная запись пользователя, а другая - учетная запись администратора. Я пробовал все четыре комбинации, перечисленные ниже:

                   Server account
   CLient      RegUser    AdminAcct   
  RegUser     Succeeds      Fails   
 AdminAcct     Fails       Succeeds    

Как вы можете видеть, это не может быть проблемой администратора, поскольку система работает, когда клиент и сервер работают под учетной записью non-admin. В обоих случаях, когда он терпит неудачу, я получаю такое же исключение на клиенте, не указав ничего из журналов сервера:

"Не удалось выполнить вызов SSPI. см. внутреннее исключение"

Внутреннее исключение . Неправильное имя целевого принципа.

Я зарегистрировал учетные записи как SPN.

Проблема возникает только из моего клиентского приложения, но не тогда, когда я использую WCVFTestClient.exe, который поставляется с Visual Studio.

Исключение, в журнале трассировки WCF,

"System.ServiceModel.Security.SecurityNegotiationException, System.ServiceModel, Version = 4.0.0.0, Culture = нейтральный, PublicKeyToken = b77a5c561934e089"

с сообщением:

"Ошибка аутентификации на удаленной стороне (поток может быть доступен для дополнительных попыток аутентификации).

След стека находится внизу: Что не так?

трассировка стека


System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeAcceptor.OnAcceptUpgrade(поток поток, SecurityMessageProperty & remoteSecurity) System.ServiceModel.Channels.StreamSecurityUpgradeAcceptorBase.AcceptUpgrade(Stream поток) System.ServiceModel.Channels.InitialServerConnectionReader.UpgradeConnection(IConnection соединение, StreamUpgradeAcceptor upgradeAcceptor, IDefaultCommunicationTimeouts defaultTimeouts) System.ServiceModel.Channels.ServerSessionPreambleConnectionReader.ServerFramingDuplexSessionChannel.OnOpen(TimeSpan тайм-аут) System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan тайм-аут) System.ServiceModel.Dispatcher.ChannelHandler.OpenAndEnsurePump() System.Runtime.ActionItem.DefaultActionItem.TraceAndInvoke() System.Runtime.ActionItem.CallbackHelper.InvokeWithoutContext(Объект государство) System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped * nativeOverlapped) System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(UInt32 ошибка, UInt32 bytesRead, NativeOverlapped * nativeOverlapped) System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped * pOVERLAP)

4b9b3361

Ответ 1

Нашел ответ. Моя проблема заключалась в сочетании двух факторов.

  • При использовании бинарного протокола WCF net.tcp режим Client Security определяет, используется ли NTLM или Kerberos для аутентификации. Если вы установите режим безопасности клиента на "Транспорт", аутентификация использует NTLM, и возможен только один переход. Если вы попытаетесь поговорить с сервером WCF с третьим сервером (например, с базой данных), он будет терпеть неудачу. Использование SecurityMode = "Сообщение", otoh, заставляет сервер WCF использовать Kerberos, что позволяет несколько переходов...

  • Вторая проблема связана с тем, что я делал на клиенте в привязке. Протокол WCF net.tcp требует, чтобы при создании экземпляра конечной точки на клиенте вы должны указать "идентификатор конечной точки" (см. Код ниже). Я ошибочно предположил, что это как-то связано с аутентификацией и, следовательно, является личным именем текущего пользователя (Windows Principal) на клиенте.

        var epId = EndpointIdentity.CreateUpnIdentity(userPrincipalName);
        var ep = new EndpointAddress(new Uri(url), epId):
    

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

    Я все еще не понимаю, почему этот идентификатор пользователя (учетной записи службы) должен быть указан в конечной точке на клиенте. Какими функциями на сервере нужны эти данные?

Ответ 2

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

Полученная ошибка, вероятно, связана с отказом на стороне клиента. Если вы настроите конечную точку обслуживания клиента для предоставления ServicePrincipalName, проблема может быть решена. Я нашел эту статью довольно полезной для решения той же проблемы, с которой я столкнулся.