├── README.md ├── dispatcher.go ├── hooks.go ├── main.go └── manifest.json /README.md: -------------------------------------------------------------------------------- 1 | # Go plugin 2 | 3 | ## Plugin overview 4 | 5 | This repository provides a sample [Go](https://golang.org/) plugin for [Tyk](https://tyk.io). 6 | 7 | The project implements a simple middleware for header injection (MyPreHook), using a **Pre** hook (see [Tyk custom middleware hooks](https://tyk.io/docs/tyk-api-gateway-v1-9/javascript-plugins/middleware-scripting/)). An authentication hook is also provided (MyAuthCheck), see [hooks.go](hooks.go). 8 | 9 | ## Requirements 10 | 11 | Go compiler. 12 | 13 | ## Instructions 14 | 15 | After checking the requirements, clone this repository: 16 | 17 | ``` 18 | $ git clone https://github.com/TykTechnologies/tyk-plugin-demo-golang.git 19 | ``` 20 | 21 | Enter the plugin directory: 22 | 23 | ``` 24 | $ cd tyk-plugin-demo-golang 25 | ``` 26 | 27 | ## Building a bundle 28 | 29 | Go plugins are delivered as plugin bundles. The manifest file (`manifest.json`) contains the custom middleware definition. 30 | 31 | ``` 32 | $ tyk-cli bundle build 33 | ``` 34 | 35 | You may check the [tyk-cli documentation](https://github.com/TykTechnologies/tyk-cli) for additional options. 36 | 37 | -------------------------------------------------------------------------------- /dispatcher.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "golang.org/x/net/context" 7 | 8 | "github.com/TykTechnologies/tyk-protobuf/bindings/go" 9 | ) 10 | 11 | // Dispatcher implementation 12 | type Dispatcher struct{} 13 | 14 | // Dispatch will be called on every request: 15 | func (d *Dispatcher) Dispatch(ctx context.Context, object *coprocess.Object) (*coprocess.Object, error) { 16 | log.Println("Receiving object:", object) 17 | 18 | // We dispatch the object based on the hook name (as specified in the manifest file), these functions are in hooks.go: 19 | switch object.HookName { 20 | case "MyPreHook": 21 | log.Println("MyPreHook is called!") 22 | return MyPreHook(object) 23 | case "MyAuthCheck": 24 | log.Println("MyAuthCheck is called!") 25 | return MyAuthCheck(object) 26 | } 27 | 28 | log.Println("Unknown hook: ", object.HookName) 29 | 30 | return object, nil 31 | } 32 | 33 | // DispatchEvent will be called when a Tyk event is triggered: 34 | func (d *Dispatcher) DispatchEvent(ctx context.Context, event *coprocess.Event) (*coprocess.EventReply, error) { 35 | return &coprocess.EventReply{}, nil 36 | } 37 | -------------------------------------------------------------------------------- /hooks.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "time" 6 | 7 | "github.com/TykTechnologies/tyk-protobuf/bindings/go" 8 | ) 9 | 10 | // MyPreHook performs a header injection: 11 | func MyPreHook(object *coprocess.Object) (*coprocess.Object, error) { 12 | object.Request.SetHeaders = map[string]string{ 13 | "Myheader": "Myvalue", 14 | } 15 | 16 | return object, nil 17 | } 18 | 19 | // MyAuthCheck will initialize and return a valid session object if the authentication is ok: 20 | func MyAuthCheck(object *coprocess.Object) (*coprocess.Object, error) { 21 | authHeader := object.Request.Headers["Authorization"] 22 | 23 | validKey := "d29e8f389a6cf39a72bc7156c5e710885e4b5b89" 24 | 25 | // If the header value doesn't match our "valid key", we don't modify the object: 26 | if authHeader != validKey { 27 | log.Println("Bad authentication on MyAuthCheck") 28 | return object, nil 29 | } 30 | 31 | log.Println("Successful authentication on MyAuthCheck") 32 | 33 | // Set the ID extractor deadline, useful for caching valid keys: 34 | extractorDeadline := time.Now().Add(time.Hour * 1).Unix() 35 | 36 | // If the header value matches, the authentication is correct and we provide a session object: 37 | object.Session = &coprocess.SessionState{ 38 | Rate: 1000.0, 39 | Per: 1.0, 40 | QuotaMax: int64(1000), 41 | QuotaRenews: time.Now().Unix(), 42 | IdExtractorDeadline: extractorDeadline, 43 | } 44 | 45 | object.Metadata = map[string]string{ 46 | "token": validKey, 47 | } 48 | 49 | return object, nil 50 | } 51 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | 7 | "net/http" 8 | 9 | "github.com/TykTechnologies/tyk-protobuf/bindings/go" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | const ( 14 | ListenAddress = ":9111" 15 | ManifestAddress = ":8888" 16 | ) 17 | 18 | func main() { 19 | lis, err := net.Listen("tcp", ListenAddress) 20 | if err != nil { 21 | log.Fatalf("Failed to listen: %v", err) 22 | } 23 | 24 | log.Printf("starting grpc server on %v", ListenAddress) 25 | s := grpc.NewServer() 26 | coprocess.RegisterDispatcherServer(s, &Dispatcher{}) 27 | go s.Serve(lis) 28 | 29 | http.HandleFunc("/bundle.zip", func(w http.ResponseWriter, r *http.Request) { 30 | log.Println("received request for manifest") 31 | http.ServeFile(w, r, "bundle.zip") 32 | }) 33 | 34 | log.Printf("starting bundle manifest server on %v", ManifestAddress) 35 | log.Fatal(http.ListenAndServe(ManifestAddress, nil)) 36 | } 37 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_list": [ 3 | ], 4 | "custom_middleware": { 5 | "pre": [ 6 | { 7 | "name": "MyPreHook" 8 | } 9 | ], 10 | "auth_check": { 11 | "name": "MyAuthCheck" 12 | }, 13 | "driver": "grpc", 14 | "id_extractor": { 15 | "extract_from": "header", 16 | "extract_with": "value", 17 | "extractor_config": { 18 | "header_name": "Authorization" 19 | } 20 | } 21 | }, 22 | "checksum": "", 23 | "signature": "" 24 | } 25 | --------------------------------------------------------------------------------