1
votes

I have been working on a project for the last 5 months - integrating one of our older systems to use Dynamics365 CRM to store and record leads for our marketing and sales department.

Everything works as it should on several environments - we have a DEV, Sandbox as well as TEST and my local machine. It works everywhere except the UAT server which is hosted in completely different city as opposed to the others which are in the building we work in.

We have made sure TSL 1.2 is used and application forces this in code. Compared .NET Features on all machines and they're exactly the same, ciphers and configuration files are nearly the same, the differences are minor such as connection strings for our databases.

We are connecting to the same instance of CRM across all environments.

The project has been compiled using .NET 4.6.1

Microsoft.CrmSdk.CoreAssemblies - 9.0.2.4

Microsoft.CrmSdk.XrmTooling.CoreAssembly - 9.0.2.7

Microsoft.IdentityModel.Clients.ActiveDirectory - 2.22.302111727

Our Azure (we use AD to login to CRM via C#) has no whitelist.

Dynamics as far as we know has no whitelist.

There is no firewall rule that blocks any outgoing connections on 443 port so everything resembles other environments yet we receive "Unable to login to Dynamics CRM" error message.

This is the code we use to connect to CRM..

string Thumbprint = ConfigurationManager.AppSettings["CertThumbprint"];
string adInstance = ConfigurationManager.AppSettings["ADInstance"];
string adTenant = ConfigurationManager.AppSettings["Tenant"];
string Url = ConfigurationManager.AppSettings["Application"];
string AppId = ConfigurationManager.AppSettings["ClientId"];

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

X509Store certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);

certStore.Open(OpenFlags.ReadOnly);


X509Certificate2Collection CertificateCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, Thumbprint, false);

if (CertificateCollection.Count == 0) 
      throw new Exception("Error: Could not find the right certificate.");


X509Certificate2 AzureCertificate = CertificateCollection[0];


CrmServiceClient.AuthOverrideHook = new AuthHook(adInstance, adTenant, Url, AppId, AzureCertificate);

var crmSvc = new CrmServiceClient(new Uri(Url), true);

if (crmSvc == null || !crmSvc.IsReady) throw new Exception(crmSvc == null ? "CrmServiceClient Failure." : crmSvc.LastCrmException.ToString());

this.service = (IOrganizationService)crmSvc.OrganizationWebProxyClient ?? crmSvc.OrganizationServiceProxy;

This line specifically returns the error and also is set as null...

var crmSvc = new CrmServiceClient(new Uri(Url), true);

Worth mentioning the only difference between UAT compared to the rest is that UAT is running on .NET 4.7.1 compared to the others runing .NET 4.7.2.

If anyone came across this one it would be highly appreciated or any ideas what it could be.


Edit: I have just tried putting a fallback method that authenticates using Office365 to no avail. Same error... this method has worked on every other environment.

The code used was:

ClientCredentials clientCredentials = new ClientCredentials();

if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["crm_user"]) && 
    !string.IsNullOrEmpty(ConfigurationManager.AppSettings["crm_password"]))
{
    clientCredentials.UserName.UserName = ConfigurationManager.AppSettings["crm_user"];
    clientCredentials.UserName.Password = ConfigurationManager.AppSettings["crm_password"];

    ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

    this.service = (IOrganizationService)new OrganizationServiceProxy(new Uri(ConfigurationManager.AppSettings["crm_org_url"]),
                                        null, clientCredentials, null);

    if (this.service == null)
    {
        Exception e = new Exception("CRM: Could not login to organization service proxy.");

        throw e;
    }
}
else
{
    throw new Exception("CRM: Could not connect using a fallback method. The web configuration doesn't contain crm_user or crm_password keys.");
}
1
"UAT is running on .NET 4.7.1 compared to the others runing .NET 4.7.2" - is that something you can change, just to rule it out?Rup
@Rup Given we don't have access to UAT and it would require a Change Request for someone higher up the chain to do - I will say no - but can be done. The problem I am facing is the fact that this is supposed to be going live tomorrow which is very unlikely at the moment. If you're suggesting we do it though, I'll raise this higher up and see if it rules it out.Adrian
:-/ Was about to suggest a few other things, but I guess you can't do them too? e.g. can you manually connect to the same URLs from browsers on the UAT machine? can get network trace though, e.g. Wireshark, to get more information - is it genuinely a connection failure, or a protocol error, or something else?Rup
@Rup We have an IT man in house who can RDP/C to UAT but can't install anything without approval from higher up. Wireshark is something we're awaiting approval for at the moment. Manually from browser we have managed to connect to the same url without problems.Adrian
All I can think of then is the proxy config: check if the browser on the UAT server has a proxy set up that (for whatever reason) isn't being picked up by your code. But that shouldn't have changed vs previous versions of the software on UAT? (I guess you need to work with 4.7.1 anyway since production would be 4.7.1.)Rup

1 Answers

1
votes

First of all, thank you to everyone who tried to help.

The solution to this (3 day) problem was that my private key that was installed on the local machine did not have the right permissions for the Web App to read it.

I was successfully finding the key but code was not able to read it.

To resolve the issue, I went to MMC, added certificated to my view, then in personal folder I have my certificates, right click the one needed, All Tasks > Manage Private Keys and make sure you have your application pool in the Group or User names section.

Worth adding I did also add IIS_IUSRS group along side my application pool (App Pools\DefautApplicationPool).

This has magically solved the UAT issue. The CRM SDK could be improved to be... more intuitive.