El otro día surgía en los foros la pregunta sobre como impersonar al usuario en las llamadas a los servicios web del CRM dentro del código .Net de un ensamblado de workflow. La documentación del SDK tiene un pequeño error sobre cómo conseguir esto, así que vamos a intentar aclarar cómo podemos conseguir está impersonación y porque es necesaria.
El Escenario
Como bien sabemos, en Microsoft Dynamics CRM disponemos de un motor de workflow que nos permite crear procesos de negocio que automaticen la realización de algunas tareas, y además, este motor de workflow puede ser extendido incluyendo nuevas acciones mediante código .Net 1.1.
El motor de Workflow se ejecuta como un servicio de Windows, «Microsoft CRM Workflow Service», y como cualquier servicio lo hace bajo unas determinadas credenciales de usuario. Por defecto, estas credenciales suelen ser las del Servicio de Red, aunque podemos cambiarlas en cualquier momento a través de la configuración del servicio. Este motor de workflow es el que se encarga de ejecutar las acciones programadas en los procesos de workflow, y por lo tanto será él el que ejecute el código de los ensamblados que hayamos añadido.
Es típico que desde este código personalizado queramos llamar a los servicios web del CRM para completar alguna tarea. Y en la mayor parte de las ocasiones queremos hacerlo en nombre del usuario que ha disparado la regla (impersonation), es decir, ejecutando la llamada a los servicios web con las credenciales del usuario. Sin embargo, si no hacemos nada el código se ejecutará bajo las credenciales que utilice el Servicio de Workflow (Servicio de Red por defecto) con lo que no conseguiremos obtener el resultado deseado.
Las credenciales del servicio de Workflow pueden ser modificadas para utilizar las de un usuario del CRM, de esta manera todas las llamadas a los servicios web desde un ensamblado de workflow utilizarán por defecto esas credenciales. Sin embargo, hacer esto no es una buena práctica, y puede introducir riesgos de seguridad.
Impersonación
Para hacer que las llamadas a los servicios web utilicen otras credenciales disponemos de varias opciones. La primera sería establecer unas nuevas credenciales «a mano» en el proxy del servicio web. Es decir fijar las credenciales de un determinado usuario mediante su nombre de login y contraseña.
1 | //Create crm service proxy |
De esta forma las llamadas al servicio web se harán en nombre de este usuario. Pero esto no es lo que buscamos, ya que de esta forma no estamos impersonando al usuario que dispara el workflow sino a un usuario específico del CRM, aunque en muchos casos esta es una solución válida.
En el SDK de Microsoft Dynamics CRM se comenta (ver código a continuación) un método para conseguir esto. Que se basa en fijar las credenciales por defecto, y establecer la propiedad CallerId (una cabecera de los mensajes SOAP del Servicio Web del CRM) con el valor del guid del usuario al que queremos impersonar.
1 | CrmService service = new CrmService(); |
Sin embargo, este método no consigue el resultado deseado ya que la utilización del mensaje WhoAmI devuelve, entre otras cosas, el guid del usuario a partir de las credenciales con las que se realiza la llamada (útil para aplicaciones integradas en el CRM), con lo que si lo hacemos desde un ensamblado de workflow nos devolverá el guid de la cuenta sobre la que se esté ejecutando el Servicio de Workflow. Cómo normalmente este se ejecuta con las credenciales del Servicio de Red, nos devolverá un guid que no pertenece a ningún usuario, si no a una cuenta de usuario especial llamada SYSTEM que no tiene permisos para realizar la mayoría de las tareas del CRM.
Entonces, ¿Cómo lo conseguimos? La respuesta está en usar el CallerID (también se menciona en el SDK). Se trata de un XML que contiene el guid del usuario que dispara la regla de workflow, y que puede ser pasado como parámetro por el motor de workflow al método del ensamblado .net. Para ello, a la hora de registrar nuestro ensamblado en el workflow.config, tendremos que especificar un parámetro del tipo caller. Y en nuestro código tendremos que recuperar del XML que viene en este parámetro el guid del usuario, podemos hacerlo mediante una función como la del ejemplo.
1 | private static Guid GetCaller(string callerXml) |
De esta forma conseguimos realmente impersonar al usuario que dispara la ejecución de la regla de workflow, y realizar operaciones en el CRM mediante los servicios web utilizando sus identidad (y sus permisos).
Espero que este rollo haya servido para aclarar un poquito el concepto de impersonación en el CRM y cómo podemos utilizarlo para llamar a los servicios web desde ensamblados personalizados de workflow. A continuación os dejo un ejemplo completo de un ensamblado que crea una actividad de fax utilizando impersonando al usuario. Proximamente, más ejemplos. Espero vuestro comentarios.
Un Saludo,
Marco Amoedo
Ejemplo Completo
– Workflow.config –
1 | <workflow.config xmlns=»http://microsoft.com/mscrm/workflow/» allowunsignedassemblies=»true»> |
– Código .Net –
1 | using System; |
Más información en el SDK de Microsoft Dynamics CRM.