Skip to content

Commit f92c8e7

Browse files
committed
UPSTREAM: <carry>: admission: authentication: validate CEL expressions compilation
Signed-off-by: Bryce Palmer <[email protected]>
1 parent 6f85aef commit f92c8e7

File tree

2 files changed

+133
-2
lines changed

2 files changed

+133
-2
lines changed

openshift-kube-apiserver/admission/customresourcevalidation/authentication/validate_authentication.go

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"k8s.io/apiserver/pkg/admission"
1313

1414
configv1 "github.com/openshift/api/config/v1"
15+
authenticationcel "k8s.io/apiserver/pkg/authentication/cel"
1516
crvalidation "k8s.io/kubernetes/openshift-kube-apiserver/admission/customresourcevalidation"
1617
)
1718

@@ -121,14 +122,83 @@ func validateAuthenticationSpec(spec configv1.AuthenticationSpec) field.ErrorLis
121122
spec.WebhookTokenAuthenticator, fmt.Sprintf("this field cannot be set with the %q .spec.type", spec.Type),
122123
))
123124
}
124-
125125
}
126126

127127
errs = append(errs, crvalidation.ValidateConfigMapReference(specField.Child("oauthMetadata"), spec.OAuthMetadata, false)...)
128128

129+
// Perform External OIDC Provider related validations
130+
// ----------------
131+
132+
// There is currently no guarantee that these fields are not set when the spec.Type is != OIDC.
133+
// To ensure we are enforcing approriate admission validations at all times, just always iterate through the list
134+
// of OIDC Providers and perform the validations.
135+
// If/when the openshift/api admission validations are updated to enforce that this field is not configured
136+
// when Type != OIDC, this loop should be a no-op due to an empty list.
137+
for i, provider := range spec.OIDCProviders {
138+
errs = append(errs, validateOIDCProvider(specField.Child("oidcProviders").Index(i), provider)...)
139+
}
140+
// ----------------
141+
129142
return errs
130143
}
131144

132145
func validateAuthenticationStatus(status configv1.AuthenticationStatus) field.ErrorList {
133146
return crvalidation.ValidateConfigMapReference(field.NewPath("status", "integratedOAuthMetadata"), status.IntegratedOAuthMetadata, false)
134147
}
148+
149+
func validateOIDCProvider(path *field.Path, provider configv1.OIDCProvider) field.ErrorList {
150+
errs := field.ErrorList{}
151+
errs = append(errs, validateClaimMappings(path, provider.ClaimMappings)...)
152+
return errs
153+
}
154+
155+
func validateClaimMappings(path *field.Path, claimMappings configv1.TokenClaimMappings) field.ErrorList {
156+
path = path.Child("claimMappings")
157+
errs := field.ErrorList{}
158+
compiler := authenticationcel.NewDefaultCompiler()
159+
errs = append(errs, validateUIDClaimMapping(path, compiler, claimMappings.UID)...)
160+
errs = append(errs, validateExtraClaimMapping(path, compiler, claimMappings.Extra...)...)
161+
return errs
162+
}
163+
164+
func validateUIDClaimMapping(path *field.Path, compiler authenticationcel.Compiler, uid *configv1.TokenClaimOrExpressionMapping) field.ErrorList {
165+
if uid == nil {
166+
return nil
167+
}
168+
169+
if uid.Expression != "" {
170+
err := validateCELExpression(compiler, &authenticationcel.ClaimMappingExpression{
171+
Expression: uid.Expression,
172+
})
173+
if err != nil {
174+
return field.ErrorList{field.Invalid(path.Child("uid", "expression"), uid.Expression, err.Error())}
175+
}
176+
}
177+
178+
return nil
179+
}
180+
181+
func validateExtraClaimMapping(path *field.Path, compiler authenticationcel.Compiler, extras ...configv1.ExtraMapping) field.ErrorList {
182+
errs := field.ErrorList{}
183+
for i, extra := range extras {
184+
errs = append(errs, validateExtra(path.Child("extra").Index(i), compiler, extra)...)
185+
}
186+
return errs
187+
}
188+
189+
func validateExtra(path *field.Path, compiler authenticationcel.Compiler, extra configv1.ExtraMapping) field.ErrorList {
190+
err := validateCELExpression(compiler, &authenticationcel.ExtraMappingExpression{
191+
Key: extra.Key,
192+
Expression: extra.ValueExpression,
193+
})
194+
if err != nil {
195+
return field.ErrorList{field.Invalid(path.Child("valueExpression"), extra.ValueExpression, err.Error())}
196+
}
197+
198+
return nil
199+
}
200+
201+
func validateCELExpression(compiler authenticationcel.Compiler, accessor authenticationcel.ExpressionAccessor) error {
202+
_, err := compiler.CompileClaimsExpression(accessor)
203+
return err
204+
}

