SharePoint 2003 and the Implications of Code Access Security

Sep 25, 11:00 pm

Article Author: Andre Strik
.NET 3.5 Books

Introduction


Often times people take the easy route in Sharepoint development, and set the virtual server’s trust level in the web.config file to full . What does that mean exactly? Well, you’ve no doubt heard of Code Access Security ( CAS ), Microsoft’s .NET-based mechanism for securing code. Setting the trust level of your virtual server to full , basically tells the .NET Runtime that all code that runs on that given virtual server, can access all those classes that are protected by permission classes. An example of this in SharePoint would be that any code could access and manipulate the SharePoint object model, eg. to create new lists, list items, or delete them. I don’t believe this is obviously not desirable, certainly not in a production environment – rather, I would argue that setting your CAS policy from the outset is definitely a best practice that should be followed.


This article will provide an overview of the code access security process as well as a detailed look into the structure of the CAS policy file. The permissions that are provided specific to SharePoint are discussed, along with examples of when these come into effect. Lastly this article shows how to tie in specific requirements of using SharePoint into the CAS policy. An example solution is provided for download, which demonstrates web parts utilizing the permissions within SharePoint.


System Requirements


To work with the solution in the downloadable sample, you need the following:


  • Visual Studio .NET 2002 or greater

  • Microsoft .NET Framework 1.1

  • Windows Server 2003

  • Windows SharePoint Services 2003

  • SharePoint Portal Server 2003 (optional)

CAS and SharePoint 2003


When developing web parts, custom web controls, web services and other functionality for use in SharePoint 2003, there will be times when you need to access some of SharePoint’s resources that are protected by SharePoint’s permission classes. In order to access them without throwing a security exception, your code will be required to have gained the required permissions for the resources that it is attempting to access.


The process of ensuring the .NET runtime grants the permissions required for your code is the responsibility of the Code Access Security policy . This policy is defined within an XML file and is used to give assemblies a given level of trust on a virtual server. The trust level for the virtual server is set in the web.config file located in the root folder of the virtual server. The default level of trust applied to a virtual server extended with Windows SharePoint Services is WSS_Minimal , which as its name implies only provides a very minimal level of trust to your installed assemblies. There are many situations when the WSS_Minimal security policy may be too restrictive for the needs of your code. A simple example would be when your web part needs to access documents in a given document library on the SharePoint site that it is installed on. In this case the runtime would throw a security exception when your code attempts to do this. Therefore the code will need to have the additional permissions granted to it in order to access the requested documents.


There are three methods that one can employ to ensure that code is granted the required permissions when accessing protected resources:


  1. Increase the level of trust of the virtual server

  2. Strong name the assembly and install it into the GAC

  3. Implement a custom policy file, tailored to the individual requirements and set the virtual servers trust level to use the custom policy

Increasing the level of trust on the web server is the easiest option – but it’s also the least secure as it means you increase the level of trust for all assemblies on that virtual server. Also, the two security policies provided with SharePoint do not cover all the CAS options, therefore this option will require in some scenarios to raise the level of trust to full, which is never recommended even though, as noted in the introduction, it’s often used because of its simplicity. Giving the environment more trust than is required raises the possibility of exposing security holes. Also, if you port your code to another environment which has more stringent security policies in place, you run the risk of your code breaking due to security exceptions being thrown.


Placing strong named assemblies in the GAC ensures you have a better idea of the origin of the code, although like the previous method it means increasing the trust of the assembly over a greater range than would normally be required. The assembly in the GAC is given full trust across the entire server that it is installed on. The code that calls into the assembly in the GAC is required to have full trust as well (unless the assembly uses the AllowPartiallyTrustedCallers attribute). The use of the AllowPartillyTrustedCallers attribute, which allows partially trusted assemblies to call assemblies in the GAC, is outside the scope of this article, but the References Section of this article contains several links to read more about this topic.


The third option – that of implementing a custom security policy – requires the most work and understanding, but provides you with the most granular and tailored options. At first glance this option appears to be a little unwieldy and is difficult to understand, though with a little insight into the workings of the Code Access Policy and the permissions provided with SharePoint, you will soon be able to implement your own custom policies, making concise decisions and knowing the full implications of those decisions. This, as you would have probably guessed is the approach recommended by Microsoft.


