Ed Musters
Microsoft Transaction Server implements a simple yet powerful security model. In this article, Ed explores the security features of MTS and shows how you can leverage this in your C++ applications.
I introduced Microsoft Transaction Server (MTS) in the November 1997 issue of Visual C++ Developer (see "Microsoft Transaction Server"). In the March 1998 issue, I explored the Shared Property Manager ("MTS Shared Property Manager"). The most frequent questions I've received from you on Microsoft Transaction Server have been in the area of security. I'd like to take the opportunity in this article to explore the security features of MTS.
Introduction to MTS securityThe Sample Bank is available as a sample application when you install MTS. We'll explore MTS security with the goal of completely locking down this application. You'll want to secure your own applications for several reasons, to ensure that:
I'm especially concerned with the second point. Someone who knows the ID of a computer belonging, for example, to a manager running a human resources application, could use the Network Monitor tool to capture all the network traffic to and from that machine. Lots of sensitive information is available "on the wire" for anyone who cares to look. I've heard a rumor (from a reliable inside source) that it's immediate grounds for dismissal for a Microsoft employee to run any Network Monitoring tool.
In this article's samples, I'll be defaulting to the highest possible levels of security. You should carefully consider the security features and how you want to implement them for your application.
Enabling security for your packageFirst, we need to get one machine configuration out of the way. For the NT Server running Microsoft Transaction Server, set the default Distributed COM configuration to its highest levels. Use the Run command to execute DCOMCNFG.EXE, and set the Default Properties tab as shown in Figure 1.
Figure 1. Distributed COM configuration tool.
This article isn't intended to be a DCOM tutorial, so I'll explain these options in the following paragraphs, in the context of MTS.
Now, open the Transaction Server Explorer (MTS 2.0, as shown here, now uses the Microsoft Management Console) and drill down to the Packages Installed. You should be looking at the window shown in Figure 2.
Figure 2. MTS 2.0 Explorer window.
Right-click on the Sample Bank package, and choose properties. Set the Security tab of the Properties page as shown in Figure 3 by checking "Enable authorization checking" and choosing the "Packet Privacy" level from the drop-down combo box.
Figure 3. Sample Bank package securtiy properties.
The available authentication levels are:
The preceding list is roughly equivalent to the following scenario: I could send you a letter (the old-fashioned paper kind). If I put a signature on the letter, you can verify that the letter was sent by me. If I put the letter in an envelope and affix a special wax seal (like the King of England used to do), then you can verify that the seal is intact and that the letter wasn't tampered with during transit. Note that the letter itself is still readable by anyone at this point! I can finally encode (that is, encrypt) the letter content itself so that it must be decoded by the receiving party before being read. Now all of the Allies can safely be informed that the D-Day landing location will in fact be Normandy and not the suspected Pas De Calais. Too bad they didn't have DCOM and Transaction Server . . .
NT security and MTS RolesThe Sample Bank application is shown in Figure 4. The dialog box has been filled out to transfer $750 between two accounts using the VC++ components.
Figure 4. Preparing a transaction in the Sample Bank application.
You might recall from previous articles about this bank application that you must be a Manager to transfer amounts exceeding $500. If I press Submit anyway, I'll get the message shown in Figure 5.
Figure 5. Managers must approve large transactions.
Well, maybe you could have come up with a nicer way of handling that error, but it does work. In our Bank, we want to assign Marc, Chris, and Andrea to the Manager role. Heck, I deserve a promotion, so I'll be a Manager too. I like the approach of creating an NT Global Group for each application role you want to assign. I suggest the naming standard of "gg<PackageName><Role>". Note that "gg" stands for "global group"—just a better way of finding and identifying these in User Manager for Domains. In our case, create a Global Group called "ggSampleBankManager" and assign the desired Users. The New Global Group dialog box is shown in Figure 6.
Figure 6. Define a new global group.
Drill down in the Transaction Server Explorer into the Sample Bank package into Roles and then Managers. Now, highlight Users and right-click. Select New->User from the popup menu. Find and select the Global Group you created in the previous step and add it to the Managers role, as shown in Figure 7. If all has gone well, you'll end up with the Transaction Server Explorer window as it appears in Figure 8.
Figure 7. Add the NT global groups to the MTS Manager role.
Figure 8. The global group has been assigned to the Manager group.
Okay, let's try this funds transfer thing again. If you set up the sample Bank application to transfer $750 between two accounts using the VC++ components, it will succeed, as shown in Figure 9.
Figure 9. Successful funds transfer transaction.
Programmatic securityWith all of that in place, it's very straightforward to use the role definitions in your C++ components. For example, the following code implements the business rule that Managers are required for transfer amounts over $500.
First, acquire your object context, the key to every Transaction Server transaction:
// get our object context
hr = GetObjectContext(&pObjectContext);
if (!SUCCEEDED(hr)) goto Error;
Next, verify that if the transfer amount is over $500, then the "Managers" role is required to perform the action:
if (lAmount > 500 || lAmount < -500) {
BOOL bInRole;
BSTR bstrRole;
bstrRole = SysAllocString(L"Managers");
hr = pObjectContext->IsCallerInRole(bstrRole,
&bInRole);
SysFreeString(bstrRole);
if (!SUCCEEDED(hr)) goto Error;
if (!bInRole) {
*pbstrResult = SysAllocString(
L"Need 'Managers' role for amounts over $500");
goto Error;
}
}
Using the roles, you can tap into the simple yet powerful security model built into Microsoft Transaction Server. This security builds cleanly on top of that security already provided by Windows NT and DCOM. Using the defined roles, you can extend this model in any custom-defined way, including some very sophisticated rules-based security driven by database tables.
MTS administrative securityIn order to credibly complete the security picture for MTS, you should assign MTS Administrative privileges only to authorized users. Highlight the System package under "Packages Installed." Enable authorization checking for this package as you did with the Sample Bank. Under the Administrator Role, assign appropriate groups and users that you wish to administer MTS. For example, in Figure 10, I've assigned Domain Admins and the Local Administrator groups. You have some flexibility in assigning what type of user can administer MTS on this machine and in restricting the administrative scope that this user has been granted. Please be careful when you do this, as you could lock yourself out forever from administering MTS.
Security scalabilityNow for a bit of bad news. Your components as they've been defined thus far won't participate well in object pooling. ODBC connections and other resources called for by the components won't pool. Scalability will suffer. Performance of your components will plummet under heavy multi-user load. A plague and pestilence will fall upon your house. Just what kind of simplicity is this, anyway?
You see, in order for objects to pool (and thus be re-used by other people), the object instances must be "identical." This "identical" nature includes the security context under which the component is instantiated. We can make the objects "identical" from a security context perspective by assigning a Package User to the Sample Bank package. In User Manager for Domains, define a user named "SampleBank PackageUser" to your Domain and assign the necessary privileges for this User. Head to the Identity tab of your Sample Bank Package properties sheet and define the user as shown in Figure 11.
Assigning a Package User has several other benefits from the Microsoft SQL Server perspective:
Figure 10. Administrative roles assigned to the system package.
Figure 11. Set up a package user so that your objects can be pooled.
Integrated security with SQL Server is beyond the scope of this article, but drop me an e-mail and I can walk you through the details of setting this up.
Further informationWell, that just about covers all the questions I've received regarding the security issue with Microsoft Transaction Server. I hope they've been answered for you as well.
I strongly encourage you use Microsoft Transaction Server as your Business Service (middle tier) mechanism for infrastructure and deployment. It gives you so much—for free! What better offer have you had lately? Microsoft Transaction Server 2.0 is part of the NT Option Pack, a free download from Microsoft. Visit http://www.microsoft.com/ntserver for more details.
Ed Musters, MCSD, is a Partner at Sage Information Consultants Inc. Visit the Sage Web page at http://www.sageconsultants.com. emusters@sageconsultants.com.