Friday, December 7, 2012

Using the SharePoint Client Object Model Over SSL

The SharePoint client object model is a thing of beauty IMO.  It allows access to your SharePoint environment through external code and can really help you out in sticky situations.  I was recently tasked with allowing external users to submit list items to an internal SharePoint task list.  My solution to this was create a simple ASP.NET form that utilized the client object model to submit the list items.  This allowed for very simple form and server side code to be deployed all while using a service account with extremely limited access (basically authenticate and add list items to a single list).

The issue I ran into was the internal server was using SSL.  Fortunately this was an easy fix which I'll detail here.  This was a two part fix:
  1. Export the SSL certificate from the internal server for use in the code.
  2. Modify my code to use that certificate.
There are a lot of examples on the web that show how to do both of these things, and I looked at most of them ;).  But I couldn't find a great post that showed an end to end solution, so here goes.

Export the Certificate

So, the first thing to do is export the SSL certificate from the server that you will be calling into.  In my case, this is the internal server.  Log into that machine and run the MMC console.

Next click File -> Add/Remove Snap-in.

In the next window click "Certificates" from the list and then click "Add".  This will bring up another window, from here select "Computer Account" and click "Next".

In the next window choose "Local Computer" and click "Finish", then click "OK".

Now you will have a list of folders under the "Certificates" header.  You will most likely find your certificate under "Personal".  Hopefully when the certificate was installed a proper Friendly Name was given to it.  In my case it was the same as the SharePoint web application name with port number.  It was easy to find!

Right click the certificate and choose All Tasks -> Export.







Now you have a copy of the certificate you can use when calling the internal server.  In my case, I copied this over to the external server to use in my calls.

The Code

Once we have our certificate exported copy it over to the external server and place it anywhere you like.  In my case I put it on the D: in its own folder.  Now for the code:

 using  (ClientContext  context = new  ClientContext("SERVERURL"))
                 ServicePointManager .ServerCertificateValidationCallback = delegate (object  sender1, X509Certificate  certificate, X509Chain  chain, SslPolicyErrors  sslPolicyErrors)
                     bool  validationResult = true ;
                     return  validationResult;
                 context.ExecutingWebRequest += new  EventHandler <WebRequestEventArgs >(context_ExecutingWebRequest);
                 Web  web = context.Web;
                 List  list = context.Web.Lists.GetByTitle("LISTNAME");
                 context.Credentials = new  NetworkCredential ("USERNAME", "PASSWORD", "DOMAIN");

This code is a stripped down example of using the ClientContext class.  As you can see there is no code after the ExecuteQuery method, nor do I perform any loads.  This example isn't meant to show case using the ClientContext, only how to use a certificate with the call.  Here are the important parts:

  • ServicePointManager.ServerCertificateValidationCallback - this method simply validates the certificate to ensure its being used on the same domain.  In my case it was not, so I simply return a true, since I know it will fail but I want to call across domains.
  • context.ExecutingWebRequest - this sets a delegate method (below) that will actually apply the cert.
  • context.Credentials - since I'm calling a different server, I need to specify credentials for a valid account.  In my case we set up an account in AD that would be used to authenticate to SharePoint.  That account was then given strict permissions in SharePoint, basically it could only add new items to one specific list in the environment.

 static  void  context_ExecutingWebRequest(object  sender, WebRequestEventArgs  e)
             HttpWebRequest  webReq = e.WebRequestExecutor.WebRequest;
             //webReq.Proxy = new WebProxy("http://[ProxyAddress]"); //Specify a proxy address if you need to 
             X509Certificate  cert = X509Certificate.CreateFromCertFile("D:\yourcert.cer");

The ExecutingWebRequest method simply creates an HttpWebRequest and adds the certificate to it.  As you can see it just grabs the cert from the D: where it is stored.

And thats it!  Using this method I was able to use the client object model to connect from an external server to an internal server and add list items.


No comments:

Post a Comment