Merge pull request #33332 from ericchiang/oidc-allow-string-as-group-claim

Automatic merge from submit-queue

oidc authenticator: allow string value as groups claim

Allow the group claim to be a single string instead of an array of
strings. This means the following claim

    {
      "role": "admin"
    }

Will be mapped to the groups

    ["admin"]

cc @kubernetes/sig-auth @mlbiam

closes #33290
This commit is contained in:
Kubernetes Submit Queue 2016-09-23 12:41:27 -07:00 committed by GitHub
commit 33eabe675b
3 changed files with 32 additions and 10 deletions

View File

@ -401,7 +401,7 @@ func (s *ServerRunOptions) AddUniversalFlags(fs *pflag.FlagSet) {
fs.StringVar(&s.OIDCGroupsClaim, "oidc-groups-claim", "", ""+
"If provided, the name of a custom OpenID Connect claim for specifying user groups. "+
"The claim value is expected to be an array of strings. This flag is experimental, "+
"The claim value is expected to be a string or array of strings. This flag is experimental, "+
"please see the authentication documentation for further details.")
fs.Var(&s.RuntimeConfig, "runtime-config", ""+

View File

@ -73,7 +73,7 @@ type OIDCOptions struct {
// GroupsClaim, if specified, causes the OIDCAuthenticator to try to populate the user's
// groups with a ID Token field. If the GrouppClaim field is present in a ID Token the value
// must be a list of strings.
// must be a string or list of strings.
GroupsClaim string
}
@ -251,10 +251,14 @@ func (a *OIDCAuthenticator) AuthenticateToken(value string) (user.Info, bool, er
if a.groupsClaim != "" {
groups, found, err := claims.StringsClaim(a.groupsClaim)
if err != nil {
// Custom claim is present, but isn't an array of strings.
return nil, false, fmt.Errorf("custom group claim contains invalid object: %v", err)
}
if found {
// Groups type is present but is not an array of strings, try to decode as a string.
group, _, err := claims.StringClaim(a.groupsClaim)
if err != nil {
// Custom claim is present, but isn't an array of strings or a string.
return nil, false, fmt.Errorf("custom group claim contains invalid type: %T", claims[a.groupsClaim])
}
info.Groups = []string{group}
} else if found {
info.Groups = groups
}
}

View File

@ -33,7 +33,7 @@ import (
oidctesting "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/oidc/testing"
)
func generateToken(t *testing.T, op *oidctesting.OIDCProvider, iss, sub, aud string, usernameClaim, value, groupsClaim string, groups []string, iat, exp time.Time) string {
func generateToken(t *testing.T, op *oidctesting.OIDCProvider, iss, sub, aud string, usernameClaim, value, groupsClaim string, groups interface{}, iat, exp time.Time) string {
signer := op.PrivKey.Signer()
claims := oidc.NewClaims(iss, sub, aud, iat, exp)
claims.Add(usernameClaim, value)
@ -49,15 +49,15 @@ func generateToken(t *testing.T, op *oidctesting.OIDCProvider, iss, sub, aud str
return jwt.Encode()
}
func generateGoodToken(t *testing.T, op *oidctesting.OIDCProvider, iss, sub, aud string, usernameClaim, value, groupsClaim string, groups []string) string {
func generateGoodToken(t *testing.T, op *oidctesting.OIDCProvider, iss, sub, aud string, usernameClaim, value, groupsClaim string, groups interface{}) string {
return generateToken(t, op, iss, sub, aud, usernameClaim, value, groupsClaim, groups, time.Now(), time.Now().Add(time.Hour))
}
func generateMalformedToken(t *testing.T, op *oidctesting.OIDCProvider, iss, sub, aud string, usernameClaim, value, groupsClaim string, groups []string) string {
func generateMalformedToken(t *testing.T, op *oidctesting.OIDCProvider, iss, sub, aud string, usernameClaim, value, groupsClaim string, groups interface{}) string {
return generateToken(t, op, iss, sub, aud, usernameClaim, value, groupsClaim, groups, time.Now(), time.Now().Add(time.Hour)) + "randombits"
}
func generateExpiredToken(t *testing.T, op *oidctesting.OIDCProvider, iss, sub, aud string, usernameClaim, value, groupsClaim string, groups []string) string {
func generateExpiredToken(t *testing.T, op *oidctesting.OIDCProvider, iss, sub, aud string, usernameClaim, value, groupsClaim string, groups interface{}) string {
return generateToken(t, op, iss, sub, aud, usernameClaim, value, groupsClaim, groups, time.Now().Add(-2*time.Hour), time.Now().Add(-1*time.Hour))
}
@ -239,6 +239,24 @@ func TestOIDCAuthentication(t *testing.T) {
true,
"",
},
{
// Group claim is a string rather than an array. Map that string to a single group.
"email",
"groups",
generateGoodToken(t, op, srv.URL, "client-foo", "client-foo", "email", "foo@example.com", "groups", "group1"),
&user.DefaultInfo{Name: "foo@example.com", Groups: []string{"group1"}},
true,
"",
},
{
// Group claim is not a string or array of strings. Throw out this as invalid.
"email",
"groups",
generateGoodToken(t, op, srv.URL, "client-foo", "client-foo", "email", "foo@example.com", "groups", 1),
nil,
false,
"custom group claim contains invalid type: float64",
},
{
"sub",
"",