Chore: Update authlib (#110880)
* 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>
This commit is contained in:
@@ -6,7 +6,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
jose "github.com/go-jose/go-jose/v4"
|
||||
"github.com/go-jose/go-jose/v4/jwt"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/sync/singleflight"
|
||||
@@ -170,7 +171,7 @@ func (s *Service) SyncIDToken(ctx context.Context, identity *authn.Identity, _ *
|
||||
}
|
||||
|
||||
func (s *Service) extractTokenClaims(token string) (*authnlib.Claims[authnlib.IDTokenClaims], error) {
|
||||
parsed, err := jwt.ParseSigned(token)
|
||||
parsed, err := jwt.ParseSigned(token, []jose.SignatureAlgorithm{jose.ES256})
|
||||
if err != nil {
|
||||
s.metrics.failedTokenSigningCounter.Inc()
|
||||
return nil, err
|
||||
|
||||
@@ -2,14 +2,19 @@ package idimpl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/go-jose/go-jose/v3"
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"github.com/go-jose/go-jose/v4/jwt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
@@ -35,14 +40,38 @@ func Test_ProvideService(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
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 TestService_SignIdentity(t *testing.T) {
|
||||
signer := &idtest.FakeSigner{
|
||||
SignIDTokenFn: func(_ context.Context, claims *auth.IDClaims) (string, error) {
|
||||
key := []byte("key")
|
||||
s, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: key}, nil)
|
||||
s, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.ES256, Key: testKey}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
token, err := jwt.Signed(s).Claims(claims.Claims).Claims(claims.Rest).CompactSerialize()
|
||||
token, err := jwt.Signed(s).Claims(claims.Claims).Claims(claims.Rest).Serialize()
|
||||
require.NoError(t, err)
|
||||
|
||||
return token, nil
|
||||
@@ -73,7 +102,7 @@ func TestService_SignIdentity(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
parsed, err := jwt.ParseSigned(token)
|
||||
parsed, err := jwt.ParseSigned(token, []jose.SignatureAlgorithm{jose.ES256})
|
||||
require.NoError(t, err)
|
||||
|
||||
gotClaims := &auth.IDClaims{}
|
||||
|
||||
@@ -3,8 +3,8 @@ package idimpl
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-jose/go-jose/v3"
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"github.com/go-jose/go-jose/v4/jwt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/signingkeys"
|
||||
@@ -33,7 +33,7 @@ func (s *LocalSigner) SignIDToken(ctx context.Context, claims *auth.IDClaims) (s
|
||||
|
||||
builder := jwt.Signed(signer).Claims(&claims.Rest).Claims(claims.Claims)
|
||||
|
||||
token, err := builder.CompactSerialize()
|
||||
token, err := builder.Serialize()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
jose "github.com/go-jose/go-jose/v4"
|
||||
"github.com/go-jose/go-jose/v4/jwt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||
@@ -69,7 +70,8 @@ func (s *AuthService) Verify(ctx context.Context, strToken string) (map[string]a
|
||||
s.log.Debug("Parsing JSON Web Token")
|
||||
|
||||
strToken = sanitizeJWT(strToken)
|
||||
token, err := jwt.ParseSigned(strToken)
|
||||
token, err := jwt.ParseSigned(strToken, []jose.SignatureAlgorithm{jose.EdDSA, jose.HS256, jose.HS384,
|
||||
jose.HS512, jose.RS512, jose.RS256, jose.ES256, jose.ES384, jose.ES512, jose.PS256, jose.PS384, jose.PS512})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -106,7 +108,8 @@ func (s *AuthService) Verify(ctx context.Context, strToken string) (map[string]a
|
||||
// HasSubClaim checks if the provided JWT token contains a non-empty "sub" claim.
|
||||
// Returns true if it contains, otherwise returns false.
|
||||
func HasSubClaim(jwtToken string) bool {
|
||||
parsed, err := jwt.ParseSigned(sanitizeJWT(jwtToken))
|
||||
parsed, err := jwt.ParseSigned(sanitizeJWT(jwtToken), []jose.SignatureAlgorithm{jose.EdDSA, jose.HS256, jose.HS384,
|
||||
jose.HS512, jose.RS512, jose.RS256, jose.ES256, jose.ES384, jose.ES512, jose.PS256, jose.PS384, jose.PS512})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
jose "github.com/go-jose/go-jose/v3"
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
jose "github.com/go-jose/go-jose/v4"
|
||||
"github.com/go-jose/go-jose/v4/jwt"
|
||||
"github.com/madflojo/testcerts"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -454,10 +454,10 @@ func TestIntegrationClaimValidation(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = sc.authJWTSvc.Verify(sc.ctx, sign(t, key, jwt.Claims{Audience: []string{"foo"}}, nil))
|
||||
require.Error(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = sc.authJWTSvc.Verify(sc.ctx, sign(t, key, jwt.Claims{Audience: []string{"bar", "baz"}}, nil))
|
||||
require.Error(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = sc.authJWTSvc.Verify(sc.ctx, sign(t, key, jwt.Claims{Audience: []string{"baz"}}, nil))
|
||||
require.Error(t, err)
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
jose "github.com/go-jose/go-jose/v3"
|
||||
jose "github.com/go-jose/go-jose/v4"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-jose/go-jose/v3"
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
)
|
||||
|
||||
var rsaKeys [3]*rsa.PrivateKey
|
||||
|
||||
@@ -3,8 +3,8 @@ package jwt
|
||||
import (
|
||||
"testing"
|
||||
|
||||
jose "github.com/go-jose/go-jose/v3"
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
jose "github.com/go-jose/go-jose/v4"
|
||||
"github.com/go-jose/go-jose/v4/jwt"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -16,9 +16,9 @@ func sign(t *testing.T, key any, claims any, opts *jose.SignerOptions) string {
|
||||
if opts == nil {
|
||||
opts = &jose.SignerOptions{}
|
||||
}
|
||||
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.PS512, Key: key}, (opts).WithType("JWT"))
|
||||
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.RS256, Key: key}, (opts).WithType("JWT"))
|
||||
require.NoError(t, err)
|
||||
token, err := jwt.Signed(sig).Claims(claims).CompactSerialize()
|
||||
token, err := jwt.Signed(sig).Claims(claims).Serialize()
|
||||
require.NoError(t, err)
|
||||
return token
|
||||
}
|
||||
@@ -40,7 +40,7 @@ func signNone(t *testing.T, claims any) string {
|
||||
|
||||
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: "none", Key: noneSigner{}}, (&jose.SignerOptions{}).WithType("JWT"))
|
||||
require.NoError(t, err)
|
||||
token, err := jwt.Signed(sig).Claims(claims).CompactSerialize()
|
||||
token, err := jwt.Signed(sig).Claims(claims).Serialize()
|
||||
require.NoError(t, err)
|
||||
return token
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
"github.com/go-jose/go-jose/v4/jwt"
|
||||
)
|
||||
|
||||
func (s *AuthService) initClaimExpectations() error {
|
||||
@@ -35,13 +35,13 @@ func (s *AuthService) initClaimExpectations() error {
|
||||
case []any:
|
||||
for _, val := range value {
|
||||
if v, ok := val.(string); ok {
|
||||
s.expectRegistered.Audience = append(s.expectRegistered.Audience, v)
|
||||
s.expectRegistered.AnyAudience = append(s.expectRegistered.AnyAudience, v)
|
||||
} else {
|
||||
return fmt.Errorf("%q expectation contains value with invalid type %T, string expected", key, val)
|
||||
}
|
||||
}
|
||||
case string:
|
||||
s.expectRegistered.Audience = []string{value}
|
||||
s.expectRegistered.AnyAudience = []string{value}
|
||||
default:
|
||||
return fmt.Errorf("%q expectation has invalid type %T, array or string expected", key, value)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user