About the Sample Code


The sample code for this article is a solution, SharePointCAS that allows you to setup a couple of workable scenarios and test out the use of a custom CAS policy with code that you can compile yourself. The solution includes three projects in which the custom CAS policy file will handle differently depending on the settings of the policy file. As seen in Figure 1, the three projects each include a web part which have all been written using the same code. The web parts each render exactly the same since when first installed I temporarily set the trust level for the virtual server to Full , and so all code is allowed to run without any security exceptions being thrown.



Figure 1. The installed web parts running with full trust


The first project, called UnprivilegedAssembly , includes a simple web part called SimpleUnprivilegedWebPart , which during execution attempts to access the SharePoint object model and save property changes. The custom policy file provided in the solution is set so the UnprivilegedAssembly is not granted the SharePointPermission and therefore when you set the trust level of your virtual server from full trust to use the custom CAS policy, the code will have exceptions thrown, as shown in Figure 2.



Figure 2. The installed web parts using the custom policy file


The second project, called PrivilegedAssembly , uses a web part that is identical other than that it is called SimplePrivilegedWebPart . The CAS Policy file is set so that the PrivilegedAssembly is granted access to the SharePoint object model and is also allowed to save properties. As you can see in Figure 2, SimplePrivilegedWebPart has been granted the necessary permissions in the Custom CAS Policy file and therefore no security exceptions are thrown. The UnprivilegedAssembly project also includes two other web parts called UnprivilegedConsumerWebPart and UnprivilegedProviderWebPart . These web parts connect to each other so that the provider should be able to provide information to the consumer. However, the CAS policy does not grant UnprivilegedAssembly the WebPartPermission.Connections attribute (more on this later), and so prevents this communication from taking place. I have wrapped the code in a try / catch block and rendered the security exception in red in the UI, to highlight what is happening. Doing this not only allows processing to continue while displaying details of the exception to the UI.


A third project called StrongNamedAssembly is provided to show what the effects are of strong naming an assembly and placing it in the GAC. The project again provides a web part using exactly the same code as for the other projects, although the webpart is now called StrongNamedWebPart . If you try changing the settings of the custom policy file, you’ll soon notice that the StrongNamedWebPart will always successfully execute. This is because, like all assemblies in the GAC, this assembly will be given full trust by the .NET runtime when the CAS policy is applied.


The sample download also includes a Word document with screen shots of what the UI should look like after specific changes have been made to the Custom CAS Policy. This will provide a guide of some examples of what you could change in the custom CAS Policy file and what the effect you should see.


Instructions for installing the web parts is provided in the readme.txt file within the sample download.


Application of Code Access Security


To fully understand the process, options and implications of implementing a custom security policy a quick overview of the application of Code Access Security is in order.


Figure 3 shows the process of loading an assembly into memory, applying CAS policy to it, and then the having that assembly attempt to access managed code that is protected by a permission class.



Figure 3. The CAS Policy Process


Loading and Gathering Evidence


CAS first comes in when the assembly is loaded. At this time, evidence is obtained to ascertain the publisher and location of the assembly. Evidence can be defined as the properties of the assembly that indicate to the .NET runtime that it contains given characteristics. These characteristics assessed against the CAS policy to determine what permissions the assembly will be granted. The characteristics in question can be divided into the two types: Location-based evidence and publisher-based evidence . Examples of these are listed in the following table.



















Location-based evidencePublisher-based evidence
URLStrong name
SitePublisher
Application DirectoryHash
Zone 



In the example solution, the custom CAS policy file that is implemented uses the URL to determine that PrivilegedAssembly should be granted the SharePointPermission and WebPartPermission , and UnprivilegedAssembly should not. Strong name evidence is also used by the policy file to determine that the StrongNamedAssembly is in the GAC and therefore granted full trust.


Applying CAS Policy and Granting Permissions


Application of the CAS policy takes place on three administrable policy levels, enterprise, machine and user. Each level has a security policy file defining a level of trust to apply to assemblies. The runtime uses the policy files to assess what permissions an assembly is granted.


For each policy level, permissions are granted to assemblies by matching their evidence with the defined named permission sets that they are matched to. After the runtime assigns the permissions for all three levels, it then takes the permissions common across the three levels and grants them to the assembly.


Accessing Protected Resources


Based on the evidence obtained and the CAS policy applied, when an assembly is loaded, it is granted just those permissions to which it is entitled. During subsequent execution, it may attempt to access a resource that is protected by a given permission class. When this occurs, the protected resource will demand the permission concerned. If the assembly has in fact been granted that permission, processing continues. If however, the assembly has not been granted the required permission, the .NET runtime will throw an appropriate security exception, an example of which is shown below.



Request for the permission of type 
Microsoft.SharePoint.Security.SharePointPermission,
Microsoft.SharePoint.Security, Version=11.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c


By the way, the SharePointPermission exception is also the exception thrown in the sample code when eg. the UnprivilegedWebPart attempts to access the SharePoint object model. In the code, the exception is caught and displayed to the UI, although obviously you’ll want to take some other appropriate action in production code – details of exceptions are the kind of information that you almost never want end users to see. Most permissions that protect resources within .NET and SharePoint have already been defined for you and these permissions have attributes that provide a method of controlling access to the resource at a fairly granular level.


Code Access Security in SharePoint 2003


There are two permission classes provided by SharePoint 2003, which protect separate resources within the product. Although there are only two permissions provided, use of their attributes provides a fine-grained ability to secure SharePoint from a code access viewpoint. These two permissions are the WebPartPermission and the SharePointPermission .


WebPartPermission


The WebPartPermission class governs access rights to web part resources. This permission class currently only handles web part to web part communication. In order for a web part to communicate information to another connected web part, the assembly or assemblies of the web parts must have been granted the WebPartPermission , either with the Connections attribute set to True, or the Unrestricted attribute set to True (enabling all rights for the permission class).


A call to the web part’s RegisterInterface() method causes the WebPartPermission demand to be made on the code. The demand specifically requires the attribute Connections to be True. The RegisterInterface() method of the web part class is used to register a web parts interface, so that it can participate in web part to web part communication.



RegisterInterface(InterfaceName, InterfaceType, MaxConnections,
     RunAtOptions, InterfaceObject, InterfaceClientReference,
     MenuLabel, Description);


If your assembly has not been granted the WebPartPermission with Connections=True , when a call is made to the RegisterInterface() method, the runtime will throw a security exception, similar to that shown below.



Request for the permission of type 
Microsoft.SharePoint.Security.WebPartPermission, Microsoft.SharePoint.Security,
Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce11e9429c failed.


In the UnprivilegedAssembly project the two web parts UnprivilegedConsumerWebPart and UnprivilegedProviderWebPart attempt to connect to each other and therefore are required to have the WebPartPermission with the attribute Connections set to True . Since these web parts are in the UnpriviliedgedAssembly and the custom CAS policy has been defined to not grant the WebPartPermission to it, a WebPartPermission exception is thrown by the .NET runtime.


SharePointPermission


The SharePointPermission class governs access rights to resources used within Windows SharePoint Services. These resources are controlled by the attributes ObjectModel and UnsafeSaveOnGet .


A SharePointPermission demand is made on code whenever you attempt to access the SharePoint object model. For example, there might be a request to get a reference to the current site context. When a demand is made in this situation the code will be required to have been granted the SharePointPermission with the attribute ObjectModel=True .



// Attempt to get a reference to the current web context
   SPWeb currentWeb = SPControl.GetContextWeb(HttpContext.Current);


A SharePointPermission demand can also occur when you attempt to save data from an HTTP-GET request. This demand is specifically asking for the SharePointPermission with the attribute UnsafeSaveOnGet=True . An example of when this demand will occur is when you attempt to save information into the Property Bag of the website that your web part is currently installed on. The demand will occur in the code example below at the commented line.



// Add a key / value entry to the property bag of the current SPWeb
currentWeb.AllowUnsafeUpdates = true; //this demands the SharePointPermission
currentWeb.Properties.Add("myKey", "myValue");
currentWeb.Properties.Update();


In the solution both the web parts, PrivilegedWebPart and UnprivilegedWebPart attempt to access the SharePoint object model and save changes on an HTTP-GET. The difference between the two is that the custom policy file grants the required SharePointPermission (with ObjectModel=True and UnsafeSaveOnGet=True ), to the PrivilegedAssembly and not the UnprivilegedAssembly .


Trust Levels within SharePoint 2003


