Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TT-4354 Go plugins to support multiple Tyk versions #3873

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions gateway/cert_test.go
Expand Up @@ -6,9 +6,6 @@ import (
"crypto/x509/pkix"
"encoding/json"
"fmt"
"github.com/TykTechnologies/tyk/headers"
"github.com/TykTechnologies/tyk/storage"
"github.com/stretchr/testify/assert"
"io/ioutil"
"net"
"net/http"
Expand All @@ -20,6 +17,10 @@ import (
"testing"
"time"

"github.com/TykTechnologies/tyk/headers"
"github.com/TykTechnologies/tyk/storage"
"github.com/stretchr/testify/assert"

"github.com/TykTechnologies/tyk/user"

"github.com/TykTechnologies/tyk/apidef"
Expand Down
10 changes: 5 additions & 5 deletions gateway/handler_error.go
Expand Up @@ -24,11 +24,11 @@ const (
defaultTemplateFormat = "json"
defaultContentType = headers.ApplicationJSON

MsgAuthFieldMissing = "Authorization field missing"
MsgApiAccessDisallowed = "Access to this API has been disallowed"
MsgBearerMailformed = "Bearer token malformed"
MsgKeyNotAuthorized = "Key not authorised"
MsgOauthClientRevoked = "Key not authorised. OAuth client access was revoked"
MsgAuthFieldMissing = "Authorization field missing"
MsgApiAccessDisallowed = "Access to this API has been disallowed"
MsgBearerMailformed = "Bearer token malformed"
MsgKeyNotAuthorized = "Key not authorised"
MsgOauthClientRevoked = "Key not authorised. OAuth client access was revoked"
MsgKeyNotAuthorizedUnexpectedSigningMethod = "Key not authorized: Unexpected signing method"
)

Expand Down
29 changes: 29 additions & 0 deletions gateway/mw_go_plugin.go
Expand Up @@ -5,6 +5,9 @@ import (
"fmt"
"io/ioutil"
"net/http"
"path/filepath"
"runtime"
"strings"
"time"

"github.com/TykTechnologies/tyk/apidef"
Expand Down Expand Up @@ -122,6 +125,12 @@ func (m *GoPluginMiddleware) loadPlugin() bool {

// try to load plugin
var err error

if !FileExist(m.Path) {
// if the exact name doesn't exist then try to load it using tyk version
m.Path = m.goPluginFromTykVersion()
sredxny marked this conversation as resolved.
Show resolved Hide resolved
}

if m.handler, err = goplugin.GetHandler(m.Path, m.SymbolName); err != nil {
m.logger.WithError(err).Error("Could not load Go-plugin")
return false
Expand Down Expand Up @@ -218,3 +227,23 @@ func (m *GoPluginMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Reque

return
}

// goPluginFromTykVersion builds a name of plugin based on tyk version
// os and architecture. The structure of the plugin name looks like:
// {plugin-dir}/{plugin-name}_{GW-version}_{OS}_{arch}.so
func (m *GoPluginMiddleware) goPluginFromTykVersion() string {
if m.Path == "" {
return ""
}

pluginDir := filepath.Dir(m.Path)
// remove plugin extension to have the plugin's clean name
pluginName := strings.TrimSuffix(filepath.Base(m.Path), ".so")
os := runtime.GOOS
architecture := runtime.GOARCH

newPluginName := strings.Join([]string{pluginName, VERSION, os, architecture}, "_")
newPluginPath := pluginDir + "/" + newPluginName + ".so"

return newPluginPath
}
37 changes: 37 additions & 0 deletions gateway/mw_go_plugin_test.go
@@ -0,0 +1,37 @@
package gateway

import (
"fmt"
"runtime"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGoPluginFromTykVersion(t *testing.T) {
m := GoPluginMiddleware{
BaseMiddleware: BaseMiddleware{},
Path: "",
SymbolName: "test-symbol",
}

type testCase struct {
userDefinedName, inferredName string
}
os := runtime.GOOS
arch := runtime.GOARCH

matrix := []testCase{
{"plugin.so", fmt.Sprintf("./plugin_%v_%v_%v.so", VERSION, os, arch)},
{"/some/path/plugin.so", fmt.Sprintf("/some/path/plugin_%v_%v_%v.so", VERSION, os, arch)},
{"/some/path/plugin", fmt.Sprintf("/some/path/plugin_%v_%v_%v.so", VERSION, os, arch)},
{"./plugin.so", fmt.Sprintf("./plugin_%v_%v_%v.so", VERSION, os, arch)},
{"", ""},
}

for _, v := range matrix {
m.Path = v.userDefinedName
newPluginPath := m.goPluginFromTykVersion()
assert.Equal(t, v.inferredName, newPluginPath)
}
}
2 changes: 1 addition & 1 deletion gateway/mw_jwt.go
Expand Up @@ -731,7 +731,7 @@ func (k *JWTMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, _
switch k.Spec.JWTSigningMethod {
case HMACSign:
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf( "%v: %v and not HMAC signature", UnexpectedSigningMethod, token.Header["alg"])
return nil, fmt.Errorf("%v: %v and not HMAC signature", UnexpectedSigningMethod, token.Header["alg"])
}
case RSASign:
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
Expand Down
12 changes: 12 additions & 0 deletions gateway/util.go
@@ -1,5 +1,10 @@
package gateway

import (
"errors"
"os"
)

// appendIfMissing appends the given new item to the given slice.
func appendIfMissing(slice []string, newSlice ...string) []string {
for _, new := range newSlice {
Expand Down Expand Up @@ -87,3 +92,10 @@ func greaterThanInt(first, second int) bool {

return first > second
}

func FileExist(filepath string) bool {
if _, err := os.Stat(filepath); errors.Is(err, os.ErrNotExist) {
return false
}
return true
}