SharePoint, Code Access Security and the SmartPart
Security is hot these days, and that’s a good thing. But from the developer’s point of view, security can be a bitch sometimes. Code Access Security (CAS for short) is a wonderful and very useful concept, but developers need to know keep CAS in mind if they want their code to run. If you want to learn more about CAS in general, I definitely recommend Maxim Karpov’s article as a starter.
When you’re building SharePoint webparts (and when you’re doing ASP.NET in general), CAS really comes into play because in most scenario’s your code won’t have Full Trust. This means that it can’t do just anything, everything needs to be explicitly granted. For more information about CAS in combination with SharePoint, check out this article on MSDN.
When you’re using the SmartPart for SharePoint (also see my previous post) you’re in a special scenario with three involved parties: SharePoint, the SmartPart and your code. Let’s say you want to create a somewhat advanced user control (to show in the SmartPart) that connects to a web service (or a database), you’ll run into some problems. If you’ve already tried to do that when using the SmartPart, you’ll find the following exception in the Event Log:
Request for the permission of type System.Net.WebPermission, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 failed.
Why do we get that exception? By default, all the code that’s executed in the \BIN folder of the SharePoint site, uses a reduced set of permissions, specified in the web.config file (e.g. WSS_Minimal or WSS_Medium). The permission to connect to a web service (WebPermission) or to connect to a database, is not granted by default. That’s why the code won’t run. To solve this issue, one would think “let’s add that permission for the webpart”. But remember we’re using the SmartPart webpart, so adding permissions won’t help us because the user control code still has does not get the needed permissions. An easy, but drastic solution is to deploy the code to the Global Assembly Cache (GAC). Every assembly in the GAC, runs in Full Trust. Installing the SmartPart in the GAC is easy, during the installation the question is asked whether you want the assembly to be installed in the GAC or not. Deploying the user control’s assembly to the GAC is also quite easy (if your assembly has a strong name of course): drag-and-drop the .dll file to c:\windows\assembly. But there’s only one issue to solve: you’ll notice that once you’ve deployed the user control’s assembly to the GAC (and deleted it from the \BIN folder of course), you’ll get an exception (unable to load). So it seems that the SmartPart does not look in the GAC to load the user control’s assembly. To fix this (last!) problem, you need make some modifications to the web.config file of the SharePoint site: in the “compilation” section you need to add the user control’s assembly:
<compilation batch="false" debug="false">
<assemblies>
<add assembly="DropDownNavigationVB, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3948f234bbbabe18" />
</assemblies>
</compilation>
All these steps may be a little bit overwhelming, so let’s summarize and create an example. The example will connect to a web service and fetch some weather information (I’ve used this web service from CapeScience).
- Step 1: install the SmartPart and make sure you deploy it to the GAC.
- Step 2: create a new ASP.NET web application that will contain our user control, name it for example WeatherInfo. Add a web reference to the GlobalWeather wsdl and name it WeatherServices for example. Add a new Web User Control to the project and name it WeatherInfo and add a Label control to it. Switch to code view, and type following code in the Page_Load method:
private void Page_Load(object sender, System.EventArgs e)
{
WeatherServices.GlobalWeather gw = new WeatherServices.GlobalWeather();
Label1.Text = "Temperature in Brussels: " +
gw.getWeatherReport("EBBR").temperature.ambient.ToString();
}
Because we will have to deploy the user control’s assembly to the GAC, we need to give it a strong name. So generate a public/private key pair, and specify it in the AssemblyKeyFileAttribute in the AssemblyInfo file. (more detailed information about this process can be found here) Additionally you can change the version number specified in the AssemblyInfo file to a fixed version number (e.g. 1.0.0.0), otherwise every build a new version number will be generated. Finally, you can build the project. - Step 3: deploy the user control’s assembly. To deploy the WeatherInfo.dll file to the GAC, you can just drag-and-drop it to the c:\windows\assembly directory, or you can use the GACUTIL utility. The WeahterInfo.ascx file needs to be copied for example to the \UserControls folder of the SharePoint site (this is not a default folder, so you need to create it yourself).
- Step 4: Alter the web.config. As mentioned before you need to alter the web.config of the SharePoint site, so the user control’s assembly can be located in the GAC. To do this, find the compilation section, that looks like this:
<compilation batch="false" debug="false" />
and change it to:
<compilation batch="false" debug="false">
<assemblies>
<add assembly="WeatherInfo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6185e98411448c6a" />
</assemblies>
</compilation>
I use the Reflector tool to read the public key of my assembly (you can copy-and-paste the full assembly name, so you won’t make any typos). - Step 5: load the user control in SharePoint. Finally you can add a SmartPart webpart to a SharePoint site, that will load the WeatherInfo control. Set the User Control property to ~\UserControls\WeatherInfo.ascx and click the OK button. If everything went well, you now should be able to see the temperature in Brussels!
To conclude, I’ll repeat one of the first sentences of this post: security can be a bitch sometimes. :-) But we must think about CAS as a good thing. Even the extra steps considered, that need to be taken to get the WeatherInfo webpart running, I still think creating SharePoint webparts with the help of ASP.NET User Controls is a productive approach. But at the same time I’m wondering about how the GAC deployment step can be avoided. Anyone has an idea?
You can download the WeatherInfo solution from the GotDotNet Workspace. In the next post I’ll dive into how you can easily test-drive webparts when using the SmartPart webpart.