Сертификаты WCF без хранилища сертификатов

Моя команда разрабатывает много плагинов WPF для стороннего приложения толстого клиента. Плагины WPF используют WCF для потребления веб-сервисов, опубликованных многими сервисами TIBCO. Приложение толстого клиента поддерживает отдельное центральное хранилище данных и использует собственный API для доступа к хранилищу данных. Толстый клиент и плагины WPF должны быть развернутыми на 10 000 рабочих станций. Наш клиент хочет сохранить сертификат используемым толстым клиентом в центральном хранилище данных так, чтобы они не должны были волноваться о переиздании сертификата (текущий цикл переиздания занимает приблизительно 3 месяца), и также имейте возможность авторизовать использование сертификата. Предлагаемая архитектура предлагает форму общего секрета / аутентификация между центральным хранилищем данных и сервисами TIBCO.

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

В основном наш клиент хочет, чтобы мы встроили в наши плагины WPF механизм, который получает сертификат от центрального хранилища данных (который будет позволен или отклонен на основе ролей в том хранилище данных) в память, затем используют сертификат для создания соединения SSL с сервисами TIBCO. Нет смысла в хранилище сертификатов локальной машины позволяется, и в версии памяти должен быть отброшен в конце каждой сессии.

Таким образом, вопрос - кто-либо, знает, возможно ли передать сертификат в оперативной памяти WCF (.NET 3.5) сервис для шифрования транспортного уровня SSL?

Примечание: Я задал подобный вопрос (здесь), но с тех пор удалил его и повторно спросил это с большей информацией.

12
задан Community 23 May 2017 в 12:16
поделиться

2 ответа

Возможно. Мы делаем нечто подобное с Mutual Certificate Auth - сертификат службы и в некоторых случаях сертификат клиента получают от центрального органа как часть механизма автоматического обнаружения / единого входа.

Не совсем ясно, в каком контексте будет использоваться сертификат, но во всех случаях вам нужно определить собственное поведение и элемент поведения, производный от конкретного поведения / элемента в System.ServiceModel.Description пространство имен, которое принимает сертификат. На данный момент я предполагаю, что это учетные данные клиента. Сначала вы должны написать поведение, которое выглядит примерно так:

public class MyCredentials : ClientCredentials
{
    public override void ApplyClientBehavior(ServiceEndpoint endpoint,
        ClientRuntime behavior)
    {
        // Assuming GetCertificateFromNetwork retrieves from CDS
        ClientCertificate.Certificate = GetCertificateFromNetwork();
    }

    protected override ClientCredentials CloneCore()
    {
        // ...
    }
}

Теперь вам нужно создать элемент, который может входить в конфигурацию XML:

public class MyCredentialsExtensionElement : ClientCredentialsElement
{
    protected override object CreateBehavior()
    {
        return new MyCredentials();
    }

    public override Type BehaviorType
    {
        get { return typeof(MyCredentials); }
    }

    // Snip other overrides like Properties
}

После этого вы можете добавить политику в вашу конфигурацию WCF:

<behaviors>
    <endpointBehaviors>
        <behavior name="MyEndpointBehavior">
            <myCredentials/>
        </behavior>
    </endpointBehaviors>
</behaviors>

Изменить: почти забыл упомянуть, вам необходимо зарегистрировать расширение:

<system.serviceModel>
    <extensions>
        <behaviorExtensions>
            <add name="myCredentials"
                 type="MyAssembly.MyCredentialsExtensionElement, MyAssembly,
                       Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </behaviorExtensions>
    </extensions>
</system.serviceModel>

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

13
ответ дан 2 December 2019 в 19:53
поделиться

Я тот парень, который заставил Кейна (нашего ТАКОГО лакея!) Задать исходный вопрос. Я подумал, что наконец-то создам учетную запись и опубликую наши выводы / результаты / опыт в отношении ответа, опубликованного Aaronaught (так что любая заслуга ему выше).

Мы попытались добавить настраиваемое поведение, как было предложено выше, и настроить behaviorConfiguration в элементе конфигурации конечной точки для его использования. Мы вообще не могли заставить код запускаться, поэтому в итоге остановились на программном подходе.

Поскольку у нас был настроен класс-оболочка для создания объекта ClientBase, мы использовали наши существующие функции создания, чтобы добавить поведение после сборки всех других частей ClientBase.

При этом мы также столкнулись с несколькими проблемами, а именно с тем, что поведение ClientCredentials уже было определено для нашей ClientBase аутентификации с использованием имени пользователя и пароля, а не нашего сертификата + имени пользователя и пароля. Поэтому мы программно удалили существующее поведение перед добавлением нашего нового поведения на основе сертификата (с введенными именем пользователя и паролем) в качестве временной меры для тестирования.По-прежнему никаких кубиков, наше поведение конструировалось, и ApplyClientBehavior запускался, но служба все еще падала, когда был вызван Invoke (мы так и не получили настоящего исключения из-за кучи операторов using, которые было трудно реорганизовать).

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

Я хотел бы поблагодарить Aaronaught (и я бы проголосовал за него, если бы мог!) За то, что направил нас на правильный путь и предоставил хорошо продуманный и полезный ответ.

Вот небольшой фрагмент кода, запущенный и работающий (с использованием тестового файла .CRT).

     protected override ClientBase<TChannel> CreateClientBase(string endpointConfigurationName)
    {
        ClientBase<TChannel> clientBase = new ClientBase<TChannel>(endpointConfigurationName); // Construct yours however you want here

        // ...

        ClientCredentials credentials = clientBase.Endpoint.Behaviors.Find<ClientCredentials>();

        X509Certificate2 certificate = new X509Certificate2();
        byte[] rawCertificateData = File.ReadAllBytes(@"C:\Path\To\YourCert.crt");
        certificate.Import(rawCertificateData);

        credentials.ClientCertificate.Certificate = certificate;

        return clientBase;
    }

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

Еще раз спасибо.

4
ответ дан 2 December 2019 в 19:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: