Simplifying?? Provider Hosted Apps with SharePoint 2013–Part 1 of X?

From my own experience and most everyone I’ve talked with, if you’ve done anything with SP2013 Provider Hosted Apps, there seem to be three outcomes:

  1. You just get it
  2. You just don’t get it
  3. You beat your head against a wall and randomly get it to work without having a clue why

 

Up until recently I have been part of group 3 above… I started playing with SP2013 before it released, but since my primary skills and experience are not developer related I haven’t needed to *really* understand all of the nuances to the new app model.

One of my biggest frustrations with the entire thing is that despite how much I search I haven’t found any single good resource to describe/discuss the different properties and configuration needed to get this working. Part of the reason for this is that most of the authors of the content make assumptions about the reader’s experience and not everyone was born to be a developer. Smile Speaking of assumptions… this post does assume that you have already configured your farm for developing these provider hosted applications as specified in this MSDN article. (yes, I know I said I hate having to jump all over many articles, call me a hypocrite)

This is going to be one really long post or a series…I’m not sure how this will end, but the specific scenario that I’m focusing on is a high-trust provider hosted app for SharePoint 2013. Basically this will be an ASP.Net Web Application secured with an SSL certificate and provides tokens that it generates internally to pass to SharePoint. There are certain differences depending on whether you are a developer using this for creating apps and debugging them or if you are an ITPro responsible for deploying these apps into a production farm. I’ll try to point out these differences as I discuss.

CONFIGURATION:

While I certainly have all the other servers that are necessary for this task, the important points here are that I have a multi-server SharePoint 2013 farm (a web front end that also hosts the Central Admin and an application server which hosts Search) and a separate IIS server to host the ‘provider hosted web application’. In my case I’m using the SP2013 web front end as my Visual Studio box as well.

DATA NEEDED:

Certificate – this can be a self-signed certificate, a domain cert, or a real cert such as Verisign or GoDaddy. In my case I’m using a domain cert issued by my domain certificate authority.

IssuerID – this is a GUID that will be used in several places. You can generate it from Visual Studio or using Powershell, but it will be used as the provider hosted application IssuerID and for part of the SPTrustedSecurityTokenIssuer registered name.

ClientID – this is another GUID that will be generated in different ways depending on the scenario you are using. It will be used as the ClientID in the web.config of the provider hosted application and as part of the ID for the SPAppPrincipal that you register either using AppRegNew.aspx or Register-SPAppPrincipal.

Create Trusted Root Authority (MSDN Link)

You will eventually need both the CER (public key) and PFX (private key) from your certificate, but for this exercise only the CER is needed. On the SharePoint server open the SharePoint Management Console and execute the following powershell:

$publicCertPath = “<full file path to .cer>”
$certificate = New-Object System.Security.Cryptography.X509Certifcates.X509Certificate2($pulicCertPath)
New-SPTrustedRootAuthority –Name “HighTrustSampleCert” –Certificate $certificate

Note that if your certificate is a sub-ordinate certificate, then you also need to repeat the above for the parent certificate and any other certificates that are in the chain. (Check the ‘Certification Path’ tab of the Certificate properties to see if there are multiple certs in the chain).

Create SP Trusted Security Token Issuer

For this section you will need to generate a new GUID to use as the IssuerID and you will create a token issuer for SharePoint that will be responsible for issuing access tokens to your provider hosted application.

<still in the same SharePoint Management Console as above>

$IssuerID = [System.Guid]::NewGuid().ToString()
$spSite = “<url of site>”
$realm = Get-SPAuthenticationRealm –ServiceContext $spSite
$fullAppIssuerID = $IssuerID + ‘@’ + $realm
New-SPTrustedSecurityTokenIssuer –Name $IssuerID –Certificate $certificate –RegisteredIssuerName $fullAppIssuerID –IsTrustBroker
IISReset

