Application Design Process

Applies To: Windows Server 2003 with SP1

Part of application design is making good choices for roles, tasks and operations. This section gives you information that will help you in your design.

Identifying operations

An operation is a low-level permission that represents privileged actions or capabilities of an application. Operations should be created for each routine, query, method, and so on that comprises a discrete application function which requires access control. An operation alone may not be enough to perform a high-level task and may be required for more than one high-level task, but the operation itself is always executed as a unit and must be secured.

For example, an operation such as ReadOrderInfo alone may not be enough for the high-level task Process Order, but the same routines may be needed for another high-level task, such as Query Order Status. Creating an operation for the set of routines that are required to use the order controls allows finer permission specification. The more precisely the operations are defined, the more flexibility you have when managing permissions. However, operations that are defined too precisely make administration more complex.

For many resource managers, operations correspond to securable routines, procedures, or queries that operate on data or resources. The operations may be low-level and meaningful only to the application developer. To create permissions that are meaningful to administrators, the application developer can group low-level operations into Authorization Manager task objects.

Figure 4: Operations and tasks

Art Image

Defining tasks

As stated above, the application should define operations for each routine that will run as a single unit and must be secured. While this allows the application to grant access more precisely, multiple operations may be required to perform a high-level task that the application exposes to the user. In this case, you should determine which operations are required to perform the high-level task and create an Authorization Manager task object for it. This requires some research on the part of the administrator. Task objects are designed to simplify role management by providing meaningful, high-level permission sets that correspond to the application tasks that an administrator would grant a user permission to perform. Therefore, it is important for applications to install with a complete set of tasks required to control access for all uses of the application. Figure 4 illustrates how you can use task objects to combine permissions into high-level tasks.

BizRules

The Authorization Manager task object has the additional ability of dynamically qualifying the permissions granted in a task, based on the result of an attached VBScript or JScript associated with the task. This allows for the access control decision to take into account runtime data, such as the dollar amount of an expense that has been requested or the inventory of a requested item. BizRules are run during the AccessCheck call, and will run in the context of the Web application in the thread calling AccessCheck. If the BizRule returns success, the user receives the requested operations which were associated with the task. If the BizRule fails, the client is not allowed to perform the operations that are associated with the task. The user may be able to perform those operations through a separate task. Parameters are sent to the BizRule through the AccessCheck call, which takes corresponding name and value arrays as its parameters. For example, the first element in the varParameterNames array is the name corresponding to the first element in the varParameterValues array. The BizRule parameter's names array (varParameterValues) must be ordered accordingly so that names and values have the same index.

An applications authorization policy can have many tasks. Each task may or may not have associated BizRules, and new tasks and BizRules may be added by application administrators. At design time, application developers do not know if a call to AccessCheck will need to specify BizRule parameters (since BizRules may not be used for any given call to AccessCheck), so the application must send in the parameters potentially needed by BizRules. To facilitate BizRule developers, applications should define and publish the set of BizRule parameters that are sent into each AccessCheck call.

The type of data that AccessCheck should send as BizRule parameters includes information such as user name and restriction data. Restriction data may include items such as amount limits, account or ID numbers, or a users manager. Any data that may be useful in determining whether or not to grant access at runtime can be used in each AccessCheck call and must be included in the applications list of published BizRules parameters.

BizRules require some scripting knowledge, and therefore it is not appropriate for most administrators to create and modify them. Usually, BizRules should be developed and shipped with the application or provided by the application vendor or other developer later. Since each BizRule that is run invokes the Windows Script Engine, BizRules should be computationally small tasks, such as comparing given parameters or querying a database.

Sample BizRules

Here is a BizRule written in JScript that insures that the time of day is between 9:00 and 17:00, using a 24-hour clock:

AzBizRuleContext.BusinessRuleResult = false; 
dt = new Date(); 
hour = dt.getHours(); 
if (hour > 9 && hour < 17) 
{ 
   AzBizRuleContext.BusinessRuleResult = true; 
} 

To improve performance of BizRules that are called frequently, the results of the BizRule are cached for the life of a client context. Because of this, BizRules are time-sensitive, as in the above example. Applications cache client contexts for appropriately short amounts of time.

Here is a Microsoft Visual Basic Scripting Edition (VBScript) BizRule to make sure an amount that is passed into the BizRule as a parameter named ExpAmount is less than 500:

Dim Amount 
AzBizRuleContext.BusinessRuleResult = FALSE 
Amount = AzBizRuleContext.GetParameter("ExpAmount") 
if Amount < 500 then AzBizRuleContext.BusinessRuleResult = TRUE 

When a BizRule refers to a parameter, AccessCheck caches the parameters, values, and result for a particular BizRule for the life of a client context. This allows improved performance in subsequent AccessCheck calls on the same client context that references the same BizRule with identical values. This means that, if BizRule results can change in subsequent AccessCheck calls without changing the BizRule parameters (as in the time of day BizRule described above), then the cached value may not be the correct value. For this reason, applications using BizRules should free the client context periodically.

Initial roles

Some applications have a small number of hard coded roles, such as Administrator, Reader, and Writer. Such applications would call the Authorization Manager API to create these initial roles at startup time.

Scoping

Authorization Manager scope objects are collections of resources, and can be either simple collections such as C:\My Documents or more collections, such as *.doc. The application must take into consideration what scoping logic it will use. A scope provides great flexibility to the application in how to apply different access control to different resources. Depending on what the application is controlling access to, the collections may vary considerably in form. For example, if an application performs operations on other computers, then a scope may represent collections of computer objects and be named something like Computers in Sales Dept or "Computers Running Windows XP. The only requirement is that the application must be able to map a user request for access to a resource to the scope containing the resource when the access validation is performed.

In addition to logical collections of resources, scopes give applications the flexibility to address complex authorization problems, such as incorporating a "work on behalf" feature into an application. A "work on behalf" feature allows a user to grant other users permission to do work on their behalf. For example, suppose Bob wants to allow James to do work on their behalf. In an application, this could be implemented by creating a scope for Bob in which a role would be defined that specifies the subset of Bobs permissions that James is allowed to use. (James would be assigned to this role.) When James connects and requests permission to perform an operation on behalf of Bob, an AccessCheck operation is performed against the Bob Work on Behalf scope to verify that James has permission to perform the operations on behalf of Bob.

Since scopes are defined by each application and the application will map each access request to the appropriate scope, the application must provide documentation to allow the administrator understand how to create scopes that are named correctly.

Installation

When an application is installed, it can install authorization policy information into a new or existing authorization store by calling the Authorization Manager API. If the application installs its authorization policy into an existing store, the installation process must give the installing user a way to specify the location of the existing store. After initializing the authorization policy store, the install application uses the CreateApplication method to create an application object in the policy store. Then, for each operation, the installation application calls the CreateOperation method. Initial tasks, scopes and roles are installed using the CreateTask, CreateScope, and CreateRole methods, respectively. The following VBScript creates a store and installs the authorization policy for a simple expense application.

'--- Initialize the admin manager object 
Dim pAzManStore 
Set pAzManStore = CreateObject("AzRoles.AzAuthorizationStore") 
'--- Create a new store for expense app 
' 0 = Open store for Access Checking. 
' AZ_AZSTORE_FLAG_CREATE   = 0x1, 
' AZ_AZSTORE_FLAG_MANAGE_STORE_ONLY = 0x2, // cannot do access 
checking. 
' AZ_AZSTORE_FLAG_BATCH_UPDATE      = 0x4, 
pAzManStore.Initialize 1+2+4, "msxml://C:\AzPolicy.xml" 
pAzManStore.Submit 
Dim App1 
Set App1 = pAzManStore.CreateApplication("Expense") 
App1.Submit 
'--- Create operations ----------------------- 
Dim Op1 
Set Op1=App1.CreateOperation("RetrieveForm") 
Op1.OperationID = CLng(61) 
Op1.Submit 
Set Op1=App1.CreateOperation("EnqueRequest") 
Op1.OperationID = CLng(62) 
Op1.Submit 
Set Op1=App1.CreateOperation("DequeRequest") 
Op1.OperationID = CLng(63) 
Op1.Submit 
Set Op1=App1.CreateOperation("UseFormCotnrol") 
Op1.OperationID = CLng(64) 
Op1.Submit 
Set Op1=App1.CreateOperation("MarkFormApproved") 
Op1.OperationID = CLng(65) 
Op1.Submit 
Set Op1=App1.CreateOperation("SendApprovalNotify") 
Op1.OperationID = CLng(66) 
Op1.Submit 
'--- Create tasks ------------------------------ 
Dim Task1 
Set Task1=App1.CreateTask("Submit Expense") 
Task1.AddOperation CStr("RetrieveForm") 
Task1.AddOperation CStr("EnqueRequest") 
Task1.AddOperation CStr("UseFormCotnrol") 
Task1.Submit 
Set Task2 = App1.CreateTask("Approve Expense") 
Task2.AddOperation CStr("MarkFormApproved") 
Task2.AddOperation CStr("SendApprovalNotify") 
Task2.AddOperation CStr("DequeRequest") 
Task2.BizRuleLanguage = CStr("VBScript") 
Task2.BizRule = "Dim Amount" & vbnewline  & _ 
           "AzBizRuleContext.BusinessRuleResult= FALSE" & vbnewline &_ 
           "Amount = AzBizRuleContext.GetParameter( " & Chr(34) &_ 
                              "Amount" & Chr(34) & ")"  & vbNewLine &_ 
           "if Amount < 500 then AzBizRuleContext.BusinessRuleResult= 
TRUE" 
Task2.Submit 
'--- Create role definitions ------------------------------ 
Set Task3 = App1.CreateTask("Expense Admin") 
Task3.AddTask CStr("Approve Expense") 
Task3.AddTask CStr("Submit Expense") 
Task3.IsRoleDefinition = TRUE 
Task3.Submit 
Set Task4 = App1.CreateTask("Expense User") 
Task4.AddTask CStr("Submit Expense") 
Task4.IsRoleDefinition = TRUE 
Task4.Submit 
'--- Create initial scopes and roles ------------------------------ 
'--- only one scope in this app (we may instead choose to use no scope) 
Dim Scope1 
Set Scope1 = App1.CreateScope("AllRoutines") 
Scope1.Submit 
Set RoleA=Scope1.CreateRole("Expense Administrator") 
RoleA.AddTask("Expense Admin") 
RoleA.Submit 
Set RoleB=Scope1.CreateRole("Expense User") 
RoleB.AddTask("Expense User") 
RoleB.Submit 
'--- Demo - add everyone to ExpenseUser Role -------------------------- 
RoleB.AddMemberName("Everyone") 
RoleB.Submit 

Application model

Applications that use Authorization Manager use the trusted subsystem application model described below. Note that, while the two models imply distinct application designs, based on the tradeoff, a particular application may choose to use a hybrid model that contains a trusted subsystem middle tier design and use impersonation to maintain back-end auditing or to interface with legacy back-end resource managers.

Impersonation model

Windows 2000 and earlier versions of Windows NT Server supported the Windows NT impersonation model. In this model, server applications obtain a token for the connected client and impersonate the client token before attempting a secure operation, such as opening a file. The ACL on the file is compared to the users token groups to determine whether or not a user has permission to open the file. While the Windows Server 2003 family enhances support for the impersonation model through the Kerberos extensions of protocol transition and constrained delegation.

Trusted subsystem application model

Authorization Manager adds support for a new trusted subsystem application model to the Windows security infrastructure.

Figure 5: Impersonation model and trusted subsystem model

Art Image

In the trusted subsystem model, the application server account only has enough access so that it can perform all the operations it exposes to clients. When a client requests an operation, the middle-tier application server authorizes the client request based on authorization policy that is specific to the application. If the client has permission to perform the requested operation, the server performs the operation on behalf of the client. In this model, clients do not have direct access to resources. While the impersonation model has its strengths and is appropriate in many cases, the trusted subsystem model has some advantages over the impersonation model.

Management of permissions

In the impersonation model, each client users account is used to access the back-end resource, so the DACLs of all resources must be maintained by granting each user the appropriate level of access. When the number of resources that are secured separately grows, especially when stored on separate back-end computers, management of the DACLs becomes more tedious. For example, you might organize resources into units that are secured in the same way, such as protecting all files in a subtree the same way or organizing users into groups with similar permissions.

In the trusted subsystem model, only the middle-tier service account is used to access the back-end resources; therefore, the DACLs can be simplified by granting only the service account sufficient access to perform all required operations on the objects. A service account should not be given Full Control rights or be a local administrator, but should have just enough permission to perform the applications complete set of operations. Application designers can document the level of permissions the application need on back-end resources. This reduces the management of DACLs, because only the service account requires access to them. The service is given permissions to the resources, so you must trust that the service will not accidentally let one user access resources of another.

Rights ion

With the impersonation model, assigning DACLs to resources to grant users the ability to perform high-level tasks can be difficult. High-level tasks such as Submit Expense or Query Inventory may require several operations on back-end resources. Rights ion is the process of determining precisely which low-level resource permissions are required for high level application operations. It can be time consuming, particularly when many secured resource types are used.

In practice, administrators sometimes grant excessive access to resources to save time. A trusted subsystem application model allows the administrator to grant access only to the service account. Since the access to the resources is broadly given to the service account, determining the correct access is easier: usually the server gives just enough access to perform all operations that the server application may need (as defined by the application designer). The administrator does not have to define and maintain different levels of permissions on DACLs.

Connection pooling

You often can achieve better scalability by connection pooling. Since the impersonation model maintains the user context through the request to a resource server, a separate connection to the resource server is usually required for each user request. If you create a connection for every client, you prevent reuse of a single connection to a resource server, such as a SQL database. A trusted subsystem server application authorizes the client's request and accesses the remote resource for the client in the context of the applications service account. Since a new connection is not required, the application server can use the same connection with resource servers to service requests from different clients.

Controlled access points

Some applications enforce rules and workflow in the application server. In the impersonation model, each client is given appropriate access to each resource. Since the client has access to directly to the resource, they could potentially access the resource though a method other than through the intended applications which could cause undesired access and manipulation of resources.

In the trusted subsystem model, only the application service account has access to resources. This means that users cannot directly gain access to resources through a tool or API. In this model, the application server has more control over how the user sees and manipulates the resources.

Auditing

Auditing allows administrators to examine which users have attempted to gain access to particular resources. Auditing is most authoritative if the audits are generated by the same application that manages the resources. The impersonation model does this by maintaining the users context when it requests access on each system. This allows the remote system to authoritatively log the user and the requested access.

When you use a trusted subsystem application model, the back-end resource managers generate audits that log the servers service account as the account requesting access, not the client user on whose behalf the operation was performed. Authorization Manager provides runtime auditing when the access validation is performed (in other words, when the AccessCheck API is called), but these audits are generated at the application server. Because of this, mapping an access audit on a back-end resource to the user who made the request requires that the audit logs on the application server be correlated with back-end audits. The application server audits can often be more informative than audits made on the back-end resource. From the application server, you can know more about the high-level task that the client is requesting, so a greater degree of the users intent can be recorded in the audits. On the back-end resource managers, only low-level operation requests can be audited, so it may be difficult to determine the users higher-level activities.

Other differences

In the impersonation model, the service account in which the application server runs may have little or no access to resources. To access resources on behalf of the client, the application server must impersonate the clients security context, which the application server can obtain when the client connects to it. When you limit the permissions of the server context, the server is limited to the permissions of the connected client when a successful attack takes place which compromises the server. If an attacker wants to gain broad access to back-end data, they must compromise the server and wait for users to connect. As each user connects to a compromised server, the access of the attacker grows in proportion to the connected users permissions. If a highly-privileged account logs on to the server, such as the applications administrator, the attacker quickly gains permissions to the application data. If client users who have access to resources other than the applications log on to the server, the attacker also gains access to those resources because of the ability to impersonate the client to those resources.

A trusted subsystem server starts out with a high degree of access to application resources so, if the server is compromised, the attacker has broad access to these resources. But since the client is not impersonated, the attacker is limited to the access of the service context (the application's resources). While the attacker gains broad access to application resources, the attacker cannot access non-application resources.