6. Working with Security Policies
Policies are an important part of working with
security in the .NET Framework. The policy defines the security
settings for one or more applications. When the CLR runs an
application, it checks the application against the security policies
and interacts with it appropriately. The .NET Framework actually
supports four levels of policies, as shown in Table 1. (The version portion of the Configuration File Location entry is the version number of the .NET Framework that you're using.)
Table 1. Policy Levels Supported by the .NET Framework
LEVEL | CONFIGURATION FILE LOCATION | DESCRIPTION |
---|
Enterprise | %Systemroot%\Microsoft.NET\Framework\version\Config\enterprise.config | Defines
policies that affect the organization as a whole. These policies are
normally set as part of an Active Directory tree or forest. |
Machine | %Systemroot%\Microsoft.NET\Framework\version\Config\security.config | Defines policies that affect all the users on a particular machine. This level has been eliminated in the .NET Framework 4. |
User | %UserProfile%\Application Data\Microsoft\CLR Security Config\version\security.config | Defines policies that affect all the applications run by a particular machine user. |
AppDomain | Normally, the application directory | Defines
policies for a specific application. This level isn't enabled by
default; you must create these policies as part of defining the
application. |
You configure the enterprise, machine, and user policies using the Code Access Security Policy (CASPol.EXE) utility found in the %Systemroot%\Microsoft.NET\Framework\ version \
directory of your system (where version is the version number of the
.NET Framework you're using).
One of the more interesting policy levels from a
developer perspective is the AppDomain. The AppDomain policies are
completely under developer control and make it possible for you to
create a completely secure application without any administrator
intervention. The following sections describe how to create an
AppDomain application.
6.1. Configuring the AppDomain Example
The AppDomain example consists of two applications:
Main (the starting application) and Called (the application started
with the AppDomain in place). The following steps help you create this
solution:
Choose File => New => Project. You'll see the New Project dialog box.
Highlight the Windows Forms Application template.
Type Main in the Name field and AppDomain in the Solution field, as shown in Figure 4. Click OK. Visual Studio creates the AppDomain solution and Main project for you.
Right-click the solution entry in Solution Explorer and choose Add => Add Project from the Context menu. You'll see the Add New Project dialog box shown in Figure 5.
Type Called in the Name field and click OK. Visual Studio adds the secondary project to your solution.
Right-click
the Called project in Solution Explorer and choose Properties from the
Context menu. You'll see the project's Properties window.
Select the Build tab. You'll see the build options for the project.
Select the Debug option in the Configuration field.
Type ..\Main\bin\Debug\ in the Output Path field. Your properties window should look like the one shown in Figure 6.
Select the Release option in the Configuration field.
Type ..\Main\bin\Release\ in the Output Path field. Visual Studio will now output the Called project's executable to the Main project's output directory.
The two applications will have one form each. The Main project will have two buttons on its form, one labeled Default (btnDefault), which performs a task using the default security settings, and the other labeled AppDomain (btnAppDomain),
which performs a task using special security settings using the Called
application.
using System.IO;
using System.Security;
using System.Security.Policy;
The Called application has a single button, Secure (btnSecure),
which performs a task using the security settings imposed by the
AppDomain created by Main. The Called application requires the
following using statements:
using System.IO;
using System.Security;
6.2. Creating the AppDomain Example Code
The idea behind this example is to create a sandbox
in which another application operates. The standard security gives full
access to all system resources, but you may not trust the code in an
application, so you place it in an environment where it can do little
harm. In this case, the example shows that full access allows the Main
application to open a file, but the LocalIntranet policy restricts the
Called application so it can't open the file. This example relies on
the same file opening code shown for the UseSecurity() method in Listing 1 for both btnDefault_Click() and btnSecure_Click(). Listing 2 shows the special code used to create a sandbox in which the Called application executes.
Example 2. Creating an AppDomain to control file access
private void btnAppDomain_Click(object sender, EventArgs e) { // Define a new AppDomain policy. PolicyLevel AppPolicy = PolicyLevel.CreateAppDomainLevel();
// Define a membership condition for the policy. AllMembershipCondition Members = new AllMembershipCondition();
// Create a permission set for the Called application. PermissionSet CalledPermissions = new PermissionSet(AppPolicy.GetNamedPermissionSet("LocalIntranet"));
// Define a policy statement based on the permssions for // the Called application. PolicyStatement CalledPolicy = new PolicyStatement(CalledPermissions);
// Create a code group for the Called application policy. The hierarchy // is AppPolicy->AllCodeGroup->CalledPolicy. CodeGroup AllCodeGroup = new UnionCodeGroup(Members, CalledPolicy);
// Assign the code group to the application policy created earlier. AppPolicy.RootCodeGroup = AllCodeGroup;
// Define an application domain that includes the policies for the
// Called application. AppDomain CalledDomain = System.AppDomain.CreateDomain("CustomDomain");
// Assign the domain policy to the new domain. CalledDomain.SetAppDomainPolicy(AppPolicy);
// Use the domain to execute the Called application with the // appropriate rights. CalledDomain.ExecuteAssembly(Application.StartupPath + @"\Called.EXE"); }
|
You'll remember from previous discussions that there
are four policy levels: Enterprise, Machine, User, and AppDomain. The
code begins by creating an AppDomain policy level, AppPolicy, by calling PolicyLevel.CreateAppDomainLevel().
A policy level is worthless unless it has members
and assigns permissions to those members. The next step in the code is
to create members using an AllMembershipCondition object, Members.
Essentially, this membership condition states that all the code that
runs in the AppDomain policy is affected by the conditions of the
membership — the permissions you assign to the policy. Therefore, the
next step is to state the permission for the policy by creating a PermissionSet object, CalledPermissions. You can assign any permissions you want to the policy, but in this case, the code calls AppPolicy.GetNamedPermissionSet()
to obtain the default permissions assigned to the LocalIntranet zone.
This permission, and any other permissions you decide you want to add,
are placed within a PolicyStatement object, CalledPolicy.
At this point, you have a policy level, a membership
condition, and a set of permissions enclosed in a policy statement. The
next step is to create a code group to contain the membership condition
and its associated permissions, and then to assign the code group to
the policy level. The code begins this step by creating a CodeGroup object, AllCodeGroup, using the UnionCodeGroup() constructor with Members and CalledPolicy as arguments. The code then assigns AllCodeGroup to the AppPolicy.RootCodeGroup property. You now have a complete AppDomain policy to work with.
The code needs to create a domain to implement the policy at this point, so it creates an AppDomain object, CalledDomain, using System.AppDomain.CreateDomain() and gives it a name of CustomDomain. A call to CalledDomain.SetAppDomainPolicy() applies AppPolicy to the AppDomain. The code ends with a call to CalledDomain.ExecuteAssembly() with the location of Called.EXE.
When you run this example, you can click Default to see that the Main application truly can access Temp.TXT
without any problem. The example displays the expected success message.
Click AppDomain and you'll see the Called application form appear.
Click Secure and you'll see an error message (see Figure 3) — the Called application can't access Temp.TXT
even though it uses the same code as the Main application. The reason
is that the Called application executes within the LocalIntranet zone
and lacks the required permission.