-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#2045 `auth` section now has new `validate_signature` boolean field, and `signature` section for configuring signature flow. Currently supports mashery signature validation modes `MasherySHA256` and `MasheryMD5`. ```json "auth": { "validate_signature": true, "signature": { "algorithm": "MasherySHA256", "header": "X-Signature", "secret": "secret", "allowed_clock_skew": 2 } } ``` "secret" field can hold dynamic values from meta or context, for example: "$tyk_meta.signature_secret". Additionally, you can override error code and message using: ``` "error_code": 403, "error_message": "your signature is invalid" ``` Benchmarks: ``` BenchmarkMasherySha256Sum_Hash-4 500000 2094 ns/op 208 B/op 4 allocs/op ```
- Loading branch information
Showing
7 changed files
with
343 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package signature_validator | ||
|
||
import ( | ||
"crypto/md5" | ||
"crypto/sha256" | ||
"strconv" | ||
) | ||
|
||
type Hasher interface { | ||
Name() string | ||
Hash(token string, sharedSecret string, timeStamp int64) []byte | ||
} | ||
|
||
type MasherySha256Sum struct{} | ||
|
||
func (m MasherySha256Sum) Name() string { | ||
return "MasherySHA256" | ||
} | ||
|
||
func (m MasherySha256Sum) Hash(token string, sharedSecret string, timeStamp int64) []byte { | ||
signature := sha256.Sum256([]byte(token + sharedSecret + strconv.FormatInt(timeStamp, 10))) | ||
|
||
return signature[:] | ||
} | ||
|
||
type MasheryMd5sum struct{} | ||
|
||
func (m MasheryMd5sum) Name() string { | ||
return "MasheryMD5" | ||
} | ||
|
||
func (m MasheryMd5sum) Hash(token string, sharedSecret string, timeStamp int64) []byte { | ||
signature := md5.Sum([]byte(token + sharedSecret + strconv.FormatInt(timeStamp, 10))) | ||
|
||
return signature[:] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package signature_validator | ||
|
||
import ( | ||
"encoding/hex" | ||
"testing" | ||
"time" | ||
) | ||
|
||
const ( | ||
token = "5bcef48a3f03d311ff27d156630baf849e3b438b8a48fec99239d5c9" | ||
sharedSecret = "foobar" | ||
now = 1546259837 | ||
) | ||
|
||
func TestMasherySha256Sum_Hash(t *testing.T) { | ||
expected := "fce2e80253cd438b666341176f34bde499116b63719e2482dae6965518ffd316" | ||
|
||
hasher := MasherySha256Sum{} | ||
hashed := hex.EncodeToString(hasher.Hash(token, sharedSecret, now)) | ||
|
||
if hashed != expected { | ||
t.Fatalf("expected %s, got %s", expected, hashed) | ||
} | ||
} | ||
|
||
func BenchmarkMasherySha256Sum_Hash(b *testing.B) { | ||
|
||
b.ReportAllocs() | ||
|
||
for n := 0; n < b.N; n++ { | ||
hasher := MasherySha256Sum{} | ||
hasher.Hash(token, sharedSecret, time.Now().Unix()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package signature_validator | ||
|
||
import ( | ||
"bytes" | ||
"encoding/hex" | ||
"errors" | ||
"fmt" | ||
"time" | ||
) | ||
|
||
type Validator interface { | ||
Init(hasherName string) error | ||
Validate(attempt, actual string, allowedClockSkew int64) error | ||
} | ||
|
||
type SignatureValidator struct { | ||
h Hasher | ||
} | ||
|
||
func (v *SignatureValidator) Init(hasherName string) error { | ||
switch hasherName { | ||
case "MasherySHA256": | ||
v.h = MasherySha256Sum{} | ||
case "MasheryMD5": | ||
v.h = MasheryMd5sum{} | ||
default: | ||
return errors.New(fmt.Sprintf("unsupported hasher type (%s)", hasherName)) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (v SignatureValidator) Validate(signature, key, secret string, allowedClockSkew int64) error { | ||
signatureBytes, _ := hex.DecodeString(signature) | ||
|
||
fmt.Println("Validating:", signature, key, secret) | ||
|
||
now := time.Now().Unix() | ||
for i := int64(0); i <= allowedClockSkew; i++ { | ||
if bytes.Equal(v.h.Hash(key, secret, now+i), signatureBytes) { | ||
return nil | ||
} | ||
|
||
if i == int64(0) { | ||
continue | ||
} | ||
|
||
if bytes.Equal(v.h.Hash(key, secret, now-i), signatureBytes) { | ||
return nil | ||
} | ||
} | ||
|
||
return errors.New("signature is not valid") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package signature_validator | ||
|
||
import ( | ||
"encoding/hex" | ||
"testing" | ||
"time" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
func TestValidateSignature_Init(t *testing.T) { | ||
|
||
type tt = struct { | ||
In string | ||
Error error | ||
} | ||
|
||
suite := []tt{ | ||
{"", errors.New("empty string in init")}, | ||
{"SomeJunk", errors.New("non existent")}, | ||
{"MasherySHA256", nil}, | ||
{"MasheryMD5", nil}, | ||
} | ||
|
||
for _, s := range suite { | ||
|
||
validator := SignatureValidator{} | ||
err := validator.Init(s.In) | ||
|
||
if err != nil && s.Error == nil { | ||
t.Errorf("expected success, got error %s", err.Error()) | ||
t.FailNow() | ||
} | ||
|
||
if err == nil && s.Error != nil { | ||
t.Errorf("expected error (%s), got success", s.Error.Error()) | ||
t.FailNow() | ||
} | ||
} | ||
} | ||
|
||
func TestValidateSignature_Validate(t *testing.T) { | ||
type tt struct { | ||
SignatureAttempt string | ||
Error error | ||
} | ||
|
||
allowedClockSkew := int64(100) | ||
|
||
suite := []tt{ | ||
{SignatureAttempt: "", Error: errors.New("should not pass with missing signature")}, | ||
{SignatureAttempt: "abcde", Error: errors.New("should not pass with incorrect signature")}, | ||
{SignatureAttempt: hex.EncodeToString(MasherySha256Sum{}.Hash(token, sharedSecret, time.Now().Unix()-101)), Error: errors.New("clock too slow")}, | ||
{SignatureAttempt: hex.EncodeToString(MasherySha256Sum{}.Hash(token, sharedSecret, time.Now().Unix()+101)), Error: errors.New("clock too fast")}, | ||
{SignatureAttempt: hex.EncodeToString(MasherySha256Sum{}.Hash(token, sharedSecret, time.Now().Unix())), Error: nil}, | ||
{SignatureAttempt: hex.EncodeToString(MasherySha256Sum{}.Hash(token, sharedSecret, time.Now().Unix()+99)), Error: nil}, | ||
{SignatureAttempt: hex.EncodeToString(MasherySha256Sum{}.Hash(token, sharedSecret, time.Now().Unix()-99)), Error: nil}, | ||
} | ||
|
||
validator := SignatureValidator{} | ||
_ = validator.Init("MasherySHA256") | ||
|
||
for _, s := range suite { | ||
err := validator.Validate(s.SignatureAttempt, token, sharedSecret, allowedClockSkew) | ||
if err != nil && s.Error == nil { | ||
t.Errorf("expected valid, got error %s", err.Error()) | ||
t.FailNow() | ||
} | ||
|
||
if err == nil && s.Error != nil { | ||
t.Errorf("expected error (%s), got valid", s.Error.Error()) | ||
t.FailNow() | ||
} | ||
} | ||
} |