gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/authz/rbac_translator_test.go (about) 1 /* 2 * 3 * Copyright 2021 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package authz 20 21 import ( 22 "strings" 23 "testing" 24 25 "github.com/google/go-cmp/cmp" 26 "google.golang.org/protobuf/testing/protocmp" 27 28 v3rbacpb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/config/rbac/v3" 29 v3routepb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/config/route/v3" 30 v3matcherpb "gitee.com/ks-custle/core-gm/go-control-plane/envoy/type/matcher/v3" 31 ) 32 33 func TestTranslatePolicy(t *testing.T) { 34 tests := map[string]struct { 35 authzPolicy string 36 wantErr string 37 wantPolicies []*v3rbacpb.RBAC 38 }{ 39 "valid policy": { 40 authzPolicy: `{ 41 "name": "authz", 42 "deny_rules": [ 43 { 44 "name": "deny_policy_1", 45 "source": { 46 "principals":[ 47 "spiffe://foo.abc", 48 "spiffe://bar*", 49 "*baz", 50 "spiffe://abc.*.com" 51 ] 52 } 53 }], 54 "allow_rules": [ 55 { 56 "name": "allow_policy_1", 57 "source": { 58 "principals":["*"] 59 }, 60 "request": { 61 "paths": ["path-foo*"] 62 } 63 }, 64 { 65 "name": "allow_policy_2", 66 "request": { 67 "paths": [ 68 "path-bar", 69 "*baz" 70 ], 71 "headers": [ 72 { 73 "key": "key-1", 74 "values": ["foo", "*bar"] 75 }, 76 { 77 "key": "key-2", 78 "values": ["baz*"] 79 } 80 ] 81 } 82 }] 83 }`, 84 wantPolicies: []*v3rbacpb.RBAC{ 85 { 86 Action: v3rbacpb.RBAC_DENY, 87 Policies: map[string]*v3rbacpb.Policy{ 88 "authz_deny_policy_1": { 89 Principals: []*v3rbacpb.Principal{ 90 {Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{ 91 Ids: []*v3rbacpb.Principal{ 92 {Identifier: &v3rbacpb.Principal_Authenticated_{ 93 Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{ 94 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "spiffe://foo.abc"}, 95 }}, 96 }}, 97 {Identifier: &v3rbacpb.Principal_Authenticated_{ 98 Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{ 99 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "spiffe://bar"}, 100 }}, 101 }}, 102 {Identifier: &v3rbacpb.Principal_Authenticated_{ 103 Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{ 104 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "baz"}, 105 }}, 106 }}, 107 {Identifier: &v3rbacpb.Principal_Authenticated_{ 108 Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{ 109 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "spiffe://abc.*.com"}, 110 }}, 111 }}, 112 }, 113 }}}, 114 }, 115 Permissions: []*v3rbacpb.Permission{ 116 {Rule: &v3rbacpb.Permission_Any{Any: true}}, 117 }, 118 }, 119 }, 120 }, 121 { 122 Action: v3rbacpb.RBAC_ALLOW, 123 Policies: map[string]*v3rbacpb.Policy{ 124 "authz_allow_policy_1": { 125 Principals: []*v3rbacpb.Principal{ 126 {Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{ 127 Ids: []*v3rbacpb.Principal{ 128 {Identifier: &v3rbacpb.Principal_Authenticated_{ 129 Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{ 130 MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}}, 131 }}, 132 }}, 133 }, 134 }}}, 135 }, 136 Permissions: []*v3rbacpb.Permission{ 137 {Rule: &v3rbacpb.Permission_AndRules{AndRules: &v3rbacpb.Permission_Set{ 138 Rules: []*v3rbacpb.Permission{ 139 {Rule: &v3rbacpb.Permission_OrRules{OrRules: &v3rbacpb.Permission_Set{ 140 Rules: []*v3rbacpb.Permission{ 141 {Rule: &v3rbacpb.Permission_UrlPath{ 142 UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{ 143 MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "path-foo"}, 144 }}}, 145 }}, 146 }, 147 }}}, 148 }, 149 }}}, 150 }, 151 }, 152 "authz_allow_policy_2": { 153 Principals: []*v3rbacpb.Principal{ 154 {Identifier: &v3rbacpb.Principal_Any{Any: true}}, 155 }, 156 Permissions: []*v3rbacpb.Permission{ 157 {Rule: &v3rbacpb.Permission_AndRules{AndRules: &v3rbacpb.Permission_Set{ 158 Rules: []*v3rbacpb.Permission{ 159 {Rule: &v3rbacpb.Permission_OrRules{OrRules: &v3rbacpb.Permission_Set{ 160 Rules: []*v3rbacpb.Permission{ 161 {Rule: &v3rbacpb.Permission_UrlPath{ 162 UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{ 163 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "path-bar"}, 164 }}}, 165 }}, 166 {Rule: &v3rbacpb.Permission_UrlPath{ 167 UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{ 168 MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "baz"}, 169 }}}, 170 }}, 171 }, 172 }}}, 173 {Rule: &v3rbacpb.Permission_AndRules{AndRules: &v3rbacpb.Permission_Set{ 174 Rules: []*v3rbacpb.Permission{ 175 {Rule: &v3rbacpb.Permission_OrRules{OrRules: &v3rbacpb.Permission_Set{ 176 Rules: []*v3rbacpb.Permission{ 177 {Rule: &v3rbacpb.Permission_Header{ 178 Header: &v3routepb.HeaderMatcher{ 179 Name: "key-1", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_ExactMatch{ExactMatch: "foo"}, 180 }, 181 }}, 182 {Rule: &v3rbacpb.Permission_Header{ 183 Header: &v3routepb.HeaderMatcher{ 184 Name: "key-1", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_SuffixMatch{SuffixMatch: "bar"}, 185 }, 186 }}, 187 }, 188 }}}, 189 {Rule: &v3rbacpb.Permission_OrRules{OrRules: &v3rbacpb.Permission_Set{ 190 Rules: []*v3rbacpb.Permission{ 191 {Rule: &v3rbacpb.Permission_Header{ 192 Header: &v3routepb.HeaderMatcher{ 193 Name: "key-2", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_PrefixMatch{PrefixMatch: "baz"}, 194 }, 195 }}, 196 }, 197 }}}, 198 }, 199 }}}, 200 }, 201 }}}, 202 }, 203 }, 204 }, 205 }, 206 }, 207 }, 208 "allow authenticated": { 209 authzPolicy: `{ 210 "name": "authz", 211 "allow_rules": [ 212 { 213 "name": "allow_authenticated", 214 "source": { 215 "principals":["*", ""] 216 } 217 }] 218 }`, 219 wantPolicies: []*v3rbacpb.RBAC{ 220 { 221 Action: v3rbacpb.RBAC_ALLOW, 222 Policies: map[string]*v3rbacpb.Policy{ 223 "authz_allow_authenticated": { 224 Principals: []*v3rbacpb.Principal{ 225 {Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{ 226 Ids: []*v3rbacpb.Principal{ 227 {Identifier: &v3rbacpb.Principal_Authenticated_{ 228 Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{ 229 MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}}, 230 }}, 231 }}, 232 {Identifier: &v3rbacpb.Principal_Authenticated_{ 233 Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{ 234 MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""}, 235 }}, 236 }}, 237 }, 238 }}}, 239 }, 240 Permissions: []*v3rbacpb.Permission{ 241 {Rule: &v3rbacpb.Permission_Any{Any: true}}, 242 }, 243 }, 244 }, 245 }, 246 }, 247 }, 248 "unknown field": { 249 authzPolicy: `{"random": 123}`, 250 wantErr: "failed to unmarshal policy", 251 }, 252 "missing name field": { 253 authzPolicy: `{}`, 254 wantErr: `"name" is not present`, 255 }, 256 "invalid field type": { 257 authzPolicy: `{"name": 123}`, 258 wantErr: "failed to unmarshal policy", 259 }, 260 "missing allow rules field": { 261 authzPolicy: `{"name": "authz-foo"}`, 262 wantErr: `"allow_rules" is not present`, 263 }, 264 "missing rule name field": { 265 authzPolicy: `{ 266 "name": "authz-foo", 267 "allow_rules": [{}] 268 }`, 269 wantErr: `"allow_rules" 0: "name" is not present`, 270 }, 271 "missing header key": { 272 authzPolicy: `{ 273 "name": "authz", 274 "allow_rules": [{ 275 "name": "allow_policy_1", 276 "request": {"headers":[{"key":"key-a", "values": ["value-a"]}, {}]} 277 }] 278 }`, 279 wantErr: `"allow_rules" 0: "headers" 1: "key" is not present`, 280 }, 281 "missing header values": { 282 authzPolicy: `{ 283 "name": "authz", 284 "allow_rules": [{ 285 "name": "allow_policy_1", 286 "request": {"headers":[{"key":"key-a"}]} 287 }] 288 }`, 289 wantErr: `"allow_rules" 0: "headers" 0: "values" is not present`, 290 }, 291 "unsupported header": { 292 authzPolicy: `{ 293 "name": "authz", 294 "allow_rules": [{ 295 "name": "allow_policy_1", 296 "request": {"headers":[{"key":":method", "values":["GET"]}]} 297 }] 298 }`, 299 wantErr: `"allow_rules" 0: "headers" 0: unsupported "key" :method`, 300 }, 301 } 302 for name, test := range tests { 303 t.Run(name, func(t *testing.T) { 304 gotPolicies, gotErr := translatePolicy(test.authzPolicy) 305 if gotErr != nil && !strings.HasPrefix(gotErr.Error(), test.wantErr) { 306 t.Fatalf("unexpected error\nwant:%v\ngot:%v", test.wantErr, gotErr) 307 } 308 if diff := cmp.Diff(gotPolicies, test.wantPolicies, protocmp.Transform()); diff != "" { 309 t.Fatalf("unexpected policy\ndiff (-want +got):\n%s", diff) 310 } 311 }) 312 } 313 }