Closed rmunn closed 1 year ago
There's a particular Mercurial behavior that's causing the problem here. Even if you specify a username and password directly in the URL, Mercurial will first send an unauthenticated HTTP request first, and wait for a 401 response before sending the Authorization header. Here's a network capture of the HTTP traffic when I did hg clone http://username:password@localhost:5158/api/v03/sena-3
:
GET /api/v03?cmd=capabilities HTTP/1.1
Accept-Encoding: identity
accept: application/mercurial-0.1
host: localhost:5158
user-agent: mercurial/proto-1.0 (Mercurial 6.1.1)
HTTP/1.1 401 Unauthorized
Content-Length: 0
Date: Tue, 30 May 2023 03:06:42 GMT
Server: Kestrel
WWW-Authenticate: Bearer
lexbox-version: dev
Note that the server is responding with WWW-Authenticate: Bearer
, not Basic
. Somehow the "AuthorizationPolicy": "UserHasAccessToProject"
line in proxy.appsettings.json is failing to send a Basic auth challenge, even though the ProxyKernel code is trying to use the BasicAuthScheme. I don't yet understand why the proxy code is failing to return Basic auth, but that's definitely the root cause of this issue.
Actually, this might stem from something else entirely. LibChorus was originally designed for use with a GUI, and some parts of its design still show through. For example, when you clone a project, if it's a normal Mercurial server it gets the username and password from the URL. But if it's a resumable server, the username and password in the URL are ignored (!!) and the username and password are taken from a config object, which ends up reading a user.config
XML file, instead (!). The design intent appears to be that resumable servers only need to be accessed from FieldWorks, and not from other sources like Language Forge.
I'm currently researching ways to work around this design: whether we can supply the username and password in environment variables somehow, or anything else. But we might just have to do a clone with a non-resumable URL, then only test the Send/Receive with the resumable URL.
The solution looks like this:
var model = new Chorus.Model.ServerSettingsModel();
model.Username = "username";
model.SaveUserSettings();
Chorus.Model.ServerSettingsModel.PasswordForSession = "pass";
Note that the SaveUserSettings()
call must come after the username, but before the password. If you attempt to set the password before saving the user settings, Chorus attempts to encrypt the password on-disk (sensible), using an API that only works on Windows (oops) and you get:
System.PlatformNotSupportedException : Windows Data Protection API (DPAPI) is not supported on this platform.
I'll take a look at my auth code. It should actually be returning WWW-Authenticate: Bearer, Basic
or something like that since they're both supported, but something might be going wrong somewhere.
closed as this was due to not having the proxy setup correctly.
When trying to clone the Sena-3 project via Mercurial directly at the command-line, I was able to get an error message that told me why one of the SendReceive tests wasn't failing:
The username and password were correct. But the ASP.Net auth service returned a JWT challenge (auth scheme "Bearer") and Mercurial doesn't know how to handle that. We need to have the auth service for the SyncReceiveProxy set up to challenge with auth scheme "Basic", and then Mercurial will be able to clone (and pull, and push) projects.
Note that I used a modern Mercurial version (version 6+) to get this error. Version 3 just returned the uninformative "abort: authorization failed" message, which wouldn't have allowed me to figure out the issue with the auth challenge being Bearer (JWT) rather than Basic.