Make a note of the $IssuerID as you will need that later. The URL of the site above is really only important if you have site subscriptions enabled (which most of you do not). We could technically get the $realm in many ways, but the above seems to be the common method. Concatenating the $IssuerID and the $realm gives us the ID for the security token issuer for issuing tokens to apps.

Create High-Trust Provider Hosted Application for SharePoint in Visual Studio

I don’t want to go into the click-by-click details of how to create a new project, but if someone needs help with this just holler in the comments section.

From Visual Studio (VS) 2013, create a new project from <language>\Office/SharePoint\Apps\App for SharePoint 2013. When you click OK after selecting the project type you will be asked for a couple of pieces of information:

What SharePoint site do you want to use for debugging?

For this, it can be any SharePoint site. If you are the developer and using this for creating/debugging the app, then you can select any developer site.

How do you want to host your app for SharePoint?

Provider-hosted

Next.. Which type of web application project do you want to create?

ASP.NET Web Forms Application

Next.. How do you want your app to authenticate?

Use a Certificate (for SharePoint on-premises apps using high-trust)
Certificate Location: path to your PFX file from above
Password: password to your certificate’s private key
Issuer ID: The issuerID from above. The same as what you used for the SPTrustedSecurityTokenIssuer. (all lowercase)

Finish..

Notes about the above section. There are 3 types of apps listed: Provider-hosted, Autohosted, and SharePoint-hosted. The Autohosted apps have been discontinued so you can ignore that option and I imagine it will be removed in the near future. SharePoint-hosted apps are totally running within your SharePoint environment.

The option about ASP.Net Web Forms vs. MVC is unimportant for the context of this blog post, but I will verify later that this configuration works for both options.

The IssuerID is critical to success. It *must* be the same IssuerID that you used above to create the SPTrustedSecurityTokenIssuer.

If you are creating/debugging this app, then at this point you should be able to hit F5 and it will launch the app and connect to the SharePoint site you specified in debug mode. This does a lot of work behind the scenes…

such as entering the correct information into the web.config for the ClientID:

VSbuild_insert_clientID_webconfig

and registers an app principal for your app and creates the app permissions:

AppPrincipal_created

AppPermissions_added

Notice in the screenshot above that the first part of the App Identifier matches the ClientID from the previous screenshot where VS inserted it into the web.config.

This will also upload the app package to the desired site (this is why it needs to either be a developer site or a site with developer features enabled). One of the differences that needs to be pointed out here is that on a developer site when you deploy an app via VS, there is no “app catalog” and apps are simply uploaded and installed directly to the site.

Create High-Trust Provider Hosted Application for SharePoint in Visual Studio for Package Deployment

So this section will show the slight differences between using VS for just creation and debugging versus using it for creation of app packages that will then be passed off to a deployment team.

The steps above for creating the SPTrustedRootAuthority and the SPTrustedSecurityTokenIssuer are the same for this process. All of that still needs to be done. The main difference is around how the app is packaged and then deployed.

Starting with a new project in VS, you will need some information such as the following:

ClientID – in the previous scenario (debugging) this was provided for you by Visual Studio. For this scenario you will need to provide this. You can create it the same way you created the IssuerID earlier with Powershell, but make a note of it as you will need it again shortly.

Certificate Location and password – path to your CER/PFX files

IssuerID – this is the same ID that you used to create the SPTrustedSecurityTokenIssuer

You start by packaging the SharePoint app project. Right-click on the SharePoint App project in your solution and select Publish:

Publish_SPApp_from_VS_thumb2

      

This launches a wizard where you need to create a new publishing profile. Click the drop down next to ‘Current Profile’ and select ‘<New>’, then select “Create new profile” and provide a descriptive name, then click Next.

Here is where you will need to provide the information from above. ClientID, Certificate location (to the PFX), Certificate password, and IssuerID. Click Finish. At this point you have created a publishing profile. Now you will need to actually create the package file by clicking the “Package the app” button:

PackageTheApp_button

