istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/security/authz/matcher/header_test.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package matcher 16 17 import ( 18 "regexp" 19 "testing" 20 21 routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" 22 matcher "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3" 23 "github.com/google/go-cmp/cmp" 24 "google.golang.org/protobuf/testing/protocmp" 25 ) 26 27 func TestHeaderMatcher(t *testing.T) { 28 testCases := []struct { 29 Name string 30 K string 31 V string 32 Expect *routepb.HeaderMatcher 33 }{ 34 { 35 Name: "exact match", 36 K: ":path", 37 V: "/productpage", 38 Expect: &routepb.HeaderMatcher{ 39 Name: ":path", 40 HeaderMatchSpecifier: &routepb.HeaderMatcher_StringMatch{ 41 StringMatch: StringMatcherExact("/productpage", false), 42 }, 43 }, 44 }, 45 { 46 Name: "suffix match", 47 K: ":path", 48 V: "*/productpage*", 49 Expect: &routepb.HeaderMatcher{ 50 Name: ":path", 51 HeaderMatchSpecifier: &routepb.HeaderMatcher_StringMatch{ 52 StringMatch: StringMatcherSuffix("/productpage*", false), 53 }, 54 }, 55 }, 56 { 57 Name: "prefix match", 58 K: ":path", 59 V: "/productpage*", 60 Expect: &routepb.HeaderMatcher{ 61 Name: ":path", 62 HeaderMatchSpecifier: &routepb.HeaderMatcher_StringMatch{ 63 StringMatch: StringMatcherPrefix("/productpage", false), 64 }, 65 }, 66 }, 67 { 68 Name: "* match", 69 K: ":path", 70 V: "*", 71 Expect: &routepb.HeaderMatcher{ 72 Name: ":path", 73 HeaderMatchSpecifier: &routepb.HeaderMatcher_PresentMatch{ 74 PresentMatch: true, 75 }, 76 }, 77 }, 78 } 79 80 for _, tc := range testCases { 81 t.Run(tc.Name, func(t *testing.T) { 82 actual := HeaderMatcher(tc.K, tc.V) 83 if !cmp.Equal(tc.Expect, actual, protocmp.Transform()) { 84 t.Errorf("expecting %v, but got %v", tc.Expect, actual) 85 } 86 }) 87 } 88 } 89 90 func TestHostMatcherWithRegex(t *testing.T) { 91 testCases := []struct { 92 Name string 93 K string 94 V string 95 Expect *routepb.HeaderMatcher 96 }{ 97 { 98 Name: "present match", 99 K: ":authority", 100 V: "*", 101 Expect: &routepb.HeaderMatcher{ 102 Name: ":authority", 103 HeaderMatchSpecifier: &routepb.HeaderMatcher_PresentMatch{PresentMatch: true}, 104 }, 105 }, 106 { 107 Name: "prefix match", 108 K: ":authority", 109 V: "*.example.com", 110 Expect: &routepb.HeaderMatcher{ 111 Name: ":authority", 112 HeaderMatchSpecifier: &routepb.HeaderMatcher_StringMatch{ 113 StringMatch: StringMatcherRegex(`(?i).*\.example\.com`), 114 }, 115 }, 116 }, 117 { 118 Name: "suffix match", 119 K: ":authority", 120 V: "example.*", 121 Expect: &routepb.HeaderMatcher{ 122 Name: ":authority", 123 HeaderMatchSpecifier: &routepb.HeaderMatcher_StringMatch{ 124 StringMatch: StringMatcherRegex(`(?i)example\..*`), 125 }, 126 }, 127 }, 128 { 129 Name: "exact match", 130 K: ":authority", 131 V: "example.com", 132 Expect: &routepb.HeaderMatcher{ 133 Name: ":authority", 134 HeaderMatchSpecifier: &routepb.HeaderMatcher_StringMatch{ 135 StringMatch: StringMatcherRegex(`(?i)example\.com`), 136 }, 137 }, 138 }, 139 } 140 141 for _, tc := range testCases { 142 t.Run(tc.Name, func(t *testing.T) { 143 actual := HostMatcherWithRegex(tc.K, tc.V) 144 if re := actual.GetStringMatch().GetSafeRegex().GetRegex(); re != "" { 145 _, err := regexp.Compile(re) 146 if err != nil { 147 t.Errorf("failed to compile regex %s: %v", re, err) 148 } 149 } 150 if !cmp.Equal(tc.Expect, actual, protocmp.Transform()) { 151 t.Errorf("expecting %v, but got %v", tc.Expect, actual) 152 } 153 }) 154 } 155 } 156 157 func TestHostMatcher(t *testing.T) { 158 testCases := []struct { 159 Name string 160 K string 161 V string 162 Expect *routepb.HeaderMatcher 163 }{ 164 { 165 Name: "present match", 166 K: ":authority", 167 V: "*", 168 Expect: &routepb.HeaderMatcher{ 169 Name: ":authority", 170 HeaderMatchSpecifier: &routepb.HeaderMatcher_PresentMatch{ 171 PresentMatch: true, 172 }, 173 }, 174 }, 175 { 176 Name: "suffix match", 177 K: ":authority", 178 V: "*.example.com", 179 Expect: &routepb.HeaderMatcher{ 180 Name: ":authority", 181 HeaderMatchSpecifier: &routepb.HeaderMatcher_StringMatch{ 182 StringMatch: StringMatcherSuffix(".example.com", true), 183 }, 184 }, 185 }, 186 { 187 Name: "prefix match", 188 K: ":authority", 189 V: "example.*", 190 Expect: &routepb.HeaderMatcher{ 191 Name: ":authority", 192 HeaderMatchSpecifier: &routepb.HeaderMatcher_StringMatch{ 193 StringMatch: StringMatcherPrefix("example.", true), 194 }, 195 }, 196 }, 197 { 198 Name: "exact match", 199 K: ":authority", 200 V: "example.com", 201 Expect: &routepb.HeaderMatcher{ 202 Name: ":authority", 203 HeaderMatchSpecifier: &routepb.HeaderMatcher_StringMatch{ 204 StringMatch: StringMatcherExact("example.com", true), 205 }, 206 }, 207 }, 208 } 209 210 for _, tc := range testCases { 211 t.Run(tc.Name, func(t *testing.T) { 212 actual := HostMatcher(tc.K, tc.V) 213 if !cmp.Equal(tc.Expect, actual, protocmp.Transform()) { 214 t.Errorf("expecting %v, but got %v", tc.Expect, actual) 215 } 216 }) 217 } 218 } 219 220 func TestPathMatcher(t *testing.T) { 221 testCases := []struct { 222 Name string 223 V string 224 Expect *matcher.PathMatcher 225 }{ 226 { 227 Name: "exact match", 228 V: "/productpage", 229 Expect: &matcher.PathMatcher{ 230 Rule: &matcher.PathMatcher_Path{ 231 Path: StringMatcherExact("/productpage", false), 232 }, 233 }, 234 }, 235 { 236 Name: "prefix match", 237 V: "/prefix*", 238 Expect: &matcher.PathMatcher{ 239 Rule: &matcher.PathMatcher_Path{ 240 Path: StringMatcherPrefix("/prefix", false), 241 }, 242 }, 243 }, 244 { 245 Name: "suffix match", 246 V: "*suffix", 247 Expect: &matcher.PathMatcher{ 248 Rule: &matcher.PathMatcher_Path{ 249 Path: StringMatcherSuffix("suffix", false), 250 }, 251 }, 252 }, 253 { 254 Name: "wildcard match", 255 V: "*", 256 Expect: &matcher.PathMatcher{ 257 Rule: &matcher.PathMatcher_Path{ 258 Path: StringMatcherRegex(".+"), 259 }, 260 }, 261 }, 262 } 263 264 for _, tc := range testCases { 265 t.Run(tc.Name, func(t *testing.T) { 266 actual := PathMatcher(tc.V) 267 if !cmp.Equal(tc.Expect, actual, protocmp.Transform()) { 268 t.Errorf("expecting %v, but got %v", tc.Expect, actual) 269 } 270 }) 271 } 272 }