Моя команда разрабатывает много плагинов WPF для стороннего приложения толстого клиента. Плагины WPF используют WCF для потребления веб-сервисов, опубликованных многими сервисами TIBCO. Приложение толстого клиента поддерживает отдельное центральное хранилище данных и использует собственный API для доступа к хранилищу данных. Толстый клиент и плагины WPF должны быть развернутыми на 10 000 рабочих станций. Наш клиент хочет сохранить сертификат используемым толстым клиентом в центральном хранилище данных так, чтобы они не должны были волноваться о переиздании сертификата (текущий цикл переиздания занимает приблизительно 3 месяца), и также имейте возможность авторизовать использование сертификата. Предлагаемая архитектура предлагает форму общего секрета / аутентификация между центральным хранилищем данных и сервисами TIBCO.
Пока я не обязательно соглашаюсь с предлагаемой архитектурой, наша команда не может изменить ее и должна работать с тем, что было обеспечено.
В основном наш клиент хочет, чтобы мы встроили в наши плагины WPF механизм, который получает сертификат от центрального хранилища данных (который будет позволен или отклонен на основе ролей в том хранилище данных) в память, затем используют сертификат для создания соединения SSL с сервисами TIBCO. Нет смысла в хранилище сертификатов локальной машины позволяется, и в версии памяти должен быть отброшен в конце каждой сессии.
Таким образом, вопрос - кто-либо, знает, возможно ли передать сертификат в оперативной памяти WCF (.NET 3.5) сервис для шифрования транспортного уровня SSL?
Примечание: Я задал подобный вопрос (здесь), но с тех пор удалил его и повторно спросил это с большей информацией.
Возможно. Мы делаем нечто подобное с 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 с помощью настраиваемого поведения .
Я тот парень, который заставил Кейна (нашего ТАКОГО лакея!) Задать исходный вопрос. Я подумал, что наконец-то создам учетную запись и опубликую наши выводы / результаты / опыт в отношении ответа, опубликованного 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 снова начал играть хорошо.
Еще раз спасибо.