Skip to content

Commit

Permalink
feat: add display name and uid for token info api (tkestack#300)
Browse files Browse the repository at this point in the history
  • Loading branch information
yadzhang committed Apr 24, 2020
1 parent 00587dc commit b62f5f2
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 30 deletions.
1 change: 1 addition & 0 deletions cmd/tke-gateway/app/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ func setupOIDCClient(oidcOpts *apiserveroptions.OIDCWithSecretOptions) (*oidc.Au
CAFile: oidcOpts.CAFile,
UsernameClaim: oidcOpts.UsernameClaim,
UsernamePrefix: oidcOpts.UsernamePrefix,
DisplayNameClaim: oidcOpts.DisplayNameClaim,
GroupsClaim: oidcOpts.GroupsClaim,
GroupsPrefix: oidcOpts.GroupsPrefix,
TenantIDClaim: oidcOpts.TenantIDClaim,
Expand Down
71 changes: 47 additions & 24 deletions pkg/apiserver/authentication/authenticator/oidc/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ const (
// TenantIDKey defines the key representing the tenant id in the additional
// information mapping table of the user information.
TenantIDKey = "tenantid"

// DisplayNameKey defines the key representing the user display name in the additional
// information mapping table of the user information.
DisplayNameKey = "displayname"
)

// Options defines the configuration options needed to initialize OpenID
Expand Down Expand Up @@ -94,6 +98,9 @@ type Options struct {
// the provided value. A value "oidc:" would result in usernames like "oidc:john".
UsernamePrefix string

// DisplayNameClaim is the JWT field to use as the user's display name.
DisplayNameClaim string

// GroupsClaim, if specified, causes the OIDCAuthenticator to try to populate the user's
// groups with an ID Token field. If the GroupsClaim field is present in an ID Token the value
// must be a string or list of strings.
Expand Down Expand Up @@ -135,18 +142,19 @@ func initVerifier(ctx context.Context, config *oidc.Config, issuer, externalIssu
// Authenticator checks a string value against a backing authentication store and
// returns a Response or an error if the token could not be checked.
type Authenticator struct {
IssuerURL string
usernameClaim string
usernamePrefix string
groupsClaim string
groupsPrefix string
tenantIDClaim string
tenantIDPrefix string
requiredClaims map[string]string
clientIDs authenticator.Audiences
apiAudiences authenticator.Audiences
verifier *oidc.IDTokenVerifier
resolver *claimResolver
IssuerURL string
usernameClaim string
usernamePrefix string
displayNameClaim string
groupsClaim string
groupsPrefix string
tenantIDClaim string
tenantIDPrefix string
requiredClaims map[string]string
clientIDs authenticator.Audiences
apiAudiences authenticator.Audiences
verifier *oidc.IDTokenVerifier
resolver *claimResolver
}

// New to create the Authenticator object by give options.
Expand Down Expand Up @@ -222,18 +230,19 @@ func New(opts *Options) (*Authenticator, error) {
}

a := &Authenticator{
IssuerURL: opts.ExternalIssuerURL,
usernameClaim: opts.UsernameClaim,
usernamePrefix: opts.UsernamePrefix,
groupsClaim: opts.GroupsClaim,
groupsPrefix: opts.GroupsPrefix,
tenantIDClaim: opts.TenantIDClaim,
tenantIDPrefix: opts.TenantIDPrefix,
requiredClaims: opts.RequiredClaims,
clientIDs: authenticator.Audiences{opts.ClientID},
apiAudiences: opts.APIAudiences,
verifier: verifier,
resolver: resolver,
IssuerURL: opts.ExternalIssuerURL,
usernameClaim: opts.UsernameClaim,
usernamePrefix: opts.UsernamePrefix,
displayNameClaim: opts.DisplayNameClaim,
groupsClaim: opts.GroupsClaim,
groupsPrefix: opts.GroupsPrefix,
tenantIDClaim: opts.TenantIDClaim,
tenantIDPrefix: opts.TenantIDPrefix,
requiredClaims: opts.RequiredClaims,
clientIDs: authenticator.Audiences{opts.ClientID},
apiAudiences: opts.APIAudiences,
verifier: verifier,
resolver: resolver,
}

return a, nil
Expand Down Expand Up @@ -543,6 +552,19 @@ func (a *Authenticator) AuthenticateToken(ctx context.Context, token string) (*a
Groups: make([]string, 0),
Extra: make(map[string][]string),
}

var displayName string
if a.displayNameClaim != "" {
if err := c.unmarshalClaim(a.displayNameClaim, &displayName); err != nil {
return nil, false, fmt.Errorf("oidc: parse displayName claims %q: %v", a.displayNameClaim, err)
}

if displayName != "" {
info.Extra[DisplayNameKey] = []string{displayName}
}
log.Info("displayName %+v", log.Any("extra", info.Extra))
}

if a.groupsClaim != "" {
if _, ok := c[a.groupsClaim]; ok {
// Some admins want to use string claims like "role" as the group value.
Expand Down Expand Up @@ -579,6 +601,7 @@ func (a *Authenticator) AuthenticateToken(ctx context.Context, token string) (*a
tenantID = a.tenantIDPrefix + tenantID
}
info.Extra[TenantIDKey] = []string{tenantID}
info.UID = federateIDClaim.UserID
}
}

Expand Down
18 changes: 13 additions & 5 deletions pkg/apiserver/options/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
flagOIDCExternalIssuerURL = "oidc-external-issuer-url"
flagOIDCUsernameClaim = "oidc-username-claim"
flagOIDCUsernamePrefix = "oidc-username-prefix"
flagOIDCDisplayNameClaim = "oidc-displayname-claim"
flagOIDCGroupsPrefix = "oidc-groups-prefix"
flagOIDCGroupsClaim = "oidc-groups-claim"
flagOIDCTenantIDClaim = "oidc-tenantid-claim"
Expand All @@ -46,6 +47,7 @@ const (
configOIDCExternalIssuerURL = "authentication.oidc.external_issuer_url"
configOIDCUsernameClaim = "authentication.oidc.username_claim"
configOIDCUsernamePrefix = "authentication.oidc.username_prefix"
configOIDCDisplayNameClaim = "authentication.oidc.displayname_claim"
configOIDCGroupsPrefix = "authentication.oidc.groups_prefix"
configOIDCGroupsClaim = "authentication.oidc.groups_claim"
configOIDCTenantIDClaim = "authentication.oidc.tenantid_claim"
Expand All @@ -64,6 +66,7 @@ type OIDCOptions struct {
ExternalIssuerURL string
UsernameClaim string
UsernamePrefix string
DisplayNameClaim string
GroupsClaim string
GroupsPrefix string
TenantIDClaim string
Expand All @@ -76,8 +79,9 @@ type OIDCOptions struct {
// NewOIDCOptions creates the default OIDCOptions object.
func NewOIDCOptions() *OIDCOptions {
return &OIDCOptions{
UsernameClaim: "sub",
SigningAlgs: []string{"RS256"},
UsernameClaim: "sub",
DisplayNameClaim: "preferred_username",
SigningAlgs: []string{"RS256"},
}
}

Expand All @@ -94,19 +98,22 @@ func (o *OIDCOptions) AddFlags(fs *pflag.FlagSet) {
"If set, the OpenID server's certificate will be verified by one of the authorities "+
"in the oidc-ca-file, otherwise the host's root CA set will be used.")
_ = viper.BindPFlag(configOIDCCAFile, fs.Lookup(flagOIDCCAFile))
fs.String(flagOIDCUsernameClaim, o.UsernameClaim, ""+
"The OpenID claim to use as the user name. Note that claims other than the default ('sub') "+
"is not guaranteed to be unique and immutable.")
fs.String(flagOIDCExternalIssuerURL, o.ExternalIssuerURL, ""+
"The URL of the OpenID external issuer, only HTTPS scheme will be accepted. "+
"is set, it will be used to verify issuer url with the OIDC provider, otherwise the oidc-issuer-url will be used.")
_ = viper.BindPFlag(configOIDCExternalIssuerURL, fs.Lookup(flagOIDCExternalIssuerURL))
fs.String(flagOIDCUsernameClaim, o.UsernameClaim, ""+
"The OpenID claim to use as the user name. Note that claims other than the default ('sub') "+
"is not guaranteed to be unique and immutable.")
_ = viper.BindPFlag(configOIDCUsernameClaim, fs.Lookup(flagOIDCUsernameClaim))
fs.String(flagOIDCUsernamePrefix, o.UsernamePrefix, ""+
"If provided, all usernames will be prefixed with this value. If not provided, "+
"username claims other than 'email' are prefixed by the issuer URL to avoid "+
"clashes. To skip any prefixing, provide the value '-'.")
_ = viper.BindPFlag(configOIDCUsernamePrefix, fs.Lookup(flagOIDCUsernamePrefix))
fs.String(flagOIDCDisplayNameClaim, o.DisplayNameClaim, ""+
"The OpenID claim to use as the user display name. Note that default claims is ('preferred_username')")
_ = viper.BindPFlag(configOIDCDisplayNameClaim, fs.Lookup(flagOIDCDisplayNameClaim))
fs.String(flagOIDCTenantIDClaim, o.TenantIDClaim,
"If provided, the name of a custom OpenID Connect claim for specifying user tenant id.")
_ = viper.BindPFlag(configOIDCTenantIDClaim, fs.Lookup(flagOIDCTenantIDClaim))
Expand Down Expand Up @@ -155,6 +162,7 @@ func (o *OIDCOptions) ApplyFlags() []error {
o.UsernameClaim = viper.GetString(configOIDCUsernameClaim)
o.UsernamePrefix = viper.GetString(configOIDCUsernamePrefix)
o.TokenReviewPath = viper.GetString(configOIDCTokenReviewPath)
o.DisplayNameClaim = viper.GetString(configOIDCDisplayNameClaim)

return errs
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func (p *localConnector) Login(ctx context.Context, scopes connector.Scopes, use
}

ident.Email = localIdentity.Spec.Email

ident.PreferredUsername = localIdentity.Spec.DisplayName
if emailVerified, ok := localIdentity.Spec.Extra["emailVerified"]; ok {
ident.EmailVerified, _ = strconv.ParseBool(emailVerified)
}
Expand Down

0 comments on commit b62f5f2

Please sign in to comment.