Wcf service on linux

Анатомия .NET Core: как мы настроили NTLM под Linux

Мы продолжаем рассказывать про миграцию мобильного сервиса в ASP.NET Core и Docker. В этой статье будет идти речь про модуль WCF-клиента, упомянутый в предыдущей статье, NTLM-авторизацию и другие проблемы при его миграции. Сейчас расскажем, почему нам пришлось немного изучить анатомию и пощупать .NET Core изнутри.

Мягкий путь. Windows-контейнер

Первым делом мы настроили дебаг в docker-образ и локально запустили сервис в windows-контейнере.

При попытке отправки запроса в WCF-сервис получили весьма витиеватую ошибку:

System.ServiceModel.Security.MessageSecurityException: The HTTP request is unauthorized with client authentication scheme ‘Negotiate’. The authentication header received from the server was ‘Negotiate TlRMTVNTUAACAAAAEAAQADgAA.

Методом проб вышли на то, что в креденшиалах сервиса требуется указывать Domain. Смешно, что можно указать любое значение, лишь бы не null — тогда работает.

Всё, теперь запросы ходят, теперь в Windows-контейнере дела ок. Едем дальше.

Пробуем .NET Core под Linux

Переключившись на сборку в Linux-контейнер, ради интереса убрали значение Domain — и оно работает.

Первая проблема при отправке запросов в WCF связана с SSL. Ругается так:

System.Net.Http.CurlException SSL peer certificate or SSH remote key was not OK

Что означает: нет доверия к сертификату. Если бы WCF-сервис присылал не только конечный сертификат, но и все промежуточные, проблемы бы не было.

1. Выкачиваем промежуточные сертификаты.

Например, в Chrome открываем ссылку и идем в F12 во вкладку Security. Дальше View Certificate → Certification Path. Для каждого сертификата открываем View Certificate и на вкладке Details по кнопке Copy To File сохраняем Base-64 encoded сертификаты в директорию проекта. Расширение файлов нужно поменять на .crt.

2. Дописываем в Dockerfile новый слой.

Для дебага и экспериментов можно и просто временно отключить SSL-валидацию:

Самое полезное и важное, что мы узнали, получив CurlException — то, что для сетевых запросов используется libcurl.

Вкусная часть ждала нас впереди.

Linux + WCF + NTLM = любовь, но после ужина

Теперь дорогу преградил такой эксепшн

MessageSecurityException The HTTP request is unauthorized with client authentication scheme ‘Negotiate’. The authentication header received from the server was ‘Negotiate, NTLM’.

Меняем Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows на HttpClientCredentialType.Ntlm

Ошибка несколько изменилась, но легче не стало:

MessageSecurityException The HTTP request is unauthorized with client authentication scheme ‘Ntlm’. The authentication header received from the server was ‘Negotiate, NTLM’.

Давайте убедимся, что мы не столкнулись с еще одной docker-related особенностью наподобие значения Domain.

Запускаем сервис в виртуалке с Ubuntu LTS.

Лирическое отступление: Docker for Windows любит Hyper-V и при установке прочих виртуальных машин может отказаться работать. Поэтому в этот раз пришлось поднимать Ubuntu под Hyper-V, в котором не работает копипаста между хостовой и гостевой машинами, что не может не радовать.

Кстати, Microsoft, как там дружба с Apple?

Рядом лежал Mac с установленным Visual Studio. Руки сами зачесались. При запуске с отключенным SslCertificateAuthentication валится ошибка The handler does not support custom handling of certificates with this combination of libcurl (7.54.0) and its SSL backend («SecureTransport») . Если вернуть на место валидацию сертификатов, то будет та же ошибка с NTLM. И все-таки первая ошибка навевает подозрение, что отличия от Linux могут быть значительным.

Читайте также:  Vnc клиенты для mac os

Какие есть еще способы поизвращаться?

Ubuntu on Windows — при запуске сервиса уперлись в ошибку System.DllNotFoundException: Unable to load DLL ‘System.Net.Http.Native’ .

И по делу: на чистом Linux ошибка ровно та же самая, что в контейнере, а значит, проблема железно кроется в реализации WCF-клиента.

Пробуем зайти с другой стороны. Из командной строки запускаем:

1. curl -v —negotiate — завершается ошибкой

2. curl -v —ntlm — все хорошо, запрос работает

