diff --git a/authority/provisioner/oidc.go b/authority/provisioner/oidc.go index c1bcc741..bb3745b7 100644 --- a/authority/provisioner/oidc.go +++ b/authority/provisioner/oidc.go @@ -376,31 +376,46 @@ func (o *OIDC) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "oidc.AuthorizeSSHSign") } - // Enforce an email claim + + if claims.Subject == "" { + return nil, errs.Unauthorized("oidc.AuthorizeSSHSign: failed to validate oidc token payload: subject not found") + } + + var data sshutil.TemplateData + var principals []string + if claims.Email == "" { - return nil, errs.Unauthorized("oidc.AuthorizeSSHSign: failed to validate oidc token payload: email not found") - } + // If email is empty, use the Subject claim instead to create minimal data for the template to use + data = sshutil.CreateTemplateData(sshutil.UserCert, claims.Subject, nil) + if v, err := unsafeParseSigned(token); err == nil { + data.SetToken(v) + } - // Get the identity using either the default identityFunc or one injected - // externally. Note that the PreferredUsername might be empty. - // TBD: Would preferred_username present a safety issue here? - iden, err := o.ctl.GetIdentity(ctx, claims.Email) - if err != nil { - return nil, errs.Wrap(http.StatusInternalServerError, err, "oidc.AuthorizeSSHSign") - } + principals = nil + } else { + // Get the identity using either the default identityFunc or one injected + // externally. Note that the PreferredUsername might be empty. + // TBD: Would preferred_username present a safety issue here? + iden, err := o.ctl.GetIdentity(ctx, claims.Email) + if err != nil { + return nil, errs.Wrap(http.StatusInternalServerError, err, "oidc.AuthorizeSSHSign") + } - // Certificate templates. - data := sshutil.CreateTemplateData(sshutil.UserCert, claims.Email, iden.Usernames) - if v, err := unsafeParseSigned(token); err == nil { - data.SetToken(v) - } - // Add custom extensions added in the identity function. - for k, v := range iden.Permissions.Extensions { - data.AddExtension(k, v) - } - // Add custom critical options added in the identity function. - for k, v := range iden.Permissions.CriticalOptions { - data.AddCriticalOption(k, v) + // Certificate templates. + data = sshutil.CreateTemplateData(sshutil.UserCert, claims.Email, iden.Usernames) + if v, err := unsafeParseSigned(token); err == nil { + data.SetToken(v) + } + // Add custom extensions added in the identity function. + for k, v := range iden.Permissions.Extensions { + data.AddExtension(k, v) + } + // Add custom critical options added in the identity function. + for k, v := range iden.Permissions.CriticalOptions { + data.AddCriticalOption(k, v) + } + + principals = iden.Usernames } // Use the default template unless no-templates are configured and email is @@ -429,7 +444,7 @@ func (o *OIDC) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption } else { signOptions = append(signOptions, sshCertOptionsValidator(SignSSHOptions{ CertType: SSHUserCert, - Principals: iden.Usernames, + Principals: principals, })) }