Client-server authentication - using SSPI?

You may ask: "How does the server confirm a client are who they say they are?"

Answer: If all the roundtrips of handshake could be finished successfully, i.e. both

  • InitializeSecurityContext returns "OK"
  • AcceptSecurityContext returns "OK"

it means the client's Windows login credentials have been confirmed to be real.

AcceptSecurityContext outputs a CtxtHandle security context (through the 6th parameter).

This context handle includes the client's Windows login username. The server can get the client's windows username by calling QueryContextAttributesEx:

SecPkgContext_NativeNames pinfo;
QueryContextAttributesEx(&m_securitycontext, SECPKG_ATTR_NATIVE_NAMES, &pinfo);

This populates a Native Names structure:

   SEC_CHAR *sClientName;
   SEC_CHAR *sServerName;

the value pinfo.sClientName is the client's real login user name.

Note: The previous handshakes already guarantee the truth of security context, so the server would believe pinfo.sClientName is just the client's real windows username.


SSPI is the right approach for this. The API isn't too hard to use, but does require a decent-sized project to wrap into C#.

In the process of researching the necessary bits to solve this question, I wrote a project to provide SSPI in .Net. Below I describe the basics of interfacing with the Windows SSPI API so that anybody may replicate my results. If you find yourself wanting to use SSPI in .Net, I may suggest you use the project I created to solve this:

NSspi - A .Net interface to the SSPI API

SSPI provides you raw byte arrays containing authentication tokens that you then decide how to transmit - be it over a socket with binary-formatted messages, a custom XML channel, .Net Remoting, some form of WCF, heck, even a serial port. You get to decide how to deal with them. With SSPI a server can authenticate clients, securely identify the client, and even perform basic message handling procedures like encryption/signing using the security context established with the client.

The SSPI API is documented here: SSPI API overview

Specifically take a look at the following functions:

  • AcquireCredentialsHandle
    • Acquires a handle to some form of credentials (eg, the current user's logon). Used by servers and clients.
  • InitializeSecurityContext
    • Used by clients to establish a security context with a server.
  • AcceptSecurityContext
    • Used by servers to establish a security context with a client.

The typical workflow is that each side will initialize their credentials using AcquireCredentialsHandle. The authentication cycle then starts and progresses as follows:

  • The client invokes InitializeSecurityContext, providing no input tokens, which returns output tokens in the form of a byte array. ISC returns 'ContinueNeeded' to indicate that the authentication cycle is not complete.
  • The client sends the tokens to the server by whichever means it desires.
  • The server feeds the received tokens as input to AcceptSecurityContext and produces its own output tokens. ASC also returns 'ContinueNeeded' to indicate that the authentication cycle is not complete.
  • The server then sends its output tokens to the client.
  • The client provides the servers tokens as input to InitializeSecurityContext, which returns new output tokens.
  • The client sends his new output tokens to the server.
  • ...

This cycle continues until the client sees InitializeSecurityContext return 'OK' and the server sees AcceptSecurityContext return 'OK'. Each function may return 'OK' and still provide an output token (as indicated by a non-null return), to indicate that it still has to send data to the other side. This is how the client knows that its half is done but the server's is still incomplete; and vice versa if the server completes before the client. Which side completes first (returns 'OK') depends on the specific security package being used under the hood by SSPI, and any SSPI consumer should be aware of this.

The information above should be enough for anybody to being interfacing with the SSPI system in order to provide 'Windows Integrated Authentication' in their application and replicate my results.

Below is my earlier answer as I learned how to invoke the SSPI API.

I had forgotten about this question, and coincidentally returned to this problem a few days ago on a whim. I do need to solve this problem in a year or two though :)

It is possible in .Net, and I am currently developing a .Net SSPI wrapper that I intend to publish.

I'm basing my work off of some SSPI samples from Microsoft I found.

The sample contains a C++/CLI managed assembly that implements the necessary parts of the SSPI API (in the folder Microsoft\Samples\Security\SSPI\SSPI extracted from the REMSSPI.exe file). They then have two UIs, a client application and a server application, both written in C# that make use of this API to perform SSPI authentication.

The UIs make use of the .Net remoting facility to tie it all together, but if I understand the SSPI API correctly, the only information that the client and server need to exchange consists of byte[]s containing security context token data, which can easily be integrated into whatever communications infrastructure you want; in my case, a binary protocol of my own design.

Some notes on getting the sample to work - they have the 'SSPI' library source, which best compiles under VS 2005, though I've gotten it to work under 2008; 2010 or above would require some rework since they use language constructs that were deprecated. You may also need to modify header files that are part of your platform SDK, because they make use of const pointer assignments to unconst variables, and I don't know a better way to make the compiler happy (I've never used C++/CLI before).

They do include a compiled SSPI dll in the Microsoft\Samples\Security\SSPI\bin folder. To get the client/server binaries to work, you have to copy that dll to their bin directory, else the fail assembly resolution.

So to summarize:

  • Go here to download the REMSSPI.exe sample self-extracting zip.
  • Extract the REMSSPI.exe file (twice..)
  • Microsoft\Samples\Security\SSPI\
    • bin\ - contains compiled dll Microsoft.Samples.Security.SSPI.dll
    • SSPI\ - contains source to dll
    • Sample\ - contains UI source code
      • bin\ - Contains build UI samples. Copy the SSPI.dll file here and run ControlPanel.Client.exe and ControlPanel.Server.exe