This launches a new wizard that requires the URL for your provider hosted web application – this is where the non-SharePoint portion of your app is running – and the ClientID. Notice that the ClientID is pre-populated for you since you supplied it in the publishing profile.

image 

Click finish and a Windows Explorer window opens showing you the .APP file that is created. This file is what you’ll deliver to the SharePoint deployment team to upload to the SharePoint App Catalog.

But we’re not done yet.. Now you need to go back to VS and before you publish the web application project, be sure to verify that the web.config contains the proper information for the location and password for the certificate as well as the IssuerID. These values should have been supplied at project creation time. The ClientID, however, needs to be added at this point to the web.config.

Now right-click the Web Application project and select Publish. Select the Publishing Profile that you created above and click Next..

image

WebPublishOptions1

There are a variety of publishing options…for this conversation I’ll use the publishing method of Web Deploy Package. This will create a set of files that can be manipulated to deploy the web application to the destination web server. Discussion of all of these details is beyond the scope of this post, unfortunately.

WebPublishOptions2

The other information needed for the above dialog is a location where to save the web deploy package and the web site name where you want the files deployed. Click Next twice and then click Publish.

Now what? You have an APP file with your SharePoint App component and a set of files from the web deploy package for the actual provider hosted app. Copy the web deploy package files over to your target IIS server and do the following:

  1. Be sure that your PFX certificate is installed so that it can be accessed by IIS
  2. Create a new IIS site and edit the bindings so that it is secured by the certificate.
  3. Disable anonymous authentication and enable Windows authentication. This is a *MUST*. The provider hosted application must be able to authenticate users when they hit the site in order to create the access tokens that are sent back to SharePoint.
  4. Now execute the .CMD file in the web deploy package folder in order to install the web application files.

 

Obviously there are details here I’m leaving out because I feel this blog post is getting too long as it is… I may come back in later and break it up into pieces if there is a lot of confusion around the parts I’m leaving out. Remember, my whole reason for doing this is that too many other blogs make too many assumptions and leave out content… now I may be understanding why they do that… it’s a LOT of content. Smile

For the .APP file, you pass this to the SharePoint Deployment team so they can upload the file to the App Catalog and make it available to the web application… but WAIT!!!

It still won’t work… recall when you were creating/debugging the app in VS against a developer site that the sheer act of publishing the app components caused some things to happen. One of those things is the creation of the AppPrincipal. The AppPrincipal is how SharePoint assigns permissions to your apps in order to access objects within SharePoint. The information you’ll need to create the AppPrincipal:

ClientID – the same ID that you created and specified in both the publishing profile and the web.config     
Realm – remember this can be obtained from Get-SPAuthenticationRealm
URL – this should be the url of the SharePoint site where you are installing the app     

$ClientID = <guid>
$realm = Get-SPAuthenticationRealm
$appID = $ClientID + ‘@’ + $realm
Register-SPAppPrincipal –Site <url> –NameIdentifier $appID

At this point, once a user adds your new app to their site, then it *should* all just work. Now we all know that isn’t what normally happens and there are a myriad of places for this to fail.

My objective here was really just to help bring together a couple pieces of data and hope to clarify where they go each time you create a new SharePoint app and deploy it.

Advertisements

Provided User Name was not Encoded as a Claim

So today’s lesson is quite bizarre.. and I’m not sure where *exactly* the problem lies just yet. I was going through the process of configuring my SharePoint 2013 (SP2013) farm to test something with an external list that is bound to an external content type (ECT) backed by a SQL Server database. Simple enough on the surface:

  1. In your SP2013 farm, create and configure Business Data Connectivity (BDC) and Secure Store (SS) Service Applications
  2. Create the SQL database
  3. Add a SQL login to use with Secure Store (for my situation I chose not to use Kerberos Delegation)
  4. In SharePoint Designer (SPD), create an ECT and connect it to the database in step 1
  5. Create a custom list from this ECT

