github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/testutil.go (about) 1 package gateway 2 3 import ( 4 "archive/zip" 5 "bytes" 6 "compress/gzip" 7 "crypto/tls" 8 "crypto/x509" 9 "encoding/binary" 10 "encoding/json" 11 "fmt" 12 "io" 13 "io/ioutil" 14 "math/rand" 15 "net" 16 "net/http" 17 "net/http/httptest" 18 "os" 19 "path/filepath" 20 "runtime" 21 "strconv" 22 "strings" 23 "sync" 24 "testing" 25 "time" 26 27 jwt "github.com/dgrijalva/jwt-go" 28 "github.com/go-redis/redis" 29 "github.com/gorilla/mux" 30 "github.com/gorilla/websocket" 31 uuid "github.com/satori/go.uuid" 32 "golang.org/x/net/context" 33 34 "github.com/TykTechnologies/tyk/apidef" 35 "github.com/TykTechnologies/tyk/cli" 36 "github.com/TykTechnologies/tyk/config" 37 "github.com/TykTechnologies/tyk/storage" 38 "github.com/TykTechnologies/tyk/test" 39 "github.com/TykTechnologies/tyk/user" 40 ) 41 42 var ( 43 // to register to, but never used 44 discardMuxer = mux.NewRouter() 45 46 // to simulate time ticks for tests that do reloads 47 reloadTick = make(chan time.Time) 48 49 // Used to store the test bundles: 50 testMiddlewarePath, _ = ioutil.TempDir("", "tyk-middleware-path") 51 52 mockHandle *test.DnsMockHandle 53 54 testServerRouter *mux.Router 55 defaultTestConfig config.Config 56 57 EnableTestDNSMock = true 58 ) 59 60 // ReloadMachinery is a helper struct to use when writing tests that do manual 61 // gateway reloads 62 type ReloadMachinery struct { 63 run bool 64 count int 65 cycles int 66 mu sync.RWMutex 67 } 68 69 // OnQueued is called when a reload has been queued. This increments the queue 70 // count 71 func (r *ReloadMachinery) OnQueued() { 72 r.mu.Lock() 73 defer r.mu.Unlock() 74 if r.run { 75 r.count++ 76 } 77 } 78 79 // OnReload is called when a reload has been completed. This increments the 80 // reload cycles count. 81 func (r *ReloadMachinery) OnReload() { 82 r.mu.Lock() 83 defer r.mu.Unlock() 84 if r.run { 85 r.cycles++ 86 } 87 } 88 89 // Reloaded returns true if a read has occured since r was enabled 90 func (r *ReloadMachinery) Reloaded() bool { 91 r.mu.RLock() 92 defer r.mu.RUnlock() 93 return r.cycles > 0 94 } 95 96 // Enable when callled it will allow r to keep track of reload cycles and queues 97 func (r *ReloadMachinery) Enable() { 98 r.mu.Lock() 99 defer r.mu.Unlock() 100 r.run = true 101 } 102 103 // Disable turns off tracking of reload cycles and queues 104 func (r *ReloadMachinery) Disable() { 105 r.mu.Lock() 106 defer r.mu.Unlock() 107 r.run = true 108 r.count = 0 109 r.cycles = 0 110 } 111 112 // Reset sets reloads counts and queues to 0 113 func (r *ReloadMachinery) Reset() { 114 r.mu.Lock() 115 defer r.mu.Unlock() 116 r.count = 0 117 r.cycles = 0 118 } 119 120 // Queued returns true if any queue happened 121 func (r *ReloadMachinery) Queued() bool { 122 r.mu.RLock() 123 defer r.mu.RUnlock() 124 return r.count > 0 125 } 126 127 // EnsureQueued this will block until any queue happens. It will timeout after 128 // 100ms 129 func (r *ReloadMachinery) EnsureQueued(t *testing.T) { 130 deadline := time.NewTimer(100 * time.Millisecond) 131 defer deadline.Stop() 132 tick := time.NewTicker(time.Millisecond) 133 defer tick.Stop() 134 for { 135 select { 136 case <-deadline.C: 137 t.Fatal("Timedout waiting for reload to be queue") 138 case <-tick.C: 139 if r.Queued() { 140 return 141 } 142 } 143 } 144 } 145 146 // EnsureReloaded this will block until any reload happens. It will timeout after 147 // 100ms 148 func (r *ReloadMachinery) EnsureReloaded(t *testing.T) { 149 deadline := time.NewTimer(100 * time.Millisecond) 150 defer deadline.Stop() 151 tick := time.NewTicker(time.Millisecond) 152 defer tick.Stop() 153 for { 154 select { 155 case <-deadline.C: 156 t.Fatal("Timedout waiting for reload to be queue") 157 case <-tick.C: 158 if r.Reloaded() { 159 return 160 } 161 } 162 } 163 } 164 165 // Tick triggers reload 166 func (r *ReloadMachinery) Tick() { 167 reloadTick <- time.Time{} 168 } 169 170 // TickOk triggers a reload and ensures a queue happend and a reload cycle 171 // happens. This will block until all the cases are met. 172 func (r *ReloadMachinery) TickOk(t *testing.T) { 173 r.EnsureQueued(t) 174 reloadTick <- time.Time{} 175 r.EnsureReloaded(t) 176 } 177 178 // ReloadTestCase use this when in any test for gateway reloads 179 var ReloadTestCase = &ReloadMachinery{} 180 181 func InitTestMain(ctx context.Context, m *testing.M, genConf ...func(globalConf *config.Config)) int { 182 setTestMode(true) 183 testServerRouter = testHttpHandler() 184 testServer := &http.Server{ 185 Addr: testHttpListen, 186 Handler: testServerRouter, 187 ReadTimeout: 1 * time.Second, 188 WriteTimeout: 1 * time.Second, 189 MaxHeaderBytes: 1 << 20, 190 } 191 192 globalConf := config.Global() 193 if err := config.WriteDefault("", &globalConf); err != nil { 194 panic(err) 195 } 196 globalConf.Storage.Database = rand.Intn(15) 197 var err error 198 globalConf.AppPath, err = ioutil.TempDir("", "tyk-test-") 199 if err != nil { 200 panic(err) 201 } 202 globalConf.EnableAnalytics = true 203 globalConf.AnalyticsConfig.EnableGeoIP = true 204 _, b, _, _ := runtime.Caller(0) 205 gatewayPath := filepath.Dir(b) 206 rootPath := filepath.Dir(gatewayPath) 207 globalConf.AnalyticsConfig.GeoIPDBLocation = filepath.Join(rootPath, "testdata", "MaxMind-DB-test-ipv4-24.mmdb") 208 globalConf.EnableJSVM = true 209 globalConf.HashKeyFunction = storage.HashMurmur64 210 globalConf.Monitor.EnableTriggerMonitors = true 211 globalConf.AnalyticsConfig.NormaliseUrls.Enabled = true 212 globalConf.AllowInsecureConfigs = true 213 // Enable coprocess and bundle downloader: 214 globalConf.CoProcessOptions.EnableCoProcess = true 215 globalConf.EnableBundleDownloader = true 216 globalConf.BundleBaseURL = testHttpBundles 217 globalConf.MiddlewarePath = testMiddlewarePath 218 purgeTicker = make(chan time.Time) 219 rpcPurgeTicker = make(chan time.Time) 220 // force ipv4 for now, to work around the docker bug affecting 221 // Go 1.8 and ealier 222 globalConf.ListenAddress = "127.0.0.1" 223 if len(genConf) > 0 { 224 genConf[0](&globalConf) 225 } 226 227 if EnableTestDNSMock { 228 mockHandle, err = test.InitDNSMock(test.DomainsToAddresses, nil) 229 if err != nil { 230 panic(err) 231 } 232 233 defer mockHandle.ShutdownDnsMock() 234 } 235 236 go func() { 237 err := testServer.ListenAndServe() 238 if err != nil { 239 log.Warn("testServer.ListenAndServe() err: ", err.Error()) 240 } 241 }() 242 243 defer testServer.Shutdown(context.Background()) 244 245 CoProcessInit() 246 afterConfSetup(&globalConf) 247 defaultTestConfig = globalConf 248 config.SetGlobal(globalConf) 249 if err := emptyRedis(); err != nil { 250 panic(err) 251 } 252 cli.Init(VERSION, confPaths) 253 initialiseSystem(ctx) 254 // Small part of start() 255 loadAPIEndpoints(mainRouter()) 256 if analytics.GeoIPDB == nil { 257 panic("GeoIPDB was not initialized") 258 } 259 260 go startPubSubLoop() 261 go reloadLoop(ctx, reloadTick, ReloadTestCase.OnReload) 262 go reloadQueueLoop(ctx, ReloadTestCase.OnQueued) 263 go reloadSimulation() 264 exitCode := m.Run() 265 os.RemoveAll(config.Global().AppPath) 266 return exitCode 267 } 268 269 func ResetTestConfig() { 270 config.SetGlobal(defaultTestConfig) 271 } 272 273 func emptyRedis() error { 274 addr := config.Global().Storage.Host + ":" + strconv.Itoa(config.Global().Storage.Port) 275 c := redis.NewClient(&redis.Options{Addr: addr}) 276 defer c.Close() 277 dbName := strconv.Itoa(config.Global().Storage.Database) 278 if err := c.Do("SELECT", dbName).Err(); err != nil { 279 return err 280 } 281 err := c.FlushDB().Err() 282 return err 283 } 284 285 // simulate reloads in the background, i.e. writes to 286 // global variables that should not be accessed in a 287 // racy way like the policies and api specs maps. 288 func reloadSimulation() { 289 for { 290 policiesMu.Lock() 291 policiesByID["_"] = user.Policy{} 292 delete(policiesByID, "_") 293 policiesMu.Unlock() 294 apisMu.Lock() 295 old := apiSpecs 296 apiSpecs = append(apiSpecs, nil) 297 apiSpecs = old 298 apisByID["_"] = nil 299 delete(apisByID, "_") 300 apisMu.Unlock() 301 time.Sleep(5 * time.Millisecond) 302 } 303 } 304 305 // map[bundleName]map[fileName]fileContent 306 var testBundles = map[string]map[string]string{} 307 var testBundleMu sync.Mutex 308 309 func RegisterJSFileMiddleware(apiid string, files map[string]string) { 310 os.MkdirAll(config.Global().MiddlewarePath+"/"+apiid+"/post", 0755) 311 os.MkdirAll(config.Global().MiddlewarePath+"/"+apiid+"/pre", 0755) 312 313 for file, content := range files { 314 ioutil.WriteFile(config.Global().MiddlewarePath+"/"+apiid+"/"+file, []byte(content), 0755) 315 } 316 } 317 318 func RegisterBundle(name string, files map[string]string) string { 319 testBundleMu.Lock() 320 defer testBundleMu.Unlock() 321 322 bundleID := name + "-" + uuid.NewV4().String() + ".zip" 323 testBundles[bundleID] = files 324 325 return bundleID 326 } 327 328 func bundleHandleFunc(w http.ResponseWriter, r *http.Request) { 329 testBundleMu.Lock() 330 defer testBundleMu.Unlock() 331 332 bundleName := strings.Replace(r.URL.Path, "/bundles/", "", -1) 333 bundle, exists := testBundles[bundleName] 334 if !exists { 335 log.Warning(testBundles) 336 http.Error(w, "Bundle not found", http.StatusNotFound) 337 return 338 } 339 340 w.Header().Set("Content-Type", "application/zip") 341 342 z := zip.NewWriter(w) 343 for name, content := range bundle { 344 f, _ := z.Create(name) 345 f.Write([]byte(content)) 346 } 347 z.Close() 348 } 349 func mainRouter() *mux.Router { 350 return getMainRouter(defaultProxyMux) 351 } 352 353 func mainProxy() *proxy { 354 return defaultProxyMux.getProxy(config.Global().ListenPort) 355 } 356 357 func controlProxy() *proxy { 358 p := defaultProxyMux.getProxy(config.Global().ControlAPIPort) 359 if p != nil { 360 return p 361 } 362 return mainProxy() 363 } 364 365 func EnablePort(port int, protocol string) { 366 c := config.Global() 367 if c.PortWhiteList == nil { 368 c.PortWhiteList = map[string]config.PortWhiteList{ 369 protocol: { 370 Ports: []int{port}, 371 }, 372 } 373 } else { 374 m, ok := c.PortWhiteList[protocol] 375 if !ok { 376 m = config.PortWhiteList{ 377 Ports: []int{port}, 378 } 379 } else { 380 m.Ports = append(m.Ports, port) 381 } 382 c.PortWhiteList[protocol] = m 383 } 384 config.SetGlobal(c) 385 } 386 387 func getMainRouter(m *proxyMux) *mux.Router { 388 var protocol string 389 if config.Global().HttpServerOptions.UseSSL { 390 protocol = "https" 391 } else { 392 protocol = "http" 393 } 394 return m.router(config.Global().ListenPort, protocol) 395 } 396 397 type TestHttpResponse struct { 398 Method string 399 URI string 400 Url string 401 Body string 402 Headers map[string]string 403 Form map[string]string 404 } 405 406 // ProxyHandler Proxies requests through to their final destination, if they make it through the middleware chain. 407 func ProxyHandler(p *ReverseProxy, apiSpec *APISpec) http.Handler { 408 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 409 baseMid := BaseMiddleware{Spec: apiSpec, Proxy: p} 410 handler := SuccessHandler{baseMid} 411 // Skip all other execution 412 handler.ServeHTTP(w, r) 413 }) 414 } 415 416 const ( 417 // We need a static port so that the urls can be used in static 418 // test data, and to prevent the requests from being randomized 419 // for checksums. Port 16500 should be obscure and unused. 420 testHttpListen = "127.0.0.1:16500" 421 // Accepts any http requests on /, only allows GET on /get, etc. 422 // All return a JSON with request info. 423 TestHttpAny = "http://" + testHttpListen 424 TestHttpGet = TestHttpAny + "/get" 425 testHttpPost = TestHttpAny + "/post" 426 testGraphQLDataSource = TestHttpAny + "/graphql-data-source" 427 testRESTDataSource = TestHttpAny + "/rest-data-source" 428 testHttpJWK = TestHttpAny + "/jwk.json" 429 testHttpJWKDER = TestHttpAny + "/jwk-der.json" 430 testHttpBundles = TestHttpAny + "/bundles/" 431 testReloadGroup = TestHttpAny + "/groupReload" 432 433 // Nothing should be listening on port 16501 - useful for 434 // testing TCP and HTTP failures. 435 testHttpFailure = "127.0.0.1:16501" 436 testHttpFailureAny = "http://" + testHttpFailure 437 MockOrgID = "507f1f77bcf86cd799439011" 438 ) 439 440 func testHttpHandler() *mux.Router { 441 var upgrader = websocket.Upgrader{ 442 ReadBufferSize: 1024, 443 WriteBufferSize: 1024, 444 } 445 446 wsHandler := func(w http.ResponseWriter, req *http.Request) { 447 conn, err := upgrader.Upgrade(w, req, nil) 448 if err != nil { 449 http.Error(w, fmt.Sprintf("cannot upgrade: %v", err), http.StatusInternalServerError) 450 } 451 452 // start simple reader/writer per connection 453 go func() { 454 for { 455 mt, p, err := conn.ReadMessage() 456 if err != nil { 457 return 458 } 459 conn.WriteMessage(mt, []byte("reply to message: "+string(p))) 460 } 461 }() 462 } 463 464 httpError := func(w http.ResponseWriter, status int) { 465 http.Error(w, http.StatusText(status), status) 466 } 467 writeDetails := func(w http.ResponseWriter, r *http.Request) { 468 if err := r.ParseForm(); err != nil { 469 httpError(w, http.StatusInternalServerError) 470 return 471 } 472 r.URL.Opaque = r.URL.RawPath 473 w.Header().Set("X-Tyk-Test", "1") 474 body, _ := ioutil.ReadAll(r.Body) 475 476 err := json.NewEncoder(w).Encode(TestHttpResponse{ 477 Method: r.Method, 478 URI: r.RequestURI, 479 Url: r.URL.String(), 480 Headers: firstVals(r.Header), 481 Form: firstVals(r.Form), 482 Body: string(body), 483 }) 484 if err != nil { 485 httpError(w, http.StatusInternalServerError) 486 } 487 } 488 handleMethod := func(method string) http.HandlerFunc { 489 return func(w http.ResponseWriter, r *http.Request) { 490 if method != "" && r.Method != method { 491 httpError(w, http.StatusMethodNotAllowed) 492 } else { 493 writeDetails(w, r) 494 } 495 } 496 } 497 498 // use gorilla's mux as it allows to cancel URI cleaning 499 // (it is not configurable in standard http mux) 500 r := mux.NewRouter() 501 502 r.HandleFunc("/get", handleMethod("GET")) 503 r.HandleFunc("/post", handleMethod("POST")) 504 r.HandleFunc("/ws", wsHandler) 505 r.HandleFunc("/jwk.json", func(w http.ResponseWriter, r *http.Request) { 506 io.WriteString(w, jwkTestJson) 507 }) 508 r.HandleFunc("/jwk-der.json", func(w http.ResponseWriter, r *http.Request) { 509 io.WriteString(w, jwkTestDERJson) 510 }) 511 r.HandleFunc("/compressed", func(w http.ResponseWriter, r *http.Request) { 512 response := "This is a compressed response" 513 w.Header().Set("Content-Encoding", "gzip") 514 gz := gzip.NewWriter(w) 515 json.NewEncoder(gz).Encode(response) 516 gz.Close() 517 }) 518 r.HandleFunc("/groupReload", groupResetHandler) 519 r.HandleFunc("/bundles/{rest:.*}", bundleHandleFunc) 520 r.HandleFunc("/errors/{status}", func(w http.ResponseWriter, r *http.Request) { 521 statusCode, _ := strconv.Atoi(mux.Vars(r)["status"]) 522 httpError(w, statusCode) 523 }) 524 r.HandleFunc("/{rest:.*}", handleMethod("")) 525 526 return r 527 } 528 529 const jwkTestJson = `{ 530 "keys": [{ 531 "alg": "RS256", 532 "kty": "RSA", 533 "use": "sig", 534 "x5c": ["Ci0tLS0tQkVHSU4gUFVCTElDIEtFWS0tLS0tCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBeXFaNHJ3S0Y4cUNFeFM3a3BZNGMKbkphLzM3Rk1rSk5rYWxaM091c2xMQjBvUkw4VDRjOTRrZEY0YWVOelNGa1NlMm45OUlCSTZTc2w3OXZiZk1aYgordDA2TDBROTRrKy9QMzd4NysvUkpaaWZmNHkxVkdqcm5ybk1JMml1OWw0aUJCUll6Tm1HNmVibHJvRU1NV2xnCms1dHlzSGd4QjU5Q1NOSWNEOWdxazFoeDRuL0ZnT212S3NmUWdXSE5sUFNEVFJjV0dXR2hCMi9YZ05WWUcycE8KbFF4QVBxTGhCSGVxR1RYQmJQZkdGOWNIeml4cHNQcjZHdGJ6UHdoc1EvOGJQeG9KN2hkZm4rcnp6dGtzM2Q2KwpIV1VSY3lOVExSZTBtalhqamVlOVo2K2daK0grZlM0cG5QOXRxVDdJZ1U2ZVBVV1Rwam9pUHRMZXhnc0FhL2N0CmpRSURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo="], 535 "n": "xofiG8gsnv9-I_g-5OWTLhaZtgAGq1QEsBCPK9lmLqhuonHe8lT-nK1DM49f6J9QgaOjZ3DB50QkhBysnIFNcXFyzaYIPMoccvuHLPgdBawX4WYKm5gficD0WB0XnTt4sqTI5usFpuop9vvW44BwVGhRqMT7c11gA8TSWMBxDI4A5ARc4MuQtfm64oN-JQodSztArwb9wcmH8WrBvSUkR4pyi9MT8W27gqJ2e2Xn8jgGnswNQWOyCTN84PawOYaN-2ORHeIea1g-URln1bofcHN73vZCIrVbE6iA2D7Ybh22AVrCfunekEDEe2GZfLZLejiZiBWG7enJhcrQIzAQGw", 536 "e": "AQAB", 537 "kid": "12345", 538 "x5t": "12345" 539 }] 540 }` 541 542 // This has public key encoded as PKIX, ASN.1 DER form. 543 const jwkTestDERJson = `{ 544 "keys": [{ 545 "alg": "RS256", 546 "kty": "RSA", 547 "use": "sig", 548 "x5c": ["MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyqZ4rwKF8qCExS7kpY4cnJa/37FMkJNkalZ3OuslLB0oRL8T4c94kdF4aeNzSFkSe2n99IBI6Ssl79vbfMZb+t06L0Q94k+/P37x7+/RJZiff4y1VGjrnrnMI2iu9l4iBBRYzNmG6eblroEMMWlgk5tysHgxB59CSNIcD9gqk1hx4n/FgOmvKsfQgWHNlPSDTRcWGWGhB2/XgNVYG2pOlQxAPqLhBHeqGTXBbPfGF9cHzixpsPr6GtbzPwhsQ/8bPxoJ7hdfn+rzztks3d6+HWURcyNTLRe0mjXjjee9Z6+gZ+H+fS4pnP9tqT7IgU6ePUWTpjoiPtLexgsAa/ctjQIDAQAB"], 549 "n": "xofiG8gsnv9-I_g-5OWTLhaZtgAGq1QEsBCPK9lmLqhuonHe8lT-nK1DM49f6J9QgaOjZ3DB50QkhBysnIFNcXFyzaYIPMoccvuHLPgdBawX4WYKm5gficD0WB0XnTt4sqTI5usFpuop9vvW44BwVGhRqMT7c11gA8TSWMBxDI4A5ARc4MuQtfm64oN-JQodSztArwb9wcmH8WrBvSUkR4pyi9MT8W27gqJ2e2Xn8jgGnswNQWOyCTN84PawOYaN-2ORHeIea1g-URln1bofcHN73vZCIrVbE6iA2D7Ybh22AVrCfunekEDEe2GZfLZLejiZiBWG7enJhcrQIzAQGw", 550 "e": "AQAB", 551 "kid": "12345", 552 "x5t": "12345" 553 }] 554 }` 555 556 func withAuth(r *http.Request) *http.Request { 557 // This is the default config secret 558 r.Header.Set("x-tyk-authorization", config.Global().Secret) 559 return r 560 } 561 562 // Deprecated: Use Test.CreateSession instead. 563 func CreateSession(sGen ...func(s *user.SessionState)) string { 564 key := generateToken("default", "") 565 session := CreateStandardSession() 566 if len(sGen) > 0 { 567 sGen[0](session) 568 } 569 if session.Certificate != "" { 570 key = generateToken("default", session.Certificate) 571 } 572 573 FallbackKeySesionManager.UpdateSession(storage.HashKey(key), session, 60, config.Global().HashKeys) 574 return key 575 } 576 577 func CreateStandardSession() *user.SessionState { 578 session := new(user.SessionState) 579 session.Rate = 10000 580 session.Allowance = session.Rate 581 session.LastCheck = time.Now().Unix() 582 session.Per = 60 583 session.Expires = -1 584 session.QuotaRenewalRate = 300 // 5 minutes 585 session.QuotaRenews = time.Now().Unix() + 20 586 session.QuotaRemaining = 10 587 session.QuotaMax = -1 588 session.Tags = []string{} 589 session.MetaData = make(map[string]interface{}) 590 session.OrgID = "default" 591 session.Mutex = &sync.RWMutex{} 592 return session 593 } 594 595 func CreateStandardPolicy() *user.Policy { 596 return &user.Policy{ 597 OrgID: "default", 598 Rate: 1000.0, 599 Per: 1.0, 600 QuotaMax: -1, 601 QuotaRenewalRate: -1, 602 AccessRights: map[string]user.AccessDefinition{}, 603 Active: true, 604 KeyExpiresIn: 60, 605 } 606 } 607 608 func CreatePolicy(pGen ...func(p *user.Policy)) string { 609 pID := keyGen.GenerateAuthKey("") 610 pol := CreateStandardPolicy() 611 pol.ID = pID 612 613 if len(pGen) > 0 { 614 pGen[0](pol) 615 } 616 617 policiesMu.Lock() 618 policiesByID[pol.ID] = *pol 619 policiesMu.Unlock() 620 621 return pol.ID 622 } 623 624 func CreateJWKToken(jGen ...func(*jwt.Token)) string { 625 // Create the token 626 token := jwt.New(jwt.GetSigningMethod("RS512")) 627 // Set the token ID 628 629 if len(jGen) > 0 { 630 jGen[0](token) 631 } 632 633 // Sign and get the complete encoded token as a string 634 signKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(jwtRSAPrivKey)) 635 if err != nil { 636 panic("Couldn't extract private key: " + err.Error()) 637 } 638 tokenString, err := token.SignedString(signKey) 639 if err != nil { 640 panic("Couldn't create JWT token: " + err.Error()) 641 } 642 643 return tokenString 644 } 645 646 func CreateJWKTokenECDSA(jGen ...func(*jwt.Token)) string { 647 // Create the token 648 token := jwt.New(jwt.GetSigningMethod("ES256")) 649 // Set the token ID 650 651 if len(jGen) > 0 { 652 jGen[0](token) 653 } 654 655 // Sign and get the complete encoded token as a string 656 signKey, err := jwt.ParseECPrivateKeyFromPEM([]byte(jwtECDSAPrivateKey)) 657 if err != nil { 658 panic("Couldn't extract private key: " + err.Error()) 659 } 660 tokenString, err := token.SignedString(signKey) 661 if err != nil { 662 panic("Couldn't create JWT token: " + err.Error()) 663 } 664 665 return tokenString 666 } 667 668 func createJWKTokenHMAC(jGen ...func(*jwt.Token)) string { 669 // Create the token 670 token := jwt.New(jwt.SigningMethodHS256) 671 // Set the token ID 672 673 if len(jGen) > 0 { 674 jGen[0](token) 675 } 676 677 tokenString, err := token.SignedString([]byte(jwtSecret)) 678 if err != nil { 679 panic("Couldn't create JWT token: " + err.Error()) 680 } 681 682 return tokenString 683 } 684 685 func TestReqBody(t testing.TB, body interface{}) io.Reader { 686 switch x := body.(type) { 687 case []byte: 688 return bytes.NewReader(x) 689 case string: 690 return strings.NewReader(x) 691 case io.Reader: 692 return x 693 case nil: 694 return nil 695 default: // JSON objects (structs) 696 bs, err := json.Marshal(x) 697 if err != nil { 698 t.Fatal(err) 699 } 700 return bytes.NewReader(bs) 701 } 702 } 703 704 func TestReq(t testing.TB, method, urlStr string, body interface{}) *http.Request { 705 return httptest.NewRequest(method, urlStr, TestReqBody(t, body)) 706 } 707 708 func CreateDefinitionFromString(defStr string) *APISpec { 709 loader := APIDefinitionLoader{} 710 def := loader.ParseDefinition(strings.NewReader(defStr)) 711 spec := loader.MakeSpec(def, nil) 712 return spec 713 } 714 715 func LoadSampleAPI(def string) (spec *APISpec) { 716 spec = CreateDefinitionFromString(def) 717 loadApps([]*APISpec{spec}) 718 return 719 } 720 721 func firstVals(vals map[string][]string) map[string]string { 722 m := make(map[string]string, len(vals)) 723 for k, vs := range vals { 724 m[k] = vs[0] 725 } 726 return m 727 } 728 729 type TestConfig struct { 730 sepatateControlAPI bool 731 Delay time.Duration 732 HotReload bool 733 overrideDefaults bool 734 CoprocessConfig config.CoProcessConfig 735 } 736 737 type Test struct { 738 URL string 739 740 testRunner *test.HTTPTestRunner 741 GlobalConfig config.Config 742 config TestConfig 743 cacnel func() 744 } 745 746 func (s *Test) Start() { 747 l, _ := net.Listen("tcp", "127.0.0.1:0") 748 _, port, _ := net.SplitHostPort(l.Addr().String()) 749 l.Close() 750 globalConf := config.Global() 751 globalConf.ListenPort, _ = strconv.Atoi(port) 752 753 if s.config.sepatateControlAPI { 754 l, _ := net.Listen("tcp", "127.0.0.1:0") 755 756 _, port, _ = net.SplitHostPort(l.Addr().String()) 757 l.Close() 758 globalConf.ControlAPIPort, _ = strconv.Atoi(port) 759 } 760 globalConf.CoProcessOptions = s.config.CoprocessConfig 761 config.SetGlobal(globalConf) 762 763 setupPortsWhitelist() 764 765 startServer() 766 ctx, cancel := context.WithCancel(context.Background()) 767 s.cacnel = cancel 768 setupGlobals(ctx) 769 // Set up a default org manager so we can traverse non-live paths 770 if !config.Global().SupressDefaultOrgStore { 771 DefaultOrgStore.Init(getGlobalStorageHandler("orgkey.", false)) 772 DefaultQuotaStore.Init(getGlobalStorageHandler("orgkey.", false)) 773 } 774 775 s.GlobalConfig = globalConf 776 777 scheme := "http://" 778 if s.GlobalConfig.HttpServerOptions.UseSSL { 779 scheme = "https://" 780 } 781 s.URL = scheme + mainProxy().listener.Addr().String() 782 783 s.testRunner = &test.HTTPTestRunner{ 784 RequestBuilder: func(tc *test.TestCase) (*http.Request, error) { 785 tc.BaseURL = s.URL 786 if tc.ControlRequest { 787 if s.config.sepatateControlAPI { 788 tc.BaseURL = scheme + controlProxy().listener.Addr().String() 789 } else if s.GlobalConfig.ControlAPIHostname != "" { 790 tc.Domain = s.GlobalConfig.ControlAPIHostname 791 } 792 } 793 r, err := test.NewRequest(tc) 794 795 if tc.AdminAuth { 796 r = withAuth(r) 797 } 798 799 if s.config.Delay > 0 { 800 tc.Delay = s.config.Delay 801 } 802 803 return r, err 804 }, 805 Do: test.HttpServerRunner(), 806 } 807 } 808 809 func (s *Test) Do(tc test.TestCase) (*http.Response, error) { 810 req, _ := s.testRunner.RequestBuilder(&tc) 811 return s.testRunner.Do(req, &tc) 812 } 813 814 func (s *Test) Close() { 815 if s.cacnel != nil { 816 s.cacnel() 817 } 818 defaultProxyMux.swap(&proxyMux{}) 819 if s.config.sepatateControlAPI { 820 globalConf := config.Global() 821 globalConf.ControlAPIPort = 0 822 config.SetGlobal(globalConf) 823 } 824 } 825 826 func (s *Test) Run(t testing.TB, testCases ...test.TestCase) (*http.Response, error) { 827 return s.testRunner.Run(t, testCases...) 828 } 829 830 //TODO:(gernest) when hot reload is suppored enable this. 831 func (s *Test) RunExt(t testing.TB, testCases ...test.TestCase) { 832 s.Run(t, testCases...) 833 var testMatrix = []struct { 834 goagain bool 835 overrideDefaults bool 836 }{ 837 {false, false}, 838 {false, true}, 839 {true, true}, 840 {true, false}, 841 } 842 843 for i, m := range testMatrix { 844 s.config.HotReload = m.goagain 845 s.config.overrideDefaults = m.overrideDefaults 846 847 if i > 0 { 848 s.Close() 849 s.Start() 850 } 851 852 title := fmt.Sprintf("hotReload: %v, overrideDefaults: %v", m.goagain, m.overrideDefaults) 853 t.(*testing.T).Run(title, func(t *testing.T) { 854 s.Run(t, testCases...) 855 }) 856 } 857 } 858 859 func GetTLSClient(cert *tls.Certificate, caCert []byte) *http.Client { 860 // Setup HTTPS client 861 tlsConfig := &tls.Config{} 862 863 if cert != nil { 864 tlsConfig.Certificates = []tls.Certificate{*cert} 865 } 866 867 if len(caCert) > 0 { 868 caCertPool := x509.NewCertPool() 869 caCertPool.AppendCertsFromPEM(caCert) 870 tlsConfig.RootCAs = caCertPool 871 tlsConfig.BuildNameToCertificate() 872 } else { 873 tlsConfig.InsecureSkipVerify = true 874 } 875 876 transport := &http.Transport{TLSClientConfig: tlsConfig} 877 878 return &http.Client{Transport: transport} 879 } 880 881 func (s *Test) CreateSession(sGen ...func(s *user.SessionState)) (*user.SessionState, string) { 882 session := CreateStandardSession() 883 if len(sGen) > 0 { 884 sGen[0](session) 885 } 886 887 client := GetTLSClient(nil, nil) 888 889 resp, err := s.Do(test.TestCase{ 890 Method: http.MethodPost, 891 Path: "/tyk/keys/create", 892 Data: session, 893 Client: client, 894 AdminAuth: true, 895 }) 896 897 if err != nil { 898 log.Fatal("Error while creating session:", err) 899 return nil, "" 900 } 901 902 keySuccess := apiModifyKeySuccess{} 903 err = json.NewDecoder(resp.Body).Decode(&keySuccess) 904 if err != nil { 905 log.Fatal("Error while decoding session response:", err) 906 return nil, "" 907 } 908 909 return session, keySuccess.Key 910 } 911 912 func StartTest(config ...TestConfig) *Test { 913 t := &Test{} 914 if len(config) > 0 { 915 t.config = config[0] 916 } 917 t.Start() 918 919 return t 920 } 921 922 const sampleAPI = `{ 923 "api_id": "test", 924 "org_id": "default", 925 "use_keyless": true, 926 "definition": { 927 "location": "header", 928 "key": "version" 929 }, 930 "auth": { 931 "auth_header_name": "authorization" 932 }, 933 "version_data": { 934 "default_version": "Default", 935 "not_versioned": true, 936 "versions": { 937 "v1": { 938 "name": "v1", 939 "use_extended_paths": true 940 } 941 } 942 }, 943 "proxy": { 944 "listen_path": "/sample", 945 "target_url": "` + TestHttpAny + `" 946 } 947 }` 948 949 func UpdateAPIVersion(spec *APISpec, name string, verGen func(version *apidef.VersionInfo)) { 950 version := spec.VersionData.Versions[name] 951 verGen(&version) 952 spec.VersionData.Versions[name] = version 953 } 954 955 func jsonMarshalString(i interface{}) (out string) { 956 b, _ := json.Marshal(i) 957 return string(b) 958 } 959 960 func BuildAPI(apiGens ...func(spec *APISpec)) (specs []*APISpec) { 961 if len(apiGens) == 0 { 962 apiGens = append(apiGens, func(spec *APISpec) {}) 963 } 964 965 for _, gen := range apiGens { 966 spec := &APISpec{APIDefinition: &apidef.APIDefinition{}} 967 if err := json.Unmarshal([]byte(sampleAPI), spec.APIDefinition); err != nil { 968 panic(err) 969 } 970 971 gen(spec) 972 specs = append(specs, spec) 973 } 974 975 return specs 976 } 977 978 func LoadAPI(specs ...*APISpec) (out []*APISpec) { 979 globalConf := config.Global() 980 oldPath := globalConf.AppPath 981 globalConf.AppPath, _ = ioutil.TempDir("", "apps") 982 config.SetGlobal(globalConf) 983 defer func() { 984 globalConf := config.Global() 985 os.RemoveAll(globalConf.AppPath) 986 globalConf.AppPath = oldPath 987 config.SetGlobal(globalConf) 988 }() 989 990 for i, spec := range specs { 991 specBytes, err := json.Marshal(spec) 992 if err != nil { 993 panic(err) 994 } 995 specFilePath := filepath.Join(config.Global().AppPath, spec.APIID+strconv.Itoa(i)+".json") 996 if err := ioutil.WriteFile(specFilePath, specBytes, 0644); err != nil { 997 panic(err) 998 } 999 } 1000 1001 DoReload() 1002 1003 for _, spec := range specs { 1004 out = append(out, getApiSpec(spec.APIID)) 1005 } 1006 1007 return out 1008 } 1009 1010 func BuildAndLoadAPI(apiGens ...func(spec *APISpec)) (specs []*APISpec) { 1011 return LoadAPI(BuildAPI(apiGens...)...) 1012 } 1013 1014 func CloneAPI(a *APISpec) *APISpec { 1015 new := &APISpec{} 1016 new.APIDefinition = &apidef.APIDefinition{} 1017 *new.APIDefinition = *a.APIDefinition 1018 1019 return new 1020 } 1021 1022 // Taken from https://medium.com/@mlowicki/http-s-proxy-in-golang-in-less-than-100-lines-of-code-6a51c2f2c38c 1023 type httpProxyHandler struct { 1024 proto string 1025 URL string 1026 server *http.Server 1027 listener net.Listener 1028 } 1029 1030 func (p *httpProxyHandler) handleTunneling(w http.ResponseWriter, r *http.Request) { 1031 dest_conn, err := net.DialTimeout("tcp", r.Host, 10*time.Second) 1032 if err != nil { 1033 http.Error(w, err.Error(), http.StatusServiceUnavailable) 1034 return 1035 } 1036 w.WriteHeader(http.StatusOK) 1037 hijacker, ok := w.(http.Hijacker) 1038 if !ok { 1039 http.Error(w, "Hijacking not supported", http.StatusInternalServerError) 1040 return 1041 } 1042 client_conn, _, err := hijacker.Hijack() 1043 if err != nil { 1044 http.Error(w, err.Error(), http.StatusServiceUnavailable) 1045 } 1046 go p.transfer(dest_conn, client_conn) 1047 go p.transfer(client_conn, dest_conn) 1048 } 1049 1050 func (p *httpProxyHandler) transfer(destination io.WriteCloser, source io.ReadCloser) { 1051 defer destination.Close() 1052 defer source.Close() 1053 io.Copy(destination, source) 1054 } 1055 func (p *httpProxyHandler) handleHTTP(w http.ResponseWriter, req *http.Request) { 1056 resp, err := http.DefaultTransport.RoundTrip(req) 1057 if err != nil { 1058 http.Error(w, err.Error(), http.StatusServiceUnavailable) 1059 return 1060 } 1061 defer resp.Body.Close() 1062 p.copyHeader(w.Header(), resp.Header) 1063 w.WriteHeader(resp.StatusCode) 1064 io.Copy(w, resp.Body) 1065 } 1066 1067 func (p *httpProxyHandler) Stop() error { 1068 ResetTestConfig() 1069 return p.server.Close() 1070 } 1071 1072 func (p *httpProxyHandler) copyHeader(dst, src http.Header) { 1073 for k, vv := range src { 1074 for _, v := range vv { 1075 dst.Add(k, v) 1076 } 1077 } 1078 } 1079 1080 func initProxy(proto string, tlsConfig *tls.Config) *httpProxyHandler { 1081 proxy := &httpProxyHandler{proto: proto} 1082 1083 proxy.server = &http.Server{ 1084 Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1085 if r.Method == http.MethodConnect { 1086 proxy.handleTunneling(w, r) 1087 } else { 1088 proxy.handleHTTP(w, r) 1089 } 1090 }), 1091 // Disable HTTP/2. 1092 TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)), 1093 } 1094 1095 var err error 1096 1097 switch proto { 1098 case "http": 1099 proxy.listener, err = net.Listen("tcp", ":0") 1100 case "https": 1101 proxy.listener, err = tls.Listen("tcp", ":0", tlsConfig) 1102 default: 1103 log.Fatal("Unsupported proto scheme", proto) 1104 } 1105 1106 if err != nil { 1107 log.Fatal(err) 1108 } 1109 1110 proxy.URL = proto + "://" + proxy.listener.Addr().String() 1111 1112 go proxy.server.Serve(proxy.listener) 1113 1114 return proxy 1115 } 1116 1117 func GenerateTestBinaryData() (buf *bytes.Buffer) { 1118 buf = new(bytes.Buffer) 1119 type testData struct { 1120 a float32 1121 b float64 1122 c uint32 1123 } 1124 for i := 0; i < 10; i++ { 1125 s := &testData{rand.Float32(), rand.Float64(), rand.Uint32()} 1126 binary.Write(buf, binary.BigEndian, s) 1127 } 1128 return buf 1129 } 1130 1131 // openssl genrsa -out app.rsa 1132 const jwtRSAPrivKey = ` 1133 -----BEGIN RSA PRIVATE KEY----- 1134 MIIEpQIBAAKCAQEAyqZ4rwKF8qCExS7kpY4cnJa/37FMkJNkalZ3OuslLB0oRL8T 1135 4c94kdF4aeNzSFkSe2n99IBI6Ssl79vbfMZb+t06L0Q94k+/P37x7+/RJZiff4y1 1136 VGjrnrnMI2iu9l4iBBRYzNmG6eblroEMMWlgk5tysHgxB59CSNIcD9gqk1hx4n/F 1137 gOmvKsfQgWHNlPSDTRcWGWGhB2/XgNVYG2pOlQxAPqLhBHeqGTXBbPfGF9cHzixp 1138 sPr6GtbzPwhsQ/8bPxoJ7hdfn+rzztks3d6+HWURcyNTLRe0mjXjjee9Z6+gZ+H+ 1139 fS4pnP9tqT7IgU6ePUWTpjoiPtLexgsAa/ctjQIDAQABAoIBAECWvnBJRZgHQUn3 1140 oDiECup9wbnyMI0D7UVXObk1qSteP69pl1SpY6xWLyLQs7WjbhiXt7FuEc7/SaAh 1141 Wttx/W7/g8P85Bx1fmcmdsYakXaCJpPorQKyTibQ4ReIDfvIFN9n/MWNr0ptpVbx 1142 GonFJFrneK52IGplgCLllLwYEbnULYcJc6E25Ro8U2gQjF2r43PDa07YiDrmB/GV 1143 QQW4HTo+CA9rdK0bP8GpXgc0wpmBhx/t/YdnDg6qhzyUMk9As7JrAzYPjHO0cRun 1144 vhA/aG/mdMmRumY75nj7wB5U5DgstsN2ER75Pjr1xe1knftIyNm15AShCPfLaLGo 1145 dA2IpwECgYEA5E8h6ssa7QroCGwp/N0wSJW41hFYGygbOEg6yPWTJkqmMZVduD8X 1146 /KFqJK4LcIbFQuR28+hWJpHm/RF1AMRhbbWkAj6h02gv5izFwDiFKev5paky4Evg 1147 G8WfUOmSZ1D+fVxwaoG0OaRZpCovUTxYig3xrI659DMeKqpQ7e8l9ekCgYEA4zql 1148 l4P4Dn0ydr+TI/s4NHIQHkaLQAVk3OWwyKowijXd8LCtuZRA1NKSpqQ4ZXi0B17o 1149 9zzF5jEUjws3qWv4PKWdxJu3y+h/etsg7wxUeNizbY2ooUGeMbk0tWxJihbgaI7E 1150 XxLIT50F3Ky4EJ2cUL9GmJ+gLCw0KIaVbkiyYAUCgYEA0WyVHB76r/2VIkS1rzHm 1151 HG7ageKfAyoi7dmzsqsxM6q+EDWHJn8Zra8TAlp0O+AkClwvkUTJ4c9sJy9gODfr 1152 dwtrSnPRVW74oRbovo4Z+H5xHbi65mwzQsZggYP/u63cA3pL1Cbt/wH3CFN52/aS 1153 8PAhg7vYb1yEi3Z3jgoUtCECgYEAhSPX4u9waQzyhKG7lVmdlR1AVH0BGoIOl1/+ 1154 NZWC23i0klLzd8lmM00uoHWYldwjoC38UuFJE5eudCIeeybITMC9sHWNO+z+xP2g 1155 TnDrDePrPkXCiLnp9ziNqb/JVyAQXTNJ3Gsk84EN7j9Fmna/IJDyzHq7XyaHaTdy 1156 VyxBWAECgYEA4jYS07bPx5UMhKiMJDqUmDfLNFD97XwPoJIkOdn6ezqeOSmlmo7t 1157 jxHLbCmsDOAsCU/0BlLXg9wMU7n5QKSlfTVGok/PU0rq2FUXQwyKGnellrqODwFQ 1158 YGivtXBGXk1hlVYlje1RB+W6RQuDAegI5h8vl8pYJS9JQH0wjatsDaE= 1159 -----END RSA PRIVATE KEY----- 1160 ` 1161 1162 const jwtECDSAPrivateKey = `-----BEGIN PRIVATE KEY----- 1163 MHcCAQEEIFjaz7TJpBOHmQttPypGRh3rqaXvRpsWE/EWUiLzc6veoAoGCCqGSM49 1164 AwEHoUQDQgAEDmKdIVHH9D5xkUiMJvo4T9H8yU+QYOIBlX5DYpJFtEvzTs4SsXYC 1165 tFsPk7c31tOpMuS8aQiLsXR82VMLqQBf1w== 1166 -----END PRIVATE KEY-----` 1167 1168 const jwtECDSAPublicKey = `-----BEGIN PUBLIC KEY----- 1169 MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDmKdIVHH9D5xkUiMJvo4T9H8yU+Q 1170 YOIBlX5DYpJFtEvzTs4SsXYCtFsPk7c31tOpMuS8aQiLsXR82VMLqQBf1w== 1171 -----END PUBLIC KEY-----` 1172 1173 const jwtSecret = "9879879878787878" 1174 const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 1175 1176 func randStringBytes(n int) string { 1177 b := make([]byte, n) 1178 1179 for i := range b { 1180 b[i] = letters[rand.Intn(len(letters))] 1181 } 1182 1183 return string(b) 1184 }