1
0
forked from baron/baron-sso
Files
baron-sso/backend/internal/handler/rp_manifest_handler_test.go
2026-05-12 13:41:43 +09:00

126 lines
5.2 KiB
Go

package handler
import (
"encoding/json"
"io"
"net/http/httptest"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/require"
)
func TestRPManifestJSONIncludesIAMAndExternalKeyContract(t *testing.T) {
t.Setenv("BACKEND_PUBLIC_URL", "")
app := fiber.New()
h := NewRPManifestHandler()
app.Get("/.well-known/baron-rp-manifest.json", h.GetJSON)
req := httptest.NewRequest("GET", "/.well-known/baron-rp-manifest.json", nil)
req.Header.Set("X-Forwarded-Proto", "https")
req.Header.Set("X-Forwarded-Host", "sso.hmac.kr")
resp, err := app.Test(req)
require.NoError(t, err)
defer resp.Body.Close()
require.Equal(t, fiber.StatusOK, resp.StatusCode)
require.Contains(t, resp.Header.Get("Content-Type"), "application/json")
var body map[string]any
require.NoError(t, json.NewDecoder(resp.Body).Decode(&body))
require.Equal(t, "https://sso.hmac.kr", body["issuer"])
oidc := body["oidc"].(map[string]any)
require.Equal(t, "https://sso.hmac.kr/.well-known/openid-configuration", oidc["discovery_url"])
require.Equal(t, "https://sso.hmac.kr/.well-known/jwks.json", oidc["jwks_url"])
iam := body["iam"].(map[string]any)
require.Equal(t, "ory-keto", iam["authorization_engine"])
require.Equal(t, "User:<baron_identity_id>", iam["subject_format"])
require.Contains(t, iam["target_object_patterns"].([]any), "RelyingParty:<client_id>")
require.Contains(t, iam["target_object_patterns"].([]any), "Tenant:<tenant_id>")
require.Contains(t, iam["target_object_patterns"].([]any), "Resource:<resource_type>:<resource_id>")
identity := body["identity_contract"].(map[string]any)
require.Equal(t, "X-Baron-External-Key", identity["external_key_header"])
require.Equal(t, true, identity["external_key_is_opaque"])
require.Equal(t, false, identity["raw_kratos_identity_id_exposed"])
require.Equal(t, "baron", identity["external_key_issuer"])
require.Equal(t, "baron_injected_header", identity["external_key_delivery"])
require.Equal(t, false, identity["rp_supplied_external_key_allowed"])
require.Equal(t, "rp_must_upsert_from_header_value", identity["rp_user_upsert_source"])
headers := body["trusted_headers"].(map[string]any)
require.Equal(t, "X-Baron-Subject", headers["subject"])
require.Equal(t, "X-Baron-External-Key", headers["external_key"])
require.Equal(t, "X-Baron-Client-ID", headers["client_id"])
security := body["security_requirements"].(map[string]any)
require.Equal(t, true, security["strip_external_identity_headers"])
require.Equal(t, false, security["backend_direct_exposure_allowed"])
audit := body["audit_contract"].(map[string]any)
require.Equal(t, "fail_closed_sync", audit["mutating_command_mode"])
require.Equal(t, "reject_mutation", audit["missing_audit_sink_behavior"])
require.Equal(t, "X-Request-Id", audit["correlation_header"])
require.Contains(t, audit["required_detail_fields"].([]any), "obj_id")
require.Contains(t, audit["required_detail_fields"].([]any), "client_id")
flow := body["object_lookup_flow"].(map[string]any)
require.Contains(t, flow["mermaid"].(string), "flowchart TD")
require.Contains(t, flow["mermaid"].(string), "obj_id")
aliasFlow := body["external_key_flow"].(map[string]any)
require.Contains(t, aliasFlow["mermaid"].(string), "Baron resolves internal identity")
require.Contains(t, aliasFlow["mermaid"].(string), "Baron injects X-Baron-External-Key")
require.Contains(t, aliasFlow["mermaid"].(string), "RP upserts local user")
require.NotContains(t, aliasFlow["mermaid"].(string), "RP creates external key")
}
func TestRPManifestSchemaRequiresLookupAndIdentityContracts(t *testing.T) {
app := fiber.New()
h := NewRPManifestHandler()
app.Get("/.well-known/baron-rp-manifest.schema.json", h.GetSchema)
resp, err := app.Test(httptest.NewRequest("GET", "/.well-known/baron-rp-manifest.schema.json", nil))
require.NoError(t, err)
defer resp.Body.Close()
require.Equal(t, fiber.StatusOK, resp.StatusCode)
var body map[string]any
require.NoError(t, json.NewDecoder(resp.Body).Decode(&body))
required := body["required"].([]any)
require.Contains(t, required, "iam")
require.Contains(t, required, "trusted_headers")
require.Contains(t, required, "identity_contract")
require.Contains(t, required, "object_lookup")
require.Contains(t, required, "audit_contract")
require.Contains(t, required, "object_lookup_flow")
require.Contains(t, required, "external_key_flow")
}
func TestRPManifestHTMLLinksMachineReadableManifest(t *testing.T) {
app := fiber.New()
h := NewRPManifestHandler()
app.Get("/.well-known/baron-rp-manifest", h.GetHTML)
resp, err := app.Test(httptest.NewRequest("GET", "/.well-known/baron-rp-manifest", nil))
require.NoError(t, err)
defer resp.Body.Close()
require.Equal(t, fiber.StatusOK, resp.StatusCode)
require.Contains(t, resp.Header.Get("Content-Type"), "text/html")
raw, err := io.ReadAll(resp.Body)
require.NoError(t, err)
text := string(raw)
require.Contains(t, text, "/.well-known/baron-rp-manifest.json")
require.Contains(t, text, "X-Baron-External-Key")
require.Contains(t, text, "RelyingParty:&lt;client_id&gt;")
require.Contains(t, text, "```mermaid")
require.Contains(t, text, "audit_contract")
require.Contains(t, text, "Baron-issued alias")
require.Contains(t, text, "RP upserts local user")
}