Dealing with SharePoint 2003 API and ASP.NET …

If you have worked with SharePoint 2003 Webservices, then you probably had to deal with some security, permissions or impersonation issues.  Some of these issues can arise if you don’t think in a solid architecture from scratch.

I will try to show a few recipes in order to make your life easier at the time of developing an ASP.NET web application integrated with SharePoint.

Let me introduce you to our project scenario.  One of our customers in the public sector needed a solution which consisted in the following three main components: ASP.NET 2.0, Windows SharePoint Server and K2 Workflow engine (old technologies but these were non functional requirements from the customer). 

The solution, currently deployed in the customer’s intranet supports the creation and flow of multiple documents within the organization based in well defined processes.

Both the ASP.NET application and the SharePoint Server run in the same box. The K2 Workflow Server runs in another box, both of them under the same Active Directory domain. Users get logged into the application by using Windows Authentication. Part of the application’s logic includes the creation of sub-sites and document’s uploading within several document libraries in SharePoint, with some code running in the ASP.NET application.Unfortunately, SharePoint 2003 does not support the creation of sub-sites through its Web Services, so we had no choice but to use the SharePoint API directly from our solution. This will end in chaos if we don’t face this correctly.Based in the previous scenario, the ASP.NET application is configured in IIS for using Windows Authentication with anonymous access unchecked.  

This is because we need to know which user started a given process … in addition, K2 Workflow methods need to execute under the context of the logged user.

For achieving this, all that we needed to do is enable impersonation in the web.config. In consequence, every method in our ASP.NET application will run under the logged user’s credentials.

This is good for K2, but not a good option for SharePoint because not every user should be allowed to create sub-sites in our server.

What decided to use WindowsImpersonationContext for passing the credentials of a user with sufficient permission for creating sub-sites and managing document libraries in SharePoint.

In order to achieve this, we called the unmanaged LogonUser method for getting the appropriate token handle and after that creating a brand new WindowsIdentity object.

It is worth to emphasize that the code running inside the WindowsImpersonationContext will have elevated privileges – or not – but in our context it does, so we need to ensure that if something happens inside this code block we can revert to the original credentials:// Some work to do ...        WindowsImpersonationContext impersonatedUser = null;        

try

{           
impersonatedUser = newIdentity.Impersonate();            // Elevated privileges work ...       
}        finally {      
impersonatedUser.Undo();       
}  

// Some more work to do ...

At a first glance, it seemed everything was fine.But I recall exactly the time when we built the application, run it, debugged the code and got the impersonated user’s credentials properly, but as soon we call the CreateSite() method, a new exception had been thrown from Sharepoint: “Access is denied exception from hresult 0x80070005”

 

Not a descriptive one thought J … so what was going on?

 

We were trying to create the sub-site with the appropriate credentials but that wasn’t enough.

 

We forgot about something … the Application Pool identity!By default, IIS Application Pools run under the Network Service account.

This account has very few privileges in order to accomplish the least privilege execution principle.

We had to change this in order to let our SharePoint API methods run properly.  The following is a very basic example of a web method which creates a sub site: 

 

[WebMethod]        public void CreateSubSite(string subSiteName){           
WindowsImpersonationContext impersonatedUser = null;                       
try{               
newIdentity = GetIdentityWithPermissionsInSPS();                impersonatedUser = newIdentity.Impersonate();                 using (SPSite site = new SPSite(spServerAddress))               
{                   

using (SPWeb theWeb = site.OpenWeb()){

       theWeb.AllowUnsafeUpdates = true;                               theWeb.Webs.Add(subSiteName);                   
}               
}           
}            finally {                
if (impersonatedUser != null){ 
                   impersonatedUser.Undo();               
}           
}                   
}

 

We decided to change the Application’s Pool identity of our ASP.NET frontend application for the appropriate account with permissions for creating sites in SharePoint right away.

As soon we did this, the exception went away!

But, it isn’t a good idea to let our ASP.NET application run under the context of an Application Pool with such privileges. So we considered creating a new Web Service -which would be referenced from the ASP.NET application- responsible of calling the SharePoint API directly. This new Web Service will run in a new Application Pool configured with an identity with enough privileges for performing changes in SharePoint.Below is an image showing how this architecture was conceived:

 Sharepoint and asp.net architectura proposal

 

In conclusion, we have performed a separation of responsibilities here; the ASP.NET application doesn’t have to know how to deal with SharePoint. For that reason, we created this new Web Service responsible of doing the “dirty” job.

I hope this post can help someone over there who might be working on a similar scenario.  By the way, we are now starting a new project for another customer with exactly the same requirements, but we can use MOSS 2007 and WF, which is cool. So we’d love to hear any advice from you in order to have our new architecture more scalable, secure, stable and performing.

 

Posted written by Damian Da Silva - UruIT Global IT Services. Dev Team 

 

No Comments