Здесь самое время вспомнить список официально поддерживаемых фич в WCF. В искомой строчке написано, что Core на Linux не умеет в NTLM. Но это никак не клеется с тем, что curl-то умеет, и было бы странно не реализовать настолько популярный вариант.

Из комментария в интернете узнаем, что Negotiate Negotiate-у рознь: в определенных реализациях есть поддержка fallback Kerberos→NTLM (повсеместно на винде), а в других — нет. Curl из последних, и Negotiate становится препятствием.

Все это наводит на мысль, что HttpClient может не учитывать этот нюанс, а значит, надежда на победу есть.

Смотрим исходники

И вот здесь нельзя не порадоваться за новый Microsoft за их решение открыть код миру. В сорцах находим ключик CURLHANDLER_DEBUG_VERBOSE=true , который нам расcкажет, чем занимается libcurl в момент выполнения WCF-запросов.

В логах видим уже знакомую ошибку gss_init_sec_context() failed и для HttpClientCredentialType.Windows, и для HttpClientCredentialType.Ntlm.

Теперь понятно, что WCF-клиент не реагирует на переключение с Windows-авторизации на NTLM и пытается использовать Negotiate в обоих случаях. Скорее всего, это происходит из-за двойного хедера WWW-Authentication ‘Negotiate, NTLM’, который присылает WCF сервис, и поскольку Negotiate является более сильной авторизацией, то он и используется.

Из мануала libcurl вкурили, что тип авторизации задается через опцию CURLOPT_HTTPAUTH . По этому следу мы вышли на таблицу выбора авторизации:

Атрибуты static readonly выглядят особенно соблазнительно, поскольку это означает, что достаточно поиграться при помощи Reflection со значениями в таблице на старте сервиса, и при HTTP-запросах не будет никакого оверхеда.

Добавили в Program.cs следующий код:

Здесь мы прибиваем гвоздями соответствие между «Negotiate» и CURLAUTH.NTLM.

Вуаля, теперь запросы срабатывают успешно.

Бонус-трек

Мы не остановились на достигнутом. Если внимательно посмотреть на логи, то видно, что один WCF запрос-ответ включает в себя несколько запросов-ответов HTTP, и один из ответов стабильно возвращается с Bad Request . В чем дело?

Для ошибочного запроса используется метод HEAD . И действительно, такое же поведение легко эмулируется с curl -I . В libcurl это соответствует опции CURLOPTION_NOBODY . В corefx эта опция используется при отправке HttpMethod.Head реквестов.
Поднимаемся по стеку выше в WCF. Видим, что в методе SendPreauthenticationHeadRequestIfNeeded отправляется HEAD запрос для авторизации, а все ошибки просто игнорируются:

Здесь явно напрашивается флаг, подобный HttpClientHandler.PreAuthenticate , чтобы не запускать запрос, заранее обреченный на 400.

Раз уж о нас не позаботились, значит, будем резать.

Метод SendPreauthenticationHeadRequestIfNeeded асинхронный, поэтому его патчинг может привести к красноглазию в слишком раннем возрасте. Если оглядеться по сторонам, то можно заметить простой и неприхотливый метод AuthenticationSchemeMayRequireResend . Очевидно, если он будет возвращать всегда false, то и не будет запускаться SendPreauthenticationHeadRequestIfNeeded .

Читайте также:  Приложение для лекций windows

Приступаем к операции.

Добавляем в решение новый проект WcfPreauthPatch. Теперь ставим Cecil, при помощи которого полезем в IL-код. Нужна бета-версия, чтобы работало под .NET Core.

Install-Package Mono.Cecil -Version 0.10.0-beta7 -ProjectName WcfPreauthPatch

В Dockerfile допишем

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

Эпилог

WCF-клиент в .NET Core доставил нам немало хлопот.

На github уже есть обсуждение поднятых в статье проблем и вопросов:

Однако, как мы увидели, эти проблемы не решены полностью. Надеемся, что наши 5 копеек в обсуждении добавят процессу новый оборот.

На закуску несколько идей и фактов

При осутствии интеграции с docker патчинг можно запускать как postbuild target.

Существуют NTLM-прокси, например, CNTLM. Альтернативный путь с настройкой NTLM-прокси внутри контейнера также имеет перспективы и более универсален, а готовый настроенный образ будет достоен выкладки на Docker Hub.

Гипотетически можно попробовать править хедер авторизации WWW-Authentication, который приходит от WCF-сервиса. Нужно переопределить поведение WCF-клиента через IEndpointBehavior и метод AfterReceiveReply. Однако, это сработает только в случае, если preauthentication запрос выключен, т.к. AfterReceiveReply его не поймает.

Если вы используете/имеете доступ к HttpClient, то вот ссылочка на workaround для похожей проблемы с NTLM.

Пропатчить CurlHandler при помощи Сecil не получится: System.Net.Http.dll — это mixed mode assembly (т.е. либа с managed и native кодом), и такой вариант в Cecil пока что не поддерживается.

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

  • Под линуксом в .NET Core нет поддержки function breakpoints.
  • Источник

    Make existing WCF service to run on Linux using .net core

    I am totally new to .net core.

    My task is to run WCF services on Linux. My WCF service is built with .NET Framework 4. I host my services in IIS.

    Can you please provide me with proper direction, to deal with below problems,

    What changes I need to do to my current WCF service, to run it on Linux?

    What OS version of Linux I need, to make it to work with .net core?

    Currently, I host my service in IIS, how can I host that in Linux, because we have about 40 services.

    What I have found on Internet, is hosting WCF service in console application, is there a better way of hosting, as I have more than 40 services.

    2 Answers 2

    .Net Core 1.0 does not support writing WCF servers, only clients that connect to them. The README of the WCF repository says:

    WCF service applications should still be created with the full .NET Framework version.

    Microsoft is considering adding support for WCF servers in the future, but nothing is certain right now. From a post on the WCF repository from 16 July 2016:

    We have reviewed all the great responses above in regards to WCF Server support in .NET Core.

    The WCF feature team is actively working on roadmap plans for WCF functionality in future .NET Core releases. For next steps, we need your feedback in terms of top scenarios, feature usage and target profiles.

    Читайте также:  Где хранится журнал регистрации 1с linux

    Источник

    Wcf service on linux

    This forum has migrated to Microsoft Q&A. Visit Microsoft Q&A to post new questions.

    Answered by:

    Question

    I know this question is already asked in other posts but the answers I found are almost a 5 years back. I just need the latest news and updated information about it.

    WCF service can run the same way on Linux platforms without making changes to existing programs or if some changes are to be made in application to make it operated on Linux what are those changes?

    please give me some elaborate information.

    Answers

    >> Is WCF fully supported on Linux?

    I wonder that if you want to know whether a Linux client can call a WCF Service or a WCF Service can be hosted in Linux.
    If you want to know whether a Linux client can call a WCF Service, then as far as I known we call WCF services from Linux via almost any programming language or platform by exposing your WCF service via XML/HTTP (via basicHttpBinding), SOAP/HTTP (wsHttpBinding) or REST.
    For more information, please try to refer to:
    http://stackoverflow.com/questions/9321979/consuming-wcf-services-from-linux-clients .
    If you want to know if a WCF Service can be hosted in Linux, then in my mind it is possible, but it may have some limitations. For more information, please try to refer to:
    http://stackoverflow.com/questions/24669003/hosting-wcf-service-on-linux .

    Best Regards,
    Amy Peng

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Источник

    Calling WCF service with NTLM auth from .NET Core on linux

    I am unable to successfully call a WCF service with NTLM authentication from .NET Core running on a linux box (docker container). The same code works perfectly on Windows 10 though.

    What I have done:

    • Add this to ConfigureServices :
    • Run apt-get -y install gss-ntlmssp
    • This is the code prior to calling the service:

    As mentioned this works fine on Windows 10. On Linux the following error is logged:

    Question is: why is it still failing on linux?

    2 Answers 2

    I found that if we remove Negotiate provider in the Windows Authentication on the server side the project will work, no matter which way of invocation.

    It seems that Netframework will auto-negotiate the way of authentication, Core cannot, which ought to be a bug.
    Feel free to let me know if there is anything I can help with.

    I had the same problem and was able to fix it, with a lot of help from the guys on the net core GitHub.

    Essentially net core uses the underlying OS to handle http calls. Before, on Linux libCurl was used, but the newer SocketsHttpHandler uses gss, which doesn’t come with ntlm support (at least not in the ‘microsoft/dotnet:2.2-aspnetcore-runtime-stretch-slim’ image).

    To fix this you need to install an extra library in your container, using the docker file. Right after

    (Or whatever image you use)

    on the next line add the following:

    RUN apt-get update && apt-get install -y —no-install-recommends apt-utils gss-ntlmssp

    Источник

    Оцените статью