gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/grpc/internal/xds/rbac/rbac_engine_test.go (about)

     1  /*
     2   * Copyright 2021 gRPC authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package rbac
    18  
    19  import (
    20  	"context"
    21  	"crypto/x509/pkix"
    22  	"net"
    23  	"net/url"
    24  	"testing"
    25  
    26  	"gitee.com/zhaochuninhefei/gmgo/x509"
    27  
    28  	tls "gitee.com/zhaochuninhefei/gmgo/gmtls"
    29  
    30  	v3corepb "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/config/core/v3"
    31  	v3rbacpb "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/config/rbac/v3"
    32  	v3routepb "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/config/route/v3"
    33  	v3matcherpb "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/type/matcher/v3"
    34  	v3typepb "gitee.com/zhaochuninhefei/gmgo/go-control-plane/envoy/type/v3"
    35  	"gitee.com/zhaochuninhefei/gmgo/grpc"
    36  	"gitee.com/zhaochuninhefei/gmgo/grpc/codes"
    37  	"gitee.com/zhaochuninhefei/gmgo/grpc/credentials"
    38  	"gitee.com/zhaochuninhefei/gmgo/grpc/internal/grpctest"
    39  	"gitee.com/zhaochuninhefei/gmgo/grpc/metadata"
    40  	"gitee.com/zhaochuninhefei/gmgo/grpc/peer"
    41  	"gitee.com/zhaochuninhefei/gmgo/grpc/status"
    42  	wrapperspb "github.com/golang/protobuf/ptypes/wrappers"
    43  )
    44  
    45  type s struct {
    46  	grpctest.Tester
    47  }
    48  
    49  func Test(t *testing.T) {
    50  	grpctest.RunSubTests(t, s{})
    51  }
    52  
    53  type addr struct {
    54  	ipAddress string
    55  }
    56  
    57  func (*addr) Network() string  { return "" }
    58  func (a *addr) String() string { return a.ipAddress }
    59  
    60  // TestNewChainEngine tests the construction of the ChainEngine. Due to some
    61  // types of RBAC configuration being logically wrong and returning an error
    62  // rather than successfully constructing the RBAC Engine, this test tests both
    63  // RBAC Configurations deemed successful and also RBAC Configurations that will
    64  // raise errors.
    65  func (s) TestNewChainEngine(t *testing.T) {
    66  	tests := []struct {
    67  		name     string
    68  		policies []*v3rbacpb.RBAC
    69  		wantErr  bool
    70  	}{
    71  		{
    72  			name: "SuccessCaseAnyMatchSingular",
    73  			policies: []*v3rbacpb.RBAC{
    74  				{
    75  					Action: v3rbacpb.RBAC_ALLOW,
    76  					Policies: map[string]*v3rbacpb.Policy{
    77  						"anyone": {
    78  							Permissions: []*v3rbacpb.Permission{
    79  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
    80  							},
    81  							Principals: []*v3rbacpb.Principal{
    82  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
    83  							},
    84  						},
    85  					},
    86  				},
    87  			},
    88  		},
    89  		{
    90  			name: "SuccessCaseAnyMatchMultiple",
    91  			policies: []*v3rbacpb.RBAC{
    92  				{
    93  					Action: v3rbacpb.RBAC_ALLOW,
    94  					Policies: map[string]*v3rbacpb.Policy{
    95  						"anyone": {
    96  							Permissions: []*v3rbacpb.Permission{
    97  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
    98  							},
    99  							Principals: []*v3rbacpb.Principal{
   100  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   101  							},
   102  						},
   103  					},
   104  				},
   105  				{
   106  					Action: v3rbacpb.RBAC_DENY,
   107  					Policies: map[string]*v3rbacpb.Policy{
   108  						"anyone": {
   109  							Permissions: []*v3rbacpb.Permission{
   110  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   111  							},
   112  							Principals: []*v3rbacpb.Principal{
   113  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   114  							},
   115  						},
   116  					},
   117  				},
   118  			},
   119  		},
   120  		{
   121  			name: "SuccessCaseSimplePolicySingular",
   122  			policies: []*v3rbacpb.RBAC{
   123  				{
   124  					Action: v3rbacpb.RBAC_ALLOW,
   125  					Policies: map[string]*v3rbacpb.Policy{
   126  						"localhost-fan": {
   127  							Permissions: []*v3rbacpb.Permission{
   128  								{Rule: &v3rbacpb.Permission_DestinationPort{DestinationPort: 8080}},
   129  								{Rule: &v3rbacpb.Permission_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "localhost-fan-page"}}}}}},
   130  							},
   131  							Principals: []*v3rbacpb.Principal{
   132  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   133  							},
   134  						},
   135  					},
   136  				},
   137  			},
   138  		},
   139  		// SuccessCaseSimplePolicyTwoPolicies tests the construction of the
   140  		// chained engines in the case where there are two policies in a list,
   141  		// one with an allow policy and one with a deny policy. A situation
   142  		// where two policies (allow and deny) is a very common use case for
   143  		// this API, and should successfully build.
   144  		{
   145  			name: "SuccessCaseSimplePolicyTwoPolicies",
   146  			policies: []*v3rbacpb.RBAC{
   147  				{
   148  					Action: v3rbacpb.RBAC_ALLOW,
   149  					Policies: map[string]*v3rbacpb.Policy{
   150  						"localhost-fan": {
   151  							Permissions: []*v3rbacpb.Permission{
   152  								{Rule: &v3rbacpb.Permission_DestinationPort{DestinationPort: 8080}},
   153  								{Rule: &v3rbacpb.Permission_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "localhost-fan-page"}}}}}},
   154  							},
   155  							Principals: []*v3rbacpb.Principal{
   156  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   157  							},
   158  						},
   159  					},
   160  				},
   161  				{
   162  					Action: v3rbacpb.RBAC_DENY,
   163  					Policies: map[string]*v3rbacpb.Policy{
   164  						"localhost-fan": {
   165  							Permissions: []*v3rbacpb.Permission{
   166  								{Rule: &v3rbacpb.Permission_DestinationPort{DestinationPort: 8080}},
   167  								{Rule: &v3rbacpb.Permission_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "localhost-fan-page"}}}}}},
   168  							},
   169  							Principals: []*v3rbacpb.Principal{
   170  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   171  							},
   172  						},
   173  					},
   174  				},
   175  			},
   176  		},
   177  		{
   178  			name: "SuccessCaseEnvoyExampleSingular",
   179  			policies: []*v3rbacpb.RBAC{
   180  				{
   181  					Action: v3rbacpb.RBAC_ALLOW,
   182  					Policies: map[string]*v3rbacpb.Policy{
   183  						"service-admin": {
   184  							Permissions: []*v3rbacpb.Permission{
   185  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   186  							},
   187  							Principals: []*v3rbacpb.Principal{
   188  								{Identifier: &v3rbacpb.Principal_Authenticated_{Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "cluster.local/ns/default/sa/admin"}}}}},
   189  								{Identifier: &v3rbacpb.Principal_Authenticated_{Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "cluster.local/ns/default/sa/superuser"}}}}},
   190  							},
   191  						},
   192  						"product-viewer": {
   193  							Permissions: []*v3rbacpb.Permission{
   194  								{Rule: &v3rbacpb.Permission_AndRules{AndRules: &v3rbacpb.Permission_Set{
   195  									Rules: []*v3rbacpb.Permission{
   196  										// HeaderMatcher_ExactMatch已废弃,改为使用HeaderMatcher_StringMatch
   197  										//{Rule: &v3rbacpb.Permission_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_ExactMatch{ExactMatch: "GET"}}}},
   198  										{Rule: &v3rbacpb.Permission_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_StringMatch{StringMatch: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "GET"}}}}}},
   199  										{Rule: &v3rbacpb.Permission_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "/products"}}}}}},
   200  										{Rule: &v3rbacpb.Permission_OrRules{OrRules: &v3rbacpb.Permission_Set{
   201  											Rules: []*v3rbacpb.Permission{
   202  												{Rule: &v3rbacpb.Permission_DestinationPort{DestinationPort: 80}},
   203  												{Rule: &v3rbacpb.Permission_DestinationPort{DestinationPort: 443}},
   204  											},
   205  										},
   206  										},
   207  										},
   208  									},
   209  								},
   210  								},
   211  								},
   212  							},
   213  							Principals: []*v3rbacpb.Principal{
   214  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   215  							},
   216  						},
   217  					},
   218  				},
   219  			},
   220  		},
   221  		{
   222  			name: "SourceIpMatcherSuccessSingular",
   223  			policies: []*v3rbacpb.RBAC{
   224  				{
   225  					Action: v3rbacpb.RBAC_ALLOW,
   226  					Policies: map[string]*v3rbacpb.Policy{
   227  						"certain-source-ip": {
   228  							Permissions: []*v3rbacpb.Permission{
   229  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   230  							},
   231  							Principals: []*v3rbacpb.Principal{
   232  								{Identifier: &v3rbacpb.Principal_DirectRemoteIp{DirectRemoteIp: &v3corepb.CidrRange{AddressPrefix: "0.0.0.0", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}},
   233  							},
   234  						},
   235  					},
   236  				},
   237  			},
   238  		},
   239  		{
   240  			name: "SourceIpMatcherFailureSingular",
   241  			policies: []*v3rbacpb.RBAC{
   242  				{
   243  					Action: v3rbacpb.RBAC_ALLOW,
   244  					Policies: map[string]*v3rbacpb.Policy{
   245  						"certain-source-ip": {
   246  							Permissions: []*v3rbacpb.Permission{
   247  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   248  							},
   249  							Principals: []*v3rbacpb.Principal{
   250  								{Identifier: &v3rbacpb.Principal_DirectRemoteIp{DirectRemoteIp: &v3corepb.CidrRange{AddressPrefix: "not a correct address", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}},
   251  							},
   252  						},
   253  					},
   254  				},
   255  			},
   256  			wantErr: true,
   257  		},
   258  		{
   259  			name: "DestinationIpMatcherSuccess",
   260  			policies: []*v3rbacpb.RBAC{
   261  				{
   262  					Action: v3rbacpb.RBAC_ALLOW,
   263  					Policies: map[string]*v3rbacpb.Policy{
   264  						"certain-destination-ip": {
   265  							Permissions: []*v3rbacpb.Permission{
   266  								{Rule: &v3rbacpb.Permission_DestinationIp{DestinationIp: &v3corepb.CidrRange{AddressPrefix: "0.0.0.0", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}},
   267  							},
   268  							Principals: []*v3rbacpb.Principal{
   269  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   270  							},
   271  						},
   272  					},
   273  				},
   274  			},
   275  		},
   276  		{
   277  			name: "DestinationIpMatcherFailure",
   278  			policies: []*v3rbacpb.RBAC{
   279  				{
   280  					Action: v3rbacpb.RBAC_ALLOW,
   281  					Policies: map[string]*v3rbacpb.Policy{
   282  						"certain-destination-ip": {
   283  							Permissions: []*v3rbacpb.Permission{
   284  								{Rule: &v3rbacpb.Permission_DestinationIp{DestinationIp: &v3corepb.CidrRange{AddressPrefix: "not a correct address", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}},
   285  							},
   286  							Principals: []*v3rbacpb.Principal{
   287  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   288  							},
   289  						},
   290  					},
   291  				},
   292  			},
   293  			wantErr: true,
   294  		},
   295  		{
   296  			name: "MatcherToNotPolicy",
   297  			policies: []*v3rbacpb.RBAC{
   298  				{
   299  					Action: v3rbacpb.RBAC_ALLOW,
   300  					Policies: map[string]*v3rbacpb.Policy{
   301  						"not-secret-content": {
   302  							Permissions: []*v3rbacpb.Permission{
   303  								{Rule: &v3rbacpb.Permission_NotRule{NotRule: &v3rbacpb.Permission{Rule: &v3rbacpb.Permission_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "/secret-content"}}}}}}}},
   304  							},
   305  							Principals: []*v3rbacpb.Principal{
   306  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   307  							},
   308  						},
   309  					},
   310  				},
   311  			},
   312  		},
   313  		{
   314  			name: "MatcherToNotPrinicipal",
   315  			policies: []*v3rbacpb.RBAC{
   316  				{
   317  					Action: v3rbacpb.RBAC_ALLOW,
   318  					Policies: map[string]*v3rbacpb.Policy{
   319  						"not-from-certain-ip": {
   320  							Permissions: []*v3rbacpb.Permission{
   321  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   322  							},
   323  							Principals: []*v3rbacpb.Principal{
   324  								{Identifier: &v3rbacpb.Principal_NotId{NotId: &v3rbacpb.Principal{Identifier: &v3rbacpb.Principal_DirectRemoteIp{DirectRemoteIp: &v3corepb.CidrRange{AddressPrefix: "0.0.0.0", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}}}},
   325  							},
   326  						},
   327  					},
   328  				},
   329  			},
   330  		},
   331  		// PrinicpalProductViewer tests the construction of a chained engine
   332  		// with a policy that allows any downstream to send a GET request on a
   333  		// certain path.
   334  		{
   335  			name: "PrincipalProductViewer",
   336  			policies: []*v3rbacpb.RBAC{
   337  				{
   338  					Action: v3rbacpb.RBAC_ALLOW,
   339  					Policies: map[string]*v3rbacpb.Policy{
   340  						"product-viewer": {
   341  							Permissions: []*v3rbacpb.Permission{
   342  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   343  							},
   344  							Principals: []*v3rbacpb.Principal{
   345  								{
   346  									Identifier: &v3rbacpb.Principal_AndIds{AndIds: &v3rbacpb.Principal_Set{Ids: []*v3rbacpb.Principal{
   347  										// HeaderMatcher_ExactMatch已废弃,改为使用HeaderMatcher_StringMatch
   348  										//{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_ExactMatch{ExactMatch: "GET"}}}},
   349  										{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_StringMatch{StringMatch: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "GET"}}}}}},
   350  										{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
   351  											Ids: []*v3rbacpb.Principal{
   352  												{Identifier: &v3rbacpb.Principal_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "/books"}}}}}},
   353  												{Identifier: &v3rbacpb.Principal_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "/cars"}}}}}},
   354  											},
   355  										}}},
   356  									}}},
   357  								},
   358  							},
   359  						},
   360  					},
   361  				},
   362  			},
   363  		},
   364  		// Certain Headers tests the construction of a chained engine with a
   365  		// policy that allows any downstream to send an HTTP request with
   366  		// certain headers.
   367  		{
   368  			name: "CertainHeaders",
   369  			policies: []*v3rbacpb.RBAC{
   370  				{
   371  					Policies: map[string]*v3rbacpb.Policy{
   372  						"certain-headers": {
   373  							Permissions: []*v3rbacpb.Permission{
   374  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   375  							},
   376  							Principals: []*v3rbacpb.Principal{
   377  								{
   378  									Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{Ids: []*v3rbacpb.Principal{
   379  										// HeaderMatcher_ExactMatch已废弃,改为使用HeaderMatcher_StringMatch
   380  										//{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_ExactMatch{ExactMatch: "GET"}}}},
   381  										{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_StringMatch{StringMatch: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "GET"}}}}}},
   382  										// HeaderMatcher_SafeRegexMatch已废弃,改为使用HeaderMatcher_StringMatch
   383  										//{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_SafeRegexMatch{SafeRegexMatch: &v3matcherpb.RegexMatcher{Regex: "GET"}}}}},
   384  										{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_StringMatch{StringMatch: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: "GET"}}}}}}},
   385  										{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_RangeMatch{RangeMatch: &v3typepb.Int64Range{
   386  											Start: 0,
   387  											End:   64,
   388  										}}}}},
   389  										{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_PresentMatch{PresentMatch: true}}}},
   390  										// HeaderMatcher_PrefixMatch已废弃,改为使用HeaderMatcher_StringMatch
   391  										//{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_PrefixMatch{PrefixMatch: "GET"}}}},
   392  										{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_StringMatch{StringMatch: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "GET"}}}}}},
   393  										// HeaderMatcher_SuffixMatch已废弃,改为使用HeaderMatcher_StringMatch
   394  										//{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_SuffixMatch{SuffixMatch: "GET"}}}},
   395  										{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_StringMatch{StringMatch: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Suffix{Suffix: "GET"}}}}}},
   396  										// HeaderMatcher_ContainsMatch已废弃,改为使用HeaderMatcher_StringMatch
   397  										//{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_ContainsMatch{ContainsMatch: "GET"}}}},
   398  										{Identifier: &v3rbacpb.Principal_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_StringMatch{StringMatch: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Contains{Contains: "GET"}}}}}},
   399  									}}},
   400  								},
   401  							},
   402  						},
   403  					},
   404  				},
   405  			},
   406  		},
   407  		{
   408  			name: "LogAction",
   409  			policies: []*v3rbacpb.RBAC{
   410  				{
   411  					Action: v3rbacpb.RBAC_LOG,
   412  					Policies: map[string]*v3rbacpb.Policy{
   413  						"anyone": {
   414  							Permissions: []*v3rbacpb.Permission{
   415  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   416  							},
   417  							Principals: []*v3rbacpb.Principal{
   418  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   419  							},
   420  						},
   421  					},
   422  				},
   423  			},
   424  			wantErr: true,
   425  		},
   426  		{
   427  			name: "ActionNotSpecified",
   428  			policies: []*v3rbacpb.RBAC{
   429  				{
   430  					Policies: map[string]*v3rbacpb.Policy{
   431  						"anyone": {
   432  							Permissions: []*v3rbacpb.Permission{
   433  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   434  							},
   435  							Principals: []*v3rbacpb.Principal{
   436  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   437  							},
   438  						},
   439  					},
   440  				},
   441  			},
   442  		},
   443  	}
   444  	for _, test := range tests {
   445  		t.Run(test.name, func(t *testing.T) {
   446  			if _, err := NewChainEngine(test.policies); (err != nil) != test.wantErr {
   447  				t.Fatalf("NewChainEngine(%+v) returned err: %v, wantErr: %v", test.policies, err, test.wantErr)
   448  			}
   449  		})
   450  	}
   451  }
   452  
   453  // TestChainEngine tests the chain of RBAC Engines by configuring the chain of
   454  // engines in a certain way in different scenarios. After configuring the chain
   455  // of engines in a certain way, this test pings the chain of engines with
   456  // different types of data representing incoming RPC's (piped into a context),
   457  // and verifies that it works as expected.
   458  func (s) TestChainEngine(t *testing.T) {
   459  	defer func(gc func(ctx context.Context) net.Conn) {
   460  		getConnection = gc
   461  	}(getConnection)
   462  	tests := []struct {
   463  		name        string
   464  		rbacConfigs []*v3rbacpb.RBAC
   465  		rbacQueries []struct {
   466  			rpcData        *rpcData
   467  			wantStatusCode codes.Code
   468  		}
   469  	}{
   470  		// SuccessCaseAnyMatch tests a single RBAC Engine instantiated with
   471  		// a config with a policy with any rules for both permissions and
   472  		// principals, meaning that any data about incoming RPC's that the RBAC
   473  		// Engine is queried with should match that policy.
   474  		{
   475  			name: "SuccessCaseAnyMatch",
   476  			rbacConfigs: []*v3rbacpb.RBAC{
   477  				{
   478  					Policies: map[string]*v3rbacpb.Policy{
   479  						"anyone": {
   480  							Permissions: []*v3rbacpb.Permission{
   481  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   482  							},
   483  							Principals: []*v3rbacpb.Principal{
   484  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   485  							},
   486  						},
   487  					},
   488  				},
   489  			},
   490  			rbacQueries: []struct {
   491  				rpcData        *rpcData
   492  				wantStatusCode codes.Code
   493  			}{
   494  				{
   495  					rpcData: &rpcData{
   496  						fullMethod: "some method",
   497  						peerInfo: &peer.Peer{
   498  							Addr: &addr{ipAddress: "0.0.0.0"},
   499  						},
   500  					},
   501  					wantStatusCode: codes.OK,
   502  				},
   503  			},
   504  		},
   505  		// SuccessCaseSimplePolicy is a test that tests a single policy
   506  		// that only allows an rpc to proceed if the rpc is calling with a certain
   507  		// path.
   508  		{
   509  			name: "SuccessCaseSimplePolicy",
   510  			rbacConfigs: []*v3rbacpb.RBAC{
   511  				{
   512  					Policies: map[string]*v3rbacpb.Policy{
   513  						"localhost-fan": {
   514  							Permissions: []*v3rbacpb.Permission{
   515  								{Rule: &v3rbacpb.Permission_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "localhost-fan-page"}}}}}},
   516  							},
   517  							Principals: []*v3rbacpb.Principal{
   518  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   519  							},
   520  						},
   521  					},
   522  				},
   523  			},
   524  			rbacQueries: []struct {
   525  				rpcData        *rpcData
   526  				wantStatusCode codes.Code
   527  			}{
   528  				// This RPC should match with the local host fan policy. Thus,
   529  				// this RPC should be allowed to proceed.
   530  				{
   531  					rpcData: &rpcData{
   532  						fullMethod: "localhost-fan-page",
   533  						peerInfo: &peer.Peer{
   534  							Addr: &addr{ipAddress: "0.0.0.0"},
   535  						},
   536  					},
   537  					wantStatusCode: codes.OK,
   538  				},
   539  
   540  				// This RPC shouldn't match with the local host fan policy. Thus,
   541  				// this rpc shouldn't be allowed to proceed.
   542  				{
   543  					rpcData: &rpcData{
   544  						peerInfo: &peer.Peer{
   545  							Addr: &addr{ipAddress: "0.0.0.0"},
   546  						},
   547  					},
   548  					wantStatusCode: codes.PermissionDenied,
   549  				},
   550  			},
   551  		},
   552  		// SuccessCaseEnvoyExample is a test based on the example provided
   553  		// in the EnvoyProxy docs. The RBAC Config contains two policies,
   554  		// service admin and product viewer, that provides an example of a real
   555  		// RBAC Config that might be configured for a given for a given backend
   556  		// service.
   557  		{
   558  			name: "SuccessCaseEnvoyExample",
   559  			rbacConfigs: []*v3rbacpb.RBAC{
   560  				{
   561  					Policies: map[string]*v3rbacpb.Policy{
   562  						"service-admin": {
   563  							Permissions: []*v3rbacpb.Permission{
   564  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   565  							},
   566  							Principals: []*v3rbacpb.Principal{
   567  								{Identifier: &v3rbacpb.Principal_Authenticated_{Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "//cluster.local/ns/default/sa/admin"}}}}},
   568  								{Identifier: &v3rbacpb.Principal_Authenticated_{Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "//cluster.local/ns/default/sa/superuser"}}}}},
   569  							},
   570  						},
   571  						"product-viewer": {
   572  							Permissions: []*v3rbacpb.Permission{
   573  								{
   574  									Rule: &v3rbacpb.Permission_AndRules{AndRules: &v3rbacpb.Permission_Set{
   575  										Rules: []*v3rbacpb.Permission{
   576  											// HeaderMatcher_ExactMatch已废弃,改为使用HeaderMatcher_StringMatch
   577  											//{Rule: &v3rbacpb.Permission_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_ExactMatch{ExactMatch: "GET"}}}},
   578  											{Rule: &v3rbacpb.Permission_Header{Header: &v3routepb.HeaderMatcher{Name: ":method", HeaderMatchSpecifier: &v3routepb.HeaderMatcher_StringMatch{StringMatch: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "GET"}}}}}},
   579  											{Rule: &v3rbacpb.Permission_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "/products"}}}}}},
   580  										},
   581  									},
   582  									},
   583  								},
   584  							},
   585  							Principals: []*v3rbacpb.Principal{
   586  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   587  							},
   588  						},
   589  					},
   590  				},
   591  			},
   592  			rbacQueries: []struct {
   593  				rpcData        *rpcData
   594  				wantStatusCode codes.Code
   595  			}{
   596  				// This incoming RPC Call should match with the service admin
   597  				// policy.
   598  				{
   599  					rpcData: &rpcData{
   600  						fullMethod: "some method",
   601  						peerInfo: &peer.Peer{
   602  							Addr: &addr{ipAddress: "0.0.0.0"},
   603  							AuthInfo: credentials.TLSInfo{
   604  								State: tls.ConnectionState{
   605  									PeerCertificates: []*x509.Certificate{
   606  										{
   607  											URIs: []*url.URL{
   608  												{
   609  													Host: "cluster.local",
   610  													Path: "/ns/default/sa/admin",
   611  												},
   612  											},
   613  										},
   614  									},
   615  								},
   616  							},
   617  						},
   618  					},
   619  					wantStatusCode: codes.OK,
   620  				},
   621  				// These incoming RPC calls should not match any policy.
   622  				{
   623  					rpcData: &rpcData{
   624  						peerInfo: &peer.Peer{
   625  							Addr: &addr{ipAddress: "0.0.0.0"},
   626  						},
   627  					},
   628  					wantStatusCode: codes.PermissionDenied,
   629  				},
   630  				{
   631  					rpcData: &rpcData{
   632  						fullMethod: "get-product-list",
   633  						peerInfo: &peer.Peer{
   634  							Addr: &addr{ipAddress: "0.0.0.0"},
   635  						},
   636  					},
   637  					wantStatusCode: codes.PermissionDenied,
   638  				},
   639  				{
   640  					rpcData: &rpcData{
   641  						peerInfo: &peer.Peer{
   642  							Addr: &addr{ipAddress: "0.0.0.0"},
   643  							AuthInfo: credentials.TLSInfo{
   644  								State: tls.ConnectionState{
   645  									PeerCertificates: []*x509.Certificate{
   646  										{
   647  											Subject: pkix.Name{
   648  												CommonName: "localhost",
   649  											},
   650  										},
   651  									},
   652  								},
   653  							},
   654  						},
   655  					},
   656  					wantStatusCode: codes.PermissionDenied,
   657  				},
   658  			},
   659  		},
   660  		{
   661  			name: "NotMatcher",
   662  			rbacConfigs: []*v3rbacpb.RBAC{
   663  				{
   664  					Policies: map[string]*v3rbacpb.Policy{
   665  						"not-secret-content": {
   666  							Permissions: []*v3rbacpb.Permission{
   667  								{
   668  									Rule: &v3rbacpb.Permission_NotRule{
   669  										NotRule: &v3rbacpb.Permission{Rule: &v3rbacpb.Permission_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Prefix{Prefix: "/secret-content"}}}}}},
   670  									},
   671  								},
   672  							},
   673  							Principals: []*v3rbacpb.Principal{
   674  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   675  							},
   676  						},
   677  					},
   678  				},
   679  			},
   680  			rbacQueries: []struct {
   681  				rpcData        *rpcData
   682  				wantStatusCode codes.Code
   683  			}{
   684  				// This incoming RPC Call should match with the not-secret-content policy.
   685  				{
   686  					rpcData: &rpcData{
   687  						fullMethod: "/regular-content",
   688  						peerInfo: &peer.Peer{
   689  							Addr: &addr{ipAddress: "0.0.0.0"},
   690  						},
   691  					},
   692  					wantStatusCode: codes.OK,
   693  				},
   694  				// This incoming RPC Call shouldn't match with the not-secret-content-policy.
   695  				{
   696  					rpcData: &rpcData{
   697  						fullMethod: "/secret-content",
   698  						peerInfo: &peer.Peer{
   699  							Addr: &addr{ipAddress: "0.0.0.0"},
   700  						},
   701  					},
   702  					wantStatusCode: codes.PermissionDenied,
   703  				},
   704  			},
   705  		},
   706  		{
   707  			name: "DirectRemoteIpMatcher",
   708  			rbacConfigs: []*v3rbacpb.RBAC{
   709  				{
   710  					Policies: map[string]*v3rbacpb.Policy{
   711  						"certain-direct-remote-ip": {
   712  							Permissions: []*v3rbacpb.Permission{
   713  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   714  							},
   715  							Principals: []*v3rbacpb.Principal{
   716  								{Identifier: &v3rbacpb.Principal_DirectRemoteIp{DirectRemoteIp: &v3corepb.CidrRange{AddressPrefix: "0.0.0.0", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}},
   717  							},
   718  						},
   719  					},
   720  				},
   721  			},
   722  			rbacQueries: []struct {
   723  				rpcData        *rpcData
   724  				wantStatusCode codes.Code
   725  			}{
   726  				// This incoming RPC Call should match with the certain-direct-remote-ip policy.
   727  				{
   728  					rpcData: &rpcData{
   729  						peerInfo: &peer.Peer{
   730  							Addr: &addr{ipAddress: "0.0.0.0"},
   731  						},
   732  					},
   733  					wantStatusCode: codes.OK,
   734  				},
   735  				// This incoming RPC Call shouldn't match with the certain-direct-remote-ip policy.
   736  				{
   737  					rpcData: &rpcData{
   738  						peerInfo: &peer.Peer{
   739  							Addr: &addr{ipAddress: "10.0.0.0"},
   740  						},
   741  					},
   742  					wantStatusCode: codes.PermissionDenied,
   743  				},
   744  			},
   745  		},
   746  		// This test tests a RBAC policy configured with a remote-ip policy.
   747  		// This should be logically equivalent to configuring a Engine with a
   748  		// direct-remote-ip policy, as per A41 - "allow equating RBAC's
   749  		// direct_remote_ip and remote_ip."
   750  		{
   751  			name: "RemoteIpMatcher",
   752  			rbacConfigs: []*v3rbacpb.RBAC{
   753  				{
   754  					Policies: map[string]*v3rbacpb.Policy{
   755  						"certain-remote-ip": {
   756  							Permissions: []*v3rbacpb.Permission{
   757  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   758  							},
   759  							Principals: []*v3rbacpb.Principal{
   760  								{Identifier: &v3rbacpb.Principal_RemoteIp{RemoteIp: &v3corepb.CidrRange{AddressPrefix: "0.0.0.0", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}},
   761  							},
   762  						},
   763  					},
   764  				},
   765  			},
   766  			rbacQueries: []struct {
   767  				rpcData        *rpcData
   768  				wantStatusCode codes.Code
   769  			}{
   770  				// This incoming RPC Call should match with the certain-remote-ip policy.
   771  				{
   772  					rpcData: &rpcData{
   773  						peerInfo: &peer.Peer{
   774  							Addr: &addr{ipAddress: "0.0.0.0"},
   775  						},
   776  					},
   777  					wantStatusCode: codes.OK,
   778  				},
   779  				// This incoming RPC Call shouldn't match with the certain-remote-ip policy.
   780  				{
   781  					rpcData: &rpcData{
   782  						peerInfo: &peer.Peer{
   783  							Addr: &addr{ipAddress: "10.0.0.0"},
   784  						},
   785  					},
   786  					wantStatusCode: codes.PermissionDenied,
   787  				},
   788  			},
   789  		},
   790  		{
   791  			name: "DestinationIpMatcher",
   792  			rbacConfigs: []*v3rbacpb.RBAC{
   793  				{
   794  					Policies: map[string]*v3rbacpb.Policy{
   795  						"certain-destination-ip": {
   796  							Permissions: []*v3rbacpb.Permission{
   797  								{Rule: &v3rbacpb.Permission_DestinationIp{DestinationIp: &v3corepb.CidrRange{AddressPrefix: "0.0.0.0", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}},
   798  							},
   799  							Principals: []*v3rbacpb.Principal{
   800  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   801  							},
   802  						},
   803  					},
   804  				},
   805  			},
   806  			rbacQueries: []struct {
   807  				rpcData        *rpcData
   808  				wantStatusCode codes.Code
   809  			}{
   810  				// This incoming RPC Call shouldn't match with the
   811  				// certain-destination-ip policy, as the test listens on local
   812  				// host.
   813  				{
   814  					rpcData: &rpcData{
   815  						peerInfo: &peer.Peer{
   816  							Addr: &addr{ipAddress: "10.0.0.0"},
   817  						},
   818  					},
   819  					wantStatusCode: codes.PermissionDenied,
   820  				},
   821  			},
   822  		},
   823  		// AllowAndDenyPolicy tests a policy with an allow (on path) and
   824  		// deny (on port) policy chained together. This represents how a user
   825  		// configured interceptor would use this, and also is a potential
   826  		// configuration for a dynamic xds interceptor.
   827  		{
   828  			name: "AllowAndDenyPolicy",
   829  			rbacConfigs: []*v3rbacpb.RBAC{
   830  				{
   831  					Policies: map[string]*v3rbacpb.Policy{
   832  						"certain-source-ip": {
   833  							Permissions: []*v3rbacpb.Permission{
   834  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   835  							},
   836  							Principals: []*v3rbacpb.Principal{
   837  								{Identifier: &v3rbacpb.Principal_DirectRemoteIp{DirectRemoteIp: &v3corepb.CidrRange{AddressPrefix: "0.0.0.0", PrefixLen: &wrapperspb.UInt32Value{Value: uint32(10)}}}},
   838  							},
   839  						},
   840  					},
   841  					Action: v3rbacpb.RBAC_ALLOW,
   842  				},
   843  				{
   844  					Policies: map[string]*v3rbacpb.Policy{
   845  						"localhost-fan": {
   846  							Permissions: []*v3rbacpb.Permission{
   847  								{Rule: &v3rbacpb.Permission_UrlPath{UrlPath: &v3matcherpb.PathMatcher{Rule: &v3matcherpb.PathMatcher_Path{Path: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "localhost-fan-page"}}}}}},
   848  							},
   849  							Principals: []*v3rbacpb.Principal{
   850  								{Identifier: &v3rbacpb.Principal_Any{Any: true}},
   851  							},
   852  						},
   853  					},
   854  					Action: v3rbacpb.RBAC_DENY,
   855  				},
   856  			},
   857  			rbacQueries: []struct {
   858  				rpcData        *rpcData
   859  				wantStatusCode codes.Code
   860  			}{
   861  				// This RPC should match with the allow policy, and shouldn't
   862  				// match with the deny and thus should be allowed to proceed.
   863  				{
   864  					rpcData: &rpcData{
   865  						peerInfo: &peer.Peer{
   866  							Addr: &addr{ipAddress: "0.0.0.0"},
   867  						},
   868  					},
   869  					wantStatusCode: codes.OK,
   870  				},
   871  				// This RPC should match with both the allow policy and deny policy
   872  				// and thus shouldn't be allowed to proceed as matched with deny.
   873  				{
   874  					rpcData: &rpcData{
   875  						fullMethod: "localhost-fan-page",
   876  						peerInfo: &peer.Peer{
   877  							Addr: &addr{ipAddress: "0.0.0.0"},
   878  						},
   879  					},
   880  					wantStatusCode: codes.PermissionDenied,
   881  				},
   882  				// This RPC shouldn't match with either policy, and thus
   883  				// shouldn't be allowed to proceed as didn't match with allow.
   884  				{
   885  					rpcData: &rpcData{
   886  						peerInfo: &peer.Peer{
   887  							Addr: &addr{ipAddress: "10.0.0.0"},
   888  						},
   889  					},
   890  					wantStatusCode: codes.PermissionDenied,
   891  				},
   892  				// This RPC shouldn't match with allow, match with deny, and
   893  				// thus shouldn't be allowed to proceed.
   894  				{
   895  					rpcData: &rpcData{
   896  						fullMethod: "localhost-fan-page",
   897  						peerInfo: &peer.Peer{
   898  							Addr: &addr{ipAddress: "10.0.0.0"},
   899  						},
   900  					},
   901  					wantStatusCode: codes.PermissionDenied,
   902  				},
   903  			},
   904  		},
   905  		// This test tests that when there are no SANs or Subject's
   906  		// distinguished name in incoming RPC's, that authenticated matchers
   907  		// match against the empty string.
   908  		{
   909  			name: "default-matching-no-credentials",
   910  			rbacConfigs: []*v3rbacpb.RBAC{
   911  				{
   912  					Policies: map[string]*v3rbacpb.Policy{
   913  						"service-admin": {
   914  							Permissions: []*v3rbacpb.Permission{
   915  								{Rule: &v3rbacpb.Permission_Any{Any: true}},
   916  							},
   917  							Principals: []*v3rbacpb.Principal{
   918  								{Identifier: &v3rbacpb.Principal_Authenticated_{Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""}}}}},
   919  							},
   920  						},
   921  					},
   922  				},
   923  			},
   924  			rbacQueries: []struct {
   925  				rpcData        *rpcData
   926  				wantStatusCode codes.Code
   927  			}{
   928  				// This incoming RPC Call should match with the service admin
   929  				// policy. No authentication info is provided, so the
   930  				// authenticated matcher should match to the string matcher on
   931  				// the empty string, matching to the service-admin policy.
   932  				{
   933  					rpcData: &rpcData{
   934  						fullMethod: "some method",
   935  						peerInfo: &peer.Peer{
   936  							Addr: &addr{ipAddress: "0.0.0.0"},
   937  							AuthInfo: credentials.TLSInfo{
   938  								State: tls.ConnectionState{
   939  									PeerCertificates: []*x509.Certificate{
   940  										{
   941  											URIs: []*url.URL{
   942  												{
   943  													Host: "cluster.local",
   944  													Path: "/ns/default/sa/admin",
   945  												},
   946  											},
   947  										},
   948  									},
   949  								},
   950  							},
   951  						},
   952  					},
   953  					wantStatusCode: codes.OK,
   954  				},
   955  			},
   956  		},
   957  	}
   958  
   959  	for _, test := range tests {
   960  		t.Run(test.name, func(t *testing.T) {
   961  			// Instantiate the chainedRBACEngine with different configurations that are
   962  			// interesting to test and to query.
   963  			cre, err := NewChainEngine(test.rbacConfigs)
   964  			if err != nil {
   965  				t.Fatalf("Error constructing RBAC Engine: %v", err)
   966  			}
   967  			// Query the created chain of RBAC Engines with different args to see
   968  			// if the chain of RBAC Engines configured as such works as intended.
   969  			for _, data := range test.rbacQueries {
   970  				func() {
   971  					// Construct the context with three data points that have enough
   972  					// information to represent incoming RPC's. This will be how a
   973  					// user uses this API. A user will have to put MD, PeerInfo, and
   974  					// the connection the RPC is sent on in the context.
   975  					ctx := metadata.NewIncomingContext(context.Background(), data.rpcData.md)
   976  
   977  					// Make a TCP connection with a certain destination port. The
   978  					// address/port of this connection will be used to populate the
   979  					// destination ip/port in RPCData struct. This represents what
   980  					// the user of ChainEngine will have to place into
   981  					// context, as this is only way to get destination ip and port.
   982  					lis, err := net.Listen("tcp", "localhost:0")
   983  					if err != nil {
   984  						t.Fatalf("Error listening: %v", err)
   985  					}
   986  					defer func(lis net.Listener) {
   987  						_ = lis.Close()
   988  					}(lis)
   989  					connCh := make(chan net.Conn, 1)
   990  					go func() {
   991  						conn, err := lis.Accept()
   992  						if err != nil {
   993  							t.Errorf("Error accepting connection: %v", err)
   994  							return
   995  						}
   996  						connCh <- conn
   997  					}()
   998  					_, err = net.Dial("tcp", lis.Addr().String())
   999  					if err != nil {
  1000  						t.Fatalf("Error dialing: %v", err)
  1001  					}
  1002  					conn := <-connCh
  1003  					defer func(conn net.Conn) {
  1004  						_ = conn.Close()
  1005  					}(conn)
  1006  					getConnection = func(context.Context) net.Conn {
  1007  						return conn
  1008  					}
  1009  					ctx = peer.NewContext(ctx, data.rpcData.peerInfo)
  1010  					stream := &ServerTransportStreamWithMethod{
  1011  						method: data.rpcData.fullMethod,
  1012  					}
  1013  
  1014  					ctx = grpc.NewContextWithServerTransportStream(ctx, stream)
  1015  					err = cre.IsAuthorized(ctx)
  1016  					if gotCode := status.Code(err); gotCode != data.wantStatusCode {
  1017  						t.Fatalf("IsAuthorized(%+v, %+v) returned (%+v), want(%+v)", ctx, data.rpcData.fullMethod, gotCode, data.wantStatusCode)
  1018  					}
  1019  				}()
  1020  			}
  1021  		})
  1022  	}
  1023  }
  1024  
  1025  type ServerTransportStreamWithMethod struct {
  1026  	method string
  1027  }
  1028  
  1029  func (sts *ServerTransportStreamWithMethod) Method() string {
  1030  	return sts.method
  1031  }
  1032  
  1033  //goland:noinspection GoUnusedParameter
  1034  func (sts *ServerTransportStreamWithMethod) SetHeader(md metadata.MD) error {
  1035  	return nil
  1036  }
  1037  
  1038  //goland:noinspection GoUnusedParameter
  1039  func (sts *ServerTransportStreamWithMethod) SendHeader(md metadata.MD) error {
  1040  	return nil
  1041  }
  1042  
  1043  //goland:noinspection GoUnusedParameter
  1044  func (sts *ServerTransportStreamWithMethod) SetTrailer(md metadata.MD) error {
  1045  	return nil
  1046  }