SharePoint Online and Windows Azure: Developing Secure BCS Connections using WCF Services

 

SharePoint Online and Windows Azure: Developing Secure BCS Connections in the Cloud

Introduction

Over the Christmas vacation, a few of us got together and started down the path of how to not only secure external data connections to SharePoint Online, but more generally discussed a few different patterns that can be used to develop ‘complete cloud’ solutions; that is, solutions that leverage the collaborative platform and features of SharePoint Online and deploy solutions to SharePoint Online with code that lives in Windows Azure.

In this blog post, I’m going to cover how to secure an external data connection with the Business Connectivity Services (BCS) using a secure WCF service deployed to Windows Azure. The discussion will highlight three additional areas you need to consider when securing the connection. The blog post will reference a comprehensive hands-on lab at the end that you can walk through to replicate what is discussed.

Business Connectivity Services and SharePoint Online

Late last year, I wrote a blog post on SharePoint Online’s newest feature addition: BCS. On its own, BCS is a very interesting artifact; it enables you to connect external line-of-business (LOB) systems with SharePoint Online. So, what at first appears to be a normal looking list actually dynamically loads the external data from a cloud-based data source like SQL Azure. This special kind of list is known as an external list. For example, you can see how the below list exposes data from an external data source and provides the user read/write permissions on the data it dynamically loads.

clip_image002[5]

Figure 1: External List Loading External Data

Now it’s not my intention in this post to give you an overview of the BCS; you can get a great introduction to SharePoint Online and BCS by reading this article: https://msdn.microsoft.com/en-us/library/hh412217.aspx. More to the point, my previous blog post(s) focused on how to walk through the creation of an external content type (ECT) using a WCF service deployed to Windows Azure that acts against a SQL Azure database, also hosted in the cloud. You can find a prescriptive walkthrough here: https://blogs.msdn.com/b/steve_fox/archive/2011/11/12/leveraging-wcf-services-to-connect-bcs-with-sharepoint-online.aspx. However, while the aforementioned blog post gave you a walkthrough of how to create the connection between an external data source and SharePoint Online, it didn’t discuss how to secure that connection.

Key Elements in Securing the Connection

While creating an open WCF service (e.g. HTTP-enabled service with no authentication) can be useful in some situations, say exposing bus schedule data or public demographic information, it’s doesn’t enable developers to add a level of security that you will often require. You can control permissions against the ECT, thus provisioning some consumers of the external list with read-only privileges and others with read/write privileges, but that’s only one layer—it doesn’t cover the service layer. To add an additional layer of security for the WCF service, in this pattern, will necessitate three additional steps:

1. Configuring the service to be an HTTPS endpoint rather than an HTTP endpoint.

2. Leveraging the UserNamePasswordValidator class to help authenticate the service.

3. Encrypting the WCF service with a certificate.

I’ll provide some discussion around these three elements and then to close this blog post will point you to a comprehensive hands-on lab that we’ve put together for you to walk through and test this pattern.

Configuring the WCF Service

To create an open or non-secure (HTTP) service, you can use BasicHttpBinding on the service. For example, the serviceModel snippet from my service web.config below illustrates how I used BasicHttpBinding to create a recent service that exposed Grades data in SharePoint Online.

<system.serviceModel>

<services>

<service behaviorConfiguration="Grades_LOB_For_SP.Service1Behavior" name="Grades_LOB_For_SP.GradeService">

<endpoint address="" binding="basicHttpBinding" contract="Grades_LOB_For_SP.IGradesService">

<identity>

<dns value="localhost" />

</identity>

</endpoint>

<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

</service>

</services>

</system.serviceModel>

However, when redeploying the service for security, you can employ a number of methods to either pass or look up the identity of the SharePoint user (or external system identity) when creating your WCF service. For example, you could amend your service configuration and move beyond BasicHttpBinding and use WSHttpBinding instead. Using WSHttpBinding provides a broader array of security options that you can use to authenticate the service. Thus, when the identity of the client is known, it is authorized to perform the functions that are built within the service—e.g. create, read, update, and delete web methods that execute against the back-end (external) data source.

<system.serviceModel>

<bindings>

<wsHttpBinding>

<binding name="Binding">

<security mode="TransportWithMessageCredential">

<transport />

<message clientCredentialType="UserName" />

</security>

</binding>

</wsHttpBinding>

</bindings>

<behaviors>

<serviceBehaviors>

<behavior name="NewBehavior">

<serviceCredentials>

<userNameAuthentication userNamePasswordValidationMode="Custom"

customUserNamePasswordValidatorType="MyService.Identity.UserAuthentication, MyService" />

</serviceCredentials>

<serviceMetadata httpsGetEnabled="true" />

<serviceDebug includeExceptionDetailInFaults="true" />

</behavior>

</serviceBehaviors>

</behaviors>

<services>

<service behaviorConfiguration="NewBehavior"

name="MyService.Service">

<endpoint address="" binding="wsHttpBinding" bindingConfiguration="Binding"

name="MyService.Service"

contract="MyService.IContentService" />

<endpoint address="mex" name="MetadataBinding" binding="mexHttpsBinding"

contract="IMetadataExchange"></endpoint>

</service>

</services>

<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

</system.serviceModel>

From the above excerpt from my web.config file, you can see that there are a few more configuration options to consider/add when locking down your service. And debugging these in the cloud can be a challenge, so be sure to turn on errors and debug locally often before deploying into your cloud environment.

For more information on transport security, go here: https://msdn.microsoft.com/en-us/library/ms729700.aspx.

Using the UserNamePasswordValidator Class

When authenticating using WCF, you can create custom user name and password authentication methods and validate a basic claim being passed from the client. The creation and passing of the username and password claim can be accomplished by using the UserNamePasswordValidator class. For example, in the following code snippet, note that the Validate method passes two string parameters and in this case uses comparative logic to ‘authenticate’ the user.

public override void Validate(string userName, string password)

{

if (null == userName || null == password)

{

throw new ArgumentNullException();

}

if (!(userName == "SPUser1" && password == "SP_Password") && !(userName == "SPUser2" && password == "SP_Password2"))

{

throw new FaultException("Unknown Username or Incorrect Password");

}

}

Note: The username and password are passed using the Secure Store Service Application ID. So, when you add the service using SharePoint Designer, you would add the username and password that would be validated within the WCF service.

This proved to be an interesting framework to test the authentication of the SharePoint Online user, but the reader should be aware that we still are discussing the pros and cons of implementing this pattern across different types of production environments. Perhaps for a small-scale production services architecture, you might leverage this, but for large, enterprise-wide deployments managing and mapping credentials for authorization would require a more involved process of building and validating the user.

You can find more information on the UserNamePasswordValidator class here: https://msdn.microsoft.com/en-us/library/aa702565.aspx.

Encrypting a WCF Service using Certificates

The final piece of creating the new and secured service was encrypting the WCF service using trusted certificates. The certificate not only enabled an encrypted connection between the WCF service and SharePoint Online, but it also established a trusted connection through the addition of an SSL certificate from a trusted certificate authority. For this service, you must create a trusted certificate authority because SharePoint Online does not trust a self-signed certificate. The username and password are passed in the request header, which is trusted by the WCF service. This provides transport level authentication for the WCF service.

Beyond the process of creating a trusted certificate authority, a couple of things you’ll need to be aware of:

1. The Windows Azure VS tools automatically create a certificate and deploy it with your code. You can view it from your Settings in your project.

2. You need to both include your trusted certificate authority with your service code and upload it to your Windows Azure management portal.

Note: I mention #1 because we ran into an error when deploying the service, and it turned out to be a mismatched certificate error with the auto-generated certificate in the tools. (Reusing the thumbprint from my trusted certificate authority got it working.)

Adding the trusted certificate authority is straightforward; you use the Cloud project Settings to add certificates, as per the figure below.

clip_image004[4]

Figure 2: Certificates in Windows Azure Project

Also, note that you’ll need to ensure you enable both HTTP and HTTPS on your service endpoint—and then map the SSL Certificate Name to your secure HTTPS endpoint in your Windows Azure project.

clip_image006[4]

Figure 3: HTTP and HTTPS Endpoints in the WCF Service Project

After you load your trusted certificate authority to your Windows Azure subscription, you’ll then note that you have the chained certs as well, as per the figure below.

clip_image008[4]

Figure 4: Uploaded Certificates in Windows Azure

The net result of deploying the now secured service is that you can browse to the service and then click the security icon in the URL field to view the certificate information. You should also be able to browse your WSDL without any issue.

image

Figure 5: Final Service

At this point, you can then use this service endpoint to create the ECT in much the same way you did in my earlier post.

Summary & Specific Guidance

This blog post was a follow-up to my earlier post on using WCF to connect SQL Azure data to SharePoint Online. It was meant to highlight how the earlier non-secure WCF service that was connected to SharePoint Online could be extended and secured using 1) WCF HTTPS, 2) the UserNamePasswordValidator class, and 3) trusted certificate authority. I typically like to give prescriptive guidance for developers to use to test out these patterns, so to help you get on your way, we’ve put together a comprehensive hands-on lab that walks you through how to create a secure WCF service and connect to SharePoint Online using BCS in a step-by-step fashion.

You can download a lengthy hands-on lab that walks you through the specifics by going here: https://tinyurl.com/7oghxln.

This is an interesting movement forward in the ever-evolving SharePoint Online and Windows Azure development story. We’ll have more for you moving forward. Look for some additional information on general cloud patterns with SharePoint Online and Windows Azure and also some cross posts that will highlight service-bus relay patterns as well as additional information around identity management.

I’d like to thank a couple of the guys on my team (Paul and Matt) and the team from Hyderabad (Aniket, Manish, Raj, & Sharad) on their collaboration to get us this far. Lots more good stuff to come on SharePoint Online and Windows Azure development with quite a bit of interest on this from the community.

Have fun!

Steve

@redmondhockey