github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/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 "github.com/hxx258456/ccgo/go-control-plane/envoy/config/rbac/v3"
    29  	v3routepb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/route/v3"
    30  	v3matcherpb "github.com/hxx258456/ccgo/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  }