diff --git a/credentials/insecure/insecure.go b/credentials/insecure/insecure.go new file mode 100644 index 00000000000..7fc11717f76 --- /dev/null +++ b/credentials/insecure/insecure.go @@ -0,0 +1,74 @@ +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package insecure provides an implementation of the +// credentials.TransportCredentials interface which disables transport security. +// +// Experimental +// +// Notice: This package is EXPERIMENTAL and may be changed or removed in a +// later release. +package insecure + +import ( + "context" + "net" + + "google.golang.org/grpc/credentials" +) + +// NewCredentials returns a credentials which disables transport security. +func NewCredentials() credentials.TransportCredentials { + return insecureTC{} +} + +// insecureTC implements the insecure transport credentials. The handshake +// methods simply return the passed in net.Conn and set the security level to +// NoSecurity. +type insecureTC struct{} + +func (insecureTC) ClientHandshake(ctx context.Context, _ string, conn net.Conn) (net.Conn, credentials.AuthInfo, error) { + return conn, Info{credentials.CommonAuthInfo{SecurityLevel: credentials.NoSecurity}}, nil +} + +func (insecureTC) ServerHandshake(conn net.Conn) (net.Conn, credentials.AuthInfo, error) { + return conn, Info{credentials.CommonAuthInfo{SecurityLevel: credentials.NoSecurity}}, nil +} + +func (insecureTC) Info() credentials.ProtocolInfo { + return credentials.ProtocolInfo{SecurityProtocol: "insecure"} +} + +func (insecureTC) Clone() credentials.TransportCredentials { + return insecureTC{} +} + +func (insecureTC) OverrideServerName(string) error { + return nil +} + +// Info contains the auth information for an insecure connection. +// It implements the AuthInfo interface. +type Info struct { + credentials.CommonAuthInfo +} + +// AuthType returns the type of Info as a string. +func (Info) AuthType() string { + return "insecure" +} diff --git a/test/insecure_creds_test.go b/test/insecure_creds_test.go new file mode 100644 index 00000000000..81d5a5ba5d0 --- /dev/null +++ b/test/insecure_creds_test.go @@ -0,0 +1,124 @@ +/* + * + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package test + +import ( + "context" + "net" + "testing" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/peer" + "google.golang.org/grpc/status" + testpb "google.golang.org/grpc/test/grpc_testing" +) + +const defaultTestTimeout = 5 * time.Second + +// TestInsecureCreds tests the use of insecure creds on the server and client +// side, and verifies that expect security level and auth info are returned. +// Also verifies that this credential can interop with existing `WithInsecure` +// DialOption. +func (s) TestInsecureCreds(t *testing.T) { + tests := []struct { + desc string + clientInsecureCreds bool + serverInsecureCreds bool + }{ + { + desc: "client and server insecure creds", + clientInsecureCreds: true, + serverInsecureCreds: true, + }, + { + desc: "client only insecure creds", + clientInsecureCreds: true, + }, + { + desc: "server only insecure creds", + serverInsecureCreds: true, + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + ss := &stubServer{ + emptyCall: func(ctx context.Context, in *testpb.Empty) (*testpb.Empty, error) { + if !test.serverInsecureCreds { + return &testpb.Empty{}, nil + } + + pr, ok := peer.FromContext(ctx) + if !ok { + return nil, status.Error(codes.DataLoss, "Failed to get peer from ctx") + } + // Check security level. + info := pr.AuthInfo.(insecure.Info) + if at := info.AuthType(); at != "insecure" { + return nil, status.Errorf(codes.Unauthenticated, "Wrong AuthType: got %q, want insecure", at) + } + if secLevel := info.CommonAuthInfo.SecurityLevel; secLevel != credentials.NoSecurity { + return nil, status.Errorf(codes.Unauthenticated, "Wrong security level: got %q, want %q", secLevel, credentials.NoSecurity) + } + return &testpb.Empty{}, nil + }, + } + + sOpts := []grpc.ServerOption{} + if test.serverInsecureCreds { + sOpts = append(sOpts, grpc.Creds(insecure.NewCredentials())) + } + s := grpc.NewServer(sOpts...) + defer s.Stop() + + testpb.RegisterTestServiceServer(s, ss) + + lis, err := net.Listen("tcp", "localhost:0") + if err != nil { + t.Fatalf("net.Listen(tcp, localhost:0) failed: %v", err) + } + + go s.Serve(lis) + + addr := lis.Addr().String() + ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) + defer cancel() + cOpts := []grpc.DialOption{grpc.WithBlock()} + if test.clientInsecureCreds { + cOpts = append(cOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } else { + cOpts = append(cOpts, grpc.WithInsecure()) + } + cc, err := grpc.DialContext(ctx, addr, cOpts...) + if err != nil { + t.Fatalf("grpc.Dial(%q) failed: %v", addr, err) + } + defer cc.Close() + + c := testpb.NewTestServiceClient(cc) + if _, err = c.EmptyCall(ctx, &testpb.Empty{}); err != nil { + t.Fatalf("EmptyCall(_, _) = _, %v; want _, ", err) + } + }) + } +}