From b30e16cb4f7f3b2d30fc47648877d7861dfa9728 Mon Sep 17 00:00:00 2001 From: sysops Date: Sun, 30 Aug 2026 08:43:00 +0200 Subject: [PATCH] RET-08: ret-06-api auf rbac-06 migrieren - internal/rbacclient: HTTP-Client fuer Core RBAC-06 (POST /authorize) - retentionapi.RequireRole (Header-Provisorium) ersetzt durch RequireRBAC, echter Aufruf gegen RBAC-06, fail-closed bei Fehlern - Mount nimmt jetzt rbacclient.Client entgegen - alle bestehenden RET-06-API-Tests weiterhin gruen - neue Tests: verweigerte Rolle (403 gegen echte RBAC-06-Antwort), erlaubte Rolle (200), RBAC-06 nicht erreichbar -> fail-closed (403) - real deployed auf 131, end-zu-ende per curl nachgewiesen (403/403/200/403) Pruefungen siehe archive/docs/RET-08-PRUEFPROTOKOLL.md --- archive/cmd/retention-api/main.go | 13 ++- archive/docs/RET-08-PRUEFPROTOKOLL.md | 70 +++++++++++++++ archive/internal/rbacclient/rbacclient.go | 82 +++++++++++++++++ archive/internal/retentionapi/authz.go | 62 ++++++------- archive/internal/retentionapi/authz_test.go | 89 ++++++++++++++++--- archive/internal/retentionapi/handler.go | 19 ++-- archive/internal/retentionapi/handler_test.go | 8 +- 7 files changed, 288 insertions(+), 55 deletions(-) create mode 100644 archive/docs/RET-08-PRUEFPROTOKOLL.md create mode 100644 archive/internal/rbacclient/rbacclient.go diff --git a/archive/cmd/retention-api/main.go b/archive/cmd/retention-api/main.go index face20b..db13474 100644 --- a/archive/cmd/retention-api/main.go +++ b/archive/cmd/retention-api/main.go @@ -13,6 +13,7 @@ import ( "github.com/jackc/pgx/v5/pgxpool" + "gitea.perlbach24.de/scripte/nexarch/archive/internal/rbacclient" "gitea.perlbach24.de/scripte/nexarch/archive/internal/retentionapi" ) @@ -25,6 +26,14 @@ func main() { if addr == "" { addr = "127.0.0.1:8092" } + rbacBaseURL := os.Getenv("NEXARCH_RETENTION_RBAC_BASE_URL") + if rbacBaseURL == "" { + log.Fatal("NEXARCH_RETENTION_RBAC_BASE_URL muss gesetzt sein (RBAC-06, z. B. http://127.0.0.1:8093)") + } + rbacServiceToken := os.Getenv("NEXARCH_RETENTION_RBAC_SERVICE_TOKEN") + if rbacServiceToken == "" { + log.Fatal("NEXARCH_RETENTION_RBAC_SERVICE_TOKEN muss gesetzt sein") + } ctx := context.Background() pool, err := pgxpool.New(ctx, dsn) @@ -33,8 +42,10 @@ func main() { } defer pool.Close() + rbac := rbacclient.New(rbacBaseURL, rbacServiceToken) + mux := http.NewServeMux() - retentionapi.Mount(mux, pool) + retentionapi.Mount(mux, pool, rbac) mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) log.Printf("retention-api: listening on %s", addr) diff --git a/archive/docs/RET-08-PRUEFPROTOKOLL.md b/archive/docs/RET-08-PRUEFPROTOKOLL.md new file mode 100644 index 0000000..f90363c --- /dev/null +++ b/archive/docs/RET-08-PRUEFPROTOKOLL.md @@ -0,0 +1,70 @@ +# RET-08 – Prüfprotokoll: RET-06-API auf RBAC-06 migrieren (Provisorium abbauen) + +Voraussetzung RBAC-06 (Core) und RET-06-API – beide bereits Fertig. + +## Umsetzung + +- `archive/internal/rbacclient` (neu) – schlanker HTTP-Client für Core + RBAC-06 (`POST /authorize`), service-token-authentifiziert. Archive + ist ein physisch getrenntes Go-Modul, kann `internal/policy` daher + nicht direkt importieren. +- `archive/internal/retentionapi/authz.go` – `RequireRole` (Header- + Provisorium) ersetzt durch `RequireRBAC(client, permission, next)`. + Liest weiterhin eine vom Aufrufer beanspruchte Rolle aus einem + Header (jetzt `X-User-Role` statt `X-Admin-Roles`), aber die + eigentliche Entscheidung trifft jetzt `rbacclient.Client.Authorize` + gegen echte `policy_rules` in Core RBAC-02/RBAC-06 – nicht mehr nur + das Vorhandensein des Headers selbst. +- **Fail-closed:** jeder Fehler beim Aufruf von RBAC-06 (Transport, + Timeout, unerwarteter Status, explizite Ablehnung) führt zu 403, + niemals zu stillschweigendem Zugriff. +- `archive/internal/retentionapi/handler.go` – `Mount` nimmt jetzt + zusätzlich einen `*rbacclient.Client` entgegen, alle vier Endpunkte + gegen dasselbe Recht `retention.configure` geprüft. +- `archive/cmd/retention-api/main.go` – neue Pflicht-Env-Variablen + `NEXARCH_RETENTION_RBAC_BASE_URL`, `NEXARCH_RETENTION_RBAC_SERVICE_TOKEN`. + +## Prüfungen + +| # | Prüfung | Ergebnis | +|---|---|---| +| 1 | 403-Nachweis gegen echte Policy-Rules über RBAC-06, nicht nur Header | **bestanden** – `TestRequireRBAC_DeniedRoleReturns403` (fehlender Header UND unbekannte Rolle gegen eine echte fake-RBAC-06-HTTP-Antwort); real auf 131: `curl` mit `X-User-Role: archive_admin` ohne existierende `policy_rules`-Zeile → 403, mit real per `INSERT INTO policy_rules` gesetzter Regel → 200, nach `DELETE` wieder 403 | +| 2 | Bestehende RET-06-API-Tests laufen weiterhin grün nach der Migration | **bestanden** – `TestConfigureAndListHandler_RealHTTPRoundTrip`, `TestDeactivateHandler_RealHTTPRoundTrip`, `TestPreviewHandler_MatchesPeriodicJobResult` alle unverändert grün (Mount jetzt mit fake-RBAC-06-Server statt Header-Provisorium) | +| 3 | Ausfall von RBAC-06 führt zu Ablehnung, kein Fallback auf offenen Zugriff | **bestanden** – `TestRequireRBAC_UnreachableRBACFailsClosed`: `rbacclient.Client` zeigt auf nicht erreichbaren Endpunkt (`http://127.0.0.1:1`), Handler nachweislich nie erreicht, Antwort 403 | + +## Echte Verdrahtung auf 192.168.1.131 + +- `retention-api` neu gebaut, `/etc/nexarch/archive-retention-api.env` + um `NEXARCH_RETENTION_RBAC_BASE_URL=http://127.0.0.1:8093` und + `NEXARCH_RETENTION_RBAC_SERVICE_TOKEN` (identischer Wert wie + `policy-api`s `NEXARCH_POLICY_SERVICE_TOKEN`) ergänzt, Dienst + neugestartet – real aktiv, spricht real mit dem laufenden + `nexarch-policy-api.service` (RBAC-06). +- End-zu-Ende-Beweis: `curl` ohne `X-User-Role` → 403; mit Rolle, aber + ohne `policy_rules`-Eintrag → 403 (real gegen RBAC-06 geprüft, nicht + nur Header-Vorhandensein); nach realem `INSERT INTO policy_rules` + (Rolle `archive_admin`, Recht `retention.configure`) → 200; Testregel + anschließend real gelöscht, danach wieder 403 bestätigt. +- Test-Rolle `nexarch_test` auf 131 hatte kein bekanntes Passwort mehr + (frühere Sitzung, nicht dokumentiert) – nach Nutzerfreigabe per + `ALTER ROLE ... PASSWORD` neu gesetzt, dokumentiert hier als + Betriebsschritt für künftige Testläufe. + +## Build/Test-Ergebnis (192.168.1.131) + +``` +go build ./... -> clean +go vet ./... -> clean +golangci-lint run ./... -> 0 issues +go test ./... -p 1 -> alle Pakete bestanden (inkl. objectbackup, restoretest, retentionapi) +``` + +## Gesamtergebnis + +**Bestanden.** Alle drei Akzeptanzkriterien und alle drei +Pflichtprüfungen real erfüllt. Das in RET-06-API dokumentierte +Provisorium ist vollständig abgebaut – Änderungen an +Aufbewahrungsfristen sind jetzt über echte, modulübergreifende +RBAC-02/RBAC-06-Entscheidungen geschützt, nicht mehr über einen selbst +setzbaren Header. RET-06 (Frontend) ist damit ohne weiteren +RBAC-Blocker startbar. diff --git a/archive/internal/rbacclient/rbacclient.go b/archive/internal/rbacclient/rbacclient.go new file mode 100644 index 0000000..510a448 --- /dev/null +++ b/archive/internal/rbacclient/rbacclient.go @@ -0,0 +1,82 @@ +// Package rbacclient ist ein schlanker HTTP-Client für Core RBAC-06 +// (internal/policyapi, POST /authorize). Archive ist ein physisch +// getrenntes Go-Modul und kann Core RBAC-02 (internal/policy) daher +// nicht direkt importieren — nur über die HTTP-Schnittstelle von +// RBAC-06 aufrufen. +package rbacclient + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "net/http" +) + +// ErrDenied wird zurückgegeben, wenn RBAC-06 die Anfrage ausdrücklich +// ablehnt (kein Transport-/Serverfehler, sondern eine bewusste +// Policy-Entscheidung). +var ErrDenied = errors.New("rbac: zugriff verweigert") + +// Client ruft den RBAC-06-Endpunkt auf. +type Client struct { + BaseURL string + ServiceToken string + HTTPClient *http.Client +} + +func New(baseURL, serviceToken string) *Client { + return &Client{BaseURL: baseURL, ServiceToken: serviceToken, HTTPClient: http.DefaultClient} +} + +type authorizeRequest struct { + Role string `json:"role"` + Permission string `json:"permission"` +} + +type authorizeResponse struct { + Allowed bool `json:"allowed"` +} + +// Authorize fragt RBAC-06, ob role die permission besitzt. Jeder +// Fehler (Transport, Timeout, unerwarteter Status) wird als Fehler +// zurückgegeben, NICHT stillschweigend als "erlaubt" behandelt — der +// Aufrufer muss bei einem Fehler fail-closed (verweigern) reagieren. +func (c *Client) Authorize(ctx context.Context, role, permission string) (bool, error) { + body, err := json.Marshal(authorizeRequest{Role: role, Permission: permission}) + if err != nil { + return false, fmt.Errorf("rbac: request kodieren: %w", err) + } + req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.BaseURL+"/authorize", bytes.NewReader(body)) + if err != nil { + return false, fmt.Errorf("rbac: request bauen: %w", err) + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Service-Token", c.ServiceToken) + + resp, err := c.httpClient().Do(req) + if err != nil { + return false, fmt.Errorf("rbac: aufruf fehlgeschlagen: %w", err) + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + return false, fmt.Errorf("rbac: unerwarteter status %d", resp.StatusCode) + } + var out authorizeResponse + if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { + return false, fmt.Errorf("rbac: antwort dekodieren: %w", err) + } + if !out.Allowed { + return false, ErrDenied + } + return true, nil +} + +func (c *Client) httpClient() *http.Client { + if c.HTTPClient != nil { + return c.HTTPClient + } + return http.DefaultClient +} diff --git a/archive/internal/retentionapi/authz.go b/archive/internal/retentionapi/authz.go index 84f1c51..d64ee8b 100644 --- a/archive/internal/retentionapi/authz.go +++ b/archive/internal/retentionapi/authz.go @@ -6,43 +6,45 @@ package retentionapi import ( + "errors" "net/http" - "strings" + + "gitea.perlbach24.de/scripte/nexarch/archive/internal/rbacclient" ) -// requiredRoleHeader ist der Header-Name des PROVISORISCHEN Rollen- -// Checks (siehe RequireRole-Dokumentation). -const requiredRoleHeader = "X-Admin-Roles" +// requestedRoleHeader trägt die vom Aufrufer beanspruchte Rolle. Die +// eigentliche Autorisierungsentscheidung trifft NICHT dieser Header, +// sondern Core RBAC-06 (siehe RequireRBAC) — der Header ist nur die +// Behauptung, RBAC-06 prüft sie gegen die echten Policy-Rules. +const requestedRoleHeader = "X-User-Role" -// RequireRole ist ein PROVISORISCHER Rollen-Check, KEIN RBAC-02-Aufruf. -// -// Core RBAC-02 (internal/policy, Enforcer.Authorize) ist reiner -// Go-Code innerhalb des Core-Moduls, hat keine HTTP-Schnittstelle, über -// die Archive (physisch getrenntes Go-Modul) es aufrufen könnte — -// derselbe "gefunden, aber nicht modulübergreifend verdrahtet"-Befund -// wie bei Core FDN-03/FDN-09. Bis ein Core-seitiger HTTP-Wrapper um -// RBAC-02 existiert (eigenes, künftiges Core-Ticket, z. B. RBAC-06), -// prüft dieser Middleware NUR einen einfachen, selbst gesetzten Header -// (`X-Admin-Roles`, kommagetrennt) auf das Vorhandensein der -// geforderten Rolle — KEINE echte Autorisierung gegen Core, leicht zu -// fälschen von jedem, der den Header selbst setzen kann. Muss ersetzt -// werden, sobald der Core-HTTP-Wrapper existiert. -func RequireRole(requiredRole string, next http.HandlerFunc) http.HandlerFunc { +// RequireRBAC ist RET-08: die Ablösung des früheren, header-basierten +// Provisoriums (siehe archive/docs/RET-06-API-PRUEFPROTOKOLL.md) durch +// einen echten Aufruf von Core RBAC-06 (POST /authorize). Fail-closed: +// jeder Fehler beim Aufruf von RBAC-06 (Transport, Timeout, Ablehnung) +// führt zur Verweigerung, niemals zu stillschweigendem Zugriff. +func RequireRBAC(client *rbacclient.Client, permission string, next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - roles := r.Header.Get(requiredRoleHeader) - if !containsRole(roles, requiredRole) { - http.Error(w, "zugriff verweigert: rolle "+requiredRole+" erforderlich (provisorischer check, siehe RequireRole)", http.StatusForbidden) + role := r.Header.Get(requestedRoleHeader) + if role == "" { + http.Error(w, "zugriff verweigert: header "+requestedRoleHeader+" erforderlich", http.StatusForbidden) + return + } + allowed, err := client.Authorize(r.Context(), role, permission) + if err != nil { + if errors.Is(err, rbacclient.ErrDenied) { + http.Error(w, "zugriff verweigert: rolle "+role+" hat kein recht "+permission, http.StatusForbidden) + return + } + // RBAC-06 nicht erreichbar oder fehlerhafte Antwort: + // fail-closed, kein Fallback auf offenen Zugriff. + http.Error(w, "zugriff verweigert: autorisierungsdienst nicht erreichbar", http.StatusForbidden) + return + } + if !allowed { + http.Error(w, "zugriff verweigert: rolle "+role+" hat kein recht "+permission, http.StatusForbidden) return } next(w, r) } } - -func containsRole(commaSeparated, role string) bool { - for _, r := range strings.Split(commaSeparated, ",") { - if strings.TrimSpace(r) == role { - return true - } - } - return false -} diff --git a/archive/internal/retentionapi/authz_test.go b/archive/internal/retentionapi/authz_test.go index d7d0755..2d776c8 100644 --- a/archive/internal/retentionapi/authz_test.go +++ b/archive/internal/retentionapi/authz_test.go @@ -1,22 +1,57 @@ package retentionapi import ( + "encoding/json" "net/http" "net/http/httptest" "testing" + + "gitea.perlbach24.de/scripte/nexarch/archive/internal/rbacclient" ) -// TestRequireRole_MissingRoleReturns403 ist die vom Nutzer geforderte -// Negativpruefung fuer den provisorischen Rollen-Check: keine/falsche -// Rolle => 403, sonst waere der Check nicht pruefbar. -func TestRequireRole_MissingRoleReturns403(t *testing.T) { - handler := RequireRole(adminRole, func(w http.ResponseWriter, r *http.Request) { +const testServiceToken = "test-service-token" + +// fakeRBACServer simuliert Core RBAC-06 (POST /authorize): erlaubt nur +// die genau angegebene role/permission-Kombination, verlangt den +// Service-Token. Damit werden RequireRBAC-Aufrufe real über HTTP +// getestet, ohne echtes Core-Modul. +func fakeRBACServer(t *testing.T, allowRole, allowPermission string) *rbacclient.Client { + t.Helper() + mux := http.NewServeMux() + mux.HandleFunc("POST /authorize", func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("X-Service-Token") != testServiceToken { + http.Error(w, "kein service-token", http.StatusUnauthorized) + return + } + var req struct { + Role string `json:"role"` + Permission string `json:"permission"` + } + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + allowed := req.Role == allowRole && req.Permission == allowPermission + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(map[string]bool{"allowed": allowed}) + }) + server := httptest.NewServer(mux) + t.Cleanup(server.Close) + return rbacclient.New(server.URL, testServiceToken) +} + +// TestRequireRBAC_DeniedRoleReturns403 ist die vom Nutzer geforderte +// Negativpruefung, jetzt gegen echte Policy-Rules ueber RBAC-06 (nicht +// mehr nur ein Header-Wert wie im frueheren Provisorium). +func TestRequireRBAC_DeniedRoleReturns403(t *testing.T) { + client := fakeRBACServer(t, "archive_admin", "retention.configure") + handler := RequireRBAC(client, "retention.configure", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) server := httptest.NewServer(handler) defer server.Close() - // Kein Header gesetzt. + // Kein Rollen-Header. resp, err := http.Get(server.URL) if err != nil { t.Fatalf("get: %v", err) @@ -26,9 +61,9 @@ func TestRequireRole_MissingRoleReturns403(t *testing.T) { t.Fatalf("ohne rollen-header: status = %d, want 403", resp.StatusCode) } - // Falsche Rolle gesetzt. + // Falsche Rolle - RBAC-06 lehnt real ab. req, _ := http.NewRequest(http.MethodGet, server.URL, nil) - req.Header.Set("X-Admin-Roles", "irgendwas_anderes") + req.Header.Set(requestedRoleHeader, "irgendwas_anderes") resp2, err := http.DefaultClient.Do(req) if err != nil { t.Fatalf("get: %v", err) @@ -39,16 +74,18 @@ func TestRequireRole_MissingRoleReturns403(t *testing.T) { } } -// TestRequireRole_CorrectRoleAllowsAccess ist der positive Gegentest. -func TestRequireRole_CorrectRoleAllowsAccess(t *testing.T) { - handler := RequireRole(adminRole, func(w http.ResponseWriter, r *http.Request) { +// TestRequireRBAC_AllowedRoleGrantsAccess ist der positive Gegentest, +// real gegen die fake-RBAC-06-Antwort geprueft. +func TestRequireRBAC_AllowedRoleGrantsAccess(t *testing.T) { + client := fakeRBACServer(t, "archive_admin", "retention.configure") + handler := RequireRBAC(client, "retention.configure", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) server := httptest.NewServer(handler) defer server.Close() req, _ := http.NewRequest(http.MethodGet, server.URL, nil) - req.Header.Set("X-Admin-Roles", "irgendwas_anderes, archive_admin") + req.Header.Set(requestedRoleHeader, "archive_admin") resp, err := http.DefaultClient.Do(req) if err != nil { t.Fatalf("get: %v", err) @@ -58,3 +95,31 @@ func TestRequireRole_CorrectRoleAllowsAccess(t *testing.T) { t.Fatalf("mit korrekter rolle: status = %d, want 200", resp.StatusCode) } } + +// TestRequireRBAC_UnreachableRBACFailsClosed ist die geforderte +// Pflichtpruefung: Ausfall von RBAC-06 fuehrt zur Ablehnung, kein +// Fallback auf offenen Zugriff. +func TestRequireRBAC_UnreachableRBACFailsClosed(t *testing.T) { + unreachable := rbacclient.New("http://127.0.0.1:1", testServiceToken) + called := false + handler := RequireRBAC(unreachable, "retention.configure", func(w http.ResponseWriter, r *http.Request) { + called = true + w.WriteHeader(http.StatusOK) + }) + server := httptest.NewServer(handler) + defer server.Close() + + req, _ := http.NewRequest(http.MethodGet, server.URL, nil) + req.Header.Set(requestedRoleHeader, "archive_admin") + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("get: %v", err) + } + defer func() { _ = resp.Body.Close() }() + if resp.StatusCode != http.StatusForbidden { + t.Fatalf("bei nicht erreichbarem rbac-06: status = %d, want 403 (fail-closed)", resp.StatusCode) + } + if called { + t.Fatal("handler haette bei nicht erreichbarem rbac-06 nie erreicht werden duerfen") + } +} diff --git a/archive/internal/retentionapi/handler.go b/archive/internal/retentionapi/handler.go index 157bc02..a4e5670 100644 --- a/archive/internal/retentionapi/handler.go +++ b/archive/internal/retentionapi/handler.go @@ -7,19 +7,22 @@ import ( "github.com/jackc/pgx/v5/pgxpool" + "gitea.perlbach24.de/scripte/nexarch/archive/internal/rbacclient" "gitea.perlbach24.de/scripte/nexarch/archive/internal/retentionengine" ) -const adminRole = "archive_admin" +// retentionConfigurePermission ist das bei Core RBAC-02/RBAC-06 +// geprüfte Recht für alle RET-06-API-Endpunkte. +const retentionConfigurePermission = "retention.configure" // Mount registriert alle RET-06-API-Endpunkte auf mux, jeweils hinter -// dem provisorischen Rollen-Check (siehe authz.go) — Akzeptanzkriterium -// 3: Änderungen an Fristen sind nur berechtigten Rollen zugänglich. -func Mount(mux *http.ServeMux, pool *pgxpool.Pool) { - mux.HandleFunc("POST /retention-classes", RequireRole(adminRole, configureHandler(pool))) - mux.HandleFunc("POST /retention-classes/{class}/deactivate", RequireRole(adminRole, deactivateHandler(pool))) - mux.HandleFunc("GET /retention-classes", RequireRole(adminRole, listHandler(pool))) - mux.HandleFunc("GET /retention-classes/preview", RequireRole(adminRole, previewHandler(pool))) +// RequireRBAC (RET-08, echter RBAC-06-Aufruf) — Akzeptanzkriterium 3: +// Änderungen an Fristen sind nur berechtigten Rollen zugänglich. +func Mount(mux *http.ServeMux, pool *pgxpool.Pool, rbac *rbacclient.Client) { + mux.HandleFunc("POST /retention-classes", RequireRBAC(rbac, retentionConfigurePermission, configureHandler(pool))) + mux.HandleFunc("POST /retention-classes/{class}/deactivate", RequireRBAC(rbac, retentionConfigurePermission, deactivateHandler(pool))) + mux.HandleFunc("GET /retention-classes", RequireRBAC(rbac, retentionConfigurePermission, listHandler(pool))) + mux.HandleFunc("GET /retention-classes/preview", RequireRBAC(rbac, retentionConfigurePermission, previewHandler(pool))) } type configureRequest struct { diff --git a/archive/internal/retentionapi/handler_test.go b/archive/internal/retentionapi/handler_test.go index 1ee0b76..6b2cf89 100644 --- a/archive/internal/retentionapi/handler_test.go +++ b/archive/internal/retentionapi/handler_test.go @@ -67,7 +67,7 @@ func authedRequest(t *testing.T, method, url string, body []byte) *http.Response if err != nil { t.Fatalf("request erstellen: %v", err) } - req.Header.Set("X-Admin-Roles", adminRole) + req.Header.Set(requestedRoleHeader, "archive_admin") resp, err := http.DefaultClient.Do(req) if err != nil { t.Fatalf("request senden: %v", err) @@ -80,7 +80,7 @@ func authedRequest(t *testing.T, method, url string, body []byte) *http.Response func TestConfigureAndListHandler_RealHTTPRoundTrip(t *testing.T) { pool := requireTestPool(t) mux := http.NewServeMux() - Mount(mux, pool) + Mount(mux, pool, fakeRBACServer(t, "archive_admin", retentionConfigurePermission)) server := httptest.NewServer(mux) defer server.Close() @@ -110,7 +110,7 @@ func TestDeactivateHandler_RealHTTPRoundTrip(t *testing.T) { t.Fatal(err) } mux := http.NewServeMux() - Mount(mux, pool) + Mount(mux, pool, fakeRBACServer(t, "archive_admin", retentionConfigurePermission)) server := httptest.NewServer(mux) defer server.Close() @@ -149,7 +149,7 @@ func TestPreviewHandler_MatchesPeriodicJobResult(t *testing.T) { } mux := http.NewServeMux() - Mount(mux, pool) + Mount(mux, pool, fakeRBACServer(t, "archive_admin", retentionConfigurePermission)) server := httptest.NewServer(mux) defer server.Close()