8000 Merge branch 'main' into validate-jwt-token-with-regex · nginx/kubernetes-ingress@58a3d46 · GitHub
[go: up one dir, main page]

Skip to content

Commit 58a3d46

Browse files
shaun-nxhaywoodsh
authored andcommitted
Merge branch 'main' into validate-jwt-token-with-regex
2 parents 9d128a0 + 48f9a8b commit 58a3d46

File tree

2 files changed

+110
-18
lines changed

2 files changed

+110
-18
lines changed

internal/k8s/validation.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,24 @@ const (
6464
)
6565

6666
const (
67-
commaDelimiter = ","
68-
annotationValueFmt = `([^"$\\]|\\[^$])*`
69-
jwtTokenValueFmt = "\\$" + annotationValueFmt
67+
commaDelimiter = ","
68+
annotationValueFmt = `([^"$\\]|\\[^$])*`
69+
pathFmt = `/[^\s{};]*`
70+
jwtTokenValueFmt = "\\$" + annotationValueFmt
71+
)
72+
73+
const (
7074
annotationValueFmtErrMsg = `a valid annotation value must have all '"' escaped and must not contain any '$' or end with an unescaped '\'`
75+
pathErrMsg = "must start with / and must not include any whitespace character, `{`, `}` or `;`"
7176
jwtTokenValueFmtErrMsg = `a valid annotation value must start with '$', have all '"' escaped, and must not contain any '$' or end with an unescaped '\'`
7277
)
7378

79+
var (
80+
pathRegexp = regexp.MustCompile("^" + pathFmt + "$")
81+
validAnnotationValueRegex = regexp.MustCompile("^" + annotationValueFmt + "$")
82+
validJWTTokenAnnotationValueRegex = regexp.MustCompile("^" + jwtTokenValueFmt + "$")
83+
)
84+
7485
type annotationValidationContext struct {
7586
annotations map[string]string
7687
specServices map[string]bool
@@ -90,9 +101,6 @@ type (
90101
validatorFunc func(val string) error
91102
)
92103

93-
var validAnnotationValueRegex = regexp.MustCompile("^" + annotationValueFmt + "$")
94-
var validJWTTokenAnnotationValueRegex = regexp.MustCompile("^" + jwtTokenValueFmt + "$")
95-
96104
var (
97105
// annotationValidations defines the various validations which will be applied in order to each ingress annotation.
98106
// If any specified validation fails, the remaining validations for that annotation will not be run.
@@ -729,6 +737,7 @@ func validateIngressSpec(spec *networking.IngressSpec, fieldPath *field.Path) fi
729737
for _, path := range r.HTTP.Paths {
730738
idxPath := idxRule.Child("http").Child("path").Index(i)
731739

740+
allErrs = append(allErrs, validatePath(path.Path, fieldPath)...)
732741
allErrs = append(allErrs, validateBackend(&path.Backend, idxPath.Child("backend"))...)
733742
}
734743
}
@@ -746,6 +755,21 @@ func validateBackend(backend *networking.IngressBackend, fieldPath *field.Path)
746755
return allErrs
747756
}
748757