Now obviously there are a lot of details that I’m leaving out above, but the purpose of this post is not to show you how to create an ECT. Step 1, specifically, is where I encountered my issues today. I had already previously created the required service applications, but I had not configured them for use. Creating the SS application went without a hitch for the most part, but with the BDC service application it was not that easy.

You need to grant rights to the Metadata Store within the BDC service application in order for users to create an ECT so my first stop was to Central Admin and in to Manage the BDC service application.

Once in the service application management page, you will need to add a user to the Metadata Store Permissions

You may notice a bit of a problem in the screenshot above in that my user has not been resolved properly. (you may not have noticed it depending on how much sleep you’ve had, but that’s another discussion) As it so happens, I’m rather stubborn, so I proceeded to click the Add button anyway. Much to my surprise AdamB was added to the user list and I was allowed to select the permissions I wanted this user to have. However, when I clicked OK is when the real fun began.

As you can see, it didn’t work very well and resulted in the following error:

A provided user name was not encoded as a claim. Parameter name: aces

Now considering the fact that I occasionally enjoy a game of cards here and there “aces” got me rather excited until I realized it was trying to tell me that something failed and I had to now fix it. So where is the first place you go to unravel errors in SharePoint? The ULS logs, of course!! And here a list of a couple of the entries (scrubbed and filtered) around this error:

ULS Log Entries

01/07/2015 17:37:20.65    w3wp.exe (0x30F8)    0x3B7C    Business Connectivity Services    Business Data    9f4h    Unexpected    ‘BDC’ BdcServiceApplication logging server side ArgumentException before marshalling and rethrowing on client side: System.ArgumentException: A provided user name was not encoded as a claim. Parameter name: aces at Microsoft.SharePoint.BusinessData.SharedService.IndividuallySecurableMetadataObjectAccessor.SetAccessControlEntries(MetadataObjectStruct metadataObjectStruct, AccessControlEntryStruct[] aces, String settingId, DbSessionWrapper dbSessionWrapper) at Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplication.<>c__DisplayClass2c.<Microsoft.SharePoint.BusinessData.SharedService.IBdcServiceApplication.SetAccessControlEntries>b__2b() at Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplication.Execute[T](String operationName, UInt32 maxRunningTime, ExecuteDelegate`1 operation)    858bdd9c-f650-b0dd-7410-7cdb3f5cb1fd

01/07/2015 17:37:20.65    w3wp.exe (0x3618)    0x340C    SharePoint Foundation    General    8nca    Medium    Application error when access /_admin/BDC/ManageBDCPermissions.aspx, Error=A provided user name was not encoded as a claim. Parameter name: aces at Microsoft.SharePoint.BusinessData.SharedService.IndividuallySecurableMetadataObjectAccessor.SetAccessControlEntries(MetadataObjectStruct metadataObjectStruct, AccessControlEntryStruct[] aces, String settingId, DbSessionWrapper dbSessionWrapper) at Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplication.<>c__DisplayClass2c.<Microsoft.SharePoint.BusinessData.SharedService.IBdcServiceApplication.SetAccessControlEntries>b__2b() at Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplication.Execute[T](String operationName, UInt32 maxRunningTime, ExecuteDelegate`1 operation)    858bdd9c-f650-b0dd-7410-7cdb3f5cb1fd

