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?
The SSPI returns transparent binary large objects. These are passed between the applications, at which point they can be passed to the SSPI layer. Thus, the SSPI enables an application to use various security models available on a computer or network without changing the interface to the security system.
SSPI Authentication. SSPI is a Windows technology for secure authentication with single sign-on. PostgreSQL will use SSPI in negotiate mode, which will use Kerberos when possible and automatically fall back to NTLM in other cases.
SSPI stands for Security Support Provider Interface. The SSPI allows an application to use any of the available security packages on a system without changing the interface to use security services.
Security Support Provider Interface (SSPI) is a component of Windows API that performs security-related operations such as authentication.
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:
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:
bin\
- contains compiled dll Microsoft.Samples.Security.SSPI.dll
SSPI\
- contains source to dllSample\
- contains UI source code bin\
- Contains build UI samples. Copy the SSPI.dll file here and run ControlPanel.Client.exe
and ControlPanel.Server.exe
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:
SecPkgContext_NativeNames { 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With