116 lines
2.9 KiB
Go
116 lines
2.9 KiB
Go
package meta
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"path/filepath"
|
|
"slices"
|
|
"testing"
|
|
|
|
"nadir/internal/auth"
|
|
"nadir/internal/module"
|
|
"nadir/internal/rbac"
|
|
|
|
"github.com/danielgtaylor/huma/v2"
|
|
"github.com/danielgtaylor/huma/v2/adapters/humago"
|
|
"github.com/danielgtaylor/huma/v2/humatest"
|
|
)
|
|
|
|
type dummyModule struct {
|
|
id string
|
|
perms []rbac.Permission
|
|
}
|
|
|
|
func (m *dummyModule) ID() string { return m.id }
|
|
func (m *dummyModule) Name() string { return m.id }
|
|
func (m *dummyModule) Permissions() []rbac.Permission { return m.perms }
|
|
func (m *dummyModule) Register(api huma.API) {}
|
|
|
|
func TestWhoami(t *testing.T) {
|
|
tempDir := t.TempDir()
|
|
sessions, err := auth.NewSessionStore(filepath.Join(tempDir, "sessions.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tokenStore, err := auth.NewTokenStore(filepath.Join(tempDir, "tokens.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer tokenStore.Close()
|
|
tokenAuth := auth.NewTokenAuth(tokenStore)
|
|
|
|
roles := rbac.New()
|
|
roles.DefineRole(rbac.Role{
|
|
Name: "admin-role",
|
|
ModuleGrants: map[string][]rbac.Permission{
|
|
"system": {rbac.Read},
|
|
},
|
|
})
|
|
roles.AssignRole("admin", "admin-role")
|
|
|
|
mods := []module.Module{
|
|
&dummyModule{
|
|
id: "system",
|
|
perms: []rbac.Permission{rbac.Read, rbac.Write},
|
|
},
|
|
}
|
|
|
|
mux := http.NewServeMux()
|
|
api := humatest.Wrap(t, humago.New(mux, huma.DefaultConfig("Test", "1.0.0")))
|
|
RegisterWhoami(api, sessions, tokenAuth, roles, mods)
|
|
|
|
// 1. Unauthorized request (no token, no session)
|
|
resp := api.Get("/api/whoami")
|
|
if resp.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected 401, got %d", resp.Code)
|
|
}
|
|
|
|
// 2. Cookie session request
|
|
sessToken, err := sessions.Create("admin")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
resp = api.Get("/api/whoami", "Cookie: nadir_session_id="+sessToken)
|
|
if resp.Code != http.StatusOK {
|
|
t.Errorf("expected 200, got %d", resp.Code)
|
|
}
|
|
var body WhoamiBody
|
|
if err := json.Unmarshal(resp.Body.Bytes(), &body); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if body.Username != "admin" {
|
|
t.Errorf("expected username admin, got %q", body.Username)
|
|
}
|
|
if !slices.Contains(body.Permissions["system"], "read") {
|
|
t.Errorf("expected system read permission, got %v", body.Permissions["system"])
|
|
}
|
|
|
|
// 3. Token request
|
|
bearerToken, err := tokenStore.Create("api-user")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
roles.DefineRole(rbac.Role{
|
|
Name: "api-role",
|
|
ModuleGrants: map[string][]rbac.Permission{
|
|
"system": {rbac.Write},
|
|
},
|
|
})
|
|
roles.AssignRole("api-user", "api-role")
|
|
|
|
resp = api.Get("/api/whoami", "Authorization: Bearer "+bearerToken)
|
|
if resp.Code != http.StatusOK {
|
|
t.Errorf("expected 200, got %d", resp.Code)
|
|
}
|
|
if err := json.Unmarshal(resp.Body.Bytes(), &body); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if body.Username != "api-user" {
|
|
t.Errorf("expected username api-user, got %q", body.Username)
|
|
}
|
|
if !slices.Contains(body.Permissions["system"], "write") {
|
|
t.Errorf("expected system write permission, got %v", body.Permissions["system"])
|
|
}
|
|
}
|