Authenticating with on-premise (IFD) CRM using NTL

2020-08-03 03:39发布

问题:

I'm asking this question on the back of a previous question I raised, as the scope of the question has changed somewhat but that might be worth reading first for background info.

I'm trying to programatically obtain data out of our Dynamics CRM instance, using a single set of admin credentials within a Node powered Express app. This Express app is hosted on a separate server outside of our network where CRM is hosted. The app will then request, process and serve CRM data back to any logged in user who has access (controlled by roles/permissions within the app), meaning an end user only has to login into the Express app.

From my web browser, if I visit our on-premise CRM endpoint: https://my.crm.endpoint, I get prompted for a username and password.

If I provide correct credentials, I am authenticated and have full access to the CRM, allowing me to query the API.

Example https://my.crm.endpoint/api/data/v8.2/contacts?$select=fullname,contactid

This returns a lovely JSON object containing all the data I want :)

NOW! Under the covers, I can see that it is using NTLM to authenticate, of which I have little knowledge :/ Having read up a little and watched a few YouTube videos, I have a basic understanding of the challenge/response mechanism but I'm still unsure as to how to proceed.

NB: I have read this from Microsoft which describes the mechanism, but doesn't give any specific examples. I don't even know what hashing algorithm should be used, or what headers to set etc.

Question Can anyone provide any sort of detail as to how I can authenticate with our CRM using NTLM from a Web App (Express in my case)?

Steps I can see the browser making...

  1. Visit https://my.crm.endpoint
  2. 302 Redirected to: https://fs.our.domain/adfs/ls/?wa=wsignin1.0&wtrealm=https%3a%2f%2fmy.crm.endpoint%2f&wctx=rm%3d1%26id%3dfaf0791c-6a3a-4c4e-9e69-9dfa8fd4c2e8%26ru%3d%252fdefault.aspx&wct=2018-04-20T10%3a12%3a37Z&wauth=urn%3afederation%3aauthentication%3awindows
  3. Prompted for user credentials
  4. ** enter credentials**
  5. A whole bunch of stuff happens here and I get a little lost but looks like it gets a couple of 401's then a POST is made to the https://my.crm.endpoint. Another 302 is shown, then finally a GET to the actual default.aspx page.
  6. I then have access to CRM.

NB: Once authenticated, I can see three cookies that have been set and which are sent when querying the api example above. These cookies are MSISAuth, MSISAuth1 and ReClientId.

If I'm missing any crucial info, please let me know and I'll provide what I can!

UPDATE

I have just installed httpntlm module and attempted to authenticate using this...

let httpntlm = require('httpntlm');
httpntlm.get({
    url: 'https://my.crm.endpoint',
    username: '<my.email@address.com>',
    password: '<mypassword>',
    workstation: '',  // unsure what to put here if anything?
    domain: ''        // unsure what to put here if anything?
}, function (err, res){
    if(err) return err;

    console.log(res.headers);
    console.log(res.body);
});

The response I get is this...

{ location: 'https://fs.our.domain/adfs/ls/?wa=wsignin1.0&wtrealm=https%3a%2f%2fmy.crm.endpoint%2f&wctx=rm%3d1%26id%3d93a4c6fd-5b17-4a2b-965f-07af5e96b08f%26ru%3d%252fdefault.aspx&wct=2018-04-20T14%3a08%3a00Z&wauth=urn%3afederation%3aauthentication%3awindows',
  server: 'Microsoft-IIS/8.5',
  req_id: '298acefc-53aa-46fa-96c4-e5d8762b1fd2',
  'x-powered-by': 'ASP.NET',
  date: 'Fri, 20 Apr 2018 14:08:00 GMT',
  connection: 'close',
  'content-length': '397' }
<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="https://fs.our.domain/adfs/ls/?wa=wsignin1.0&wtrealm=https%3a%2f%2fmy.crm.endpoint%2f&wctx=rm%3d1%26id%3d93a4c6fd-5b17-4a2b-965f-07af5e96b08f%26ru%3d%252fdefault.aspx&wct=2018-04-20T14%3a08%3a00Z&wauth=urn%3afederation%3aauthentication%3awindows">here</a>.</h2>
</body></html>

Anyone able to shed any light on what I actually need to be doing?! :-/

UPDATE 2

Following @markgamache comment, and having read the suggested docs, we are indeed using WS-Fed! As the Wa=signin1.0 parameter informs the browser to pop up a login box, does this make it impossible to achieve this programmatically, without additional user interaction?

回答1:

Based on my following understanding:

  • You are using CRM on premises with claims authentication (ADFS). This means that when an user accesses CRM, the user is redirected to ADFS for authentication (if the user is in the internal network, by default ADFS uses integrated Windows authentication) and then the user is redirected back to CRM.
  • You must call a CRM endpoint from an external (node.js) application. That call is NOT "client side" (i.e. via browser/javascript) but "server side" (i.e. from the web server hosting the application)

The ideal solution would be to apply here the S2S (server to server) scenario which involves an application user in CRM which in turn is used to call a CRM API using the OAuth client credentials flow (client id + secret). Problem is, as far as I know, currently the application user concept is only supported in CRM online, not on premises.

So then you can try one of these 3 options:

  1. Despite the fact that you are using claims authentication in CRM, you can still use integrated Windows authentication (IWA). How? If you check the CRM IIS site, you must have an HTTPS binding. If you add an HTTP binding (i.e. port 80 no host header), you can access http://CRM_Server_Name/api/data/v8.2/contacts using IWA. So in this scenario, the httpntlm module you already tried could work. Please note that CRM supports one HTTPS IIS binding and one HTTP IIS binding - so make sure to not to add more of one binding of each type.
  2. Mimic (programmatically of course) the authentication flow you observed in the browser. What does this mean? Generate an IWA authenticated request to https://fs.our.domain/adfs/ls/?wa=wsignin1.0&wtrealm=https%3a%2f%2fmy.crm.endpoint%2f&wauth=urn%3afederation%3aauthentication%3awindows. ADFS will authenticate you and will give you some cookies. You will need to store those cookies to make a subsequent request to https://my.crm.endpoint/api/data/v8.2/contacts. Not a great solution but should work.
  3. Use OAuth. Problem is that as I described at the beginning, the ideal OAuth flow for this scenario (client credentials) is not available for CRM on prem as far as I know. So then you must use the Authorization Code Grant flow, described here. First you will need to register an ADFS application and then again, you will need to make several HTTPS calls (one of them will be a call to the ADFS IWA authentication endpoint) to finally obtain a token that you can use to make calls to the CRM endpoint.


回答2:

that is a redirect to an ADFS server for claims based authentication. That page, or the next redirect, will ask you to authenticate with either cert, forms, or windows integrated (NTLM or Kerberos). If you pass auth, your browser will be given a token to send to https://my.crm.endpoint. The URL suggest the claims will be via WS*. https://blogs.technet.microsoft.com/askpfeplat/2014/11/02/adfs-deep-dive-comparing-ws-fed-saml-and-oauth/