Merge pull request #6217 from touchifyapp/@feature/cors-expose-headers

Add annotation to configure CORS Access-Control-Expose-Headers
This commit is contained in:
Kubernetes Prow Robot 2020-09-26 16:52:48 -07:00 committed by GitHub
commit 6fd891f3df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 54 additions and 5 deletions

View file

@ -37,6 +37,7 @@ var (
annotationCorsEnabled = parser.GetAnnotationWithPrefix("enable-cors")
annotationCorsAllowMethods = parser.GetAnnotationWithPrefix("cors-allow-methods")
annotationCorsAllowHeaders = parser.GetAnnotationWithPrefix("cors-allow-headers")
annotationCorsExposeHeaders = parser.GetAnnotationWithPrefix("cors-expose-headers")
annotationCorsAllowCredentials = parser.GetAnnotationWithPrefix("cors-allow-credentials")
backendProtocol = parser.GetAnnotationWithPrefix("backend-protocol")
defaultCorsMethods = "GET, PUT, POST, DELETE, PATCH, OPTIONS"
@ -201,12 +202,13 @@ func TestCors(t *testing.T) {
headers string
origin string
credentials bool
expose string
}{
{map[string]string{annotationCorsEnabled: "true"}, true, defaultCorsMethods, defaultCorsHeaders, "*", true},
{map[string]string{annotationCorsEnabled: "true", annotationCorsAllowMethods: "POST, GET, OPTIONS", annotationCorsAllowHeaders: "$nginx_version", annotationCorsAllowCredentials: "false"}, true, "POST, GET, OPTIONS", defaultCorsHeaders, "*", false},
{map[string]string{annotationCorsEnabled: "true", annotationCorsAllowCredentials: "false"}, true, defaultCorsMethods, defaultCorsHeaders, "*", false},
{map[string]string{}, false, defaultCorsMethods, defaultCorsHeaders, "*", true},
{nil, false, defaultCorsMethods, defaultCorsHeaders, "*", true},
{map[string]string{annotationCorsEnabled: "true"}, true, defaultCorsMethods, defaultCorsHeaders, "*", true, ""},
{map[string]string{annotationCorsEnabled: "true", annotationCorsAllowMethods: "POST, GET, OPTIONS", annotationCorsAllowHeaders: "$nginx_version", annotationCorsAllowCredentials: "false", annotationCorsExposeHeaders: "X-CustomResponseHeader"}, true, "POST, GET, OPTIONS", defaultCorsHeaders, "*", false, "X-CustomResponseHeader"},
{map[string]string{annotationCorsEnabled: "true", annotationCorsAllowCredentials: "false"}, true, defaultCorsMethods, defaultCorsHeaders, "*", false, ""},
{map[string]string{}, false, defaultCorsMethods, defaultCorsHeaders, "*", true, ""},
{nil, false, defaultCorsMethods, defaultCorsHeaders, "*", true, ""},
}
for _, foo := range fooAnns {

View file

@ -43,6 +43,9 @@ var (
// Headers must contain valid values only (X-HEADER12, X-ABC)
// May contain or not spaces between each Header
corsHeadersRegex = regexp.MustCompile(`^([A-Za-z0-9\-\_]+,?\s?)+$`)
// Expose Headers must contain valid values only (*, X-HEADER12, X-ABC)
// May contain or not spaces between each Header
corsExposeHeadersRegex = regexp.MustCompile(`^(([A-Za-z0-9\-\_]+|\*),?\s?)+$`)
)
type cors struct {
@ -56,6 +59,7 @@ type Config struct {
CorsAllowMethods string `json:"corsAllowMethods"`
CorsAllowHeaders string `json:"corsAllowHeaders"`
CorsAllowCredentials bool `json:"corsAllowCredentials"`
CorsExposeHeaders string `json:"corsExposeHeaders"`
CorsMaxAge int `json:"corsMaxAge"`
}
@ -75,6 +79,9 @@ func (c1 *Config) Equal(c2 *Config) bool {
if c1.CorsMaxAge != c2.CorsMaxAge {
return false
}
if c1.CorsExposeHeaders != c2.CorsExposeHeaders {
return false
}
if c1.CorsAllowCredentials != c2.CorsAllowCredentials {
return false
}
@ -125,6 +132,11 @@ func (c cors) Parse(ing *networking.Ingress) (interface{}, error) {
config.CorsAllowCredentials = true
}
config.CorsExposeHeaders, err = parser.GetStringAnnotation("cors-expose-headers", ing)
if err != nil || !corsExposeHeadersRegex.MatchString(config.CorsExposeHeaders) {
config.CorsExposeHeaders = ""
}
config.CorsMaxAge, err = parser.GetIntAnnotation("cors-max-age", ing)
if err != nil {
config.CorsMaxAge = defaultCorsMaxAge

View file

@ -73,6 +73,7 @@ func TestIngressCorsConfigValid(t *testing.T) {
data[parser.GetAnnotationWithPrefix("cors-allow-credentials")] = "false"
data[parser.GetAnnotationWithPrefix("cors-allow-methods")] = "GET, PATCH"
data[parser.GetAnnotationWithPrefix("cors-allow-origin")] = "https://origin123.test.com:4443"
data[parser.GetAnnotationWithPrefix("cors-expose-headers")] = "*, X-CustomResponseHeader"
data[parser.GetAnnotationWithPrefix("cors-max-age")] = "600"
ing.SetAnnotations(data)
@ -106,6 +107,10 @@ func TestIngressCorsConfigValid(t *testing.T) {
t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix("cors-allow-origin")], nginxCors.CorsAllowOrigin)
}
if nginxCors.CorsExposeHeaders != "*, X-CustomResponseHeader" {
t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix("cors-expose-headers")], nginxCors.CorsExposeHeaders)
}
if nginxCors.CorsMaxAge != 600 {
t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix("cors-max-age")], nginxCors.CorsMaxAge)
}
@ -122,6 +127,7 @@ func TestIngressCorsConfigInvalid(t *testing.T) {
data[parser.GetAnnotationWithPrefix("cors-allow-credentials")] = "no"
data[parser.GetAnnotationWithPrefix("cors-allow-methods")] = "GET, PATCH, $nginx"
data[parser.GetAnnotationWithPrefix("cors-allow-origin")] = "origin123.test.com:4443"
data[parser.GetAnnotationWithPrefix("cors-expose-headers")] = "@alright, #ingress"
data[parser.GetAnnotationWithPrefix("cors-max-age")] = "abcd"
ing.SetAnnotations(data)
@ -155,6 +161,10 @@ func TestIngressCorsConfigInvalid(t *testing.T) {
t.Errorf("expected %v but returned %v", "*", nginxCors.CorsAllowOrigin)
}
if nginxCors.CorsExposeHeaders != "" {
t.Errorf("expected %v but returned %v", "", nginxCors.CorsExposeHeaders)
}
if nginxCors.CorsMaxAge != defaultCorsMaxAge {
t.Errorf("expected %v but returned %v", defaultCorsMaxAge, nginxCors.CorsMaxAge)
}