In Windows, there are two types of security mechanisms: Role based Security and Code Access Security. Role based security is easy to understand. Code Access Security(CAS) is to prevent “Bad” module from doing any damage. A module is “Bad” if it does not just do what it claims to do. For example, you run a module downloaded from internet to display a nice screen saver. However, although the module displays the screen saver, it also silently sends your local files to a remote location. In this case, the module does not just do what supposed to do.
How does CAS prevent “Bad” module from doing any damage? It is achieve by two mechanisms working together.
1. Configure CAS policy so the “Bad” module won’t have the CAS permission to do damage such as sending files to a remote location.
2. The code of sending file to a remote location must use CAS security Demand to demand the calling module to have the CAS permission. In case of sending files to a remote location. “WebRequest” CAS permission is demanded. Without the security demanding, configuring CAS policy is useless since CAS security enforcement typically starts with CAS permission demanding and then checks the security policy to see if the demanded permission is granted to the calling module.
While developing CAS strategy, in addition to configure CAS security policy, it is important to use the second mechanism so the code you wrote won’t be used by “Bad” module to cause any damage.
In SharePoint, it is a best practice to deploy your Dlls to the bin directory instead of GAC and configure minimum CAS permissions for the Dlls through CAS policy files. The tutorial will guide your through how to do it. The tutorial will use a couple of simple custom web parts, deploy them into the bin directory and use them in sharepoint content pages.
Lab 1: Deploy and use the first web part in SharePoint
Step 1: Develop DummyWebPart, build a Dll (Dummy.dll), copy dummy.dll to the SharePoint’s Bin directory
The source code of the first web part DummyWebpart is as the following
namespace Dummy
{ [ToolboxData("<{0}:DummyWebPart runat=server></{0}:DummyWebPart>")]public class DummyWebPart : WebPart
{protected override void RenderContents(HtmlTextWriter output)
{ output.Write("Hello World");}
}
}
<SafeControls>
......
<SafeControl Assembly="Dummy" Namespace="Dummy" TypeName="*" Safe="True" />
......
</SafeControls>
<%@ Page Language="C#" %><%@ Register assembly="Dummy" namespace="Dummy" tagprefix="Dummy" %><html dir="ltr">
<body>
<form id="form1" runat="server">
<Dummy:DummyWebPart ID="DummyWebPart1" runat="server"/>
</form>
</body>
</html>
Now, open Dummy.aspx in the SharePoint site in a browser. It just works without any trouble
Lab 2: Deploy and use the second web part,DummySPWebPart, in SharePoint, which will cause Code Access Security Exception.
Step 1: Develop DummySPWebPart, build a Dll (SPDummy.dll), copy the SPDummy.dll to Bin directory
The source code of the second web part DummySPWepart is as the following
namespace SPDummy
{ [ToolboxData("<{0}:DummySPWebPart runat=server></{0}:DummySPWebPart>")]public class DummySPWebPart : WebPart
{protected override void RenderContents(HtmlTextWriter output)
{ output.Write(string.Format("root web title is {0}",SPContext.Current.Site.RootWeb.Title));}
}
}
<SafeControls>
......
<SafeControl Assembly="SPDummy" Namespace="SpDummy" TypeName="*" Safe="True" />
......
</SafeControls>
<%@ Page Language="C#" %><%@ Register assembly="SPDummy" namespace="SPDummy" tagprefix="SPDummy" %><html dir="ltr">
<body>
<form id="form1" runat="server">
<SPDummy:DummySPWebPart runat="server"/>
</form>
</body>
</html>
The exception thrown is caused by invoking SPContext.Current.Site.RootWeb.Title, which requests for the CAS permission of type 'Microsoft.SharePoint.Security.SharePointPermission”. However, the current security policy does not grant the SPDummy.dll the CAS permission. In Lab 3, we will grant the CAS “SharePointPermission” to SPDummy.dll by editing CAS security policy.
Lab 3: Step by step guide on editing CAS
Step 1: Create a custom policy file wss_custom.config by copying the out-of-box policy file
a. Open directory “C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\CONFIG”. The directory contains the out-of-box policy files defining Wss_Medium and Wss_Minimal trust levels of SharePoint.
b. Make a copy wss_minimaltrust.config in the same directory and rename it to wss_custom.config.
Step 2: Refer to the “wss_custom.config” policy file from the web.config
a. Add a new trustLevel entry to the web.config. The trustLevel points to the new policy file wss_custom.config your created in step 1.
<securityPolicy>
......
<trustLevel name="WSS_Custom" policyFile="C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\config\wss_custom.config" />
</securityPolicy>
b. Change <trust level="WSS_Minimal" originUrl="" /> to <trust level="WSS_Custom" originUrl="" />
<trust level="WSS_Custom" originUrl="" />
After the first two steps, your sharepoint web application starts to use the custom poplicy file, wss_custom.config. Rememeber the “wss_custom.config” is just a copy of the out-of-box “wss_minimaltrust.config”. Now, we need to modify the file.
Step 3: Modify the “wss_custom.config” policy file so the Dlls in bin directory of the sharepoint web application have CAS SharepointPermission. You just need to add one IPermission element to an existing permissionset element as the follows:
<PermissionSet class="NamedPermissionSet" version="1" Name="SPRestricted">
<!-- add the following element --><IPermission
class="Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
version="1"
ObjectModel="True"
/><!-- end of the element --></PermissionSet>
Save your change and open SPDummy.aspx. Now, it works without any exception!
How did I figure out to add the SharePointPermission to the SPRestricted permissionset? First, the exception message already tells you that we need to add SharePointPermission. So, you need to add IPermission element with SharePointPermission as its class.You can just use Version=”1”. The real catch is how to figure out adding ObjectModel=”true”. Go to http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.security.sharepointpermission_properties.aspx. You notice the SharePointPermission is a .NET class with three public properties. ObjectModel is one of them. What I did was to try each property and assign them to true. After a few tries, ObjectModel=”True” is the only one that really matters. There is no silver bullet here.
You should also ask why I choose to add it to SPRestricted PermissionSet. This requires a basic understanding of the structure of the CAS Policy file. Do a search on “SPRestricted” in the WSS_custom.config file. You will find the following element:
<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="SPRestricted">
<IMembershipCondition
class="UrlMembershipCondition"
version="1"
Url="$AppDirUrl$/*"
/></CodeGroup>
This is the code group that dictates the CAS permission for all the Dlls under "$AppDirUrl$ directory, which includes the bin directory. This code group uses “SPRestricted” permission set. That is why to add the IPermission element to the “SPRestricted” permissionset.
NOTE, the tutorial explains the CAS security in SharePoint. In real world, you should use Windows SharePoint Packaging (WSP) to deploy the changes to CAS policy. This tutorial tells you what happens behind the scene. I will write another blog regarding the deployment in near future.
Thanks a lot on this one. I have been Googling my brains out for days to resolve this problem in a web part I am creating. This completely resolved this part of my troubles.
ReplyDeleteWish I new about the calcperm tool when I started created a cas policy.
ReplyDeleteAlso spent ages trying to trace a bug in my cas policy turned out it was an lower case n in my Name attribute tag