COM+ Security

.NET has an elaborate component-oriented security model. .NET security model manages what the component is allowed to do and what permissions are given to the component and all its clients up the call chain. You can (and should) still manage the security attributes of your hosting COM+ application to authenticate incoming calls, authorize callers, and control impersonation level.

.NET also has what .NET calls role-based security, but that service is limited compared with COM+ role-based security. A role in .NET is actually a Windows NT user group. As a result, .NET role-based security is only as granular as the user groups in the hosting domain. Usually, you do not have control over your end customer’s IT department. If you deploy your application in an environment where the user groups are coarse, or where they do not map well to actual roles users play in your application, then .NET role-based security is of little use to you. COM+ roles are unrelated to the user groups, allowing you to assign roles directly from the application business domain.

Configuring Application-Level Security Settings

The assembly attribute ApplicationAccessControl is used to configure all the settings on the hosting COM+ application’s Security tab.

You can use ApplicationAccessControl to turn application-level authentication on or off:

[assembly: ApplicationAccessControl(true)]

The ApplicationAccessControl attribute has a default constructor, which sets authorization to true if you do not provide a construction value. Consequently, the following two statements are equivalent:

[assembly: ApplicationAccessControl] 
[assembly: ApplicationAccessControl(true)]

If you do not use the ApplicationAccessControl attribute at all, then when you register your assembly, the COM+ default takes effect and application-level authorization is turned off.

The ApplicationAccessControl attribute has three public properties you can use to set the access checks, authentication, and impersonation level. The AccessChecksLevel property accepts an enum parameter of type AccessChecksLevelOption , defined as:

public enum AccessChecksLevelOption
{
    Application,
    ApplicationComponent
}

AccessChecksLevel is used to set the application-level access checks to the process only (AccessChecksLevelOption.Application) or process and component level (AccessChecksLevelOption.ApplicationComponent). If you do not specify an access level, then the ApplicationAccessControl attribute’s constructors set the access level to AccessChecksLevelOption.ApplicationComponent, the same as the COM+ default.

The Authentication property accepts an enum parameter of type AuthenticationOption , defined as:

public enum AuthenticationOption
{
   None,
   Connect,
   Call,
   Packet,
   Integrity,
   Privacy,
   Default
}

The values of AuthenticationOption map to the six authentication options discussed in Chapter 7. If you do not specify an authentication level or if you use the Default value, the ApplicationAccessControl attribute’s constructors set the authentication level to AuthenticationOption.Packet, the same as the COM+ default.

The Impersonation property accepts an enum parameter of type ImpersonationLevelOption , defined as:

public enum ImpersonationLevelOption
{
   Anonymous,
   Identify,
   Impersonate,
   Delegate,
   Default
}

The values of ImpersonationLevelOption map to the four impersonation options discussed in Chapter 7. If you do not specify an impersonation level or if you use the Default value, then the ApplicationAccessControl attribute’s constructors set the impersonation level to ImpersonationLevelOption.Impersonate, the same as the COM+ default.

Example 10-11 demonstrates using the ApplicationAccessControl attribute with a server application. The example enables application-level authentication and sets the security level to perform access checks at the process and component level. It sets authentication to authenticate incoming calls at the packet level and sets the impersonation level to Identify.

Example 10-11. Configuring a server application security

[assembly: ApplicationActivation(ActivationOption.Server)]

[assembly: ApplicationAccessControl(
           true,//Authentication is on
           AccessChecksLevel=AccessChecksLevelOption.ApplicationComponent,
           Authentication=AuthenticationOption.Packet,
           ImpersonationLevel=ImpersonationLevelOption.Identify)]

A library COM+ application has no use for impersonation level, and it can only choose whether it wants to take part in its hosting process authentication level (that is, it cannot dictate the authentication level). To turn authentication off for a library application, set the authentication property to AuthenticationOption.None. To turn it on, use any other value, such as AuthenticationOption.Packet. Example 10-12 demonstrates how to use the ApplicationAccessControl to configure the security setting of a library application.

Example 10-12. Configuring a library application security

[assembly: ApplicationActivation(ActivationOption.Library)]

[assembly: ApplicationAccessControl(
           true,//Authentication 
           AccessChecksLevel=AccessChecksLevelOption.ApplicationComponent,
           //use AuthenticationOption.None to turn off authentication, 
           //and any other value to turn it on
           Authentication=AuthenticationOption.Packet)]

Component-Level Access Checks

The component attribute ComponentAccessControl is used to enable or disable access checks at the component level. Recall from Chapter 7 that this is your component’s role-based security master switch. The ComponentAccessControl attribute’s constructor accepts a Boolean parameter, used to turn access control on or off. For example, you can configure your serviced component to require component-level access checks:

[ComponentAccessControl(true)]
public class MyComponent :ServicedComponent 
{...}

