-
Notifications
You must be signed in to change notification settings - Fork 881
chore: ensure github uids are unique #11826
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Github Oauth login matches on github user id, not their email
The test written still passes, will keep looking
coderd/userauth.go
Outdated
// If we have a nil GitHub ID, that is a big problem. That would mean we link | ||
// this user and all other users with this bug to the same uuid. | ||
// We should instead throw an error. This should never occur in production. | ||
// | ||
// Verified that the lowest ID on GitHub is "1", so 0 should never occur. | ||
if ghUser.GetID() == 0 { | ||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ | ||
Message: "The GitHub user returned an ID of 0, this should never happen. Please report this error.", | ||
// If this happens, the User could either be: | ||
// - Empty, in which case all these fields would also be empty. | ||
// - Not a user, in which case the "Type" would be something other than "User" | ||
Detail: fmt.Sprintf("Other user fields: name=%q, email=%q, type=%q", | ||
ghUser.GetName(), | ||
ghUser.GetEmail(), | ||
ghUser.GetType(), | ||
), | ||
}) | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the main change.
t.Run("ChangedEmail", func(t *testing.T) { | ||
t.Parallel() | ||
|
||
fake := oidctest.NewFakeIDP(t, | ||
oidctest.WithServing(), | ||
oidctest.WithCallbackPath("/api/v2/users/oauth2/github/callback"), | ||
) | ||
const ghID = int64(7777) | ||
auditor := audit.NewMock() | ||
coderEmail := &github.UserEmail{ | ||
Email: github.String("alice@coder.com"), | ||
Verified: github.Bool(true), | ||
Primary: github.Bool(true), | ||
} | ||
gmailEmail := &github.UserEmail{ | ||
Email: github.String("alice@gmail.com"), | ||
Verified: github.Bool(true), | ||
Primary: github.Bool(false), | ||
} | ||
emails := []*github.UserEmail{ | ||
gmailEmail, | ||
coderEmail, | ||
} | ||
|
||
client := coderdtest.New(t, &coderdtest.Options{ | ||
Auditor: auditor, | ||
GithubOAuth2Config: &coderd.GithubOAuth2Config{ | ||
AllowSignups: true, | ||
AllowEveryone: true, | ||
OAuth2Config: promoauth.NewFactory(prometheus.NewRegistry()).NewGithub("test-github", fake.OIDCConfig(t, []string{})), | ||
ListOrganizationMemberships: func(ctx context.Context, client *http.Client) ([]*github.Membership, error) { | ||
return []*github.Membership{}, nil | ||
}, | ||
TeamMembership: func(ctx context.Context, client *http.Client, org, team, username string) (*github.Membership, error) { | ||
return nil, xerrors.New("no teams") | ||
}, | ||
AuthenticatedUser: func(ctx context.Context, client *http.Client) (*github.User, error) { | ||
return &github.User{ | ||
Login: github.String("alice"), | ||
ID: github.Int64(ghID), | ||
}, nil | ||
}, | ||
ListEmails: func(ctx context.Context, client *http.Client) ([]*github.UserEmail, error) { | ||
return emails, nil | ||
}, | ||
}, | ||
}) | ||
|
||
ctx := testutil.Context(t, testutil.WaitMedium) | ||
// This should register the user | ||
client, _ = fake.Login(t, client, jwt.MapClaims{}) | ||
user, err := client.User(ctx, "me") | ||
require.NoError(t, err) | ||
userID := user.ID | ||
require.Equal(t, user.Email, *coderEmail.Email) | ||
|
||
// Now the user is registered, let's change their primary email. | ||
coderEmail.Primary = github.Bool(false) | ||
gmailEmail.Primary = github.Bool(true) | ||
|
||
client, _ = fake.Login(t, client, jwt.MapClaims{}) | ||
user, err = client.User(ctx, "me") | ||
require.NoError(t, err) | ||
require.Equal(t, user.ID, userID) | ||
require.Equal(t, user.Email, *gmailEmail.Email) | ||
|
||
// Entirely change emails. | ||
newEmail := "alice@newdomain.com" | ||
emails = []*github.UserEmail{ | ||
{ | ||
Email: github.String("alice@newdomain.com"), | ||
Primary: github.Bool(true), | ||
Verified: github.Bool(true), | ||
}, | ||
} | ||
client, _ = fake.Login(t, client, jwt.MapClaims{}) | ||
user, err = client.User(ctx, "me") | ||
require.NoError(t, err) | ||
require.Equal(t, user.ID, userID) | ||
require.Equal(t, user.Email, newEmail) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a change email unit test using the fake idp.
Detail: fmt.Sprintf("Other user fields: name=%q, email=%q, type=%q", | ||
ghUser.GetName(), | ||
ghUser.GetEmail(), | ||
ghUser.GetType(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this potentially leak another user's email? Would it be safer to log this instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No it cannot. This comes from the authenticated request to github using your oauth token.
So this payload comes from:
- User does github oauth flow with coder
- Oauth flow succeeds
- Coder uses their oauth token to determine to make a new user or link to an existing
- In this flow, the AuthentictedUser request fails from an
id=0
.
- In this flow, the AuthentictedUser request fails from an
To leak someone else email, you would need to authenticate as that user via github.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
What this does
If a github uid is nil, it is returned as
0
. If we link a user with this uid, then multiple users could potentially be considered the same user. We should reject this.I also added a unit test to test changing primary emails.
This was found when trying to debug #10972.