80 lines
2.9 KiB
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")
|
|
}
|
|
})
|
|
}
|
|
}
|