Skip to content

Examples on how to use Dataverse Service Client to connect to Dynamics 365 CRM on-premises

License

Notifications You must be signed in to change notification settings

janis-veinbergs/DataverseServiceClientOnPremSamples

Repository files navigation

Examples on how to connect to Dynamics 365 CRM On-Prem using Dataverse Service Client (DVSC). This repo is supporting material for the following article: Using Dataverse Service Client to connect to OnPrem Dynamics 365 CRM (From .NET 6+)

In all cases, populate appsettings.json with your values for each project.

ADFS requires specific configuration before all of this works.

ADFS2019ConnectionString

Connect to Dynamics 365 CRM On-Prem using ADFS 2019 and OAuth 2.0 using only connection string

  • Authorization code grant: AuthType=OAuth;Url=https://org.crm.example.com/;Username=user@example.com;Password=<pw>;RedirectUri=http://localhost:54321;AppId=174697c7-4ec8-401a-88ce-e6af4d05b6dd;LoginPrompt=Always

    UI required (browser). Takes 2 requests to get access token. MSAL library takes care of listening to particular port specified in RedirectUri, so that when first request goes out to ADFS and you get authorization code, browser on your computer where the app runs can get the response, extract authorization code and issue another request to ADFS to finally get the access token.

  • Resource Owner Password Credentials grant: AuthType=OAuth;Url=https://org.crm.example.com/;Username=user@example.com;Password=<pw>;AppId=174697c7-4ec8-401a-88ce-e6af4d05b6dd;LoginPrompt=Never

    You authenticate as particular user. No UI required. Takes 1 request to get access token.

    This flow is considered for Desktop and Mobile application types, however I am going to use it for Service (Daemon) application as it requires no user interaction and I'm not so sure if Client credentials flow (which is officially meant for daemon applications) can be supported by on-premises instance.

    Has drawbacks - no MFA support, passwords with leading/trailing whitespace not supported etc. See notes and consider what applies to on-premises.

ADFS2019DeviceFlow

Connect to Dynamics 365 CRM On-Prem using tokenProvider to use MSAL library and implement device flow

ADFS2016

MSAL is not compatible with ADFS2016, thus DVSC cannot be used. Instead, use tokenProvider to get access token and use it to connect to Dynamics 365 CRM On-Prem.

Configuring CRM/ADFS 2019

  1. You must have: Windows Server 2019+/ADFS 2019+

  2. KB4490481 must be installed. Required for MSAL support.

  3. Configure the Microsoft Dynamics 365 Server for claims-based authentication and also for IFD. Don't forget to do the appropriate configuration on AD FS server too for [claims](Configure the AD FS server for claims-based authentication | Microsoft Learn) and IFD auth. Regarding non-IFD, Claims-only configuration for internal access - I tested it with DVSC and as of writing, it didn't work. It did get the access token, but then failed to send requests to right URL - it didn't append the /org after the URL host part.

    So I will assume the following:

    You maybe have org.example.com IFD URL in real life if you had IFD configured previously as per MS documentation. See IFD configuration notes at the end of the article.

  4. On ADFS Server you have to tell that you have to register your application. You will use ClientId in connection string. And you have to give permissions for this application to get access token for CRM IFD relying party. RedirectUri must contain port and must use http protocol (for localhost). If port will not be specified, random will be used by MSAL when you connect via DVSC, but ADFS just won't accept it.

    # MSAL will listen on localhost this particular port to get answer from ADFS (authorization code), but that is only true for authorization code grant flow: https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/overview/ad-fs-openid-connect-oauth-flows-scenarios#authorization-code-grant-flow
    > Add-AdfsClient -ClientId ([guid]::NewGuid()) -Name "DVSC Client" -RedirectUri "http://localhost:54321" -Description "Dataverse Service Client will connect to CRM" -ClientType Public
    > $ClientId = (Get-AdfsClient -Name "DVSC Client").ClientId
    # If you don't grant permissions, you will get error: MSIS9605: The client is not allowed to access the requested resource. when trying to issue token at /adfs/oauth2/token.
    # For ServerRoleIdentifier, "external domain" URL must be used you chose when you configured IFD. You inputted 4 domains/urls, this would be the 4th one.
    # Another way to find out - go to ADFS, open Relying parties, open the IFD relying party (auth.crm.example.com), open Identities, and pick the first one: https://auth.crm.example.com/
    > Grant-AdfsApplicationPermission -ClientRoleIdentifier $ClientId -ServerRoleIdentifier "https://auth.crm.example.com/" -ScopeNames "openid"
    > $ClientId
     
    1260534b-00ca-4663-870f-d77b8d4ad6d3

    What does openid has to do anything with this? [It means](AD FS OpenID Connect/OAuth concepts | Microsoft Learn) that you allow your client application to use OpenID Connect (OIDC) authentication protocol.

  5. OAuth must be enabled for CRM. Execute this on CRM server:

    Add-PSSnapin Microsoft.Crm.PowerShell  
    $ClaimsSettings = Get-CrmSetting -SettingType OAuthClaimsSettings  
    $ClaimsSettings.Enabled = $true  
    Set-CrmSetting -Setting $ClaimsSettings  

    If you want to validate OAuth is enabled, you must open: https://org.crm.example.com/XRMServices/2011/Organization.svc/web and see with, say, Fiddler, whether you get WWW-Authenticate header that is like: Bearer redirect_uri=https://adfs.example.com/adfs/ls/

    You may get multiple headers, like WWW-Authenticate: Negotiate and WWW-Authenticate: NTLM, but one with Bearer must be present. If you don't want to configure fiddler to catch TLS requests, you can check what headers that request returns like this:

    > Invoke-WebRequest -Uri "https://org.crm.exmple.com/XRMServices/2011/Organization.svc/web" -UseBasicParsing
    > $error[0].exception.response.headers["WWW-Authenticate"]
    
    Bearer authorization_uri=https://adfs.example.com/adfs/oauth2/authorize, resource_id=https://org.crm.example.com/

    Don't worry, the Invoke-WebRequest returns 401 error - it is expected.

  6. As of writing, the DVSC will fail to connect if you get multiple WWW-Authenticate headers. It is due to a bug in the client itself and hopefully it gets fixed. isOnPrem not passed down correctly when invoking GetAuthorityFromTargetServiceAsync · Issue #396 · microsoft/PowerPlatform-DataverseServiceClient (github.com).

Thus, at the time of writing, we need additional configuration:

  1. Open C:\windows\system32\inetsrv\config\applicationHost.config on CRM server.
  2. Find this XML element:
    <location path="Microsoft Dynamics CRM/XRMServices/2011/Organization.svc">
     <system.webServer>
         <security>
             <authentication>
                 <digestAuthentication enabled="false" />
                 <basicAuthentication enabled="false" />
                 <anonymousAuthentication enabled="true" />
                 <windowsAuthentication enabled="true" />
             </authentication>
         </security>
     </system.webServer>
 </location>
  1. Change windowsAuthentication to false:
    <location path="Microsoft Dynamics CRM/XRMServices/2011/Organization.svc">
     <system.webServer>
         <security>
             <authentication>
                 <digestAuthentication enabled="false" />
                 <basicAuthentication enabled="false" />
                 <anonymousAuthentication enabled="true" />
                 <windowsAuthentication enabled="false" />
             </authentication>
         </security>
     </system.webServer>
 </location>

About

Examples on how to use Dataverse Service Client to connect to Dynamics 365 CRM on-premises

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages