From 101b998b2154ec7c02f9692bcbdd00d11e155a9c Mon Sep 17 00:00:00 2001 From: Ventsislav Georgiev Date: Sun, 18 May 2025 16:03:08 +0300 Subject: [PATCH] feat(oidc): allow email prefix as username fallback --- CHANGELOG.md | 2 ++ hscontrol/types/users.go | 10 +++++++++- hscontrol/types/users_test.go | 22 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91a23a05..c128bea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # CHANGELOG ## Next +- OIDC: Fallback to using email prefix as username if is EmailVerified when + preferred_username is missing ### BREAKING diff --git a/hscontrol/types/users.go b/hscontrol/types/users.go index 6cd2c41a..740bfda7 100644 --- a/hscontrol/types/users.go +++ b/hscontrol/types/users.go @@ -273,7 +273,7 @@ func CleanIdentifier(identifier string) string { cleanParts = append(cleanParts, part) } } - + if len(cleanParts) == 0 { u.Path = "" } else { @@ -319,6 +319,14 @@ func (u *User) FromClaim(claims *OIDCClaims) { u.Name = claims.Username } else { log.Debug().Err(err).Msgf("Username %s is not valid", claims.Username) + + if claims.Email != "" && claims.EmailVerified { + emailParts := strings.Split(claims.Email, "@") + if len(emailParts) > 0 && emailParts[0] != "" { + u.Name = emailParts[0] + log.Debug().Msgf("Using email prefix %s as name", u.Name) + } + } } if claims.EmailVerified { diff --git a/hscontrol/types/users_test.go b/hscontrol/types/users_test.go index f36489a3..1d665bd9 100644 --- a/hscontrol/types/users_test.go +++ b/hscontrol/types/users_test.go @@ -307,6 +307,7 @@ func TestOIDCClaimsJSONToUser(t *testing.T) { want: User{ Provider: util.RegisterMethodOIDC, Email: "test@test.no", + Name: "test", // Expect email prefix to be used as fallback name ProviderIdentifier: sql.NullString{ String: "/test", Valid: true, @@ -325,6 +326,7 @@ func TestOIDCClaimsJSONToUser(t *testing.T) { want: User{ Provider: util.RegisterMethodOIDC, Email: "test2@test.no", + Name: "test2", // Expect email prefix to be used as fallback name ProviderIdentifier: sql.NullString{ String: "/test2", Valid: true, @@ -446,6 +448,26 @@ func TestOIDCClaimsJSONToUser(t *testing.T) { ProfilePicURL: "https://cdn.casbin.org/img/casbin.svg", }, }, + { + name: "empty-username-use-email-prefix", + jsonstr: ` +{ + "sub": "123456789", + "email": "johndoe@example.com", + "email_verified": true, + "iss": "https://auth.example.com" +} + `, + want: User{ + Provider: util.RegisterMethodOIDC, + Email: "johndoe@example.com", + Name: "johndoe", // Should use email prefix + ProviderIdentifier: sql.NullString{ + String: "https://auth.example.com/123456789", + Valid: true, + }, + }, + }, } for _, tt := range tests {