Skip to content

Commit bd62124

Browse files
committed
fix: transform underscores to hyphens for github login
Fixes #13339.
1 parent 79d73f7 commit bd62124

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
@@ -641,7 +641,15 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
641641
if user.ID == uuid.Nil {
642642
aReq.Action = database.AuditActionRegister
643643
}
644-
644+
// See: https://github.com/coder/coder/discussions/13340
645+
// In GitHub Enterprise, admins are permitted to have `_`
646+
// in their usernames. This is janky, but much better
647+
// than changing the username format globally.
648+
username := ghUser.GetLogin()
649+
if strings.Contains(username, "_") {
650+
api.Logger.Warn(ctx, "login associates a github username that contains underscores. underscores are not permitted in usernames, replacing with `-`", slog.F("username", username))
651+
username = strings.ReplaceAll(username, "_", "-")
652+
}
645653
params := (&oauthLoginParams{
646654
User: user,
647655
Link: link,
@@ -650,7 +658,7 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
650658
LoginType: database.LoginTypeGithub,
651659
AllowSignups: api.GithubOAuth2Config.AllowSignups,
652660
Email: verifiedEmail.GetEmail(),
653-
Username: ghUser.GetLogin(),
661+
Username: username,
654662
AvatarURL: ghUser.GetAvatarURL(),
655663
DebugContext: OauthDebugContext{},
656664
}).SetInitAuditRequest(func(params *audit.RequestParams) (*audit.Request[database.User], func()) {

coderd/userauth_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,50 @@ func TestUserOAuth2Github(t *testing.T) {
568568
require.Len(t, auditor.AuditLogs(), numLogs)
569569
require.Equal(t, database.AuditActionRegister, auditor.AuditLogs()[numLogs-1].Action)
570570
})
571+
t.Run("SignupReplaceUnderscores", func(t *testing.T) {
572+
t.Parallel()
573+
auditor := audit.NewMock()
574+
client := coderdtest.New(t, &coderdtest.Options{
575+
Auditor: auditor,
576+
GithubOAuth2Config: &coderd.GithubOAuth2Config{
577+
AllowSignups: true,
578+
AllowEveryone: true,
579+
OAuth2Config: &testutil.OAuth2Config{},
580+
ListOrganizationMemberships: func(_ context.Context, _ *http.Client) ([]*github.Membership, error) {
581+
return []*github.Membership{}, nil
582+
},
583+
TeamMembership: func(_ context.Context, _ *http.Client, _, _, _ string) (*github.Membership, error) {
584+
return nil, xerrors.New("no teams")
585+
},
586+
AuthenticatedUser: func(_ context.Context, _ *http.Client) (*github.User, error) {
587+
return &github.User{
588+
ID: github.Int64(100),
589+
Login: github.String("mathias_coder"),
590+
}, nil
591+
},
592+
ListEmails: func(_ context.Context, _ *http.Client) ([]*github.UserEmail, error) {
593+
return []*github.UserEmail{{
594+
Email: github.String("mathias@coder.com"),
595+
Verified: github.Bool(true),
596+
Primary: github.Bool(true),
597+
}}, nil
598+
},
599+
},
600+
})
601+
numLogs := len(auditor.AuditLogs())
602+
603+
resp := oauth2Callback(t, client)
604+
numLogs++ // add an audit log for login
605+
606+
require.Equal(t, http.StatusTemporaryRedirect, resp.StatusCode)
607+
require.Len(t, auditor.AuditLogs(), numLogs)
608+
require.Equal(t, database.AuditActionRegister, auditor.AuditLogs()[numLogs-1].Action)
609+
610+
client.SetSessionToken(authCookieValue(resp.Cookies()))
611+
user, err := client.User(context.Background(), "me")
612+
require.NoError(t, err)
613+
require.Equal(t, "mathias-coder", user.Username)
614+
})
571615
t.Run("SignupFailedInactiveInOrg", func(t *testing.T) {
572616
t.Parallel()
573617
client := coderdtest.New(t, &coderdtest.Options{

0 commit comments

Comments
 (0)