Show Changes Show Changes
Edit Edit
Print Print
Recent Changes Recent Changes
Subscriptions Subscriptions
Lost and Found Lost and Found
Find References Find References
Rename Rename
Search

History

5/4/2005 9:12:45 AM
List all versions List all versions
How To Implement Role Based Security For A Managed COM App
.

If you're writing a ServicedComponent and you want to secure it, there are several attributes in System.EnterpriseServices that you need to use. Let me walk you through a concrete example. Figure 56.1 shows a simple component that implements role-based security.

 // PetStore.cs
 using System;
 using System.Reflection;
 using System.EnterpriseServices;


 [assembly: AssemblyDelaySign(true)]
 [assembly: AssemblyKeyFile(@"..\..\pubkey")]
 [assembly: ApplicationName("Pet Store")]
 [assembly: ApplicationActivation(ActivationOption.Server)]
 [assembly: ApplicationAccessControl(true,
   Authentication     = AuthenticationOption.Privacy,
   ImpersonationLevel = ImpersonationLevelOption.Identify,
   AccessChecksLevel  = AccessChecksLevelOption.ApplicationComponent)]


 [ComponentAccessControl(true)]
 [SecureMethod]
 public class PetStore : ServicedComponent, IPetStore {
     [SecurityRole("Customers")] public void PetAnimal()  {}
     [SecurityRole("Customers")] public void BuyAnimal()  {}
     [SecurityRole("Staff")]     public void FeedAnimal() {}
     [SecurityRole("Owners")]    public void GiveRaise()  {}
 }


 public interface IPetStore {
     void PetAnimal();
     void BuyAnimal();
     void FeedAnimal();
     void GiveRaise();
 }

Figure 56.1 A simple, secured managed COM+ component in C#

First of all, notice that the assembly has been given a public key: All managed COM+ components must be strongly named. Next, notice that I've given my application a name via ApplicationNameAttribute. I've also chosen a server app (as opposed to a library app) via ApplicationActivationAttribute. This will ensure that my application gets its own process.

The next attribute, ApplicationAccessControlAttribute, is very important, as it controls several process-level security settings, including our old friends the authentication level (What Is The COM Authentication Level) and the impersonation level (What is teh COM IMpersonation Level). This also allows us to control two things with respect to role-based authorization: whether it's on at all and how granular it is. Note how I passed true as the first argument to the attribute. This turns on role-based checks for the application as a whole, which is a really important thing to do! Then AccessChecksLevelAttribute allows me to specify the granularity of the checks. There are two granularity options:

The names might seem a bit confusing at first, but here's how they work. The first option tells COM+ to perform access checks only at the process level. These are checks 1 and 2 in Figure 56.2. The second option, which is the setting you should always stick with, adds access checks at the application level (3) and turns on the "security call context," which allows you to programmatically ask questions about the caller at runtime, such as "Is my caller in the Managers role?"

Figure 56.2 The three different COM+ access checks

Let me explain Figure 56.2 a bit. You see, COM+ access checks are performed only when a call crosses either a process boundary (1 and 2) or an application boundary (3). Access check 1 is the launch permission check, which is performed only if the server process hasn't yet been launched, and the SCM needs to determine whether the caller has permissions to launch it with her activation request. Access check 2 is the process-level access permission check, which is performed for each and every COM method call that comes in from outside the process. Both of these process-level checks are implemented in COM+ by simply checking to see if the caller is in at least one role for the server application in the process. If the caller isn't in any roles at all, he's denied the right to launch and denied the right to make any COM calls into the process.

The third access check (3) occurs whenever a normal COM method call crosses an application boundary. By normal, I mean a method call to an object that's already been created, and I'm not talking about methods like QueryInterface or Release.1 COM implements this third "component-level" access check by checking to see if the caller is in a role that grants access to the method (or the interface or class; any of these is sufficient to grant access).

Let's get back to the code in Figure 56.1. Note that I've placed a ComponentAccessControlAttribute on my class, passing true for its only argument. Don't forget this step because all classes without this feature turned on will have component-level access checks disabled for them. In other words, access check 3 in Figure 56.2 won't be implemented for those classes.

SecureMethodAttribute really needs better documentation. First of all, you need to realize that when you make a call from a managed COM+ client to a managed COM+ server, say IPetStore.GiveRaise, the EnterpriseServices infrastructure may elect not to use the IPetStore interface to dispatch the call. You see, there's an undocumented interface that's sometimes used to implement calls from managed clients to managed servers, and it's called IRemoteDispatch. You see, if this little shortcut is used instead of the real interface, method-level role-based access checks aren't enforced for that call. By putting SecureMethodAttribute on a class, you're telling the EnterpriseServices guys, "Hey, I've got method-level access checks on this class. Don't use the IRemoteDispatch shortcut because I need those checks to be honored!" Until Microsoft deigns to tell us exactly why IRemoteDispatch is useful, as a rule make sure you put this attribute on all of your classes.2

Finally, note that I've placed a SecureRoleAttribute on each method. This does two things: When you deploy this component in the COM+ catalog (via regsvcs.exe), it ensures there's a role with that name created for the application, which allows an administrator to add users to the role. Second, it assigns that particular role to the method so that anyone in the role will be allowed to call the method. You can also place this attribute on interfaces or classes if you want to grant broader permissions. Remember that a caller only has to be a member of a role on the method, interface, or class. Any one of these is sufficient to allow the call to proceed.

One thing you'll notice when you deploy this component with regsvcs.exe is that a magical role called "Marshalers"3 will be created in your application as well. You need to put everyone in this role who is allowed to use your application (either specify Authenticated Users or, if you can narrow it down further, use your own custom groups to restrict access to the overall application).

If declarative security on methods, interfaces, and classes isn't granular enough, you can add explicit role checks by calling ContextUtil.IsCallerInRole. Note that this isn't available unless you've configured your application for the correct access control level (AccessChecksLevelOption.ApplicationComponent), as I mentioned earlier. This additional logic allows you to take into consideration the parameters being passed to your method and other state that might change the outcome of the permission check. But please note that ContextUtil.IsCallerInRole always returns true if access checks are disabled. By disabling access checks, you're turning off not only any declarative security but also any explicit role checks you have programmed directly via ContextUtil.IsCallerInRole. Here's a simplified example of how you can use this method.

 void Bank::WithdrawMoney(int accountNumber, int amount) {
   if (amount > 10000) {
     // for this much money, need to be a manager
     if (!ContextUtil.IsCallerInRole("Managers")) {
       throw new ApplicationException("Access Denied");
     }
   }
   //...
 }

One important thing to note is that COM+ role-based security is a separate feature from the newer .NET role-based security exposed via IPrincipal, Thread.CurrentPrincipal, and friends (What is the Thread.Principal). To check COM+ roles, you must use the ContextUtil class as I've shown.

If you're worried about an administrator turning off role-based checks, you might be tempted to use ContextUtil.IsSecurityEnabled, which will tell you if role-based access checks have been disabled. In fact, I've seen a lot of people write code that looks like this:

 if (ContextUtil.IsSecurityEnabled &&
     ContextUtil.IsCallerInRole("Managers")) {
     // do some privileged operation
 }

This is fine, but you need to realize that it's only protecting against someone accidentally disabling security for your application. If a rogue administrator really wants to disable role-based checks, all he needs to do is add the Everyone group to each role and he's effectively achieved the same thing. Checking IsSecurityEnabled won't detect this sort of fraud. This is just another reminder that the administrator owns the machine and ultimately must be trusted. How to hire trustworthy people is a topic beyond the scope of this book!

1 These are low-level COM methods that are mainly called by plumbing and by anyone unfortunate enough to still be writing COM code in a language like C++.

2 As a security guy, I think this is totally backwards. I'd rather see an attribute that allows use of IRemoteDispatch as an exception to the rule rather than the other way around. Prefer secure defaults!

3 There is very little documentation on this role, and what little there is can be tough to find, since the spelling of “Marshaler” is often varied. The best I’ve seen so far is an article by Shannon Pahl in the MSDN library. You can find this article by searching for the following: “marshaller EnterpriseServices”.

PortedBy ChrisTavares

PluralsightTraining

Keith's first book-in-a-wiki. If you would like to read the book online or order a physical copy to throw at annoying coworkers, surf to the HomePage. Please note that due to overwhelming wikispam, this particular wiki is no longer editable.

About FlexWiki.

Recent Topics