The ComponentAccessControl attribute has an overloaded default constructor that uses truefor the attribute construction. Consequently, the following two statements are equivalent:

[ComponentAccessControl]
[ComponentAccessControl(true)]

Adding Roles to an Application

You can use the Component Services Explorer to add roles to the COM+ application hosting your serviced components. You can also use the SecurityRole attribute to add the roles at the assembly level. When you register the assembly with COM+, the roles in the assembly are added to the roles defined for the hosting COM+ application. For example, to add the Manager and Teller roles to a bank application, simply add the two roles as assembly attributes:

[assembly: SecurityRole("Manager")]
[assembly: SecurityRole("Teller")]

The SecurityRole attribute has two public properties you can set. The first is Description . Any text assigned to the Description property will show up in the Component Services Explorer in the Description field on the role’s General tab:

[assembly: SecurityRole("Manager",Description = "Can access all components")]
[assembly: SecurityRole("Teller",Description = "Can access IAccountsManager only")]

The second property is the SetEveryoneAccess Boolean property. If you set SetEveryoneAccess to true , then when the component is registered, the registration process adds the user Everyone as a user for that role, thus allowing everyone access to whatever the role is assigned to. If you set it to false , then no user is added during registration and you have to explicitly add users during deployment using the Component Services Explorer. The SecurityRole attribute sets the value of SetEveryoneAccess by default to true. As a result, the following statements are equivalent:

[assembly: SecurityRole("Manager")]
[assembly: SecurityRole("Manager",true)] 
[assembly: SecurityRole("Manager",SetEveryoneAccess = true)]

Automatically granting everyone access is a nice debugging feature; it eliminates security problems, letting you focus on analyzing your domain-related bug. However, you must suppress granting everyone access in a release build, by setting the SetEveryoneAccess property to false:

#if DEBUG
[assembly: SecurityRole("Manager")]
#else
[assembly: SecurityRole("Manager",SetEveryoneAccess = false)]
#endif

Assigning Roles to Component, Interface, and Method

The SecurityRole attribute is also used to grant access for a role to a component, interface, or method. Example 10-13 shows how to grant access to Role1 at the component level, to Role2 at the interface level, and to Role3 at the method level.

Example 10-13. Assigning roles at the component, interface, and method levels

[assembly: SecurityRole("Role1")]
[assembly: SecurityRole("Role2")]
[assembly: SecurityRole("Role3")]

[SecurityRole("Role2")]
public 
interface IMyInterface
{  
   [SecurityRole("Role3")]  
   void MyMethod(  );
}
 
[SecurityRole("Role1")]
public class MyComponent :ServicedComponent,IMyInterface
{...}

Figure 10-2 shows the resulting role assignment in the Component Services Explorer at the method level. Note that Role1 and Role2 are inherited from the component and interface levels.

The resulting role assignment of Example 10-13 in the Component Services Explorer, as seen at the method level

Figure 10-2. The resulting role assignment of Example 10-13 in the Component Services Explorer, as seen at the method level

If you only assign a role (at the component, interface, or method level) but do not define it at the assembly level, then that role is added to the application automatically during registration. However, you should define roles at the assembly level to provide one centralized place for roles description and configuration.

Verifying Caller’s Role Membership

Sometimes it is useful to verify programmatically the caller’s role membership before granting it access. Your serviced components can do that just as easily as configured COM components. .NET provides you the helper class SecurityCallContext that gives you access to the security parameters of the current call. SecurityCallContext encapsulates the COM+ call-object’s implementation of ISecurityCallContext , discussed in Chapter 7. The class SecurityCallContext has a public static property called CurrentCall . CurrentCall is a read-only property of type SecurityCallContext (it returns an instance of the same type). You use the SecurityCallContext object returned from CurrentCall to access the current call. Example 10-14 demonstrates the use of the security call context to verify a caller’s role membership, using the same use-case as Example 7-1.

Example 10-14. Verifying the caller’s role membership using the SecurityCallContext class

public class Bank :ServicedComponent,IAccountsManager 
{   
   void TransferMoney(int sum,ulong accountSrc,ulong accountDest)   
   {      
      bool callerInRole = false;      
      callerInRole = SecurityCallContext.CurrentCall.IsCallerInRole("Customer");   
	  if(callerInRole)//The caller is a customer      
      {        
         if(sum > 5000)            
           throw(new UnauthorizedAccessException(@"Caller does not have sufficient 
                                              credentials to transfer this sum"));      
      }      
      DoTransfer(sum,accountSrc,accountDest);//Helper method
   }
   //Other methods
}

You should use the Boolean property IsSecurityEnabled of SecurityCallContext to verify that security is enabled before accessing the IsCallerInRole( ) method:

bool securityEnabled = SecurityCallContext.CurrentCall.IsSecurityEnabled;
if(securityEnabled)
{
   //the rest of the verification process
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset