Skip to content

Commit 0a927b6

Browse files
Allow CORS Access-Control-Allow-Origin: null (kubernetes#12402)
1 parent a5cd15d commit 0a927b6

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

internal/ingress/annotations/cors/main.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ var (
4040
// that could cause the Response to contain some internal value/variable (like returning $pid, $upstream_addr, etc)
4141
// Origin must contain a http/s Origin (including or not the port) or the value '*'
4242
// This Regex is composed of the following:
43-
// * Sets a group that can be (https?://)?*?.something.com:port?
43+
// * Sets a group that can be (https?://)?*?.something.com:port? OR null
4444
// * Allows this to be repeated as much as possible, and separated by comma
4545
// Otherwise it should be '*'
46-
corsOriginRegexValidator = regexp.MustCompile(`^(((([a-z]+://)?(\*\.)?[A-Za-z0-9\-.]*(:\d+)?,?)+)|\*)?$`)
46+
corsOriginRegexValidator = regexp.MustCompile(`^((((([a-z]+://)?(\*\.)?[A-Za-z0-9\-.]*(:\d+)?,?)|null)+)|\*)?$`)
4747
// corsOriginRegex defines the regex for validation inside Parse
48-
corsOriginRegex = regexp.MustCompile(`^([a-z]+://(\*\.)?[A-Za-z0-9\-.]*(:\d+)?|\*)?$`)
48+
corsOriginRegex = regexp.MustCompile(`^([a-z]+://(\*\.)?[A-Za-z0-9\-.]*(:\d+)?|\*|null)?$`)
4949
// Method must contain valid methods list (PUT, GET, POST, BLA)
5050
// May contain or not spaces between each verb
5151
corsMethodsRegex = regexp.MustCompile(`^([A-Za-z]+,?\s?)+$`)
@@ -78,7 +78,7 @@ var corsAnnotation = parser.Annotation{
7878
Scope: parser.AnnotationScopeIngress,
7979
Risk: parser.AnnotationRiskMedium,
8080
Documentation: `This annotation controls what's the accepted Origin for CORS.
81-
This is a multi-valued field, separated by ','. It must follow this format: protocol://origin-site.com or protocol://origin-site.com:port
81+
This is a multi-valued field, separated by ','. It must follow this format: protocol://origin-site.com, protocol://origin-site.com:port, null, or *.
8282
It also supports single level wildcard subdomains and follows this format: https://*.foo.bar, http://*.bar.foo:8080 or myprotocol://*.abc.bar.foo:9000
8383
Protocol can be any lowercase string, like http, https, or mycustomprotocol.`,
8484
},

internal/ingress/annotations/cors/main_test.go

+33-3
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func TestIngressCorsConfigValid(t *testing.T) {
8282
data[parser.GetAnnotationWithPrefix(corsAllowHeadersAnnotation)] = "DNT,X-CustomHeader, Keep-Alive,User-Agent"
8383
data[parser.GetAnnotationWithPrefix(corsAllowCredentialsAnnotation)] = "false"
8484
data[parser.GetAnnotationWithPrefix(corsAllowMethodsAnnotation)] = "GET, PATCH"
85-
data[parser.GetAnnotationWithPrefix(corsAllowOriginAnnotation)] = "https://origin123.test.com:4443"
85+
data[parser.GetAnnotationWithPrefix(corsAllowOriginAnnotation)] = "null, https://origin123.test.com:4443"
8686
data[parser.GetAnnotationWithPrefix(corsExposeHeadersAnnotation)] = "*, X-CustomResponseHeader"
8787
data[parser.GetAnnotationWithPrefix(corsMaxAgeAnnotation)] = "600"
8888
ing.SetAnnotations(data)
@@ -113,7 +113,7 @@ func TestIngressCorsConfigValid(t *testing.T) {
113113
t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix(corsAllowMethodsAnnotation)], nginxCors.CorsAllowMethods)
114114
}
115115

116-
if nginxCors.CorsAllowOrigin[0] != "https://origin123.test.com:4443" {
116+
if !reflect.DeepEqual(nginxCors.CorsAllowOrigin, []string{"null", "https://origin123.test.com:4443"}) {
117117
t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix(corsAllowOriginAnnotation)], nginxCors.CorsAllowOrigin)
118118
}
119119

@@ -176,7 +176,7 @@ func TestIngressCorsConfigInvalid(t *testing.T) {
176176
}
177177
}
178178

179-
func TestIngresCorsConfigAllowOriginWithTrailingComma(t *testing.T) {
179+
func TestIngressCorsConfigAllowOriginWithTrailingComma(t *testing.T) {
180180
ing := buildIngress()
181181

182182
data := map[string]string{}
@@ -206,6 +206,36 @@ func TestIngresCorsConfigAllowOriginWithTrailingComma(t *testing.T) {
206206
}
207207
}
208208

209+
func TestIngressCorsConfigAllowOriginNull(t *testing.T) {
210+
ing := buildIngress()
211+
212+
data := map[string]string{}
213+
data[parser.GetAnnotationWithPrefix(corsEnableAnnotation)] = enableAnnotation
214+
215+
// Include a trailing comma and an empty value between the commas.
216+
data[parser.GetAnnotationWithPrefix(corsAllowOriginAnnotation)] = "https://origin123.test.com:4443,null,https://origin321.test.com:4443"
217+
ing.SetAnnotations(data)
218+
219+
corst, err := NewParser(&resolver.Mock{}).Parse(ing)
220+
if err != nil {
221+
t.Errorf("error parsing annotations: %v", err)
222+
}
223+
224+
nginxCors, ok := corst.(*Config)
225+
if !ok {
226+
t.Errorf("expected a Config type but returned %t", corst)
227+
}
228+
229+
if !nginxCors.CorsEnabled {
230+
t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix(corsEnableAnnotation)], nginxCors.CorsEnabled)
231+
}
232+
233+
expectedCorsAllowOrigins := []string{"https://origin123.test.com:4443", "null", "https://origin321.test.com:4443"}
234+
if !reflect.DeepEqual(nginxCors.CorsAllowOrigin, expectedCorsAllowOrigins) {
235+
t.Errorf("expected %v but returned %v", expectedCorsAllowOrigins, nginxCors.CorsAllowOrigin)
236+
}
237+
}
238+
209239
func TestIngressCorsConfigAllowOriginWithNonHttpProtocol(t *testing.T) {
210240
ing := buildIngress()
211241

0 commit comments

Comments
 (0)