Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitbe40fa8

Browse files
committed
feat: Add allowlist of GitHub teams for OAuth
Fixes#2848.
1 parent4f1e9da commitbe40fa8

File tree

4 files changed

+123
-3
lines changed

4 files changed

+123
-3
lines changed

‎cli/cliflag/cliflag.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func StringArrayVarP(flagset *pflag.FlagSet, ptr *[]string, name string, shortha
4747
def=strings.Split(val,",")
4848
}
4949
}
50-
flagset.StringArrayVarP(ptr,name,shorthand,def,usage)
50+
flagset.StringArrayVarP(ptr,name,shorthand,def,fmtUsage(usage,env))
5151
}
5252

5353
// Uint8VarP sets a uint8 flag on the given flag set.

‎cli/server.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ func server() *cobra.Command {
8282
oauth2GithubClientIDstring
8383
oauth2GithubClientSecretstring
8484
oauth2GithubAllowedOrganizations []string
85+
oauth2GithubAllowedTeams []string
8586
oauth2GithubAllowSignupsbool
8687
telemetryEnablebool
8788
telemetryURLstring
@@ -264,7 +265,7 @@ func server() *cobra.Command {
264265
}
265266

266267
ifoauth2GithubClientSecret!="" {
267-
options.GithubOAuth2Config,err=configureGithubOAuth2(accessURLParsed,oauth2GithubClientID,oauth2GithubClientSecret,oauth2GithubAllowSignups,oauth2GithubAllowedOrganizations)
268+
options.GithubOAuth2Config,err=configureGithubOAuth2(accessURLParsed,oauth2GithubClientID,oauth2GithubClientSecret,oauth2GithubAllowSignups,oauth2GithubAllowedOrganizations,oauth2GithubAllowedTeams)
268269
iferr!=nil {
269270
returnxerrors.Errorf("configure github oauth2: %w",err)
270271
}
@@ -535,6 +536,8 @@ func server() *cobra.Command {
535536
"Specifies a client secret to use for oauth2 with GitHub.")
536537
cliflag.StringArrayVarP(root.Flags(),&oauth2GithubAllowedOrganizations,"oauth2-github-allowed-orgs","","CODER_OAUTH2_GITHUB_ALLOWED_ORGS",nil,
537538
"Specifies organizations the user must be a member of to authenticate with GitHub.")
539+
cliflag.StringArrayVarP(root.Flags(),&oauth2GithubAllowedTeams,"oauth2-github-allowed-teams","","CODER_OAUTH2_GITHUB_ALLOWED_TEAMS",nil,
540+
"Specifies teams inside organizations the user must be a member of to authenticate with GitHub. Formatted as: <organization-name>/<team-slug>.")
538541
cliflag.BoolVarP(root.Flags(),&oauth2GithubAllowSignups,"oauth2-github-allow-signups","","CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS",false,
539542
"Specifies whether new users can sign up with GitHub.")
540543
cliflag.BoolVarP(root.Flags(),&telemetryEnable,"telemetry","","CODER_TELEMETRY",true,"Specifies whether telemetry is enabled or not. Coder collects anonymized usage data to help improve our product.")
@@ -719,7 +722,7 @@ func configureTLS(listener net.Listener, tlsMinVersion, tlsClientAuth, tlsCertFi
719722
returntls.NewListener(listener,tlsConfig),nil
720723
}
721724

722-
funcconfigureGithubOAuth2(accessURL*url.URL,clientID,clientSecretstring,allowSignupsbool,allowOrgs []string) (*coderd.GithubOAuth2Config,error) {
725+
funcconfigureGithubOAuth2(accessURL*url.URL,clientID,clientSecretstring,allowSignupsbool,allowOrgs []string,allowTeams []string) (*coderd.GithubOAuth2Config,error) {
723726
redirectURL,err:=accessURL.Parse("/api/v2/users/oauth2/github/callback")
724727
iferr!=nil {
725728
returnnil,xerrors.Errorf("parse github oauth callback url: %w",err)
@@ -738,6 +741,7 @@ func configureGithubOAuth2(accessURL *url.URL, clientID, clientSecret string, al
738741
},
739742
AllowSignups:allowSignups,
740743
AllowOrganizations:allowOrgs,
744+
AllowTeams:allowTeams,
741745
AuthenticatedUser:func(ctx context.Context,client*http.Client) (*github.User,error) {
742746
user,_,err:=github.NewClient(client).Users.Get(ctx,"")
743747
returnuser,err
@@ -749,9 +753,18 @@ func configureGithubOAuth2(accessURL *url.URL, clientID, clientSecret string, al
749753
ListOrganizationMemberships:func(ctx context.Context,client*http.Client) ([]*github.Membership,error) {
750754
memberships,_,err:=github.NewClient(client).Organizations.ListOrgMemberships(ctx,&github.ListOrgMembershipsOptions{
751755
State:"active",
756+
ListOptions: github.ListOptions{
757+
PerPage:100,
758+
},
752759
})
753760
returnmemberships,err
754761
},
762+
ListTeams:func(ctx context.Context,client*http.Client,orgstring) ([]*github.Team,error) {
763+
teams,_,err:=github.NewClient(client).Teams.ListTeams(ctx,org,&github.ListOptions{
764+
PerPage:100,
765+
})
766+
returnteams,err
767+
},
755768
},nil
756769
}
757770

‎coderd/userauth.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"errors"
77
"fmt"
88
"net/http"
9+
"strings"
910

1011
"github.com/google/go-github/v43/github"
1112
"github.com/google/uuid"
@@ -23,9 +24,11 @@ type GithubOAuth2Config struct {
2324
AuthenticatedUserfunc(ctx context.Context,client*http.Client) (*github.User,error)
2425
ListEmailsfunc(ctx context.Context,client*http.Client) ([]*github.UserEmail,error)
2526
ListOrganizationMembershipsfunc(ctx context.Context,client*http.Client) ([]*github.Membership,error)
27+
ListTeamsfunc(ctx context.Context,client*http.Client,orgstring) ([]*github.Team,error)
2628

2729
AllowSignupsbool
2830
AllowOrganizations []string
31+
AllowTeams []string
2932
}
3033

3134
func (api*API)userAuthMethods(rw http.ResponseWriter,_*http.Request) {
@@ -64,6 +67,49 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) {
6467
return
6568
}
6669

70+
// The default if no teams are specified is to allow all.
71+
iflen(api.GithubOAuth2Config.AllowTeams)>0 {
72+
teams,err:=api.GithubOAuth2Config.ListTeams(r.Context(),oauthClient,*selectedMembership.Organization.Login)
73+
iferr!=nil {
74+
httpapi.Write(rw,http.StatusInternalServerError, httpapi.Response{
75+
Message:"Failed to fetch teams from GitHub.",
76+
Detail:err.Error(),
77+
})
78+
return
79+
}
80+
81+
varallowedTeam*github.Team
82+
for_,team:=rangeteams {
83+
for_,organizationAndTeam:=rangeapi.GithubOAuth2Config.AllowTeams {
84+
parts:=strings.SplitN(organizationAndTeam,"/",2)
85+
iflen(parts)!=2 {
86+
httpapi.Write(rw,http.StatusInternalServerError, httpapi.Response{
87+
Message:"Team allowlist isn't formatted correctly.",
88+
Detail:fmt.Sprintf("Got %s, wanted <organization>/<team>",organizationAndTeam),
89+
})
90+
return
91+
}
92+
ifparts[0]!=*selectedMembership.Organization.Login {
93+
// This needs to continue because multiple organizations
94+
// could exist in the allow/team listings.
95+
continue
96+
}
97+
ifparts[1]!=*team.Slug {
98+
continue
99+
}
100+
allowedTeam=team
101+
break
102+
}
103+
}
104+
105+
ifallowedTeam==nil {
106+
httpapi.Write(rw,http.StatusUnauthorized, httpapi.Response{
107+
Message:fmt.Sprintf("You aren't a member of an authorized team in the %s Github organization!",*selectedMembership.Organization.Login),
108+
})
109+
return
110+
}
111+
}
112+
67113
emails,err:=api.GithubOAuth2Config.ListEmails(r.Context(),oauthClient)
68114
iferr!=nil {
69115
httpapi.Write(rw,http.StatusInternalServerError, httpapi.Response{

‎coderd/userauth_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,30 @@ func TestUserOAuth2Github(t *testing.T) {
7373
resp:=oauth2Callback(t,client)
7474
require.Equal(t,http.StatusUnauthorized,resp.StatusCode)
7575
})
76+
t.Run("NotInAllowedTeam",func(t*testing.T) {
77+
t.Parallel()
78+
client:=coderdtest.New(t,&coderdtest.Options{
79+
GithubOAuth2Config:&coderd.GithubOAuth2Config{
80+
AllowOrganizations: []string{"coder"},
81+
AllowTeams: []string{"another/something","coder/frontend"},
82+
OAuth2Config:&oauth2Config{},
83+
ListOrganizationMemberships:func(ctx context.Context,client*http.Client) ([]*github.Membership,error) {
84+
return []*github.Membership{{
85+
Organization:&github.Organization{
86+
Login:github.String("coder"),
87+
},
88+
}},nil
89+
},
90+
ListTeams:func(ctx context.Context,client*http.Client,orgstring) ([]*github.Team,error) {
91+
return []*github.Team{{
92+
Slug:github.String("nope"),
93+
}},nil
94+
},
95+
},
96+
})
97+
resp:=oauth2Callback(t,client)
98+
require.Equal(t,http.StatusUnauthorized,resp.StatusCode)
99+
})
76100
t.Run("UnverifiedEmail",func(t*testing.T) {
77101
t.Parallel()
78102
client:=coderdtest.New(t,&coderdtest.Options{
@@ -184,6 +208,43 @@ func TestUserOAuth2Github(t *testing.T) {
184208
resp:=oauth2Callback(t,client)
185209
require.Equal(t,http.StatusTemporaryRedirect,resp.StatusCode)
186210
})
211+
t.Run("SignupAllowedTeam",func(t*testing.T) {
212+
t.Parallel()
213+
client:=coderdtest.New(t,&coderdtest.Options{
214+
GithubOAuth2Config:&coderd.GithubOAuth2Config{
215+
AllowSignups:true,
216+
AllowOrganizations: []string{"coder"},
217+
AllowTeams: []string{"coder/frontend"},
218+
OAuth2Config:&oauth2Config{},
219+
ListOrganizationMemberships:func(ctx context.Context,client*http.Client) ([]*github.Membership,error) {
220+
return []*github.Membership{{
221+
Organization:&github.Organization{
222+
Login:github.String("coder"),
223+
},
224+
}},nil
225+
},
226+
ListTeams:func(ctx context.Context,client*http.Client,orgstring) ([]*github.Team,error) {
227+
return []*github.Team{{
228+
Slug:github.String("frontend"),
229+
}},nil
230+
},
231+
AuthenticatedUser:func(ctx context.Context,client*http.Client) (*github.User,error) {
232+
return&github.User{
233+
Login:github.String("kyle"),
234+
},nil
235+
},
236+
ListEmails:func(ctx context.Context,client*http.Client) ([]*github.UserEmail,error) {
237+
return []*github.UserEmail{{
238+
Email:github.String("kyle@coder.com"),
239+
Verified:github.Bool(true),
240+
Primary:github.Bool(true),
241+
}},nil
242+
},
243+
},
244+
})
245+
resp:=oauth2Callback(t,client)
246+
require.Equal(t,http.StatusTemporaryRedirect,resp.StatusCode)
247+
})
187248
}
188249

189250
funcoauth2Callback(t*testing.T,client*codersdk.Client)*http.Response {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp