Skip to content

Commit

Permalink
allow @ and Log if OIDC username is not consider valid (#2340)
Browse files Browse the repository at this point in the history
  • Loading branch information
kradalby authored Jan 16, 2025
1 parent 1ab7b31 commit 38aef77
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 4 deletions.
5 changes: 4 additions & 1 deletion hscontrol/types/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/hscontrol/util"
"github.com/rs/zerolog/log"
"google.golang.org/protobuf/types/known/timestamppb"
"gorm.io/gorm"
"tailscale.com/tailcfg"
Expand Down Expand Up @@ -173,9 +174,11 @@ func (c *OIDCClaims) Identifier() string {
// FromClaim overrides a User from OIDC claims.
// All fields will be updated, except for the ID.
func (u *User) FromClaim(claims *OIDCClaims) {
err := util.CheckForFQDNRules(claims.Username)
err := util.ValidateUsername(claims.Username)
if err == nil {
u.Name = claims.Username
} else {
log.Debug().Err(err).Msgf("Username %s is not valid", claims.Username)
}

if claims.EmailVerified {
Expand Down
37 changes: 34 additions & 3 deletions hscontrol/util/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/netip"
"regexp"
"strings"
"unicode"

"go4.org/netipx"
"tailscale.com/util/dnsname"
Expand All @@ -20,10 +21,40 @@ const (
LabelHostnameLength = 63
)

var invalidDNSRegex = regexp.MustCompile("[^a-z0-9-.]+")
var invalidCharsInUserRegex = regexp.MustCompile("[^a-z0-9-.]+")

var ErrInvalidUserName = errors.New("invalid user name")

func ValidateUsername(username string) error {
// Ensure the username meets the minimum length requirement
if len(username) < 2 {
return errors.New("username must be at least 2 characters long")
}

// Ensure the username does not start with a number
if unicode.IsDigit(rune(username[0])) {
return errors.New("username cannot start with a number")
}

atCount := 0
for _, char := range username {
switch {
case unicode.IsLetter(char), unicode.IsDigit(char), char == '-':
// Valid characters
case char == '@':
atCount++
if atCount > 1 {
return errors.New("username cannot contain more than one '@'")
}
default:
return fmt.Errorf("username contains invalid character: '%c'", char)
}
}

return nil
}

func CheckForFQDNRules(name string) error {
if len(name) > LabelHostnameLength {
return fmt.Errorf(
Expand All @@ -39,7 +70,7 @@ func CheckForFQDNRules(name string) error {
ErrInvalidUserName,
)
}
if invalidCharsInUserRegex.MatchString(name) {
if invalidDNSRegex.MatchString(name) {
return fmt.Errorf(
"DNS segment should only be composed of lowercase ASCII letters numbers, hyphen and dots. %v doesn't comply with theses rules: %w",
name,
Expand All @@ -52,7 +83,7 @@ func CheckForFQDNRules(name string) error {

func ConvertWithFQDNRules(name string) string {
name = strings.ToLower(name)
name = invalidCharsInUserRegex.ReplaceAllString(name, "")
name = invalidDNSRegex.ReplaceAllString(name, "")

return name
}
Expand Down Expand Up @@ -197,7 +228,7 @@ func NormalizeToFQDNRules(name string, stripEmailDomain bool) (string, error) {
} else {
name = strings.ReplaceAll(name, "@", ".")
}
name = invalidCharsInUserRegex.ReplaceAllString(name, "-")
name = invalidDNSRegex.ReplaceAllString(name, "-")

for _, elt := range strings.Split(name, ".") {
if len(elt) > LabelHostnameLength {
Expand Down

0 comments on commit 38aef77

Please sign in to comment.