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

View File

@ -255,27 +255,31 @@ func TestWritableGroups(t *testing.T) {
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) {
t.Errorf("GetSanitisedUser: got %v, expected ErrNotExist", err)
}
err = UpdateUser("test", "jch", "", &UserDescription{
err = UpdateUser("test", username, wildcard, "", &UserDescription{
Permissions: Permissions{name: "observe"},
})
if err != nil {
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" {
t.Errorf("GetDescription: got %v %v, expected %v %v",
err, user.Permissions.name, nil, "observe",
)
}
err = UpdateUser("test", "jch", "", &UserDescription{
err = UpdateUser("test", username, wildcard, "", &UserDescription{
Permissions: Permissions{name: "present"},
})
if !errors.Is(err, ErrTagMismatch) {
@ -283,7 +287,7 @@ func TestWritableGroups(t *testing.T) {
err)
}
err = UpdateUser("test", "jch", token, &UserDescription{
err = UpdateUser("test", username, wildcard, token, &UserDescription{
Permissions: Permissions{name: "present"},
})
if err != nil {
@ -291,20 +295,13 @@ func TestWritableGroups(t *testing.T) {
}
pw := "pw"
err = SetUserPassword("test", "jch", Password{
err = SetUserPassword("test", username, wildcard, Password{
Type: "plain",
Key: &pw,
})
if err != nil {
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) {

View File

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