Programmatic Security Techniques

As well as using declarative security in MTS by adding roles to packages, we can add code to a component that exerts finer control over the way it behaves. An excellent example of this in our Wrox Car Co application would be where we wanted to control access in different ways for different 'ranks' of people in the showroom. For example we might want to limit the total size of an order if it was being placed by a salesperson, and permit only managers to place fleet orders (say more than one car to the same customer).

Why Use Programmatic Security?

To do this with only declarative security would mean creating a separate component, placing it in a separate package, and having salespersons and managers log on and use the appropriate component. Instead we can add both user account groups (Sales staff and Showroom managers) to the roles of the component and then differentiate between them inside the component using programmatic security.

We can even use the MTS objects to get the username of the caller, although this technique is generally frowned upon. If we hard-code account names into the component we have to rebuild it when the account details change—when a new manager joins the company for example. By using the MTS roles, we just add users to, and remove them from, the NT groups assigned to the roles for this component's package.

How Programmatic Security Works

To use programmatic security we take advantage of methods and other objects that MTS makes available within our components, via the

ObjectContext
object. The two methods are:

Using these methods is easy enough. However, bear in mind that an error should prevent access, and not allow it by default. In other words, your code needs to be fail-safe. The sequence of events is to check first that the component is running under MTS, then that security is enabled, and finally see if the caller is listed in the specified role of the package. The following example returns

True
if the user is part of the role specified in the
strRoleName
argument, and
False
if not:

Function ValidateCaller(strRoleName As String) As Boolean

On Error GoTo Validate_Error

Dim objContext As ObjectContext

Set objContext = GetObjectContext()

'if objContext is Nothing we're not running in MTS

If objContext Is Nothing Then

ValidateCaller = False

Exit Function

End If

'see if security is enabled

If objContext.IsSecurityEnabled() = False Then

IsInRole = False

Exit Function

End If

'OK, so call the IsCallerInRole method

ValidateCaller = objContext.IsCallerInRole(strRoleName)

Exit Function

Validate_Error:

ValidateCaller = False

Exit Function

End Function

We could then use this function to limit fleet sales in our Wrox Car Co application to members of the Showroom managers NT account group with:

...

If intNumberCars > 1 Then

If ValidateCaller("Showroom managers") Then

'OK to process order

Else

'Error, user is not a manager

End If

End If

...

Finding The Original and Direct Users

The

Security
property of the
ObjectContext
object returns a reference to the component's
SecurityProperty
object. This provides four methods, all of which we can use to get details of the original user account that started off the process within which our component is executing.

There are two situations to consider. The original process is the process that started off the whole chain of events. This will be the user who accessed the application via IIS in our Web based examples. In effect, the name of the original process is that of the 'real' user's account.

The base process is that which initiated the current process. If we are in a component inside a transaction, for example, the base process will be the component that initiated the transaction. It will always be a component or user outside the current package, but may not be the same as the original process.

For each of these two processes, we can retrieve the account username for either the caller or the creator. In general these will be the same. They will differ when one process creates an instance of a component and then passes a reference to it on to another component, which then calls a method in the new component. In this case the creator and the caller are different processes, and so could have different usernames.

GetOriginalCallerName
The username of the original process that called the currently executing method.
GetOriginalCreatorName
The username of the original process that directly created the current object.
GetDirectCallerName
The username of the base process that called the currently executing method.
GetDirectCreatorName
The username of the base process that directly created the current object.

As an example, look at the following (somewhat contrived) example. The diagram shows a process A, which creates an instance of an object C. It then passes a reference to this object on to process B, which calls a method in that object. Object C then calls a method in object D, creating an instance of it in the process:

In this case, within the security context of object D, the original caller is process B while the direct caller is object C. The original creator, however, is process A; and the direct creator is object C.

To get the username of the original caller, we could use the code:

Dim strUserName As String

Dim objContext As ObjectContext

objContext = GetObjectContext()

strUserName = objContext.Security.GetOriginalCallerName()

As we noted earlier, using these methods to retrieve details of user accounts for 'real' users (i.e. people, rather than package identities) is generally not a good idea. It means that you will have to change the code if you need to add or remove users in the future. It's far better to design the security structure of the application around declarative security and the two

ObjectContext
methods
IsSecurityEnabled
and
IsCallerInRole
. Then you can use the Windows NT User Manager to add and remove users, and the changes will automatically be picked up by MTS.

As you've seen in this section of the chapter, MTS security techniques are at the heart of any DNA application. Using declarative security, combined where appropriate with programmatic security, means that we can exert fine control over which users can access our application, and which parts of the application they can use. The next step is to consider how we configure other parts of our application to work securely with MTS.

© 1998 by Wrox Press. All rights reserved.