There are five default security policy files provided by the .NET framework with which you can apply a level of assembly trust and its associated set of permissions for a virtual server. These trust levels of Full , High , Medium , Low , and Minimal , are mutually exclusive and are applied by setting the trust level within the web.config file that resides in the root folder of the web application’s virtual directory. When extending a virtual server with Windows SharePoint Services, two additional trust levels are provided. These are WSS_Minimal and WSS_Medium that extend the default ASP.NET trust level policies of Minimal and Medium respectively. In addition to the permissions defined in the ASP.NET policies, WSS_Minimal and WSS_Medium also grant the WebPartPermission and SharePointPermission ( WSS_Medium only) to assemblies in allowable situations defined by the policy.


It must be noted that there is no provision provided in these out-of-the-box policies for the SharePointPermission , with the attribute UnsafeSaveOnGet set to True. In order to grant this permission to your assembly, you should implement a custom security policy.


You can change the trust level of the assemblies on your virtual server that has SharePoint installed by specifying the level of trust in the trust element in the web.config file. Figure 2 shows situation with the current level of trust for the virtual server is WSS_Minimal .


Note: you must reset IIS after changing the trust level of a virtual server. This can be accomplished by clicking on Start → Run and typing iisreset in the open textbox and clicking on the Ok button. For the sample solution, none of these trust settings are used, and a custom trust level is set. Creating a custom CAS policy file that is tailored to your individual requirements will ensure you target your CAS policy to your exact requirements.


Implementing your own Custom Trust Level


The way to implement your own security policy is to copy an existing CAS policy file and then modify your copy. For obvious reasons it’s not recommended to change any of the existing policy files without taking a backup of the original policy first. You can copy any policy file including wss_minimaltrust.config and wss_mediumtrust.config to use as the basis for your changes, although I would recommend using the WSS_Minimal . These two policy files can be found in the following directory on your server:



<drive>:Program FilesCommon FilesMicrosoft Shared
   web server extensions60config


It is recommended that you save your custom policy file in the same folder as wss_minimaltrust.config and wss_mediumtrust.config ; In the example I named my copy wss_customtrust.config . You will want to create a PermissionSet , containing permissions that which are granted when an assembly is matched to a MembershipCondition . This is discussed in detail below in the Defining a Custom Security Policy section.


Once the custom policy has been defined, you can set the virtual server to use it by performing the following actions:


Open the web.config file for the WSS virtual server, locate the securityPolicy section (within the system.web section), and define a new trustLevel element referencing the custom CAS policy ( WSS_Custom.config ).



<trustLevel name="WSS_Custom" policyFile="C:Program FilesCommon 
FilesMicrosoft SharedWeb Server Extensions60configwss_custom.config" />


Now that the custom CAS policy file has been referenced within the config file, you can set the trust level of the WSS virtual server to the custom trustLevel name. To do this locate the trust element (a child of the system.web element) and set the value of the level attribute to WSS_Custom .



<trust level="WSS_Custom" originUrl="" />



Figure 4. WSS Virtual Servers web.config implementing a custom CAS Policy


Once these steps have been completed and the changes saved, open a command window and type in iisreset and press the enter key. This will ensure the IIS Web Server is reset and that you don’t receive any AppDomain related security errors. You could also accomplish this through restarting the service through the Internet Services Manager snap-in.


Before I describe how to set about defining your custom policy, I think it is beneficial to first understand the structure of the CAS policy file and how the runtime applies the policy defined within them. With this in hand, you will then be best able to define the custom CAS policy.


CAS Policy File Structure


The definition of the CAS policy is encompassed with the PolicyLevel element. Within it there are 3 main sections:


  1. SecurityClasses

  2. NamedPermissionSets

  3. CodeGroups

These three sections are indicated in Figure 5which shows the sections defined in a file located at <drive>:Program FilesCommon FilesMicrosoft Sharedweb server extensions60config .



Figure 5. CAS policy file structure


SecurityClasses


This section of the CAS policy is used to reference any permission class that will be used within the policy. It is very important to correctly reference any assemblies that define permission classes used in the policy. If the permission class assembly is not referenced correctly, but is applied within a named permission set, then no assemblies will be granted the permission, even if the CAS policy would grant it.


NamedPermissionSets


This section of the policy file defines one or more sets of permissions that are given a unique name within the policy file. Each PermissionSet contains one or more permissions, defined by the IPermission child element. Permissions can be defined in none, some, or all of the PermissionSet s, with attributes enabling the setting of specific resource access rights.


By using these attributes the developer can easily grant or revoke access to individual aspects of the protected resource. As shown in Figure 6 the WebPartPermission ‘s Connections value could easily be set to False and therefore not allow the web parts to communicate between each other for the specific NamedPermissionSet .


All IPermission s and their associated attribute settings contained within the PermissionSet are granted to an assembly when matched to a given code group.



Figure 6. Named Permission Sets


CodeGroups


This is the section of the security policy file ties all the other sections together. The runtime uses the defined CodeGroup s to logically group code that matches a specified membership condition. Membership conditions define whether an assembly is to be associated with a given CodeGroup . When a membership condition match is made, the assembly becomes a member of that CodeGroup and the NamedPermissionSet is then associated with the assembly and therefore gains the permissions within it. Note that an assembly can be a member of more than one code group. In matching an assembly to a CodeGroup the runtime starts at the root CodeGroup element at the top of the section (shown in Figure 7) and works its way down the code group tree. For each CodeGroup element defined, the runtime assesses whether the membership condition for it matches the assembly.



Figure 7. Hierarchical application of Code Groups


The CodeGroup section structure contains one root CodeGroup element which in turn contains child CodeGroup elements. These child elements can contain their own child CodeGroup elements as well. If a CodeGroup is defined with a class of UnionCodeGroup then if matches are made in the multiple children elements (if present), the permissions assigned to the assembly are the union of the permissions defined for the associated NamedPermissionSet s.


Membership Conditions


As defined previously, each CodeGroup has a membership condition defined for it. This provides the runtime with the ability to match an assembly’s evidence to the CodeGroup itself. Once a match is made the NamedPermissionSet for the CodeGroup is associated with the assembly.


Membership conditions come in eight different types and specify different characteristics of evidence that an assembly must match in order to meet its membership condition. Both location and publisher evidence types are provided by membership condition classes. Therefore when specifying a match condition you are able to match on location evidence such as the site ( http://<site name> ), installation directory, Url or the zone that the assembly resides in. Publisher evidence can also be used as a match condition including the software publisher, cryptographic hash, or the strong name of the assembly.


There are eight types of membership condition that you can use to match assemblies to a given code group. These are listed in the following tables:
















Name:All code
Type:AllMembershipCondition
Description:Represents a membership condition that matches all code. Since, it represents all code no specific match value is required.
Example:<IMembershipCondition class="AllMembershipCondition" version="1" />




















Name:Application directory
Type:ApplicationDirectoryMembershipCondition
Description:The application’s installation directory, again no specific match condition is required.
Example:<IMembershipCondition class="ApplicationDirectoryMembershipCondition"
version="1" /> 

















Name:Cryptographic hash
Type:HashMembershipCondition
Description:A Cryptographic hash, including MD5 and SHA1.
Example: <IMembershipCondition class="HashMembershipCondition" version="1" HashValue= "A3A5547DF2DDB25F46EE01FA167F23F0" HashAlgorithm= "System.Security.Cryptography.MD5CryptoServiceProvider" />

















Name:Software publisher
Type:PublisherMembershipCondition
Description:The public key of a valid Authenticode signature.
Example:<IMembershipCondition class="PublisherMembershipCondition" version="1" X509Certificate="3082048E3082 "/>

















Name:Site membership
Type:SiteMembershipCondition
Description:The HTTP, HTTPS, and FTP site from which the code originates. Only the sites name is relevant and not the subdirectories of the site. Use of the wildcard * is available as a prefix, therefore in the following example below, you could have Site="*.asptoday.com".
Example:<IMembershipCondition class="SiteMembershipCondition" version="1" Site="http://www.asptoday.com" />

















Name:Strong name
Type:StrongNameMembershipCondition
Description:A cryptographically strong signature.
Example: <IMembershipCondition class="StrongNameMembershipCondition" version="1" PublicKeyBlob="00000000000000000400000000000000" />

















Name:URL
Type:UrlMembershipCondition
Description:The URL where the code originates. The wildcard , can be used as a suffix to the supplied condition: http://site/app/.
Example: <IMembershipCondition class="UrlMembershipCondition" version="1" Url="$AppDirUrl$/Bin/PrivilegedAssembly.dll" />

















Name:Zone
Type:ZoneMembershipCondition
Description:The zone where the code originates.
Example:<Imembershipcondition class="ZoneMembershipCondition" version="1" Zone="MyComputer" />



As shown in the UrlMembershipCondition type above, you can use a substitution parameter to specify the initial directory location to be used for matching.
















ParameterRepresents
$AppDirUrl$The virtual root directory of the application. In the case of a default Windows SharePoint Services installation, then $AppDirUrl$, would be mapped to virtual directory for the root site, C:inetpubwwwroot
$CodeGen$The directory where dynamically generated assemblies are contained, and allows permissions to be applied to dynamically generated assemblies.
$Gac$Any assembly that is installed in the GAC.



Defining a Custom Security Policy


This section will walk you through step by step in creating your own custom security policy.


  1. Open your custom CAS policy file that was created previously.

  2. Ensure the references to the permissions that your policy will use are defined in the SecurityClass section.

Example security class reference definition for the WebPartPermission:



<SecurityClass Name="WebPartPermission" 
Description="Microsoft.SharePoint.Security.WebPartPermission,
Microsoft.SharePoint.Security, Version=11.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c"/>


Example security class reference definition for the SharePointPermission :



<SecurityClass Name="SharePointPermission" 
Description="Microsoft.SharePoint.Security.SharePointPermission,
Microsoft.SharePoint.Security, Version=11.0.0.0, Culture=neutral,
PublicKeyToken=71e9bce111e9429c"/>


Next you should define the custom NamedPermissionSet . To do you need to insert a new PermissionSet element similar to that shown below directly after the closing element of the PermissionSet with the Name of ASP.NET.



<PermissionSet class="NamedPermissionSet" version="1" Name="CustomSet">
</PermissionSet>


Now define any permission (as child IPermission elements) that you would like to be granted to assemblies when this NamedPermissionSet is being applied. The PermissionSet should now resemble something like the following, depending on your requirements. Set the attributes required for each IPermission to provide the specific granular access required.



<PermissionSet class="NamedPermissionSet" version="1" Name="CustomSet">
  <IPermission class="AspNetHostingPermission" version="1" Level="Minimal" />
  <IPermission class="SecurityPermission" version="1" Flags="Execution" />
  <IPermission class="WebPartPermission" version="1" Connections="True" />
</PermissionSet>


In order to have the CAS apply the NamedPermissionSet with its associated permissions to assemblies that the policy is applied to, you must define a CodeGroup that will be matched to the assemblies in specific membership conditions. As previously noted, the application of the CodeGroup sections is hierarchical, and since you will be implementing a CodeGroup that would have otherwise been matched to the ASP.NET NamedPermissionSet, you need to insert your custom CodeGroup before the ASP.NET one. See the example below:



<!— … —>
<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="SharePointPermission"> <IMembershipCondition class="UrlMembershipCondition" version="1" Url="$AppDirUrl$/Bin/PrivilegedAssembly.dll" />
</CodeGroup>
<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="ASP.Net"> <IMembershipCondition class="UrlMembershipCondition" version="1" Url="$AppDirUrl$/*" />
</CodeGroup>
<!— … —>


For your CodeGroup define a membership condition that will be used to match the defined permission set name of your CodeGroup to the NamedPermissionSet that you defined earlier.


Save your changes and adjust the trust level of your virtual server to that of your newly created custom policy trust level.


Reset the web service (perform an iisreset ).


Conclusion


In this areticle I’ve shown you how to implement CAS Security within a SharePoint environment. To do this, it is important to understand both how the runtime applies CAS and what permissions are used by SharePoint. The benefit is that you will be able to allow code to run when required, but simultaneously stop possibly malicious code from accessing protected resources.


I strongly recommend implementing your own custom CAS policy, tailored to your individual requirements, when using SharePoint. This custom policy can be based off any of the predefined ASP.NET policy files and can utilize any of the ASP.NET Permissions, as well as the two SharePoint Permissions, WebPartPermission and SharePointPermission . The custom policy can then be set as a given level of trust for your Sharepoint-enabled virtual server.

Founders at Work

Commenting is closed for this article.