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 }