WCF SOAP 1.1 и WS-Security 1.0, аутентификация транспорта сертификата клиента, сертификат службы для подписи тела сообщения, UsernameToken, дайджест пароля, Nonce
Резюме: Я работаю над клиентом .NET 4.0 WCF для использования веб-службы (DataPower, Java-сервис на другом конце) с использованием SOAP 1.1 и WS-Security 1.0. Клиент WCF должен реализовать сертификат клиента для взаимной аутентификации на транспортном уровне. Тело сообщения должно быть подписано с использованием отдельного сертификата службы / подписи. Заголовок SOAP также должен содержать токен имени пользователя с паролем дайджеста и теги Nonce и Created.
Я могу использовать этот веб-сервис, используя WSE 3.0 с BasicHTTPBinding. Но до сих пор мне не удалось реализовать то же самое с WCF с использованием WSHttpBinding или CustomBinding. Я'Мы перепробовали все элементы безопасности, и пока не повезло.
Я также использую библиотеку usernametoken отсюда (http://blogs.msdn.com/b/aszego/archive/2010/06/24/usernametoken-profile-vs-wcf.aspx), поэтому я могу добавить дайджест пароля / nonce /, созданный в UsernameToken в заголовке SOAP.
В настоящее время я использую SecurityBindingElement.CreateMutualCertificateBindingElement I 'мы также пробовали несколько других, таких как AsymmetricSecurityBindingElement, TransportSecurityBindingElement и т. д. (закомментировано в приведенном ниже коде)
CERTS: У меня есть и клиентский сертификат, и сертификат службы, загруженные в хранилище сертификатов с помощью MMC (кстати, в Windows 7). И у сертификата клиента, и у сертификата службы есть закрытые ключи. Я'Мы загрузили оба файла PFX в LocalMachine / Personal, LocalMachine / Root и LocalMachine / TrustedPeople. Я также запустил FindPrivateKey / ICACLS, чтобы дать разрешение «Пул приложений IIS / DefaultAppPool ” учетная запись. Хотя все это не имеет значения, так как я могу запустить код WSE 3.0 со своего компьютера, и он работает без каких-либо проблем.
Команды запускаются:
FindPrivateKey.exe My LocalMachine -t "thumbprint of client cert"
FindPrivateKey.exe My LocalMachine -t "thumbprint of service cert"
icacls C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\{privateKeyOfClientCert} /grant "IIS AppPool\DefaultAppPool":R
icacls C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\{privateKeyOfServiceCert} /grant "IIS AppPool\DefaultAppPool":R
ВОПРОС WCF: В настоящее время я получаюНе удалось установить безопасный канал для SSL / TLS с правами доступа 'x.x.com» сообщение обратно от шлюза DataPower. Я полагаю, что это может быть связано с тем, что шлюз принимает сертификат службы и использует его для аутентификации клиента, а не с помощью сертификата клиента, который я отправляю. Я говорю это потому, что когда я не указываю DNS-идентификатор для конечной точки, я получаю сообщение о том, что шлюз ожидает, что DNS-идентификатор будет «{имя субъекта услуги / сертификат подписи} ».
Вот SOAP-запрос, сгенерированный WCF, который выдает вышеуказанную ошибку. Запрос WCF SOAP выглядит очень похоже на запрос WSE SOAP. Вышеуказанная ошибка, скорее всего, возникает из-за проблемы с сертификатом на уровне SSL / транспорта.
WCF SOAP запрос:
2013-02-06T20:53:04.679Z
2013-02-06T20:58:04.679Z
Removed Service Cert Encoded Value
USER_Removed
XXX=
XXX==
2013-02-06T20:53:04Z
XXX=
XXX=
XXX=
XXXLongXXX=
hello
WAP 3.0 SOAP-запрос (это работает):
urn:uuid:ff8becb7-74c2-4844-ab46-8ae23f1355a7
http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous
https://x.x.com/xxx/v1
2013-02-06T19:38:39Z
2013-02-06T19:43:39Z
USER_Removed
XXX=
XXX==
2013-02-06T19:38:39Z
XXX=
XXX=
XXX=
XXX=
XXX=
XXX=
XXXLongXXX=
XXX=
hello
Вот все настройки, пожалуйста, дайте мне знать, что я делаю не так!
WCF web.config: я удалил все из web.config, так как я делаю всю конфигурацию в коде.
Конфигурация WCF в коде: я
var proxy = GetProxy();
pingResponseMessage resp = proxy.ping("hello");
lblStatus.Text = resp.status.ToString();
private XXXClient GetProxy()
{
System.Net.ServicePointManager.ServerCertificateValidationCallback += (se, cert, chain, sslerror) => { return true; };
XXXClient proxy = new XXXClient(GetCustomBinding(), new EndpointAddress(new Uri("https://xxx"), EndpointIdentity.CreateDnsIdentity("I am forced to put the signing cert subject here, nothing else works"), new AddressHeaderCollection()));
proxy.Endpoint.Behaviors.Remove(typeof(ClientCredentials));
proxy.Endpoint.Behaviors.Add(new UsernameClientCredentials(new UsernameInfo(@"USER_Removed", "X")));
proxy.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "REMOVED");
proxy.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "REMOVED");
proxy.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
return proxy;
}
private Binding GetCustomBinding()
{
//TransportSecurityBindingElement secBE = SecurityBindingElement.CreateCertificateOverTransportBindingElement(MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10);
//AsymmetricSecurityBindingElement secBE = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
//secBE.InitiatorTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient, RequireDerivedKeys = false, X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier };
//secBE.RecipientTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToInitiator, RequireDerivedKeys = false, X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier };
//secBE.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
//secBE.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters() { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient, RequireDerivedKeys = false });
//secBE.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters(X509KeyIdentifierClauseType.SubjectKeyIdentifier, SecurityTokenInclusionMode.Never) { InclusionMode = SecurityTokenInclusionMode.Never, RequireDerivedKeys = false, X509ReferenceStyle = X509KeyIdentifierClauseType.SubjectKeyIdentifier });
//secBE.ProtectionTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient };
//secBE.DefaultAlgorithmSuite = new CustomSecurityAlgorithm();
SecurityBindingElement secBE = SecurityBindingElement.CreateMutualCertificateBindingElement(MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10);
secBE.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
secBE.EndpointSupportingTokenParameters.Signed.Add(new UsernameTokenParameters() { InclusionMode= SecurityTokenInclusionMode.AlwaysToRecipient, ReferenceStyle = SecurityTokenReferenceStyle.External, RequireDerivedKeys = false });
secBE.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
//secBE.AllowInsecureTransport = false;
//secBE.AllowSerializedSigningTokenOnReply = false;
secBE.EnableUnsecuredResponse = true;
secBE.IncludeTimestamp = true;
secBE.SetKeyDerivation(false);
TextMessageEncodingBindingElement textEncBE = new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8);
HttpsTransportBindingElement httpsBE = new HttpsTransportBindingElement();
httpsBE.RequireClientCertificate = true;
//httpsBindingElement.AllowCookies = false;
//httpsBindingElement.AuthenticationScheme = System.Net.AuthenticationSchemes.Basic;
httpsBE.BypassProxyOnLocal = false;
httpsBE.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
//httpsBindingElement.KeepAliveEnabled = false;
httpsBE.TransferMode = TransferMode.Buffered;
httpsBE.UseDefaultWebProxy = true;
CustomBinding myBinding = new CustomBinding();
myBinding.Elements.Add(secBE);
myBinding.Elements.Add(textEncBE);
myBinding.Elements.Add(httpsBE);
return myBinding;
}
мы добавили ProtectionLevel.Sign в ServiceContract и OperationContracts, поскольку мне нужно только подписать тело сообщения. Я неЯ пока зашла так далеко, чтобы это проверить.
[System.ServiceModel.ServiceContractAttribute(Namespace = "https://x.x.com/xxx/v1", ConfigurationName = "x.x", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)]
public interface XXXService {
[System.ServiceModel.OperationContractAttribute(Action = "", ReplyAction = "*", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
[return: System.ServiceModel.MessageParameterAttribute(Name="return")]
XXX.pingResponse ping(XXX.ping request);
[System.ServiceModel.ServiceContractAttribute(Namespace = "https://x.x.com/xxx/v1", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)]
public partial class XXXClient : System.ServiceModel.ClientBase {
[System.ServiceModel.OperationContractAttribute(Action = "", ReplyAction = "*", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)]
public XXX.pingResponseMessage ping(string pingRequest) {
Мы добавили следующее в web.config, чтобы разрешить регистрацию всего мыла, включая данные pii.
(for pii, also added under to C:\Windows\Microsoft.NET\Framework\vX\CONFIG\machine.config)
===============
WSE 3.0 (рабочий конфиг и код): web.config:
... и код WSE3:
var proxy = new XXXImplServiceWse();
UsernameToken usernameToken = new UsernameToken(@"USER_Removed", "X");
proxy.RequestSoapContext.Security.Tokens.Add(usernameToken);
X509Certificate2 mutualCert = LoadCertFromStore(StoreLocation.LocalMachine, StoreName.My, "Client Cert Subject Name");
proxy.ClientCertificates.Add(mutualCert);
X509Certificate2 signCert = LoadCertFromStore(StoreLocation.LocalMachine, StoreName.My, "Service Cert Subject Name");
X509SecurityToken signatureToken = new X509SecurityToken(signCert);
MessageSignature signature = new MessageSignature(signatureToken); //
proxy.RequestSoapContext.Security.Elements.Add(signature);
==========
Итак, как мне преобразовать приведенный выше код WSE 3.0 в WCF?