Default to "username" claim in jwtcachefiller
Signed-off-by: Margo Crawford <margaretc@vmware.com>
This commit is contained in:
parent
720bc7ae42
commit
05ab8f375e
@ -29,7 +29,7 @@ import (
|
|||||||
// These default values come from the way that the Supervisor issues and signs tokens. We make these
|
// These default values come from the way that the Supervisor issues and signs tokens. We make these
|
||||||
// the defaults for a JWTAuthenticator so that they can easily integrate with the Supervisor.
|
// the defaults for a JWTAuthenticator so that they can easily integrate with the Supervisor.
|
||||||
const (
|
const (
|
||||||
defaultUsernameClaim = "sub"
|
defaultUsernameClaim = "username"
|
||||||
defaultGroupsClaim = "groups"
|
defaultGroupsClaim = "groups"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -19,11 +19,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/square/go-jose.v2/jwt"
|
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"gopkg.in/square/go-jose.v2"
|
"gopkg.in/square/go-jose.v2"
|
||||||
|
"gopkg.in/square/go-jose.v2/jwt"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||||
@ -327,16 +326,17 @@ func TestController(t *testing.T) {
|
|||||||
goodSubject = "some-subject"
|
goodSubject = "some-subject"
|
||||||
group0 = "some-group-0"
|
group0 = "some-group-0"
|
||||||
group1 = "some-group-1"
|
group1 = "some-group-1"
|
||||||
|
goodUsername = "pinny123"
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, test := range testTableForAuthenticateTokenTests(
|
for _, test := range testTableForAuthenticateTokenTests(
|
||||||
t,
|
t,
|
||||||
goodSubject,
|
|
||||||
goodRSASigningKey,
|
goodRSASigningKey,
|
||||||
goodRSASigningAlgo,
|
goodRSASigningAlgo,
|
||||||
goodRSASigningKeyID,
|
goodRSASigningKeyID,
|
||||||
group0,
|
group0,
|
||||||
group1,
|
group1,
|
||||||
|
goodUsername,
|
||||||
) {
|
) {
|
||||||
test := test
|
test := test
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
@ -351,8 +351,9 @@ func TestController(t *testing.T) {
|
|||||||
IssuedAt: jwt.NewNumericDate(time.Now().Add(-time.Hour)),
|
IssuedAt: jwt.NewNumericDate(time.Now().Add(-time.Hour)),
|
||||||
}
|
}
|
||||||
var groups interface{}
|
var groups interface{}
|
||||||
|
username := goodUsername
|
||||||
if test.jwtClaims != nil {
|
if test.jwtClaims != nil {
|
||||||
test.jwtClaims(&wellKnownClaims, &groups)
|
test.jwtClaims(&wellKnownClaims, &groups, &username)
|
||||||
}
|
}
|
||||||
|
|
||||||
var signingKey interface{} = goodECSigningKey
|
var signingKey interface{} = goodECSigningKey
|
||||||
@ -362,7 +363,7 @@ func TestController(t *testing.T) {
|
|||||||
test.jwtSignature(&signingKey, &signingAlgo, &signingKID)
|
test.jwtSignature(&signingKey, &signingAlgo, &signingKID)
|
||||||
}
|
}
|
||||||
|
|
||||||
jwt := createJWT(t, signingKey, signingAlgo, signingKID, &wellKnownClaims, groups)
|
jwt := createJWT(t, signingKey, signingAlgo, signingKID, &wellKnownClaims, groups, username)
|
||||||
rsp, authenticated, err := cachedAuthenticator.AuthenticateToken(context.Background(), jwt)
|
rsp, authenticated, err := cachedAuthenticator.AuthenticateToken(context.Background(), jwt)
|
||||||
if test.wantErrorRegexp != "" {
|
if test.wantErrorRegexp != "" {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
@ -380,15 +381,15 @@ func TestController(t *testing.T) {
|
|||||||
|
|
||||||
func testTableForAuthenticateTokenTests(
|
func testTableForAuthenticateTokenTests(
|
||||||
t *testing.T,
|
t *testing.T,
|
||||||
goodSubject string,
|
|
||||||
goodRSASigningKey *rsa.PrivateKey,
|
goodRSASigningKey *rsa.PrivateKey,
|
||||||
goodRSASigningAlgo jose.SignatureAlgorithm,
|
goodRSASigningAlgo jose.SignatureAlgorithm,
|
||||||
goodRSASigningKeyID string,
|
goodRSASigningKeyID string,
|
||||||
group0 string,
|
group0 string,
|
||||||
group1 string,
|
group1 string,
|
||||||
|
goodUsername string,
|
||||||
) []struct {
|
) []struct {
|
||||||
name string
|
name string
|
||||||
jwtClaims func(wellKnownClaims *jwt.Claims, groups *interface{})
|
jwtClaims func(wellKnownClaims *jwt.Claims, groups *interface{}, username *string)
|
||||||
jwtSignature func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string)
|
jwtSignature func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string)
|
||||||
wantResponse *authenticator.Response
|
wantResponse *authenticator.Response
|
||||||
wantAuthenticated bool
|
wantAuthenticated bool
|
||||||
@ -396,7 +397,7 @@ func testTableForAuthenticateTokenTests(
|
|||||||
} {
|
} {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
jwtClaims func(wellKnownClaims *jwt.Claims, groups *interface{})
|
jwtClaims func(wellKnownClaims *jwt.Claims, groups *interface{}, username *string)
|
||||||
jwtSignature func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string)
|
jwtSignature func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string)
|
||||||
wantResponse *authenticator.Response
|
wantResponse *authenticator.Response
|
||||||
wantAuthenticated bool
|
wantAuthenticated bool
|
||||||
@ -406,7 +407,7 @@ func testTableForAuthenticateTokenTests(
|
|||||||
name: "good token without groups and with EC signature",
|
name: "good token without groups and with EC signature",
|
||||||
wantResponse: &authenticator.Response{
|
wantResponse: &authenticator.Response{
|
||||||
User: &user.DefaultInfo{
|
User: &user.DefaultInfo{
|
||||||
Name: goodSubject,
|
Name: goodUsername,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantAuthenticated: true,
|
wantAuthenticated: true,
|
||||||
@ -420,19 +421,19 @@ func testTableForAuthenticateTokenTests(
|
|||||||
},
|
},
|
||||||
wantResponse: &authenticator.Response{
|
wantResponse: &authenticator.Response{
|
||||||
User: &user.DefaultInfo{
|
User: &user.DefaultInfo{
|
||||||
Name: goodSubject,
|
Name: goodUsername,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantAuthenticated: true,
|
wantAuthenticated: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "good token with groups as array",
|
name: "good token with groups as array",
|
||||||
jwtClaims: func(_ *jwt.Claims, groups *interface{}) {
|
jwtClaims: func(_ *jwt.Claims, groups *interface{}, username *string) {
|
||||||
*groups = []string{group0, group1}
|
*groups = []string{group0, group1}
|
||||||
},
|
},
|
||||||
wantResponse: &authenticator.Response{
|
wantResponse: &authenticator.Response{
|
||||||
User: &user.DefaultInfo{
|
User: &user.DefaultInfo{
|
||||||
Name: goodSubject,
|
Name: goodUsername,
|
||||||
Groups: []string{group0, group1},
|
Groups: []string{group0, group1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -440,12 +441,12 @@ func testTableForAuthenticateTokenTests(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "good token with groups as string",
|
name: "good token with groups as string",
|
||||||
jwtClaims: func(_ *jwt.Claims, groups *interface{}) {
|
jwtClaims: func(_ *jwt.Claims, groups *interface{}, username *string) {
|
||||||
*groups = group0
|
*groups = group0
|
||||||
},
|
},
|
||||||
wantResponse: &authenticator.Response{
|
wantResponse: &authenticator.Response{
|
||||||
User: &user.DefaultInfo{
|
User: &user.DefaultInfo{
|
||||||
Name: goodSubject,
|
Name: goodUsername,
|
||||||
Groups: []string{group0},
|
Groups: []string{group0},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -453,26 +454,26 @@ func testTableForAuthenticateTokenTests(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "good token with nbf unset",
|
name: "good token with nbf unset",
|
||||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||||
claims.NotBefore = nil
|
claims.NotBefore = nil
|
||||||
},
|
},
|
||||||
wantResponse: &authenticator.Response{
|
wantResponse: &authenticator.Response{
|
||||||
User: &user.DefaultInfo{
|
User: &user.DefaultInfo{
|
||||||
Name: goodSubject,
|
Name: goodUsername,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantAuthenticated: true,
|
wantAuthenticated: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bad token with groups as map",
|
name: "bad token with groups as map",
|
||||||
jwtClaims: func(_ *jwt.Claims, groups *interface{}) {
|
jwtClaims: func(_ *jwt.Claims, groups *interface{}, username *string) {
|
||||||
*groups = map[string]string{"not an array": "or a string"}
|
*groups = map[string]string{"not an array": "or a string"}
|
||||||
},
|
},
|
||||||
wantErrorRegexp: "oidc: parse groups claim \"groups\": json: cannot unmarshal object into Go value of type string",
|
wantErrorRegexp: "oidc: parse groups claim \"groups\": json: cannot unmarshal object into Go value of type string",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bad token with wrong issuer",
|
name: "bad token with wrong issuer",
|
||||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||||
claims.Issuer = "wrong-issuer"
|
claims.Issuer = "wrong-issuer"
|
||||||
},
|
},
|
||||||
wantResponse: nil,
|
wantResponse: nil,
|
||||||
@ -480,39 +481,46 @@ func testTableForAuthenticateTokenTests(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bad token with no audience",
|
name: "bad token with no audience",
|
||||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||||
claims.Audience = nil
|
claims.Audience = nil
|
||||||
},
|
},
|
||||||
wantErrorRegexp: `oidc: verify token: oidc: expected audience "some-audience" got \[\]`,
|
wantErrorRegexp: `oidc: verify token: oidc: expected audience "some-audience" got \[\]`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bad token with wrong audience",
|
name: "bad token with wrong audience",
|
||||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||||
claims.Audience = []string{"wrong-audience"}
|
claims.Audience = []string{"wrong-audience"}
|
||||||
},
|
},
|
||||||
wantErrorRegexp: `oidc: verify token: oidc: expected audience "some-audience" got \["wrong-audience"\]`,
|
wantErrorRegexp: `oidc: verify token: oidc: expected audience "some-audience" got \["wrong-audience"\]`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bad token with nbf in the future",
|
name: "bad token with nbf in the future",
|
||||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||||
claims.NotBefore = jwt.NewNumericDate(time.Date(3020, 2, 3, 4, 5, 6, 7, time.UTC))
|
claims.NotBefore = jwt.NewNumericDate(time.Date(3020, 2, 3, 4, 5, 6, 7, time.UTC))
|
||||||
},
|
},
|
||||||
wantErrorRegexp: `oidc: verify token: oidc: current time .* before the nbf \(not before\) time: 3020-.*`,
|
wantErrorRegexp: `oidc: verify token: oidc: current time .* before the nbf \(not before\) time: 3020-.*`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bad token with exp in past",
|
name: "bad token with exp in past",
|
||||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||||
claims.Expiry = jwt.NewNumericDate(time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC))
|
claims.Expiry = jwt.NewNumericDate(time.Date(1, 2, 3, 4, 5, 6, 7, time.UTC))
|
||||||
},
|
},
|
||||||
wantErrorRegexp: `oidc: verify token: oidc: token is expired \(Token Expiry: 0001-02-02 20:12:08 -0752 LMT\)`,
|
wantErrorRegexp: `oidc: verify token: oidc: token is expired \(Token Expiry: 0001-02-02 20:12:08 -0752 LMT\)`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bad token without exp",
|
name: "bad token without exp",
|
||||||
jwtClaims: func(claims *jwt.Claims, _ *interface{}) {
|
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||||
claims.Expiry = nil
|
claims.Expiry = nil
|
||||||
},
|
},
|
||||||
wantErrorRegexp: `oidc: verify token: oidc: token is expired \(Token Expiry: 0001-01-01 00:00:00 \+0000 UTC\)`,
|
wantErrorRegexp: `oidc: verify token: oidc: token is expired \(Token Expiry: 0001-01-01 00:00:00 \+0000 UTC\)`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "token does not have username claim",
|
||||||
|
jwtClaims: func(claims *jwt.Claims, _ *interface{}, username *string) {
|
||||||
|
*username = ""
|
||||||
|
},
|
||||||
|
wantErrorRegexp: `oidc: parse username claims "username": claim not present`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "signing key is wrong",
|
name: "signing key is wrong",
|
||||||
jwtSignature: func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string) {
|
jwtSignature: func(key *interface{}, algo *jose.SignatureAlgorithm, kid *string) {
|
||||||
@ -560,6 +568,7 @@ func createJWT(
|
|||||||
kid string,
|
kid string,
|
||||||
claims *jwt.Claims,
|
claims *jwt.Claims,
|
||||||
groups interface{},
|
groups interface{},
|
||||||
|
username string,
|
||||||
) string {
|
) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@ -573,6 +582,9 @@ func createJWT(
|
|||||||
if groups != nil {
|
if groups != nil {
|
||||||
builder = builder.Claims(map[string]interface{}{"groups": groups})
|
builder = builder.Claims(map[string]interface{}{"groups": groups})
|
||||||
}
|
}
|
||||||
|
if username != "" {
|
||||||
|
builder = builder.Claims(map[string]interface{}{"username": username})
|
||||||
|
}
|
||||||
jwt, err := builder.CompactSerialize()
|
jwt, err := builder.CompactSerialize()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user