1
Fork 0

Add low-level support for managing wildcard user.

This commit is contained in:
Juliusz Chroboczek 2024-05-03 20:42:51 +02:00
parent f0ebf4d63c
commit d29d14da16
3 changed files with 106 additions and 50 deletions

View File

@ -602,31 +602,49 @@ func GetUsers(group string) ([]string, string, error) {
return users, makeETag(desc.fileSize, desc.modTime), nil return users, makeETag(desc.fileSize, desc.modTime), nil
} }
func GetSanitisedUser(group, username string) (UserDescription, string, error) { func GetSanitisedUser(group, username string, wildcard bool) (UserDescription, string, error) {
if wildcard && username != "" {
return UserDescription{}, "",
errors.New("wildcard with username")
}
desc, err := GetDescription(group) desc, err := GetDescription(group)
if err != nil { if err != nil {
return UserDescription{}, "", err return UserDescription{}, "", err
} }
var u UserDescription
if wildcard {
if desc.WildcardUser == nil {
return UserDescription{}, "", os.ErrNotExist
}
u = *desc.WildcardUser
} else {
if desc.Users == nil { if desc.Users == nil {
return UserDescription{}, "", os.ErrNotExist return UserDescription{}, "", os.ErrNotExist
} }
u, ok := desc.Users[username] ok := false
u, ok = desc.Users[username]
if !ok { if !ok {
return UserDescription{}, "", os.ErrNotExist return UserDescription{}, "", os.ErrNotExist
} }
}
u.Password = Password{} u.Password = Password{}
return u, makeETag(desc.fileSize, desc.modTime), nil return u, makeETag(desc.fileSize, desc.modTime), nil
} }
func GetUserTag(group, username string) (string, error) { func GetUserTag(group, username string, wildcard bool) (string, error) {
_, etag, err := GetSanitisedUser(group, username) _, etag, err := GetSanitisedUser(group, username, wildcard)
return etag, err return etag, err
} }
func DeleteUser(group, username, etag string) error { func DeleteUser(group, username string, wildcard bool, etag string) error {
if wildcard && username != "" {
return errors.New("wildcard with username")
}
groups.mu.Lock() groups.mu.Lock()
defer groups.mu.Unlock() defer groups.mu.Unlock()
@ -634,28 +652,43 @@ func DeleteUser(group, username, etag string) error {
if err != nil { if err != nil {
return err return err
} }
if wildcard {
if desc.WildcardUser == nil {
return os.ErrNotExist
}
} else {
if desc.Users == nil { if desc.Users == nil {
return os.ErrNotExist return os.ErrNotExist
} }
_, ok := desc.Users[username] _, ok := desc.Users[username]
if !ok { if !ok {
return os.ErrNotExist return os.ErrNotExist
} }
}
oldetag := makeETag(desc.fileSize, desc.modTime) oldetag := makeETag(desc.fileSize, desc.modTime)
if oldetag != etag { if oldetag != etag {
return ErrTagMismatch return ErrTagMismatch
} }
if wildcard {
desc.WildcardUser = nil
} else {
delete(desc.Users, username) delete(desc.Users, username)
}
return rewriteDescriptionFile(desc.FileName, desc) return rewriteDescriptionFile(desc.FileName, desc)
} }
func UpdateUser(group, username, etag string, user *UserDescription) error { func UpdateUser(group, username string, wildcard bool, etag string, user *UserDescription) error {
if wildcard && username != "" {
return errors.New("wildcard with username")
}
if user.Password.Type != "" || user.Password.Key != nil { if user.Password.Type != "" || user.Password.Key != nil {
return errors.New("user description is not sanitised") return errors.New("user description is not sanitised")
} }
groups.mu.Lock() groups.mu.Lock()
defer groups.mu.Unlock() defer groups.mu.Unlock()
@ -663,11 +696,21 @@ func UpdateUser(group, username, etag string, user *UserDescription) error {
if err != nil { if err != nil {
return err return err
} }
var old UserDescription
var ok bool
if wildcard {
if desc.WildcardUser != nil {
ok = true
old = *desc.WildcardUser
}
} else {
if desc.Users == nil { if desc.Users == nil {
desc.Users = make(map[string]UserDescription) desc.Users = make(map[string]UserDescription)
} }
old, ok = desc.Users[username]
}
old, ok := desc.Users[username]
var oldetag string var oldetag string
if ok { if ok {
oldetag = makeETag(desc.fileSize, desc.modTime) oldetag = makeETag(desc.fileSize, desc.modTime)
@ -681,11 +724,20 @@ func UpdateUser(group, username, etag string, user *UserDescription) error {
newuser := *user newuser := *user
newuser.Password = old.Password newuser.Password = old.Password
if wildcard {
desc.WildcardUser = &newuser
} else {
desc.Users[username] = newuser desc.Users[username] = newuser
}
return rewriteDescriptionFile(desc.FileName, desc) return rewriteDescriptionFile(desc.FileName, desc)
} }
func SetUserPassword(group, username string, pw Password) error { func SetUserPassword(group, username string, wildcard bool, pw Password) error {
if wildcard && username != "" {
return errors.New("wildcard with username")
}
groups.mu.Lock() groups.mu.Lock()
defer groups.mu.Unlock() defer groups.mu.Unlock()
@ -697,6 +749,12 @@ func SetUserPassword(group, username string, pw Password) error {
return os.ErrNotExist return os.ErrNotExist
} }
if wildcard {
if desc.WildcardUser == nil {
return os.ErrNotExist
}
desc.WildcardUser.Password = pw
} else {
user, ok := desc.Users[username] user, ok := desc.Users[username]
if !ok { if !ok {
return os.ErrNotExist return os.ErrNotExist
@ -704,5 +762,6 @@ func SetUserPassword(group, username string, pw Password) error {
user.Password = pw user.Password = pw
desc.Users[username] = user desc.Users[username] = user
}
return rewriteDescriptionFile(desc.FileName, desc) return rewriteDescriptionFile(desc.FileName, desc)
} }

View File

@ -255,27 +255,31 @@ func TestWritableGroups(t *testing.T) {
nil, "Test", err, desc.AllowAnonymous, nil, "Test", err, desc.AllowAnonymous,
) )
} }
testUser(t, "jch", false)
testUser(t, "", true)
}
_, _, err = GetSanitisedUser("test", "jch") func testUser(t *testing.T, username string, wildcard bool) {
_, _, err := GetSanitisedUser("test", username, wildcard)
if !errors.Is(err, os.ErrNotExist) { if !errors.Is(err, os.ErrNotExist) {
t.Errorf("GetSanitisedUser: got %v, expected ErrNotExist", err) t.Errorf("GetSanitisedUser: got %v, expected ErrNotExist", err)
} }
err = UpdateUser("test", "jch", "", &UserDescription{ err = UpdateUser("test", username, wildcard, "", &UserDescription{
Permissions: Permissions{name: "observe"}, Permissions: Permissions{name: "observe"},
}) })
if err != nil { if err != nil {
t.Errorf("UpdateUser: got %v", err) t.Errorf("UpdateUser: got %v", err)
} }
user, token, err := GetSanitisedUser("test", "jch") user, token, err := GetSanitisedUser("test", username, wildcard)
if err != nil || token == "" || user.Permissions.name != "observe" { if err != nil || token == "" || user.Permissions.name != "observe" {
t.Errorf("GetDescription: got %v %v, expected %v %v", t.Errorf("GetDescription: got %v %v, expected %v %v",
err, user.Permissions.name, nil, "observe", err, user.Permissions.name, nil, "observe",
) )
} }
err = UpdateUser("test", "jch", "", &UserDescription{ err = UpdateUser("test", username, wildcard, "", &UserDescription{
Permissions: Permissions{name: "present"}, Permissions: Permissions{name: "present"},
}) })
if !errors.Is(err, ErrTagMismatch) { if !errors.Is(err, ErrTagMismatch) {
@ -283,7 +287,7 @@ func TestWritableGroups(t *testing.T) {
err) err)
} }
err = UpdateUser("test", "jch", token, &UserDescription{ err = UpdateUser("test", username, wildcard, token, &UserDescription{
Permissions: Permissions{name: "present"}, Permissions: Permissions{name: "present"},
}) })
if err != nil { if err != nil {
@ -291,20 +295,13 @@ func TestWritableGroups(t *testing.T) {
} }
pw := "pw" pw := "pw"
err = SetUserPassword("test", "jch", Password{ err = SetUserPassword("test", username, wildcard, Password{
Type: "plain", Type: "plain",
Key: &pw, Key: &pw,
}) })
if err != nil { if err != nil {
t.Errorf("SetUserPassword: got %v", err) t.Errorf("SetUserPassword: got %v", err)
} }
desc, err = GetDescription("test")
if err != nil || *desc.Users["jch"].Password.Key != "pw" {
t.Errorf("GetDescription: got %v %v, expected %v %v",
err, desc.Users["jch"].Password.Key, nil, "pw",
)
}
} }
func TestSubGroup(t *testing.T) { func TestSubGroup(t *testing.T) {

View File

@ -297,7 +297,7 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string) {
} }
if r.Method == "HEAD" || r.Method == "GET" { if r.Method == "HEAD" || r.Method == "GET" {
user, etag, err := group.GetSanitisedUser(g, user) user, etag, err := group.GetSanitisedUser(g, user, false)
if err != nil { if err != nil {
httpError(w, err) httpError(w, err)
return return
@ -310,7 +310,7 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string) {
sendJSON(w, r, user) sendJSON(w, r, user)
return return
} else if r.Method == "PUT" { } else if r.Method == "PUT" {
etag, err := group.GetUserTag(g, user) etag, err := group.GetUserTag(g, user, false)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
etag = "" etag = ""
err = nil err = nil
@ -329,7 +329,7 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string) {
if done { if done {
return return
} }
err = group.UpdateUser(g, user, etag, &newdesc) err = group.UpdateUser(g, user, false, etag, &newdesc)
if err != nil { if err != nil {
httpError(w, err) httpError(w, err)
return return
@ -341,7 +341,7 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string) {
} }
return return
} else if r.Method == "DELETE" { } else if r.Method == "DELETE" {
etag, err := group.GetUserTag(g, user) etag, err := group.GetUserTag(g, user, false)
if err != nil { if err != nil {
httpError(w, err) httpError(w, err)
return return
@ -352,7 +352,7 @@ func userHandler(w http.ResponseWriter, r *http.Request, g, user string) {
return return
} }
err = group.DeleteUser(g, user, etag) err = group.DeleteUser(g, user, false, etag)
if err != nil { if err != nil {
httpError(w, err) httpError(w, err)
return return
@ -375,7 +375,7 @@ func passwordHandler(w http.ResponseWriter, r *http.Request, g, user string) {
if done { if done {
return return
} }
err := group.SetUserPassword(g, user, pw) err := group.SetUserPassword(g, user, false, pw)
if err != nil { if err != nil {
httpError(w, err) httpError(w, err)
return return
@ -403,7 +403,7 @@ func passwordHandler(w http.ResponseWriter, r *http.Request, g, user string) {
Salt: hex.EncodeToString(salt), Salt: hex.EncodeToString(salt),
Iterations: iterations, Iterations: iterations,
} }
err = group.SetUserPassword(g, user, pw) err = group.SetUserPassword(g, user, false, pw)
if err != nil { if err != nil {
httpError(w, err) httpError(w, err)
return return
@ -411,7 +411,7 @@ func passwordHandler(w http.ResponseWriter, r *http.Request, g, user string) {
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
return return
} else if r.Method == "DELETE" { } else if r.Method == "DELETE" {
err := group.SetUserPassword(g, user, group.Password{}) err := group.SetUserPassword(g, user, false, group.Password{})
if err != nil { if err != nil {
httpError(w, err) httpError(w, err)
return return