Skip to content
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

Open
pvaartstra opened this issue Jul 17, 2024 · 5 comments
Open

ServerContext not Stateless? #29

pvaartstra opened this issue Jul 17, 2024 · 5 comments

Comments

@pvaartstra
Copy link

pvaartstra commented Jul 17, 2024

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?

@antiduh
Copy link
Owner

antiduh commented Jul 22, 2024

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.

@antiduh antiduh changed the title SeverContext not Stateless? ServerContext not Stateless? Jul 22, 2024
@pvaartstra
Copy link
Author

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.

@antiduh
Copy link
Owner

antiduh commented Jul 22, 2024

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?

@pvaartstra
Copy link
Author

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.

@antiduh
Copy link
Owner

antiduh commented Jul 24, 2024

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?

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):

https://stackoverflow.com/a/24312883/344638

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants