diff --git a/controller/annotations/ingress/resSetCORS.go b/controller/annotations/ingress/resSetCORS.go index 012fe00e..8a4f65d3 100644 --- a/controller/annotations/ingress/resSetCORS.go +++ b/controller/annotations/ingress/resSetCORS.go @@ -135,7 +135,7 @@ func (a ResSetCORSAnn) Process(k store.K8s, annotations ...map[string]string) (e Cond: "if", }) case "cors-allow-credentials": - if a.parent.acl == "" { + if a.parent.acl == "" || input != "true" { return } a.parent.rules.Add(&rules.SetHdr{ diff --git a/deploy/tests/e2e/cors/config/configmap.yaml.tmpl b/deploy/tests/e2e/cors/config/configmap.yaml.tmpl new file mode 100644 index 00000000..67779d08 --- /dev/null +++ b/deploy/tests/e2e/cors/config/configmap.yaml.tmpl @@ -0,0 +1,22 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: haproxy-kubernetes-ingress + namespace: haproxy-controller +data: +{{range .ConfigMapAnnotations}} + {{ .Key }}: {{ .Value }} +{{end}} + global-config-snippet: | + stats socket 0.0.0.0:31024 + syslog-server: | + address: stdout, format: raw, facility:daemon + maxconn: "1000" + server-slots: "4" + timeout-client: 50s + timeout-connect: 5s + timeout-http-keep-alive: 1m + timeout-http-request: 5s + timeout-queue: 5s + timeout-server: 50s + timeout-tunnel: 1h \ No newline at end of file diff --git a/deploy/tests/e2e/cors/config/patternfile-a.yml b/deploy/tests/e2e/cors/config/patternfile-a.yml deleted file mode 100644 index 21301089..00000000 --- a/deploy/tests/e2e/cors/config/patternfile-a.yml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: patternfiles - namespace: haproxy-controller -data: - cors-allow-credentials: 'false' - cors-allow-headers: >- - x-api-key - cors-allow-methods: GET, POST - cors-allow-origin: >- - ^https://configmap.com?$ - cors-enable: 'true' - cors-max-age: 100s diff --git a/deploy/tests/e2e/cors/config/patternfile-empty.yml b/deploy/tests/e2e/cors/config/patternfile-empty.yml deleted file mode 100644 index 306ba976..00000000 --- a/deploy/tests/e2e/cors/config/patternfile-empty.yml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: patternfiles - namespace: haproxy-controller -data: {} diff --git a/deploy/tests/e2e/cors/cors_test.go b/deploy/tests/e2e/cors/cors_test.go index 2f3c87e0..2565715e 100644 --- a/deploy/tests/e2e/cors/cors_test.go +++ b/deploy/tests/e2e/cors/cors_test.go @@ -37,92 +37,252 @@ const ( Star = "*" ) +func (suite *CorsSuite) Test_Configmap_Alone() { + suite.Run("Default", suite.Default(false)) + suite.Run("CorsOriginAlone", suite.CorsOriginAlone(false)) + suite.Run("CorsMethodsAlone", suite.CorsMethodsAlone(false)) + suite.Run("CorsMethodsHeadersAlone", suite.CorsMethodsHeadersAlone(false)) + suite.Run("CorsMethodsAgeAlone", suite.CorsMethodsAgeAlone(false)) + suite.Run("CorsMethodsCredentialAlone", suite.CorsMethodsCredentialAlone(false)) + suite.Run("CorsDisable", suite.CorsDisable(false)) + suite.Run("CorsMethodsCredentialDisable", suite.CorsMethodsCredentialDisable(false)) + suite.NoError(suite.test.Apply("../../config/3.configmap.yaml", "", nil)) +} + func (suite *CorsSuite) Test_Ingress_Alone() { - suite.Run("Default", func() { + suite.Run("Default", suite.Default(true)) + suite.Run("CorsOriginAlone", suite.CorsOriginAlone(true)) + suite.Run("CorsMethodsAlone", suite.CorsMethodsAlone(true)) + suite.Run("CorsMethodsHeadersAlone", suite.CorsMethodsHeadersAlone(true)) + suite.Run("CorsMethodsAgeAlone", suite.CorsMethodsAgeAlone(true)) + suite.Run("CorsMethodsCredentialAlone", suite.CorsMethodsCredentialAlone(true)) + suite.Run("CorsDisable", suite.CorsDisable(true)) + suite.Run("CorsMethodsCredentialDisable", suite.CorsMethodsCredentialDisable(true)) +} + +func (suite *CorsSuite) eventuallyReturns(expecedHeaders, unexpectedHeaders http.Header) { + suite.Eventually(func() bool { + res, cls, err := suite.client.Do() + if err != nil { + suite.T().Logf("Connection ERROR: %s", err.Error()) + return false + } + defer cls() + if res.StatusCode == 503 { + return false + } + for expectedHeader, expectedValues := range expecedHeaders { + values, ok := res.Header[expectedHeader] + if !ok || len(values) != 1 || values[0] != expectedValues[0] { + return false + } + + } + for unexpectedHeader := range unexpectedHeaders { + if _, ok := res.Header[unexpectedHeader]; ok { + return false + } + } + return true + }, e2e.WaitDuration, e2e.TickDuration) +} + +func q(value string) string { + return "\"" + value + "\"" +} + +func (suite *CorsSuite) Default(ingressCors bool) func() { + return func() { expectedHeaders := http.Header{ AccessControlAllowOrigin: {Star}, AccessControlAllowMethods: {Star}, AccessControlAllowHeaders: {Star}, AccessControlMaxAge: {"5"}, } - suite.tmplData.IngAnnotations = []struct{ Key, Value string }{ + unexpectedHeaders := http.Header{ + AccessControlAllowCredential: {}, + } + annotations := &suite.tmplData.IngAnnotations + if !ingressCors { + annotations = &suite.tmplData.ConfigMapAnnotations + } + *annotations = []struct{ Key, Value string }{ {AnnotationCorsEnable, q("true")}, } - suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData)) - - suite.eventuallyReturns(expectedHeaders, http.Header{}) - }) + yamlFile := "config/deploy.yaml.tmpl" + ns := suite.test.GetNS() + if !ingressCors { + yamlFile = "config/configmap.yaml.tmpl" + ns = "" + } + suite.NoError(suite.test.Apply(yamlFile, ns, suite.tmplData)) - suite.Run("CorsOriginAlone", func() { + suite.eventuallyReturns(expectedHeaders, unexpectedHeaders) + } +} +func (suite *CorsSuite) CorsOriginAlone(ingressCors bool) func() { + return func() { expectedHeaders := http.Header{ AccessControlAllowOrigin: {"http://" + suite.tmplData.Host}, AccessControlAllowMethods: {Star}, AccessControlAllowHeaders: {Star}, AccessControlMaxAge: {"5"}, } - suite.tmplData.IngAnnotations = []struct{ Key, Value string }{ + unexpectedHeaders := http.Header{ + AccessControlAllowCredential: {}, + } + annotations := &suite.tmplData.IngAnnotations + if !ingressCors { + annotations = &suite.tmplData.ConfigMapAnnotations + } + *annotations = []struct{ Key, Value string }{ {AnnotationCorsEnable, q("true")}, {AnnotationCorsOrigin, q("http://" + suite.tmplData.Host)}, } - suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData)) + yamlFile := "config/deploy.yaml.tmpl" + ns := suite.test.GetNS() + if !ingressCors { + yamlFile = "config/configmap.yaml.tmpl" + ns = "" + } + suite.NoError(suite.test.Apply(yamlFile, ns, suite.tmplData)) - suite.eventuallyReturns(expectedHeaders, http.Header{}) - }) + suite.eventuallyReturns(expectedHeaders, unexpectedHeaders) + } +} - suite.Run("CorsMethodsAlone", func() { +func (suite *CorsSuite) CorsMethodsAlone(ingressCors bool) func() { + return func() { expectedHeaders := http.Header{ AccessControlAllowOrigin: {Star}, AccessControlAllowMethods: {"GET"}, AccessControlAllowHeaders: {Star}, AccessControlMaxAge: {"5"}, } - suite.tmplData.IngAnnotations = []struct{ Key, Value string }{ + unexpectedHeaders := http.Header{ + AccessControlAllowCredential: {}, + } + annotations := &suite.tmplData.IngAnnotations + if !ingressCors { + annotations = &suite.tmplData.ConfigMapAnnotations + } + *annotations = []struct{ Key, Value string }{ {AnnotationCorsEnable, q("true")}, {AnnotationCorsMethods, q("GET")}, } - suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData)) + yamlFile := "config/deploy.yaml.tmpl" + ns := suite.test.GetNS() + if !ingressCors { + yamlFile = "config/configmap.yaml.tmpl" + ns = "" + } + suite.NoError(suite.test.Apply(yamlFile, ns, suite.tmplData)) - suite.eventuallyReturns(expectedHeaders, http.Header{}) - }) + suite.eventuallyReturns(expectedHeaders, unexpectedHeaders) + } +} - suite.Run("CorsMethodsHeaders", func() { +func (suite *CorsSuite) CorsMethodsHeadersAlone(ingressCors bool) func() { + return func() { expectedHeaders := http.Header{ AccessControlAllowOrigin: {Star}, AccessControlAllowMethods: {Star}, AccessControlAllowHeaders: {"Accept"}, AccessControlMaxAge: {"5"}, } - suite.tmplData.IngAnnotations = []struct{ Key, Value string }{ + unexpectedHeaders := http.Header{ + AccessControlAllowCredential: {}, + } + annotations := &suite.tmplData.IngAnnotations + if !ingressCors { + annotations = &suite.tmplData.ConfigMapAnnotations + } + *annotations = []struct{ Key, Value string }{ {AnnotationCorsEnable, q("true")}, {AnnotationCorsHeaders, q("Accept")}, } - suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData)) + yamlFile := "config/deploy.yaml.tmpl" + ns := suite.test.GetNS() + if !ingressCors { + yamlFile = "config/configmap.yaml.tmpl" + ns = "" + } + suite.NoError(suite.test.Apply(yamlFile, ns, suite.tmplData)) - suite.eventuallyReturns(expectedHeaders, http.Header{}) - }) + suite.eventuallyReturns(expectedHeaders, unexpectedHeaders) + } +} - suite.Run("CorsMethodsAge", func() { +func (suite *CorsSuite) CorsMethodsAgeAlone(ingressCors bool) func() { + return func() { expectedHeaders := http.Header{ AccessControlAllowOrigin: {Star}, AccessControlAllowMethods: {Star}, AccessControlAllowHeaders: {Star}, AccessControlMaxAge: {"500"}, } - suite.tmplData.IngAnnotations = []struct{ Key, Value string }{ + unexpectedHeaders := http.Header{ + AccessControlAllowCredential: {}, + } + annotations := &suite.tmplData.IngAnnotations + if !ingressCors { + annotations = &suite.tmplData.ConfigMapAnnotations + } + *annotations = []struct{ Key, Value string }{ {AnnotationCorsEnable, q("true")}, {AnnotationCorsAge, q("500s")}, } - suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData)) + yamlFile := "config/deploy.yaml.tmpl" + ns := suite.test.GetNS() + if !ingressCors { + yamlFile = "config/configmap.yaml.tmpl" + ns = "" + } + suite.NoError(suite.test.Apply(yamlFile, ns, suite.tmplData)) - suite.eventuallyReturns(expectedHeaders, http.Header{}) - }) + suite.eventuallyReturns(expectedHeaders, unexpectedHeaders) + } +} - suite.Run("CorsMethodsCredential", func() { +func (suite *CorsSuite) CorsMethodsCredentialDisable(ingressCors bool) func() { + return func() { + expectedHeaders := http.Header{ + AccessControlAllowOrigin: {Star}, + AccessControlAllowMethods: {Star}, + AccessControlAllowHeaders: {Star}, + AccessControlMaxAge: {"5"}, + } + unexpectedHeaders := http.Header{ + AccessControlAllowCredential: {}, + } + + annotations := &suite.tmplData.IngAnnotations + if !ingressCors { + annotations = &suite.tmplData.ConfigMapAnnotations + } + *annotations = []struct{ Key, Value string }{ + {AnnotationCorsEnable, q("true")}, + {AnnotationCorsCredential, q("false")}, + } + yamlFile := "config/deploy.yaml.tmpl" + ns := suite.test.GetNS() + if !ingressCors { + yamlFile = "config/configmap.yaml.tmpl" + ns = "" + } + suite.NoError(suite.test.Apply(yamlFile, ns, suite.tmplData)) + + suite.eventuallyReturns(expectedHeaders, unexpectedHeaders) + } +} + +func (suite *CorsSuite) CorsMethodsCredentialAlone(ingressCors bool) func() { + return func() { expectedHeaders := http.Header{ AccessControlAllowOrigin: {Star}, AccessControlAllowMethods: {Star}, @@ -130,17 +290,28 @@ func (suite *CorsSuite) Test_Ingress_Alone() { AccessControlAllowCredential: {"true"}, AccessControlMaxAge: {"5"}, } - suite.tmplData.IngAnnotations = []struct{ Key, Value string }{ + annotations := &suite.tmplData.IngAnnotations + if !ingressCors { + annotations = &suite.tmplData.ConfigMapAnnotations + } + *annotations = []struct{ Key, Value string }{ {AnnotationCorsEnable, q("true")}, {AnnotationCorsCredential, q("true")}, } - - suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData)) + yamlFile := "config/deploy.yaml.tmpl" + ns := suite.test.GetNS() + if !ingressCors { + yamlFile = "config/configmap.yaml.tmpl" + ns = "" + } + suite.NoError(suite.test.Apply(yamlFile, ns, suite.tmplData)) suite.eventuallyReturns(expectedHeaders, http.Header{}) - }) + } +} - suite.Run("CorsDisable", func() { +func (suite *CorsSuite) CorsDisable(ingressCors bool) func() { + return func() { unexpectedHeaders := http.Header{ AccessControlAllowOrigin: {}, AccessControlAllowMethods: {}, @@ -149,7 +320,11 @@ func (suite *CorsSuite) Test_Ingress_Alone() { AccessControlAllowCredential: {}, } - suite.tmplData.IngAnnotations = []struct{ Key, Value string }{ + annotations := &suite.tmplData.IngAnnotations + if !ingressCors { + annotations = &suite.tmplData.ConfigMapAnnotations + } + *annotations = []struct{ Key, Value string }{ {AnnotationCorsEnable, q("false")}, {AnnotationCorsOrigin, q("http://wrong.com")}, {AnnotationCorsCredential, q("true")}, @@ -157,36 +332,13 @@ func (suite *CorsSuite) Test_Ingress_Alone() { {AnnotationCorsHeaders, q("Accept")}, } - suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), suite.tmplData)) - - suite.eventuallyReturns(http.Header{}, unexpectedHeaders) - }) -} - -func (suite *CorsSuite) eventuallyReturns(expecedHeaders, unexpectedHeaders http.Header) { - suite.Eventually(func() bool { - res, cls, err := suite.client.Do() - if err != nil { - suite.T().Logf("Connection ERROR: %s", err.Error()) - return false - } - defer cls() - for expectedHeader, expectedValues := range expecedHeaders { - values, ok := res.Header[expectedHeader] - if !ok || len(values) != 1 || values[0] != expectedValues[0] { - return false - } - - } - for unexpectedHeader := range unexpectedHeaders { - if _, ok := res.Header[unexpectedHeader]; ok { - return false - } + yamlFile := "config/deploy.yaml.tmpl" + ns := suite.test.GetNS() + if !ingressCors { + yamlFile = "config/configmap.yaml.tmpl" + ns = "" } - return true - }, e2e.WaitDuration, e2e.TickDuration) -} - -func q(value string) string { - return "\"" + value + "\"" + suite.NoError(suite.test.Apply(yamlFile, ns, suite.tmplData)) + suite.eventuallyReturns(http.Header{}, unexpectedHeaders) + } } diff --git a/deploy/tests/e2e/cors/suite_test.go b/deploy/tests/e2e/cors/suite_test.go index 9606bdd5..e125bdd9 100644 --- a/deploy/tests/e2e/cors/suite_test.go +++ b/deploy/tests/e2e/cors/suite_test.go @@ -32,8 +32,9 @@ type CorsSuite struct { } type tmplData struct { - IngAnnotations []struct{ Key, Value string } - Host string + IngAnnotations []struct{ Key, Value string } + ConfigMapAnnotations []struct{ Key, Value string } + Host string } func (suite *CorsSuite) SetupSuite() { @@ -44,11 +45,13 @@ func (suite *CorsSuite) SetupSuite() { suite.client, err = e2e.NewHTTPClient(suite.tmplData.Host) suite.NoError(err) - suite.NoError(suite.test.Apply("config/patternfile-empty.yml", "", nil)) + suite.NoError(suite.test.Apply("../../config/3.configmap.yaml", "", nil)) + suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), tmplData{Host: suite.test.GetNS() + ".test"})) } func (suite *CorsSuite) TearDownSuite() { - suite.test.Apply("config/patternfile-empty.yml", "", nil) + //suite.test.Apply("../../config/3.configmap.yaml", "", nil) + suite.NoError(suite.test.Apply("config/deploy.yaml.tmpl", suite.test.GetNS(), tmplData{Host: suite.test.GetNS() + ".test"})) suite.test.TearDown() }