4. Identities
All Windows processes run with an authenticated security
identity, and the process hosting a WCF service is no different. The
identity is actually a Windows account whose security token is
attached to the process (and to every thread in the process). However,
it is up to the application administrator to decide which identity to
use. One option is to have the host run with an
interactive user identity; that is, the identity
of the user who launched the host process. An interactive identity is
typically used when self-hosting and is ideal for debugging, because
the debugger will automatically attach itself to the host process when
launched from within Visual Studio. However, relying on an interactive
identity is impractical for deployment on a server machine, where
there will not necessarily be a logged-on user, and if there is a
logged-on user that user may not have the necessary credentials to
perform the requested work. For production deployment, you typically
rely on a designated account, which is a preset
Windows account used primarily by your service or services. To launch
the service under a designated account, you can use the “Run as” shell
option. However, “Run as” is useful only for simple testing. You can
also have an NT service as your host and use the Control Panel
Services applet to assign a designated identity to the host. If you’re
hosting in IIS 5/6 or the WAS, you can use those environments’
configuration tools to assign a designated identity to the process
from the pool.
4.1. The IIdentity interface
In .NET, the IIdentity
interface (from the System.Security.Principal namespace)
represents a security identity:
public interface IIdentity
{
string AuthenticationType
{get;}
bool IsAuthenticated
{get;}
string Name
{get;}
}
The interface lets you know whether the identity
behind the interface is authenticated (and, if so, which
authentication mechanism was used) and allows you to obtain the name
of the identity. Out of the box, WCF takes advantage of three
implementations of IIdentity
offered by .NET: WindowsIdentity,
GenericIdentity, and X509Identity. The WindowsIdentity class represents a Windows
account. The GenericIdentity
class is a general-purpose class whose main use is to wrap an
identity name with an IIdentity. With both GenericIdentity and WindowsIdentity, if the identity name is
an empty string, that identity is considered unauthenticated, and
any other non-zero-length name is considered authenticated. Finally,
X509Identity is an internal class
that represents an identity that was authenticated using an X509
certificate. The identity behind an X509Identity is always
authenticated.
4.2. Working with WindowsIdentity
The WindowsIdentity
class offers a few useful methods above and beyond the mere
implementation of IIdentity:
public class WindowsIdentity : IIdentity,...
{
public WindowsIdentity(string sUserPrincipalName);
public static WindowsIdentity GetAnonymous();
public static WindowsIdentity GetCurrent();
public virtual bool IsAnonymous
{get;}
public virtual bool IsAuthenticated
{get;}
public virtual string Name
{get;}
//More members
}
The IsAnonymous Boolean
property indicates whether the underlying identity is anonymous and the GetAnonymous() method returns an anonymous
Windows identity, typically used for impersonation to mask the real
identity:
WindowsIdentity identity = WindowsIdentity.GetAnonymous();
Debug.Assert(identity.Name == "");
Debug.Assert(identity.IsAuthenticated == false);
Debug.Assert(identity.IsAnonymous == true);
The GetCurrent() static
method returns the identity of the process where it is called. That
identity is always non-anonymous and authenticated:
WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();
Debug.Assert(currentIdentity.Name != "");
Debug.Assert(currentIdentity.IsAuthenticated == true);
Debug.Assert(currentIdentity.IsAnonymous == false);
5. The Security Call Context
Every operation on a secured WCF service has a security
call context. The security call context is represented by the class
ServiceSecurityContext, defined
as:
public class ServiceSecurityContext
{
public static ServiceSecurityContext Current
{get;}
public bool IsAnonymous
{get;}
public IIdentity PrimaryIdentity
{get;}
public WindowsIdentity WindowsIdentity
{get;}
//More members
}
The main use for the security call context is for custom
security mechanisms, as well as analysis and auditing. While it is
presented here in the context of the intranet scenario, all other
secured scenarios have use for the security call context as
well.
Note that in spite of its name, this is the security context of
the call, not the service. Two operations on the same service can
definitely have different security call contexts.
The security call context is stored in the TLS, so every method
on every object down the call chain from the service can access the
security call context, including your service constructor. To obtain
your current security call context, simply access the Current static property. Another way of
accessing the security call context is via the ServiceSecurityContext property of the
OperationContext:
public sealed class OperationContext : ...
{
public ServiceSecurityContext ServiceSecurityContext
{get;}
//More members
}
Regardless of which mechanism you use, you will get the same
object:
ServiceSecurityContext context1 = ServiceSecurityContext.Current;
ServiceSecurityContext context2 = OperationContext.Current.ServiceSecurityContext;
Debug.Assert(context1 == context2);
Warning:
Your service has a security call context only if security is
enabled. When security is disabled, ServiceSecurityContext.Current returns
null.
The PrimaryIdentity property
of ServiceSecurityContext contains
the identity of the immediate client up the call chain. If the client
is unauthenticated, PrimaryIdentityIIdentity with a blank identity. When
Windows authentication is used,
the PrimaryIdentity property will
be set to an instance of WindowsIdentity.
will reference an implementation of
The WindowsIdentity property
is meaningful only when using Windows authentication, and it will
always be of the type WindowsIdentity. When valid Windows
credentials are provided, the WindowsIdentity property will contain the
corresponding client identity and will match the value of PrimaryIdentity.
Note:
The constructor of a singleton service does not have a
security call context, since it is called when the host is launched,
not as a result of a client call.