google.golang.org/grpc@v1.72.2/authz/grpc_authz_end2end_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_test
    20  
    21  import (
    22  	"context"
    23  	"crypto/tls"
    24  	"crypto/x509"
    25  	"io"
    26  	"os"
    27  	"testing"
    28  	"time"
    29  
    30  	"google.golang.org/grpc"
    31  	"google.golang.org/grpc/authz"
    32  	"google.golang.org/grpc/codes"
    33  	"google.golang.org/grpc/credentials"
    34  	"google.golang.org/grpc/credentials/insecure"
    35  	"google.golang.org/grpc/internal/grpctest"
    36  	"google.golang.org/grpc/internal/stubserver"
    37  	"google.golang.org/grpc/metadata"
    38  	"google.golang.org/grpc/status"
    39  	"google.golang.org/grpc/testdata"
    40  
    41  	testgrpc "google.golang.org/grpc/interop/grpc_testing"
    42  	testpb "google.golang.org/grpc/interop/grpc_testing"
    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  var authzTests = map[string]struct {
    54  	authzPolicy string
    55  	md          metadata.MD
    56  	wantStatus  *status.Status
    57  }{
    58  	"DeniesRPCMatchInDenyNoMatchInAllow": {
    59  		authzPolicy: `{
    60  				"name": "authz",
    61  				"allow_rules":
    62  				[
    63  					{
    64  						"name": "allow_StreamingOutputCall",
    65  						"request": {
    66  							"paths":
    67  							[
    68  								"/grpc.testing.TestService/StreamingOutputCall"
    69  							]
    70  						}
    71  					}
    72  				],
    73  				"deny_rules":
    74  				[
    75  					{
    76  						"name": "deny_TestServiceCalls",
    77  						"request": {
    78  							"paths":
    79  							[
    80  								"/grpc.testing.TestService/*"
    81  							],
    82  							"headers":
    83  							[
    84  								{
    85  									"key": "key-abc",
    86  									"values":
    87  									[
    88  										"val-abc",
    89  										"val-def"
    90  									]
    91  								}
    92  							]
    93  						}
    94  					}
    95  				]
    96  			}`,
    97  		md:         metadata.Pairs("key-abc", "val-abc"),
    98  		wantStatus: status.New(codes.PermissionDenied, "unauthorized RPC request rejected"),
    99  	},
   100  	"DeniesRPCMatchInDenyAndAllow": {
   101  		authzPolicy: `{
   102  				"name": "authz",
   103  				"allow_rules":
   104  				[
   105  					{
   106  						"name": "allow_all",
   107  						"request": {
   108  							"paths":
   109  							[
   110  								"*"
   111  							]
   112  						}
   113  					}
   114  				],
   115  				"deny_rules":
   116  				[
   117  					{
   118  						"name": "deny_all",
   119  						"request": {
   120  							"paths":
   121  							[
   122  								"*"
   123  							]
   124  						}
   125  					}
   126  				]
   127  			}`,
   128  		wantStatus: status.New(codes.PermissionDenied, "unauthorized RPC request rejected"),
   129  	},
   130  	"AllowsRPCNoMatchInDenyMatchInAllow": {
   131  		authzPolicy: `{
   132  				"name": "authz",
   133  				"allow_rules":
   134  				[
   135  					{
   136  						"name": "allow_all"
   137  					}
   138  				],
   139  				"deny_rules":
   140  				[
   141  					{
   142  						"name": "deny_TestServiceCalls",
   143  						"request": {
   144  							"paths":
   145  							[
   146  								"/grpc.testing.TestService/UnaryCall",
   147  								"/grpc.testing.TestService/StreamingInputCall"
   148  							],
   149  							"headers":
   150  							[
   151  								{
   152  									"key": "key-abc",
   153  									"values":
   154  									[
   155  										"val-abc",
   156  										"val-def"
   157  									]
   158  								}
   159  							]
   160  						}
   161  					}
   162  				]
   163  			}`,
   164  		md:         metadata.Pairs("key-xyz", "val-xyz"),
   165  		wantStatus: status.New(codes.OK, ""),
   166  	},
   167  	"DeniesRPCNoMatchInDenyAndAllow": {
   168  		authzPolicy: `{
   169  				"name": "authz",
   170  				"allow_rules":
   171  				[
   172  					{
   173  						"name": "allow_some_user",
   174  						"source": {
   175  							"principals":
   176  							[
   177  								"some_user"
   178  							]
   179  						}
   180  					}
   181  				],
   182  				"deny_rules":
   183  				[
   184  					{
   185  						"name": "deny_StreamingOutputCall",
   186  						"request": {
   187  							"paths":
   188  							[
   189  								"/grpc.testing.TestService/StreamingOutputCall"
   190  							]
   191  						}
   192  					}
   193  				]
   194  			}`,
   195  		wantStatus: status.New(codes.PermissionDenied, "unauthorized RPC request rejected"),
   196  	},
   197  	"AllowsRPCEmptyDenyMatchInAllow": {
   198  		authzPolicy: `{
   199  				"name": "authz",
   200  				"allow_rules":
   201  				[
   202  					{
   203  						"name": "allow_UnaryCall",
   204  						"request":
   205  						{
   206  							"paths":
   207  							[
   208  								"/grpc.testing.TestService/UnaryCall"
   209  							]
   210  						}
   211  					},
   212  					{
   213  						"name": "allow_StreamingInputCall",
   214  						"request":
   215  						{
   216  							"paths":
   217  							[
   218  								"/grpc.testing.TestService/StreamingInputCall"
   219  							]
   220  						}
   221  					}
   222  				]
   223  			}`,
   224  		wantStatus: status.New(codes.OK, ""),
   225  	},
   226  	"DeniesRPCEmptyDenyNoMatchInAllow": {
   227  		authzPolicy: `{
   228  				"name": "authz",
   229  				"allow_rules":
   230  				[
   231  					{
   232  						"name": "allow_StreamingOutputCall",
   233  						"request":
   234  						{
   235  							"paths":
   236  							[
   237  								"/grpc.testing.TestService/StreamingOutputCall"
   238  							]
   239  						}
   240  					}
   241  				]
   242  			}`,
   243  		wantStatus: status.New(codes.PermissionDenied, "unauthorized RPC request rejected"),
   244  	},
   245  	"DeniesRPCRequestWithPrincipalsFieldOnUnauthenticatedConnection": {
   246  		authzPolicy: `{
   247  				"name": "authz",
   248  				"allow_rules":
   249  				[
   250  					{
   251  						"name": "allow_authenticated",
   252  						"source": {
   253  							"principals": ["*", ""]
   254  						}
   255  					}
   256  				]
   257  			}`,
   258  		wantStatus: status.New(codes.PermissionDenied, "unauthorized RPC request rejected"),
   259  	},
   260  	"DeniesRPCRequestNoMatchInAllowFailsPresenceMatch": {
   261  		authzPolicy: `{
   262  				"name": "authz",
   263  				"allow_rules":
   264  				[
   265  					{
   266  						"name": "allow_TestServiceCalls",
   267  						"request": {
   268  							"paths":
   269  							[
   270  								"/grpc.testing.TestService/*"
   271  							],
   272  							"headers":
   273  							[
   274  								{
   275  									"key": "key-abc",
   276  									"values":
   277  									[
   278  										"*"
   279  									]
   280  								}
   281  							]
   282  						}
   283  					}
   284  				]
   285  			}`,
   286  		md:         metadata.Pairs("key-abc", ""),
   287  		wantStatus: status.New(codes.PermissionDenied, "unauthorized RPC request rejected"),
   288  	},
   289  }
   290  
   291  func (s) TestStaticPolicyEnd2End(t *testing.T) {
   292  	for name, test := range authzTests {
   293  		t.Run(name, func(t *testing.T) {
   294  			// Start a gRPC server with gRPC authz unary and stream server interceptors.
   295  			i, _ := authz.NewStatic(test.authzPolicy)
   296  
   297  			stub := &stubserver.StubServer{
   298  				UnaryCallF: func(ctx context.Context, req *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
   299  					return &testpb.SimpleResponse{}, nil
   300  				},
   301  				StreamingInputCallF: func(stream testgrpc.TestService_StreamingInputCallServer) error {
   302  					for {
   303  						_, err := stream.Recv()
   304  						if err == io.EOF {
   305  							return stream.SendAndClose(&testpb.StreamingInputCallResponse{})
   306  						}
   307  						if err != nil {
   308  							return err
   309  						}
   310  					}
   311  				},
   312  				S: grpc.NewServer(grpc.ChainUnaryInterceptor(i.UnaryInterceptor), grpc.ChainStreamInterceptor(i.StreamInterceptor)),
   313  			}
   314  			stubserver.StartTestService(t, stub)
   315  			defer stub.Stop()
   316  
   317  			// Establish a connection to the server.
   318  			cc, err := grpc.NewClient(stub.Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
   319  			if err != nil {
   320  				t.Fatalf("grpc.NewClient(%v) failed: %v", stub.Address, err)
   321  			}
   322  			defer cc.Close()
   323  			client := testgrpc.NewTestServiceClient(cc)
   324  
   325  			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   326  			defer cancel()
   327  			ctx = metadata.NewOutgoingContext(ctx, test.md)
   328  
   329  			// Verifying authorization decision for Unary RPC.
   330  			_, err = client.UnaryCall(ctx, &testpb.SimpleRequest{})
   331  			if got := status.Convert(err); got.Code() != test.wantStatus.Code() || got.Message() != test.wantStatus.Message() {
   332  				t.Fatalf("[UnaryCall] error want:{%v} got:{%v}", test.wantStatus.Err(), got.Err())
   333  			}
   334  
   335  			// Verifying authorization decision for Streaming RPC.
   336  			stream, err := client.StreamingInputCall(ctx)
   337  			if err != nil {
   338  				t.Fatalf("failed StreamingInputCall err: %v", err)
   339  			}
   340  			req := &testpb.StreamingInputCallRequest{
   341  				Payload: &testpb.Payload{
   342  					Body: []byte("hi"),
   343  				},
   344  			}
   345  			if err := stream.Send(req); err != nil && err != io.EOF {
   346  				t.Fatalf("failed stream.Send err: %v", err)
   347  			}
   348  			_, err = stream.CloseAndRecv()
   349  			if got := status.Convert(err); got.Code() != test.wantStatus.Code() || got.Message() != test.wantStatus.Message() {
   350  				t.Fatalf("[StreamingCall] error want:{%v} got:{%v}", test.wantStatus.Err(), got.Err())
   351  			}
   352  		})
   353  	}
   354  }
   355  
   356  func (s) TestAllowsRPCRequestWithPrincipalsFieldOnTLSAuthenticatedConnection(t *testing.T) {
   357  	authzPolicy := `{
   358  				"name": "authz",
   359  				"allow_rules":
   360  				[
   361  					{
   362  						"name": "allow_authenticated",
   363  						"source": {
   364  							"principals": ["*", ""]
   365  						}
   366  					}
   367  				]
   368  			}`
   369  	// Start a gRPC server with gRPC authz unary server interceptor.
   370  	i, _ := authz.NewStatic(authzPolicy)
   371  	creds, err := credentials.NewServerTLSFromFile(testdata.Path("x509/server1_cert.pem"), testdata.Path("x509/server1_key.pem"))
   372  	if err != nil {
   373  		t.Fatalf("failed to generate credentials: %v", err)
   374  	}
   375  
   376  	stub := &stubserver.StubServer{
   377  		UnaryCallF: func(ctx context.Context, req *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
   378  			return &testpb.SimpleResponse{}, nil
   379  		},
   380  		S: grpc.NewServer(grpc.Creds(creds), grpc.ChainUnaryInterceptor(i.UnaryInterceptor)),
   381  	}
   382  	stubserver.StartTestService(t, stub)
   383  	defer stub.S.Stop()
   384  
   385  	// Establish a connection to the server.
   386  	creds, err = credentials.NewClientTLSFromFile(testdata.Path("x509/server_ca_cert.pem"), "x.test.example.com")
   387  	if err != nil {
   388  		t.Fatalf("failed to load credentials: %v", err)
   389  	}
   390  	cc, err := grpc.NewClient(stub.Address, grpc.WithTransportCredentials(creds))
   391  	if err != nil {
   392  		t.Fatalf("grpc.NewClient(%v) failed: %v", stub.Address, err)
   393  	}
   394  	defer cc.Close()
   395  	client := testgrpc.NewTestServiceClient(cc)
   396  
   397  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   398  	defer cancel()
   399  
   400  	// Verifying authorization decision.
   401  	if _, err = client.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil {
   402  		t.Fatalf("client.UnaryCall(_, _) = %v; want nil", err)
   403  	}
   404  }
   405  
   406  func (s) TestAllowsRPCRequestWithPrincipalsFieldOnMTLSAuthenticatedConnection(t *testing.T) {
   407  	authzPolicy := `{
   408  				"name": "authz",
   409  				"allow_rules":
   410  				[
   411  					{
   412  						"name": "allow_authenticated",
   413  						"source": {
   414  							"principals": ["*", ""]
   415  						}
   416  					}
   417  				]
   418  			}`
   419  	// Start a gRPC server with gRPC authz unary server interceptor.
   420  	i, _ := authz.NewStatic(authzPolicy)
   421  	cert, err := tls.LoadX509KeyPair(testdata.Path("x509/server1_cert.pem"), testdata.Path("x509/server1_key.pem"))
   422  	if err != nil {
   423  		t.Fatalf("tls.LoadX509KeyPair(x509/server1_cert.pem, x509/server1_key.pem) failed: %v", err)
   424  	}
   425  	ca, err := os.ReadFile(testdata.Path("x509/client_ca_cert.pem"))
   426  	if err != nil {
   427  		t.Fatalf("os.ReadFile(x509/client_ca_cert.pem) failed: %v", err)
   428  	}
   429  	certPool := x509.NewCertPool()
   430  	if !certPool.AppendCertsFromPEM(ca) {
   431  		t.Fatal("failed to append certificates")
   432  	}
   433  	creds := credentials.NewTLS(&tls.Config{
   434  		ClientAuth:   tls.RequireAndVerifyClientCert,
   435  		Certificates: []tls.Certificate{cert},
   436  		ClientCAs:    certPool,
   437  	})
   438  	stub := &stubserver.StubServer{
   439  		UnaryCallF: func(ctx context.Context, req *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
   440  			return &testpb.SimpleResponse{}, nil
   441  		},
   442  		S: grpc.NewServer(grpc.Creds(creds), grpc.ChainUnaryInterceptor(i.UnaryInterceptor)),
   443  	}
   444  	stubserver.StartTestService(t, stub)
   445  	defer stub.Stop()
   446  
   447  	// Establish a connection to the server.
   448  	cert, err = tls.LoadX509KeyPair(testdata.Path("x509/client1_cert.pem"), testdata.Path("x509/client1_key.pem"))
   449  	if err != nil {
   450  		t.Fatalf("tls.LoadX509KeyPair(x509/client1_cert.pem, x509/client1_key.pem) failed: %v", err)
   451  	}
   452  	ca, err = os.ReadFile(testdata.Path("x509/server_ca_cert.pem"))
   453  	if err != nil {
   454  		t.Fatalf("os.ReadFile(x509/server_ca_cert.pem) failed: %v", err)
   455  	}
   456  	roots := x509.NewCertPool()
   457  	if !roots.AppendCertsFromPEM(ca) {
   458  		t.Fatal("failed to append certificates")
   459  	}
   460  	creds = credentials.NewTLS(&tls.Config{
   461  		Certificates: []tls.Certificate{cert},
   462  		RootCAs:      roots,
   463  		ServerName:   "x.test.example.com",
   464  	})
   465  	cc, err := grpc.NewClient(stub.Address, grpc.WithTransportCredentials(creds))
   466  	if err != nil {
   467  		t.Fatalf("grpc.NewClient(%v) failed: %v", stub.Address, err)
   468  	}
   469  	defer cc.Close()
   470  	client := testgrpc.NewTestServiceClient(cc)
   471  
   472  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   473  	defer cancel()
   474  
   475  	// Verifying authorization decision.
   476  	if _, err = client.UnaryCall(ctx, &testpb.SimpleRequest{}); err != nil {
   477  		t.Fatalf("client.UnaryCall(_, _) = %v; want nil", err)
   478  	}
   479  }
   480  
   481  func (s) TestFileWatcherEnd2End(t *testing.T) {
   482  	for name, test := range authzTests {
   483  		t.Run(name, func(t *testing.T) {
   484  			file := createTmpPolicyFile(t, name, []byte(test.authzPolicy))
   485  			i, _ := authz.NewFileWatcher(file, 1*time.Second)
   486  			defer i.Close()
   487  
   488  			stub := &stubserver.StubServer{
   489  				UnaryCallF: func(ctx context.Context, req *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
   490  					return &testpb.SimpleResponse{}, nil
   491  				},
   492  				StreamingInputCallF: func(stream testgrpc.TestService_StreamingInputCallServer) error {
   493  					for {
   494  						_, err := stream.Recv()
   495  						if err == io.EOF {
   496  							return stream.SendAndClose(&testpb.StreamingInputCallResponse{})
   497  						}
   498  						if err != nil {
   499  							return err
   500  						}
   501  					}
   502  				},
   503  				// Start a gRPC server with gRPC authz unary and stream server interceptors.
   504  				S: grpc.NewServer(grpc.ChainUnaryInterceptor(i.UnaryInterceptor), grpc.ChainStreamInterceptor(i.StreamInterceptor)),
   505  			}
   506  			stubserver.StartTestService(t, stub)
   507  			defer stub.Stop()
   508  
   509  			// Establish a connection to the server.
   510  			cc, err := grpc.NewClient(stub.Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
   511  			if err != nil {
   512  				t.Fatalf("grpc.NewClient(%v) failed: %v", stub.Address, err)
   513  			}
   514  			defer cc.Close()
   515  			client := testgrpc.NewTestServiceClient(cc)
   516  
   517  			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   518  			defer cancel()
   519  			ctx = metadata.NewOutgoingContext(ctx, test.md)
   520  
   521  			// Verifying authorization decision for Unary RPC.
   522  			_, err = client.UnaryCall(ctx, &testpb.SimpleRequest{})
   523  			if got := status.Convert(err); got.Code() != test.wantStatus.Code() || got.Message() != test.wantStatus.Message() {
   524  				t.Fatalf("[UnaryCall] error want:{%v} got:{%v}", test.wantStatus.Err(), got.Err())
   525  			}
   526  
   527  			// Verifying authorization decision for Streaming RPC.
   528  			stream, err := client.StreamingInputCall(ctx)
   529  			if err != nil {
   530  				t.Fatalf("failed StreamingInputCall : %v", err)
   531  			}
   532  			req := &testpb.StreamingInputCallRequest{
   533  				Payload: &testpb.Payload{
   534  					Body: []byte("hi"),
   535  				},
   536  			}
   537  			if err := stream.Send(req); err != nil && err != io.EOF {
   538  				t.Fatalf("failed stream.Send : %v", err)
   539  			}
   540  			_, err = stream.CloseAndRecv()
   541  			if got := status.Convert(err); got.Code() != test.wantStatus.Code() || got.Message() != test.wantStatus.Message() {
   542  				t.Fatalf("[StreamingCall] error want:{%v} got:{%v}", test.wantStatus.Err(), got.Err())
   543  			}
   544  		})
   545  	}
   546  }
   547  
   548  func retryUntil(ctx context.Context, tsc testgrpc.TestServiceClient, want *status.Status) (lastErr error) {
   549  	for ctx.Err() == nil {
   550  		_, lastErr = tsc.UnaryCall(ctx, &testpb.SimpleRequest{})
   551  		if s := status.Convert(lastErr); s.Code() == want.Code() && s.Message() == want.Message() {
   552  			return nil
   553  		}
   554  		time.Sleep(20 * time.Millisecond)
   555  	}
   556  	return lastErr
   557  }
   558  
   559  func (s) TestFileWatcher_ValidPolicyRefresh(t *testing.T) {
   560  	valid1 := authzTests["DeniesRPCMatchInDenyAndAllow"]
   561  	file := createTmpPolicyFile(t, "valid_policy_refresh", []byte(valid1.authzPolicy))
   562  	i, _ := authz.NewFileWatcher(file, 100*time.Millisecond)
   563  	defer i.Close()
   564  
   565  	stub := &stubserver.StubServer{
   566  		UnaryCallF: func(ctx context.Context, req *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
   567  			return &testpb.SimpleResponse{}, nil
   568  		},
   569  		// Start a gRPC server with gRPC authz unary server interceptor.
   570  		S: grpc.NewServer(grpc.ChainUnaryInterceptor(i.UnaryInterceptor)),
   571  	}
   572  	stubserver.StartTestService(t, stub)
   573  	defer stub.Stop()
   574  
   575  	// Establish a connection to the server.
   576  	cc, err := grpc.NewClient(stub.Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
   577  	if err != nil {
   578  		t.Fatalf("grpc.NewClient(%v) failed: %v", stub.Address, err)
   579  	}
   580  	defer cc.Close()
   581  	client := testgrpc.NewTestServiceClient(cc)
   582  
   583  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   584  	defer cancel()
   585  
   586  	// Verifying authorization decision.
   587  	_, err = client.UnaryCall(ctx, &testpb.SimpleRequest{})
   588  	if got := status.Convert(err); got.Code() != valid1.wantStatus.Code() || got.Message() != valid1.wantStatus.Message() {
   589  		t.Fatalf("client.UnaryCall(_, _) = %v; want = %v", got.Err(), valid1.wantStatus.Err())
   590  	}
   591  
   592  	// Rewrite the file with a different valid authorization policy.
   593  	valid2 := authzTests["AllowsRPCEmptyDenyMatchInAllow"]
   594  	if err := os.WriteFile(file, []byte(valid2.authzPolicy), os.ModePerm); err != nil {
   595  		t.Fatalf("os.WriteFile(%q) failed: %v", file, err)
   596  	}
   597  
   598  	// Verifying authorization decision.
   599  	if got := retryUntil(ctx, client, valid2.wantStatus); got != nil {
   600  		t.Fatalf("client.UnaryCall(_, _) = %v; want = %v", got, valid2.wantStatus.Err())
   601  	}
   602  }
   603  
   604  func (s) TestFileWatcher_InvalidPolicySkipReload(t *testing.T) {
   605  	valid := authzTests["DeniesRPCMatchInDenyAndAllow"]
   606  	file := createTmpPolicyFile(t, "invalid_policy_skip_reload", []byte(valid.authzPolicy))
   607  	i, _ := authz.NewFileWatcher(file, 20*time.Millisecond)
   608  	defer i.Close()
   609  
   610  	stub := &stubserver.StubServer{
   611  		UnaryCallF: func(ctx context.Context, req *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
   612  			return &testpb.SimpleResponse{}, nil
   613  		},
   614  		// Start a gRPC server with gRPC authz unary server interceptors.
   615  		S: grpc.NewServer(grpc.ChainUnaryInterceptor(i.UnaryInterceptor)),
   616  	}
   617  	stubserver.StartTestService(t, stub)
   618  	defer stub.Stop()
   619  
   620  	// Establish a connection to the server.
   621  	cc, err := grpc.NewClient(stub.Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
   622  	if err != nil {
   623  		t.Fatalf("grpc.NewClient(%v) failed: %v", stub.Address, err)
   624  	}
   625  	defer cc.Close()
   626  	client := testgrpc.NewTestServiceClient(cc)
   627  
   628  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   629  	defer cancel()
   630  
   631  	// Verifying authorization decision.
   632  	_, err = client.UnaryCall(ctx, &testpb.SimpleRequest{})
   633  	if got := status.Convert(err); got.Code() != valid.wantStatus.Code() || got.Message() != valid.wantStatus.Message() {
   634  		t.Fatalf("client.UnaryCall(_, _) = %v; want = %v", got.Err(), valid.wantStatus.Err())
   635  	}
   636  
   637  	// Skips the invalid policy update, and continues to use the valid policy.
   638  	if err := os.WriteFile(file, []byte("{}"), os.ModePerm); err != nil {
   639  		t.Fatalf("os.WriteFile(%q) failed: %v", file, err)
   640  	}
   641  
   642  	// Wait 40 ms for background go routine to read updated files.
   643  	time.Sleep(40 * time.Millisecond)
   644  
   645  	// Verifying authorization decision.
   646  	_, err = client.UnaryCall(ctx, &testpb.SimpleRequest{})
   647  	if got := status.Convert(err); got.Code() != valid.wantStatus.Code() || got.Message() != valid.wantStatus.Message() {
   648  		t.Fatalf("client.UnaryCall(_, _) = %v; want = %v", got.Err(), valid.wantStatus.Err())
   649  	}
   650  }
   651  
   652  func (s) TestFileWatcher_RecoversFromReloadFailure(t *testing.T) {
   653  	valid1 := authzTests["DeniesRPCMatchInDenyAndAllow"]
   654  	file := createTmpPolicyFile(t, "recovers_from_reload_failure", []byte(valid1.authzPolicy))
   655  	i, _ := authz.NewFileWatcher(file, 100*time.Millisecond)
   656  	defer i.Close()
   657  
   658  	stub := &stubserver.StubServer{
   659  		UnaryCallF: func(ctx context.Context, req *testpb.SimpleRequest) (*testpb.SimpleResponse, error) {
   660  			return &testpb.SimpleResponse{}, nil
   661  		},
   662  		S: grpc.NewServer(grpc.ChainUnaryInterceptor(i.UnaryInterceptor)),
   663  	}
   664  	stubserver.StartTestService(t, stub)
   665  	defer stub.Stop()
   666  
   667  	// Establish a connection to the server.
   668  	cc, err := grpc.NewClient(stub.Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
   669  	if err != nil {
   670  		t.Fatalf("grpc.NewClient(%v) failed: %v", stub.Address, err)
   671  	}
   672  	defer cc.Close()
   673  	client := testgrpc.NewTestServiceClient(cc)
   674  
   675  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   676  	defer cancel()
   677  
   678  	// Verifying authorization decision.
   679  	_, err = client.UnaryCall(ctx, &testpb.SimpleRequest{})
   680  	if got := status.Convert(err); got.Code() != valid1.wantStatus.Code() || got.Message() != valid1.wantStatus.Message() {
   681  		t.Fatalf("client.UnaryCall(_, _) = %v; want = %v", got.Err(), valid1.wantStatus.Err())
   682  	}
   683  
   684  	// Skips the invalid policy update, and continues to use the valid policy.
   685  	if err := os.WriteFile(file, []byte("{}"), os.ModePerm); err != nil {
   686  		t.Fatalf("os.WriteFile(%q) failed: %v", file, err)
   687  	}
   688  
   689  	// Wait 120 ms for background go routine to read updated files.
   690  	time.Sleep(120 * time.Millisecond)
   691  
   692  	// Verifying authorization decision.
   693  	_, err = client.UnaryCall(ctx, &testpb.SimpleRequest{})
   694  	if got := status.Convert(err); got.Code() != valid1.wantStatus.Code() || got.Message() != valid1.wantStatus.Message() {
   695  		t.Fatalf("client.UnaryCall(_, _) = %v; want = %v", got.Err(), valid1.wantStatus.Err())
   696  	}
   697  
   698  	// Rewrite the file with a different valid authorization policy.
   699  	valid2 := authzTests["AllowsRPCEmptyDenyMatchInAllow"]
   700  	if err := os.WriteFile(file, []byte(valid2.authzPolicy), os.ModePerm); err != nil {
   701  		t.Fatalf("os.WriteFile(%q) failed: %v", file, err)
   702  	}
   703  
   704  	// Verifying authorization decision.
   705  	if got := retryUntil(ctx, client, valid2.wantStatus); got != nil {
   706  		t.Fatalf("client.UnaryCall(_, _) = %v; want = %v", got, valid2.wantStatus.Err())
   707  	}
   708  }