MCPcopy
hub / github.com/filebrowser/filebrowser / TestSignupRejectsCollidingNormalizedScope

Function TestSignupRejectsCollidingNormalizedScope

http/auth_test.go:20–71  ·  view source on GitHub ↗

Regression for the username-normalization home-directory collision (GHSA-7rc3-g7h6-22m7): with Signup and CreateUserDir enabled, two distinct usernames that cleanUsername() normalizes to the same directory must not be handed the same home directory. The second registration is rejected.

(t *testing.T)

Source from the content-addressed store, hash-verified

18// usernames that cleanUsername() normalizes to the same directory must not be
19// handed the same home directory. The second registration is rejected.
20func TestSignupRejectsCollidingNormalizedScope(t *testing.T) {
21 root := t.TempDir()
22
23 db, err := storm.Open(filepath.Join(t.TempDir(), "db"))
24 if err != nil {
25 t.Fatalf("failed to open db: %v", err)
26 }
27 t.Cleanup(func() { _ = db.Close() })
28
29 st, err := bolt.NewStorage(db)
30 if err != nil {
31 t.Fatalf("failed to get storage: %v", err)
32 }
33 if err := st.Settings.Save(&settings.Settings{
34 Key: []byte("test-signing-key"),
35 Signup: true,
36 CreateUserDir: true,
37 UserHomeBasePath: "/users",
38 MinimumPasswordLength: 1,
39 }); err != nil {
40 t.Fatalf("failed to save settings: %v", err)
41 }
42
43 server := &settings.Server{Root: root}
44
45 signup := func(username string) *httptest.ResponseRecorder {
46 body := `{"username":"` + username + `","password":"CollidePw12345!"}`
47 req, _ := http.NewRequest(http.MethodPost, "/signup", strings.NewReader(body))
48 rec := httptest.NewRecorder()
49 handle(signupHandler, "", st, server).ServeHTTP(rec, req)
50 return rec
51 }
52
53 // Victim registers first and gets /users/teamone-x.
54 if rec := signup("teamone-x"); rec.Code != http.StatusOK {
55 t.Fatalf("first signup: expected 200, got %d body=%q", rec.Code, rec.Body.String())
56 }
57
58 // Attacker picks a distinct username that normalizes to the same scope.
59 if rec := signup("teamone/x"); rec.Code != http.StatusConflict {
60 t.Fatalf("VULNERABLE: colliding signup expected 409, got %d body=%q", rec.Code, rec.Body.String())
61 }
62
63 // The shared scope must still be owned solely by the first user.
64 owner, err := st.Users.GetByScope("/users/teamone-x")
65 if err != nil {
66 t.Fatalf("expected first user to own the scope: %v", err)
67 }
68 if owner.Username != "teamone-x" {
69 t.Fatalf("scope owner = %q, want teamone-x", owner.Username)
70 }
71}

Callers

nothing calls this directly

Calls 8

NewStorageFunction · 0.92
handleFunction · 0.85
signupFunction · 0.85
CloseMethod · 0.65
SaveMethod · 0.65
GetByScopeMethod · 0.65
OpenMethod · 0.45
StringMethod · 0.45

Tested by

no test coverage detected