2fas-server/internal/pass/sign/lib_test.go
2024-04-30 15:58:48 +02:00

146 lines
3.1 KiB
Go

package sign
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"errors"
"testing"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/google/uuid"
)
type ecdsaSigningMethodWithStaticKey struct {
privateKey *ecdsa.PrivateKey
}
func (e ecdsaSigningMethodWithStaticKey) Verify(signingString string, sig []byte, key interface{}) error {
panic("not needed")
}
func (e ecdsaSigningMethodWithStaticKey) Sign(signingString string, key interface{}) ([]byte, error) {
return jwt.SigningMethodES256.Sign(signingString, e.privateKey)
}
func (e ecdsaSigningMethodWithStaticKey) Alg() string {
return jwt.SigningMethodES256.Alg()
}
func TestSignAndVerifyHappyPath(t *testing.T) {
srv := createTestService(t)
now := time.Now()
token, err := srv.SignAndEncode(Message{
ConnectionID: uuid.New().String(),
ExpiresAt: now.Add(time.Hour),
ConnectionType: ConnectionTypeBrowserExtensionProxy,
})
if err != nil {
t.Fatal(err)
}
_, err = srv.CanI(token, ConnectionTypeBrowserExtensionProxy)
if err != nil {
t.Fatal(err)
}
}
func createTestService(t *testing.T) Service {
t.Helper()
pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
srv := Service{
publicKey: &pk.PublicKey,
signingMethod: ecdsaSigningMethodWithStaticKey{
privateKey: pk,
},
}
return srv
}
func TestSignAndVerify(t *testing.T) {
srv := createTestService(t)
now := time.Now()
tests := []struct {
name string
tokenFn func() string
expectedError error
}{
{
name: "not even jwt token",
tokenFn: func() string {
return "xxx"
},
expectedError: jwt.ErrTokenMalformed,
},
{
name: "token is expired",
tokenFn: func() string {
token, err := srv.SignAndEncode(Message{
ConnectionID: uuid.New().String(),
ExpiresAt: now.Add(-time.Hour),
ConnectionType: ConnectionTypeBrowserExtensionProxy,
})
if err != nil {
t.Fatal(err)
}
return token
},
expectedError: jwt.ErrTokenExpired,
},
{
name: "invalid claim",
tokenFn: func() string {
token, err := srv.SignAndEncode(Message{
ConnectionID: uuid.New().String(),
ExpiresAt: now.Add(time.Hour),
ConnectionType: ConnectionTypeBrowserExtensionWait,
})
if err != nil {
t.Fatal(err)
}
return token
},
expectedError: ErrInvalidClaims,
},
{
name: "invalid signature",
tokenFn: func() string {
serviceWithAnotherKey := createTestService(t)
token, err := serviceWithAnotherKey.SignAndEncode(Message{
ConnectionID: uuid.New().String(),
ExpiresAt: now.Add(-time.Hour),
ConnectionType: ConnectionTypeBrowserExtensionProxy,
})
if err != nil {
t.Fatal(err)
}
return token
},
expectedError: jwt.ErrTokenSignatureInvalid,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
token := tc.tokenFn()
_, err := srv.CanI(token, ConnectionTypeBrowserExtensionProxy)
if err == nil {
t.Fatalf("Expected error %v, got nil", tc.expectedError)
}
if !errors.Is(err, tc.expectedError) {
t.Fatalf("Expected error %v, got %v", tc.expectedError, err)
}
})
}
}