* Chore: Update authlib * exclude incompatible version of github.com/grafana/gomemcache * Update go-jose to v4 * fix jose imports * remove jose v3 from go.mod * fix tests * fix serialize * fix failing live tests * add v1 of ES256 testkeys. Port tests to use ES256 instead of HS256 * accept more signature algs for okta and azuread * azure social graph token sig * accept more signature algs for oauth refresh and jwt auth * update workspace * add a static signer for inproc * rebase and fix ext_jwt * fix jwt tests * apply alex patch on gomemcache * update linting * fix ext_jwt panic * update workspaces --------- Co-authored-by: Jo Garnier <git@jguer.space>
127 lines
2.8 KiB
Go
127 lines
2.8 KiB
Go
package identity_test
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/go-jose/go-jose/v4"
|
|
"github.com/go-jose/go-jose/v4/jwt"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
|
)
|
|
|
|
func TestIsIDTokenExpired(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
token func(t *testing.T) string
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "should return false when ID token is not set",
|
|
token: func(t *testing.T) string {
|
|
return ""
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "should return false when ID token is not expired",
|
|
token: func(t *testing.T) string {
|
|
expiration := time.Now().Add(time.Hour)
|
|
return createToken(t, &expiration)
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "should return true when ID token is expired",
|
|
token: func(t *testing.T) string {
|
|
expiration := time.Now().Add(-time.Hour)
|
|
return createToken(t, &expiration)
|
|
},
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "should return false when ID token has no expiry claim",
|
|
token: func(t *testing.T) string {
|
|
return createToken(t, nil)
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "should return false when ID token is malformed",
|
|
token: func(t *testing.T) string {
|
|
return "invalid.jwt.token"
|
|
},
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "should handle token that expires exactly now",
|
|
token: func(t *testing.T) string {
|
|
expiration := time.Now().Add(-time.Millisecond)
|
|
return createToken(t, &expiration)
|
|
},
|
|
expected: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
token := tt.token(t)
|
|
requester := &identity.StaticRequester{IDToken: token}
|
|
|
|
result := identity.IsIDTokenExpired(requester)
|
|
require.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
var testKey = decodePrivateKey([]byte(`
|
|
-----BEGIN EC PRIVATE KEY-----
|
|
MHcCAQEEID6lXWsmcv/UWn9SptjOThsy88cifgGIBj2Lu0M9I8tQoAoGCCqGSM49
|
|
AwEHoUQDQgAEsf6eNnNMNhl+q7jXsbdUf3ADPh248uoFUSSV9oBzgptyokHCjJz6
|
|
n6PKDm2W7i3S2+dAs5M5f3s7d8KiLjGZdQ==
|
|
-----END EC PRIVATE KEY-----
|
|
`))
|
|
|
|
func decodePrivateKey(data []byte) *ecdsa.PrivateKey {
|
|
block, _ := pem.Decode(data)
|
|
if block == nil {
|
|
panic("should include PEM block")
|
|
}
|
|
|
|
privateKey, err := x509.ParseECPrivateKey(block.Bytes)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("should be able to parse ec private key: %v", err))
|
|
}
|
|
if privateKey.Curve.Params().Name != "P-256" {
|
|
panic("should be valid private key")
|
|
}
|
|
|
|
return privateKey
|
|
}
|
|
|
|
func createToken(t *testing.T, exp *time.Time) string {
|
|
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.ES256, Key: testKey}, nil)
|
|
require.NoError(t, err)
|
|
|
|
claims := struct {
|
|
jwt.Claims
|
|
}{
|
|
Claims: jwt.Claims{
|
|
Subject: "test-user",
|
|
},
|
|
}
|
|
|
|
if exp != nil {
|
|
claims.Expiry = jwt.NewNumericDate(*exp)
|
|
}
|
|
|
|
token, err := jwt.Signed(signer).Claims(claims).Serialize()
|
|
require.NoError(t, err)
|
|
return token
|
|
}
|