01/07/2015 17:37:20.65    w3wp.exe (0x3618)    0x340C    SharePoint Foundation    Runtime    tkau    Unexpected    System.ArgumentException: A provided user name was not encoded as a claim. Parameter name: aces at Microsoft.SharePoint.BusinessData.SharedService.IndividuallySecurableMetadataObjectAccessor.SetAccessControlEntries(MetadataObjectStruct metadataObjectStruct, AccessControlEntryStruct[] aces, String settingId, DbSessionWrapper dbSessionWrapper) at Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplication.<>c__DisplayClass2c.<Microsoft.SharePoint.BusinessData.SharedService.IBdcServiceApplication.SetAccessControlEntries>b__2b() at Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplication.Execute[T](String operationName, UInt32 maxRunningTime, ExecuteDelegate`1 operation)    858bdd9c-f650-b0dd-7410-7cdb3f5cb1fd

01/07/2015 17:37:20.65    w3wp.exe (0x3618)    0x340C    SharePoint Foundation    General    ajlz0    High    Getting Error Message for Exception System.Web.HttpUnhandledException (0x80004005): Exception of type ‘System.Web.HttpUnhandledException’ was thrown. —> System.ArgumentException: A provided user name was not encoded as a claim. Parameter name: aces —> System.ArgumentException: A provided user name was not encoded as a claim. Parameter name: aces at Microsoft.SharePoint.BusinessData.SharedService.IndividuallySecurableMetadataObjectAccessor.SetAccessControlEntries(MetadataObjectStruct metadataObjectStruct, AccessControlEntryStruct[] aces, String settingId, DbSessionWrapper dbSessionWrapper) at Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplication.<>c__DisplayClass2c.<Microsoft.SharePoint.BusinessData.SharedService.IBdcServiceApplication.SetAccessControlEntries>b__2b() at Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplication.Execute[T](String operationName, UInt32 maxRunningTime, ExecuteDelegate`1 operation) — End of inner exception stack trace — at Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplicationProxy.Execute[T](String operationName, UInt32 maxRunningTime, ExecuteDelegate`1 operation, Boolean performCanaryCheck, Boolean isChannelThatDelegatesIdentity) at Microsoft.SharePoint.BusinessData.SharedService.BdcServiceApplicationProxy.SetAccessControlEntries(MetadataObjectStruct metadataObjectStruct, AccessControlEntryStruct[] aces, String settingId) at Microsoft.SharePoint.BusinessData.Infrastructure.BdcAccessControlList.SaveAs(MetadataObjectStruct metadataObjectStruct, String settingId, BdcServiceApplicationProxy serviceProxy) at Microsoft.SharePoint.BusinessData.Administration.IndividuallySecurableMetadataObject.SetAccessControlList(IAccessControlList acl, String settingId) at Microsoft.SharePoint.ApplicationPages.ManageBDCPermissions.OkButton_Click(Object sender, EventArgs e) at System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) at System.Web.UI.Page.HandleError(Exception e) at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) at System.Web.UI.Page.ProcessRequest() at System.Web.UI.Page.ProcessRequest(HttpContext context) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)    858bdd9c-f650-b0dd-7410-7cdb3f5cb1fd

So while the ULS information did put me at ease that I was not going to be shot by Wild Bill and it helped me to understand that the problem was with adding entries to Access Control Entries (ACEs) I still wasn’t any closer to a resolution. Thinking about the error a bit, though, did help me arrive at a path of investigation. The error is specifically talking about a user name that wasn’t “encoded as a claim”. So internally in SharePoint between the service applications we are utilizing windows claims for user identities. Within my farm specifically, my Central Administration web application is configured for NTLM Classic mode authentication and my content web applications are all configured for Windows Claims.

On a whim I tried to enter my user name in the People Picker in its claims format: i:0#w|contoso\adamb, but that provided no benefit and resulted in the same error series. So thinking about this a bit more I started wondering why we were looking for a claims encoded user name and remembered that although my content web applications were not using SAML claims I did, in fact, have a SAML Claims provider configured in the farm.

So we go on another whim and remove the SPTrustedIdentityTokenIssuer and try again. This time it worked without errors… neither the People Picker name resolution error, nor the “user name provided was not encoded as a claim” error appeared.

SYNOPSIS

When trying to add a user to the Metadata Store permissions of your BDC service application, if you receive name resolution errors and more specifically an error stating that the user name provided was not encoded as a claim, then you may need to remove any configured SAML claims providers in order to add the users to the permissions list.