Client-server authentication - using SSPI?

antiduh picture antiduh · Jun 21, 2013 · Viewed 19.4k times · Source

I'm working on a client-server application and I want the client to authenticate itself to the server using the user's logon credentials, but I don't want the user to have to type in their user name and password. I certainly don't want to be responsible for securely handling passwords. I only need the user to prove to me that they are who they say they are, and then my server can go ahead and grant/deny commands as it pleases.

My users are part of a domain, and so I want to be able to use the logon credentials they created when they logged in.

I'm not using any sort of web services, nor do I want to. I control both the client and server software, and both are written in pure C# and use good ol' sockets for getting work done.

I'd prefer to do this with pure C#/.Net, but I'm open to using unsafe C# and pinvokes to win32 API if it means that I'll get the job done.

I've read a little bit about SSPI in windows, but I'm kind of feeling around in the dark since this sort of application development is new to me.

Does anybody know how to do this? Is SSPI the way? How does one use SSPI from within C#? Is there a .Net-native way so that my code can remain portable?

Answer

antiduh picture antiduh · Jun 19, 2014

Update:

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:

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