openshift-kube-apiserver/admission/customresourcevalidation/authentication/validate_authentication_test.go

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,41 @@ func TestFailValidateAuthenticationSpec(t *testing.T) {
4949
errorType: field.ErrorTypeInvalid,
5050
errorField: "spec.webhookTokenAuthenticator",
5151
},
52+
"invalid UID CEL expression": {
53+
spec: configv1.AuthenticationSpec{
54+
Type: "OIDC",
55+
OIDCProviders: []configv1.OIDCProvider{
56+
{
57+
ClaimMappings: configv1.TokenClaimMappings{
58+
UID: &configv1.TokenClaimOrExpressionMapping{
59+
Expression: "!@^#&(!^@(*#&(",
60+
},
61+
},
62+
},
63+
},
64+
},
65+
errorType: field.ErrorTypeInvalid,
66+
errorField: "spec.oidcProviders[0].claimMappings.uid.expression",
67+
},
68+
"invalid Extra CEL expression": {
69+
spec: configv1.AuthenticationSpec{
70+
Type: "OIDC",
71+
OIDCProviders: []configv1.OIDCProvider{
72+
{
73+
ClaimMappings: configv1.TokenClaimMappings{
74+
Extra: []configv1.ExtraMapping{
75+
{
76+
Key: "foo/bar",
77+
ValueExpression: "!@*(&#^(!@*)&^&",
78+
},
79+
},
80+
},
81+
},
82+
},
83+
},
84+
errorType: field.ErrorTypeInvalid,
85+
errorField: "spec.oidcProviders[0].claimMappings.extra[0].valueExpression",
86+
},
5287
}
5388

5489
for tcName, tc := range errorCases {
@@ -109,6 +144,33 @@ func TestSucceedValidateAuthenticationSpec(t *testing.T) {
109144
{KubeConfig: configv1.SecretNameReference{Name: "thisisawebhook33"}},
110145
},
111146
},
147+
"valid uid CEL expression": {
148+
Type: "OIDC",
149+
OIDCProviders: []configv1.OIDCProvider{
150+
{
151+
ClaimMappings: configv1.TokenClaimMappings{
152+
UID: &configv1.TokenClaimOrExpressionMapping{
153+
Expression: "claims.uid",
154+
},
155+
},
156+
},
157+
},
158+
},
159+
"valid Extra CEL expression": {
160+
Type: "OIDC",
161+
OIDCProviders: []configv1.OIDCProvider{
162+
{
163+
ClaimMappings: configv1.TokenClaimMappings{
164+
Extra: []configv1.ExtraMapping{
165+
{
166+
Key: "foo/bar",
167+
ValueExpression: "claims.roles",
168+
},
169+
},
170+
},
171+
},
172+
},
173+
},
112174
}
113175

114176
for tcName, s := range successCases {
@@ -175,5 +237,4 @@ func TestSucceedValidateAuthenticationStatus(t *testing.T) {
175237
t.Errorf("'%s': expected success, but failed: %v", tcName, errs.ToAggregate().Error())
176238
}
177239
}
178-
179240
}

0 commit comments

Comments
 (0)