Files
orbit/internal/transport/httpserver/console_scope_test.go

80 lines
2.9 KiB
Go

package httpserver
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"git.yuntuo.hk/k2safe/orbit/internal/consoleauth"
core "git.yuntuo.hk/k2safe/orbit/model"
"git.yuntuo.hk/k2safe/orbit/platform/auth"
)
type fakeConsoleScopes struct{ calls int }
func (s *fakeConsoleScopes) ResolveScope(_ context.Context, t auth.Token, target core.ID) (auth.Token, error) {
s.calls++
t.Console = &auth.ConsoleIdentity{SessionNamespaceID: t.NamespaceID, Username: "admin", UserID: t.CredentialID}
t.NamespaceID = target
return t, nil
}
func (*fakeConsoleScopes) GetScope(context.Context, auth.Token, core.ID) (consoleauth.Scope, error) {
return consoleauth.Scope{}, nil
}
func TestConsoleScopeOnlyBridgesCookieManagementRequests(t *testing.T) {
ns, _ := core.NewID()
cred, _ := core.NewID()
target, _ := core.NewID()
raw, _, _ := auth.Issue(ns, cred)
for _, tc := range []struct {
name, method, path, origin, bearer string
cookie, marker bool
status int
}{
{"read", "GET", "/v1/tasks", "", "", true, true, 200},
{"control", "POST", "/v1/tasks/task:cancel", "http://example.com", "", true, true, 200},
{"SDK", "GET", "/v1/tasks", "", "Bearer " + raw, false, true, 403},
{"ambiguous", "GET", "/v1/tasks", "", "Bearer " + raw, true, true, 403},
{"anonymous", "GET", "/v1/tasks", "", "", false, true, 401},
{"missing-marker", "GET", "/v1/tasks", "", "", true, false, 403},
{"cross-origin", "POST", "/v1/tasks/task:cancel", "https://other.invalid", "", true, true, 403},
{"worker", "GET", "/v1/worker/connect", "", "", true, true, 403},
{"consumer", "GET", "/v1/events/connect", "", "", true, true, 403},
{"create", "POST", "/v1/tasks", "", "", true, true, 403},
{"onboarding", "POST", "/console/applications/prepare", "", "", true, true, 403},
} {
t.Run(tc.name, func(t *testing.T) {
scope := &fakeConsoleScopes{}
handler := ConsoleSessionMiddleware(wrap(func(r *http.Request, tok auth.Token) (any, int, error) {
if tok.NamespaceID != target || tok.Console == nil || tok.Console.SessionNamespaceID != ns {
t.Fatal("scope lost")
}
return map[string]bool{"ok": true}, 200, nil
}), &fakeConsoleAuth{valid: true}, scope)
req := httptest.NewRequest(tc.method, tc.path, nil)
req.Header.Set("X-Orbit-Namespace", string(target))
if tc.marker {
req.Header.Set("X-Orbit-Console", "1")
}
if tc.origin != "" {
req.Header.Set("Origin", tc.origin)
}
if tc.bearer != "" {
req.Header.Set("Authorization", tc.bearer)
}
if tc.cookie {
req.AddCookie(&http.Cookie{Name: consoleSessionCookie, Value: raw})
}
res := httptest.NewRecorder()
handler.ServeHTTP(res, req)
if res.Code != tc.status {
t.Fatalf("HTTP %d: %s", res.Code, res.Body.String())
}
if tc.status != 200 && scope.calls != 0 {
t.Fatal("rejected request reached scope resolver")
}
})
}
}