2016-08-16 3 views
7

Я сталкиваюсь следующее сообщение об ошибке при попытке подключиться к WCF API, который находится за HTTPS прокси:WCF WS2007FederationHttpBinding с HTTPS

сертификат сервера с именем «CN = имя хоста» не прошла проверку идентичности, так как его отпечатком (» X ') не совпадает с указанным в идентификаторе конечной точки (' Y ​​'). В результате текущий запрос HTTPS не удался. Обновите идентификатор конечной точки, используемый на клиенте или сертификат, используемый сервером.

Где X является отпечатком сертификата, используемого прокси-сервером и Y Отпечаток сертификата, используемого службой

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

Я воспроизвел проблему на своем ПК с помощью локального прокси SSL, сертификат, используемый на прокси, доверен на моем ПК. При использовании HTTP все нормально.

Я искал решение в течение нескольких дней, и теперь я заметил эту статью KB, которая близка к моей проблеме, но не применимо больше (я бегу образец и сервер в .Net 4.5): https://support.microsoft.com/en-us/kb/2564823

Что я не хватает?

Вот код:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us"); 

     string serverUrl = ConfigurationManager.AppSettings["ServerURL"]; 
     GenericXmlSecurityToken token = GetToken(serverUrl); 

     Console.WriteLine("Token Received"); 
     Console.WriteLine(token); 

     TestServiceClient client = CreateClient(serverUrl, token); 

     try 
     { 
      client.SearchSomething(); 

      Console.WriteLine("SearchSomething succeeded"); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("SearchSomething failed :" + e); 
     } 

     Console.ReadLine(); 

    } 

    private static TestServiceClient CreateClient(string serverUrl, GenericXmlSecurityToken token) 
    { 
     var binding = new WS2007FederationHttpBinding(WSFederationHttpSecurityMode.Message) 
     { 
      MaxReceivedMessageSize = int.MaxValue, 
      MaxBufferPoolSize = int.MaxValue 
     }; 

     binding.Security.Message.EstablishSecurityContext = false; 
     binding.Security.Message.IssuedTokenType = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"; 
     binding.Security.Message.NegotiateServiceCredential = false; 

     binding.ReaderQuotas.MaxDepth = int.MaxValue; 
     binding.ReaderQuotas.MaxStringContentLength = int.MaxValue; 
     binding.ReaderQuotas.MaxArrayLength = int.MaxValue; 
     binding.ReaderQuotas.MaxBytesPerRead = int.MaxValue; 
     binding.ReaderQuotas.MaxNameTableCharCount = int.MaxValue; 

     var uri = new Uri(serverUrl + "Test.Service/Test.Service.svc"); 

     var identity = new X509CertificateEndpointIdentity(new X509Certificate2(ConfigurationManager.AppSettings["ServiceCertificate"], ConfigurationManager.AppSettings["ServiceCertificatePassword"])); 

     var client = new TestServiceClient(binding, new EndpointAddress(uri, identity)); 
     client.ClientCredentials.SupportInteractive = false; 

     var customBinding = new CustomBinding(); 
     var bindingElements = binding.CreateBindingElements(); 

     if (serverUrl.Contains("https")) 
     { 
      bindingElements.Remove<HttpTransportBindingElement>(); 

      bindingElements.Add(new HttpsTransportBindingElement() { MaxReceivedMessageSize = int.MaxValue }); 
     } 
     customBinding.Elements.AddRange(bindingElements.ToArray()); 

     client.Endpoint.Binding = customBinding; 

     var clientCredentials = new SamlClientCredentials(token, client.ClientCredentials); 
     client.Endpoint.Behaviors.Remove<ClientCredentials>(); 
     client.Endpoint.Behaviors.Add(clientCredentials); 

     return client; 
    } 

    private static GenericXmlSecurityToken GetToken(string serverUrl) 
    { 
     string username = ConfigurationManager.AppSettings["Username"]; 
     string password = ConfigurationManager.AppSettings["Password"]; 
     string identityDnsName = ConfigurationManager.AppSettings["IdentityDnsName"]; 
     string ClientCertificate = ConfigurationManager.AppSettings["ClientCertificate"]; 
     string ClientCertificatePassword = ConfigurationManager.AppSettings["ClientCertificatePassword"]; 
     string ServiceCertificate = ConfigurationManager.AppSettings["ServiceCertificate"]; 
     string ServiceCertificatePassword = ConfigurationManager.AppSettings["ServiceCertificatePassword"]; 

     var stsUrl = serverUrl + "Security.Sts/Security.Sts.svc"; 

     GenericXmlSecurityToken token = null; 

     try 
     { 
      var customBinding = new CustomBinding(); 

      var securityBindingElement = 
       (SymmetricSecurityBindingElement) SecurityBindingElement.CreateMutualCertificateBindingElement(); 
      securityBindingElement.SetKeyDerivation(true); 
      securityBindingElement.MessageSecurityVersion = 
       MessageSecurityVersion 
        .WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10; 
      securityBindingElement.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt; 
      securityBindingElement.RequireSignatureConfirmation = false; 

      var securityTokenParameters = new UserNameSecurityTokenParameters() 
      { 
       InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient, 
       RequireDerivedKeys = false 
      }; 
      securityBindingElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(securityTokenParameters); 
      customBinding.Elements.Add(securityBindingElement); 

      if (serverUrl.StartsWith("http:")) 
       customBinding.Elements.Add(new HttpTransportBindingElement() 
       { 
        MaxReceivedMessageSize = int.MaxValue, 
        MaxBufferPoolSize = int.MaxValue, 
        MaxBufferSize = int.MaxValue 
       }); 
      else if (serverUrl.StartsWith("https:")) 
       customBinding.Elements.Add(new HttpsTransportBindingElement() 
       { 
        MaxReceivedMessageSize = int.MaxValue, 
        MaxBufferPoolSize = int.MaxValue, 
        MaxBufferSize = int.MaxValue 
       }); 

      var stsChannelFactory = new WSTrustChannelFactory(customBinding, 
       new EndpointAddress(new Uri(stsUrl), new DnsEndpointIdentity(identityDnsName))); 

      stsChannelFactory.Credentials.SupportInteractive = false; 

      stsChannelFactory.Credentials.ClientCertificate.Certificate = new X509Certificate2(ClientCertificate, 
       ClientCertificatePassword); 
      stsChannelFactory.Credentials.ServiceCertificate.DefaultCertificate = 
       new X509Certificate2(ServiceCertificate, ServiceCertificatePassword); 
      stsChannelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = 
       X509CertificateValidationMode.None; 

      stsChannelFactory.Credentials.UserName.UserName = username; 
      stsChannelFactory.Credentials.UserName.Password = password; 

      foreach (OperationDescription operationDescription in stsChannelFactory.Endpoint.Contract.Operations) 
      { 
       var operationBehavior = 
        operationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>(); 
       if (operationBehavior != null) 
        operationBehavior.MaxItemsInObjectGraph = int.MaxValue; 
      } 

      var stsChannel = stsChannelFactory.CreateChannel(); 

      RequestSecurityToken request = new RequestSecurityToken(); 
      request.KeyType = "http://schemas.microsoft.com/idfx/keytype/symmetric"; 
      request.RequestType = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue"; 
      request.TokenType = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"; 
      token = (GenericXmlSecurityToken) stsChannel.Issue(request); 

      return token; 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine("GetToken Exception :" + e); 
     } 
     return token; 
    } 
} 

