fix: Use membership endpoint to ensure user exists in team (#3129)

This was using the incorrect GitHub endpoint prior, which fetched a team
by slug. Any user in a GitHub organization can view all teams, so this
didn't block signups like intended.

I've verified this API returns an error when the calling user is not a
member  of the team requested.

Fixes #3105.
This commit is contained in:
Kyle Carberry
2022-07-22 13:54:08 -05:00
committed by GitHub
parent 471564df7d
commit fd4954b4e5
3 changed files with 22 additions and 16 deletions

View File

@ -29,7 +29,7 @@ type GithubOAuth2Config struct {
AuthenticatedUser func(ctx context.Context, client *http.Client) (*github.User, error)
ListEmails func(ctx context.Context, client *http.Client) ([]*github.UserEmail, error)
ListOrganizationMemberships func(ctx context.Context, client *http.Client) ([]*github.Membership, error)
Team func(ctx context.Context, client *http.Client, org, team string) (*github.Team, error)
TeamMembership func(ctx context.Context, client *http.Client, org, team, username string) (*github.Membership, error)
AllowSignups bool
AllowOrganizations []string
@ -72,9 +72,18 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
return
}
ghUser, err := api.GithubOAuth2Config.AuthenticatedUser(r.Context(), oauthClient)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching authenticated Github user.",
Detail: err.Error(),
})
return
}
// The default if no teams are specified is to allow all.
if len(api.GithubOAuth2Config.AllowTeams) > 0 {
var allowedTeam *github.Team
var allowedTeam *github.Membership
for _, allowTeam := range api.GithubOAuth2Config.AllowTeams {
if allowTeam.Organization != *selectedMembership.Organization.Login {
// This needs to continue because multiple organizations
@ -82,7 +91,7 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
continue
}
allowedTeam, err = api.GithubOAuth2Config.Team(r.Context(), oauthClient, allowTeam.Organization, allowTeam.Slug)
allowedTeam, err = api.GithubOAuth2Config.TeamMembership(r.Context(), oauthClient, allowTeam.Organization, allowTeam.Slug, *ghUser.Login)
// The calling user may not have permission to the requested team!
if err != nil {
continue
@ -151,14 +160,6 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
// email to organization.
organizationID = organizations[0].ID
}
ghUser, err := api.GithubOAuth2Config.AuthenticatedUser(r.Context(), oauthClient)
if err != nil {
httpapi.Write(rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching authenticated Github user.",
Detail: err.Error(),
})
return
}
var verifiedEmail *github.UserEmail
for _, email := range emails {
if !email.GetPrimary() || !email.GetVerified() {

View File

@ -88,7 +88,12 @@ func TestUserOAuth2Github(t *testing.T) {
},
}}, nil
},
Team: func(ctx context.Context, client *http.Client, org, team string) (*github.Team, error) {
AuthenticatedUser: func(ctx context.Context, client *http.Client) (*github.User, error) {
return &github.User{
Login: github.String("kyle"),
}, nil
},
TeamMembership: func(ctx context.Context, client *http.Client, org, team, username string) (*github.Membership, error) {
return nil, xerrors.New("no perms")
},
},
@ -222,8 +227,8 @@ func TestUserOAuth2Github(t *testing.T) {
},
}}, nil
},
Team: func(ctx context.Context, client *http.Client, org, team string) (*github.Team, error) {
return &github.Team{}, nil
TeamMembership: func(ctx context.Context, client *http.Client, org, team, username string) (*github.Membership, error) {
return &github.Membership{}, nil
},
AuthenticatedUser: func(ctx context.Context, client *http.Client) (*github.User, error) {
return &github.User{