On 23. 5. 25 23:48, Peter Balogh wrote:
Hi,

The reason I choose the 499 status code, that it was the cleanest way to reroute the 2FA case in auth.c dispatch_auth function
Hard-coding the 401 can also accomplish this
But without that, I have two directions I can take, and I'd appreciate some insight, what should I try next:

1.
I can provide a response with 401 status and valid WWW-Authenticate header where I control the realm string I can use that to intercept the 2FA request in svn_ra_serf__credentials_callback in libsvn_ra_serf util.c, and do the 2FA input That combined with bearer token, that we return could work without modifying serf

2.
I can introduce a new serf__authn_scheme_t, and have a cleaner implementation, but it means serf would have an unofficial auth scheme implementation

I'm all for doing the right thing, working out how to extend the RFC, but I have 0 knowledge or experience doing that I'm happy to help any way I can, but I'd rather not wait for months, before implementing this :)

What do you think, what route should I explore next?
Do I have a change to get the 1. version approved by the svn community?
Do I have a change to get the 2. version approved by the serf community? :)


I guess that you realise by now that there's a large overlap between the two. :)

I just read through RFC 7235 and the way I read this, It's perfectly OK and blessed from on high to use status 401 to require a multi-factor token. The interaction would look like this:

1. Client: sends request to URL
2. Server: responds with 401 + WWW-Authenticate for initial
   username+password authentication, with Subversion's realm=... parameter
3. Client: sends to URL + Authorization with username and password

   (This is how it works now, regardless of authentication type, and
   the client continues to send further requests with the same
   Authorization header. In the multi-factor scenario, what happens
   next is; I'll illustrate with TOTP):

4. Server responds with 401 + "WWW-Authenticate: TOTP realm=..."
5. Client: sends to URL + "Authorization: TOTP 123456" (the time-based PIN)
6. Server: processes the request and responds with a generated token in
   a header (or cookies). The token could be a JWT if we want more
   control or a random token as suggested by Greg.
7. Client sends "Authorization: Bearer <token>" with further requests.


This works for other 2FA schemes, too; for example, in step 4 the server could respond with "WWW-Authenticate: SCRAM challenge=Y2hhbGxlbmdlPw==, realm=..." and in step 5 the client would respond with "Authenticate: SCRAM cmVzcG9uc2Uh", using the shared secret and the challenge to generate the token.

This does not require any changes in Serf and is, as far as I can see, compliant with RFC 7235. But you do need an authentication handler on the server side to handle the second (and third and fourth... there's no reason this would be limited to two factors). Also if you use some random token, the authn handler has to store it and eventually invalidate it; a JWT contains its expiration time, removing the need for a token database on the server, but it's a bit of a pain to implement.

On the Subversion client side, libsvn_ra_serf might have to grow another hook for multi-factor callbacks, and we'd need another authentication provider that would store the shared-secret per realm, similar to what the username provider does now.



Best regards,
Peter

On 2025. 05. 23. 17:28, Branko Čibej wrote:
On 23. 5. 25 17:05, Daniel Sahlberg wrote:
Den fre 23 maj 2025 kl 00:35 skrev Peter Balogh<pe...@svnplus.com>:

Hi,

So basically the patch becomes this
I can't say I like the actual branch condition, but I'm open to
suggestions :)

Hi,

I have not studied the patches in detail but I'm not so sure if I like the idea of Serf special-casing / hardcoding a custom response reason. I feel it would be better to offloading this to Subversion since we control both
ends there.


I agree. Serf is a general-purpose HTTP client, what we're talking about here is application-level behaviour. Serf already offloads authentication to the application, I also can't see a reason why this would be special-cased in Serf.

Also, RFC7235 [1] require a 401 response to send a WWW-Authenticate header - I don't know if it would be possible to use this to send the challenge.

I have to read up on WWW-Authenticate. ISTR that aside from telling the client /how/ to authenticate, it's there also support complex authentication processes.

The response could then be added as a header field. Would it be possible
for the server to return a bearer token (= more or less the same as a
Set-Cookie) that we could store client-side to include on future requests?

I'm surprised that multi-step challenge/response mechanism isn't already standardised in HTTP. True, all the multi-factor schemes I've used to date are for authentication flow in browsers, where the server presents a user interface. For headless cases, things like API tokens tend to be generated in advance through an out of band channel (again, usually through a UI in a browser). App tokens are, again, not multi-factor authentication.

Maybe we will have to invent an HTTP workflow for this, but let's not go it alone. This is, after all, the ASF and there are a few people around that are ... quite knowledgeable about HTTP. I suggest we consult. Worst case, there may be an IETF RFC waiting to be written.

-- Brane


P.S.: I say "worst case" because it should've been written long ago instead of people using status 499 and stuff like that.

Reply via email to