From 2097676ca8a90a2e15b0b768968f78455ff665bf Mon Sep 17 00:00:00 2001 From: Ricardo Pchevuzinske Katz Date: Thu, 19 Oct 2017 18:03:02 -0200 Subject: [PATCH] Adds support for other Cors directives CORS annotations improvements Cors improvements Cors improevements Cors improvements Cors improvements --- docs/annotations.md | 10 ++- docs/user-guide/annotations.md | 24 ++++++ pkg/ingress/annotations/cors/main.go | 91 +++++++++++++++++++++- pkg/ingress/annotations/cors/main_test.go | 91 +++++++++++++++------- pkg/ingress/controller/annotations.go | 8 +- pkg/ingress/controller/annotations_test.go | 76 +++++++++++++++--- pkg/ingress/controller/util_test.go | 3 +- pkg/ingress/types.go | 5 +- pkg/ingress/types_equals.go | 2 +- rootfs/etc/nginx/template/nginx.tmpl | 50 ++++-------- 10 files changed, 277 insertions(+), 83 deletions(-) diff --git a/docs/annotations.md b/docs/annotations.md index 0ab91b446..90ae61daa 100644 --- a/docs/annotations.md +++ b/docs/annotations.md @@ -52,12 +52,20 @@ Key: | `base-url-scheme` | Specify the scheme of the `` tags. | | nginx | `preserve-host` | Whether to pass the client request host (`true`) or the origin hostname (`false`) in the HTTP Host field. | | trafficserver +## CORS Related +| Name | Meaning | Default | Controller +| --- | --- | --- | --- | +| `enable-cors` | Enable CORS headers in response. | false | nginx, voyager +| `cors-allow-origin` | Specifies the Origin allowed in CORS (Access-Control-Allow-Origin) | * | nginx +| `cors-allow-headers` | Specifies the Headers allowed in CORS (Access-Control-Allow-Headers) | DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization | nginx +| `cors-allow-methods` | Specifies the Methods allowed in CORS (Access-Control-Allow-Methods) | GET, PUT, POST, DELETE, PATCH, OPTIONS | nginx +| `cors-allow-credentials` | Specifies the Access-Control-Allow-Credentials | true | nginx + ## Miscellaneous | Name | Meaning | Default | Controller | --- | --- | --- | --- | | `configuration-snippet` | Arbitrary text to put in the generated configuration file. | | nginx -| `enable-cors` | Enable CORS headers in response. | | nginx, voyager | `limit-connections` | Limit concurrent connections per IP address[1]. | | nginx, voyager | `limit-rps` | Limit requests per second per IP address[1]. | | nginx, voyager | `limit-rpm` | Limit requests per minute per IP address. | | nginx, voyager diff --git a/docs/user-guide/annotations.md b/docs/user-guide/annotations.md index 9a10e123e..9e8a5269e 100644 --- a/docs/user-guide/annotations.md +++ b/docs/user-guide/annotations.md @@ -20,6 +20,10 @@ The following annotations are supported: |[ingress.kubernetes.io/configuration-snippet](#configuration-snippet)|string| |[ingress.kubernetes.io/default-backend](#default-backend)|string| |[ingress.kubernetes.io/enable-cors](#enable-cors)|true or false| +|[ingress.kubernetes.io/cors-allow-origin](#enable-cors)|string| +|[ingress.kubernetes.io/cors-allow-methods](#enable-cors)|string| +|[ingress.kubernetes.io/cors-allow-headers](#enable-cors)|string| +|[ingress.kubernetes.io/cors-allow-credentials](#enable-cors)|true or false| |[ingress.kubernetes.io/force-ssl-redirect](#server-side-https-enforcement-through-redirect)|true or false| |[ingress.kubernetes.io/from-to-www-redirect](#redirect-from-to-www)|true or false| |[ingress.kubernetes.io/limit-connections](#rate-limiting)|number| @@ -162,6 +166,26 @@ This is a global configuration for the ingress controller. In some cases could b ### Enable CORS To enable Cross-Origin Resource Sharing (CORS) in an Ingress rule add the annotation `ingress.kubernetes.io/enable-cors: "true"`. This will add a section in the server location enabling this functionality. + +CORS can be controlled with the following annotations: + +* `ingress.kubernetes.io/cors-allow-methods` controls which methods are accepted. This is a multi-valued field, separated by ',' and accepts only letters (upper and lower case). + +Example: `ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS"` + +* `ingress.kubernetes.io/cors-allow-headers` controls which headers are accepted. This is a multi-valued field, separated by ',' and accepts letters, numbers, _ and -. + +Example: `ingress.kubernetes.io/cors-allow-methods: "X-Forwarded-For, X-app123-XPTO"` + +* `ingress.kubernetes.io/cors-allow-origin` controls what's the accepted Origin for CORS and defaults to '*'. This is a single field value, with the following format: http(s)://origin-site.com or http(s)://origin-site.com:port + +Example: `ingress.kubernetes.io/cors-allow-origin: "https://origin-site.com:4443"` + +* `ingress.kubernetes.io/cors-allow-credentials` controls if credentials can be passed during CORS operations. + +Example: `ingress.kubernetes.io/cors-allow-credentials: "true"` + + For more information please check https://enable-cors.org/server_nginx.html ### Server Alias diff --git a/pkg/ingress/annotations/cors/main.go b/pkg/ingress/annotations/cors/main.go index 8ea55bb1f..b9be21fb0 100644 --- a/pkg/ingress/annotations/cors/main.go +++ b/pkg/ingress/annotations/cors/main.go @@ -17,25 +17,112 @@ limitations under the License. package cors import ( + "regexp" + extensions "k8s.io/api/extensions/v1beta1" "k8s.io/ingress-nginx/pkg/ingress/annotations/parser" ) const ( - annotation = "ingress.kubernetes.io/enable-cors" + annotationCorsEnabled = "ingress.kubernetes.io/enable-cors" + annotationCorsAllowOrigin = "ingress.kubernetes.io/cors-allow-origin" + annotationCorsAllowMethods = "ingress.kubernetes.io/cors-allow-methods" + annotationCorsAllowHeaders = "ingress.kubernetes.io/cors-allow-headers" + annotationCorsAllowCredentials = "ingress.kubernetes.io/cors-allow-credentials" + // Default values + defaultCorsMethods = "GET, PUT, POST, DELETE, PATCH, OPTIONS" + defaultCorsHeaders = "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization" +) + +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]+)?|\*)?$`) + // 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?)+$`) + // 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?)+$`) ) type cors struct { } +// CorsConfig contains the Cors configuration to be used in the Ingress +type CorsConfig struct { + CorsEnabled bool `json:"corsEnabled"` + CorsAllowOrigin string `json:"corsAllowOrigin"` + CorsAllowMethods string `json:"corsAllowMethods"` + CorsAllowHeaders string `json:"corsAllowHeaders"` + CorsAllowCredentials bool `json:"corsAllowCredentials"` +} + // NewParser creates a new CORS annotation parser func NewParser() parser.IngressAnnotation { return cors{} } +// Equal tests for equality between two External types +func (c1 *CorsConfig) Equal(c2 *CorsConfig) bool { + if c1 == c2 { + return true + } + if c1 == nil || c2 == nil { + return false + } + if c1.CorsAllowCredentials != c2.CorsAllowCredentials { + return false + } + if c1.CorsAllowHeaders != c2.CorsAllowHeaders { + return false + } + if c1.CorsAllowOrigin != c2.CorsAllowOrigin { + return false + } + if c1.CorsEnabled != c2.CorsEnabled { + return false + } + + return true +} + // Parse parses the annotations contained in the ingress // rule used to indicate if the location/s should allows CORS func (a cors) Parse(ing *extensions.Ingress) (interface{}, error) { - return parser.GetBoolAnnotation(annotation, ing) + corsenabled, err := parser.GetBoolAnnotation(annotationCorsEnabled, ing) + if err != nil { + corsenabled = false + } + + corsalloworigin, err := parser.GetStringAnnotation(annotationCorsAllowOrigin, ing) + if err != nil || corsalloworigin == "" || !corsOriginRegex.MatchString(corsalloworigin) { + corsalloworigin = "*" + } + + corsallowheaders, err := parser.GetStringAnnotation(annotationCorsAllowHeaders, ing) + if err != nil || corsallowheaders == "" || !corsHeadersRegex.MatchString(corsallowheaders) { + corsallowheaders = defaultCorsHeaders + } + + corsallowmethods, err := parser.GetStringAnnotation(annotationCorsAllowMethods, ing) + if err != nil || corsallowmethods == "" || !corsMethodsRegex.MatchString(corsallowmethods) { + corsallowmethods = defaultCorsMethods + } + + corsallowcredentials, err := parser.GetBoolAnnotation(annotationCorsAllowCredentials, ing) + if err != nil { + corsallowcredentials = true + } + + return &CorsConfig{ + CorsEnabled: corsenabled, + CorsAllowOrigin: corsalloworigin, + CorsAllowHeaders: corsallowheaders, + CorsAllowMethods: corsallowmethods, + CorsAllowCredentials: corsallowcredentials, + }, nil + } diff --git a/pkg/ingress/annotations/cors/main_test.go b/pkg/ingress/annotations/cors/main_test.go index 330b059f4..2a1782b89 100644 --- a/pkg/ingress/annotations/cors/main_test.go +++ b/pkg/ingress/annotations/cors/main_test.go @@ -22,42 +22,75 @@ import ( api "k8s.io/api/core/v1" extensions "k8s.io/api/extensions/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" ) -const ( - notCorsAnnotation = "ingress.kubernetes.io/enable-not-cors" -) - -func TestParse(t *testing.T) { - ap := NewParser() - if ap == nil { - t.Fatalf("expected a parser.IngressAnnotation but returned nil") +func buildIngress() *extensions.Ingress { + defaultBackend := extensions.IngressBackend{ + ServiceName: "default-backend", + ServicePort: intstr.FromInt(80), } - testCases := []struct { - annotations map[string]string - expected bool - }{ - {map[string]string{annotation: "true"}, true}, - {map[string]string{annotation: "false"}, false}, - {map[string]string{notCorsAnnotation: "true"}, false}, - {map[string]string{}, false}, - {nil, false}, - } - - ing := &extensions.Ingress{ + return &extensions.Ingress{ ObjectMeta: meta_v1.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }, - Spec: extensions.IngressSpec{}, - } - - for _, testCase := range testCases { - ing.SetAnnotations(testCase.annotations) - result, _ := ap.Parse(ing) - if result != testCase.expected { - t.Errorf("expected %t but returned %t, annotations: %s", testCase.expected, result, testCase.annotations) - } + Spec: extensions.IngressSpec{ + Backend: &extensions.IngressBackend{ + ServiceName: "default-backend", + ServicePort: intstr.FromInt(80), + }, + Rules: []extensions.IngressRule{ + { + Host: "foo.bar.com", + IngressRuleValue: extensions.IngressRuleValue{ + HTTP: &extensions.HTTPIngressRuleValue{ + Paths: []extensions.HTTPIngressPath{ + { + Path: "/foo", + Backend: defaultBackend, + }, + }, + }, + }, + }, + }, + }, } } + +func TestIngressCorsConfig(t *testing.T) { + ing := buildIngress() + + data := map[string]string{} + data[annotationCorsEnabled] = "true" + data[annotationCorsAllowHeaders] = "DNT,X-CustomHeader, Keep-Alive,User-Agent" + data[annotationCorsAllowCredentials] = "false" + data[annotationCorsAllowMethods] = "PUT, GET,OPTIONS, PATCH, $nginx_version" + data[annotationCorsAllowOrigin] = "https://origin123.test.com:4443" + ing.SetAnnotations(data) + + corst, _ := NewParser().Parse(ing) + nginxCors, ok := corst.(*CorsConfig) + if !ok { + t.Errorf("expected a Config type") + } + + if nginxCors.CorsEnabled != true { + t.Errorf("expected cors enabled but returned %v", nginxCors.CorsEnabled) + } + + if nginxCors.CorsAllowHeaders != "DNT,X-CustomHeader, Keep-Alive,User-Agent" { + t.Errorf("expected headers not found. Found %v", nginxCors.CorsAllowHeaders) + } + + if nginxCors.CorsAllowMethods != "GET, PUT, POST, DELETE, PATCH, OPTIONS" { + t.Errorf("expected default methods, but got %v", nginxCors.CorsAllowMethods) + } + + if nginxCors.CorsAllowOrigin != "https://origin123.test.com:4443" { + t.Errorf("expected origin https://origin123.test.com:4443, but got %v", nginxCors.CorsAllowOrigin) + } + +} diff --git a/pkg/ingress/controller/annotations.go b/pkg/ingress/controller/annotations.go index 463d1e8ff..a1445e3d3 100644 --- a/pkg/ingress/controller/annotations.go +++ b/pkg/ingress/controller/annotations.go @@ -67,7 +67,7 @@ func newAnnotationExtractor(cfg extractorConfig) annotationExtractor { "BasicDigestAuth": auth.NewParser(auth.AuthDirectory, cfg), "ExternalAuth": authreq.NewParser(), "CertificateAuth": authtls.NewParser(cfg), - "EnableCORS": cors.NewParser(), + "CorsConfig": cors.NewParser(), "HealthCheck": healthcheck.NewParser(cfg), "Whitelist": ipwhitelist.NewParser(cfg), "UsePortInRedirects": portinredirect.NewParser(cfg), @@ -130,6 +130,7 @@ const ( sessionAffinity = "SessionAffinity" serviceUpstream = "ServiceUpstream" serverAlias = "Alias" + enableCors = "EnableCORS" clientBodyBufferSize = "ClientBodyBufferSize" certificateAuth = "CertificateAuth" serverSnippet = "ServerSnippet" @@ -175,6 +176,11 @@ func (e *annotationExtractor) SessionAffinity(ing *extensions.Ingress) *sessiona return val.(*sessionaffinity.AffinityConfig) } +func (e *annotationExtractor) Cors(ing *extensions.Ingress) *cors.CorsConfig { + val, _ := e.annotations[enableCors].Parse(ing) + return val.(*cors.CorsConfig) +} + func (e *annotationExtractor) CertificateAuth(ing *extensions.Ingress) *authtls.AuthSSLConfig { val, err := e.annotations[certificateAuth].Parse(ing) if errors.IsMissingAnnotations(err) { diff --git a/pkg/ingress/controller/annotations_test.go b/pkg/ingress/controller/annotations_test.go index 04581d99b..025a526d5 100644 --- a/pkg/ingress/controller/annotations_test.go +++ b/pkg/ingress/controller/annotations_test.go @@ -29,15 +29,22 @@ import ( ) const ( - annotationSecureUpstream = "ingress.kubernetes.io/secure-backends" - annotationSecureVerifyCACert = "ingress.kubernetes.io/secure-verify-ca-secret" - annotationUpsMaxFails = "ingress.kubernetes.io/upstream-max-fails" - annotationUpsFailTimeout = "ingress.kubernetes.io/upstream-fail-timeout" - annotationPassthrough = "ingress.kubernetes.io/ssl-passthrough" - annotationAffinityType = "ingress.kubernetes.io/affinity" - annotationAffinityCookieName = "ingress.kubernetes.io/session-cookie-name" - annotationAffinityCookieHash = "ingress.kubernetes.io/session-cookie-hash" - annotationUpstreamHashBy = "ingress.kubernetes.io/upstream-hash-by" + annotationSecureUpstream = "ingress.kubernetes.io/secure-backends" + annotationSecureVerifyCACert = "ingress.kubernetes.io/secure-verify-ca-secret" + annotationUpsMaxFails = "ingress.kubernetes.io/upstream-max-fails" + annotationUpsFailTimeout = "ingress.kubernetes.io/upstream-fail-timeout" + annotationPassthrough = "ingress.kubernetes.io/ssl-passthrough" + annotationAffinityType = "ingress.kubernetes.io/affinity" + annotationCorsEnabled = "ingress.kubernetes.io/enable-cors" + annotationCorsAllowOrigin = "ingress.kubernetes.io/cors-allow-origin" + annotationCorsAllowMethods = "ingress.kubernetes.io/cors-allow-methods" + annotationCorsAllowHeaders = "ingress.kubernetes.io/cors-allow-headers" + annotationCorsAllowCredentials = "ingress.kubernetes.io/cors-allow-credentials" + defaultCorsMethods = "GET, PUT, POST, DELETE, PATCH, OPTIONS" + defaultCorsHeaders = "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization" + annotationAffinityCookieName = "ingress.kubernetes.io/session-cookie-name" + annotationAffinityCookieHash = "ingress.kubernetes.io/session-cookie-hash" + annotationUpstreamHashBy = "ingress.kubernetes.io/upstream-hash-by" ) type mockCfg struct { @@ -293,3 +300,54 @@ func TestAffinitySession(t *testing.T) { } } } + +func TestCors(t *testing.T) { + ec := newAnnotationExtractor(mockCfg{}) + ing := buildIngress() + + fooAnns := []struct { + annotations map[string]string + corsenabled bool + methods string + headers string + origin string + credentials bool + }{ + {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}, + } + + for _, foo := range fooAnns { + ing.SetAnnotations(foo.annotations) + r := ec.Cors(ing) + t.Logf("Testing pass %v %v %v %v %v", foo.corsenabled, foo.methods, foo.headers, foo.origin, foo.credentials) + if r == nil { + t.Errorf("Returned nil but expected a Cors.CorsConfig") + continue + } + + if r.CorsEnabled != foo.corsenabled { + t.Errorf("Returned %v but expected %v for Cors Enabled", r.CorsEnabled, foo.corsenabled) + } + + if r.CorsAllowHeaders != foo.headers { + t.Errorf("Returned %v but expected %v for Cors Headers", r.CorsAllowHeaders, foo.headers) + } + + if r.CorsAllowMethods != foo.methods { + 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 r.CorsAllowCredentials != foo.credentials { + t.Errorf("Returned %v but expected %v for Cors Methods", r.CorsAllowCredentials, foo.credentials) + } + + } +} diff --git a/pkg/ingress/controller/util_test.go b/pkg/ingress/controller/util_test.go index c0e0dad2f..cf19d94ea 100644 --- a/pkg/ingress/controller/util_test.go +++ b/pkg/ingress/controller/util_test.go @@ -23,6 +23,7 @@ import ( "k8s.io/ingress-nginx/pkg/ingress" "k8s.io/ingress-nginx/pkg/ingress/annotations/auth" "k8s.io/ingress-nginx/pkg/ingress/annotations/authreq" + "k8s.io/ingress-nginx/pkg/ingress/annotations/cors" "k8s.io/ingress-nginx/pkg/ingress/annotations/ipwhitelist" "k8s.io/ingress-nginx/pkg/ingress/annotations/proxy" "k8s.io/ingress-nginx/pkg/ingress/annotations/ratelimit" @@ -45,7 +46,7 @@ func TestMergeLocationAnnotations(t *testing.T) { "Backend": "foo_backend", "BasicDigestAuth": auth.BasicDigest{}, DeniedKeyName: &fakeError{}, - "EnableCORS": true, + "EnableCORS": cors.CorsConfig{}, "ExternalAuth": authreq.External{}, "RateLimit": ratelimit.RateLimit{}, "Redirect": redirect.Redirect{}, diff --git a/pkg/ingress/types.go b/pkg/ingress/types.go index fac9764a1..840dc9b3d 100644 --- a/pkg/ingress/types.go +++ b/pkg/ingress/types.go @@ -29,6 +29,7 @@ import ( "k8s.io/ingress-nginx/pkg/ingress/annotations/auth" "k8s.io/ingress-nginx/pkg/ingress/annotations/authreq" "k8s.io/ingress-nginx/pkg/ingress/annotations/authtls" + "k8s.io/ingress-nginx/pkg/ingress/annotations/cors" "k8s.io/ingress-nginx/pkg/ingress/annotations/ipwhitelist" "k8s.io/ingress-nginx/pkg/ingress/annotations/proxy" "k8s.io/ingress-nginx/pkg/ingress/annotations/ratelimit" @@ -293,9 +294,9 @@ type Location struct { // Denied returns an error when this location cannot not be allowed // Requesting a denied location should return HTTP code 403. Denied error `json:"denied,omitempty"` - // EnableCORS indicates if path must support CORS + // CorsConfig returns the Cors Configration for the ingress rule // +optional - EnableCORS bool `json:"enableCors,omitempty"` + CorsConfig cors.CorsConfig `json:"corsConfig,omitempty"` // ExternalAuth indicates the access to this location requires // authentication using an external provider // +optional diff --git a/pkg/ingress/types_equals.go b/pkg/ingress/types_equals.go index 3791080da..0c6a79740 100644 --- a/pkg/ingress/types_equals.go +++ b/pkg/ingress/types_equals.go @@ -355,7 +355,7 @@ func (l1 *Location) Equal(l2 *Location) bool { if l1.Denied != l2.Denied { return false } - if l1.EnableCORS != l2.EnableCORS { + if !(&l1.CorsConfig).Equal(&l2.CorsConfig) { return false } if !(&l1.ExternalAuth).Equal(&l2.ExternalAuth) { diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index 920b68216..10c95a363 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -505,48 +505,24 @@ stream { {{/* CORS support from https://michielkalkman.com/snippets/nginx-cors-open-configuration.html */}} {{ define "CORS" }} + {{ $cors := .CorsConfig }} + # Cors Preflight methods needs additional options and different Return Code if ($request_method = 'OPTIONS') { - add_header 'Access-Control-Allow-Origin' '*'; - # - # Om nom nom cookies - # - add_header 'Access-Control-Allow-Credentials' 'true'; - add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, PATCH, OPTIONS'; - # - # Custom headers and headers various browsers *should* be OK with but aren't - # - add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; - # - # Tell client that this pre-flight info is valid for 20 days - # + add_header 'Access-Control-Allow-Origin' '{{ $cors.CorsAllowOrigin }}'; + {{ if $cors.CorsAllowCredentials }} add_header 'Access-Control-Allow-Credentials' '{{ $cors.CorsAllowCredentials }}'; {{ end }} + add_header 'Access-Control-Allow-Methods' '{{ $cors.CorsAllowMethods }}'; + add_header 'Access-Control-Allow-Headers' '{{ $cors.CorsAllowHeaders }}'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain charset=UTF-8'; add_header 'Content-Length' 0; return 204; } - set $cors_method 0; - if ($request_method = 'GET') { - set $cors_method 1; - } - if ($request_method = 'PUT') { - set $cors_method 1; - } - if ($request_method = 'POST') { - set $cors_method 1; - } - if ($request_method = 'DELETE') { - set $cors_method 1; - } - if ($request_method = 'PATCH') { - set $cors_method 1; - } - if ($cors_method = 1) { - add_header 'Access-Control-Allow-Origin' '*' always; - add_header 'Access-Control-Allow-Credentials' 'true'; - add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, PATCH, OPTIONS'; - add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; - } + add_header 'Access-Control-Allow-Origin' '{{ $cors.CorsAllowOrigin }}'; + {{ if $cors.CorsAllowCredentials }} add_header 'Access-Control-Allow-Credentials' '{{ $cors.CorsAllowCredentials }}'; {{ end }} + add_header 'Access-Control-Allow-Methods' '{{ $cors.CorsAllowMethods }}'; + add_header 'Access-Control-Allow-Headers' '{{ $cors.CorsAllowHeaders }}'; + {{ end }} {{/* definition of server-template to avoid repetitions with server-alias */}} @@ -719,8 +695,8 @@ stream { proxy_set_header Authorization ""; {{ end }} - {{ if $location.EnableCORS }} - {{ template "CORS" }} + {{ if $location.CorsConfig.CorsEnabled }} + {{ template "CORS" $location }} {{ end }} {{ if not (empty $location.Redirect.URL) }}