tags:

views:

195

answers:

3

I'd like to create a plug-in architecture where I can limit an assemblies API to something very restricted, i.e. only allow a whitelist of functions. Is it possible to restrict what functions/methods a plug in assembly can call? Can I do it using AppDomains?

Does anyone have a simple example?

A: 

It should be possible with Code Access Security.

I found this article.

http://www.15seconds.com/Issue/040121.htm

AppDomain Policy Level would be yours

EDIT: It's quite complicated to provide a sample code. But MSDN should give you some good hints: http://msdn.microsoft.com/en-us/library/yctbsyf4%28VS.71%29.aspx

Arthur
This could work, but under full trust, all permissions are granted anyways.
leppie
But you can configure an AppDomain with low trust and load there your Plugin.
Arthur
Edit my answer: Added link to MSDN
Arthur
+1  A: 

using the internal keyword for anytihng you don't want other assemblies to see should work. Am i missing something?

What you do is this:

  • Make all "full permissions" items internal
  • in the AssemblyInfo.cs, add the InternalsVisibleTo attribute for each assembly you fully trust. Code example: [InternalsVisibleTo("fullNameOfAssemblyFromOtherLibrariesAssemblyInfoFile")]
  • Ta-da, all of your code is secured! (barring Reflection, which you can't really stop anyway)
RCIX
Yes, I want some code to run with full permissions, and other code to run with a very limited set of permissions. Using internal would prevent all assemblies from accessing it, not just the plug in ones. The Code Access Security is in the right direction, it answers the first/second questions, but not the third, i.e. a simple example.
Dave Hillier
I don't understand. Anything you want to see the internal stuff, set the InternalsVisibleTo attribute on your originating assembly. The plugin assembly won't have this ability and thus won't see anything that needs "full permissions". I'll edit my answer with some links.
RCIX
You can limit the use of reflection by applying an appropriate CASPOL.
Anderson Imes
+3  A: 

.NET has added the "Managed Addin Framework" that might fit the bill. It has the following features:

  • Isolation. Plugins run in their own AppDomain if desired, or even their own process if you need that level of isolation.
  • Contractual communication. You setup contracts and this is the only thing you distribute to plugin authors. They need not know about any other aspect of your application.
  • Discovery. Has a builtin mechanism for sniffing out plugins from a folder full of assemblies.
  • Security. Sets of CASPOLs are automatically applied when you load a plugin. There are a few options builtin to make this easy (see AddInSecurityLevel Enum).

Most approaches to isolation also limit communication and UI integration. MAF attempts to get around those limitations. It requires that you setup contractual communication pipelines, but will perform most of the work you would normally have to do yourself.

An example would be stitching together UI pieces running in two seperate processes (this is magic) or being able to raise events across an AppDomain or process. These things are non-trivial, but MAF helps a lot in this regard.

Sample

Here's a simple example. As the "Shell" author, you'll be supplying a contract to your plugin authors. Here's a typical contract (it's just an abstract class):

public abstract class Calculator 
{
    public abstract double Add(double a, double b);    
    public abstract double Subtract(double a, double b);
    public abstract double Multiply(double a, double b);
    public abstract double Divide(double a, double b);
}

If a plugin author wanted to write a plugin, they would simply subclass this contract and add the "Addin" attribute:

[AddIn("Sample Calculator AddIn", Version="1.0.0.0")]
public class SampleCalculatorAddIn : Calculator
{
    public override double Add(double a, double b)
    {
        return a + b;
    }
    public override double Subtract(double a, double b)
    {
        return a-b;
    }
    public override double Multiply(double a, double b)
    {
        return a * b;
    }
    public override double Divide(double a, double b)
    {
        return a / b;
    }
}

And here's how you would load these addins and interact with them:

// In this sample we expect the AddIns and components to 
// be installed in the current directory
String addInRoot = Environment.CurrentDirectory;

// Check to see if new AddIns have been installed
AddInStore.Rebuild(addInRoot);

// Look for Calculator AddIns in our root directory and 
// store the results
Collection<AddInToken> tokens = 
    AddInStore.FindAddIns(typeof(Calculator), addInRoot);

// Ask the user which AddIn they would like to use
AddInToken calcToken = ChooseCalculator(tokens);

// Activate the selected AddInToken in a new AppDomain set sandboxed 
// in the internet zone. You can find out what this gives access
// to by running "mscorcfg.msc", but essentially this will limit
// any access to the filesystem and other obvious OS services.
// Use of reflection is also very limited in this zone.
Calculator calculator = 
    calcToken.Activate<Calculator>(AddInSecurityLevel.Internet);

// Run the read-eval-print loop
RunCalculator(calculator);

That's pretty much the gist. There's obviously more to it than that, but you get the idea.

Further Reading

Good intro article
http://msdn.microsoft.com/en-us/magazine/cc163476.aspx

Overview on MSDN
http://msdn.microsoft.com/en-us/library/bb384200.aspx

System.Addin on Codeplex (lots of samples)
http://www.codeplex.com/clraddins

Tools

Pipeline Builder (helps to generate communication pipeline between shell and addins)
http://clraddins.codeplex.com/wikipage?title=Pipeline%20Builder&amp;referringTitle=Home

Fx-Cop rules for System.Addin
http://clraddins.codeplex.com/wikipage?title=Add-in%20FxCop%20Rules&amp;referringTitle=Home

Anderson Imes