Repository: grpc/grpc-go
File: credentials/credentials_ext_test.go (Go)

Code before:
			}
			return &testpb.Empty{}, nil
		},
	}
	if err := ss.Start(nil); err != nil {
		t.Fatalf("Error starting endpoint server: %v", err)
	}
	defer ss.Stop()

	cc, err := grpc.NewClient(ss.Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		t.Fatalf("grpc.NewClient(%q) = %v", ss.Address, err)
	}
	defer cc.Close()

	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
	defer cancel()
	if _, err = testgrpc.NewTestServiceClient(cc).EmptyCall(ctx, &testpb.Empty{}, grpc.CallAuthority(authority)); err != nil {
		t.Fatalf("EmptyCall() rpc failed: %v", err)
	}
}

// Tests the scenario where the `grpc.CallAuthority` call option is used with
// local transport credentials. The test verifies that the specified
// authority is correctly propagated to the server.
func (s) TestAuthorityCallOptionWithLocalCreds(t *testing.T) {
	const authority = "test.server.name"

	ss := &stubserver.StubServer{
		EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
			if err := authorityChecker(ctx, authority); err != nil {
				return nil, err
			}
			return &testpb.Empty{}, nil
		},
	}
	if err := ss.Start(nil); err != nil {
		t.Fatalf("Error starting endpoint server: %v", err)
	}
	defer ss.Stop()

	cc, err := grpc.NewClient(ss.Address, grpc.WithTransportCredentials(local.NewCredentials()))
	if err != nil {
		t.Fatalf("grpc.NewClient(%q) = %v", ss.Address, err)
	}
	defer cc.Close()

	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
	defer cancel()
	if _, err = testgrpc.NewTestServiceClient(cc).EmptyCall(ctx, &testpb.Empty{}, grpc.CallAuthority(authority)); err != nil {
		t.Fatalf("EmptyCall() rpc failed: %v", err)

Review comment (security):
Looking at this test *now*, it feels like there is some scope for making a table driven test for cases where the credentials is expected to accept the authority override, and the RPC is expected to succeed.

The table will have three entries: one for TLS, one for insecure and one for local. The table would also have fields for server and client credentials. 

And if you make a helper function that reads the server cert+key pair and the CA cert, and returns two `credentials.TransportCredentials`, one for the server and one for the client, you can populate the those two fields in the table (for the TLS case). For the other two cases, it would just be `insecure.NewCredentials` and `local.NewCredentials`.

Code after:

	serverCalled := make(chan struct{})
	ss := &stubserver.StubServer{
		EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
			close(serverCalled)
			return nil, nil
		},
	}
	if err := ss.StartServer(grpc.Creds(credentials.NewServerTLSFromCert(&cert))); err != nil {
		t.Fatalf("Error starting endpoint server: %v", err)
	}
	defer ss.Stop()

	cc, err := grpc.NewClient(ss.Address, grpc.WithTransportCredentials(creds))
	if err != nil {
		t.Fatalf("grpc.NewClient(%q) = %v", ss.Address, err)
	}
	defer cc.Close()

	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
	defer cancel()

	const authority = "auth.example.com"
	if _, err = testgrpc.NewTestServiceClient(cc).EmptyCall(ctx, &testpb.Empty{}, grpc.CallAuthority(authority)); status.Code(err) != codes.Unavailable {
		t.Fatalf("EmptyCall() returned status %v, want %v", status.Code(err), codes.Unavailable)
	}
	select {
	case <-serverCalled:
		t.Fatalf("Server handler should not have been called")
	case <-time.After(defaultTestShortTimeout):
	}
}

// testAuthInfoNoValidator implements only credentials.AuthInfo and not
// credentials.AuthorityValidator.
type testAuthInfoNoValidator struct{}

// AuthType returns the authentication type.
func (testAuthInfoNoValidator) AuthType() string {
	return "test"
}

// testAuthInfoWithValidator implements both credentials.AuthInfo and
// credentials.AuthorityValidator.
type testAuthInfoWithValidator struct {
	validAuthority string
}

// AuthType returns the authentication type.
func (testAuthInfoWithValidator) AuthType() string {
	return "test"