Skip to content

Commit 611176d

Browse files
author
OpenShift Bot
authored
Merge pull request #13495 from enj/enj/i/attribute_restrictions_policy
Merged by openshift-bot
2 parents 2ac05d6 + 03bcc7c commit 611176d

File tree

6 files changed

+449
-39
lines changed

6 files changed

+449
-39
lines changed

pkg/authorization/api/validation/validation.go

+52-9
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ func ValidateClusterPolicyUpdate(policy *authorizationapi.ClusterPolicy, oldPoli
134134
}
135135

136136
func ValidatePolicy(policy *authorizationapi.Policy, isNamespaced bool) field.ErrorList {
137+
return validatePolicy(policy, isNamespaced, false)
138+
}
139+
140+
func validatePolicy(policy *authorizationapi.Policy, isNamespaced, skipRoleValidation bool) field.ErrorList {
137141
allErrs := validation.ValidateObjectMeta(&policy.ObjectMeta, isNamespaced, ValidatePolicyName, field.NewPath("metadata"))
138142

139143
rolePath := field.NewPath("roles")
@@ -147,16 +151,32 @@ func ValidatePolicy(policy *authorizationapi.Policy, isNamespaced bool) field.Er
147151
allErrs = append(allErrs, field.Invalid(keyPath.Child("metadata", "name"), role.Name, "must be "+roleKey))
148152
}
149153

150-
allErrs = append(allErrs, validateRole(role, isNamespaced, keyPath)...)
154+
if !skipRoleValidation {
155+
allErrs = append(allErrs, validateRole(role, isNamespaced, keyPath)...) // policy creation validation is more strict
156+
}
151157
}
152158

153159
return allErrs
154160
}
155161

156162
func ValidatePolicyUpdate(policy *authorizationapi.Policy, oldPolicy *authorizationapi.Policy, isNamespaced bool) field.ErrorList {
157-
allErrs := ValidatePolicy(policy, isNamespaced)
163+
// We skip role validation here because we handle it below
164+
// It needs to based on if the role is an existing one vs. a new one
165+
allErrs := validatePolicy(policy, isNamespaced, true)
158166
allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(&policy.ObjectMeta, &oldPolicy.ObjectMeta, field.NewPath("metadata"))...)
159-
167+
rolePath := field.NewPath("roles")
168+
for roleKey, role := range policy.Roles {
169+
if role == nil {
170+
continue // these cause errors in validatePolicy so we do not worry about them
171+
}
172+
keyPath := rolePath.Key(roleKey)
173+
oldRole, isExistingRole := oldPolicy.Roles[roleKey]
174+
if isExistingRole {
175+
allErrs = append(allErrs, validateRoleUpdate(role, oldRole, isNamespaced, keyPath)...)
176+
} else {
177+
allErrs = append(allErrs, validateRole(role, isNamespaced, keyPath)...) // new roles have stricter validation
178+
}
179+
}
160180
return allErrs
161181
}
162182

@@ -236,15 +256,15 @@ func ValidateLocalRole(policy *authorizationapi.Role) field.ErrorList {
236256
}
237257

238258
func ValidateLocalRoleUpdate(policy *authorizationapi.Role, oldRole *authorizationapi.Role) field.ErrorList {
239-
return ValidateRoleUpdate(policy, oldRole, true)
259+
return ValidateRoleUpdate(policy, oldRole, true, nil)
240260
}
241261

242262
func ValidateClusterRole(policy *authorizationapi.ClusterRole) field.ErrorList {
243263
return ValidateRole(authorizationapi.ToRole(policy), false)
244264
}
245265

246266
func ValidateClusterRoleUpdate(policy *authorizationapi.ClusterRole, oldRole *authorizationapi.ClusterRole) field.ErrorList {
247-
return ValidateRoleUpdate(authorizationapi.ToRole(policy), authorizationapi.ToRole(oldRole), false)
267+
return ValidateRoleUpdate(authorizationapi.ToRole(policy), authorizationapi.ToRole(oldRole), false, nil)
248268
}
249269

250270
func ValidateRole(role *authorizationapi.Role, isNamespaced bool) field.ErrorList {
@@ -253,21 +273,44 @@ func ValidateRole(role *authorizationapi.Role, isNamespaced bool) field.ErrorLis
253273

254274
func validateRole(role *authorizationapi.Role, isNamespaced bool, fldPath *field.Path) field.ErrorList {
255275
allErrs := validation.ValidateObjectMeta(&role.ObjectMeta, isNamespaced, path.ValidatePathSegmentName, fldPath.Child("metadata"))
276+
rulesPath := fldPath.Child("rules")
256277
for i, rule := range role.Rules {
257278
if rule.AttributeRestrictions != nil {
258-
allErrs = append(allErrs, field.Invalid(fldPath.Child("rules").Index(i).Child("attributeRestrictions"), rule.AttributeRestrictions, "must be null"))
279+
allErrs = append(allErrs, field.Invalid(rulesPath.Index(i).Child("attributeRestrictions"), rule.AttributeRestrictions, "must be null"))
259280
}
260281
}
261282
return allErrs
262283
}
263284

264-
func ValidateRoleUpdate(role *authorizationapi.Role, oldRole *authorizationapi.Role, isNamespaced bool) field.ErrorList {
265-
allErrs := ValidateRole(role, isNamespaced)
266-
allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(&role.ObjectMeta, &oldRole.ObjectMeta, field.NewPath("metadata"))...)
285+
func ValidateRoleUpdate(role *authorizationapi.Role, oldRole *authorizationapi.Role, isNamespaced bool, fldPath *field.Path) field.ErrorList {
286+
allErrs := validateRoleUpdate(role, oldRole, isNamespaced, fldPath)
287+
// We can use ValidateObjectMetaUpdate here because we know that we are validating a single role, and not a role embedded inside a policy object
288+
allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(&role.ObjectMeta, &oldRole.ObjectMeta, fldPath.Child("metadata"))...)
289+
return allErrs
290+
}
267291

292+
func validateRoleUpdate(role *authorizationapi.Role, oldRole *authorizationapi.Role, isNamespaced bool, fldPath *field.Path) field.ErrorList {
293+
// We use ValidateObjectMeta here because roles embedded inside of policy objects are not guaranteed to
294+
// have a resource version and thus will fail the policy's validation if ValidateObjectMetaUpdate was used
295+
allErrs := validation.ValidateObjectMeta(&role.ObjectMeta, isNamespaced, path.ValidatePathSegmentName, fldPath.Child("metadata"))
296+
rulesPath := fldPath.Child("rules")
297+
for i, rule := range role.Rules {
298+
if rule.AttributeRestrictions != nil && isNewRule(rule, oldRole) {
299+
allErrs = append(allErrs, field.Invalid(rulesPath.Index(i).Child("attributeRestrictions"), rule.AttributeRestrictions, "must be null"))
300+
}
301+
}
268302
return allErrs
269303
}
270304

305+
func isNewRule(rule authorizationapi.PolicyRule, oldRole *authorizationapi.Role) bool {
306+
for _, r := range oldRole.Rules {
307+
if r.AttributeRestrictions != nil && kapi.Semantic.DeepEqual(rule, r) { // only do expensive comparision against rules that have attribute restrictions
308+
return false
309+
}
310+
}
311+
return true
312+
}
313+
271314
func ValidateLocalRoleBinding(policy *authorizationapi.RoleBinding) field.ErrorList {
272315
return ValidateRoleBinding(policy, true)
273316
}

0 commit comments

Comments
 (0)