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 seenand it's briefis in Stoecker.)
(Stoecker, pp. 388-390)
Configuration Files
Setting Dynamic Properties using Configuration Files
- Dynamic properties are read from an XML configuration file when the app starts
up. The point is to allow changes in settings without requiring
recompiling and redeployment.
- You do remember, don't you, that we have already used
such configuration files? Remember setting
Trace and
Debug switches?
- These config files are handled by the
System.Configuration.AppSettingsReader
class, but, with one exception,
you'll use the IDE instead.
- You can add a configuration file through the IDE by requesting
Add / Add New Item and,
in the 2003 version of .NET, choosing an
Application Configuration File.
This gives you a file (in the IDE, remember) named
App.config.
It contains the following lines of XML:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>
- To create dynamic properties, and the
App.config file that holds them,
use the "DynamicProperties" setting in the "Configurations"
group in the Control's Properties window.
- Here what this file looks like after specifying a dynamic setting for
the Form's Text property:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<!-- User application and configured property settings go here.-->
<!-- Example: -->
<add key="Form1.Text" value="Form caption set through XML" />
</appSettings>
</configuration>
- Warning: once you have compiled your routine in the IDE,
you will have two copies of the configuration file:
App.config in the top-level directory,
and App.exe.config
in the bin directory.
But the IDE considers these two to be the same file.
Changes you make to one file might get rolled back;
and if you delete one file, you will delete the other, too.
- You can also set a value for a variable in, say,
a Form class with a dynamic property.
This is the case where you use the
System.Configuration.AppSettingsReader
class explicitly. Here's the code you put in your program:
(Stoecker, pp. 496-7)
System.Configuration.AppSettingsReader reader =
new System.Configuration.AppSettingsReader();
System.Threading.Thread.CurrentThread.CurrentCulture =
new System.Globalization.CultureInfo
((string) (reader.GetValue("Culture", typeof(string))));
And here is what you add to your configuration file:
<appSettings>
<add key="Culture" value="it-IT"/>
</appSettings>
- You can set dynamic properties for executables
(.exe files) only,
not for DLLs.
(Kalani, box, page 998)
- You can set only "simple" properties.
You can set numbers or strings.
You cannot set a class or a structure.
You cannot, therefore, set a color.
But isn't it true that a string is a class, and an integer is
a structure? Yes.
It's also true that the last example showed how to set a culture from a string
stored in the config file.
You want an explanation for all this? Shaddup.
- The IDE sometimes gives you dynamic property settings you don't expect,
such as SQL Connection information if you set up Data Connections using
drag-and-drop from the Toolbox.
(Kalani, box, page 998)
- You set properties by specifying "Dynamic Properties" in the Form's Properties
window.
- When you do this, you will be asked for a mapping
from each Control's property to the configured property.
- You can set more than one Control's property to the same mapped
value. See exercise 15.1
(Kalani, page 1028)
where several Buttons share a Key Mapping value.
Notice also that Button.Enabled
is a "simple" property that can in fact be set from a configuration
file. (It's set here to "False".)
- If you do this, you don't need to set up the configuration file
in a separate Add-New-Item step.
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:
- The Machine Configuration File,
machine.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.
- 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.
- 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:
- <dependentAssembly> identifies the assembly
and how to handle it.
- <bindingRedirect> redirects one assembly
version to another.
- <codeBase> tells where to find this assembly
if it's not on this machine. Its use requires an
assembly version number and a URL.
"If the assembly has a strong name, the codebase setting can be anywhere
on the local intranet or the Internet. If the assembly is a
private assembly, the codebase setting must be a path relative
to the application's directory."
(Help: "codeBase element")
- <probing> gives a private path to the
assembly. "The directories specified in privatePath must be
subdirectories of the application base directory."
(Help: "probing element")
- <publisherPolicy> says whether to apply the
directives in the Publisher Policy File; see below.
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 assemblyfor
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:
- Code-based security depends on the facilities your code requires.
- Role-based security depends on who the user of this code isthat is,
what credentials the user has.
Permissions are controlled by classes that derive from
System.Security.CodeAccessPermission.
Here are some examples of "atomic" permissions:
- Code Addess Permissions
- DirectoryServicePermission
- FileDialogPermission
- FileIOPermission
(It is possible to specify the exact file to use.)
(Stoecker, p. 485)
- PrintingPermission
- SQLClientPermission
- WebPermission
- Identity Permissions
- PublisherIdentityPermission
- SiteIdentityPermission
- StrongNameIdentityPermission
- URLIdentityPermission
- ZoneIdentityPermission
- Role-Based 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:
- Exclusive, which limits any checking to this
group alone; and
- LevelFinal, which prevents any consideration of
policy levels below the one where this descriptor appears.
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-5; Kalani, p.1008-9)
- Application directory (where the app is installed)
- Cryptographic hash (of the assembly,
which must be recalculated after each compilation of the program)
- Software publisher (based on the Authenticode signature)
- Site (the origin of the code; a URL)
- Strong name
- URL (of the assembly location)
- Zone (of the assembly location, e.g.,
MyComputer)
(Incidentally, all of these types of evidence can be suppliedor
fakedwithout 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)
- Nothing
- Execution
- Internet
- LocalIntranet
- Everything. All, that is, except permission
to skip verification.
- SkipVerification
- FullTrust
Assigning Permissions to Code
You do not assign permissions to a piece of code,
but only to a code groupeven if there's only one routine in the group.
You do not assign individual permissions, but only a permission seteven
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)
- 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.
- Create a code group that includes your assemblyfor instance,
by including the Hash code for that assembly.
- 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
- Declarative Security uses an attribute
declared atop your requesting class:
using System.Security.Permissions;
[assembly:FileDialogPermissionAttribute
(SecurityAction.RequestMinimum, Unrestricted=true)]
QUESTIONS: What is the difference between this and no attribute?
If the system weren't going to grant this permission,
when would it have refused it?
- Imperative Security is used when you don't know what permissions
you will need until run time. Imperative security is
shown in this code:
(Kalani, p.1011-2)
FileDialogPermission fdp =
new FileDialogPermission(PermissionState.Unrestricted);
fdp.Demand();
This will throw a security exception if the permission is not granted.
Computing Code-Access Permissions
There are four complicated steps in this complicated process:
(Kalani, pp. 1013-4;
Stoecker, p.491)
- Determine the code groups this code belongs to.
All such groups are considered, unless one is marked
Exclusive.
- Take the union of the permissions for all such groupsthat is,
the "OR" product.
If any group gives a certain permission,
then the code is given that permission.
- 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.
- 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)
- None
- Forms-based
- Windows
- Passport
- Custom
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
- AuthenticationType
- Is Anonymous
- IsAuthenticated
- IsGuest
- IsSystem
- Name
- Token
To get the current principal:
WindowsPrincipal prin = new WindowsPrincipal(wi);
You can now access its properties, such as
- AuthenticationType
- IsAuthenticated
- Name
- IsInRole(<specific role>)
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:
- IsInRole(WindowsBuiltInRole),
where the role is a member of the
WindowsBuiltInRole enumeration
- IsInRole(string groupName),
where the string should begin, for built-in constants, with
BUILTIN\
- IsInRole(integer RID),
where RID is a role identifier, which is assigned by the operating
system in a language-independent way
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
- How do some of the odd arguments workfor instance,
how do you use RequestMinimum
and what other code do you need?
- Arguments to other declarative security attributes such as
Trust=Unlimited .
Find out about these.
- Exactly when imperative vs. declarative security are checked in program loading
and execution
- What is Impersonation?
The (parenthesized references)
in the above list are explained here.
In the questions at the end of chapter 15 in long Kalani,
- Question 2 should read "Select All that apply".
(So should question 3.)
- Question 4 is pretty bad: there are in fact at least
three "configuration" files that could apply:
app.exe.config, a Publisher Policy File, and
machine.config.
And what about having one Publisher Policy File for each version?
How many configuration files would that make?
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 1, question 54: Don't confuse machine level with
machine.config.
Test 2: questions
7 (page 407; answer: page 440),
31, 42, 52, 53, 54.
- Test 2, question 7: This question is the only mention of a
Publisher Policy File in either short or long Kalani.
(Some of these questions may duplicate those in long Kalani.
Both texts are listed
here.)
Last revised Dec. 10, 2004