Después de unos cuantos choques contra la pared lo he conseguido. En este post explico lo que he hecho para que funcione y también he puesto unos cuantos recursos que he encontrado durante la investigación.
Servicio Paso 1: Bindings y Seguridad
Para maximizar la interoperativilidad de un servicio WCF, manteniendo el flujo de credenciales, el servicio WCF necesita ser configurado de una manera especial. Lo más crítico es la configuración adecuada de los bindings y de la seguridad; he tardado mucho tiempo en conseguir un basicHttpbinding con el modo seguro “TransportWithMessageCredentials”. Esta resultó ser la manera incorrecta de hacerlo (en nuestro caso). El modo de seguridad era en Transporte con las credenciales (clientCredentialType) de Windows.
<basicHttpBinding>
<binding name=”basic”>
<security mode=”Transport”>
<transport clientCredentialType=”Windows” />
</security>
</binding>
</basicHttpBinding>
Básicamente estamos diciendo que la seguridad estará en la capa de transporte (SSL con http- https), con las credenciales de windows que se pasarán a nivel de transporte (cabeceras http – creo). El siguiente problema es hostear el servicio en IIS.
Servicio Paso 2. Configuración de IIS
Las credenciales en IIS deben corresponderse con la configuración del binding del servicio. En este caso, lo que quiere decir es que deshabilitemos el acceso anónimo y habilitemos la autenticación de windows. Fijáos que el servicio debe hostearse en un sitio SSL (en este post se explica cómo configurarlo). Intentad crear y ver el servicio.
Si véis un mensaje de error diciendo que el servicio necesita acceso anónimo significa que hay algún problema con vuestros bindings. En mi caso esto se debía a que tenía un endpoint mex para el servicio (ya que se genera automáticamente), pero como no usaba la mísma configuración del binding estaba dando problemas cuando le pedía acceso anónimo (en IIS). Es importante que todos los endpoints del servicio tengan opciones compatibles de seguridad.
Si veis un error diciendo que el servicio necesita autenticación de windows, eso es debido a un problema con IIS (En este blog está la solución – notad que en nuestro caso, debido a una configuración compleja d IIS, las instrucciones no estaban del todo bien, básicamente, aseguraos de que la seccion <IISWebService> que hace referencia a tu sitio, la línea NTAuthenticationProviders=”Negotiate,NTLM” está incluida).
Hasta este punto deberíais ser capaces de ver el servicio en vuestro navegador y ver el wsdl.
Servicio Paso 3 – Mejorando la interoperativilidad de WSDL
El comportamiento por defecto de WCF permite importar documentos wsdl y esquemas xsd (usando la sintaxis wsdl=wsdl0, xsd=xsd0). Algunas herramientas de generación de proxies no son capaces de manejar estas importaciones. Sin embargo para mejorar la interoperativilidad haced lo siguiente:
Usad WSDLExportExtension para incluir el XSD inline
Los comportamientos (behaviours) de WCF permiten sobreescribir la manera en que se generar los wsdl. Un behaviour personalizado puede eliminar todas las csd importadas y meterlas inline. Los detalles los tenéis en
http://www.winterdom.com/weblog/2006/10/03/InlineXSDInWSDLWithWCF.aspx
Que todas las wsdl aparezcan inline
También es posible usar un behaviour personalizado para importar inline todas las wsdl, sin embargo hasta donde he llegado, nadie ha creado esto. En el lado positivo tenemos que todos los tipos de contratos (datos, servicio, …) comparten el mismo namespace xml así que no se importan ningun wsdl.
Cliente Paso 1. Preparar el wsdl para consumirlo.
Incluso con las mejoras en la interoperativilidad de WSDL la herramienta de generación de proxis de C++ (sproxy) fallará con este WSDL debido a las opciones de seguridad que se incluyen en las secciones ws-policy. Para no tener este problema, haced una copia local de wsdl guardándolo desde el navegador. Entonces eliminad cualquier mención a las políticas.
Cliente Paso2. Generar un proxy C++ con sproxy
Abrimos una consola de Visual Studio (esto lo podemos hacer también desde Visual Studio en “Add Web Reference”, pero en la práctica parece haber algunas diferencias). Id al direcotrio donde guardamos el wsdl y escribimos el siguiente comando
>sproxy /wsdl ArchivoWSDL.wsdl
Cliente Paso 3. Incluir el proxy en nuestro proyecto C++
Simplemente coged el contenido de los archivos generados anteriormente y pegadlos en un archivo de cabecera estándar de C++.
Cliente Paso 4. Llamad al servicio
El proxy generado usa CSoapSocketClientT para hacer las llamadas al servicio. Sin embargo podemos especificar un tipo diferente (ya que es conforme con el Arquetipo Cliente Soap de ATL), es decir, podemos usar CSoapWininetClient, este tipo se ha creado para usar comunicaciones seguras de manera que las credenciales cliente se pueden incluir automáticamente. Aunque mi cliente es sólo una aplicación de consola, y en el momento en el que deja de funcionar (No soy un experto en C++), consigue llamar al servicio y obtener la respuesta.
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
{
CTestInterfaceT<CSoapWininetClient> cli;
int te;
HRESULT res= cli.MyOperation(&te);
cli.Cleanup();
}
Uninitialize();
return 0;
}
Y lo que tenemos aquí señoras y caballeros es un cliente en C++ no manegado llamando a un servicio WCF con seguridad y autenticación en el transporte!!!!!
Traducido por: Juan María Laó Ramos.