COM+ 1.0 authorization involves three main concerns:
The first and second concerns are addressed by COM+ 1.0 roles with, as we'll see shortly, support for authorization driven by access control lists (ACLs). With the critical support provided by Windows 2000, COM+ 1.0 addresses the third concern, at the core of three-tier scenarios, with two important idioms:
Figure 7-9 illustrates these models.
Figure 7-9. The COM+ trusted application and impersonation/delegation models.
COM+ roles are used to establish an authorization policy: determining whom to let in and with what authority. In constructing a policy, you're deciding who should be able to perform which actions and access which resources. Roles facilitate this by acting as an access control mechanism invoked whenever a user attempts to access any application resource. A role is essentially a list of users—more precisely, a grouping of users that share the same security privileges. When you assign a role to an application resource, you're granting access permission for that resource to whoever is a member of that role.
Therefore, you can define an extremely particular security privilege by declaring it as a role and then assigning the role to specific resources. This design is fulfilled when the application is deployed and system administrators populate the role with users and user groups. When the application runs, COM+ 1.0 will enforce the policy by carrying out role checks.
The fundamental asset you protect with roles is code: methods that can be called by clients of a COM+ application. With role-based security, the application protects resources by protecting the code accessing those resources. (Alternatively, as we'll discuss in a moment, in the impersonation/delegation model the application can simply act on the client's behalf with the client's authority.) Role membership is checked whenever a client attempts to call a method exposed by a component in an application. The call will succeed only if the caller is in a role assigned to the method being called.
It's often useful to configure role membership by using Microsoft Windows NT/Windows 2000 groups, rather than individual users. Here are some reasons:
Access to application methods is controlled through configuration, as described in the previous section. Access to private application resources is controlled programmatically either with roles or ACLs. Figure 7-10 illustrates both methods of accessing private application resources.
Figure 7-10. Accessing methods and private application resources.
Roles are defined per application by using the Component Services snap-in, which is shown in Figure 7-11. The Roles folder in each application contains the roles defined for that application. Each role object, such as Administrator in the figure, contains a Users folder that contains Windows 2000 users and groups defining that role membership.
Figure 7-11. Defining roles in the Component Services snap-in.
Once a role has been defined, it can be used to enforce either coarse-grained access control to the entire application or fine-grained access control to the application's components, interfaces, and methods. One of these access control policy types is selected by setting the security level on the Security tab of the application's Properties page, as was shown in Figure 7-7. When fine-grained access control is selected, roles can be used to protect a method call by associating the role in the following ways:
Figure 7-12 shows a role being associated with an interface.
Figure 7-12. Associating a role with an interface to protect that interface's methods.
Note that a common source of trouble with the fine-grained security level is defining a role for an application without associating the role to a component, interface, or method. In this case, the user sometimes mistakenly expects that the members of the role will be granted access to all the application methods. This is not the case, and the result is denial of access even for those users who are members of that role. Again, with the fine-grained security level, roles at the application level are simply defined and are not used to directly grant access to the application components, interfaces, or methods.
In addition to role configuration, COM+ 1.0 offers other controls that affect authorization:
Figure 7-13. Toggling access checking on a component.
Programming
To control access to a private application resource, the application developer needs to gate access to that resource with a test of role membership, as shown here:
Dim objCallCtx As SecurityCallContext ' Get the security call context. Set objCallCtx = GetSecurityCallContext(); ' Perform the role check. Allowed = objCallCtx.IsCallerInRole("<role name>"); ' Act according to the result. If (Allowed) Then End If |
Alternatively, in the case of resources protected by ACLs, COM+ 1.0 supports the following programming idiom, as demonstrated in C++:
// COM server impersonates client to obtain its token. CoImpersonateClient(); // Obtain private object security descriptor. MyStatus = GetObjectSD(Object, , &SD); // Your own routine. // Obtain client's token; revert to the server's identity. Status = OpenThreadToken( , &Token); CoRevertToSelf(); // Perform access check. Status = AccessCheck(SD, Token, DesiredAccess, GenericMapping, &PrivsUsed, &PrivLength, &GrantedAccess, &Allowed); if (Allowed) { } |
Aside from the technical details of how to realize one or the other three-tier authorization models, it's important to understand some of the reasons underlying the choice of one or the other models.
It's useful to recall that meaningful security rests on a policy that defines "who can do what to what." Note that typical policies will make statements about both subjects, the principals attempting access, and objects, the resources that are the target of that access. Here are some sample policy statements:
Each of these statements expresses access that depends in varying degrees on both the subjects and objects of the underlying operation. For instance, the first statement is very much centered on the subject—administrator vs. everyone—but the third one concerns a subtle relationship between subject and object, manager and data. These observations are somewhat simplistic, but they do offer some insight as to how to approach the problem of defining access policy and how, as we will see, this characterization affects the choice of a three-tier authorization model (or any authorization model for that matter).
The trusted application model
The trusted application authorization model is characterized by the fact that the application enforces the access control policy and accesses external resources under its own identity. In other words, the application is trusted by the external resource managers—for example, Microsoft SQL Server—to make the proper access decisions.
This model is most applicable when the overall application policy primarily concerns subjects performing the various application requests. This is the case because the subject security information is readily available to the application and because information about external resources is not essential to access control.
The strength of this model is its simple implementation and scalability because the application performs all secondary access under its own identity. Resources that are subject to per-identity constraints can be efficiently managed because the single application identity does all the work. This makes connection pooling viable because connection pooling does not work well with many authenticated connections using different identities.
Finally, note that this model requires careful design and implementation so that flaws cannot be exploited by the client to gain access through the trusted application to resources that the client is not entitled to access directly. In other words, it's essential to this model that the application live up to its title of "trusted."
The impersonation/delegation model consists of the application taking on the client's identity during the course of work performed on the client's behalf. Figure 7-14 illustrates the COM+ impersonation/delegation model.
Figure 7-14. The COM+ impersonation/delegation model.
This model is useful when the application access policy expresses statements about the objects of a client's request. This is, for example, the case for access policies centered on data.
The implementation of this model requires the delegation capabilities of Kerberos, which will be autoselected by COM+, if possible.
The disadvantages of this model are its relative complexity and its reduced scalability compared with the trusted application model. Issues related to scaling include the following:
For delegation to work, the following client-side requirements must be met:
Programming
As noted in the previous section, the client might want to explicitly allow its identity to be delegated for use by the application through a call to CoSetProxyBlanket. On the application side, the following programming form is used for the application to perform work under the client's identity:
// COM server impersonates client. CoImpersonateClient(); // Do work as the client. // Revert to server's own identity once we are done. CoRevertToSelf(); |
You'll need to use the following code declarations if you want to use CoImpersonateClient and CoRevertToSelf in your Visual Basic components:
Public Declare Function CoImpersonateClient _ Lib "ole32.dll" () As Long Public Declare Function CoRevertToSelf _ Lib "ole32.dll" () As Long |
The following example code shows how to use these functions in a Visual Basic method call:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' This function is an example only. It is not ' recommended that you: ' (a) return large database result sets from COM+ processes ' (b) pass arbitrary SQL queries and execute them ' without checking the query syntax first '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Public Function GenericQuery(ByVal ConnectionString As String, _ ByVal QueryString As String) _ As ADODB.Recordset Dim hr As Long Dim rs As ADODB.Recordset Dim conn As ADODB.Connection On Error GoTo ErrorHandler hr = CoImpersonateClient 'Open the connection to the database. Set conn = New ADODB.Connection conn.Open ConnectionString conn.CursorLocation = adUseClient 'Execute the query. Set rs = conn.Execute(QueryString) Set GenericQuery = rs hr = CoRevertToSelf Exit Function ErrorHandler: If Not conn Is Nothing Then Set conn = Nothing End If hr = CoRevertToSelf Err.Raise Err.Number, Err.Description End Function |
Until Windows 2000, the behavior of COM—and, by extension, that of MTS because it is built on COM—was anomalous with respect to impersonation. In particular, if an impersonating thread (that is, one carrying the security context of a caller) made a COM call, the security context associated with the call was the security context of the process, not the impersonated security context. This problem is rectified in Windows 2000, but to prevent compatibility problems with existing applications, COM+ 1.0 introduces a way to control this behavior through a capability called cloaking. When cloaking is disabled, the impersonation behavior is the old one—calls to COM and COM+ 1.0 components are carried out in the security context of the process. If cloaking is enabled, calls to COM and COM+ 1.0 components are carried out in the impersonated security context, provided one exists, of course. Figure 7-15 illustrates impersonation with and without cloaking. Cloaking is controlled programmatically and enabled by default for COM+ 1.0 applications.
Figure 7-15. Impersonation with and without cloaking.
COM+ 1.0 provides a mechanism that enables you to retrieve security information regarding all upstream callers in the chain of calls to your components. This information is available only when the security level is set to fine-grained access control. The data carried in the call context is formed by COM+ 1.0 from call information supplied by the authentication service on every call. This information is then packaged by COM+ 1.0 and sent along the call chain, as shown in Figure 7-16.
Figure 7-16. Collecting call security information with the call context.
Note that the trustworthiness of the call context information is based on
Thus, it's important to use the call context information carefully. This facility is particularly useful for detailed logging in an environment in which the application logic is distributed among several COM+ 1.0 applications that trust one another. You can access security call context information by using the ISecurityCallContext interface.