Good news and better news for deploying Code Access Security policies within
SharePoint v3... :)
First...
A big thank you ... no, make that a
huge thank you ... goes out to
everyone that voiced their
opinions on this blog, at TechReady, PDC, etc!! Your comments about the
difficulty of deploying code access security policies with your WebPart
assemblies helped shape a feature that was long overdue within WSS.
Now for the good news...
WPPackager is going away. Bad new... sort of.
However, there is a silver lining. The core
functionality of deploying code access security policies has been integrated
into v3's Solution deployment engine.
And the even better news...
You will be able to deploy CAS policies starting
with Beta 2 TR.
That's right! The development community will have a way of
deploying CAS policies natively within SharePoint. You will no longer be
required to rely on a (buggy) tool. Oh Yeah!!!
Here's a quick rundown of the CAS deployment capability in v3...
- It's very similar to the protocols established by wppackager. If
you haven't read the wppackager
documentation in awhile, it might be helpful to briefly review them.
- It's just another deployment feature of the Solutions architecture.
If you haven't considered deploying your WebPart assemblies via Solutions,
now is the time to reconsider. :)
- Unlike wppackager, the new CAS Solutions deployment
model will allow you to specify multiple policies within a single Solution
package.
- You can associate policies to either signed or unsigned assemblies.
Although similar functionality existed with wppackager, it was not widely
known. Depending on how you form your Solution manifest, the resulting CodeGroups
within the trust file will utilize either
StrongNameMembershipCondition or
UrlMembershipCondition classes.
What does the schema look like?
A quick example is in order ... note the yellow highlighted section ...
<!--Solution
created by InstallAssemblies.exe on 8/15/2006 7:03:53 PM-->
<Assemblies>
<Assembly Location="MyCustomWebParts.dll" DeploymentTarget="WebApplication">
<ClassResources>
<ClassResource Location="MyCustomWebParts.pdb"
/>
<ClassResource Location="en\two\generic.txt" />
<ClassResource Location="de\two\specific.txt" />
<ClassResource Location="header.html" />
</ClassResources>
<SafeControls>
<SafeControl Assembly="MyCustomWebParts,
version=1.0.0.0, Culture=neutral, PublicKeyToken=636addc00401d15b" Namespace="Example.CodeAccessSecurity" TypeName="*" />
</SafeControls>
</Assembly>
</Assemblies>
<DwpFiles>
<DwpFile Location="StandardAspNetWebPart.webpart" />
<DwpFile Location="HybridWSSWebPart.webpart" />
<DwpFile Location="StandardWSSWebPart.dwp" />
</DwpFiles>
<CodeAccessSecurity>
<PolicyItem>
<PermissionSet class="NamedPermissionSet"
version="1" Description="Permission
set for custom test WebParts">
<IPermission class="AspNetHostingPermission"
version="1" Level="Minimal" />
<IPermission class="SecurityPermission"
version="1" Flags="Execution" />
<IPermission class="Microsoft.SharePoint.Security.SharePointPermission,
Microsoft.SharePoint.Security, version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
version="1" ObjectModel="True" />
<IPermission class="System.Net.WebPermission,
System, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1">
<ConnectAccess>
<URI uri="https?://.*" />
</ConnectAccess>
</IPermission>
<IPermission class="System.Security.Permissions.SecurityPermission,
mscorlib, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1" Flags="ControlThread,
UnmanagedCode" />
<IPermission class="System.Security.Permissions.EnvironmentPermission,
mscorlib, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1" Read="UserName"
/>
</PermissionSet>
<Assemblies>
<Assembly
PublicKeyBlob="hexadecimalValueTruncatedForClarity"
/>
</Assemblies>
</PolicyItem>
</CodeAccessSecurity>
</Solution>
Schema rules:
- There can only be 1 CodeAccessSecurity node per Solution manifest.
- There can be any number of PolicyItem nodes.
- Each PolicyItem node can contain only 1 PermissionSer and Assemblies
node.
- Each PermissionSet node can contain any number of IPermission nodes
- Schema of IPermission nodes are defined by the .NET framework
- Each Assemblies node can contain any number of Assembly nodes.
- The CodeAccessSecurity/PolicyItem/Assemblies/Assembly node is different
than the Solution/Assemblies/Assembly node.
- The Assembly node can contain any of the following attributes:
- Name
- Version
- PublicKeyBlob
Commands to add and deploy your Solution which
contains a code access security policy...
Add: stsadm.exe -o addSolution -filename
"InstallAssemblies_Solution_2052225630.cab"
Deploy: stsadm.exe -o deploySolution -name
"InstallAssemblies_Solution_2052225630.cab" -allcontenturls -local -force
-allowCasPolicies
Note that stsadm.exe will require the use of the -allowCasPolicies flag for
Solution packages that contain CAS policies.
What does the trust file look like once the
Solution has been deployed?
If you were to use the manifest file from above, the policy file will look
like the following file... again note the yellow highlighted sections...
<configuration>
<mscorlib>
<security>
<policy>
<PolicyLevel version="1">
<SecurityClasses>
<SecurityClass Name="AllMembershipCondition" Description="System.Security.Policy.AllMembershipCondition,
mscorlib, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
/>
<SecurityClass Name="AspNetHostingPermission" Description="System.Web.AspNetHostingPermission,
System, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<SecurityClass Name="FirstMatchCodeGroup" Description="System.Security.Policy.FirstMatchCodeGroup,
mscorlib, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<SecurityClass Name="NamedPermissionSet" Description="System.Security.NamedPermissionSet" />
<SecurityClass Name="SecurityPermission" Description="System.Security.Permissions.SecurityPermission,
mscorlib, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<SecurityClass Name="StrongNameMembershipCondition" Description="System.Security.Policy.StrongNameMembershipCondition,
mscorlib, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<SecurityClass Name="UnionCodeGroup" Description="System.Security.Policy.UnionCodeGroup,
mscorlib, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<SecurityClass Name="UrlMembershipCondition" Description="System.Security.Policy.UrlMembershipCondition,
mscorlib, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<SecurityClass Name="WebPartPermission" Description="Microsoft.SharePoint.Security.WebPartPermission,
Microsoft.SharePoint.Security, version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
<SecurityClass Name="ZoneMembershipCondition" Description="System.Security.Policy.ZoneMembershipCondition,
mscorlib, version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</SecurityClasses>
<
NamedPermissionSets>
<PermissionSet class="NamedPermissionSet"
version="1" Description="Permission
set for custom test WebParts" Name="installassemblies_solution_2052225630.cab-b172f003-d6c7-3e13-f737-a5d84a02e3e5-1">
<IPermission class="AspNetHostingPermission"
version="1" Level="Minimal" />
<IPermission class="SecurityPermission"
version="1" Flags="Execution" />
<IPermission class="Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
version="1" ObjectModel="True" />
<IPermission class="System.Net.WebPermission, System,
version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1">
<ConnectAccess>
<URI uri="https?://.*" />
</ConnectAccess>
</IPermission>
<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib,
version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1" Flags="ControlThread, UnmanagedCode" />
<IPermission class="System.Security.Permissions.EnvironmentPermission, mscorlib,
version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1" Read="UserName" />
</PermissionSet>
<PermissionSet class="NamedPermissionSet"
version="1" Unrestricted="true" Name="FullTrust" Description="Allows full access to all resources" />
<PermissionSet class="NamedPermissionSet"
version="1" Name="Nothing" Description="Denies all resources, including the right to execute" />
<PermissionSet class="NamedPermissionSet"
version="1" Name="SPRestricted">
<IPermission class="AspNetHostingPermission"
version="1" Level="Minimal" />
<IPermission class="SecurityPermission"
version="1" Flags="Execution" />
<IPermission class="WebPartPermission"
version="1" Connections="True" />
</PermissionSet>
</NamedPermissionSets>
<CodeGroup class="FirstMatchCodeGroup"
version="1" PermissionSetName="Nothing">
<IMembershipCondition class="AllMembershipCondition"
version="1" />
<CodeGroup class="UnionCodeGroup"
version="1" PermissionSetName="installassemblies_solution_2052225630.cab-b172f003-d6c7-3e13-f737-a5d84a02e3e5-1">
<IMembershipCondition
version="1" class="StrongNameMembershipCondition"
PublicKeyBlob="hexadecimalValueTruncatedForClarity"
/>
</CodeGroup>
<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="FullTrust">
<IMembershipCondition class="UrlMembershipCondition"
version="1" Url="$AppDirUrl$/_app_bin/*" />
</CodeGroup>
<CodeGroup class="UnionCodeGroup"
version="1" PermissionSetName="SPRestricted">
<IMembershipCondition class="UrlMembershipCondition"
version="1" Url="$AppDirUrl$/*" />
</CodeGroup>
<CodeGroup class="UnionCodeGroup"
version="1" PermissionSetName="FullTrust">
<IMembershipCondition class="UrlMembershipCondition"
version="1" Url="$CodeGen$/*" />
</CodeGroup>
<CodeGroup class="UnionCodeGroup"
version="1" PermissionSetName="FullTrust">
<IMembershipCondition class="UrlMembershipCondition" Url="$Gac$/*"
version="1" />
</CodeGroup>
<CodeGroup class="UnionCodeGroup"
version="1" PermissionSetName="Nothing">
<IMembershipCondition class="ZoneMembershipCondition"
version="1" Zone="MyComputer" />
<CodeGroup class="UnionCodeGroup"
version="1" PermissionSetName="FullTrust" Name="Microsoft_Strong_Name" Description="This code group grants code signed with the Microsoft strong name full trust. ">
<IMembershipCondition class="StrongNameMembershipCondition"
version="1"
PublicKeyBlob="hexadecimalValueTruncatedForClarity" />
</CodeGroup>
<CodeGroup class="UnionCodeGroup"
version="1" PermissionSetName="FullTrust" Name="Ecma_Strong_Name" Description="This code group grants code signed with the ECMA strong name full trust. ">
<IMembershipCondition class="StrongNameMembershipCondition"
version="1"
PublicKeyBlob="00000000000000000400000000000000" />
</CodeGroup>
</CodeGroup>
</CodeGroup>
</PolicyLevel>
</policy>
</security>
</mscorlib>
</
configuration>
From manifest to trust file... what happened?
- The PermissionSet from the PolicyItem is directly inserted into the
trust file (the first yellow highlighted section). In this example, the PermissionSet
is named "installassemblies_solution_2052225630.cab-b172f003-d6c7-3e13-f737-a5d84a02e3e5-1".
The name is a combination of the installation package ("installassemblies_solution_2052225630.cab") plus the SolutionId
("b172f003-d6c7-3e13-f737-a5d84a02e3e5")
plus the PolicyItem index (in this case there is only 1 PolicyItem).
- For each Assembly associated with a given PolicyItem in the manifest,
one (1) CodeGroup (the second yellow highlighted section) is created. Each
CodeGroup will reference the associated PermissionSet within the PolicyItem.
Additionally, each CodeGroup is inserted in the first position of the parent
CodeGroup container. This ensure the FirstMatchCodeGroup behavior
allows custom policies to be honored before the default WSS permission sets
are applied.
Now let's look at how the CodeGroups are
created based on the data within the manifest file...
As mentioned in the schema rules section above, the Solution\CodeAccessSecurity\Assemblies\Assembly node can contain three attributes: Name, Version and PublicKeyBlob. The
combination of the three attributes determine which Membership class is used.
Name only --> UrlMembershipCondition
Use this format when assemblies have not been signed and deployment will be isolated to the BIN folder.
Manifest xml
<Assembly Name="MyCustomWebParts" />
Resulting CodeGroup
<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="generatedPermissionSetName">
<IMembershipCondition version="1" class="UrlMembershipCondition" Url="$AppDirUrl$/bin/MyCustomWebParts.dll" />
</CodeGroup>
PublicKeyBlob only --> StrongNameMembershipCondition
Use this format when you wish to globally apply a policy to all assemblies with the specified signature.
Manifest xml
<Assembly PublicKeyBlob="hexademical_number" />
Resulting CodeGroup
<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="generatedPermissionSetName">
<IMembershipCondition version="1" class="StrongNameMembershipCondition" PublicKeyBlob="hexidecimalValue" />
</CodeGroup>
PublicKeyBlob + Name --> StrongNameMembershipCondition
Use this format when you wish to isolate a policy to a particular
signed assembly. The policy will apply to all versions.
Manifest xml
<Assembly PublicKeyBlob="hexademical_number" Name="assemblyName" />
Resulting CodeGroup
<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="generatedPermissionSetName">
<IMembershipCondition version="1" class="StrongNameMembershipCondition" PublicKeyBlob="hexidecimalValue" Name="assemblyName" />
</CodeGroup>
PublicKeyBlob + Name + Version --> StrongNameMembershipCondition
Use this format when you wish to isolate a policy to a particular
signed assembly and assembly version.
Manifest xml
<Assembly PublicKeyBlob="hexademical_number" Name="assemblyName" Version="0.0.0.0" />
Resulting CodeGroup
<CodeGroup class="UnionCodeGroup" version="1" PermissionSetName="generatedPermissionSetName">
<IMembershipCondition version="1" class="StrongNameMembershipCondition" PublicKeyBlob="hexidecimalValue" Name="assemblyName" Version="0.0.0.0" />
</CodeGroup>
Finally - reliable, supported deployment of code access security policies
is now available in WSS. :)
-Maurice