diff --git a/gateway/host_checker_test.go b/gateway/host_checker_test.go index a7b383a9a72..4b591af042d 100644 --- a/gateway/host_checker_test.go +++ b/gateway/host_checker_test.go @@ -398,6 +398,8 @@ func TestTestCheckerTCPHosts_correct_answers_proxy_protocol(t *testing.T) { } func TestTestCheckerTCPHosts_correct_wrong_answers(t *testing.T) { + t.Skip() // TT-13861 + ts := StartTest(nil) defer ts.Close() diff --git a/internal/crypto/hash.go b/internal/crypto/hash.go new file mode 100644 index 00000000000..c57df46bf36 --- /dev/null +++ b/internal/crypto/hash.go @@ -0,0 +1,60 @@ +package crypto + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "hash" + + "github.com/sirupsen/logrus" + + "github.com/TykTechnologies/murmur3" +) + +const ( + HashSha256 = "sha256" + HashMurmur32 = "murmur32" + HashMurmur64 = "murmur64" + HashMurmur128 = "murmur128" +) + +func hashFunction(algorithm string) (hash.Hash, error) { + switch algorithm { + case HashSha256: + return sha256.New(), nil + case HashMurmur64: + return murmur3.New64(), nil + case HashMurmur128: + return murmur3.New128(), nil + case "", HashMurmur32: + return murmur3.New32(), nil + default: + return murmur3.New32(), fmt.Errorf("Unknown key hash function: %s. Falling back to murmur32.", algorithm) + } +} + +func HashStr(in string, withAlg ...string) string { + var algo string + if len(withAlg) > 0 && withAlg[0] != "" { + algo = withAlg[0] + } else { + algo = TokenHashAlgo(in) + } + + h, err := hashFunction(algo) + + if err != nil { + logrus.Error(err) + } + + h.Write([]byte(in)) + return hex.EncodeToString(h.Sum(nil)) +} + +func HashKey(in string, hashKey bool) string { + if !hashKey { + // Not hashing? Return the raw key + return in + } + return HashStr(in) +} diff --git a/internal/crypto/token.go b/internal/crypto/token.go new file mode 100644 index 00000000000..9e982eabe61 --- /dev/null +++ b/internal/crypto/token.go @@ -0,0 +1,91 @@ +package crypto + +import ( + "encoding/base64" + "encoding/hex" + "fmt" + "strings" + + "github.com/sirupsen/logrus" + + "github.com/buger/jsonparser" + + "github.com/TykTechnologies/tyk/internal/uuid" +) + +// `{"` in base64 +const B64JSONPrefix = "ey" + +const DefaultHashAlgorithm = "murmur64" + +const MongoBsonIdLength = 24 + +// GenerateToken generates a token. +// If hashing algorithm is empty, it uses legacy key generation. +func GenerateToken(orgID, keyID, hashAlgorithm string) (string, error) { + if keyID == "" { + keyID = uuid.NewHex() + } + + if hashAlgorithm != "" { + _, err := hashFunction(hashAlgorithm) + if err != nil { + hashAlgorithm = DefaultHashAlgorithm + } + + jsonToken := fmt.Sprintf(`{"org":"%s","id":"%s","h":"%s"}`, orgID, keyID, hashAlgorithm) + return base64.StdEncoding.EncodeToString([]byte(jsonToken)), err + } + + // Legacy keys + return orgID + keyID, nil +} + +func TokenHashAlgo(token string) string { + // Legacy tokens not b64 and not JSON records + if strings.HasPrefix(token, B64JSONPrefix) { + if jsonToken, err := base64.StdEncoding.DecodeString(token); err == nil { + hashAlgo, err := jsonparser.GetString(jsonToken, "h") + + if err != nil { + logrus.Error(err) + return "" + } + + return hashAlgo + } + } + + return "" +} + +func TokenID(token string) (id string, err error) { + jsonToken, err := base64.StdEncoding.DecodeString(token) + if err != nil { + return "", err + } + + return jsonparser.GetString(jsonToken, "id") +} + +func TokenOrg(token string) string { + if strings.HasPrefix(token, B64JSONPrefix) { + if jsonToken, err := base64.StdEncoding.DecodeString(token); err == nil { + // Checking error in case if it is a legacy token which just by accided has the same b64JSON prefix + if org, err := jsonparser.GetString(jsonToken, "org"); err == nil { + return org + } + } + } + + // 24 is mongo bson id length + if len(token) > MongoBsonIdLength { + newToken := token[:MongoBsonIdLength] + _, err := hex.DecodeString(newToken) + if err == nil { + return newToken + } + } + + return "" +} diff --git a/storage/alias.go b/storage/alias.go new file mode 100644 index 00000000000..539df2c0a04 --- /dev/null +++ b/storage/alias.go @@ -0,0 +1,24 @@ +package storage + +import ( + "github.com/TykTechnologies/tyk/internal/crypto" +) + +const ( + HashSha256 = crypto.HashSha256 + HashMurmur32 = crypto.HashMurmur32 + HashMurmur64 = crypto.HashMurmur64 + HashMurmur128 = crypto.HashMurmur128 +) + +var ( + HashStr = crypto.HashStr + HashKey = crypto.HashKey +) + +var ( + GenerateToken = crypto.GenerateToken + TokenHashAlgo = crypto.TokenHashAlgo + TokenID = crypto.TokenID + TokenOrg = crypto.TokenOrg +) diff --git a/storage/storage.go b/storage/storage.go index e4b889e18b6..34c9d1156d3 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -1,20 +1,9 @@ package storage import ( - "crypto/sha256" - "encoding/base64" - "encoding/hex" "errors" - "fmt" - "hash" - "strings" - "github.com/buger/jsonparser" - - "github.com/TykTechnologies/murmur3" logger "github.com/TykTechnologies/tyk/log" - - "github.com/TykTechnologies/tyk/internal/uuid" ) //go:generate mockgen -destination=./mock/storage.go -package mock . Handler @@ -26,8 +15,6 @@ var ErrKeyNotFound = errors.New("key not found") var ErrMDCBConnectionLost = errors.New("mdcb connection is lost") -const MongoBsonIdLength = 24 - // Handler is a standard interface to a storage backend, used by // AuthorisationManager to read and write key values to the backend type Handler interface { @@ -73,115 +60,3 @@ type AnalyticsHandler interface { SetExp(string, int64) error // Set key expiration GetExp(string) (int64, error) // Returns expiry of a key } - -const defaultHashAlgorithm = "murmur64" - -// If hashing algorithm is empty, use legacy key generation -func GenerateToken(orgID, keyID, hashAlgorithm string) (string, error) { - if keyID == "" { - keyID = uuid.NewHex() - } - - if hashAlgorithm != "" { - _, err := hashFunction(hashAlgorithm) - if err != nil { - hashAlgorithm = defaultHashAlgorithm - } - - jsonToken := fmt.Sprintf(`{"org":"%s","id":"%s","h":"%s"}`, orgID, keyID, hashAlgorithm) - return base64.StdEncoding.EncodeToString([]byte(jsonToken)), err - } - - // Legacy keys - return orgID + keyID, nil -} - -// `{"` in base64 -const B64JSONPrefix = "ey" - -func TokenHashAlgo(token string) string { - // Legacy tokens not b64 and not JSON records - if strings.HasPrefix(token, B64JSONPrefix) { - if jsonToken, err := base64.StdEncoding.DecodeString(token); err == nil { - hashAlgo, _ := jsonparser.GetString(jsonToken, "h") - return hashAlgo - } - } - - return "" -} - -// TODO: add checks -func TokenID(token string) (id string, err error) { - jsonToken, err := base64.StdEncoding.DecodeString(token) - if err != nil { - return "", err - } - - return jsonparser.GetString(jsonToken, "id") -} - -func TokenOrg(token string) string { - if strings.HasPrefix(token, B64JSONPrefix) { - if jsonToken, err := base64.StdEncoding.DecodeString(token); err == nil { - // Checking error in case if it is a legacy tooken which just by accided has the same b64JSON prefix - if org, err := jsonparser.GetString(jsonToken, "org"); err == nil { - return org - } - } - } - - // 24 is mongo bson id length - if len(token) > MongoBsonIdLength { - newToken := token[:MongoBsonIdLength] - _, err := hex.DecodeString(newToken) - if err == nil { - return newToken - } - } - - return "" -} - -var ( - HashSha256 = "sha256" - HashMurmur32 = "murmur32" - HashMurmur64 = "murmur64" - HashMurmur128 = "murmur128" -) - -func hashFunction(algorithm string) (hash.Hash, error) { - switch algorithm { - case HashSha256: - return sha256.New(), nil - case HashMurmur64: - return murmur3.New64(), nil - case HashMurmur128: - return murmur3.New128(), nil - case "", HashMurmur32: - return murmur3.New32(), nil - default: - return murmur3.New32(), fmt.Errorf("Unknown key hash function: %s. Falling back to murmur32.", algorithm) - } -} - -func HashStr(in string, withAlg ...string) string { - var algo string - if len(withAlg) > 0 && withAlg[0] != "" { - algo = withAlg[0] - } else { - algo = TokenHashAlgo(in) - } - - h, _ := hashFunction(algo) - h.Write([]byte(in)) - return hex.EncodeToString(h.Sum(nil)) -} - -func HashKey(in string, hashKey bool) string { - if !hashKey { - // Not hashing? Return the raw key - return in - } - return HashStr(in) -}