Wah On Terra .NET: Martin Granell's Blog

Attacking the scary bits in .NET

Home Contact Syndicate this Site (RSS 2.0) Syndicate this Site (Atom) Login
  29 Posts :: 0 Stories :: 68 Comments :: 3210 Trackbacks

Archives

Post Categories

Readify Blogs


Thursday, February 10, 2005 #

This post and comments can now be found on my new blog here

Lets start off with Why bother to use declarative security attributes? It’s only a few more lines of code to write:

 public void DoSomethind()

{

    IAuthorizationProvider prov = AuthorizationFactory.GetAuthorizationProvider();

     if(!prov.Authorize(Thread.CurrentPrincipal, "important stuff"))

    {

        throw new SecurityException("Not allowed to do this");

    }

}

Versus:

[AuthorizationPermission(SecurityAction.Demand,  Context = "important stuff")]

public void DoSomethind()

{

 

}

But there are two main advantages to the attribute approach (as well as reduced LOC, and cleaner code):

1.      The ability to read the metadata. Permview is an example of an application that can read the meta data from an assembly, and spits out the following for the method above:

 Method AuthTest.Class1::DoSomethind() NonCasDemand permission set:

<PermissionSet class="System.Security.PermissionSet"
               version="1">

   <IPermissionclass="Readify.EnterpriseLibrary.Permissions.AuthorizationPermissionXml, Readify.Entlib.Permissions"
                version="1"
                unrestricted="False"
                context="important stuff"/>

</PermissionSet>

This then allows us to scan all the assemblies in the application, and build up a manifest of which methods are protected by which authorities.

2.      Flexibility – If we want to add additional logging to our attribute, or change the factory behaviour, we have one level of isolation from the underlying authorization source (in this case enterprise library).

OK, well how do we build one? Have a look at the source from here to see a finished custom non-code access security attribute. See this post for an overview of the process.

There are a few tricks to know:

1.      The attribute must derive from CodeAccessSecurityAttribute, even if it is not a CAS attribute. If it just derives from SecurityAttribute, then the C# compiler will ignore it (although the VB.NET one does the right thing…)

2.      The ToXml() method must create an element with the name IPermission, and there must be a class attribute with the assembly qualified name.

3.      The assembly must be strongly named, otherwise you won’t get the compiler to emit the permission.

4.      The assembly must either be added to the GAC, or to the Visual Studio devenv.exe directory, for the VS.NET compiler to find it (although the command line compiler does not have the same problem).

5.      The attribute must have a single constructor which takes a single SecurityAction parameter. Don’t be tempted to provide multiple parameters to initialize the attribute instead.

6.      The debugger is your friend. Debug visual studio by launching it in the program arguments of the project debugging properties, and step through what your permission and attribute is doing.

7.      Reflector is critical. When things start going wrong, the error messages are usually totally irrelevant. Look at the implementation of PermissionSet in reflector, and use permview to dump the XML that your attribute created.

8.      Unit tests. Unit tests. Unit tests. Unit tests. Did I mention unit tests?

Now, point number 3 was that the assembly had to be strong named. Since we want to call the authorization interface in enterprise library, and the default installation of enterprise library is not strong named, this is a problem.

Well… back to reflection land. I’ve created three wrapper classes, that on class constructor dynamically load the weakly named enterprise library using an assembly string, using reflection to grab MethodInfo instances for each the types, and then has some public wrapper methods that invoke the method infos.

Performance should not be too bad, and should be outweighed by the real authorization costs being performed anyway. From a security perspective (Trojan succeptability), this is no worse than using the IAuthorizationProvider interfaces directly, if the enterprise library assemblies being used are not strongly named.

If you do strongly name your enterprise library, then you can rip out the wrappers, and the calls to the wrappers, and replace with direct calls to the enterprise library factory and interfaces.

posted @ 12:42 AM

This post and comments can now be found on my new blog here

One of the bugs in Enterprise Library v1.0 relates to Type validation.  The problem occurs when selecting a type from an assembly which is not in the Global Asssembly Cache, and not in the EntLibConfig.exe directory.

Example steps to reproduce are:

·         Create a project with a custom authorization provider (i.e. derive from ConfigurationProvider, and implement IAuthorizationProvider).

·         Add an application configuration file.

·         Build the app.

·         Run enterprise library, and open the application configuration file.

·         Add a Security Application Block section.

·         Add a Custom Authorization Provider.

·         Click the ellipsis on the type name.

·         Add the application assembly containing the custom provider type

·         Select the new type.

·         Attempt to save.

 

At this point you will receive a validation error stating that the type is not valid. The problem is that some of the configuration settings have the [TypeValidation] attribute, which will attempt to check that the assembly qualified name of the type is a valid type. Unfortunately, this is running in an App Domain which is rooted in the EntLibConfig.exe directory, and so will only be able to resolves types in assemblies in that directory, or in the GAC.

 

The longer term solution is for the TypeValidation attribute to be able to look in the correct assembly locations, but at the moment you will need to change the enterprise library source.

 

Open the file: <Program Files>\Microsoft Enterprise Library\src\Configuration\Design\Validation\TypeValidationAttribute.cs

And comment out line 60:

                // errors.Add(instance, name, SR.ExceptionTypeNotValid(typeName));

 

Re-build Enterprise library by running the batch file:

<Program Files>\Microsoft Enterprise Library\src\BuildLibrary.bat

 

posted @ 12:02 AM