node.js dynamics-crm azure-active-directory microsoft-dynamics adfs

node.js - Cómo consultar un Dynamics CRM local desde una aplicación web(Nodo/Express)



dynamics-crm azure-active-directory (1)

¡Estuve golpeando mi cabeza contra algunas paredes con esto, así que espero que algunos expertos en CRM / Dynamics puedan ayudarme!

Estoy tratando de obtener datos de forma programática de nuestra instancia de Dynamics CRM, usando un único conjunto de credenciales de administrador dentro de una aplicación Express de Node. Esta aplicación Express está alojada en un servidor separado fuera de nuestra red donde se hospeda CRM. Luego, la aplicación solicitará, procesará y entregará datos de CRM a cualquier usuario que haya iniciado sesión (controlado por roles / permisos dentro de la aplicación), lo que significa que un usuario final solo tiene que iniciar sesión en la aplicación Express, y no tiene que iniciar sesión a través de ADFS para que la aplicación acceda a la instancia de CRM.

Nuestra configuración de CRM es un servidor local configurado para estar orientado a Internet (IFD). Esto utiliza servicios de federación de Active Directory. Tenemos servidores proxy de aplicaciones web que ejecutan servicios de federación en el perímetro de la red que se comunican con los servidores ADFS en la red interna. ADFS autentica a los usuarios que se conectan desde fuera de la red (desde Internet) contra el AD prematuro. Una vez autenticado, el proxy permite a los usuarios conectarse a través de CRM.

Nuestro directorio activo principal se sincroniza con Azure AD ya que tenemos una implementación híbrida. Cualquier servicio O365 (intercambio en línea, sharepoint, etc.) usa Azure AD en segundo plano. Sincronizamos el directorio activo, por lo que solo tenemos que administrar usuarios en un solo lugar.

El CRM tiene un punto final, por ejemplo, https://my.crm.endpoint y he registrado una aplicación (llamada CRM App) en el Portal de Azure, con la página de inicio configurada en el punto final de CRM https://my.crm.endpoint .

Pregunta ¿Es la configuración de la página de inicio de la aplicación en https://my.crm.endpoint suficiente para "vincularla" con nuestra instancia de CRM local?

He escrito una secuencia de comandos (crm.js) que solicita correctamente un token de acceso para mi aplicación de CRM registrada en el Portal de Azure, utilizando su ID de aplicación.

Token de Ejemplo

eyJ0dWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzE5ZTk1...

Utilizando el token de portador, luego intento sacar algunos contactos de Dynamics a través del punto final habitual: https://my.crm.endpoint/api/data/v8.2/contacts?$select=fullname,contactid

Esto falla y recibo un mensaje de error 401 Unauthorised .

Pregunta: ¿Puede alguien sugerir cuál podría ser el problema? ¿Y / o proporciona detalles de cómo puede conectar una aplicación web (Express en mi caso) para realizar solicitudes autenticadas a Dynamics CRM que se ejecuta en un servidor local (IFD) que usa ADFS?

crm.js

let util = require(''util''); let request = require("request"); let test = { username: ''<[email protected]>'', password: ''<my_password>'', app_id: ''<app_id>'', secret: ''<secret>'', authenticate_url: ''https://login.microsoftonline.com/<tenant_id>/oauth2/token'', crm_url: ''https://<my.crm.endpoint>'' }; function CRM() { } CRM.prototype.authenticate = function () { return new Promise((resolve, reject) => { let options = { method: ''POST'', url: test.authenticate_url, formData: { grant_type: ''client_credentials'', client_id: test.app_id, // application id client_secret: test.secret, // secret username: test.username, // on premise windows login (admin) password: test.password, // password resource: test.app_id // application id } }; // ALWAYS RETURNS AN ACCESS_TOKEN request(options, function (error, response, body) { console.log(''AUTHENTICATE RESPONSE'', body); resolve(body); }); }) }; CRM.prototype.getContacts = function (token) { return new Promise((resolve, reject) => { let options = { method: ''GET'', url: `${test.crm_url}/api/data/v8.2/contacts?$select=fullname,contactid`, headers: { ''Authorization'': `Bearer ${token}`, ''Accept'': ''application/json'', ''OData-MaxVersion'': 4.0, ''OData-Version'': 4.0, ''Content-Type'': ''application/json; charset=utf-8'' } }; request(options, (error, response, body) => { console.log(''getContacts'', util.inspect(error), util.inspect(body)); resolve(body); }); }); }; let API = new CRM(); // instantiate the CRM object API.authenticate() // call authenticate function .then(response => { if (response) { let json = JSON.parse(response); let token = json.access_token; console.log(''TOKEN'', token); API.getContacts(''token'') .then(contacts => { // DO SOMETHING WITH THE CONTACTS console.log(''CONTACTS'', contacts); }) } }); module.exports = CRM;

Respuesta de error

HTTP Error 401 - Unauthorized: Access is denied

INFORMACIÓN ADICIONAL

Mi solución actual se basa en estos documentos ...

https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service

ACTUALIZAR

Siguiendo el comentario de @andresm53, creo que necesito autenticar directamente contra ADFS. He encontrado esta publicación de blog que describe cómo generar un secreto compartido en ADFS que se puede usar con OAuth.

"Al usar esta forma de Autenticación del cliente, enviaría su identificador de cliente (como client_id) y su secreto de cliente (como client_secret) al punto final de STS. Aquí hay un ejemplo de tal POST HTTP (usando la concesión de credenciales del cliente, solo saltos de línea agregados para la legibilidad): "

resource=https%3a%2f%2fmy.crm.endpoint &client_id=**2954b462-a5de-5af6-83bc-497cc20bddde ** ??????? &client_secret=56V0RnQ1COwhf4YbN9VSkECTKW9sOHsgIuTl1FV9 &grant_type=client_credentials

ACTUALIZACIÓN 2

Ahora he creado la aplicación de servidor en ADFS y estoy POSTANDO la carga útil anterior con el client_id y client_secret correctos.

Sin embargo, recibo un mensaje de Object moved .

RESOLVED BODY: ''<html><head><title>Object moved</title></head><body>/r/n<h2>Object moved to <a href="https://fs.our.domain.name/adfs/ls/?wa=wsignin1.0&amp;wtrealm=https%3a%2f%2fmy.crm.endpoint%2f&amp;wctx=http%253a%252f%252f2954b462-a5de-5af6-83bc-497cc20bddde%252f&amp;wct=2018-04-16T13%3a17%3a29Z&amp;wauth=urn%3afederation%3aauthentication%3awindows">here</a>.</h2>/r/n</body></html>/r/n''

PREGUNTA ¿Puede alguien, por favor, describir lo que estoy haciendo mal y lo que debería estar haciendo para autenticarme contra ADFS / CRM correctamente?

NB: cuando estoy en mi navegador y visito https://my.crm.endpoint , se me solicita que ingrese mi nombre de usuario y contraseña. Ingresar mis credenciales funciona y obtengo acceso a CRM. ¿Ha notado en la pestaña de la red que está usando NTLM para hacer esto? ¿Cambia esto el enfoque que necesito tomar?

ACTUALIZACIÓN 3

Por favor vea la nueva pregunta here


Tuvimos esta situación similar. Nuestra organización es OnPrem 8.2. Es accesible a través de VPN o desde la red doméstica. Si nos fijamos en el problema de manera muy básica, no se puede acceder a nuestro CRM desde fuera.

Lo que hicimos fue

  1. Creamos WebAPI para la acción desde CRM.
  2. Expusimos este WebAPI a través del puerto adicional al mundo exterior.
  3. Agregamos este WebAPI en IIS como un servicio.
  4. Pero nos aseguramos de que solo se pudiera acceder a este WebAPI a través de un nombre de usuario y contraseña específicos que creamos en nuestro archivo web.config.
  5. En Antecedentes lo que hicimos fue creado Acción.
  6. La acción a su vez ejecutará el complemento y devolverá los datos según lo solicitado, es decir, la URL de WebAPI se puede modificar. Por ejemplo: ... / las cuentas se devolverán para la entidad de la Cuenta siempre que tenga la lógica incorporada en su complemento.

    No confunda esto con Dynamics CRM OOB WebAPI. Lo que quiero decir es que crear nuestra propia API y agregar esto como un servicio en IIS con su propio nombre de usuario y contraseña.

Supongo que esto le dará al menos algún indicio en qué dirección mirar.