filebrowser/auth/proxy_test.go
Henrique Dias cd5749dff8
test(auth): cover per-user scope isolation for proxy and hook provisioning
Unit tests for Settings.CreateUserHome (derives a per-user home, rejects a
colliding scope, preserves an explicit scope) plus proxy and hook regression
tests asserting that with CreateUserDir enabled two provisioned users receive
distinct home directories instead of the server root.

Refs GHSA-j7jh-37pf-mf8h, GHSA-j2fc-28fx-hc8q
2026-07-25 08:16:18 +02:00

123 lines
3.5 KiB
Go

package auth
import (
"net/http"
"testing"
fberrors "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users"
)
type mockUserStore struct {
users map[string]*users.User
}
func (m *mockUserStore) Get(_ string, _ bool, id interface{}) (*users.User, error) {
if v, ok := id.(string); ok {
if u, ok := m.users[v]; ok {
return u, nil
}
}
return nil, fberrors.ErrNotExist
}
func (m *mockUserStore) GetByScope(_ string) (*users.User, error) { return nil, fberrors.ErrNotExist }
func (m *mockUserStore) Gets(_ string, _ bool) ([]*users.User, error) { return nil, nil }
func (m *mockUserStore) Update(_ *users.User, _ ...string) error { return nil }
func (m *mockUserStore) Save(user *users.User) error {
m.users[user.Username] = user
return nil
}
func (m *mockUserStore) Delete(_ interface{}) error { return nil }
func (m *mockUserStore) LastUpdate(_ uint) int64 { return 0 }
func TestProxyAuthCreateUserRestrictsDefaults(t *testing.T) {
t.Parallel()
store := &mockUserStore{users: make(map[string]*users.User)}
srv := &settings.Server{Root: t.TempDir()}
s := &settings.Settings{
Key: []byte("key"),
AuthMethod: MethodProxyAuth,
Defaults: settings.UserDefaults{
Perm: users.Permissions{
Admin: true,
Execute: true,
Create: true,
Rename: true,
Modify: true,
Delete: true,
Share: true,
Download: true,
},
Commands: []string{"git", "ls", "cat", "id"},
},
}
auth := ProxyAuth{Header: "X-Remote-User"}
req, _ := http.NewRequest(http.MethodGet, "/", http.NoBody)
req.Header.Set("X-Remote-User", "newproxyuser")
user, err := auth.Auth(req, store, s, srv)
if err != nil {
t.Fatalf("Auth() error: %v", err)
}
if user.Perm.Admin {
t.Error("auto-provisioned proxy user should not have Admin permission")
}
if user.Perm.Execute {
t.Error("auto-provisioned proxy user should not have Execute permission")
}
if len(user.Commands) != 0 {
t.Errorf("auto-provisioned proxy user should have empty Commands, got %v", user.Commands)
}
if !user.Perm.Create {
t.Error("auto-provisioned proxy user should retain Create permission from defaults")
}
}
// With CreateUserDir enabled, two distinct proxy-authenticated users must each
// receive their own home directory instead of both inheriting the server root.
func TestProxyAuthCreateUserDirIsolatesScope(t *testing.T) {
t.Parallel()
store := &mockUserStore{users: make(map[string]*users.User)}
srv := &settings.Server{Root: t.TempDir()}
s := &settings.Settings{
Key: []byte("key"),
AuthMethod: MethodProxyAuth,
CreateUserDir: true,
UserHomeBasePath: "/users",
Defaults: settings.UserDefaults{
Scope: ".",
Perm: users.Permissions{Create: true},
},
}
auth := ProxyAuth{Header: "X-Remote-User"}
provision := func(name string) *users.User {
req, _ := http.NewRequest(http.MethodGet, "/", http.NoBody)
req.Header.Set("X-Remote-User", name)
u, err := auth.Auth(req, store, s, srv)
if err != nil {
t.Fatalf("Auth(%q) error: %v", name, err)
}
return u
}
alice := provision("alice")
bob := provision("bob")
if alice.Scope == "/" || bob.Scope == "/" {
t.Fatalf("provisioned users inherited the server root: alice=%q bob=%q", alice.Scope, bob.Scope)
}
if alice.Scope == bob.Scope {
t.Fatalf("distinct users must get distinct scopes, both got %q", alice.Scope)
}
if alice.Scope != "/users/alice" {
t.Errorf("expected /users/alice, got %q", alice.Scope)
}
}