758+
func validatePath(path string, fieldPath *field.Path) field.ErrorList {
759+
allErrs := field.ErrorList{}
760+
761+
if path == "" {
762+
return append(allErrs, field.Required(fieldPath, ""))
763+
}
764+
765+
if !pathRegexp.MatchString(path) {
766+
msg := validation.RegexError(pathErrMsg, pathFmt, "/", "/path", "/path/subpath-123")
767+
return append(allErrs, field.Invalid(fieldPath, path, msg))
768+
}
769+
770+
return allErrs
771+
}
772+
749773
func validateMasterSpec(spec *networking.IngressSpec, fieldPath *field.Path) field.ErrorList {
750774
allErrs := field.ErrorList{}
751775

internal/k8s/validation_test.go

Lines changed: 80 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2544,7 +2544,7 @@ func TestValidateNginxIngressAnnotations(t *testing.T) {
25442544
func TestValidateIngressSpec(t *testing.T) {
25452545
tests := []struct {
25462546
spec *networking.IngressSpec
2547-
expectedErrors []string
2547+
expectedErrors []field.ErrorType
25482548
msg string
25492549
}{
25502550
{
@@ -2570,6 +2570,56 @@ func TestValidateIngressSpec(t *testing.T) {
25702570
expectedErrors: nil,
25712571
msg: "valid input",
25722572
},
2573+
{
2574+
spec: &networking.IngressSpec{
2575+
Rules: []networking.IngressRule{
2576+
{
2577+
Host: "foo.example.com",
2578+
IngressRuleValue: networking.IngressRuleValue{
2579+
HTTP: &networking.HTTPIngressRuleValue{
2580+
Paths: []networking.HTTPIngressPath{
2581+
{
2582+
Path: `/tea\{custom_value}`,
2583+
Backend: networking.IngressBackend{
2584+
Service: &networking.IngressServiceBackend{},
2585+
},
2586+
},
2587+
},
2588+
},
2589+
},
2590+
},
2591+
},
2592+
},
2593+
expectedErrors: []field.ErrorType{
2594+
field.ErrorTypeInvalid,
2595+
},
2596+
msg: "test invalid characters in path",
2597+
},
2598+
{
2599+
spec: &networking.IngressSpec{
2600+
Rules: []networking.IngressRule{
2601+
{
2602+
Host: "foo.example.com",
2603+
IngressRuleValue: networking.IngressRuleValue{
2604+
HTTP: &networking.HTTPIngressRuleValue{
2605+
Paths: []networking.HTTPIngressPath{
2606+
{
2607+
Path: "",
2608+
Backend: networking.IngressBackend{
2609+
Service: &networking.IngressServiceBackend{},
2610+
},
2611+
},
2612+
},
2613+
},
2614+
},
2615+
},
2616+
},
2617+
},
2618+
expectedErrors: []field.ErrorType{
2619+
field.ErrorTypeRequired,
2620+
},
2621+
msg: "test empty in path",
2622+
},
25732623
{
25742624
spec: &networking.IngressSpec{
25752625
DefaultBackend: &networking.IngressBackend{
@@ -2588,8 +2638,8 @@ func TestValidateIngressSpec(t *testing.T) {
25882638
spec: &networking.IngressSpec{
25892639
Rules: []networking.IngressRule{},
25902640
},
2591-
expectedErrors: []string{
2592-
"spec.rules: Required value",
2641+
expectedErrors: []field.ErrorType{
2642+
field.ErrorTypeRequired,
25932643
},
25942644
msg: "zero rules",
25952645
},
@@ -2601,8 +2651,8 @@ func TestValidateIngressSpec(t *testing.T) {
26012651
},
26022652
},
26032653
},
2604-
expectedErrors: []string{
2605-
"spec.rules[0].host: Required value",
2654+
expectedErrors: []field.ErrorType{
2655+
field.ErrorTypeRequired,
26062656
},
26072657
msg: "empty host",
26082658
},
@@ -2617,8 +2667,8 @@ func TestValidateIngressSpec(t *testing.T) {
26172667
},
26182668
},
26192669
},
2620-
expectedErrors: []string{
2621-
`spec.rules[1].host: Duplicate value: "foo.example.com"`,
2670+
expectedErrors: []field.ErrorType{
2671+
field.ErrorTypeDuplicate,
26222672
},
26232673
msg: "duplicated host",
26242674
},
@@ -2633,8 +2683,8 @@ func TestValidateIngressSpec(t *testing.T) {
26332683
},
26342684
},
26352685
},
2636-
expectedErrors: []string{
2637-
"spec.defaultBackend.resource: Forbidden: resource backends are not supported",
2686+
expectedErrors: []field.ErrorType{
2687+
field.ErrorTypeForbidden,
26382688
},< 6968 /div>
26392689
msg: "invalid default backend",
26402690
},
@@ -2658,16 +2708,16 @@ func TestValidateIngressSpec(t *testing.T) {
26582708
},
26592709
},
26602710
},
2661-
expectedErrors: []string{
2662-
"spec.rules[0].http.path[0].backend.resource: Forbidden: resource backends are not supported",
2711+
expectedErrors: []field.ErrorType{
2712+
field.ErrorTypeForbidden,
26632713
},
26642714
msg: "invalid backend",
26652715
},
26662716
}
26672717

26682718
for _, test := range tests {
26692719
allErrs := validateIngressSpec(test.spec, field.NewPath("spec"))
2670-
assertion := assertErrors("validateIngressSpec()", test.msg, allErrs, test.expectedErrors)
2720+
assertion := assertErrorTypes(test.msg, allErrs, test.expectedErrors)
26712721
if assertion != "" {
26722722
t.Error(assertion)
26732723
}
@@ -2843,6 +2893,14 @@ func TestValidateMinionSpec(t *testing.T) {
28432893
}
28442894
}
28452895

2896+
func assertErrorTypes(msg string, allErrs field.ErrorList, expectedErrors []field.ErrorType) string {
2897+
returnedErrors := errorListToTypes(allErrs)
2898+
if !reflect.DeepEqual(returnedErrors, expectedErrors) {
2899+
return fmt.Sprintf("%s returned %s but expected %s", msg, returnedErrors, expectedErrors)
2900+
}
2901+
return ""
2902+
}
2903+
28462904
func assertErrors(funcName string, msg string, allErrs field.ErrorList, expectedErrors []string) string {
28472905
errors := errorListToStrings(allErrs)
28482906
if !reflect.DeepEqual(errors, expectedErrors) {
@@ -2865,6 +2923,16 @@ func errorListToStrings(list field.ErrorList) []string {
28652923
return result
28662924
}
28672925

2926+
func errorListToTypes(list field.ErrorList) []field.ErrorType {
2927+
var result []field.ErrorType
2928+
2929+
for _, e := range list {
2930+
result = append(result, e.Type)
2931+
}
2932+
2933+
return result
2934+
}
2935+
28682936
func TestGetSpecServices(t *testing.T) {
28692937
tests := []struct {
28702938
spec networking.IngressSpec

0 commit comments

Comments
 (0)
0