mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-20 13:30:46 +02:00
* feat(iam): claim-based policy mode for AssumeRoleWithWebIdentity When the caller passes the sentinel RoleArn arn:aws:iam:::role/sts-claim-based (or omits it entirely) and the matched OIDC provider has policyClaim set, mint a session whose effective policies come from that JWT claim instead of from a server-side role mapping. Accepts string, comma-separated string, or array shapes — MinIO-compatible behaviour for IDPs that already attach policies to the user. Trust-policy validation is skipped in claim-mode: the IDP is the sole authority for both authentication and authorization, mirroring the contract MinIO documents for its DummyRoleARN flow. Concrete-role mode is unchanged and still requires the role definition + trust policy. * fix(iam): trim policy-claim array elements + clean up stale comments Three medium-priority cleanups gemini flagged on the claim-based path: - extractClaimPolicies's array branch was leaving whitespace on each element while the string/comma-separated branch trimmed via splitPolicyClaimString. An IDP that emits ["readonly", " billing "] would create a "billing" policy lookup that didn't match the stored name. Trim every array element, drop empties. - The "synthetic ARN keyed on the session name" comment was wrong — effectiveRoleArn here is the literal sentinel; it's the assumed-role ARN generated downstream that's session-keyed. Reword. - The empty if/else block at the start of validateAssumeRoleWithWebIdentityRequest existed only to host a comment about deferred validation; the comment now lives in the function godoc and the empty branch is gone. Addresses three gemini medium reviews on PR #9322.
58 lines
1.7 KiB
Go
58 lines
1.7 KiB
Go
package oidc
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestExtractClaimPoliciesString(t *testing.T) {
|
|
got := extractClaimPolicies(map[string]interface{}{"policy": "readonly"}, "policy")
|
|
if !reflect.DeepEqual(got, []string{"readonly"}) {
|
|
t.Fatalf("got=%v", got)
|
|
}
|
|
}
|
|
|
|
func TestExtractClaimPoliciesCommaSeparated(t *testing.T) {
|
|
got := extractClaimPolicies(map[string]interface{}{"policy": "readonly, billing , "}, "policy")
|
|
if !reflect.DeepEqual(got, []string{"readonly", "billing"}) {
|
|
t.Fatalf("got=%v", got)
|
|
}
|
|
}
|
|
|
|
func TestExtractClaimPoliciesArray(t *testing.T) {
|
|
got := extractClaimPolicies(map[string]interface{}{
|
|
"policy": []interface{}{"readonly", "billing", 42, ""}, // non-string + empty filtered
|
|
}, "policy")
|
|
if !reflect.DeepEqual(got, []string{"readonly", "billing"}) {
|
|
t.Fatalf("got=%v", got)
|
|
}
|
|
}
|
|
|
|
func TestExtractClaimPoliciesMissing(t *testing.T) {
|
|
if got := extractClaimPolicies(map[string]interface{}{}, "policy"); got != nil {
|
|
t.Fatalf("expected nil, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestExtractClaimPoliciesEmptyClaimName(t *testing.T) {
|
|
// Provider not in claim-mode -> never read the claim, even if present.
|
|
if got := extractClaimPolicies(map[string]interface{}{"policy": "readonly"}, ""); got != nil {
|
|
t.Fatalf("empty claim name should return nil, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestExtractClaimPoliciesUnsupportedShape(t *testing.T) {
|
|
// Numeric / object / bool values should be ignored, not panic.
|
|
cases := []interface{}{
|
|
42,
|
|
3.14,
|
|
map[string]interface{}{"x": "y"},
|
|
true,
|
|
}
|
|
for _, v := range cases {
|
|
if got := extractClaimPolicies(map[string]interface{}{"policy": v}, "policy"); got != nil {
|
|
t.Fatalf("value %v: expected nil, got %v", v, got)
|
|
}
|
|
}
|
|
}
|