gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/test/creds_test.go (about) 1 /* 2 * 3 * Copyright 2018 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 "errors" 24 "fmt" 25 "net" 26 "strings" 27 "testing" 28 "time" 29 30 grpc "gitee.com/ks-custle/core-gm/grpc" 31 "gitee.com/ks-custle/core-gm/grpc/codes" 32 "gitee.com/ks-custle/core-gm/grpc/connectivity" 33 "gitee.com/ks-custle/core-gm/grpc/credentials" 34 "gitee.com/ks-custle/core-gm/grpc/credentials/insecure" 35 "gitee.com/ks-custle/core-gm/grpc/metadata" 36 "gitee.com/ks-custle/core-gm/grpc/resolver" 37 "gitee.com/ks-custle/core-gm/grpc/resolver/manual" 38 "gitee.com/ks-custle/core-gm/grpc/status" 39 "gitee.com/ks-custle/core-gm/grpc/tap" 40 testpb "gitee.com/ks-custle/core-gm/grpc/test/grpc_testing" 41 "gitee.com/ks-custle/core-gm/grpc/testdata" 42 ) 43 44 const ( 45 bundlePerRPCOnly = "perRPCOnly" 46 bundleTLSOnly = "tlsOnly" 47 ) 48 49 type testCredsBundle struct { 50 t *testing.T 51 mode string 52 } 53 54 func (c *testCredsBundle) TransportCredentials() credentials.TransportCredentials { 55 if c.mode == bundlePerRPCOnly { 56 return insecure.NewCredentials() 57 } 58 59 creds, err := credentials.NewClientTLSFromFile(testdata.Path("x509/server_ca_cert.pem"), "x.test.example.com") 60 if err != nil { 61 c.t.Logf("Failed to load credentials: %v", err) 62 return nil 63 } 64 return creds 65 } 66 67 func (c *testCredsBundle) PerRPCCredentials() credentials.PerRPCCredentials { 68 if c.mode == bundleTLSOnly { 69 return nil 70 } 71 return testPerRPCCredentials{} 72 } 73 74 func (c *testCredsBundle) NewWithMode(mode string) (credentials.Bundle, error) { 75 return &testCredsBundle{mode: mode}, nil 76 } 77 78 func (s) TestCredsBundleBoth(t *testing.T) { 79 te := newTest(t, env{name: "creds-bundle", network: "tcp", security: "empty"}) 80 te.tapHandle = authHandle 81 te.customDialOptions = []grpc.DialOption{ 82 grpc.WithCredentialsBundle(&testCredsBundle{t: t}), 83 } 84 creds, err := credentials.NewServerTLSFromFile(testdata.Path("x509/server1_cert.pem"), testdata.Path("x509/server1_key.pem")) 85 if err != nil { 86 t.Fatalf("Failed to generate credentials %v", err) 87 } 88 te.customServerOptions = []grpc.ServerOption{ 89 grpc.Creds(creds), 90 } 91 te.startServer(&testServer{}) 92 defer te.tearDown() 93 94 cc := te.clientConn() 95 tc := testpb.NewTestServiceClient(cc) 96 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 97 defer cancel() 98 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil { 99 t.Fatalf("Test failed. Reason: %v", err) 100 } 101 } 102 103 func (s) TestCredsBundleTransportCredentials(t *testing.T) { 104 te := newTest(t, env{name: "creds-bundle", network: "tcp", security: "empty"}) 105 te.customDialOptions = []grpc.DialOption{ 106 grpc.WithCredentialsBundle(&testCredsBundle{t: t, mode: bundleTLSOnly}), 107 } 108 creds, err := credentials.NewServerTLSFromFile(testdata.Path("x509/server1_cert.pem"), testdata.Path("x509/server1_key.pem")) 109 if err != nil { 110 t.Fatalf("Failed to generate credentials %v", err) 111 } 112 te.customServerOptions = []grpc.ServerOption{ 113 grpc.Creds(creds), 114 } 115 te.startServer(&testServer{}) 116 defer te.tearDown() 117 118 cc := te.clientConn() 119 tc := testpb.NewTestServiceClient(cc) 120 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 121 defer cancel() 122 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil { 123 t.Fatalf("Test failed. Reason: %v", err) 124 } 125 } 126 127 func (s) TestCredsBundlePerRPCCredentials(t *testing.T) { 128 te := newTest(t, env{name: "creds-bundle", network: "tcp", security: "empty"}) 129 te.tapHandle = authHandle 130 te.customDialOptions = []grpc.DialOption{ 131 grpc.WithCredentialsBundle(&testCredsBundle{t: t, mode: bundlePerRPCOnly}), 132 } 133 te.startServer(&testServer{}) 134 defer te.tearDown() 135 136 cc := te.clientConn() 137 tc := testpb.NewTestServiceClient(cc) 138 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 139 defer cancel() 140 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil { 141 t.Fatalf("Test failed. Reason: %v", err) 142 } 143 } 144 145 type clientTimeoutCreds struct { 146 credentials.TransportCredentials 147 timeoutReturned bool 148 } 149 150 func (c *clientTimeoutCreds) ClientHandshake(ctx context.Context, addr string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { 151 if !c.timeoutReturned { 152 c.timeoutReturned = true 153 return nil, nil, context.DeadlineExceeded 154 } 155 return rawConn, nil, nil 156 } 157 158 func (c *clientTimeoutCreds) Info() credentials.ProtocolInfo { 159 return credentials.ProtocolInfo{} 160 } 161 162 func (c *clientTimeoutCreds) Clone() credentials.TransportCredentials { 163 return nil 164 } 165 166 func (s) TestNonFailFastRPCSucceedOnTimeoutCreds(t *testing.T) { 167 te := newTest(t, env{name: "timeout-cred", network: "tcp", security: "empty"}) 168 te.userAgent = testAppUA 169 te.startServer(&testServer{security: te.e.security}) 170 defer te.tearDown() 171 172 cc := te.clientConn(grpc.WithTransportCredentials(&clientTimeoutCreds{})) 173 tc := testpb.NewTestServiceClient(cc) 174 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 175 defer cancel() 176 // This unary call should succeed, because ClientHandshake will succeed for the second time. 177 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); err != nil { 178 te.t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want <nil>", err) 179 } 180 } 181 182 type methodTestCreds struct{} 183 184 func (m *methodTestCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { 185 ri, _ := credentials.RequestInfoFromContext(ctx) 186 return nil, status.Errorf(codes.Unknown, ri.Method) 187 } 188 189 func (m *methodTestCreds) RequireTransportSecurity() bool { return false } 190 191 func (s) TestGRPCMethodAccessibleToCredsViaContextRequestInfo(t *testing.T) { 192 const wantMethod = "/grpc.testing.TestService/EmptyCall" 193 te := newTest(t, env{name: "context-request-info", network: "tcp"}) 194 te.userAgent = testAppUA 195 te.startServer(&testServer{security: te.e.security}) 196 defer te.tearDown() 197 198 cc := te.clientConn(grpc.WithPerRPCCredentials(&methodTestCreds{})) 199 tc := testpb.NewTestServiceClient(cc) 200 201 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) 202 defer cancel() 203 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); status.Convert(err).Message() != wantMethod { 204 t.Fatalf("ss.client.EmptyCall(_, _) = _, %v; want _, _.Message()=%q", err, wantMethod) 205 } 206 207 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); status.Convert(err).Message() != wantMethod { 208 t.Fatalf("ss.client.EmptyCall(_, _) = _, %v; want _, _.Message()=%q", err, wantMethod) 209 } 210 } 211 212 const clientAlwaysFailCredErrorMsg = "clientAlwaysFailCred always fails" 213 214 type clientAlwaysFailCred struct { 215 credentials.TransportCredentials 216 } 217 218 func (c clientAlwaysFailCred) ClientHandshake(ctx context.Context, addr string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { 219 return nil, nil, errors.New(clientAlwaysFailCredErrorMsg) 220 } 221 func (c clientAlwaysFailCred) Info() credentials.ProtocolInfo { 222 return credentials.ProtocolInfo{} 223 } 224 func (c clientAlwaysFailCred) Clone() credentials.TransportCredentials { 225 return nil 226 } 227 228 func (s) TestFailFastRPCErrorOnBadCertificates(t *testing.T) { 229 te := newTest(t, env{name: "bad-cred", network: "tcp", security: "empty", balancer: "round_robin"}) 230 te.startServer(&testServer{security: te.e.security}) 231 defer te.tearDown() 232 233 opts := []grpc.DialOption{grpc.WithTransportCredentials(clientAlwaysFailCred{})} 234 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 235 defer cancel() 236 cc, err := grpc.DialContext(ctx, te.srvAddr, opts...) 237 if err != nil { 238 t.Fatalf("Dial(_) = %v, want %v", err, nil) 239 } 240 defer cc.Close() 241 242 tc := testpb.NewTestServiceClient(cc) 243 for i := 0; i < 1000; i++ { 244 // This loop runs for at most 1 second. The first several RPCs will fail 245 // with Unavailable because the connection hasn't started. When the 246 // first connection failed with creds error, the next RPC should also 247 // fail with the expected error. 248 if _, err = tc.EmptyCall(ctx, &testpb.Empty{}); strings.Contains(err.Error(), clientAlwaysFailCredErrorMsg) { 249 return 250 } 251 time.Sleep(time.Millisecond) 252 } 253 te.t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want err.Error() contains %q", err, clientAlwaysFailCredErrorMsg) 254 } 255 256 func (s) TestWaitForReadyRPCErrorOnBadCertificates(t *testing.T) { 257 te := newTest(t, env{name: "bad-cred", network: "tcp", security: "empty", balancer: "round_robin"}) 258 te.startServer(&testServer{security: te.e.security}) 259 defer te.tearDown() 260 261 opts := []grpc.DialOption{grpc.WithTransportCredentials(clientAlwaysFailCred{})} 262 dctx, dcancel := context.WithTimeout(context.Background(), 10*time.Second) 263 defer dcancel() 264 cc, err := grpc.DialContext(dctx, te.srvAddr, opts...) 265 if err != nil { 266 t.Fatalf("Dial(_) = %v, want %v", err, nil) 267 } 268 defer cc.Close() 269 270 tc := testpb.NewTestServiceClient(cc) 271 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) 272 defer cancel() 273 if _, err = tc.EmptyCall(ctx, &testpb.Empty{}, grpc.WaitForReady(true)); strings.Contains(err.Error(), clientAlwaysFailCredErrorMsg) { 274 return 275 } 276 te.t.Fatalf("TestService/EmptyCall(_, _) = _, %v, want err.Error() contains %q", err, clientAlwaysFailCredErrorMsg) 277 } 278 279 var ( 280 // test authdata 281 authdata = map[string]string{ 282 "test-key": "test-value", 283 "test-key2-bin": string([]byte{1, 2, 3}), 284 } 285 ) 286 287 type testPerRPCCredentials struct{} 288 289 func (cr testPerRPCCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { 290 return authdata, nil 291 } 292 293 func (cr testPerRPCCredentials) RequireTransportSecurity() bool { 294 return false 295 } 296 297 func authHandle(ctx context.Context, info *tap.Info) (context.Context, error) { 298 md, ok := metadata.FromIncomingContext(ctx) 299 if !ok { 300 return ctx, fmt.Errorf("didn't find metadata in context") 301 } 302 for k, vwant := range authdata { 303 vgot, ok := md[k] 304 if !ok { 305 return ctx, fmt.Errorf("didn't find authdata key %v in context", k) 306 } 307 if vgot[0] != vwant { 308 return ctx, fmt.Errorf("for key %v, got value %v, want %v", k, vgot, vwant) 309 } 310 } 311 return ctx, nil 312 } 313 314 func (s) TestPerRPCCredentialsViaDialOptions(t *testing.T) { 315 for _, e := range listTestEnv() { 316 testPerRPCCredentialsViaDialOptions(t, e) 317 } 318 } 319 320 func testPerRPCCredentialsViaDialOptions(t *testing.T, e env) { 321 te := newTest(t, e) 322 te.tapHandle = authHandle 323 te.perRPCCreds = testPerRPCCredentials{} 324 te.startServer(&testServer{security: e.security}) 325 defer te.tearDown() 326 327 cc := te.clientConn() 328 tc := testpb.NewTestServiceClient(cc) 329 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 330 defer cancel() 331 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}); err != nil { 332 t.Fatalf("Test failed. Reason: %v", err) 333 } 334 } 335 336 func (s) TestPerRPCCredentialsViaCallOptions(t *testing.T) { 337 for _, e := range listTestEnv() { 338 testPerRPCCredentialsViaCallOptions(t, e) 339 } 340 } 341 342 func testPerRPCCredentialsViaCallOptions(t *testing.T, e env) { 343 te := newTest(t, e) 344 te.tapHandle = authHandle 345 te.startServer(&testServer{security: e.security}) 346 defer te.tearDown() 347 348 cc := te.clientConn() 349 tc := testpb.NewTestServiceClient(cc) 350 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 351 defer cancel() 352 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.PerRPCCredentials(testPerRPCCredentials{})); err != nil { 353 t.Fatalf("Test failed. Reason: %v", err) 354 } 355 } 356 357 func (s) TestPerRPCCredentialsViaDialOptionsAndCallOptions(t *testing.T) { 358 for _, e := range listTestEnv() { 359 testPerRPCCredentialsViaDialOptionsAndCallOptions(t, e) 360 } 361 } 362 363 func testPerRPCCredentialsViaDialOptionsAndCallOptions(t *testing.T, e env) { 364 te := newTest(t, e) 365 te.perRPCCreds = testPerRPCCredentials{} 366 // When credentials are provided via both dial options and call options, 367 // we apply both sets. 368 te.tapHandle = func(ctx context.Context, _ *tap.Info) (context.Context, error) { 369 md, ok := metadata.FromIncomingContext(ctx) 370 if !ok { 371 return ctx, fmt.Errorf("couldn't find metadata in context") 372 } 373 for k, vwant := range authdata { 374 vgot, ok := md[k] 375 if !ok { 376 return ctx, fmt.Errorf("couldn't find metadata for key %v", k) 377 } 378 if len(vgot) != 2 { 379 return ctx, fmt.Errorf("len of value for key %v was %v, want 2", k, len(vgot)) 380 } 381 if vgot[0] != vwant || vgot[1] != vwant { 382 return ctx, fmt.Errorf("value for %v was %v, want [%v, %v]", k, vgot, vwant, vwant) 383 } 384 } 385 return ctx, nil 386 } 387 te.startServer(&testServer{security: e.security}) 388 defer te.tearDown() 389 390 cc := te.clientConn() 391 tc := testpb.NewTestServiceClient(cc) 392 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 393 defer cancel() 394 if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.PerRPCCredentials(testPerRPCCredentials{})); err != nil { 395 t.Fatalf("Test failed. Reason: %v", err) 396 } 397 } 398 399 const testAuthority = "test.auth.ori.ty" 400 401 type authorityCheckCreds struct { 402 credentials.TransportCredentials 403 got string 404 } 405 406 func (c *authorityCheckCreds) ClientHandshake(ctx context.Context, authority string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { 407 c.got = authority 408 return rawConn, nil, nil 409 } 410 func (c *authorityCheckCreds) Info() credentials.ProtocolInfo { 411 return credentials.ProtocolInfo{} 412 } 413 func (c *authorityCheckCreds) Clone() credentials.TransportCredentials { 414 return c 415 } 416 417 // This test makes sure that the authority client handshake gets is the endpoint 418 // in dial target, not the resolved ip address. 419 func (s) TestCredsHandshakeAuthority(t *testing.T) { 420 lis, err := net.Listen("tcp", "localhost:0") 421 if err != nil { 422 t.Fatal(err) 423 } 424 cred := &authorityCheckCreds{} 425 s := grpc.NewServer() 426 go s.Serve(lis) 427 defer s.Stop() 428 429 r := manual.NewBuilderWithScheme("whatever") 430 431 cc, err := grpc.Dial(r.Scheme()+":///"+testAuthority, grpc.WithTransportCredentials(cred), grpc.WithResolvers(r)) 432 if err != nil { 433 t.Fatalf("grpc.Dial(%q) = %v", lis.Addr().String(), err) 434 } 435 defer cc.Close() 436 r.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: lis.Addr().String()}}}) 437 438 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 439 defer cancel() 440 for { 441 s := cc.GetState() 442 if s == connectivity.Ready { 443 break 444 } 445 if !cc.WaitForStateChange(ctx, s) { 446 t.Fatalf("ClientConn is not ready after 100 ms") 447 } 448 } 449 450 if cred.got != testAuthority { 451 t.Fatalf("client creds got authority: %q, want: %q", cred.got, testAuthority) 452 } 453 } 454 455 // This test makes sure that the authority client handshake gets is the endpoint 456 // of the ServerName of the address when it is set. 457 func (s) TestCredsHandshakeServerNameAuthority(t *testing.T) { 458 const testServerName = "test.server.name" 459 460 lis, err := net.Listen("tcp", "localhost:0") 461 if err != nil { 462 t.Fatal(err) 463 } 464 cred := &authorityCheckCreds{} 465 s := grpc.NewServer() 466 go s.Serve(lis) 467 defer s.Stop() 468 469 r := manual.NewBuilderWithScheme("whatever") 470 471 cc, err := grpc.Dial(r.Scheme()+":///"+testAuthority, grpc.WithTransportCredentials(cred), grpc.WithResolvers(r)) 472 if err != nil { 473 t.Fatalf("grpc.Dial(%q) = %v", lis.Addr().String(), err) 474 } 475 defer cc.Close() 476 r.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: lis.Addr().String(), ServerName: testServerName}}}) 477 478 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 479 defer cancel() 480 for { 481 s := cc.GetState() 482 if s == connectivity.Ready { 483 break 484 } 485 if !cc.WaitForStateChange(ctx, s) { 486 t.Fatalf("ClientConn is not ready after 100 ms") 487 } 488 } 489 490 if cred.got != testServerName { 491 t.Fatalf("client creds got authority: %q, want: %q", cred.got, testAuthority) 492 } 493 } 494 495 type serverDispatchCred struct { 496 rawConnCh chan net.Conn 497 } 498 499 func (c *serverDispatchCred) ClientHandshake(ctx context.Context, addr string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { 500 return rawConn, nil, nil 501 } 502 func (c *serverDispatchCred) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) { 503 select { 504 case c.rawConnCh <- rawConn: 505 default: 506 } 507 return nil, nil, credentials.ErrConnDispatched 508 } 509 func (c *serverDispatchCred) Info() credentials.ProtocolInfo { 510 return credentials.ProtocolInfo{} 511 } 512 func (c *serverDispatchCred) Clone() credentials.TransportCredentials { 513 return nil 514 } 515 func (c *serverDispatchCred) OverrideServerName(s string) error { 516 return nil 517 } 518 func (c *serverDispatchCred) getRawConn() net.Conn { 519 return <-c.rawConnCh 520 } 521 522 func (s) TestServerCredsDispatch(t *testing.T) { 523 lis, err := net.Listen("tcp", "localhost:0") 524 if err != nil { 525 t.Fatal(err) 526 } 527 cred := &serverDispatchCred{ 528 rawConnCh: make(chan net.Conn, 1), 529 } 530 s := grpc.NewServer(grpc.Creds(cred)) 531 go s.Serve(lis) 532 defer s.Stop() 533 534 cc, err := grpc.Dial(lis.Addr().String(), grpc.WithTransportCredentials(cred)) 535 if err != nil { 536 t.Fatalf("grpc.Dial(%q) = %v", lis.Addr().String(), err) 537 } 538 defer cc.Close() 539 540 rawConn := cred.getRawConn() 541 // Give grpc a chance to see the error and potentially close the connection. 542 // And check that connection is not closed after that. 543 time.Sleep(100 * time.Millisecond) 544 // Check rawConn is not closed. 545 if n, err := rawConn.Write([]byte{0}); n <= 0 || err != nil { 546 t.Errorf("Read() = %v, %v; want n>0, <nil>", n, err) 547 } 548 }