diff --git a/conformance/tests/cors-allow-credentials-behavior.go b/conformance/tests/cors-allow-credentials-behavior.go new file mode 100644 index 0000000000..391b3cee80 --- /dev/null +++ b/conformance/tests/cors-allow-credentials-behavior.go @@ -0,0 +1,100 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tests + +import ( + "testing" + + "k8s.io/apimachinery/pkg/types" + + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + ConformanceTests = append(ConformanceTests, CORSAllowCredentialsBehavior) +} + +var CORSAllowCredentialsBehavior = suite.ConformanceTest{ + ShortName: "CORSAllowCredentialsBehavior", + Description: "Validate ACA-Credentials responses", + Manifests: []string{"tests/cors-allow-credentials-behavior.yaml"}, + Features: []features.FeatureName{ + features.SupportGateway, + features.SupportHTTPRoute, + features.SupportHTTPRouteCORS, + }, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "cors-allow-credentials", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN) + + origin := "https://app.example" + + testCases := []http.ExpectedResponse{ + { + Request: http.Request{ + Method: "GET", + Path: "/cors-behavior-creds-false", + Headers: map[string]string{ + "Origin": origin, + "Cookie": "sid=abc123", + "Authorization": "Bearer test", + }, + }, + Response: http.Response{ + StatusCode: 200, + AbsentHeaders: []string{"Access-Control-Allow-Credentials"}, + }, + Namespace: ns, + }, + { + Request: http.Request{ + Method: "GET", + Path: "/cors-behavior-creds-true", + Headers: map[string]string{ + "Origin": origin, + "Cookie": "sid=abc123", + "Authorization": "Bearer test", + }, + }, + Response: http.Response{ + StatusCode: 200, + Headers: map[string]string{ + "Access-Control-Allow-Credentials": "true", + "Access-Control-Allow-Origin": origin, + }, + }, + Namespace: ns, + }, + } + + for i := range testCases { + // Declare tc here to avoid loop variable + // reuse issues across parallel tests. + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc) + }) + } + }, +} diff --git a/conformance/tests/cors-allow-credentials-behavior.yaml b/conformance/tests/cors-allow-credentials-behavior.yaml new file mode 100644 index 0000000000..13992e28f4 --- /dev/null +++ b/conformance/tests/cors-allow-credentials-behavior.yaml @@ -0,0 +1,32 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: cors-allow-credentials + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - path: + type: PathPrefix + value: /cors-behavior-creds-false + backendRefs: + - name: infra-backend-v1 + port: 8080 + filters: + - cors: + allowCredentials: false + type: CORS + - matches: + - path: + type: PathPrefix + value: /cors-behavior-creds-true + backendRefs: + - name: infra-backend-v1 + port: 8080 + filters: + - cors: + allowCredentials: true + type: CORS + diff --git a/pkg/features/httproute.go b/pkg/features/httproute.go index 6c484da96c..c8b7b0c09c 100644 --- a/pkg/features/httproute.go +++ b/pkg/features/httproute.go @@ -100,6 +100,9 @@ const ( // This option indicates support for the name field in the HTTPRouteRule (extended conformance) SupportHTTPRouteNamedRouteRule FeatureName = "HTTPRouteNamedRouteRule" + + // This option indicates support for the cors filter in the HTTPRouteFilter (extended conformance) + SupportHTTPRouteCORS FeatureName = "HTTPRouteNamedRouteRule" ) var ( @@ -198,6 +201,11 @@ var ( Name: SupportHTTPRouteNamedRouteRule, Channel: FeatureChannelStandard, } + // HTTPRouteCORS contains metadata for the SupportHTTPRouteCORS feature. + HTTPRouteCORS = Feature{ + Name: SupportHTTPRouteCORS, + Channel: FeatureChannelExperimental, + } ) // HTTPRouteExtendedFeatures includes all extended features for HTTPRoute @@ -223,4 +231,5 @@ var HTTPRouteExtendedFeatures = sets.New( HTTPRouteBackendProtocolH2CFeature, HTTPRouteBackendProtocolWebSocketFeature, HTTPRouteNamedRouteRule, + HTTPRouteCORS, )