google.golang.org/grpc@v1.72.2/test/insecure_creds_test.go (about)

     1  /*
     2   *
     3   * Copyright 2020 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 test
    20  
    21  import (
    22  	"context"
    23  	"strings"
    24  	"testing"
    25  
    26  	"google.golang.org/grpc"
    27  	"google.golang.org/grpc/codes"
    28  	"google.golang.org/grpc/credentials"
    29  	"google.golang.org/grpc/credentials/insecure"
    30  	"google.golang.org/grpc/internal/stubserver"
    31  	"google.golang.org/grpc/internal/testutils"
    32  	"google.golang.org/grpc/peer"
    33  	"google.golang.org/grpc/status"
    34  
    35  	testgrpc "google.golang.org/grpc/interop/grpc_testing"
    36  	testpb "google.golang.org/grpc/interop/grpc_testing"
    37  )
    38  
    39  // testLegacyPerRPCCredentials is a PerRPCCredentials that has yet incorporated security level.
    40  type testLegacyPerRPCCredentials struct{}
    41  
    42  func (cr testLegacyPerRPCCredentials) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {
    43  	return nil, nil
    44  }
    45  
    46  func (cr testLegacyPerRPCCredentials) RequireTransportSecurity() bool {
    47  	return true
    48  }
    49  
    50  func getSecurityLevel(ai credentials.AuthInfo) credentials.SecurityLevel {
    51  	if c, ok := ai.(interface {
    52  		GetCommonAuthInfo() credentials.CommonAuthInfo
    53  	}); ok {
    54  		return c.GetCommonAuthInfo().SecurityLevel
    55  	}
    56  	return credentials.InvalidSecurityLevel
    57  }
    58  
    59  // TestInsecureCreds tests the use of insecure creds on the server and client
    60  // side, and verifies that expect security level and auth info are returned.
    61  // Also verifies that this credential can interop with existing `WithInsecure`
    62  // DialOption.
    63  func (s) TestInsecureCreds(t *testing.T) {
    64  	tests := []struct {
    65  		desc                string
    66  		clientInsecureCreds bool
    67  		serverInsecureCreds bool
    68  	}{
    69  		{
    70  			desc:                "client and server insecure creds",
    71  			clientInsecureCreds: true,
    72  			serverInsecureCreds: true,
    73  		},
    74  		{
    75  			desc:                "client only insecure creds",
    76  			clientInsecureCreds: true,
    77  		},
    78  		{
    79  			desc:                "server only insecure creds",
    80  			serverInsecureCreds: true,
    81  		},
    82  	}
    83  
    84  	for _, test := range tests {
    85  		t.Run(test.desc, func(t *testing.T) {
    86  			lis, err := testutils.LocalTCPListener()
    87  			if err != nil {
    88  				t.Fatalf("net.Listen(tcp, localhost:0) failed: %v", err)
    89  			}
    90  
    91  			ss := &stubserver.StubServer{
    92  				Listener: lis,
    93  				EmptyCallF: func(ctx context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
    94  					if !test.serverInsecureCreds {
    95  						return &testpb.Empty{}, nil
    96  					}
    97  
    98  					pr, ok := peer.FromContext(ctx)
    99  					if !ok {
   100  						return nil, status.Error(codes.DataLoss, "Failed to get peer from ctx")
   101  					}
   102  					// Check security level.
   103  					secLevel := getSecurityLevel(pr.AuthInfo)
   104  					if secLevel == credentials.InvalidSecurityLevel {
   105  						return nil, status.Errorf(codes.Unauthenticated, "peer.AuthInfo does not implement GetCommonAuthInfo()")
   106  					}
   107  					if secLevel != credentials.NoSecurity {
   108  						return nil, status.Errorf(codes.Unauthenticated, "Wrong security level: got %q, want %q", secLevel, credentials.NoSecurity)
   109  					}
   110  					return &testpb.Empty{}, nil
   111  				},
   112  			}
   113  			sOpts := []grpc.ServerOption{}
   114  			if test.serverInsecureCreds {
   115  				ss.S = grpc.NewServer(grpc.Creds(insecure.NewCredentials()))
   116  			} else {
   117  				ss.S = grpc.NewServer(sOpts...)
   118  			}
   119  			stubserver.StartTestService(t, ss)
   120  			defer ss.S.Stop()
   121  			addr := lis.Addr().String()
   122  			opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
   123  			cc, err := grpc.NewClient(addr, opts...)
   124  			if err != nil {
   125  				t.Fatalf("grpc.NewClient(%q) failed: %v", addr, err)
   126  			}
   127  			defer cc.Close()
   128  
   129  			c := testgrpc.NewTestServiceClient(cc)
   130  			ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   131  			defer cancel()
   132  			if _, err = c.EmptyCall(ctx, &testpb.Empty{}); err != nil {
   133  				t.Fatalf("EmptyCall(_, _) = _, %v; want _, <nil>", err)
   134  			}
   135  		})
   136  	}
   137  }
   138  
   139  func (s) TestInsecureCreds_WithPerRPCCredentials_AsCallOption(t *testing.T) {
   140  	lis, err := testutils.LocalTCPListener()
   141  	if err != nil {
   142  		t.Fatalf("net.Listen(tcp, localhost:0) failed: %v", err)
   143  	}
   144  
   145  	ss := &stubserver.StubServer{
   146  		Listener: lis,
   147  		EmptyCallF: func(context.Context, *testpb.Empty) (*testpb.Empty, error) {
   148  			return &testpb.Empty{}, nil
   149  		},
   150  		S: grpc.NewServer(grpc.Creds(insecure.NewCredentials())),
   151  	}
   152  	stubserver.StartTestService(t, ss)
   153  	defer ss.S.Stop()
   154  
   155  	addr := lis.Addr().String()
   156  	ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
   157  	defer cancel()
   158  
   159  	dopts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
   160  	copts := []grpc.CallOption{grpc.PerRPCCredentials(testLegacyPerRPCCredentials{})}
   161  	cc, err := grpc.NewClient(addr, dopts...)
   162  	if err != nil {
   163  		t.Fatalf("grpc.NewClient(%q) failed: %v", addr, err)
   164  	}
   165  	defer cc.Close()
   166  
   167  	const wantErr = "transport: cannot send secure credentials on an insecure connection"
   168  	c := testgrpc.NewTestServiceClient(cc)
   169  	if _, err = c.EmptyCall(ctx, &testpb.Empty{}, copts...); err == nil || !strings.Contains(err.Error(), wantErr) {
   170  		t.Fatalf("insecure credentials with per-RPC credentials requiring transport security returned error: %v; want %s", err, wantErr)
   171  	}
   172  }
   173  
   174  func (s) TestInsecureCreds_WithPerRPCCredentials_AsDialOption(t *testing.T) {
   175  	lis, err := testutils.LocalTCPListener()
   176  	if err != nil {
   177  		t.Fatalf("net.Listen(tcp, localhost:0) failed: %v", err)
   178  	}
   179  	ss := &stubserver.StubServer{
   180  		Listener: lis,
   181  		EmptyCallF: func(_ context.Context, _ *testpb.Empty) (*testpb.Empty, error) {
   182  			return &testpb.Empty{}, nil
   183  		},
   184  		S: grpc.NewServer(grpc.Creds(insecure.NewCredentials())),
   185  	}
   186  	stubserver.StartTestService(t, ss)
   187  	defer ss.S.Stop()
   188  
   189  	addr := lis.Addr().String()
   190  	dopts := []grpc.DialOption{
   191  		grpc.WithTransportCredentials(insecure.NewCredentials()),
   192  		grpc.WithPerRPCCredentials(testLegacyPerRPCCredentials{}),
   193  	}
   194  	const wantErr = "the credentials require transport level security"
   195  	if _, err := grpc.NewClient(addr, dopts...); err == nil || !strings.Contains(err.Error(), wantErr) {
   196  		t.Fatalf("grpc.NewClient(%q) returned err %v, want: %v", addr, err, wantErr)
   197  	}
   198  }