-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GSSAPI support #3
Comments
The SSPI API exposes this through the authentication cycle. Keep in mind that SSPI is supposed to be provider agnostic - the calling code doesn't need to know whether it's working with NTLM tokens, kerberos tokens, or some other system's tokens. The authentication cycle assumes that you already have access to some sort of credential - in Kerberos's case, the credential would be the ticket granting ticket (TGT). So, on the client side, I get a handle to my user's TGT - which was created when the user logged on. On the server side, the service gets a handle to the TGT of whatever principle it's running on, which was created when the service started. From there, the authentication cycle begins. On the client side, there are three pieces of data involved in the authentication cycle.
Note that the client usually starts, and so, on the first invocation we provide null for the server's previous token. On the server side, there are the same three pieces of data:
So the authentication cycle usually progresses as follows:
Depending on how much the two sides need to talk, there could be many iterations of the above cycle. Eventually, one side will return a status 'OK'. That means that, from that side's perspective, it has everything it needs. However, it will still have a token to write to the other side. So the above could continue in one of the two following manners:
or
In short: If ISC or ASC returns a token, then you have to write that to the other side, regardless of what status ISC or ASC return. So how does kerberos fit into this design? Well, the client doesn't have to specify the principle name of the server he wants to connect to; it's an optional parameter to the Well, you ask him. So:
That process may be more or less complicated, depending on circumstances and parameters. If you use the negotiate package, then the first couple tokens to be exchanged between the client and server will be queries about what security packages they support, and which is the most secure package that they both have. After they settle on the security package, the tokens will be about exchanging principle information and then finally tickets. You can also initialize the However, please keep in mind that the SSPI API uses a custom protocol - it carries kerberos tickets in its payload, but it is not simply the kerberos protocol itself, or at least, you should not assume it is. From the caller's perspective, it's an opaque protocol: you receive a packet, call the function, get an output packet, send it to the other side .. they receive a packet, call a function, get an output to send back ... and so on until the cycle is complete. So far we've discussed the SSPI API - which is a win32 API, and is not my software. the To answer your direct question: we start the cycle in the ClientForm when the user clicks the connect button:
We call the DoInit() function the first time when the button is clicked. That performs the first call to InitializeSecurityContext and then using our own little toy custom protocol, we send the token to the server:
When we receive a packet back from the server, we'll look at what kind of packet it is, and if it's an authentication cycle packet, we'll call DoInit() again:
Hopefully, that answers your question. Please keep in mind the TestClient and TestServer are meant to be demo projects - not production code. Please think twice before copy-and-pasting the code. Additionally, keep in mind that the SSPI API just gives you bytes to transmit, and its up to you to decide how to transmit those bytes. If you look in the NSspi project, there's a Program.cs file that shows how to perform the authentication cycle locally, with the client and server running in the same process. The tokens are 'transmitted' by in memory - we just directly call the next function with the bytes returned from the previous function. |
Please let me know if the above comment answers your question, and if so, I'll close this issue. |
Thanks antiduh for the detailed explanation. I got it now. I'm just following your implementation to get an idea about how SSPI works as I have to develop a C#.net client to consume one of our server's (java) kerberos secured rest proxy with Active Directory as the KDC. Please close the issue. |
Does it implement GSSAPI? In that case, you can use the SSPI API to perform authentication, which means with some modifications you would be able to use Nsspi to implement it. The following page outlines how to invoke the SSPI API to be compatible with GSSAPI: https://msdn.microsoft.com/en-us/library/windows/desktop/aa380496(v=vs.85).aspx If you modified nsspi to take those changes into account, it should work. |
Yes. The requirement is to implement it using GSSAPI. So as I'm developing the client in .NET I can use SSPI, that means some modifications to Nsspi as you said as the client and I can directly use GSSAPI in java server side for this communication flow. Do we need to consider SPNEGO spec [1] separately with our implementation or GSSAPI and SSPI covers that spec too? |
Yeah, that sounds like it should work, so long as Microsoft's claim to be GSSAPI compatible is true. Note, when you go digging through the nsspi code, you're going to run across Constrained Execution Regions (CERs). I've had to manually implement them because the SSPI handle isn't compatible with .Net's SafeHandle class, which normally handles a lot of magic for you in a very concise way. I have a fairly verbose blog article that provides a ground up explanation of CERs, why they're necessary etc. Start here: https://antiduh.com/blog/?q=node/4 |
Thanks antiduh. I will follow the things and will start the implementation. :) |
Hi antiduh, |
I'm not sure how much I'm going to be able to help here. My only advice would be to read the Win32 SSPI documentation thoroughly, dig into what the errors mean, and make sure you follow the above MSDN article on GSSAPI interoperability to the letter. |
Hi, what will be the reason for getting this "The specified principle is not known in the authentication system." error in nsspi. I got it when I'm validating the server token which I got from server side after accepting the TGT of the client. Do you have any idea? |
It probably means that the client doesn't recognize the servers principle name (SPN). If I recall that documentation correctly, you need to perform translation of some of the received tokens before passing to InitializeSecurityContext because Microsoft's kerberos implementation doesn't understand some SPN formats. |
Hi antiduh, |
That's really good news, I'm glad you were able to get it to work. SSPI can be a right pain in the neck sometimes. Would you be willing to contribute back your code? You don't have to (my license says you can do whatever you want with my code and your code), but I'd like to save folks in the future the trouble of reimplementing it themselves. |
Yes antiduh, Sure. I will contribute my code. I have a tight schedule till 1st July. Will contribute the code ASAP. thanks |
@DMHP Can you please contribute (if possible). i have to implement the same for my proxy server authentication. Initially i assumed to support only NTLM but I guess i would have to take both approaches of kerberos and NTLM, as NTLM usually is a fall back mechanism in case kerberos is not available ! |
Hey @DMHP - any news? If you just want to send me a code dump I can sort through it, clean it up; i'd just be happy to have your contributions to add to the project. |
hi @antiduh , I could successfully support the negotiate and ntlm based authentication (win auth) for both proxy server and subsequently win server. However, at customer site the first authentication cycle fails with response coming back as just NEGOTIATE in proxy authenticate header. Ideally it should contain server token as well. Usually I take this token and continue auth cycle. However, this works in my local setup with tmg proxy and iis server running on vms. Customer setup is diff in the sense that they have AD and sso setup I believe. I am just wondering that if I dont use kerberos security package and just sticking to win base auth (negotiate) then would my code still work irrespective of AD DOMAIN setup on customer side? If this is suposed to work fine then I should look for sm other bugs, however, at this point I dont know if there are any other bugs leading to this behavior. also please note that basic auth just works fine at customers place.... Thanks |
Negotiate is a 'meta' package; it's not actually a security system in its own. The real packages are ones like Kerberos and NTLM. When you specify Kerberos/NTLM, you're stating that you have a hard requirement for one or the other. If you pick Kerberos and the other end doesn't support it, the context will probably fail. If you use Negotiate, then both ends will automatically figure out whether they should use Kerberos or NTLM. To you, you'll just be passing back and forth a bunch of opaque tokens and eventually the auth cycle will complete; to them, they're first exchanging tokens to figure out what security package (NTLM, Kerberos) they both support and in what order they prefer them, then which one they'll decide on, then the real tokens for that package. If you want it to work irrespective of customer configuration, use Negotiate; it'll pick Kerberos or NTLM for you automatically. IIRC, most modern AD sites use Kerberos. |
So it means that if I am using negotiate mechanism, and server supports kerberos then server will automatically choose kerberos. But my question is what happens when my code does not support Kerberos. I am not sure about on my side of the code because I am usually giving the target server a proxy server, and uses this API to get the tokens (using windows credentials, domain name etc). I am wondering if my code needs to communicate with KDC (AD in this case i assume) seperately? In a nutshell I am not clear on how client really knows about the KDC ? Is it via the service principle name (SPN). I mean I can print the SPN after this line of code clientCred = new NSspi.Credentials.ClientCredential(packageName, username, password, domain); clientCred.principleName gives me the SPN. |
The question comes down to how your process is acquiring credentials. In the standard situation, you have a client (user) that is part of the same AD as the server. The client logs in, and in doing so, creates kerberos credentials. The server is logged in, and in doing so, creates its kerberos credentials. In the normal circumstance, the program that uses nsspi is only acquiring a handle to existing credentials that SSPI already knows about - credentials that were assigned to your process when the process was started. In your circumstance, it appears that you're creating credentials by calling some sort of kerberos logon - the constructor The client knows about the KDC via system configuration. If you are creating credentials via username/pass, then under the hood, the API is talking to the KDC to get the kerberos creds. I don't know if the code you're using (that ClientCredential constructor overload) is acquiring kerberos creds or NTLM creds. If you're accidentally acquiring NTLM creds, then its possible that auth is failing because the client and the server don't have compatible SSPs. |
Well actually you are right. I had to tweak the code a little as the requirement was that one should be able to provide the winauth credentials (in case the machine is not in a domain but the process has to authenticate with a remote proxy or web server ) with some sort of pop up screen. This was a pain because the credentials of these two machines might be different as they are not monitored by some domain controller. However, this is just one use case which we needed for our testing. We create an HttpRequest class which different clients call to use my API to get the authentication. However, in production case there are no user id, passwords passed internally as they are null. Inside the NSSPI code we check for this and the 5th argument to function AcquireCredentialsHandle is null ptr as in the original NSSPi code .. if (username == null || username.Length == 0)
Now having said that As per my understanding in usual circumstance (also in my case) the SSPi takes care of acquiring credentials for my process and hence kerberos OR NTLM, it should be fine ? (given that I am still using the NSspi.Credentials.ClientCredential(packageName);, which is the original NSSPI code ! |
I'll admit, I'm starting to get a little confused by the back and forth between how you normally use nsspi, and how its used with this customer (and is breaking). If you are attempted to use nsspi on a client to authenticate with a server, then both the client and server must be part of the same kerberos domain. So ultimately your client has to talk to kdcserver.domain.com, and the server ultimately has to talk to kdcserver.domain.com; they need to have TGTs from the same KDC. I'm not sure what other values It would really help if you could fork nsspi and commit your changes so I can see how you're using it, then you could tell me what parts are failing. |
I am sorry for the confusion. I am assembling the instance of SEC_WINNT_AUTH_IDENTITY structure as you have mentioned for that purpose. So basically I was given a task to have following 2 situations
So as you can see that if the client code passes the values of user credentials ( in case the client is not on the same domain and IT IS NTLM based authentication ) then this code works fine. However, if client chooses to use SSPI for automatically figuring out the user credentials then the code works BAU (The original NSSPI flow). I hope It is more clear now. I tested this in my local environment , steps were as following
Flow 2: At Customer environment:
So basically I am wondering if this was the issue with the authentication and credentials, then should not it have failed at the first cycle itself? I know that choosing Negotiate means that client and server automatically choose the best mechanism supported by both ends, which happens to be in this case Kerberos. My doubt is if i need to do something different on my side to support Kerberos? I am suspecting that this is failing because Server supports Kerberos but my code does not ? Thanks for reading this long post !! I hope I made it more clear than last time. |
@antiduh can nsspi be used to implement kerberos authentication in iis . |
It seems this is the only mention of GSSAPI within these posts. Can you be more specific regarding "to take those changes into account"? BTW, I successfully get a negotiated bind between client/server. The encrypt/decrypt fail. When I look at the byte array I receive from the server (150 bytes in total), it is nothing like what your code describes as: 124 /// The structure of the returned data is as follows: My byte array in decimal is: I'm guessing GSSAPI is the issue. |
@hambonewa - GSSAPI is its own standard, separate from SSPI. SSPI can be used compatibly with GSSAPI, but with some tweaks. There's documentation on MSDN that describes it. About the message handling methods - those structures are defined by nsspi, and are not set by any standard. In SSPI, they're treated as separate objects, and perhaps I should've designed nsspi the same way. However, there's nothing stopping you from structuring the data you receive in the way that nsspi expects it. I can't help you if you don't know how your data is structured, however. I hazard a guess that it's specified in the gssapi spec. |
I got the code modified and working. It appears the EncryptMessage is not thread safe. I had to add a lock to call EncryptMessage and to copy the adapter buffers after. And this is where each thread has its own unique context. |
If you like to send me patches, I'd welcome them. If you're not happy with
the state of the code, I can offer to clean them up for you.
Also, I would assume that all of nsspi is not thread safe by default.
Cheers.
…On Wed, Dec 5, 2018, 8:32 PM hambonewa ***@***.*** wrote:
I got the code modified and working. It appears the EncryptMessage is not
thread safe. I had to add a lock to call EncryptMessage and to copy the
adapter buffers after. And this is where each thread has its own unique
context.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#3 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AIvvFGhEe5SzAKEUVrG_gqKWUBdBH3Vlks5u2HOdgaJpZM4I29cE>
.
|
Hi antiduh, I'm following this in the github. In kerberos we have some steps like 1. Client requesting the TGT from KDC 2. Client getting the TGT 3.Client requesting SGT from KDC by using TGT, to access specific service 4. Client getting the SGT 5. Send SGT to resource server 6. Access the resource. Can you please tell me how do you handle the 3rd and 4th steps in the github.com/antiduh/nsspi/blob/master/TestClient/ClientForm.cs. Thanks.:)
The text was updated successfully, but these errors were encountered: