fix(auth): bound OIDC initiation and transport

This commit is contained in:
2026-08-17 07:03:19 +02:00
parent 8573500121
commit bdabecbb63
15 changed files with 747 additions and 111 deletions
+8 -7
View File
@@ -26,9 +26,10 @@ const (
)
var (
digestFilename = regexp.MustCompile(`^[a-f0-9]{64}\.json$`)
claimFilename = regexp.MustCompile(`^[a-f0-9]{64}\.claim$`)
errInvalid = errors.New("auth storage request invalid")
digestFilename = regexp.MustCompile(`^[a-f0-9]{64}\.json$`)
claimFilename = regexp.MustCompile(`^[a-f0-9]{64}\.claim$`)
oidcSlotFilename = regexp.MustCompile(`^slot-(?:[0-5][0-9]|6[0-3])\.json$`)
errInvalid = errors.New("auth storage request invalid")
)
type request struct {
@@ -141,7 +142,7 @@ func execute(input request) (response, error) {
return response{}, errInvalid
}
for _, entry := range entries {
if !digestFilename.MatchString(entry.Name) && !(input.Directory == "oidc" && claimFilename.MatchString(entry.Name)) {
if !digestFilename.MatchString(entry.Name) && !(input.Directory == "oidc" && (claimFilename.MatchString(entry.Name) || oidcSlotFilename.MatchString(entry.Name))) {
return response{}, errInvalid
}
}
@@ -176,11 +177,11 @@ func validOperationShape(input request) bool {
noContents := input.ContentBase64 == ""
switch input.Operation {
case "create", "replace":
return digestFilename.MatchString(input.Filename)
return digestFilename.MatchString(input.Filename) || (input.Operation == "create" && input.Directory == "oidc" && oidcSlotFilename.MatchString(input.Filename))
case "read":
return noContents && digestFilename.MatchString(input.Filename)
return noContents && (digestFilename.MatchString(input.Filename) || (input.Directory == "oidc" && oidcSlotFilename.MatchString(input.Filename)))
case "remove":
return noContents && (digestFilename.MatchString(input.Filename) || (input.Directory == "oidc" && claimFilename.MatchString(input.Filename)))
return noContents && (digestFilename.MatchString(input.Filename) || (input.Directory == "oidc" && (claimFilename.MatchString(input.Filename) || oidcSlotFilename.MatchString(input.Filename))))
case "list":
return input.Filename == "" && noContents
case "claim-consume", "read-claim", "remove-claim":
@@ -44,6 +44,28 @@ func TestProtocolCreatesReadsReplacesListsAndRemovesPrivateRecord(t *testing.T)
}
}
func TestProtocolPermitsBoundedReservationSlotsOnlyForOIDCRecords(t *testing.T) {
root := filepath.Join(privateTestRoot(t), "auth")
slot := "slot-00.json"
contents := base64.StdEncoding.EncodeToString([]byte("reservation"))
if created := runRequest(t, request{Version: 1, Operation: "create", Root: root, Directory: "oidc", Filename: slot, ContentBase64: contents}); !created.Created {
t.Fatal("OIDC slot create did not report success")
}
if read := runRequest(t, request{Version: 1, Operation: "read", Root: root, Directory: "oidc", Filename: slot}); !read.Found || decodeContent(t, read) != "reservation" {
t.Fatalf("OIDC slot read = %#v", read)
}
listed := runRequest(t, request{Version: 1, Operation: "list", Root: root, Directory: "oidc"})
if listed.Entries == nil || len(*listed.Entries) != 1 || (*listed.Entries)[0].Name != slot {
t.Fatalf("OIDC slot list = %#v", listed.Entries)
}
if removed := runRequest(t, request{Version: 1, Operation: "remove", Root: root, Directory: "oidc", Filename: slot}); !removed.Removed {
t.Fatal("OIDC slot remove did not report success")
}
runRejected(t, request{Version: 1, Operation: "create", Root: root, Directory: "sessions", Filename: slot, ContentBase64: contents})
runRejected(t, request{Version: 1, Operation: "create", Root: root, Directory: "oidc", Filename: "slot-64.json", ContentBase64: contents})
}
func TestProtocolListSerializesLowerCamelBridgeDTO(t *testing.T) {
root := filepath.Join(privateTestRoot(t), "auth")
filename := "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.json"