1
Fork 0

Implement FallbackUsers in API.

This commit is contained in:
Juliusz Chroboczek 2024-04-11 13:45:30 +02:00
parent 31a18bcf44
commit 7673a95b05
4 changed files with 80 additions and 0 deletions

View File

@ -55,6 +55,14 @@ on-disk format but without any user definitions or cryptographic keys.
Allowed methods are HEAD, GET, PUT and DELETE. The only accepted Allowed methods are HEAD, GET, PUT and DELETE. The only accepted
content-type is `application/json`. content-type is `application/json`.
### Fallback users
/galene-api/0/.groups/groupname/.fallback-users
Contains fallback user descriptions, in the same format as the
`fallbackUsers` field of the on-disk format. Allowed methods are PUT and
DELETE. The only accepted content-type is `application/json`.
### Authentication keys ### Authentication keys
/galene-api/0/.groups/groupname/.keys /galene-api/0/.groups/groupname/.keys

View File

@ -540,6 +540,18 @@ func GetDescriptionNames() ([]string, error) {
return names, err return names, err
} }
func SetFallbackUsers(group string, users []UserDescription) error {
groups.mu.Lock()
defer groups.mu.Unlock()
desc, err := readDescription(group, false)
if err != nil {
return err
}
desc.FallbackUsers = users
return rewriteDescriptionFile(desc.FileName, desc)
}
func SetKeys(group string, keys []map[string]any) error { func SetKeys(group string, keys []map[string]any) error {
groups.mu.Lock() groups.mu.Lock()
defer groups.mu.Unlock() defer groups.mu.Unlock()

View File

@ -128,6 +128,9 @@ func apiGroupHandler(w http.ResponseWriter, r *http.Request, pth string) {
if kind == ".users" { if kind == ".users" {
apiUserHandler(w, r, g, rest) apiUserHandler(w, r, g, rest)
return return
} else if kind == ".fallback-users" && rest == "" {
fallbackUsersHandler(w, r, g)
return
} else if kind == ".keys" && rest == "" { } else if kind == ".keys" && rest == "" {
keysHandler(w, r, g) keysHandler(w, r, g)
return return
@ -433,6 +436,46 @@ func passwordHandler(w http.ResponseWriter, r *http.Request, g, user string) {
return return
} }
func fallbackUsersHandler(w http.ResponseWriter, r *http.Request, g string) {
if !checkAdmin(w, r) {
return
}
if r.Method == "PUT" {
ctype := parseContentType(r.Header.Get("Content-Type"))
if !strings.EqualFold(ctype, "application/json") {
http.Error(w, "unsupported content type",
http.StatusUnsupportedMediaType)
return
}
d := json.NewDecoder(r.Body)
var users []group.UserDescription
err := d.Decode(&users)
if err != nil {
httpError(w, err)
return
}
err = group.SetFallbackUsers(g, users)
if err != nil {
httpError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
return
} else if r.Method == "DELETE" {
err := group.SetFallbackUsers(g, nil)
if err != nil {
httpError(w, err)
return
}
w.WriteHeader(http.StatusNoContent)
return
}
methodNotAllowed(w, "PUT", "DELETE")
return
}
type jwkset = struct { type jwkset = struct {
Keys []map[string]any `json:"keys"` Keys []map[string]any `json:"keys"`
} }

View File

@ -168,6 +168,13 @@ func TestApi(t *testing.T) {
t.Errorf("Get groups: %v %#v", err, s) t.Errorf("Get groups: %v %#v", err, s)
} }
resp, err = do("PUT", "/galene-api/0/.groups/test/.fallback-users",
"application/json", "", "",
`[{"password": "topsecret"}]`)
if err != nil || resp.StatusCode != http.StatusNoContent {
t.Errorf("Set fallback users: %v %v", err, resp.StatusCode)
}
resp, err = do("PUT", "/galene-api/0/.groups/test/.keys", resp, err = do("PUT", "/galene-api/0/.groups/test/.keys",
"application/jwk-set+json", "", "", "application/jwk-set+json", "", "",
`{"keys": [{ `{"keys": [{
@ -261,10 +268,20 @@ func TestApi(t *testing.T) {
t.Errorf("Users (after delete): %#v", desc.Users) t.Errorf("Users (after delete): %#v", desc.Users)
} }
if len(desc.FallbackUsers) != 1 {
t.Errorf("Keys: %v", len(desc.AuthKeys))
}
if len(desc.AuthKeys) != 1 { if len(desc.AuthKeys) != 1 {
t.Errorf("Keys: %v", len(desc.AuthKeys)) t.Errorf("Keys: %v", len(desc.AuthKeys))
} }
resp, err = do("DELETE", "/galene-api/0/.groups/test/.fallback-users",
"", "", "", "")
if err != nil || resp.StatusCode != http.StatusNoContent {
t.Errorf("Delete fallback users: %v %v", err, resp.StatusCode)
}
resp, err = do("DELETE", "/galene-api/0/.groups/test/.keys", resp, err = do("DELETE", "/galene-api/0/.groups/test/.keys",
"", "", "", "") "", "", "", "")
if err != nil || resp.StatusCode != http.StatusNoContent { if err != nil || resp.StatusCode != http.StatusNoContent {