I have developed a Provider Hosted MVC App for SP2013. Everything works in my development environment; however, I am struggling getting it to work in our production (on-premises) environment.
Anything with the [SharePointContextFilter] attribute will not load (i.e. Home/Index aka start page), but About or Contact pages will as they do not have the attribute. The homepage redirects to my 'Error' page; however, other actions give the unexpected error page: "An unexpected error has occurred. Please try again by launching the app installed on your site."
When navigating to the app I see, via Fiddler, the following error: SPAppToken=&SPSiteUrl=http%3A%2F%2Ftest.thrive&SPSiteTitle=Test+Thrive&SPSiteLogoUrl=&SPSiteLanguage=en-US&SPSiteCulture=en-US&SPRedirectMessage=EndpointAuthorityMatches&SPErrorCorrelationId=b237159f-1886-7076-971c-96c26a739eb2&SPErrorInfo=The+Azure+Access+Control+service+is+unavailable.
Which appears to be a red-hearing and seems exactly like this post: SharePoint 2013 Provider-Hosted App "Azure Access Control Service is unavailable"
I have looked at the suggested blog posts by Russ (Part 1 & Part 2).
I have my provider hosted web hosted on a seperate server from the SP ones which is accessible via https://apps.mycompany.on.ca/appname and is using our company wildcard cert issued by GoDaddy.
Because of this on the SharePoint side I have added 4 Trusted Root Authorities to SharePoint as my understanding is the entire certificate chain needs to be a trusted authority:
- Company Wildcard cert
- GoDaddy CA - G2
- GoDaddy Root CA
- GoDaddy Class 2 CA
I have also registered the company wildcard as a trusted token issuer:
$certPath = "C:\wildcard\wc.cer" $certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath) $realm = Get-SPAuthenticationRealm $specificIssuerId = [guid]::NewGuid() # Make sure to take note of this $fullIssuerIdentifier = $($specificIssuerId.toString() + '@' + $realm) New-SPTrustedSecurityTokenIssuer -Name "Company High Trust Apps Cert" -Certificate $certificate -RegisteredIssuerName $fullIssuerIdentifier -IsTrustBroker I thought this would have allowed things to work properly. It is worth noting that our web app (HNSCs) is not SSL, nor is our add-in domain (however, other apps are working, i.e. ones bought from the store).
I have also seen mention of modifying the TokenHelper.cs file which I have done to the following:
#if DEBUG private static readonly string ClientSigningCertificatePath = WebConfigurationManager.AppSettings.Get("ClientSigningCertificatePath"); private static readonly string ClientSigningCertificatePassword = WebConfigurationManager.AppSettings.Get("ClientSigningCertificatePassword"); private static readonly X509Certificate2 ClientCertificate = (string.IsNullOrEmpty(ClientSigningCertificatePath) || string.IsNullOrEmpty(ClientSigningCertificatePassword)) ? null : new X509Certificate2(ClientSigningCertificatePath, ClientSigningCertificatePassword); private static readonly X509SigningCredentials SigningCredentials = (ClientCertificate == null) ? null : new X509SigningCredentials(ClientCertificate, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest); #else private static readonly string ClientSigningCertificateSerialNumber = WebConfigurationManager.AppSettings.Get("ClientSigningCertificateSerialNumber"); private static readonly X509SigningCredentials SigningCredentials = GetSigningCredentials(GetCertificateFromStore()); #endif #if !DEBUG private static X509SigningCredentials GetSigningCredentials(X509Certificate2 cert) { return (cert == null) ? null : new X509SigningCredentials(cert, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest); } private static X509Certificate2 GetCertificateFromStore() { if (string.IsNullOrEmpty(ClientSigningCertificateSerialNumber)) { return null; } // Get the machine's personal store X509Certificate2 storedCert; X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); try { // Open for read-only access store.Open(OpenFlags.ReadOnly); // Find the cert storedCert = store.Certificates.Find(X509FindType.FindBySerialNumber, ClientSigningCertificateSerialNumber, true) .OfType<X509Certificate2>().SingleOrDefault(); } finally { store.Close(); } return storedCert; } #endif And in the Web project Web.config I added the following app settings:
<add key="ClientID" value="12035ef7-6e7f-4d9f-9d6b-2f974fef09c4" /> <add key="ClientSigningCertificateSerialNumber" value="<Company Wildcard Serial Number>" /> <add key="IssuerId" value="de9920bd-b2b8-42a8-b441-cb1e7b7f3636" /> In the AppManifest.xml I have tried hardcoding the ClientId into the file... but thought this unecessary when it should be done via the publishing process? Same ClientId as in the Web.config file.
I do not understand what I am missing to get this to all come together into a working production app (everything works in my development environment via Visual Studio).
I have also checked out this Step by Step Installation Guide – SharePoint 2013 On-Premises Provider Hosted High Trust Configuration for guidance.
Any help/suggestions would be greatly appreciated. Thanks.