-
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
ServerContext not Stateless? #29
Comments
Hi, sorry but ServerContext is not stateless. When negotiating a connection, you're building a context between the server and a specific client, and it takes several messages to do. It's been a long time since I looked at this, but if I recall correctly, there are modes available to minimize the back-and-forth. Also, for what it's worth, NTLM is being deprecated by Microsoft, and soon. Your only option would be to use Kerberos. |
Given that it is not stateless, how can I save and restore state between HTTP requests? I do not think storing the entire context in application static memory is appropriate because WebAPI is multi-threaded. |
I'm not a web developer, so I don't know. You'll have to store it in a collection in some way that you can relate it back to each request; that's what cookies are for, right? You'll need to manage lifetime, so you don't hold onto the context indefinitely. I would not be surprised if ASP has a better way to do exactly what you're trying to do (I thought ASP supported integrated auth natively?). I wrote this project for a case where I'm not doing http, it was for a case where communication happens over much more primitive systems. Have you looked at NegotiateStream? |
Yes, cookies can be used to persist data between Http requests. But that brings me back to my question: what "data" about a ServerContext needs to be persisted, and how can it be read and restored? You are correct that ASP has a better way to do this - at least for standard authentication. A couple of simple tags in web.config will generally take care of it. But what I am ultimately trying to do is build a Proxy. This requires Proxy Authentication which from what I can tell uses the same mechanics just different header names ("Proxy-Authenticate" and "Proxy-Authorization") rather than . I assume standard authentication is more familiar though, so I hoped to write a simple prototype using Negotiate over standard authentication using SSPI and then modify it for Proxy authentication. I took a look at NegotiateStream and it appears to assume a read/write connected socket. I don't see how it would work with the disconnected Request/Response model of HTTP. |
The SSPI API is an opaque API for having a conversation with a Windows security provider such as NTLM or Kerberos (or the Negotiate meta-package which, after a conversation, chooses for you which one your client is compatible with). Initializing a security context between a client and a server in these protocols is a conversation, thus inherently stateful. All I'm doing is providing you a c# API to make easy to call the Windows SSPI API; if you were doing this yourself, you'd have the same experience. It's not about what ServerContext needs for itself; it's about what SSPI needs. Run the demo program and debug it, you'll see that SSPI asks us to send and receive multiple tokens before it's satisfied. My SO answer here discusses some of the details (InitializeSecurityContext, AcceptSecurityContext): |
I created a minimal WebAPI application, attempting to do Negotiate authentication using the NSSPI library. The first negotiate token I get back from the client (browser or PowerShell) generates a ContinueNeeded status from serverContext.AcceptToken(). I send the generated server token back to the client, but then the next negotiate token I get back from the client throws an exception within serverContext.AcceptToken().
Here is the message flow:
(client:) GET /secure
(server:) HTTP 401
WWW-Authenticate: Negotiate
(client:) GET /secure
Authorization: Negotiate {initial token generated by client}
(server:) HTTP 401
WWW-Authenticate: Negotiate: {server token generated by server.AcceptToken}
(client:) GET /secure
Authorization: Negotiate {presumably a secondary token generated by the client based on the server token}
(server:) HTTP 500
Body: {"Failed to call AcceptSecurityContext. Error Code = '0x80090308' - "The provided authentication token is invalid or corrupted."."}
I'm guessing this has to do with the multi-threaded nature of WebAPI and that the serverContext instance is destroyed between the first step and the second step of authentication. I turns out that if I make the serverContext static, that two-step negotiation works fine. Is SeverContext not stateless? How can I save and restore its state if I need to avoid static members?
The text was updated successfully, but these errors were encountered: