Support cors-allow-origin with multiple origins (#7614)
* Add Initial support for multiple cors origins in nginx - bump cluster version for `make dev-env` - add buildOriginRegex function in nginx.tmpl - add e2e 4 e2e tests for cors.go - refers to feature request #5496 * add tests + use search to identify '*' origin * add tests + use search to identify '*' origin Signed-off-by: Christopher Larivière <lariviere.c@gmail.com> * fix "should enable cors test" looking at improper values * Modify tests and add some logic for origin validation - add origin validation in cors ingress annotations - add extra tests to validate regex - properly escape regex using "QuoteMeta" - fix some copy/paste errors * add TrimSpace and length validation before adding a new origin * modify documentation for cors and remove dangling comment * add support for optional port mapping on origin * support single-level wildcard subdomains + tests * Remove automatic `*` fonctionality from incorrect origins - use []string instead of basic string to avoid reparsing in template.go - fix typo in docs - modify template to properly enable only if the whole block is enabled - modify cors parsing - test properly by validating that the value returned is the proper origin - update unit tests and annotation tests * Re-add `*` when no cors origins are supplied + fix tests - fix e2e tests to allow for `*` - re-add `*` to cors parsing if trimmed cors-allow-origin is empty (supplied but empty) and if it wasn't supplied at all. * remove unecessary logic for building cors origin + remove comments - add some edge cases in e2e tests - rework logic for building cors origin there was no need for logic in template.go for buildCorsOriginRegex if there is a `*` it ill be short-circuited by first if. if it's a wildcard domain or any domain (without a wildcard), it MUST match the main/cors.go regex format. if there's a star in a wildcard domain, it must be replaced with `[A-Za-z0-9]+` * add missing check in e2e tests
This commit is contained in:
parent
a5bab6a715
commit
65b8eeddec
10 changed files with 570 additions and 44 deletions
|
@ -61,7 +61,7 @@ echo "[dev-env] building image"
|
|||
make build image
|
||||
docker tag "${REGISTRY}/controller:${TAG}" "${DEV_IMAGE}"
|
||||
|
||||
export K8S_VERSION=${K8S_VERSION:-v1.20.2@sha256:8f7ea6e7642c0da54f04a7ee10431549c0257315b3a634f6ef2fecaaedb19bab}
|
||||
export K8S_VERSION=${K8S_VERSION:-v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6}
|
||||
|
||||
KIND_CLUSTER_NAME="ingress-nginx-dev"
|
||||
|
||||
|
|
|
@ -354,10 +354,13 @@ CORS can be controlled with the following annotations:
|
|||
|
||||
* `nginx.ingress.kubernetes.io/cors-allow-origin`: Controls what's the accepted Origin for CORS.
|
||||
|
||||
This is a single field value, with the following format: `http(s)://origin-site.com` or `http(s)://origin-site.com:port`
|
||||
This is a multi-valued field, separated by ','. It must follow this format: `http(s)://origin-site.com` or `http(s)://origin-site.com:port`
|
||||
|
||||
- Default: `*`
|
||||
- Example: `nginx.ingress.kubernetes.io/cors-allow-origin: "https://origin-site.com:4443"`
|
||||
- Example: `nginx.ingress.kubernetes.io/cors-allow-origin: "https://origin-site.com:4443, http://origin-site.com, https://example.org:1199"`
|
||||
|
||||
It also supports single level wildcard subdomains and follows this format: `http(s)://*.foo.bar`, `http(s)://*.bar.foo:8080` or `http(s)://*.abc.bar.foo:9000`
|
||||
- Example: `nginx.ingress.kubernetes.io/cors-allow-origin: "https://*.origin-site.com:4443, http://*.origin-site.com, https://example.org:1199"`
|
||||
|
||||
* `nginx.ingress.kubernetes.io/cors-allow-credentials`: Controls if credentials can be passed during CORS operations.
|
||||
|
||||
|
|
1
go.mod
1
go.mod
|
@ -78,6 +78,7 @@ require (
|
|||
github.com/go-openapi/jsonreference v0.19.3 // indirect
|
||||
github.com/go-openapi/spec v0.19.5 // indirect
|
||||
github.com/go-openapi/swag v0.19.5 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.0.4 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
|
|
1
go.sum
1
go.sum
|
@ -269,6 +269,7 @@ github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2K
|
|||
github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM=
|
||||
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
|
||||
|
|
|
@ -215,15 +215,15 @@ func TestCors(t *testing.T) {
|
|||
corsenabled bool
|
||||
methods string
|
||||
headers string
|
||||
origin 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", 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, ""},
|
||||
{map[string]string{annotationCorsEnabled: "true"}, true, defaultCorsMethods, defaultCorsHeaders, []string{"*"}, true, ""},
|
||||
{map[string]string{annotationCorsEnabled: "true", annotationCorsAllowMethods: "POST, GET, OPTIONS", annotationCorsAllowHeaders: "$nginx_version", annotationCorsAllowCredentials: "false", annotationCorsExposeHeaders: "X-CustomResponseHeader"}, true, "POST, GET, OPTIONS", defaultCorsHeaders, []string{"*"}, false, "X-CustomResponseHeader"},
|
||||
{map[string]string{annotationCorsEnabled: "true", annotationCorsAllowCredentials: "false"}, true, defaultCorsMethods, defaultCorsHeaders, []string{"*"}, false, ""},
|
||||
{map[string]string{}, false, defaultCorsMethods, defaultCorsHeaders, []string{"*"}, true, ""},
|
||||
{nil, false, defaultCorsMethods, defaultCorsHeaders, []string{"*"}, true, ""},
|
||||
}
|
||||
|
||||
for _, foo := range fooAnns {
|
||||
|
@ -243,12 +243,18 @@ func TestCors(t *testing.T) {
|
|||
t.Errorf("Returned %v but expected %v for Cors Methods", r.CorsAllowMethods, foo.methods)
|
||||
}
|
||||
|
||||
if r.CorsAllowOrigin != foo.origin {
|
||||
t.Errorf("Returned %v but expected %v for Cors Methods", r.CorsAllowOrigin, foo.origin)
|
||||
if len(r.CorsAllowOrigin) != len(foo.origin) {
|
||||
t.Errorf("Lengths of Cors Origins are not equal. Expected %v - Actual %v", r.CorsAllowOrigin, foo.origin)
|
||||
}
|
||||
|
||||
for i, v := range r.CorsAllowOrigin {
|
||||
if v != foo.origin[i] {
|
||||
t.Errorf("Values of Cors Origins are not equal. Expected %v - Actual %v", r.CorsAllowOrigin, foo.origin)
|
||||
}
|
||||
}
|
||||
|
||||
if r.CorsAllowCredentials != foo.credentials {
|
||||
t.Errorf("Returned %v but expected %v for Cors Methods", r.CorsAllowCredentials, foo.credentials)
|
||||
t.Errorf("Returned %v but expected %v for Cors Credentials", r.CorsAllowCredentials, foo.credentials)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,10 @@ package cors
|
|||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
networking "k8s.io/api/networking/v1"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"k8s.io/ingress-nginx/internal/ingress/annotations/parser"
|
||||
"k8s.io/ingress-nginx/internal/ingress/resolver"
|
||||
|
@ -36,7 +38,7 @@ var (
|
|||
// Regex are defined here to prevent information leak, if user tries to set anything not valid
|
||||
// that could cause the Response to contain some internal value/variable (like returning $pid, $upstream_addr, etc)
|
||||
// Origin must contain a http/s Origin (including or not the port) or the value '*'
|
||||
corsOriginRegex = regexp.MustCompile(`^(https?://[A-Za-z0-9\-\.]*(:[0-9]+)?|\*)?$`)
|
||||
corsOriginRegex = regexp.MustCompile(`^(https?://(\*\.)?[A-Za-z0-9\-\.]*(:[0-9]+)?|\*)?$`)
|
||||
// Method must contain valid methods list (PUT, GET, POST, BLA)
|
||||
// May contain or not spaces between each verb
|
||||
corsMethodsRegex = regexp.MustCompile(`^([A-Za-z]+,?\s?)+$`)
|
||||
|
@ -55,7 +57,7 @@ type cors struct {
|
|||
// Config contains the Cors configuration to be used in the Ingress
|
||||
type Config struct {
|
||||
CorsEnabled bool `json:"corsEnabled"`
|
||||
CorsAllowOrigin string `json:"corsAllowOrigin"`
|
||||
CorsAllowOrigin []string `json:"corsAllowOrigin"`
|
||||
CorsAllowMethods string `json:"corsAllowMethods"`
|
||||
CorsAllowHeaders string `json:"corsAllowHeaders"`
|
||||
CorsAllowCredentials bool `json:"corsAllowCredentials"`
|
||||
|
@ -91,13 +93,20 @@ func (c1 *Config) Equal(c2 *Config) bool {
|
|||
if c1.CorsAllowMethods != c2.CorsAllowMethods {
|
||||
return false
|
||||
}
|
||||
if c1.CorsAllowOrigin != c2.CorsAllowOrigin {
|
||||
return false
|
||||
}
|
||||
if c1.CorsEnabled != c2.CorsEnabled {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(c1.CorsAllowOrigin) != len(c2.CorsAllowOrigin) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, v := range c1.CorsAllowOrigin {
|
||||
if v != c2.CorsAllowOrigin[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -112,9 +121,23 @@ func (c cors) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
config.CorsEnabled = false
|
||||
}
|
||||
|
||||
config.CorsAllowOrigin, err = parser.GetStringAnnotation("cors-allow-origin", ing)
|
||||
if err != nil || !corsOriginRegex.MatchString(config.CorsAllowOrigin) {
|
||||
config.CorsAllowOrigin = "*"
|
||||
unparsedOrigins, err := parser.GetStringAnnotation("cors-allow-origin", ing)
|
||||
if err == nil {
|
||||
config.CorsAllowOrigin = strings.Split(unparsedOrigins, ",")
|
||||
for i, origin := range config.CorsAllowOrigin {
|
||||
origin = strings.TrimSpace(origin)
|
||||
if origin == "*" {
|
||||
config.CorsAllowOrigin = []string{"*"}
|
||||
break
|
||||
}
|
||||
if !corsOriginRegex.MatchString(origin) {
|
||||
klog.Errorf("Error parsing cors-allow-origin parameters. Supplied incorrect origin: %s. Skipping.", origin)
|
||||
config.CorsAllowOrigin = append(config.CorsAllowOrigin[:i], config.CorsAllowOrigin[i+1:]...)
|
||||
}
|
||||
klog.Infof("Current config.corsAllowOrigin %v", config.CorsAllowOrigin)
|
||||
}
|
||||
} else {
|
||||
config.CorsAllowOrigin = []string{"*"}
|
||||
}
|
||||
|
||||
config.CorsAllowHeaders, err = parser.GetStringAnnotation("cors-allow-headers", ing)
|
||||
|
@ -143,5 +166,4 @@ func (c cors) Parse(ing *networking.Ingress) (interface{}, error) {
|
|||
}
|
||||
|
||||
return config, nil
|
||||
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ func TestIngressCorsConfigValid(t *testing.T) {
|
|||
t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix("cors-allow-methods")], nginxCors.CorsAllowMethods)
|
||||
}
|
||||
|
||||
if nginxCors.CorsAllowOrigin != "https://origin123.test.com:4443" {
|
||||
if nginxCors.CorsAllowOrigin[0] != "https://origin123.test.com:4443" {
|
||||
t.Errorf("expected %v but returned %v", data[parser.GetAnnotationWithPrefix("cors-allow-origin")], nginxCors.CorsAllowOrigin)
|
||||
}
|
||||
|
||||
|
@ -164,10 +164,6 @@ func TestIngressCorsConfigInvalid(t *testing.T) {
|
|||
t.Errorf("expected %v but returned %v", defaultCorsHeaders, nginxCors.CorsAllowMethods)
|
||||
}
|
||||
|
||||
if nginxCors.CorsAllowOrigin != "*" {
|
||||
t.Errorf("expected %v but returned %v", "*", nginxCors.CorsAllowOrigin)
|
||||
}
|
||||
|
||||
if nginxCors.CorsExposeHeaders != "" {
|
||||
t.Errorf("expected %v but returned %v", "", nginxCors.CorsExposeHeaders)
|
||||
}
|
||||
|
|
|
@ -276,6 +276,7 @@ var (
|
|||
"shouldLoadAuthDigestModule": shouldLoadAuthDigestModule,
|
||||
"shouldLoadInfluxDBModule": shouldLoadInfluxDBModule,
|
||||
"buildServerName": buildServerName,
|
||||
"buildCorsOriginRegex": buildCorsOriginRegex,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -1676,3 +1677,29 @@ func convertGoSliceIntoLuaTable(goSliceInterface interface{}, emptyStringAsNil b
|
|||
return "", fmt.Errorf("could not process type: %s", kind)
|
||||
}
|
||||
}
|
||||
|
||||
func buildOriginRegex(origin string) string {
|
||||
origin = regexp.QuoteMeta(origin)
|
||||
origin = strings.Replace(origin, "\\*", "[A-Za-z0-9]+", 1)
|
||||
return fmt.Sprintf("(%s)", origin)
|
||||
}
|
||||
|
||||
func buildCorsOriginRegex(corsOrigins []string) string {
|
||||
if len(corsOrigins) == 1 && corsOrigins[0] == "*" {
|
||||
return "set $http_origin *;\nset $cors 'true';"
|
||||
}
|
||||
|
||||
var originsRegex string = "if ($http_origin ~* ("
|
||||
for i, origin := range corsOrigins {
|
||||
originTrimmed := strings.TrimSpace(origin)
|
||||
if len(originTrimmed) > 0 {
|
||||
builtOrigin := buildOriginRegex(originTrimmed)
|
||||
originsRegex += builtOrigin
|
||||
if i != len(corsOrigins)-1 {
|
||||
originsRegex = originsRegex + "|"
|
||||
}
|
||||
}
|
||||
}
|
||||
originsRegex = originsRegex + ")$ ) { set $cors 'true'; }"
|
||||
return originsRegex
|
||||
}
|
||||
|
|
|
@ -867,8 +867,24 @@ stream {
|
|||
{{ define "CORS" }}
|
||||
{{ $cors := .CorsConfig }}
|
||||
# Cors Preflight methods needs additional options and different Return Code
|
||||
{{ if $cors.CorsAllowOrigin }}
|
||||
{{ buildCorsOriginRegex $cors.CorsAllowOrigin }}
|
||||
{{ end }}
|
||||
if ($request_method = 'OPTIONS') {
|
||||
more_set_headers 'Access-Control-Allow-Origin: {{ $cors.CorsAllowOrigin }}';
|
||||
set $cors ${cors}options;
|
||||
}
|
||||
|
||||
if ($cors = "true") {
|
||||
more_set_headers 'Access-Control-Allow-Origin: $http_origin';
|
||||
{{ if $cors.CorsAllowCredentials }} more_set_headers 'Access-Control-Allow-Credentials: {{ $cors.CorsAllowCredentials }}'; {{ end }}
|
||||
more_set_headers 'Access-Control-Allow-Methods: {{ $cors.CorsAllowMethods }}';
|
||||
more_set_headers 'Access-Control-Allow-Headers: {{ $cors.CorsAllowHeaders }}';
|
||||
{{ if not (empty $cors.CorsExposeHeaders) }} more_set_headers 'Access-Control-Expose-Headers: {{ $cors.CorsExposeHeaders }}'; {{ end }}
|
||||
more_set_headers 'Access-Control-Max-Age: {{ $cors.CorsMaxAge }}';
|
||||
}
|
||||
|
||||
if ($cors = "trueoptions") {
|
||||
more_set_headers 'Access-Control-Allow-Origin: $http_origin';
|
||||
{{ if $cors.CorsAllowCredentials }} more_set_headers 'Access-Control-Allow-Credentials: {{ $cors.CorsAllowCredentials }}'; {{ end }}
|
||||
more_set_headers 'Access-Control-Allow-Methods: {{ $cors.CorsAllowMethods }}';
|
||||
more_set_headers 'Access-Control-Allow-Headers: {{ $cors.CorsAllowHeaders }}';
|
||||
|
@ -878,11 +894,6 @@ stream {
|
|||
more_set_headers 'Content-Length: 0';
|
||||
return 204;
|
||||
}
|
||||
|
||||
more_set_headers 'Access-Control-Allow-Origin: {{ $cors.CorsAllowOrigin }}';
|
||||
{{ if $cors.CorsAllowCredentials }} more_set_headers 'Access-Control-Allow-Credentials: {{ $cors.CorsAllowCredentials }}'; {{ end }}
|
||||
{{ if not (empty $cors.CorsExposeHeaders) }} more_set_headers 'Access-Control-Expose-Headers: {{ $cors.CorsExposeHeaders }}'; {{ end }}
|
||||
|
||||
{{ end }}
|
||||
|
||||
{{/* definition of server-template to avoid repetitions with server-alias */}}
|
||||
|
|
|
@ -44,10 +44,12 @@ var _ = framework.DescribeAnnotation("cors-*", func() {
|
|||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return strings.Contains(server, "more_set_headers 'Access-Control-Allow-Methods: GET, PUT, POST, DELETE, PATCH, OPTIONS';") &&
|
||||
strings.Contains(server, "more_set_headers 'Access-Control-Allow-Origin: *';") &&
|
||||
strings.Contains(server, "more_set_headers 'Access-Control-Allow-Origin: $http_origin';") &&
|
||||
strings.Contains(server, "more_set_headers 'Access-Control-Allow-Headers: DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';") &&
|
||||
strings.Contains(server, "more_set_headers 'Access-Control-Max-Age: 1728000';") &&
|
||||
strings.Contains(server, "more_set_headers 'Access-Control-Allow-Credentials: true';")
|
||||
strings.Contains(server, "more_set_headers 'Access-Control-Allow-Credentials: true';") &&
|
||||
strings.Contains(server, "set $http_origin *;") &&
|
||||
strings.Contains(server, "$cors 'true';")
|
||||
})
|
||||
|
||||
f.HTTPTestClient().
|
||||
|
@ -107,6 +109,7 @@ var _ = framework.DescribeAnnotation("cors-*", func() {
|
|||
|
||||
ginkgo.It("should allow origin for cors", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "https://origin.cors.com:8080"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "https://origin.cors.com:8080",
|
||||
|
@ -115,10 +118,20 @@ var _ = framework.DescribeAnnotation("cors-*", func() {
|
|||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.WaitForNginxServer(host,
|
||||
func(server string) bool {
|
||||
return strings.Contains(server, "more_set_headers 'Access-Control-Allow-Origin: https://origin.cors.com:8080';")
|
||||
})
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{origin})
|
||||
})
|
||||
|
||||
ginkgo.It("should allow headers for cors", func() {
|
||||
|
@ -152,4 +165,450 @@ var _ = framework.DescribeAnnotation("cors-*", func() {
|
|||
return strings.Contains(server, "more_set_headers 'Access-Control-Expose-Headers: X-CustomResponseHeader, X-CustomSecondHeader';")
|
||||
})
|
||||
})
|
||||
|
||||
ginkgo.It("should allow - single origin for multiple cors values", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "https://origin.cors.com:8080"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "https://origin.cors.com:8080, https://origin2.cors.com",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{origin})
|
||||
})
|
||||
|
||||
ginkgo.It("should not allow - single origin for multiple cors values", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "http://no.origin.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "http://origin2.cors.com, https://origin.com",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
// the client should still receive a response but browsers should block the request
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().NotContainsKey("Access-Control-Allow-Origin")
|
||||
})
|
||||
|
||||
ginkgo.It("should allow correct origins - single origin for multiple cors values", func() {
|
||||
host := "cors.foo.com"
|
||||
badOrigin := "origin.cors.com:8080"
|
||||
origin1 := "https://origin2.cors.com"
|
||||
origin2 := "https://origin.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "origin.cors.com:8080, https://origin2.cors.com, https://origin.com",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", badOrigin).
|
||||
Expect().
|
||||
Headers().NotContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin1).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin1).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{origin1})
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin2).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin2).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{origin2})
|
||||
})
|
||||
|
||||
ginkgo.It("should not break functionality", func() {
|
||||
host := "cors.foo.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "*",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{"*"})
|
||||
})
|
||||
|
||||
ginkgo.It("should not break functionality - without `*`", func() {
|
||||
host := "cors.foo.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{"*"})
|
||||
})
|
||||
|
||||
ginkgo.It("should not break functionality with extra domain", func() {
|
||||
host := "cors.foo.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "*, foo.bar.com",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{"*"})
|
||||
})
|
||||
|
||||
ginkgo.It("should not match", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "https://fooxbar.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "https://foo.bar.com",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
// the client should still receive a response but browsers should block the request
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().NotContainsKey("Access-Control-Allow-Origin")
|
||||
})
|
||||
|
||||
ginkgo.It("should allow - single origin with required port", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "http://origin.com:8080"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "http://origin.cors.com:8080, http://origin.com:8080",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
// the client should still receive a response but browsers should block the request
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{origin})
|
||||
})
|
||||
|
||||
ginkgo.It("should not allow - single origin with port and origin without port", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "http://origin.com:8080"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "https://origin2.cors.com, http://origin.com",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().NotContainsKey("Access-Control-Allow-Origin")
|
||||
})
|
||||
|
||||
ginkgo.It("should not allow - single origin without port and origin with required port", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "http://origin.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "http://origin.cors.com:8080, http://origin.com:8080",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
// the client should still receive a response but browsers should block the request
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().NotContainsKey("Access-Control-Allow-Origin")
|
||||
})
|
||||
|
||||
ginkgo.It("should allow - matching origin with wildcard origin (2 subdomains)", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "http://foo.origin.cors.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "http://*.origin.cors.com, http://*.origin.com:8080",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{origin})
|
||||
})
|
||||
|
||||
ginkgo.It("should not allow - unmatching origin with wildcard origin (2 subdomains)", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "http://bar.foo.origin.cors.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "http://*.origin.cors.com, http://*.origin.com:8080",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
// the client should still receive a response but browsers should block the request
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().NotContainsKey("Access-Control-Allow-Origin")
|
||||
})
|
||||
|
||||
ginkgo.It("should allow - matching origin+port with wildcard origin", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "http://abc.origin.com:8080"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "http://origin.cors.com:8080, http://*.origin.com:8080",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{origin})
|
||||
})
|
||||
|
||||
ginkgo.It("should not allow - portless origin with wildcard origin", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "http://abc.origin.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "http://origin.cors.com:8080, http://*.origin.com:8080",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
// the client should still receive a response but browsers should block the request
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().NotContainsKey("Access-Control-Allow-Origin")
|
||||
})
|
||||
|
||||
ginkgo.It("should allow correct origins - missing subdomain + origin with wildcard origin and correct origin", func() {
|
||||
host := "cors.foo.com"
|
||||
badOrigin := "http://origin.com:8080"
|
||||
origin := "http://bar.origin.com:8080"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": "http://origin.cors.com:8080, http://*.origin.com:8080",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
// the client should still receive a response but browsers should block the request
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", badOrigin).
|
||||
Expect().
|
||||
Headers().NotContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{origin})
|
||||
})
|
||||
|
||||
ginkgo.It("should allow - missing origins (should allow all origins)", func() {
|
||||
host := "cors.foo.com"
|
||||
origin := "http://origin.com"
|
||||
origin2 := "http://book.origin.com"
|
||||
origin3 := "test.origin.com"
|
||||
annotations := map[string]string{
|
||||
"nginx.ingress.kubernetes.io/enable-cors": "true",
|
||||
"nginx.ingress.kubernetes.io/cors-allow-origin": " ",
|
||||
}
|
||||
|
||||
ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.EchoService, 80, annotations)
|
||||
f.EnsureIngress(ing)
|
||||
|
||||
// the client should still receive a response but browsers should block the request
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{"*"})
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin2).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin2).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{"*"})
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin3).
|
||||
Expect().
|
||||
Headers().ContainsKey("Access-Control-Allow-Origin")
|
||||
|
||||
f.HTTPTestClient().
|
||||
GET("/").
|
||||
WithHeader("Host", host).
|
||||
WithHeader("Origin", origin3).
|
||||
Expect().
|
||||
Status(http.StatusOK).Headers().
|
||||
ValueEqual("Access-Control-Allow-Origin", []string{"*"})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue