2013-03-25 2 views
12

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

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

    Server account 
    CLient  RegUser AdminAcct 
    RegUser  Succeeds  Fails 
AdminAcct  Fails  Succeeds  

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

Внутреннее исключение - «Неправильное название целевого объекта».

Я зарегистрировал счета как СПП.

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

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

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

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

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

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

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


System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeAcceptor.OnAcceptUpgrade (поток поток, SecurityMessageProperty & remoteSecurity) System.ServiceModel.Channels.StreamSecurityUpgradeAcceptorBase.AcceptUpgrade (поток поток) System.ServiceModel.Channels.InitialServerConnectionReader.UpgradeConnection (IConnection подключение, StreamUpgradeAcceptor upgradeAccept или, 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)

ответ

12

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

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

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

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

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

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

+0

Большое спасибо за этот ответ. После нескольких часов и часов пробной ошибки я попробовал это решение, и это работает как шарм! Если мы когда-нибудь встретимся, я дам тебе пиво ;-) –

+0

Тебе очень рады! Куда пойти, чтобы получить пиво?

+0

Согласно вашему профилю, я думаю, что мы не встретимся в ближайшем будущем ... но никогда не закончившееся спасибо будет следовать за вами ;-) –

1

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

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