From f3c67f1d716f6ee50af89cfd51a908d962bdc73a Mon Sep 17 00:00:00 2001 From: binwiederhier Date: Sun, 27 Jul 2025 11:02:34 +0200 Subject: [PATCH] Refuse to update manually created users --- cmd/serve.go | 4 ++-- server/config.go | 4 ++-- server/server.go | 4 ++-- user/manager.go | 18 +++++++++++------- user/manager_test.go | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/cmd/serve.go b/cmd/serve.go index 882debdc..7e7e56e1 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -416,8 +416,8 @@ func execServe(c *cli.Context) error { conf.AuthFile = authFile conf.AuthStartupQueries = authStartupQueries conf.AuthDefault = authDefault - conf.AuthProvisionedUsers = authProvisionUsers - conf.AuthProvisionedAccess = authProvisionAccess + conf.AuthProvisionUsers = authProvisionUsers + conf.AuthProvisionAccess = authProvisionAccess conf.AttachmentCacheDir = attachmentCacheDir conf.AttachmentTotalSizeLimit = attachmentTotalSizeLimit conf.AttachmentFileSizeLimit = attachmentFileSizeLimit diff --git a/server/config.go b/server/config.go index 86971e47..5cf0b035 100644 --- a/server/config.go +++ b/server/config.go @@ -95,8 +95,8 @@ type Config struct { AuthFile string AuthStartupQueries string AuthDefault user.Permission - AuthProvisionedUsers []*user.User - AuthProvisionedAccess map[string][]*user.Grant + AuthProvisionUsers []*user.User + AuthProvisionAccess map[string][]*user.Grant AuthBcryptCost int AuthStatsQueueWriterInterval time.Duration AttachmentCacheDir string diff --git a/server/server.go b/server/server.go index 4fcd9ba3..dbe61905 100644 --- a/server/server.go +++ b/server/server.go @@ -201,8 +201,8 @@ func New(conf *Config) (*Server, error) { StartupQueries: conf.AuthStartupQueries, DefaultAccess: conf.AuthDefault, ProvisionEnabled: true, // Enable provisioning of users and access - ProvisionUsers: conf.AuthProvisionedUsers, - ProvisionAccess: conf.AuthProvisionedAccess, + ProvisionUsers: conf.AuthProvisionUsers, + ProvisionAccess: conf.AuthProvisionAccess, BcryptCost: conf.AuthBcryptCost, QueueWriterInterval: conf.AuthStatsQueueWriterInterval, } diff --git a/user/manager.go b/user/manager.go index 70d16370..2e176450 100644 --- a/user/manager.go +++ b/user/manager.go @@ -1697,13 +1697,17 @@ func (a *Manager) maybeProvisionUsersAndAccess() error { if err := a.addUserTx(tx, user.Name, user.Hash, user.Role, true, true); err != nil && !errors.Is(err, ErrUserExists) { return fmt.Errorf("failed to add provisioned user %s: %v", user.Name, err) } - } else if existingUser.Provisioned && (existingUser.Hash != user.Hash || existingUser.Role != user.Role) { - log.Tag(tag).Info("Updating provisioned user %s", user.Name) - if err := a.changePasswordTx(tx, user.Name, user.Hash, true); err != nil { - return fmt.Errorf("failed to change password for provisioned user %s: %v", user.Name, err) - } - if err := a.changeRoleTx(tx, user.Name, user.Role); err != nil { - return fmt.Errorf("failed to change role for provisioned user %s: %v", user.Name, err) + } else { + if !existingUser.Provisioned { + log.Tag(tag).Warn("Refusing to update manually user %s", user.Name) + } else if existingUser.Hash != user.Hash || existingUser.Role != user.Role { + log.Tag(tag).Info("Updating provisioned user %s", user.Name) + if err := a.changePasswordTx(tx, user.Name, user.Hash, true); err != nil { + return fmt.Errorf("failed to change password for provisioned user %s: %v", user.Name, err) + } + if err := a.changeRoleTx(tx, user.Name, user.Role); err != nil { + return fmt.Errorf("failed to change role for provisioned user %s: %v", user.Name, err) + } } } } diff --git a/user/manager_test.go b/user/manager_test.go index 94bd1b97..2ce078f3 100644 --- a/user/manager_test.go +++ b/user/manager_test.go @@ -1193,6 +1193,39 @@ func TestManager_WithProvisionedUsers(t *testing.T) { require.Equal(t, "*", users[1].Name) } +func TestManager_DoNotUpdateNonProvisionedUsers(t *testing.T) { + f := filepath.Join(t.TempDir(), "user.db") + conf := &Config{ + Filename: f, + DefaultAccess: PermissionReadWrite, + ProvisionEnabled: true, + ProvisionUsers: []*User{}, + ProvisionAccess: map[string][]*Grant{}, + } + a, err := NewManager(conf) + require.Nil(t, err) + + // Manually add user + require.Nil(t, a.AddUser("philuser", "manual", RoleUser, false)) + + // Re-open the DB (second app start) + require.Nil(t, a.db.Close()) + conf.ProvisionUsers = []*User{ + {Name: "philuser", Hash: "$2a$10$AAAU21sX1uhZamTLJXHuxgVC0Z/GKISibrKCLohPgtG7yIxSk4C", Role: RoleAdmin}, + } + conf.ProvisionAccess = map[string][]*Grant{} + a, err = NewManager(conf) + require.Nil(t, err) + + // Check that the provisioned users are there + users, err := a.Users() + require.Nil(t, err) + require.Len(t, users, 2) + require.Equal(t, "philuser", users[0].Name) + require.Equal(t, RoleUser, users[0].Role) // Should not have been updated + require.NotEqual(t, "$2a$10$AAAU21sX1uhZamTLJXHuxgVC0Z/GKISibrKCLohPgtG7yIxSk4C", users[0].Hash) +} + func TestToFromSQLWildcard(t *testing.T) { require.Equal(t, "up%", toSQLWildcard("up*")) require.Equal(t, "up\\_%", toSQLWildcard("up_*"))