Catch-22 запобігає потоковому сервісу TCP WCF, захищеному WIF; руйнує моє Різдво, психічне здоров'я


181

У мене є вимога захистити поточну кінцеву точку служби WCF net.tcp за допомогою WIF . Він повинен ідентифікувати вхідні дзвінки проти нашого сервера токенів. Послуга передається в потоковому режимі, оскільки вона призначена для передачі великої кількості даних n матеріалів.

Це видається неможливим. І якщо я не зможу обійти улов, моє Різдво зіпсується, і я вип'ю себе на смерть у жолобі, поки веселі покупці перейдуть на моє повільно охолоджене тіло. Дуже серйозно, хлопці.

Чому це неможливо? Ось Catch-22.

На клієнті мені потрібно створити канал із GenericXmlSecurityToken, який я отримую з нашого сервера токенів. Ніяких проблем.

// people around here hate the Framework Design Guidelines.
var token = Authentication.Current._Token;
var service = base.ChannelFactory.CreateChannelWithIssuedToken(token);
return service.Derp();

Я сказав: "немає проблем"? Проблеми. Фактично,NullReferenceException стильові проблеми.

"Брат," я запитав у Рамці, "ти навіть перевіряєш нуль?" Рамка мовчала, тому я розібрав і знайшов це

((IChannel)(object)tChannel).
    GetProperty<ChannelParameterCollection>().
    Add(federatedClientCredentialsParameter);

було джерелом винятку, і що GetPropertyдзвінок повертався null. Отже, WTF? Виявляється, якщо я ввімкнув захист повідомлень і встановив тип облікових даних клієнта, IssuedTokenто ця властивість тепер існує у ClientFactory(protip: у IChannel, ублюдок, немає еквівалента "SetProperty").

<binding name="OMGWTFLOL22" transferMode="Streamed" >
    <security mode="Message">
        <message clientCredentialType="IssuedToken"/>
    </security>
</binding>

Солодке. Більше немає НРЕ. Однак зараз мій клієнт винен при народженні (все одно люблю його, тхо). Копаючи діагностику WCF (протип: змушуйте своїх найгірших ворогів робити це після того, як їх розчавлять і загнали перед вами, але прямо перед тим, як насолоджуватися скаргами їх жінок і дітей), я бачу, що це відбувається через невідповідність безпеки між сервером і клієнтом.

Запитане оновлення не підтримується 'net.tcp: // localhost: 49627 / MyService'. Це може бути пов'язано з невідповідними прив'язками (наприклад, безпека увімкнена на клієнті, а не на сервері).

Перевіряючи діалоги хоста (знову: розчавити, керувати, читати журнали, насолоджуватися голосом), я бачу, що це правда

Програма протоколу / ssl-tls була надіслана службі, яка не підтримує цей тип оновлення.

"Ну, я", - кажу я, - я просто ввімкну захист повідомлення від хоста! І я. Якщо ви хочете знати, як це виглядає, це точна копія конфігурації клієнта. Подивіться.

Результат: Кабум.

Прив'язка ('NetTcpBinding', ' http://tempuri.org/ ') підтримує потокове передавання, яке неможливо налаштувати разом із захистом рівня повідомлень. Подумайте про вибір іншого способу передачі або безпеку транспортного рівня.

Таким чином, мій хост не може бути як потоковим, так і захищеним через жетони . Ловля-22.

tl; dr: Як я можу захистити поточну кінцеву точку net.tcp WCF за допомогою WIF ???


3
Гаразд, напевно, тут необізнане запитання, але чи потрібен WIF-режим справді? Режим транспорту звучить так, що він би краще працював із потоковим потоком, щось на кшталт очевидно неперевіреного<security mode="Transport" /> <transport clientCredentialType="IssuedToken" /> </security>
Йоахім Ісакссон

3
TransportWithMessageCredentialрежим може бути іншим варіантом.
Йоахім Ісакссон

3
TMLK, MessageSecurity може підписувати та шифрувати завантажену корисну навантаження, але розмовляє під час роботи з потоками. Чи розглядали ви за допомогою аутентифікаціїMode = IssuedTokenOverTransport?
OnoSendai

7
Дозвольте мені побачити, чи можу я викликати привидів з минулого, щоб допомогти врятувати ваші канікули тоді. Деякі натяки тут: social.msdn.microsoft.com/Forums/vstudio/en-US/…
OnoSendai

2
Чи є можливість ви опублікувати тестовий проект, з яким могли б експериментувати інші?
antiduh

Відповіді:


41

WCF має декілька областей із потоковим потоком (я дивлюся на вас, MTOM 1 ) через принципову проблему того, як він не виконує попередню перевірку так, як більшість людей думає, що це має працювати (це впливає лише на наступні запити цього каналу , не перший запит) Добре, тож це не зовсім ваше питання, але будь ласка, слідкуйте за тим, як я до кінця дістанусь до вашого. Зазвичай виклик HTTP працює так:

  1. клієнт потрапляє на сервер анонімно
  2. сервер каже, вибачте, 401, мені потрібна автентифікація
  3. клієнт звертається до сервера за допомогою маркера аутентифікації
  4. сервер приймає.

Тепер, якщо ви коли-небудь намагатиметеся ввімкнути поток MTOM на кінцевій точці WCF на сервері, він не скаржиться. Але, якщо ви налаштуєте його на клієнтському проксі (як слід, вони повинні відповідати прив’язкам), він вибухне вогненною смертю. Причиною цього є те, що вищезазначена послідовність подій, яку намагається запобігти WCF, полягає в наступному:

  1. клієнт передає 100MB файл на сервер анонімно в одному POST
  2. сервер каже вибачте, 401, мені потрібна автентифікація
  3. клієнт знову передає файл на 100 Мб на сервер із заголовком аутентифікації
  4. сервер приймає.

Зауважте, що щойно ви надіслали 200MB на сервер, коли вам потрібно було лише надіслати 100MB. Ну, це проблема. Відповідь полягає в тому, щоб надіслати автентифікацію з першої спроби, але це неможливо в WCF без написання користувацької поведінки. У всякому разі, я відволікаюсь.

Ваша проблема

Спочатку дозвольте сказати, що те, що ви намагаєтеся, неможливо 2 . Тепер, щоб ви перестали крутити колеса, дозвольте мені сказати, чому:

Мене вражає, що ти зараз блукаєш у подібному класі проблем. Якщо ввімкнути захист рівня повідомлень, клієнт повинен завантажити весь потік даних у пам'ять, перш ніж він фактично може закрити повідомлення зі звичайною хеш-функцією та підписом xml, необхідними ws-security. Якщо він повинен прочитати весь потік для підписання єдиного повідомлення (що насправді не є повідомленням, але це єдиний безперервний потік), тоді ви можете побачити проблему тут. WCF доведеться передати його один раз "локально", щоб обчислити захист повідомлення, а потім знову потік, щоб надіслати його на сервер. Це явно нерозумно, тому WCF не дозволяє захистити рівень повідомлень для потокового передавання даних.

Отже, проста відповідь тут полягає в тому, що ви повинні надіслати маркер або як параметр початковій веб-службі, або як заголовок SOAP та використовувати власну поведінку для перевірки його. Ви не можете використовувати WS-Security для цього. Відверто кажучи, це не лише питання WCF - я не можу зрозуміти, як це може працювати практично для будь-яких інших груп.

Вирішення проблеми MTOM

Це лише для прикладу, як я вирішив свою проблему зі потоком MTOM для базової аутентифікації, тож, можливо, ви могли б взяти кишки цього і реалізувати щось подібне для своєї проблеми. Суть у тому, що для того, щоб увімкнути ваш власний інспектор повідомлень, ви повинні відключити все поняття безпеки на клієнтському проксі (він залишається ввімкненим на сервері), крім транспортного рівня (SSL):

this._contentService.Endpoint.Behaviors.Add(
    new BasicAuthenticationBehavior(
        username: this.Settings.HttpUser,
        password: this.Settings.HttpPass));
var binding = (BasicHttpBinding)this._contentService.Endpoint.Binding;
binding.Security.Mode = BasicHttpSecurityMode.Transport; // SSL only            
binding.Security.Transport.ClientCredentialType = 
   HttpClientCredentialType.None; // Do not provide

Зауважте, що тут я відключив транспортну безпеку, оскільки буду забезпечувати себе інспектором повідомлень та користувацькою поведінкою:

internal class BasicAuthenticationBehavior : IEndpointBehavior
{
    private readonly string _username;
    private readonly string _password;

    public BasicAuthenticationBehavior(string username, string password)
    {
        this._username = username;
        this._password = password;
    }
    public void AddBindingParameters(ServiceEndpoint endpoint, 
        BindingParameterCollection bindingParameters) { }
    public void ApplyClientBehavior(ServiceEndpoint endpoint,
        ClientRuntime clientRuntime)
    {
        var inspector = new BasicAuthenticationInspector(
            this._username, this._password);
        clientRuntime.MessageInspectors.Add(inspector);
    }
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
        EndpointDispatcher endpointDispatcher) { }
    public void Validate(ServiceEndpoint endpoint) { }
}

internal class BasicAuthenticationInspector : IClientMessageInspector
{
    private readonly string _username;
    private readonly string _password;

    public BasicAuthenticationInspector(string username, string password)
    {
        this._username = username;
        this._password = password;
    }

    public void AfterReceiveReply(ref Message reply,
        object correlationState) { }

    public object BeforeSendRequest(ref Message request,
        IClientChannel channel)
    {
        // we add the headers manually rather than using credentials 
        // due to proxying issues, and with the 101-continue http verb 
        var authInfo = Convert.ToBase64String(
            Encoding.Default.GetBytes(this._username + ":" + this._password));

        var messageProperty = new HttpRequestMessageProperty();
        messageProperty.Headers.Add("Authorization", "Basic " + authInfo);
        request.Properties[HttpRequestMessageProperty.Name] = messageProperty;

        return null;
    }
}

Отже, цей приклад призначений для всіх, хто страждає від проблеми MTOM, але також як скелет для вас, щоб реалізувати щось подібне для автентифікації вашого маркера, згенерованого первинною WIF-захищеною токеновою службою.

Сподіваюся, це допомагає.

(1) Великі дані та потокове передавання

(2) Захист повідомлень у WCF (див. "Недоліки").


MTOM and Basic Authorization, а MTOM і OAuth2 ?
Кікенет
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.