0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.