@@ -20,6 +20,7 @@ package test
20
20
21
21
import (
22
22
"context"
23
+ "encoding/base64"
23
24
"fmt"
24
25
"net"
25
26
"net/http"
@@ -568,3 +569,98 @@ func (s) TestGrpcNewClientWithContextDialer(t *testing.T) {
568
569
default :
569
570
}
570
571
}
572
+
573
+ // TestBasicAuthInGrpcNewClientWithProxy tests grpc.NewClient with default i.e
574
+ // DNS resolver for targetURI and a proxy and verifies that it connects to proxy
575
+ // server and sends unresolved target URI in the HTTP CONNECT req and connects
576
+ // to backend. Also verifies that correct user info is sent in the CONNECT.
577
+ func (s ) TestBasicAuthInGrpcNewClientWithProxy (t * testing.T ) {
578
+ // Set up a channel to receive signals from OnClientResolution.
579
+ resolutionCh := make (chan bool , 1 )
580
+
581
+ // Overwrite OnClientResolution to send a signal to the channel.
582
+ origOnClientResolution := delegatingresolver .OnClientResolution
583
+ delegatingresolver .OnClientResolution = func (int ) {
584
+ resolutionCh <- true
585
+ }
586
+ t .Cleanup (func () { delegatingresolver .OnClientResolution = origOnClientResolution })
587
+
588
+ // Create and start a backend server.
589
+ backendAddr := createAndStartBackendServer (t )
590
+ const (
591
+ user = "notAUser"
592
+ password = "notAPassword"
593
+ )
594
+ // Set up and start the proxy server.
595
+ proxyLis , errCh , doneCh , _ := setupProxy (t , backendAddr , false , func (req * http.Request ) error {
596
+ if req .Method != http .MethodConnect {
597
+ return fmt .Errorf ("unexpected Method %q, want %q" , req .Method , http .MethodConnect )
598
+ }
599
+ if req .URL .Host != unresolvedTargetURI {
600
+ return fmt .Errorf ("unexpected URL.Host %q, want %q" , req .URL .Host , unresolvedTargetURI )
601
+ }
602
+ wantProxyAuthStr := "Basic " + base64 .StdEncoding .EncodeToString ([]byte (user + ":" + password ))
603
+ if got := req .Header .Get ("Proxy-Authorization" ); got != wantProxyAuthStr {
604
+ gotDecoded , _ := base64 .StdEncoding .DecodeString (got )
605
+ wantDecoded , _ := base64 .StdEncoding .DecodeString (wantProxyAuthStr )
606
+ return fmt .Errorf ("unexpected auth %q (%q), want %q (%q)" , got , gotDecoded , wantProxyAuthStr , wantDecoded )
607
+ }
608
+ return nil
609
+ })
610
+
611
+ // Overwrite the proxy resolution function and restore it afterward.
612
+ hpfe := func (req * http.Request ) (* url.URL , error ) {
613
+ if req .URL .Host == unresolvedTargetURI {
614
+ u := url.URL {
615
+ Scheme : "https" ,
616
+ Host : unresolvedProxyURI ,
617
+ }
618
+ u .User = url .UserPassword (user , password )
619
+ return & u , nil
620
+ }
621
+ return nil , nil
622
+ }
623
+ defer overwriteAndRestore (hpfe )()
624
+
625
+ // Set up a manual resolver for proxy resolution.
626
+ mrProxy := setupDNS (t )
627
+
628
+ // Update the proxy resolver state with the proxy's address.
629
+ mrProxy .InitialState (resolver.State {
630
+ Addresses : []resolver.Address {
631
+ {Addr : proxyLis .Addr ().String ()},
632
+ },
633
+ })
634
+
635
+ // Dial to the proxy server.
636
+ ctx , cancel := context .WithTimeout (context .Background (), defaultTestTimeout )
637
+ defer cancel ()
638
+
639
+ conn , err := grpc .NewClient (unresolvedTargetURI , grpc .WithTransportCredentials (insecure .NewCredentials ()))
640
+ if err != nil {
641
+ t .Fatalf ("grpc.NewClient failed: %v" , err )
642
+ }
643
+ defer conn .Close ()
644
+
645
+ // Send an RPC to the backend through the proxy.
646
+ client := testgrpc .NewTestServiceClient (conn )
647
+ if _ , err := client .EmptyCall (ctx , & testgrpc.Empty {}); err != nil {
648
+ t .Errorf ("EmptyCall failed: %v" , err )
649
+ }
650
+
651
+ // Verify if the proxy server encountered any errors.
652
+ select {
653
+ case err := <- errCh :
654
+ t .Fatalf ("proxy server encountered an error: %v" , err )
655
+ case <- doneCh :
656
+ t .Logf ("proxy server succeeded" )
657
+ }
658
+
659
+ // Verify if OnClientResolution was triggered.
660
+ select {
661
+ case <- resolutionCh :
662
+ t .Error ("Client-side resolution was unexpectedly called" )
663
+ default :
664
+ // Success: OnClientResolution was not called.
665
+ }
666
+ }
0 commit comments