github.com/dbernstein1/tyk@v2.9.0-beta9-dl-apic+incompatible/gateway/grpc_test.go (about) 1 package gateway 2 3 import ( 4 "context" 5 "crypto/tls" 6 "crypto/x509" 7 "encoding/base64" 8 "encoding/json" 9 "fmt" 10 "io/ioutil" 11 "net" 12 "net/http" 13 "net/http/httptest" 14 "strings" 15 "testing" 16 "time" 17 18 "github.com/TykTechnologies/tyk/config" 19 "github.com/TykTechnologies/tyk/test" 20 "github.com/TykTechnologies/tyk/user" 21 "golang.org/x/net/http2" 22 "google.golang.org/grpc" 23 "google.golang.org/grpc/credentials" 24 pb "google.golang.org/grpc/examples/helloworld/helloworld" 25 ) 26 27 // For gRPC, we should be sure that HTTP/2 works with Tyk. 28 func TestHTTP2_TLS(t *testing.T) { 29 defer ResetTestConfig() 30 31 expected := "HTTP/2.0" 32 33 // Certificates 34 _, _, _, clientCert := genCertificate(&x509.Certificate{}) 35 serverCertPem, _, combinedPEM, _ := genServerCertificate() 36 certID, _ := CertificateManager.Add(combinedPEM, "") 37 defer CertificateManager.Delete(certID) 38 39 // Upstream server supporting HTTP/2 40 upstream := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 41 actual := r.Proto 42 if expected != actual { 43 t.Fatalf("Tyk-Upstream connection protocol is expected %s, actual %s", expected, actual) 44 } 45 46 fmt.Fprintln(w, "Hello, I am an HTTP/2 Server") 47 48 })) 49 upstream.TLS = new(tls.Config) 50 upstream.TLS.NextProtos = []string{"h2"} 51 upstream.StartTLS() 52 defer upstream.Close() 53 54 // Tyk 55 globalConf := config.Global() 56 globalConf.ProxySSLInsecureSkipVerify = true 57 globalConf.ProxyEnableHttp2 = true 58 globalConf.HttpServerOptions.EnableHttp2 = true 59 globalConf.HttpServerOptions.SSLCertificates = []string{certID} 60 globalConf.HttpServerOptions.UseSSL = true 61 config.SetGlobal(globalConf) 62 defer ResetTestConfig() 63 64 ts := StartTest() 65 defer ts.Close() 66 67 BuildAndLoadAPI(func(spec *APISpec) { 68 spec.Proxy.ListenPath = "/" 69 spec.UseKeylessAccess = true 70 spec.Proxy.TargetURL = upstream.URL 71 }) 72 73 // HTTP/2 client 74 http2Client := getTLSClient(&clientCert, serverCertPem) 75 http2.ConfigureTransport(http2Client.Transport.(*http.Transport)) 76 77 ts.Run(t, test.TestCase{Client: http2Client, Path: "", Code: 200, Proto: "HTTP/2.0", BodyMatch: "Hello, I am an HTTP/2 Server"}) 78 } 79 80 func TestGRPC_TLS(t *testing.T) { 81 defer ResetTestConfig() 82 83 _, _, combinedPEM, _ := genServerCertificate() 84 certID, _ := CertificateManager.Add(combinedPEM, "") 85 defer CertificateManager.Delete(certID) 86 87 // gRPC server 88 s := startGRPCServer(t, nil) 89 defer s.GracefulStop() 90 91 // Tyk 92 globalConf := config.Global() 93 globalConf.ProxySSLInsecureSkipVerify = true 94 globalConf.ProxyEnableHttp2 = true 95 globalConf.HttpServerOptions.EnableHttp2 = true 96 globalConf.HttpServerOptions.SSLCertificates = []string{certID} 97 globalConf.HttpServerOptions.UseSSL = true 98 config.SetGlobal(globalConf) 99 defer ResetTestConfig() 100 101 ts := StartTest() 102 defer ts.Close() 103 104 BuildAndLoadAPI(func(spec *APISpec) { 105 spec.Proxy.ListenPath = "/" 106 spec.UseKeylessAccess = true 107 spec.Proxy.TargetURL = "https://localhost:50051" 108 }) 109 110 address := strings.TrimPrefix(ts.URL, "https://") 111 name := "Furkan" 112 113 // gRPC client 114 r := sayHelloWithGRPCClient(t, nil, nil, false, "", address, name) 115 116 // Test result 117 expected := "Hello " + name 118 actual := r.Message 119 120 if expected != actual { 121 t.Fatalf("Expected %s, actual %s", expected, actual) 122 } 123 } 124 125 func TestGRPC_MutualTLS(t *testing.T) { 126 // Mutual Authentication for both downstream-tyk and tyk-upstream 127 defer ResetTestConfig() 128 129 _, _, combinedClientPEM, clientCert := genCertificate(&x509.Certificate{}) 130 clientCert.Leaf, _ = x509.ParseCertificate(clientCert.Certificate[0]) 131 serverCertPem, _, combinedPEM, _ := genServerCertificate() 132 133 certID, _ := CertificateManager.Add(combinedPEM, "") // For tyk to know downstream 134 defer CertificateManager.Delete(certID) 135 136 clientCertID, _ := CertificateManager.Add(combinedClientPEM, "") // For upstream to know tyk 137 defer CertificateManager.Delete(clientCertID) 138 139 // Protected gRPC server 140 s := startGRPCServer(t, clientCert.Leaf) 141 defer s.GracefulStop() 142 143 // Tyk 144 globalConf := config.Global() 145 globalConf.ProxySSLInsecureSkipVerify = true 146 globalConf.ProxyEnableHttp2 = true 147 globalConf.HttpServerOptions.EnableHttp2 = true 148 globalConf.HttpServerOptions.SSLCertificates = []string{certID} 149 globalConf.HttpServerOptions.UseSSL = true 150 config.SetGlobal(globalConf) 151 defer ResetTestConfig() 152 153 ts := StartTest() 154 defer ts.Close() 155 156 BuildAndLoadAPI(func(spec *APISpec) { 157 spec.Proxy.ListenPath = "/" 158 spec.UseKeylessAccess = true 159 spec.UpstreamCertificates = map[string]string{ 160 "*": clientCertID, 161 } 162 spec.Proxy.TargetURL = "https://localhost:50051" 163 }) 164 165 address := strings.TrimPrefix(ts.URL, "https://") 166 name := "Furkan" 167 168 // gRPC client 169 r := sayHelloWithGRPCClient(t, &clientCert, serverCertPem, false, "", address, name) 170 171 // Test result 172 expected := "Hello " + name 173 actual := r.Message 174 175 if expected != actual { 176 t.Fatalf("Expected %s, actual %s", expected, actual) 177 } 178 } 179 180 func TestGRPC_BasicAuthentication(t *testing.T) { 181 defer ResetTestConfig() 182 _, _, combinedPEM, _ := genServerCertificate() 183 certID, _ := CertificateManager.Add(combinedPEM, "") 184 defer CertificateManager.Delete(certID) 185 186 // gRPC server 187 s := startGRPCServer(t, nil) 188 defer s.GracefulStop() 189 190 // Tyk 191 globalConf := config.Global() 192 globalConf.ProxySSLInsecureSkipVerify = true 193 globalConf.ProxyEnableHttp2 = true 194 globalConf.HttpServerOptions.EnableHttp2 = true 195 globalConf.HttpServerOptions.SSLCertificates = []string{certID} 196 globalConf.HttpServerOptions.UseSSL = true 197 config.SetGlobal(globalConf) 198 defer ResetTestConfig() 199 200 ts := StartTest() 201 defer ts.Close() 202 203 session := CreateStandardSession() 204 session.BasicAuthData.Password = "password" 205 session.AccessRights = map[string]user.AccessDefinition{"test": {APIID: "test", Versions: []string{"v1"}}} 206 session.OrgID = "default" 207 208 BuildAndLoadAPI(func(spec *APISpec) { 209 spec.UseBasicAuth = true 210 spec.Proxy.ListenPath = "/" 211 spec.UseKeylessAccess = false 212 spec.Proxy.TargetURL = "https://localhost:50051" 213 spec.OrgID = "default" 214 }) 215 216 address := strings.TrimPrefix(ts.URL, "https://") 217 name := "Furkan" 218 client := getTLSClient(nil, nil) 219 220 // To create key 221 ts.Run(t, []test.TestCase{ 222 {Method: "POST", Path: "/tyk/keys/defaultuser", Data: session, AdminAuth: true, Code: 200, Client: client}, 223 }...) 224 225 // gRPC client 226 r := sayHelloWithGRPCClient(t, nil, nil, true, "", address, name) 227 228 // Test result 229 expected := "Hello " + name 230 actual := r.Message 231 232 if expected != actual { 233 t.Fatalf("Expected %s, actual %s", expected, actual) 234 } 235 } 236 237 func TestGRPC_TokenBasedAuthentication(t *testing.T) { 238 defer ResetTestConfig() 239 _, _, combinedPEM, _ := genServerCertificate() 240 certID, _ := CertificateManager.Add(combinedPEM, "") 241 defer CertificateManager.Delete(certID) 242 243 // gRPC server 244 s := startGRPCServer(t, nil) 245 defer s.GracefulStop() 246 247 // Tyk 248 globalConf := config.Global() 249 globalConf.ProxySSLInsecureSkipVerify = true 250 globalConf.ProxyEnableHttp2 = true 251 globalConf.HttpServerOptions.EnableHttp2 = true 252 globalConf.HttpServerOptions.SSLCertificates = []string{certID} 253 globalConf.HttpServerOptions.UseSSL = true 254 config.SetGlobal(globalConf) 255 defer ResetTestConfig() 256 257 ts := StartTest() 258 defer ts.Close() 259 260 session := CreateStandardSession() 261 session.AccessRights = map[string]user.AccessDefinition{"test": {APIID: "test", Versions: []string{"v1"}}} 262 session.OrgID = "default" 263 264 BuildAndLoadAPI(func(spec *APISpec) { 265 spec.Proxy.ListenPath = "/" 266 spec.UseKeylessAccess = false 267 spec.Proxy.TargetURL = "https://localhost:50051" 268 spec.OrgID = "default" 269 }) 270 271 address := strings.TrimPrefix(ts.URL, "https://") 272 name := "Furkan" 273 client := getTLSClient(nil, nil) 274 275 // To create key 276 resp, _ := ts.Run(t, []test.TestCase{ 277 {Method: "POST", Path: "/tyk/keys/create", Data: session, AdminAuth: true, Code: 200, Client: client}, 278 }...) 279 280 // Read key 281 body, _ := ioutil.ReadAll(resp.Body) 282 var resMap map[string]string 283 err := json.Unmarshal(body, &resMap) 284 if err != nil { 285 t.Fatal(err) 286 } 287 288 // gRPC client 289 r := sayHelloWithGRPCClient(t, nil, nil, false, resMap["key"], address, name) 290 291 // Test result 292 expected := "Hello " + name 293 actual := r.Message 294 295 if expected != actual { 296 t.Fatalf("Expected %s, actual %s", expected, actual) 297 } 298 } 299 300 // server is used to implement helloworld.GreeterServer. 301 type server struct{} 302 303 // SayHello implements helloworld.GreeterServer 304 func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { 305 log.Printf("Received: %v", in.Name) 306 return &pb.HelloReply{Message: "Hello " + in.Name}, nil 307 } 308 309 func startGRPCServer(t *testing.T, clientCert *x509.Certificate) *grpc.Server { 310 // Server 311 lis, err := net.Listen("tcp", ":50051") 312 if err != nil { 313 t.Fatalf("failed to listen: %v", err) 314 } 315 316 cert, key, _, _ := genCertificate(&x509.Certificate{}) 317 certificate, _ := tls.X509KeyPair(cert, key) 318 319 pool := x509.NewCertPool() 320 321 tlsConfig := &tls.Config{} 322 if clientCert != nil { 323 tlsConfig = &tls.Config{ 324 ClientAuth: tls.RequireAndVerifyClientCert, 325 ClientCAs: pool, 326 InsecureSkipVerify: true, 327 Certificates: []tls.Certificate{certificate}, 328 } 329 pool.AddCert(clientCert) 330 } else { 331 tlsConfig = &tls.Config{ 332 InsecureSkipVerify: true, 333 Certificates: []tls.Certificate{certificate}, 334 } 335 } 336 337 creds := credentials.NewTLS(tlsConfig) 338 339 if err != nil { 340 t.Fatalf("failed to listen: %v", err) 341 } 342 343 s := grpc.NewServer(grpc.Creds(creds)) 344 345 pb.RegisterGreeterServer(s, &server{}) 346 347 go func() { 348 err := s.Serve(lis) 349 if err != nil { 350 t.Fatalf("failed to serve: %v", err) 351 } 352 }() 353 354 return s 355 } 356 357 func sayHelloWithGRPCClient(t *testing.T, cert *tls.Certificate, caCert []byte, basicAuth bool, token string, address string, name string) *pb.HelloReply { 358 // gRPC client 359 tlsConfig := &tls.Config{} 360 361 if cert != nil { 362 tlsConfig.Certificates = []tls.Certificate{*cert} 363 } 364 365 if len(caCert) > 0 { 366 caCertPool := x509.NewCertPool() 367 caCertPool.AppendCertsFromPEM(caCert) 368 tlsConfig.RootCAs = caCertPool 369 tlsConfig.BuildNameToCertificate() 370 } else { 371 tlsConfig.InsecureSkipVerify = true 372 } 373 374 creds := credentials.NewTLS(tlsConfig) 375 376 opts := []grpc.DialOption{grpc.WithTransportCredentials(creds)} 377 378 if basicAuth { 379 opts = append(opts, grpc.WithPerRPCCredentials(&loginCredsOrToken{ 380 Username: "user", 381 Password: "password", 382 })) 383 } else if token != "" { // Token Based Authentication 384 opts = append(opts, grpc.WithPerRPCCredentials(&loginCredsOrToken{ 385 TokenBasedAuth: true, 386 Token: token, 387 })) 388 } 389 390 conn, err := grpc.Dial(address, opts...) 391 if err != nil { 392 t.Fatalf("did not connect: %v", err) 393 } 394 defer conn.Close() 395 c := pb.NewGreeterClient(conn) 396 397 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 398 defer cancel() 399 r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name}) 400 if err != nil { 401 t.Fatalf("could not greet: %v", err) 402 } 403 404 return r 405 } 406 407 type loginCredsOrToken struct { 408 Username string 409 Password string 410 TokenBasedAuth bool 411 Token string 412 } 413 414 func (l *loginCredsOrToken) GetRequestMetadata(context.Context, ...string) (headers map[string]string, err error) { 415 auth := l.Username + ":" + l.Password 416 enc := base64.StdEncoding.EncodeToString([]byte(auth)) 417 418 headers = make(map[string]string) 419 420 if l.TokenBasedAuth { 421 headers["Authorization"] = l.Token 422 } else { 423 headers["Authorization"] = "Basic " + enc 424 } 425 426 return 427 } 428 429 func (*loginCredsOrToken) RequireTransportSecurity() bool { 430 return true 431 }