add field and label selectors to authorization attributes
Co-authored-by: Jordan Liggitt <liggitt@google.com>
This commit is contained in:
committed by
Jordan Liggitt
parent
f5e5bef2e0
commit
92e3445e9d
@@ -29,6 +29,50 @@ func TestValidateSARSpec(t *testing.T) {
|
||||
successCases := []authorizationapi.SubjectAccessReviewSpec{
|
||||
{ResourceAttributes: &authorizationapi.ResourceAttributes{}, User: "me"},
|
||||
{NonResourceAttributes: &authorizationapi.NonResourceAttributes{}, Groups: []string{"my-group"}},
|
||||
{ // field raw selector
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
FieldSelector: &authorizationapi.FieldSelectorAttributes{
|
||||
RawSelector: "***foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{ // label raw selector
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
RawSelector: "***foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{ // unknown field operator
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
FieldSelector: &authorizationapi.FieldSelectorAttributes{
|
||||
Requirements: []metav1.FieldSelectorRequirement{
|
||||
{
|
||||
Key: "k",
|
||||
Operator: metav1.FieldSelectorOperator("fake"),
|
||||
Values: []string{"val"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ // unknown label operator
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
Requirements: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "k",
|
||||
Operator: metav1.LabelSelectorOperator("fake"),
|
||||
Values: []string{"val"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, successCase := range successCases {
|
||||
if errs := ValidateSubjectAccessReviewSpec(successCase, field.NewPath("spec")); len(errs) != 0 {
|
||||
@@ -58,29 +102,257 @@ func TestValidateSARSpec(t *testing.T) {
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{},
|
||||
},
|
||||
msg: `spec.user: Invalid value: "": at least one of user or group must be specified`,
|
||||
}, {
|
||||
name: "resource attributes: field selector specify both",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
FieldSelector: &authorizationapi.FieldSelectorAttributes{
|
||||
RawSelector: "foo",
|
||||
Requirements: []metav1.FieldSelectorRequirement{
|
||||
{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: `spec.resourceAttributes.fieldSelector.rawSelector: Invalid value: "foo": may not specified at the same time as requirements`,
|
||||
}, {
|
||||
name: "resource attributes: field selector specify neither",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
FieldSelector: &authorizationapi.FieldSelectorAttributes{},
|
||||
},
|
||||
},
|
||||
msg: `spec.resourceAttributes.fieldSelector.requirements: Required value: when spec.resourceAttributes.fieldSelector is specified, requirements or rawSelector is required`,
|
||||
}, {
|
||||
name: "resource attributes: field selector no key",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
FieldSelector: &authorizationapi.FieldSelectorAttributes{
|
||||
Requirements: []metav1.FieldSelectorRequirement{
|
||||
{
|
||||
Key: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: `spec.resourceAttributes.fieldSelector.requirements[0].key: Required value: must be specified`,
|
||||
}, {
|
||||
name: "resource attributes: field selector no value for in",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
FieldSelector: &authorizationapi.FieldSelectorAttributes{
|
||||
Requirements: []metav1.FieldSelectorRequirement{
|
||||
{
|
||||
Key: "k",
|
||||
Operator: metav1.FieldSelectorOpIn,
|
||||
Values: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "spec.resourceAttributes.fieldSelector.requirements[0].values: Required value: must be specified when `operator` is 'In' or 'NotIn'",
|
||||
}, {
|
||||
name: "resource attributes: field selector no value for not in",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
FieldSelector: &authorizationapi.FieldSelectorAttributes{
|
||||
Requirements: []metav1.FieldSelectorRequirement{
|
||||
{
|
||||
Key: "k",
|
||||
Operator: metav1.FieldSelectorOpNotIn,
|
||||
Values: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "spec.resourceAttributes.fieldSelector.requirements[0].values: Required value: must be specified when `operator` is 'In' or 'NotIn'",
|
||||
}, {
|
||||
name: "resource attributes: field selector values for exists",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
FieldSelector: &authorizationapi.FieldSelectorAttributes{
|
||||
Requirements: []metav1.FieldSelectorRequirement{
|
||||
{
|
||||
Key: "k",
|
||||
Operator: metav1.FieldSelectorOpExists,
|
||||
Values: []string{"val"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "spec.resourceAttributes.fieldSelector.requirements[0].values: Forbidden: may not be specified when `operator` is 'Exists' or 'DoesNotExist'",
|
||||
}, {
|
||||
name: "resource attributes: field selector values for not exists",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
FieldSelector: &authorizationapi.FieldSelectorAttributes{
|
||||
Requirements: []metav1.FieldSelectorRequirement{
|
||||
{
|
||||
Key: "k",
|
||||
Operator: metav1.FieldSelectorOpDoesNotExist,
|
||||
Values: []string{"val"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "spec.resourceAttributes.fieldSelector.requirements[0].values: Forbidden: may not be specified when `operator` is 'Exists' or 'DoesNotExist'",
|
||||
}, {
|
||||
name: "resource attributes: label selector specify both",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
RawSelector: "foo",
|
||||
Requirements: []metav1.LabelSelectorRequirement{
|
||||
{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: `spec.resourceAttributes.labelSelector.rawSelector: Invalid value: "foo": may not specified at the same time as requirements`,
|
||||
}, {
|
||||
name: "resource attributes: label selector specify neither",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{},
|
||||
},
|
||||
},
|
||||
msg: `spec.resourceAttributes.labelSelector.requirements: Required value: when spec.resourceAttributes.labelSelector is specified, requirements or rawSelector is required`,
|
||||
}, {
|
||||
name: "resource attributes: label selector no key",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
Requirements: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: `spec.resourceAttributes.labelSelector.requirements[0].key: Invalid value: "": name part must be non-empty`,
|
||||
}, {
|
||||
name: "resource attributes: label selector invalid label name",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
Requirements: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "()foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: `spec.resourceAttributes.labelSelector.requirements[0].key: Invalid value: "()foo": name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')`,
|
||||
}, {
|
||||
name: "resource attributes: label selector no value for in",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
Requirements: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "k",
|
||||
Operator: metav1.LabelSelectorOpIn,
|
||||
Values: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "spec.resourceAttributes.labelSelector.requirements[0].values: Required value: must be specified when `operator` is 'In' or 'NotIn'",
|
||||
}, {
|
||||
name: "resource attributes: label selector no value for not in",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
Requirements: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "k",
|
||||
Operator: metav1.LabelSelectorOpNotIn,
|
||||
Values: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "spec.resourceAttributes.labelSelector.requirements[0].values: Required value: must be specified when `operator` is 'In' or 'NotIn'",
|
||||
}, {
|
||||
name: "resource attributes: label selector values for exists",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
Requirements: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "k",
|
||||
Operator: metav1.LabelSelectorOpExists,
|
||||
Values: []string{"val"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "spec.resourceAttributes.labelSelector.requirements[0].values: Forbidden: may not be specified when `operator` is 'Exists' or 'DoesNotExist'",
|
||||
}, {
|
||||
name: "resource attributes: label selector values for not exists",
|
||||
obj: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "me",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
Requirements: []metav1.LabelSelectorRequirement{
|
||||
{
|
||||
Key: "k",
|
||||
Operator: metav1.LabelSelectorOpDoesNotExist,
|
||||
Values: []string{"val"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: "spec.resourceAttributes.labelSelector.requirements[0].values: Forbidden: may not be specified when `operator` is 'Exists' or 'DoesNotExist'",
|
||||
}}
|
||||
|
||||
for _, c := range errorCases {
|
||||
errs := ValidateSubjectAccessReviewSpec(c.obj, field.NewPath("spec"))
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("%s: expected failure for %q", c.name, c.msg)
|
||||
} else if !strings.Contains(errs[0].Error(), c.msg) {
|
||||
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
|
||||
}
|
||||
|
||||
errs = ValidateSubjectAccessReview(&authorizationapi.SubjectAccessReview{Spec: c.obj})
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("%s: expected failure for %q", c.name, c.msg)
|
||||
} else if !strings.Contains(errs[0].Error(), c.msg) {
|
||||
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
|
||||
}
|
||||
errs = ValidateLocalSubjectAccessReview(&authorizationapi.LocalSubjectAccessReview{Spec: c.obj})
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("%s: expected failure for %q", c.name, c.msg)
|
||||
} else if !strings.Contains(errs[0].Error(), c.msg) {
|
||||
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
|
||||
}
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
errs := ValidateSubjectAccessReviewSpec(c.obj, field.NewPath("spec"))
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("%s: expected failure for %q", c.name, c.msg)
|
||||
} else if !strings.Contains(errs[0].Error(), c.msg) {
|
||||
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
|
||||
}
|
||||
|
||||
errs = ValidateSubjectAccessReview(&authorizationapi.SubjectAccessReview{Spec: c.obj})
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("%s: expected failure for %q", c.name, c.msg)
|
||||
} else if !strings.Contains(errs[0].Error(), c.msg) {
|
||||
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
|
||||
}
|
||||
errs = ValidateLocalSubjectAccessReview(&authorizationapi.LocalSubjectAccessReview{Spec: c.obj})
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("%s: expected failure for %q", c.name, c.msg)
|
||||
} else if !strings.Contains(errs[0].Error(), c.msg) {
|
||||
t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +381,20 @@ func TestValidateSelfSAR(t *testing.T) {
|
||||
NonResourceAttributes: &authorizationapi.NonResourceAttributes{},
|
||||
},
|
||||
msg: "cannot be specified in combination with resourceAttributes",
|
||||
}, {
|
||||
// here we only test one to be sure the function is called. The more exhaustive suite is tested above.
|
||||
name: "resource attributes: label selector specify both",
|
||||
obj: authorizationapi.SelfSubjectAccessReviewSpec{
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
RawSelector: "foo",
|
||||
Requirements: []metav1.LabelSelectorRequirement{
|
||||
{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: `spec.resourceAttributes.labelSelector.rawSelector: Invalid value: "foo": may not specified at the same time as requirements`,
|
||||
}}
|
||||
|
||||
for _, c := range errorCases {
|
||||
@@ -175,6 +461,23 @@ func TestValidateLocalSAR(t *testing.T) {
|
||||
},
|
||||
},
|
||||
msg: "disallowed on this kind of request",
|
||||
}, {
|
||||
// here we only test one to be sure the function is called. The more exhaustive suite is tested above.
|
||||
name: "resource attributes: label selector specify both",
|
||||
obj: &authorizationapi.LocalSubjectAccessReview{
|
||||
Spec: authorizationapi.SubjectAccessReviewSpec{
|
||||
User: "user",
|
||||
ResourceAttributes: &authorizationapi.ResourceAttributes{
|
||||
LabelSelector: &authorizationapi.LabelSelectorAttributes{
|
||||
RawSelector: "foo",
|
||||
Requirements: []metav1.LabelSelectorRequirement{
|
||||
{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
msg: `spec.resourceAttributes.labelSelector.rawSelector: Invalid value: "foo": may not specified at the same time as requirements`,
|
||||
}}
|
||||
|
||||
for _, c := range errorCases {
|
||||
|
||||
Reference in New Issue
Block a user