clientconn: override authority with address's ServerName, if set (#3073)

This commit is contained in:
Joe Betz 2019-10-08 13:59:02 -07:00 коммит произвёл Doug Fawley
Родитель d08614fd39
Коммит 2e7984e2c0
3 изменённых файлов: 58 добавлений и 2 удалений

Просмотреть файл

@ -1210,10 +1210,16 @@ func (ac *addrConn) createTransport(addr resolver.Address, copts transport.Conne
onCloseCalled := make(chan struct{})
reconnect := grpcsync.NewEvent()
authority := ac.cc.authority
// addr.ServerName takes precedent over ClientConn authority, if present.
if addr.ServerName != "" {
authority = addr.ServerName
}
target := transport.TargetInfo{
Addr: addr.Addr,
Metadata: addr.Metadata,
Authority: ac.cc.authority,
Authority: authority,
}
once := sync.Once{}

Просмотреть файл

@ -86,9 +86,16 @@ type Address struct {
// Type is the type of this address.
Type AddressType
// ServerName is the name of this address.
// If non-empty, the ServerName is used as the transport certification authority for
// the address, instead of the hostname from the Dial target string. In most cases,
// this should not be set.
//
// e.g. if Type is GRPCLB, ServerName should be the name of the remote load
// If Type is GRPCLB, ServerName should be the name of the remote load
// balancer, not the name of the backend.
//
// WARNING: ServerName must only be populated with trusted values. It
// is insecure to populate it with data from untrusted inputs since untrusted
// values could be used to bypass the authority checks performed by TLS.
ServerName string
// Metadata is the information associated with Addr, which may be used
// to make load balancing decision.

Просмотреть файл

@ -4969,6 +4969,49 @@ func (s) TestCredsHandshakeAuthority(t *testing.T) {
}
}
// This test makes sure that the authority client handshake gets is the endpoint
// of the ServerName of the address when it is set.
func (s) TestCredsHandshakeServerNameAuthority(t *testing.T) {
const testAuthority = "test.auth.ori.ty"
const testServerName = "test.server.name"
lis, err := net.Listen("tcp", "localhost:0")
if err != nil {
t.Fatalf("Failed to listen: %v", err)
}
cred := &authorityCheckCreds{}
s := grpc.NewServer()
go s.Serve(lis)
defer s.Stop()
r, rcleanup := manual.GenerateAndRegisterManualResolver()
defer rcleanup()
cc, err := grpc.Dial(r.Scheme()+":///"+testAuthority, grpc.WithTransportCredentials(cred))
if err != nil {
t.Fatalf("grpc.Dial(%q) = %v", lis.Addr().String(), err)
}
defer cc.Close()
r.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: lis.Addr().String(), ServerName: testServerName}}})
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
for {
s := cc.GetState()
if s == connectivity.Ready {
break
}
if !cc.WaitForStateChange(ctx, s) {
// ctx got timeout or canceled.
t.Fatalf("ClientConn is not ready after 100 ms")
}
}
if cred.got != testServerName {
t.Fatalf("client creds got authority: %q, want: %q", cred.got, testAuthority)
}
}
type clientFailCreds struct{}
func (c *clientFailCreds) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {