Desktop SharePoint Apps for SAML Secured SharePoint Sites

Continuing on with the theme of SAML secured SharePoint sites and SharePoint Apps, this next posting looks at another common application model, which is using what I call a desktop app to connect to SharePoint. By “desktop”, I mean an app that doesn’t have an HttpContext, like a console application or winforms app. It could run on a desktop, on a server, in an Azure web job, etc. but the fundamental theme is that there is no HttpContext associated with the request and there may not be an active user context either (as is the case with a console app).

To create this solution we’re going to build upon two previous Share-n-Dipity posts:  https://blogs.technet.com/b/speschka/archive/2013/06/12/converting-a-vs-net-web-for-a-provider-hosted-sharepoint-app-to-a-full-blown-web-or-console-application.aspx and https://blogs.technet.com/b/speschka/archive/2014/09/30/an-updated-claimstokenhelper-for-sharepoint-2013-high-trust-apps-and-saml.aspx. There are some slightly newer steps required to get your desktop application configured to be used as a SharePoint App, and then I’ve made some additions to the ClaimsTokenHelper code to facilitate this scenario. When you’re done you’ll be able to use a desktop app for the following scenarios:

  1. High trust with an App + User context

  2. High trust with an App Only context

  3. Low trust with an App Only context

So in short we can address all of the primary app contexts except for low trust App + User; the reason we can’t do that one is that as described above, there is no HttpContext so we can’t get SharePoint to give us a low trust user context. There’s still a lot to work with though so let’s walk through the process.

As a starting point for this scenario, I always recommend that you build out a working “standard” provider hosted SharePoint App for your scenario. To do that, start with Visual Studio and create your application using the Visual Studio wizard. It creates the SharePoint App as well as web application project that uses IIS Express. From this point forward this web application project that VS.NET creates shall be referred to as the "original web app". Verify that everything is working correctly.

Next create the new application you are going to use - a console project or winforms project. You now need to copy over the configuration information from the web.config file of the original web app to your application. The difference of course is that neither a console nor winforms project has a web.config, so you will put the configuration information in the application settings. To do so, go into the Properties of the application, click on the Settings link on the left. If you are in a console application then you will see a link in the middle of the page that says "This project does not contain a default settings file. Click here to create one."; click on it to create a settings file. A winforms project displays the settings grid by default so you can just begin creating properties. Go ahead and create properties for each of the appSetting properties from the original web app’s web.config file - copy in both the key (as the setting Name) and value (as the setting Value). Make sure you configure each setting an Application scope property (it is User by default).

The references required for the project should be added next. Add the following references to your project:

  • Microsoft.IdentityModel

  • Microsoft.IdentityModel.Extensions

  • Microsoft.SharePoint.Client

  • Microsoft.SharePoint.Client.Runtime

  • System.IdentityModel

  • System.ServiceModel

  • System.Web

  • System.Web.Extensions

  • System.Configuration

Now create a new folder called “App_Code” and copy into it the TokenHelper.cs and SharePointContext.cs files from the original web project. Also copy in the ClaimsTokenHelper.cs and SharePointContextExtensions.cs files that are included with this post. After you’ve added the files change the namespace attribute in each class to match the namespace attribute of your project. For example, if you create a console project called “SamlConsoleApp”, then you should change the namespace attribute in each class to be:

Namespace SamlConsoleApp

{

      //rest of your class here

}

Next you need to update the properties in TokenHelper.cs and ClaimsTokenHelper.cs that currently look to the web.config file for their values. They should instead use the application settings, since that’s where the configuration is being stored in console and winforms apps. In TokenHelper.cs look for the following properties:

  • ClientId

  • ClientSigningCertificatePath

  • ClientSigningCertificatePassword

  • IssuerId

  • ClientSecret

In ClaimsTokenHelper.cs find these properties:

  • TrustedProviderName

  • MembershipProviderName

 

Replace the value of each of these properties with a call to the application settings, like this:

private static readonly string TrustedProviderName = yourAppNamespace.Properties.Settings.Default.TrustedProviderName;

Where yourAppNamespace is the namespace for your console or winforms application.

NOTE: If you did not create each of those properties in your application’s Settings file, then you will not have corresponding properties for each item listed above in TokenHelper.cs and ClaimsTokenHelper.cs. That’s okay – just leave them as is and change the ones you DO have.

Finally, you need to change the modifier on the TokenHelper class from public to public partial. You can do that by changing the class from “public class TokenHelper” to “public partial class TokenHelper”. At this point all of the modifications are complete. You should compile your code and verify that it completes without error. If you missed any of the steps above then you will likely get compiler errors or warnings now that should direct you to the areas that need to be fixed. Now you can finally start writing some code!

The actual code to connect to SharePoint and get a ClientContext varies depending upon the scenario you are using. Here’s an example in a console app of all three use cases I described above:

//this is the SharePoint site we want to work

//with; you must provide this since there is no HttpContext

Uri hostWeb = new Uri("https://samlpnp.vbtoys.com");

 

//request using:

//1.  High Trust

//2.  App + User context

using (var userContext =

SharePointContextProvider.Current.CreateDesktopUserContext(hostWeb,

TokenHelper.IdentityClaimType.SMTP,

"sam.smith@contoso.com"))

{

     //your code here

}

 

//request using:

//1.  High Trust

//2.  App Only context

using (var highAppContext =

SharePointContextProvider.Current.

CreateDesktopHighTrustAppOnlyContext(hostWeb))

{

     //your code here

}

 

//request using:

//1.  Low Trust

//2.  App Only context

using (var lowAppContext =

SharePointContextProvider.Current.

CreateDesktopLowTrustAppOnlyContext(hostWeb))

{

     //your code here

}

Now for a couple of notes on the implementation. I made changes to both the ClaimsTokenHelper and SharePointContextExtensions classes from my previous post on this topic. For ClaimsTokenHelper I modified it so that you can pass it the identity claim you want to use for the user when using an App + User context. Again, this is because there is no HttpContext so you don’t have access to things like a claims collection or an authentication process you can plug into. You can use the current process identity, a configuration file, or even just hard code the identity you want to use into your application. You aren’t send along credentials in this case, you’re just telling SharePoint the user context that should be used when it processes your CSOM calls. That is exactly what high trust was designed to do.

In addition to that, I added some additional methods to the SharePointContextExtensions class. Again, the original SharePointContextProvider class creates a SharePointContext based on an HttpContext, and then you create a ClientContext from that. Since the HttpContext doesn’t exist, none of those methods work. To work around that, we can bypass creating the SharePointContext and go straight to creating a ClientContext. The extensions class was updated to add these additional methods that you see demonstrated above: CreateDesktopUserContext, CreateDesktopHighTrustAppOnlyContext, and CreateDesktopLowTrustAppOnlyContext. As a side note, one of the other interesting “features” of doing this in a desktop app is that you can mix both low trust and high trust calls in the same application. Because of the way the SharePointContextProvider class that comes with Visual Studio uses session state to manage your context, this is not possible in a web application. I don’t know if that will ever matter to anyone, but it doesn’t hurt to have another capability in the tool belt.

Here are screenshots of the code executing successfully in a console app and then in a winforms app:

 

 

That’s it for this post. I’ve attached a zip file with the updated ClaimsTokenHelper.cs and SharePointContextExtensions.cs files, as well as two sample projects – one a console app and the other a winforms app that demonstrates using these new classes and techniques. Good luck!

SamlConsole.zip