Estoy usando una aplicación de escritorio en una PC cliente para comunicarme con un servicio web IIS WCF que se ejecuta en un servidor, usando WsHttpBinding para pasar las credenciales de usuario de Windows. La aplicación ha funcionado bien durante muchos años, pero ahora estamos intentando que se comunique a través de HTTPS en lugar de solo HTTP.
En el lado del servidor, agregamos un certificado SSL al sitio web de IIS y cambiamos WCF web.config para usar Transport security para la definición de enlace:
<wsHttpBinding> <binding name="WSHttpBinding_IService1"> <readerQuotas maxArrayLength="2147483647" /> <security mode="Transport" /> </binding> </wsHttpBinding>En el lado del cliente, el objeto del cliente que se usa para conectarse al servicio usa el modo de seguridad de transporte para tener en cuenta el modo de comunicación HTTPS:
Dim serverURL as String = ReadServerURL() Dim client As Service1Client Dim binding As Channels.Binding Dim dcso As ServiceModel.Description.DataContractSerializerOperationBehavior binding = New WSHttpBinding("WSHttpBinding_IService1") If serverURL.ToLower.StartsWith("https://") Then CType(binding, WSHttpBinding).Security.Mode = SecurityMode.Transport Else CType(binding, WSHttpBinding).Security.Mode = SecurityMode.Message End If CType(binding, WSHttpBinding).Security.Message.ClientCredentialType = MessageCredentialType.Windows CType(binding, WSHttpBinding).Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows binding.ReceiveTimeout = New TimeSpan(0, 10, 0) client = New Service1Client(binding, New EndpointAddress(serverURL)) client.ClientCredentials.Windows.ClientCredential = CType(CredentialCache.DefaultCredentials, NetworkCredential) client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.DelegationAlgunos clientes usan Kerberos para pasar las credenciales de Windows a otro servidor, razón por la cual usamos Delegación.
La mayoría de los clientes han optado por usar certificados autofirmados porque solo usan servidores internos.
En IIS, el sitio de WCF tiene habilitada la autenticación de Windows, con los proveedores de negociación y NTLM habilitados.
Este enfoque parece funcionar bien en la mayoría de los sitios de los clientes, pero al menos uno está experimentando este error:
La solicitud HTTP no está autorizada con el esquema de autenticación del cliente 'Negociar. El encabezado de autenticación recibido del servidor fue 'Negociar oXlwcKADCgEBomkEZ2....oZSQ='.
No estoy seguro de dónde proviene este proveedor alternativo 'Negociar oXlwcK...' en IIS o cómo configurar el cliente para comunicarse correctamente con él. ¿Se trata de un problema de configuración de IIS, un problema con el código de servicio WCF y/o el código de la aplicación cliente, o podría ser un problema de red/dominio? Cualquier ayuda es muy apreciada.
Si ve este problema llamando a un servicio WCF alojado en la misma máquina, es posible que deba completar la clave de registro BackConnectionHostNames.
En regedit, busque y luego haga clic en la siguiente subclave del registro: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
Haga clic con el botón derecho en MSV1_0, señale Nuevo y luego haga clic en Valor de cadena múltiple.
En la columna Nombre, escriba BackConnectionHostNames y luego presione ENTRAR.
Haga clic con el botón derecho en BackConnectionHostNames y luego haga clic en Modificar. En el cuadro Información del valor, escriba el CNAME o el alias de DNS, que se usa para los recursos compartidos locales en la computadora, y luego haga clic en Aceptar.
Escriba cada nombre de host en una línea separada.
Consulte llamar al servicio WCF alojado en IIS en la misma máquina que el cliente genera un error de autenticación para obtener más detalles.
Pude resolver este problema agregando un objeto UpnEndpointIdentity al constructor EndpointAddress .
Para el parámetro en UpnEndpointIdentity , tuve que usar el nombre de usuario que se muestra en la columna "Identidad" del grupo de aplicaciones de IIS. Por ejemplo var id = new UpnEndpointIdentity("DOMAIN\user.name");
Esto solo funcionó en .NET Framework pero no en .NET Core 3.1 (no probé .NET Core 5.0).