- bouncer.Dispatch, WithDispatch, Dispatched: context-only pre-resolved
principal marker honoured by Registry.Middleware for listed guard names
- cabana.ResolveBackend honours a backend-kind marker; additive
ResolveBackendToken, ScopeLimitFor and BackendPrincipal resolvers
- surf.Router.Handler and compileHandlers: one compiled chain per route,
shared by BuildRouter validation and compile
- smoke tests TestDispatchSmoke, TestDispatchedSmoke, TestDispatchMarkerSmoke
- READMEs and docs/services/{authentication,routing}.md updated
73 lines
3.3 KiB
Go
73 lines
3.3 KiB
Go
package cabana
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
|
"git.golem15.com/golem15/summercms/modules/bouncer"
|
|
)
|
|
|
|
// TestDispatchMarkerSmoke covers ResolveBackend with the in-process dispatch
|
|
// marker (phase 19.7 D-17): a backend marker is honoured without a bearer or
|
|
// a published resolver, a frontend marker is refused, and a scoped marker is
|
|
// still checked against the cover codes.
|
|
func TestDispatchMarkerSmoke(t *testing.T) {
|
|
app := backpack.New(nil)
|
|
withMarker := func(p *bouncer.Principal) *http.Request {
|
|
r := httptest.NewRequest(http.MethodGet, "/acme/posts", nil)
|
|
marker := &bouncer.Dispatch{Guards: []string{"backend"}, Principal: p, Credential: "cred"}
|
|
return r.WithContext(bouncer.WithDispatch(r.Context(), marker))
|
|
}
|
|
|
|
// A backend marker: the principal is returned and stored on the context.
|
|
r, principal, err := ResolveBackend(app, withMarker(&bouncer.Principal{ID: 42, Backend: true}), "acme.*")
|
|
if err != nil || principal == nil || principal.ID != 42 {
|
|
t.Fatalf("backend marker: %+v, %v", principal, err)
|
|
}
|
|
if got, ok := bouncer.User(r.Context()); !ok || got.ID != 42 {
|
|
t.Fatalf("principal not stored on the returned request: %+v, %v", got, ok)
|
|
}
|
|
if cred, ok := bouncer.Credential(r.Context()); !ok || cred != "cred" {
|
|
t.Fatalf("credential not stored on the returned request: %v, %v", cred, ok)
|
|
}
|
|
|
|
// A frontend marker (Backend false) is never a backend principal.
|
|
if _, _, err := ResolveBackend(app, withMarker(&bouncer.Principal{ID: 7}), "acme.*"); !errors.Is(err, ErrUnauthenticated) {
|
|
t.Fatalf("frontend marker: err = %v, want ErrUnauthenticated", err)
|
|
}
|
|
|
|
// A scoped marker whose scope does not cover acme.* is refused as a
|
|
// scoped token would be; one that covers it passes.
|
|
scoped := &bouncer.Principal{ID: 42, Backend: true, Scope: &bouncer.ScopeLimit{Scopes: [][]string{{"other.*"}}}}
|
|
if _, _, err := ResolveBackend(app, withMarker(scoped), "acme.*"); !errors.Is(err, ErrTokenScope) {
|
|
t.Fatalf("scoped marker: err = %v, want ErrTokenScope", err)
|
|
}
|
|
covering := &bouncer.Principal{ID: 42, Backend: true, Scope: &bouncer.ScopeLimit{Scopes: [][]string{{"acme.*"}}}}
|
|
if _, _, err := ResolveBackend(app, withMarker(covering), "acme.*"); err != nil {
|
|
t.Fatalf("covering scoped marker: %v", err)
|
|
}
|
|
|
|
// Without a marker the request still needs a bearer; a forged header is
|
|
// not a marker.
|
|
plain := httptest.NewRequest(http.MethodGet, "/acme/posts", nil)
|
|
plain.Header.Set("X-Summer-Dispatch", "42")
|
|
if _, _, err := ResolveBackend(app, plain, "acme.*"); !errors.Is(err, ErrUnauthenticated) {
|
|
t.Fatalf("no marker: err = %v, want ErrUnauthenticated", err)
|
|
}
|
|
|
|
// The additive resolvers answer unauthenticated on an app without cabana.
|
|
if _, _, _, err := ResolveBackendToken(context.Background(), app, "g15_0000000000000000000000000000000000000000"); !errors.Is(err, ErrUnauthenticated) {
|
|
t.Fatalf("ResolveBackendToken without cabana: %v", err)
|
|
}
|
|
if limit, known, methodOK := ScopeLimitFor(app, []string{"*"}, http.MethodGet); limit != nil || known != 0 || methodOK != 0 {
|
|
t.Fatalf("ScopeLimitFor without cabana = %v, %d, %d", limit, known, methodOK)
|
|
}
|
|
if _, err := BackendPrincipal(context.Background(), app, 1); !errors.Is(err, ErrUnauthenticated) {
|
|
t.Fatalf("BackendPrincipal without cabana: %v", err)
|
|
}
|
|
}
|