CSCI E-143 CertPrep:   Configuring   (Kalani, chapter 15)

Saturday,  Dec. 4,  2004

This Saturday we cover Kalani's chapter 15,  "Configuring a Windows Application".   We are covering it out of sequence because it is the most important of the remaining chapters,  and I wanted to make sure it got covered before Christmas break.

Warning:  don't try to ignore this stuff just because it's at the end of the book.   Mr. Holley said there were a lot of security questions on his exam.

The  (parenthesized references)  in this list are explained  here.  


Licensing

Licensing of controls and other classes is handled by the  LicenseProvider  class.   In its default state, it works by checking whether a license (text) file is present on the machine attempting to use the control.   (Kalani has no discussion of this.   The only discussion I've seen—and it's brief—is in Stoecker.)   (Stoecker, pp. 388-390)


Configuration Files

Setting Dynamic Properties using Configuration Files


Specifying Assembly Versions using Configuration Files:

      app.exe.config,   Publisher Policy,   and   machine.config  

These control which version of an assembly the system will actually load.   (Some of this material is covered again in Kalani's chapter 13,  "Deployment".   But be warned:  Kalani doesn't talk at all about Publisher Policy Files.)

Once an executable is set up to call a DLL  (through the use of a reference,  say),  it will remember the version of the DLL.   If you want it to use a different version of the DLL,  you have to go through some redirection process:  either redo your reference in the IDE and then recompile,  or set up a configuration file to redirect the routine to a new DLL.

There are three levels of such configuration files,  of which Kalani mentions two.   These three files all use the same syntax;  the difference is in their position.   They are listed here from the highest level down:

  1. The Machine Configuration Filemachine.config,  is at the highest level,  and overrides the other two.   The Machine Configuration File is in
            %SystemRoot%\Microsoft.NET\Framework\<version>\Config
    (Here,  <Version>  refers to that of the .NET Framework,  not of your routine.)   The machine policy file will control the redirection of all DLLs on the machine.
  2. Publisher Policy Files,  which Kalani doesn't mention,  are XML modules each of which is assembled  (yes,  by the command-line assembler)  and placed in the GAC.   Each Publisher Policy File controls the redirection of one specific version of one named DLL.
  3. The Application Configuration File,  with a name like  appName.exe.config  (a name you ought to recognize),  is in the same directory as the executable.   This configuration file thus controls redirected loading of a DLL for that executable only.
You use the .NET Framework Configuration Tool to handle these files  (you can do a  lot  of things with this configuration tool),  although you can also handle the XML directly.   To start it,
        Start / Control Panel / Administrative Tools 
           / Microsoft .NET Framework 1.1 Configuration

(This is another area where Kalani is too brief.   The best short discussion of this I have seen is in Burton,  which supplied this description.)     (Burton, pages 171-180)

These three files all use the syntax.   Here's an extreme example.   Warning:  several of these tags have attributes not listed here.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <runtime>
      <assemblyBinding  xmlns="urn:schemas-microsoft-com:asm.v1">
         <dependentAssembly>
            <assemblyIdentity  name="FooLib" 
               publicKeyToken="ba01............"/>
            <bindingRedirect  oldversion="1.2.3.4"  newVersion="1.3.5.7"/>
            <codeBase  version="a.b.c.d"  href="URL of the assembly"/>
            <publisherPolicy/>
         </dependentAssembly>
         <probing/>
         <publisherPolicy/>
      </assemblyBinding>
   </runtime>
</configuration>
Some of these require further definition:

Here's how these configuration files get where they're supposed to be:

The rules of precedence were stated above, but there is one important exception:  the  publisherPolicy  tag  (listed in the XML above),  when placed in the  Application  Configuration File,  can implement  "safe mode"  by causing the Publisher Policy File to be ignored for that assembly—for instance,  with a setting of

         <publisherPolicy apply="no"/>
—which would cause a reversion to the last known good configuration.

QUESTION:  What in the world does Kalani mean by saying that configuration files  "can direct the CLR ... to enable just-in-time (JIT) debugging for Windows Forms"?   He never explains.   (Kalani, p. 999)


Security

There are two kinds of security:

Permissions are controlled by classes that derive from  System.Security.CodeAccessPermission.   Here are some examples of "atomic" permissions:

By default,  you have permission to run anything you want on your own computer.   (But this is subject to the operating system's permissions.   I can have Windows XP deny write permission on a directory,  and .NET can't do anything about it.)   (Bock, pp. 155-157)

Code-based Security

This is set up by a combination of two factors:  permission sets and code groups.

A code group is a set of assemblies that share a security "context".   A given assembly may be in more than one code group.

There are four policy levels at which permissions may be described.   From the top,  they are     (Stoecker, p. 491)

Level Applies to   /   Changed by   /   Changed with
Enterprise Applies to every computer on the network
Changed only by network administrator
Changed with .NET Framework Configuration Tool
Machine Applies to individual computer
Changed by machine administrator
Changed with .NET Framework Configuration Tool
User Applies to processes of the current user
Changed by that user
Changed with .NET Framework Configuration Tool
Application Domain "Applies to managed code executed in the hosts's application domain"
Set in code
Not configurable by the .NET Framework configuration tool,  but only by code

Each of these levels can reduce the permissions granted,  but cannot expand them.
Code can't grant itself permissions.

There is one default code group that exists at each one of the three higher levels:   All_Code     (Bock, p. 96)

Code groups have two attributes that help determine permissions:

There are seven types of evidence that the system uses to determine permissions.   These are various attributes of an assembly.)   They amount to membership conditions for joining a code group;  in fact,  these are sometimes  called  code groups.   They are     (Bock, pp. 94-5Kalani, p.1008-9)

(Incidentally,  all of these types of evidence can be supplied—or faked—without recourse to third-party suppliers,  by using utilities available in .NET.)     (Bock, pp. 103-4)

A permission set  is a collection of permissions granted as a unit.   (This is true even if only one permission is granted.)   There are seven built-in permission sets:   (Kalani, p.1009)

Assigning Permissions to Code

You do not assign permissions to a piece of code,  but only to a code group—even if there's only one routine in the group.

You do not assign individual permissions,  but only a permission set—even if there is only one permission in the set.

You set up permissions using the .NET Framework Configuration Tool.   Using it,  you do the following:   (Kalani, example, p.1010)

  1. Create a permission set.   One way to do this is to begin with one of the built-in sets,  and then add or subtract permissions.
  2. Create a code group that includes your assembly—for instance,  by including the Hash code for that assembly.
  3. Assign the permission set to the code group.
At this point I urge you to go through Kalani's example on page 1010.   It is simple, and it works.

Two ways of requesting code access

Computing Code-Access Permissions

There are four complicated steps in this complicated process:   (Kalani, pp. 1013-4;  Stoecker, p.491)

  1. Determine the code groups this code belongs to.   All such groups are considered,  unless one is marked  Exclusive
  2. Take the union of the permissions for all such groups—that is,  the  "OR"  product.   If any group gives a certain permission,  then the code is given that permission.
  3. Take the intersection of permissions at each of the policy levels relevant to this code.   If any code group is marked  Exclusive,  you use that group's permissions.   Otherwise,  start at the top and work down until you reach a level  (if any)  marked  LevelFinal,  where you stop.
  4. Perform a stack walk,  involving the permissions of all the routines in the calling sequence to the routine in question.   The result is the intersection  (the "AND" product)  of all such permissions.   (For instance,  if this piece of code has the  FileIOPermission  but the code calling it does not,  the permission is not granted.)

Permissions can be determined by using the .NET Framework Configuration Tool.     (Kalani, box, p. 1014)

Other types of Code-Access Permissions

You can request optional permissions using the  SecurityAction.RequestOptional  option.   For this to work,  you must have a  Main()  method with a  try  and a  Catch.   (No,  you can't use this to catch the cases where you don't get even the minimum permissions.   Such a program is "shut down.")     (Kalani, p. 1014)

To refuse permissions  (as in a case where you don't want questionable code using your code to do objectionable things),  you can refuse permissions with  SecurityAction.RequestRefuse.

Finally,  SecurityAction.Demand  assures that all code in the calling stack has the specified permission.   (You include this in your declaration of the security attribute.)

Custom Security Attributes

Kalani has two pages outlining the steps implementing a custom permission.   I'm sorry,  but I find them unreadable,  and I can't recommend that you take the large amount of time that understanding them would require.   Look at data access instead.


Role-based Security

Two definitions:

Authentication  is the confirming of a user's identity from credentials.

Authorization  is the granting of rights depending on that authentication.

In Windows,  you are authenticated when you log on.   This gives you a name and a role.

In addition,  there are a few authentication methods for ASP,  which might pop up if an ASP request calls Windows code:     (Kalani, p. 1021)

WindowsIdentity  and  WindowsPrincipal

WindowsIdentity,  which implements  IIdentity,  represents the Windows user.   WindowsPrincipal,  which implements  IPrincipal,  represents the  "entire security context"  of this user.   It is this latter object that the CLR inspects to determine role-based permissions.     (Kalani, p. 1022)

Namespace:  System.Security.Principal

You must tell the CLR that you're using Windows authentication:

        AppDomain.CurrentDomain.SetPrincipalPolicy
           (PrincipalPolicy.WindowsPrincipal);

To get the current identity:

        WindowsIdentity wi = WindowsIdentity.GetCurrent();
You can now access various properties of the identity,  such as

To get the current principal:

        WindowsPrincipal prin = new WindowsPrincipal(wi);
You can now access its properties,  such as

There is another way of retrieving just the current principal:  use the static method

        Thread.CurrentPrincipal()

To verify role membership,  you can use code like the following:     (Kalani, p. 1024)

        AppDomain.CurrentDomain.SetPrincipalPolicy
           (PrincipalPolicy.WindowsPrincipal);
        WindowsPrincipal prin = 
           (WindowsPrincipal)Thread.CurrentPrincipal;
        Boolean fAdmin = prin.IsInRole(WindowsBuiltInRole.Administrator);

There are three overloads of this  IsInRole()  method:

WARNING:   What this  IsInRole()  method checks for is membership in a user group.   To find out about roles and user groups on your own machine,  open

    Control Panel / Administrative Tools / Computer Management / System Tools / Local Users and Groups / Users

You will have better luck getting a response of "true" from this method if you use either the  WindowsBuiltInRole  enumeration or a carefully spelled string such as  BUILTIN\Administrators.   I haven't been able to get a positive result if I use a string including,  say,  the name of my machine.

Declarative security checking with the  PrincipalPermissionAttribute:     (Kalani, example 15.2, pp. 1028-9)

        using System.Security.Permissions;
        using System.Security.Principal;

        [PrincipalPermissionAttribute
           (SecurityAction.Demand, Role="Administrators")]
        public class Foo
        { 
            //... if you get here, you're in the group
        }

Imperative security checking with the  PrincipalPermission  class:     (Kalani, p. 1026)

        using System.Security.Permissions;
        using System.Security.Principal;

        AppDomain.CurrentDomain.SetPrincipalPolicy
           (PrincipalPolicy.WindowsPrincipal);
        PrincipalPermission pp = 
           new PrincipalPermission(null, "Developers");
        try
        {
           pp.Demand();
           //success if you get here
        }
        catch (Exception ex)
        {
           //failure if you get here
        }

Some Remaining Questions


The  (parenthesized references)  in the above list are explained  here.
In the questions at the end of chapter 15 in long Kalani, 

Here are the relevant questions from the two tests at the end of the "short Kalani"  book:

  Test 1:  questions  21  (page 365;  answer:  page 393),  49,  54,  55,  56.

  Test 2:  questions  7  (page 407;  answer:  page 440),  31,  42,  52,  53,  54.

(Some of these questions may duplicate those in long Kalani.   Both texts are listed here.)


Last revised  Dec. 10, 2004