At a recent TechTalk I talked about code access security and how to perform declarative and imperative security demands & requests. There’s no doubt declarative security checking is nicer than imperative checking, but not everything can be done declaratively.
Say we have the following method:
We want to make sure we have permission to write to the filepath. Declaratively, we can request (SecurityAction.RequestMinimum) for an unrestricted FileIOPermission which would ensure that we had write access. But requesting unrestricted IO access is way overkill, since we only need access to select paths.
I got the question, why we could not perform that security check declaratively? As all declarative security checks are done at JIT and not at runtime, we simply do not have any knowledge of the filePath parameter value, and thus we can’t require permission for those specific paths. The only way we can demand permission for just the paths we need, is to do an imperative permission demand like so:
This however, clutters up our writeFile implementation as we now dedicate 2/3 lines for security checking… If only we could do this declaratively.
PostSharp Laos is a free open source AOP framework for .NET. Using PostSharp, we can define our own custom attributes that define proxy methods that will be invoked at runtime, instead of the actual method they decorate. Thus, we are able to define an imperative security check in our custom attribute, which will run before our actual method. I’ll jump right into it and present such an attribute:
In this attribute, we take two parameters, the FileIOPermissionAccess that is required, as well as the name of the parameter containing the file path we should demand permission for. The CompileTimeInitialize method is actually run at compile time - it will look through the list of parameters the method receives, and find the index of the parameter (by its name) and store it for later use. The stored values will be serialized in binary format, thus the need for making the class Serializable. If the parameter name is not found, we throw an exception. It’s important to note that this exception will be thrown at compile time, not at runtime. Thus there’s nothing dangerous in specyfying the parameter by its name (in string format) as we still have full compile time checking. Finally, the OnInvocation method is run when the decorated method is invoked. It’ll do the imperative security check and proceed with the original method call.
Using our FilePathPermission attribute, we can now rewrite our writeFile method as:
And there we go, we’ve now abstracted the security plumbing code out of our method implementation, while still doing an imperative security demand at runtime. In the same way, we can implement logging, exception handling, parameter sanitation, validation and so forth.
So what happens behind the scenes? The state we saved at compile time is embedded as a resource:
PostSharp also includes a special class it uses to keep track of the decorated methods, aspect state and so forth:
Let’s compare the complete initial code:
With the reflected code after PostSharp has done its magic:
Note that these are debug builds, but the code modifications are the same in both release and debug mode. The main method is unaffected. A static initializer has been added which takes care of PostSharp’s intialization, obtaining pointers to the proxy methods - of which there is only one in this example. Finally, the writeFile method has been renamed to ~writeFile (otherwise unmodified), and a new writeFile method has been added. The new writeFile method, generated by PostSharp, invokes our FilePathPermissionAttributes OnInvocation method, passing in an MethodInvocationEventArgs parameter containing the parameter values.
While PostSharp does make a lot of things happen automagically at the compile stage, the effects are rather easy to get a comprehension of. Also, since PostSharp is completely open source and very well documented, you can always pinpoint exactly what happens and why it happens.
What about performance? There’s definitely a performance hit when using PostSharp. The build may be longer since PostSharp is invoked as part of the build process, but in my experience this is a rather quick process. As for runtime performance penalties, I constructed the following short app to test the performance hit by executing it both with and without the LaosTest attribute (using CodeProfiler for profiling):
Profiling 10^6 calls to test() over five iterations yielded a total runtime of 13.879ms when using the PostSharp attribute - in release mode, excluding the first call. Running the same test, without the attribute, takes just 23ms. That’s 600 times quicker than when using PostSharp. But, still, that’s just 0.0027ms per call when using PostSharp (and nearly unmeasurable when not). Given that in all real life situations, the actual business logic will be much much slower, this performance penalty has almost no effect. Usually, we’re much better off sacrificing these minute amounts of speed over much better manageability of our source code.