NGWS SDK Documentation  

This is preliminary documentation and subject to change.
To comment on this topic, please send us email at ngwssdk@microsoft.com. Thanks!

Managing Identity and Role Information

There are number of scenarios we must be concerned with that impact the creation and management of identity/role information. This section discusses the requirements and design for handling each of these. We briefly summarize the situations of concern below. The subsequent sections expand on how these are handled.

  1. Unmanaged code has determined the Principal & Identity objects useful for this application and wants to set them prior to calling into the managed application code. In this case, the unmanaged code must be able to set the desired reference to the Principal object for the current thread of execution prior to calling the managed code entry point.
  2. The unmanaged code developer know that the entry into managed code is always to some highly trusted (i.e., an ASP+ handler) managed object that sets the correct Principal object reference. In this case, we should not construct default Principal and Identity objects.
  3. The managed application code knows it handles requestor authentication and will create the correct Principal & Identity objects, attaching the Principal object to the current execution thread prior to any use of such objects. Again, we should not construct default Principal and Identity objects.
  4. The application relies on a worker thread pool. A thread will pick up an asynchronous completion event and then transition into managed application code in the correct AppDomain. In general, the application will want the Principal object associated with the asynchronous call to be attached to new worker thread.
  5. The host doesn’t know what Principal & Identity info the app may want nor if the app performs its own authentication services. In this case, we must be prepared to compute appropriate default Principal and Identity objects and attach the Principal to the thread.
  6. Managed code creates a new Context in the current AppDomain which needs to have the appropriate Principal and Identity objects associated with it.
  7. Managed code creates a new execution thread which needs to have the appropriate Principal and Identity objects associated with it.
  8. Managed code does a remote object call to another AppDomain in the same process, an AppDomain executing in a different process, or an AppDomain executing on a different machine. The appropriate Principal and Identity objects needs to be available to the called code.
  9. The managed code application is designed to extend an existing COM+1.0 application and compatibility with COM+1.0 security semantics is required.

Creating the Initial Principal and Identity Objects

To support role-based Security, the NGWS runtime infrastructure must provide a means for managed code to inquire about the identity and/or role of entity on whose behalf the application is acting. The Principal object, exposing the identity and role information through public properties and methods, supports this. Effectively, this means we must know what Principal object should be associated with each execution thread transitioning into a given AppDomain.

One option for determining this is to have the calling code supply this information just prior to transitioning into managed code. If the code is sufficiently trusted this should be allowed. For example, we support scenarios where the trusted host has access to authentication information prior to calling into managed code within an AppDomain.

A second option is that we simply create default objects representing the identity and role information based on an AppDomain specific policy. There are two options that must be supported.

We default to the first option since it is generally dangerous to give potentially hostile code access to information about OS account names, roles, etc. In a typical situation involving mobile Internet code, this could allow a user’s log-on name to be communicated back to the code’s site opening up a potential attack. But there are also situations where an application has legitimate requirements to access such information. Typically, these applications would be more trusted and reside on the local machine.

The NGWS runtime will support these options through a global AppDomain policy setting. A Trusted Host may override the default policy specifying use of Principal and Identity objects for the unauthenticated entity. The implementation defers construction of default Principal and Identity objects until the first attempt to reference them. Constructing these objects can be expensive, especially if it requires accessing an NT account token. Many applications will never check identity or role information, so we only do this work when absolutely necessary. This means that no special handling is required for scenarios where managed application code will supply the Principal and Identity prior to making and role checks. The act of attaching the Principal to the execution thread automatically overrides the default AppDomain policy.

Irrespective of how the Principal and Identity objects are created, we need to associate them with the executing code. Maintaining the Principal and Identity objects as an attribute of the AppDomain isn’t adequate to meet all needs. Rather, these objects need to be bound to an NGWS runtime execution Context within the AppDomain. Asynchronous execution models, such as implemented by ASP+, drive this requirement. The runtime supports this model by allowing certain context properties to flow between the threads serially assigned to processing a request is based on CallContexts. By attaching a Principal object reference to the CallContext we fit into this general architecture. Note that it isn’t necessary to attach the Identity object to the CallContext since the Principal object contains a reference to it. This design doesn’t present any unusual problems since a default context is created with an AppDomain, so there is always one available to accept the Principal object.

Context Transitions

A given AppDomain may contain multiple contexts. This raises the issue of how to handle the Principal object when creating a new context within managed code. One could insert a reference to caller’s Principal object on transition into a callee’s context, or create a new Principal object for each context. A single Principal object referred to by multiple contexts has several advantages:

However, it also has disadvantages:

The advantages of maintaining a single Principal object outweigh the potential disadvantages. There is limited overhead in references to an object across contexts if it is declared marshal-by-value. Given that Principal object references will typically be infrequent, this approach should be more efficient than cloning the Principal object on each context creation and managing changes to multiple contexts when an application needs to change the valid Principal object.

We also need to properly handle the Principal object when creating a new thread within an AppDomain. When a new thread is created, a CallContext will be created for the new thread. We will automatically copy the Principal object reference from the creating thread to the new threads CallContext. This provides the new thread with the required Principal and Identity objects. There may be certain pathological cases where it is difficult to determine the Principal object of the creator when a new thread is started. In such cases, we fall back to the default AppDomain policy for Principal and Identity object creation.

Replacing the Principal Object in Managed Code

It must be possible for managed application code to replace the Principal object for a given thread. This is necessary in those case where an application supplies managed code authentication services. This capability is security critical, since the Principal object affects subsequent authorization actions based on identity/role information. Hence, any code attaching Principal objects to the current Context must be trusted by the application calling it. We use Code Access Security to provide a means of expressing this trust and restricting access to manipulation of the Principal object reference in the CallContext. Only Assemblies granted the System.Security.Permissions.SecurityPermission(ControlPrincipal) permission will be able to perform this operation. This permission does not impact the ability to create Principal objects or the ability to perform role-based security checks.

Principal object lifetimes are handled in exactly the same manner as any other managed object. Once all references to the object are released, they are subject to garbage collection. This does mean an application may need to free Principal object references when replacing the active Principal objects.

Impersonation and Revert Operations

A natural question to ask is the relationship between the Identity object and impersonation/revert operations under Windows NT. There is no required coupling between an Identity object and the NT process token under which a thread is currently executing. If the Identity object is a WindowsIdentity object, then it is possible the Identity object will represent an impersonatable NT token.

Given a WindowsIdentity object, and sufficient NT privilege, a thread can use this object to impersonate the referenced account. This simply requires calling the Impersonate method on the WindowsIdentity. Doing an impersonation does not change the Principal object associated with the current CallContext. Reverting to self is equally simple and also does not alter the Principal object for the current CallContext.

Object Remoting

Object remoting introduces additional considerations on the management of Principal objects. Within the NGWS runtime, object remoting is generally used to describe the process of calling a method on a class when the code is not running in the current AppDomain. Hence, it includes calls that are to:

When doing object remoting, the called code may be interested in performing authorization actions based on the entity identity/roles associated with the calling code. A simplistic approach to addressing this requirement is to simply “flow” the Principal object associated with the caller’s Context to the callee’s Context. Unfortunately, other considerations make this unworkable as a general solution.

Remoting to a Different Machine

Consider the case where the call is between objects on different machines. Copying of the Principal object to the callee’s machine raises both a trust issue and usability issue. The Principal object contains information about a entity’s identity and roles, but these were generated by trusted code on the caller’s system based on some form of authentication Credentials. The Principal object doesn’t provide the callee with access to the authentication Credentials and even if it did there is no guarantee it would resolve these credentials to the same identity and roles. Hence, there is no reason for the callee to believe the information contained in the Principal object. To make this approach viable would require cross-machine trust between the NGWS runtimes, an infrastructure for understanding cross-machine Authentication policy, and a secure channel for passing the Principal object between the systems. The full span of required mechanisms are not availablein the NGWS runtime V1 product.

There are also potential usability issues. If the callee’s Identity object (accessible via the Principal object) represents an abstraction of a Windows OS token, there is no way to preserve the original semantics when copying since Windows security tokens are machine dependent. Other specialized application-defined Identity objects may exhibit similar problems.

In addition, the NGWS runtime is required to support interoperability with existing systems. Hence, objects on a remote system may be called by unmanaged code. This only requires the callee to properly format and transmit a message that is understood by the caller. For such cases, it is unreasonable to force applications to support a complex infrastructure for transmitting trusted Principal objects between machines.

In consequence, Principal objects are not be transmitted between machines. Rather, we require the appropriate entity Credentials (as defined by the called application) be transmitted so the correct Principal and Identity objects can be constructed for the caller’s Context. In some cases, the remoting infrastructure may be able to automatically determine the correct Credentials to use. Examples include Kerberos delegation or PublicKey/Certificate-based authentication when only a single valid entity Certificate exists. In other cases, this may require user interface code to request entity Credentials (name/password, correct Certificate to use, and so forth).

Remoting to a Different Process

In this case, one is concerned about remoting to an object running in a different process but on the same machine. It is similar to the cross machine case in that both processes must be running, the AppDomains created and the caller and callee objects instantiated prior to the call being made. This means the caller already has a Context with a Principal object at the time of the remote call.

But since one is communicating between two processes on the same machine the trust and usability issues associated with the cross-machine case are largely mitigated. Since each process may be running a different version of the NGWS runtime, they may still have different policies in effect.

In consideration of these factors, we use exactly the same model as the remote machine case. Specifically, this approach:

Remoting within the Same Process

This case further simplifies the potential issues in passing identity/role information since we know the Process is running under a single security policy, there is only one version of the NGWS runtime, and the Principal object can easily be referenced across the two AppDomains. In addition, it would be unusual to expect code designed to run in-process to perform its own Authentication services.

Given these factors, it isn’t necessary to use the same approach as for the cross-Process and cross-Machine situations. Rather we will use a very straightforward mechanism:

This is the only behavior supported and no application specific configuration is provided.

COM+1.0 Interoperability

The NGWS runtime supports managed code interoperability with COM+1.0 security services as discussed in the subsequent paragraphs. Interoperability with the older MTS functionality, only available on NT 4, is not directly supported from managed code though it is accessible using unmanaged code interoperability. This decision was made due to the more limited deployment of MTS along with a number of functional limitations (i.e., the inability to use security services from inside the caller’s process).

COM+1.0 security services can only be used by managed code on Windows2000 systems. Using these services requires the managed application code be exposed as COM objects and registered with the COM+1.0 registration database. COM+1.0 then transparently tracks the ‘context’ associated with the code and maintains the mapping between the process token account and application-defined roles.

To make managed code visible to COM+1.0 services requires it be marked with the ComEmulate custom attribute. This insures all calls into this code are made using COM-compatible mechanisms. Developers should be aware that calls into other managed code objects not marked ComEmulate are opaque to COM+1.0 services. Basically, they are treated the same as COM component calls into non-COM DLLs.