Skip to content

feat: Add allowlist of GitHub teams for OAuth #2849

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

Merged
merged 3 commits into from
Jul 9, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Merge branch 'main' into githubteams
  • Loading branch information
kylecarbs committed Jul 9, 2022
commit ce18015b0b32e3d4e53b659a924e34c722d349b6
13 changes: 12 additions & 1 deletion cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -722,11 +722,22 @@ func configureTLS(listener net.Listener, tlsMinVersion, tlsClientAuth, tlsCertFi
return tls.NewListener(listener, tlsConfig), nil
}

func configureGithubOAuth2(accessURL *url.URL, clientID, clientSecret string, allowSignups bool, allowOrgs []string, allowTeams []string) (*coderd.GithubOAuth2Config, error) {
func configureGithubOAuth2(accessURL *url.URL, clientID, clientSecret string, allowSignups bool, allowOrgs []string, rawTeams []string) (*coderd.GithubOAuth2Config, error) {
redirectURL, err := accessURL.Parse("/api/v2/users/oauth2/github/callback")
if err != nil {
return nil, xerrors.Errorf("parse github oauth callback url: %w", err)
}
allowTeams := make([]coderd.GithubOAuth2Team, 0, len(rawTeams))
for _, rawTeam := range rawTeams {
parts := strings.SplitN(rawTeam, "/", 2)
if len(parts) != 2 {
return nil, xerrors.Errorf("github team allowlist is formatted incorrectly. got %s; wanted <organization>/<team>", rawTeam)
}
allowTeams = append(allowTeams, coderd.GithubOAuth2Team{
Organization: parts[0],
Slug: parts[1],
})
}
return &coderd.GithubOAuth2Config{
OAuth2Config: &oauth2.Config{
ClientID: clientID,
Expand Down
3 changes: 3 additions & 0 deletions coderd/database/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (

func TestNestedInTx(t *testing.T) {
t.Parallel()
if testing.Short() {
t.SkipNow()
}

uid := uuid.New()
sqlDB := testSQLDB(t)
Expand Down
23 changes: 10 additions & 13 deletions coderd/userauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"net/http"
"strings"

"github.com/google/go-github/v43/github"
"github.com/google/uuid"
Expand All @@ -18,6 +17,12 @@ import (
"github.com/coder/coder/codersdk"
)

// GithubOAuth2Team represents a team scoped to an organization.
type GithubOAuth2Team struct {
Organization string
Slug string
}

// GithubOAuth2Provider exposes required functions for the Github authentication flow.
type GithubOAuth2Config struct {
httpmw.OAuth2Config
Expand All @@ -28,7 +33,7 @@ type GithubOAuth2Config struct {

AllowSignups bool
AllowOrganizations []string
AllowTeams []string
AllowTeams []GithubOAuth2Team
}

func (api *API) userAuthMethods(rw http.ResponseWriter, _ *http.Request) {
Expand Down Expand Up @@ -80,21 +85,13 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {

var allowedTeam *github.Team
for _, team := range teams {
for _, organizationAndTeam := range api.GithubOAuth2Config.AllowTeams {
parts := strings.SplitN(organizationAndTeam, "/", 2)
if len(parts) != 2 {
httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{
Message: "Team allowlist isn't formatted correctly.",
Detail: fmt.Sprintf("Got %s, wanted <organization>/<team>", organizationAndTeam),
})
return
}
if parts[0] != *selectedMembership.Organization.Login {
for _, allowTeam := range api.GithubOAuth2Config.AllowTeams {
if allowTeam.Organization != *selectedMembership.Organization.Login {
// This needs to continue because multiple organizations
// could exist in the allow/team listings.
continue
}
if parts[1] != *team.Slug {
if allowTeam.Slug != *team.Slug {
continue
}
allowedTeam = team
Expand Down
4 changes: 2 additions & 2 deletions coderd/userauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func TestUserOAuth2Github(t *testing.T) {
client := coderdtest.New(t, &coderdtest.Options{
GithubOAuth2Config: &coderd.GithubOAuth2Config{
AllowOrganizations: []string{"coder"},
AllowTeams: []string{"another/something", "coder/frontend"},
AllowTeams: []coderd.GithubOAuth2Team{{"another", "something"}, {"coder", "frontend"}},
OAuth2Config: &oauth2Config{},
ListOrganizationMemberships: func(ctx context.Context, client *http.Client) ([]*github.Membership, error) {
return []*github.Membership{{
Expand Down Expand Up @@ -214,7 +214,7 @@ func TestUserOAuth2Github(t *testing.T) {
GithubOAuth2Config: &coderd.GithubOAuth2Config{
AllowSignups: true,
AllowOrganizations: []string{"coder"},
AllowTeams: []string{"coder/frontend"},
AllowTeams: []coderd.GithubOAuth2Team{{"coder", "frontend"}},
OAuth2Config: &oauth2Config{},
ListOrganizationMemberships: func(ctx context.Context, client *http.Client) ([]*github.Membership, error) {
return []*github.Membership{{
Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.