fix(server): first user created should be admin, when using reverse proxy

Fix #3902

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan 2025-04-02 15:01:31 -04:00
parent 2b84c574ba
commit c01eea8224
2 changed files with 55 additions and 1 deletions

View file

@ -292,13 +292,17 @@ func handleLoginFromHeaders(ds model.DataStore, r *http.Request) map[string]inte
user, err := userRepo.FindByUsernameWithPassword(username)
if user == nil || err != nil {
log.Info(r, "User passed in header not found", "user", username)
// Check if this is the first user being created
count, _ := userRepo.CountAll()
isFirstUser := count == 0
newUser := model.User{
ID: id.NewRandom(),
UserName: username,
Name: username,
Email: "",
NewPassword: consts.PasswordAutogenPrefix + id.NewRandom(),
IsAdmin: false,
IsAdmin: isFirstUser, // Make the first user an admin
}
err := userRepo.Put(&newUser)
if err != nil {

View file

@ -292,4 +292,54 @@ var _ = Describe("Auth", func() {
})
})
})
Describe("handleLoginFromHeaders", func() {
var ds model.DataStore
var req *http.Request
const trustedIP = "192.168.0.42"
BeforeEach(func() {
ds = &tests.MockDataStore{}
req = httptest.NewRequest("GET", "/", nil)
req = req.WithContext(request.WithReverseProxyIp(req.Context(), trustedIP))
conf.Server.ReverseProxyWhitelist = "192.168.0.0/16"
conf.Server.ReverseProxyUserHeader = "Remote-User"
})
It("makes the first user an admin", func() {
// No existing users
req.Header.Set("Remote-User", "firstuser")
result := handleLoginFromHeaders(ds, req)
Expect(result).ToNot(BeNil())
Expect(result["isAdmin"]).To(BeTrue())
// Verify user was created as admin
u, err := ds.User(context.Background()).FindByUsername("firstuser")
Expect(err).To(BeNil())
Expect(u.IsAdmin).To(BeTrue())
})
It("does not make subsequent users admins", func() {
// Create the first user
_ = ds.User(context.Background()).Put(&model.User{
ID: "existing-user-id",
UserName: "existinguser",
Name: "Existing User",
IsAdmin: true,
})
// Try to create a second user via proxy header
req.Header.Set("Remote-User", "seconduser")
result := handleLoginFromHeaders(ds, req)
Expect(result).ToNot(BeNil())
Expect(result["isAdmin"]).To(BeFalse())
// Verify user was created as non-admin
u, err := ds.User(context.Background()).FindByUsername("seconduser")
Expect(err).To(BeNil())
Expect(u.IsAdmin).To(BeFalse())
})
})
})