Request directa a WEB API de CRM Online mediante Azure AD

Cómo hacer una petición directa a la WEB API de CRM para la versión Online mediante Azure AD.

Normalmente cuando queremos hacer una consulta a nuestra base de datos en CRM Dynamics utilizamos la SDK que Microsoft nos proporciona y escribimos un código donde instanciaremos el objeto OrganizationService desde el cual podremos ejecutar un RetrieveMultiple para obtener la información que deseemos de nuestro CRM.

Cuando disponemos de un CRM On Premise podemos también recurrir a la invocación de webservices con autenticación delegada o NTLM, cosa que no podemos hacer en el CRM Online.

Pero ¿qué ocurre si la aplicación que estamos desarrollando no está ideada en C#? En principio no podremos usar la SDK que nos proporciona Microsoft para integrarnos con el CRM. Una solución podría ser utilizar Xamarin para compilar nuestro código en otro lenguaje que necesitemos pero Xamarin no cubre todo el abanico de lenguajes. ¿Cómo podríamos integrarnos con un CRM Online si nuestra aplicación está hecha en PHP, NodeJS, Javascript, etc? ¿Podríamos conectar un CRM Online con otro CRM Online mediante Javascript y sin utilizar un Middleware?, ¿Un sistema tercero podría conectarse con nuestro CRM para enviar información sin necesidad de un Middleware? ¿Un JIRA podría integrarse con nuestro CRM directamente? La respuesta es que sí. Podemos realizar una petición a la API Rest de CRM directamente desde cualquier entorno utilizando el protocolo OAuth2 del Azure Active Directory.

Existe un modo genérico de integrarse con un CRM Online que podemos explotar desde cualquier lenguaje de programación que nos proporcione herramientas para ejecutar peticiones web.

El proceso es el siguiente: primero lanzamos una petición a Azure con nuestros credenciales y la URL del CRM sobre el que queremos ejecutar la query y será el propio Azure el que nos los validará. Si son correctos, Azure nos responderá a nuestra petición con un token. Este token es un “codigo de acceso temporal” a nuestro CRM. Podremos utilizar este código para hacer queries al CRM durante un tiempo limitado (normalmente 3600 segundos) y después caducará. Podremos entonces volver a pedir otro token y repetir el proceso.

Tenemos pues 2 peticiones web: obtener el token y realizar la query en CRM.

Vamos a ver cómo configurarlo paso a paso. Lo primero de todo que tenemos que tener en cuenta es que nuestro Dynamics 365 Online tendrá asociado siempre una cuenta de Azure.

Accedemos a nuestro CRM Online:

Página de inicio de CRM Dynamics 365

Página de inicio de CRM Dynamics 365

 

Una vez logados en nuestro CRM accedemos a Azure mediante el portal de acceso: https://portal.azure.com. El usuario con el que nos hará automáticamente el login será el mismo que nuestro CRM Online.

Página de inicio de Azure

Página de inicio de Azure

 

Accedemos a la sección Registro de aplicaciones mediante la barra de búsqueda superior.

Búsqueda de "Registro de aplicaciones" en azure

Búsqueda de “Registro de aplicaciones” en azure

 

Accedemos a Puntos de conexión en la parte superior.

Puntos de conexiones o "endpoints"

Puntos de conexiones o “endpoints”

 

Bajamos un poco y copiamos la URL del Punto de conexión de token de OAuth 2.0. La URL será del estilo: https://login.microsoftonline.com/d627e6dd-343b-4323-8d8d-b9381c722c7a/oauth2/token

Descripción de puntos de conexión. Token de OAuth 2.0

Descripción de puntos de conexión. Token de OAuth 2.0

 

Bien, esta será la URL a la que tendremos que solicitar el token. Nos la guardamos para más adelante.

Volvemos a Registro de aplicaciones y creamos una nueva aplicación.

Nuevo registro de aplicación

Nuevo registro de aplicación

 

De nombre pondremos “Acceso API CRM”, tipo de aplicación “Aplicación web o API” y URL de inicio de sesión podremos la URL de nuestro Dynamics:

Detalles de la nueva aplicación

Detalles de la nueva aplicación

 

Una vez creada la buscamos entre la lista y la abrimos. Vamos al apartado Propiedades y copiamos el código  Id de aplicación. Este ID lo tendremos que incluir también en petición de token. Lo guardamos junto con la URL.

Propiedades de la nueva aplicación

Propiedades de la nueva aplicación

 

Vamos al apartado Claves:

Claves de la aplicación

Claves de la aplicación

 

Creamos una nueva Clave con descripción “Token” y que expire en 1 año (eres libre de seleccionar lo que más te convenga en este punto). Pulsamos “Guardar” y nos aparecerá el valor (denominado secreto). Debemos copiarlo y guardarlo en este instante pues no tendremos otra posibilidad de volver a conseguirlo:

"Secreto" del token de la nueva aplicación

“Secreto” del token de la nueva aplicación

 

Vamos al apartado Permisos necesarios y pulsamos en Agregar.

Agregar permisos de aplicación

Agregar permisos de aplicación

 

Como API seleccionamos Dynamics CRM Online.

Seleccionar aplicación Dynamics CRM Online

Seleccionar aplicación Dynamics CRM Online

 

Como permisos seleccionamos Access CRM Online as organization users.

Seleccionar permisos delegados

Seleccionar permisos delegados

 

Una vez agregado tenemos que pulsar “Conceder permisos” en la parte superior. Importante: si estás en un Azure de una compañía esta acción la tendrá que realizar un administrador.

Conceder permisos

Conceder permisos

 

Con esto ya tenemos configurado lo necesario en Azure.

Los datos que tendremos por el momento son los siguientes:

Dato Valor Descripción
URL OAuth2.0  https://login.microsoftonline.com/d627e6dd-343b-4323-8d8d-b9381c722c7a/oauth2/token La URL de petición de token
URL CRM  https://micrm.crm4.dynamics.com/ La URL de nuestro CRM
Usuario CRM  ddiaz@micrm.onmicrosoft.com Usuario de nuestro CRM
Password CRM  MiPassw0rd! El password de nuestro usuario
Id Aplicación  b68b3b21-9f40-4923-85e1-7f8e3bc5b746 Id de la aplicación creada en Azure
Secreto  I/sRo1MyR6wRFUS9RgYnCJmCMWiIbq2IPx9evCm45Qc= Disponible solo por 1 año

Con esta información ya podemos ejecutar una query sobre nuestro CRM.

 

Peticiones web

Obtención de token

Los datos que tenemos que incluir en la petición de token son los siguientes

Nombre Key Value
ID Cliente client_id b68b3b21-9f40-4923-85e1-7f8e3bc5b746
URL CRM* resource https://micrm.crm4.dynamics.com/
Usuario* username ddiaz@micrm.onmicrosoft.com
Contraseña* password MiPassw0rd!
Tipo acceso grant_type password
Secreto client_secret I/sRo1MyR6wRFUS9RgYnCJmCMWiIbq2IPx9evCm45Qc=

(*) Los valores tendrán que ser incluidos con encodeURIComponent, por ejemplo el usuario ddiaz@micrm.onmicrosoft.com quedaría como ddiaz%40micrm.onmicrosoft.com

La petición que tendremos que lanzar será

Un ejemplo de petición con datos reales

La respuesta a la petición será como la siguiente:

Y el parámetro en cuestión que nos interesa es el access_token. Con esto ya tenemos el token.

 

Ejecución de query

Una vez que tenemos el token podemos acceder a la WEB API de CRM invocando cualquiera de sus métodos, siempre teniendo en cuenta el nivel de seguridad del usuario para el que hemos obtenido el token. Esto significa que si el usuario ddiaz@micrm.onmicrosoft.com no tiene permisos en CRM para editar contactos, no podrá ejecutar una petición de actualización de un contacto.

Otro punto importante es que mediante este método solo podremos acceder a la WEB API de tipo Rest de CRM y no podremos invocar peticiones directas al OrganizationService con SOAP.

La petición que hagamos tendrá que incluir en el header la propiedad “Authorization” con el valor “Bearer:” + token. Esto será suficiente para obtener acceso a la base de datos de CRM.

El ejemplo que vamos a mostrar es una petición a la API Rest para crear un contacto en CRM.

La petición sería:

 

La URL a donde  enviaremos la petición es de la API Rest de CRM. En particular nos referimos a la entidad “Contacto”. Como vemos, en el header incluimos el token con la palabra “Bearer:” antes. El método POST indica que queremos crear un registro de la entidad. Y en el objeto Data incluimos los logicalName de los campos de la entidad y sus correspondientes valores.

Para sacar partido a la WEB API de CRM existe mucha documentación oficial al respecto para ejecutar cualquier acción sobre nuestra base de datos.

 

Resultados

He implementado un pequeño código de ejemplo en Javascript para hacer la prueba. En particular he utilizado la librería Angular para realizar las peticiones http, pero podría implementarse sin Angular o con cualquier otro framework.

Los archivos que he utilizado son los siguientes:

Archivos del ejemplo de autenticación por OAuth 2.0

Archivos del ejemplo de autenticación por OAuth 2.0

El framework de Angular lo podéis descargar del sitio oficial. Los archivos indexOauth.html y js_api_rest_oauth.js los detallo a continuación:

indexOauth.html:

js_api_rest_oauth.js:

El resultado de la ejecución del código anterior genera la siguiente respuesta:

Resultados de ejecución del ejemplo

Resultados de ejecución del ejemplo

Si lo ejecutáis desde vuestro PC en local es posible que obtengáis el error de No ‘Access-Control-Allow-Origin’. Para solucionarlo existen extensiones de Google Chrome que lo resuelven.

Como veis hemos creado un contacto en CRM a través de un token obtenido mediante OAuth del Azure Active Directory ejecutando una petición a la WEB API.

Espero que os sirva!

 

Obtener el OrganizationService heredado del USD

Cuando queremos meter algún tipo de funcionalidad específica en nuestro USD lo realizamos mediante un Custom Hosted Control. Este control se realizaría desde Visual Studio extendiendo la clase DynamicsBaseHostedControl del compilado Microsoft.Crm.UnifiedServiceDesk. Esta clase a su vez implementa varias interfaces como son IDesktopUserActionsConsumer, IUsdControl y ISessionInfoConsumer. Estas interfaces incluyen funciones  como el DoAction –que se utiliza para recibir ActionsCalls del USD en nuestra clase- , el DesktopReady –que se ejecuta cuando el USD ha cargado-  o el NotifyContextChange –evento de cambio en alguna variable del contexto- entre otras. Dentro de todas estas funciones es muy probable que necesitemos interactuar con nuestro CRM. Como siempre, la API de CRM nos permitirá hacerlo utilizando el objeto OrganizationService. Como ya sabréis este objeto se puede instanciar utilizando una cadena de conexión con la IP de nuestro CRM y el usuario y contraseña de un usuario del CRM.

Pero puesto que en USD ya nos hemos tenido que identificar para poder acceder al mismo introduciendo unos credenciales al inicio –o en su defecto utilizando los credenciales del Active Directory- no sería práctico volver a instanciar el objecto OrganizationService puesto que deberíamos volver a preguntar al usuario sus credenciales.

El USD por dentro utiliza un objecto OrganizationService de igual modo que cuando realizamos un programa nosotros. Este objeto OrganizationService se instancia de los credenciales iniciales que se introducen en la pantalla de inicio del USD –la clásica pantalla azul de USD- y se utiliza internamente para descargar toda la configuración del agente al PC desde donde se está ejecutando el USD.

Probablemente existan varios métodos para obtener este objeto instanciado en nuestro código. Yo únicamente conozco dos.

El primero es heredar en nuestra clase la clase AifServiceBase. Esta clase que está en la librería Microsoft.Uii.AifServices, en el contexto de USD hereda el objeto OrganizationService para poder utilizarlo. El esquema que yo utilizaría sería, por un lado, la clase principal de la dll -la que incluiremos como Hosted Control en nuestra configuración- que hereda del  DynamicsBaseHostedControl  y por otro lado una clase que actúe de interface entre USD y CRM que herede del AifServiceBase. Dentro de la primera clase instanciaremos la segunda una sola vez pudiendo acceder al objeto a partir de ese momento.

Ejemplo estructura clases Custom Hosted Control con AifService

Ejemplo estructura clases Custom Hosted Control con AifService



Como lado negativo de este método comentar que a mi únicamente me ha funcionado con la versión 1.2 de USD y sospecho que es debido a que el AifService requiere la dll Microsoft.Crm.Sdk.Proxy que únicamente está incluida en la SDK de 2015 y por algún motivo no funciona en versiones de compilados superiores.

El segundo método y el más sencillo es obtener el IOrganizationService directamente del objeto Global Manager.

El USD siempre requiere de tres objetos principales y que son, podríamos decir, obligatorios: El Global Manager, el  Connection Manager y el Panel Layout. La idea es obtener en nuestra clase el Global Manager del USD y extraer el OrganizationService de dentro del objeto.

Para ello únicamente necesitamos conocer el nombre del Hosted Control de tipo Global Manager. El nombre lo obtenemos de la configuración del Unified Service Desk de nuestro CRM. Si durante la instalación del USD seleccionamos la opción de incluir datos de ejemplo, este Hosted Control ya estaría creado en nuestro primer USD. Si por el contrario hicimos una instalación limpia, tuvimos que crearlo nosotros mismos en algún momento. Lo que necesitamos es el nombre del Hosted Control, esto es, el string que se ve en la configuración.

Nombre del Hosted Control Global Manager

Nombre del Hosted Control Global Manager

En nuestro caso el Hosted Control se llama “Global Manager” por lo que para obtener el OrganizationService simplemente deberíamos de ejecutar la siguiente línea: