Creating a Microsoft Installer File to Manage Security Policies

Creating a Microsoft Installer File to Manage Security Policies

Downloading and running a .NET assembly from the Internet is not an automatic given. Security settings (see Chapter 18) are likely to change from customer to customer, and the default settings will evolve over time as more is understood about customers' basic security needs. If you are providing executable assemblies for download from the Internet, you may need to provide a reliable means for your customers to be able to run those assemblies. You could count on the customers knowing how to manage the security settings for .NET themselves ; but if some actually don't know them, good customers may walk away from your application as a viable solution. As an alternative you could provide written instructions that describe how to manage security settings, or (the best alternative) you could automate the security modifications on the customers' behalf .

In this section we take a look at how to manually and programmatically manage permissions for smart client applications. There is enough information in this section for you to successfully perform the tasks described, but you will need to read Chapter 18 for more general background information on .NET security.

Defining a New Code Group

There are several ways to manage security. You can use the caspol .exe utility to manage code access security policy from the command line or a batch file, or you can use the .NET Framework Configuration utility console snap-in to manage security with a graphical user interface. We will use the .NET Framework Configuration snap-in because it is more convenient .

Suppose that a customer clicks on a link to your executable assembly and instead of the application starting up, the user sees an error message or, worse yet, nothing happens. Most usersincluding mehave a very short fuse when it comes to waiting for content from the Web. If the application doesn't start up and there is no apparent easy remedy, the user is likely to go to the next cool thing on the Web.

As techies we can manage security permissions on our machines, and we should be able to explain them to someone else if the need arises or we need to programmatically modify permissions for our applications. Back to our scenario.

For demonstration purposes, let's say you had problems running the Football game we talked about earlier in the chapter. You click on Football.exe and it doesn't run. You can give it permission to run by following the steps below.

  1. Start the .NET Framework Configuration tool by opening a command prompt, changing the current directory to C:\WINNT\Microsoft.NET\Framework\< version >\ (where version is the version of the .NET Framework whose policy you want to modify), and typing mmc mscorcfg .msc . These steps will open the .NET Framework Configuration snap-in (Figure 10.8). Alternatively, you can open the console by selecting StartControl PanelAdministrative Tools.NET Framework Configuration.

    Figure 10.8. Use the .NET Framework Configuration console to set security permissions for .NET.

    graphics/10fig08.gif

  2. Expand the Runtime Security Policy folder and the Machine node. (This will allow you to set permissions for the workstation.)

  3. Expand the Code Groups node and select New from the All_Code group's context menu. (This option is also available from the Action menu.) This step starts the Code Group wizard (Figure 10.9).

    Figure 10.9. The Code Group wizard permits you to identify a new code group with which to associate permissions.

    graphics/10fig09.gif

  4. Provide a name and description for the code group, using Figure 10.9 as a visual guide. (Because Football.exe comes from Software Conceptions, for the figure I chose a name and description suitable to describe code from Software Conceptions.) Click Next.

  5. Choose a condition type (Figure 10.10). In this example, let's use a specific URL, http://www.softconcepts.com/Football/Football.exe. Select the URL condition and type the precise URL. Be sure to include the moniker ( http:// or ftp:// ) since this is used as part of the membership condition. Although a URL is not the most secure way of identifying the source of code, it suits our purposes for now. Click Next.

    Figure 10.10. Choose the condition that determines membership in the code group, for example, a specific URL.

    graphics/10fig10.gif

  6. Assign a permission set to the code group (Figure 10.11). (On my particular workstation, the Internet group has execute permissions but limits many other permissions. Hence, for the figure I selected Use existing permission set and picked the Internet permission set.) Click Next.

    Figure 10.11. Assign a permission set to your code group.

    graphics/10fig11.gif

  7. Click Finish.

When you are done, you should see the Softconcepts Football child group in the All_Code code group.

Manually setting permissions isn't too difficult to do on an occasional basis; however, many Internet users may not be comfortable setting security permissions or may themselves not have sufficient privileges on their machines to do so. In addition, if you had to manage permissions for a wide variety of applications, it would become tedious to do so manually. We have the option of writing code to manage permissions for us; this approachonce the code has been perfectedis less prone to error and is much faster.

Managing Code Groups and Permissions Programmatically

Support for managing code groups and permissions can be found in the System.Security namespace. The classes in this namespace support performing operations analogous to those we performed in the .NET Framework Configuration tool. All we have to do is convert the operations to method signatures. To summarize, we need to complete the following tasks.

  • Pick a security policy level.

  • Pick a permission set.

  • Create a policy statement, assigning the permissions set to it.

  • Pick the conditions required for membership in that set.

  • Create the code group, adding the membership conditions and policy information to that group.

  • Provide a name and description for that code group.

  • Save everything.

Listing 10.3 contains an example console application that adds a custom code group to the machine policy. The code group is approximately identical to the policy changes we made manually in the preceding section. You can find this console application, SecuritySetupTest.vbproj , as part of Football.sln .

NOTE

When you modify security settings using caspol.exe or the .NET Framework Configuration snap-in, you are modifying text in an XML file. For example, the machine policy is stored in C:\WINNT\Microsoft.NET\Framework\< version >\CONFIG\security.config . If you are feeling brave, you can modify these files directly. It is a good idea to make a backup copy if you modify the policy configuration files directly. However, if you make a mistake, you can delete the security policy files, and the next .NET application to run will write new versions with default information. This will in effect reset your security policy for that level, but it will allow you to get up and going again.

Listing 10.3 Managing Security Policy Programmatically in .NET
 1:  Imports System.Security.Policy 2:  Imports System.Security.Permissions 3:  Imports System.Security           ' SecurityManager 4:  Imports System.ComponentModel     ' RunInstallerAttribute 5:  Imports System.Collections        ' IEnumerator 6: 7:  Public Module Module1 8: 9:    Public Sub Main() 10:     Dim machinePolicy As PolicyLevel = GetMachinePolicyLevel() 11:     If (Not (machinePolicy Is Nothing)) Then 12: 13:       Dim permissions As PermissionSet = _ 14:         New NamedPermissionSet("Internet") 15: 16:       Dim policy As PolicyStatement = _ 17:         New PolicyStatement(permissions) 18: 19:       Dim membership As IMembershipCondition = _ 20:         New UrlMembershipCondition( _ 21:         "http://www.softconcepts.com/Football/Football.exe") 22: 23:       Dim group As CodeGroup = _ 24:         New UnionCodeGroup(membership, policy) 25: 26:       group.Description = "Permissions for Softconcepts Football" 27:       group.Name = "Software Conceptions, Inc." 28:       machinePolicy.RootCodeGroup.AddChild(group) 29:       SecurityManager.SavePolicy() 30: 31:     Else 32:       Debug.WriteLine("Failed to find user policy.") 33:     End If 34: 35:   End Sub 36: 37: 38:   Private Function GetMachinePolicyLevel() As PolicyLevel 39:     Dim policies As IEnumerator = _ 40:       SecurityManager.PolicyHierarchy 41: 42:     While (policies.MoveNext()) 43: 44:       If (CType(policies.Current, _ 45:         PolicyLevel).Label = "Machine") Then 46: 47:         Return CType(policies.Current, PolicyLevel) 48:       End If 49:     End While 50: 51:     Return Nothing 52: 53:   End Function 54: 55: End Module 

Lines 38 through 53 use an enumerator to find the machine policy. There should be an indexer and enumerator on PolicyHierarchy to simplify access. There may not be one to more readily support future policy levels.

The Main subroutine in lines 9 through 35 actually performs the steps to add the code group to the machine policy. Line 10 searches PolicyHierarchy to obtain the correct PolicyLevel object. If the machinePolicy object is found (line 11), we create an instance of the Internet permission set in lines 13 and 14. The permission set is used to create an instance of a PolicyStatement object (lines 16 and 17). Lines 19 through 21 set a membership condition. (The assembly must come from http://www.softconcepts.com/Football/Football.exe.)

Finally, the new code group is created, adding the membership condition and policy to the group, and a name and description are provided. The last step is to save the policy (line 29). When the code has finished running, you should be able to search the security.config file and find the entry for Software Conceptions, Inc.

Writing code to programmatically change policy settings is reliable once the code works correctly. However, this approach won't work for customers who can't run the assembly from the Internet because the policy modification application won't run for the same reason the original assembly didn't run. We have a solution to this problem too.

Managing Permissions by Using an Installer

Microsoft Installer ( .msi ) files are permitted to run from the Internet because they require user interactionthe user acknowledges operations as the installer runs. For this reason we can add security permissions to a .msi file, and a customer can run this .msi file to update the security policy. The actual code for modifying the security policy is almost the same, but we do need to create the .msi project and write the policy modification code as part of an Installer class. I will walk you through the steps of defining the setup project and show the complete listing for the installer. (You can download the complete solution as part of Football.sln , which includes the installer and the setup project.)

Implementing an Installer Library

The System.Configuration.Install.Installer class is the base class for custom installers . We can define a class in a class library project and add the project to a .msi project. The Microsoft Windows Installer will load and run the code in the custom installer. For this mechanism to work we have to inherit from System.Configuration.Install.Installer and apply the RunInstallerAttribute to the custom Installer class. Armed with this information, the Windows Installer will run our custom installer. We can program the custom installer to perform any installation task we might need, including modifying the security policy. Because .msi files are permitted to run from the Internet, this is an ideal way to update a customer's security policy.

Listing 10.4 contains the source code for our custom installer. Note the similarities between the installer and the console application discussed in the preceding subsection (Listing 10.3).

Listing 10.4 Implementing a Custom Installer
 1:  Imports System.Security.Policy 2:  Imports System.Configuration.Install 3:  Imports System.Security.Permissions 4:  Imports System.Security           ' SecurityManager 5:  Imports System.ComponentModel     ' RunInstallerAttribute 6:  Imports System.Collections        ' IEnumerator 7: 8:  <RunInstaller(True)> _ 9:  Public Class Installer1 10:   Inherits System.Configuration.Install.Installer 11: 12:   Public Sub New() 13: 14:     Dim machinePolicy As PolicyLevel = GetMachinePolicyLevel() 15:     If (Not (machinePolicy Is Nothing)) Then 16: 17:       Dim permissions As PermissionSet = _ 18:         New NamedPermissionSet("Internet") 19: 20:       Dim policy As PolicyStatement = _ 21:         New PolicyStatement(permissions) 22: 23:       Dim membership As IMembershipCondition = _ 24:         New UrlMembershipCondition( _ 25:         "http://www.softconcepts.com/Football/Football.exe") 26: 27:       Dim group As CodeGroup = _ 28:         New UnionCodeGroup(membership, policy) 29: 30:       group.Description = "Permissions for Softconcepts Football" 31:       group.Name = "Software Conceptions, Inc." 32:       machinePolicy.RootCodeGroup.AddChild(group) 33:       SecurityManager.SavePolicy() 34: 35:     Else 36:       Debug.WriteLine("Failed to find the machine policy.") 37:     End If 38: 39:   End Sub 40: 41: 42:   Private Function GetMachinePolicyLevel() As PolicyLevel 43:     Dim policies As IEnumerator = _ 44:       SecurityManager.PolicyHierarchy 45: 46:     While (policies.MoveNext()) 47: 48:       If (CType(policies.Current, _ 49:         PolicyLevel).Label = "Machine") Then 50: 51:         Return CType(policies.Current, PolicyLevel) 52:       End If 53:     End While 54: 55:     Return Nothing 56: 57:   End Function 58: 59: End Class 

There is little need to repeat the elaboration of the code in Listing 10.4; it is almost identical to the code in Listing 10.3. The notable differences are that in Listing 10.4 we define public class Installer1 as inheriting from System.Configuration.Install.Installer (line 10), indicating that Installer1 is a custom installer. The RunInstallerAttribute indicates that an installer application should be run during the installation of the assembly containing this custom installer.

Now all we have to do is add SecuritySetup.vbproj , which contains the custom installer, to a setup project and tell the setup project what to do with the library.

Defining the Setup Project

Setup Project templates ship with Visual Studio .NET. (Check your version of Visual Studio .NET to determine whether the Setup Project template ships with your specific version.) We can add a Windows Installer setup project to Football.sln , which also contains SecuritySetup.vbproj , and use this project to manage the security policy modifications on our behalf.

Defining the setup project is a straightforward process. Follow these steps.

  1. With Football.sln open (or your custom solution), select FileAdd ProjectNew Project. This opens the Add New Project dialog.

  2. In the Add New Project dialog, select the Setup and Deployment folder from the Project Types list, and pick the Setup Project template from the list of templates.

  3. Name the template something suitable. (For Football.sln I named the template SetupFootballPermissions.)

  4. Delete the User's Desktop and User's Programs menu folders from File System on Target Machine, leaving just the Application folder. We will install SecuritySetup.dll to the Program Files directory.

  5. Right-click on the Application folder and select AddProject Output. Select the SecuritySetup project as shown in Figure 10.12 (or the project containing your custom installer) and click OK. The resultant setup configuration should look like Figure 10.13.

    Figure 10.12. The SecuritySetup project containing our custom installer.

    graphics/10fig12.gif

    Figure 10.13. The setup configuration after we add the SecuritySetup.dll assembly.

    graphics/10fig13.gif

  6. Next we need to tell the Windows Installer how to treat the SecuritySetup.dll assembly. With the setup project selected in the Solution Explorer, click the ViewEditorCustom Actions menu item. Select the Install folder and pick Add Custom Action from the context menu. The custom action we want to perform is to install the SecuritySetup.dll assembly (see Figure 10.14). (Recall that installing a custom installer will run the installer code.)

    Figure 10.14. The custom install action installs the SecuritySetup.dll assembly, which will run the customer installer code.

    graphics/10fig14.gif

TIP

You can run the Windows Installer from the Solution Explorer by right-clicking on the setup project and selecting Install from the context menu.

At this point we are all set. We can build our entire solution, which includes the SecuritySetup.dll assembly and the SetupFootballPermissions setup project. After we have built the project we can test the installation right from Visual Studio .NET. VS .NET will roll back previous installations and run the Windows Installer. If the custom installer makes the correct modifications to the security policy, we are ready to deploy the .msi file. Placing this file conveniently on your Web site will give your customers an easy remedy in the event they cannot run your executable assembly from the Web.



Visual Basic. NET Power Coding
Visual Basic(R) .NET Power Coding
ISBN: 0672324075
EAN: 2147483647
Year: 2005
Pages: 215
Authors: Paul Kimmel

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net