Skip to content

Commit c9cca9d

Browse files
authored
fix: transform underscores to hyphens for github login (coder#13384)
Fixes coder#13339.
1 parent 7958c52 commit c9cca9d

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

coderd/userauth.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,15 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
644644
if user.ID == uuid.Nil {
645645
aReq.Action = database.AuditActionRegister
646646
}
647-
647+
// See: https://github.com/coder/coder/discussions/13340
648+
// In GitHub Enterprise, admins are permitted to have `_`
649+
// in their usernames. This is janky, but much better
650+
// than changing the username format globally.
651+
username := ghUser.GetLogin()
652+
if strings.Contains(username, "_") {
653+
api.Logger.Warn(ctx, "login associates a github username that contains underscores. underscores are not permitted in usernames, replacing with `-`", slog.F("username", username))
654+
username = strings.ReplaceAll(username, "_", "-")
655+
}
648656
params := (&oauthLoginParams{
649657
User: user,
650658
Link: link,
@@ -653,7 +661,7 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
653661
LoginType: database.LoginTypeGithub,
654662
AllowSignups: api.GithubOAuth2Config.AllowSignups,
655663
Email: verifiedEmail.GetEmail(),
656-
Username: ghUser.GetLogin(),
664+
Username: username,
657665
AvatarURL: ghUser.GetAvatarURL(),
658666
Name: normName,
659667
DebugContext: OauthDebugContext{},

coderd/userauth_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,50 @@ func TestUserOAuth2Github(t *testing.T) {
665665
require.Len(t, auditor.AuditLogs(), numLogs)
666666
require.Equal(t, database.AuditActionRegister, auditor.AuditLogs()[numLogs-1].Action)
667667
})
668+
t.Run("SignupReplaceUnderscores", func(t *testing.T) {
669+
t.Parallel()
670+
auditor := audit.NewMock()
671+
client := coderdtest.New(t, &coderdtest.Options{
672+
Auditor: auditor,
673+
GithubOAuth2Config: &coderd.GithubOAuth2Config{
674+
AllowSignups: true,
675+
AllowEveryone: true,
676+
OAuth2Config: &testutil.OAuth2Config{},
677+
ListOrganizationMemberships: func(_ context.Context, _ *http.Client) ([]*github.Membership, error) {
678+
return []*github.Membership{}, nil
679+
},
680+
TeamMembership: func(_ context.Context, _ *http.Client, _, _, _ string) (*github.Membership, error) {
681+
return nil, xerrors.New("no teams")
682+
},
683+
AuthenticatedUser: func(_ context.Context, _ *http.Client) (*github.User, error) {
684+
return &github.User{
685+
ID: github.Int64(100),
686+
Login: github.String("mathias_coder"),
687+
}, nil
688+
},
689+
ListEmails: func(_ context.Context, _ *http.Client) ([]*github.UserEmail, error) {
690+
return []*github.UserEmail{{
691+
Email: github.String("mathias@coder.com"),
692+
Verified: github.Bool(true),
693+
Primary: github.Bool(true),
694+
}}, nil
695+
},
696+
},
697+
})
698+
numLogs := len(auditor.AuditLogs())
699+
700+
resp := oauth2Callback(t, client)
701+
numLogs++ // add an audit log for login
702+
703+
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
704+
require.Len(t, auditor.AuditLogs(), numLogs)
705+
require.Equal(t, database.AuditActionRegister, auditor.AuditLogs()[numLogs-1].Action)
706+
707+
client.SetSessionToken(authCookieValue(resp.Cookies()))
708+
user, err := client.User(context.Background(), "me")
709+
require.NoError(t, err)
710+
require.Equal(t, "mathias-coder", user.Username)
711+
})
668712
t.Run("SignupFailedInactiveInOrg", func(t *testing.T) {
669713
t.Parallel()
670714
client := coderdtest.New(t, &coderdtest.Options{

0 commit comments

Comments
 (0)