internal class SamlClientCredentials : ClientCredentials 
{ 
    public GenericXmlSecurityToken Token { get; private set; } 

    public SamlClientCredentials(GenericXmlSecurityToken token, ClientCredentials clientCredentials) 
     : base(clientCredentials) 
    { 
     Token = token; 
    } 

    protected override ClientCredentials CloneCore() 
    { 
     return new SamlClientCredentials(Token, this); 
    } 

    public override SecurityTokenManager CreateSecurityTokenManager() 
    { 
     return new SamlSecurityTokenManager(this); 
    } 
} 

internal class SamlSecurityTokenManager : ClientCredentialsSecurityTokenManager 
{ 
    private SamlClientCredentials clientCredentials; 

    public SamlSecurityTokenManager(SamlClientCredentials clientCredentials) 
     : base(clientCredentials) 
    { 
     this.clientCredentials = clientCredentials; 
    } 

    public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) 
    { 
     if (tokenRequirement.TokenType == SecurityTokenTypes.Saml || tokenRequirement.TokenType == "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1") 
      return new SamlSecurityTokenProvider(this.clientCredentials.Token); 
     return base.CreateSecurityTokenProvider(tokenRequirement); 
    } 
} 

internal class SamlSecurityTokenProvider : SecurityTokenProvider 
{ 
    private readonly GenericXmlSecurityToken token; 

    public SamlSecurityTokenProvider(GenericXmlSecurityToken token) 
    { 
     this.token = token; 
    } 

    protected override SecurityToken GetTokenCore(TimeSpan timeout) 
    { 
     return token; 
    } 
} 
+0

После много времени, затраченного на поиск решения, представляется, что WS2007FederationHttpBinding с «Сообщение» Режим безопасности не предназначен для использования в этот контекст из-за проверки подлинности сервера. Тем не менее, можно использовать один и тот же сертификат для перегружателя SSL и для идентификации службы. – Bren

+0

Другой режим безопасности «TransportWithMessageCredential» предназначен для использования с HTTPS, однако сообщение защищено только между клиентом и SSL-разгрузчиком, а также привязка должна быть изменена на стороне сервера, поскольку веб-сервер не обрабатывает HTTPS в соответствии с : [link] (http://blog.hackedbrain.com/2006/09/26/how-to-ssl-passthrough-with-wcf-or-transportwithmessagecredential-over-plain-http/) [link] (https: //social.msdn.microsoft.com/Forums/vstudio/en-US/87a254c8-e9d1-4d4c-8f62-54eae497423f/how-to-ssl-passthrough-from-bigip?forum=wcf) – Bren

ответ

0

Как я прокомментировал вопрос: После много времени, затраченных на поиск решения, представляется, что WS2007FederationHttpBinding с «Сообщением» режим безопасности не должен быть используется в этом контексте из-за проверки идентификатора сервера. Тем не менее, можно использовать один и тот же сертификат для перегружателя SSL и для идентификации службы.

Это решение, которое я выбрал, чтобы сохранить модель безопасности и решить мою проблему