Skip to content

Commit f62e1ed

Browse files
authored
feat: Add support for GitHub Enterprise authentication (#3422)
This was manually tested with GitHub Enterprise v3.6.0-rc1.
1 parent 7bdb8ff commit f62e1ed

File tree

3 files changed

+88
-7
lines changed

3 files changed

+88
-7
lines changed

cli/server.go

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ func server() *cobra.Command {
8787
oauth2GithubAllowedOrganizations []string
8888
oauth2GithubAllowedTeams []string
8989
oauth2GithubAllowSignups bool
90+
oauth2GithubEnterpriseBaseURL string
9091
oidcAllowSignups bool
9192
oidcClientID string
9293
oidcClientSecret string
@@ -286,7 +287,7 @@ func server() *cobra.Command {
286287
}
287288

288289
if oauth2GithubClientSecret != "" {
289-
options.GithubOAuth2Config, err = configureGithubOAuth2(accessURLParsed, oauth2GithubClientID, oauth2GithubClientSecret, oauth2GithubAllowSignups, oauth2GithubAllowedOrganizations, oauth2GithubAllowedTeams)
290+
options.GithubOAuth2Config, err = configureGithubOAuth2(accessURLParsed, oauth2GithubClientID, oauth2GithubClientSecret, oauth2GithubAllowSignups, oauth2GithubAllowedOrganizations, oauth2GithubAllowedTeams, oauth2GithubEnterpriseBaseURL)
290291
if err != nil {
291292
return xerrors.Errorf("configure github oauth2: %w", err)
292293
}
@@ -695,6 +696,8 @@ func server() *cobra.Command {
695696
"Specifies teams inside organizations the user must be a member of to authenticate with GitHub. Formatted as: <organization-name>/<team-slug>.")
696697
cliflag.BoolVarP(root.Flags(), &oauth2GithubAllowSignups, "oauth2-github-allow-signups", "", "CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS", false,
697698
"Specifies whether new users can sign up with GitHub.")
699+
cliflag.StringVarP(root.Flags(), &oauth2GithubEnterpriseBaseURL, "oauth2-github-enterprise-base-url", "", "CODER_OAUTH2_GITHUB_ENTERPRISE_BASE_URL", "",
700+
"Specifies the base URL of a GitHub Enterprise instance to use for oauth2.")
698701
cliflag.BoolVarP(root.Flags(), &oidcAllowSignups, "oidc-allow-signups", "", "CODER_OIDC_ALLOW_SIGNUPS", true,
699702
"Specifies whether new users can sign up with OIDC.")
700703
cliflag.StringVarP(root.Flags(), &oidcClientID, "oidc-client-id", "", "CODER_OIDC_CLIENT_ID", "",
@@ -972,7 +975,7 @@ func configureTLS(listener net.Listener, tlsMinVersion, tlsClientAuth, tlsCertFi
972975
return tls.NewListener(listener, tlsConfig), nil
973976
}
974977

975-
func configureGithubOAuth2(accessURL *url.URL, clientID, clientSecret string, allowSignups bool, allowOrgs []string, rawTeams []string) (*coderd.GithubOAuth2Config, error) {
978+
func configureGithubOAuth2(accessURL *url.URL, clientID, clientSecret string, allowSignups bool, allowOrgs []string, rawTeams []string, enterpriseBaseURL string) (*coderd.GithubOAuth2Config, error) {
976979
redirectURL, err := accessURL.Parse("/api/v2/users/oauth2/github/callback")
977980
if err != nil {
978981
return nil, xerrors.Errorf("parse github oauth callback url: %w", err)
@@ -988,11 +991,38 @@ func configureGithubOAuth2(accessURL *url.URL, clientID, clientSecret string, al
988991
Slug: parts[1],
989992
})
990993
}
994+
createClient := func(client *http.Client) (*github.Client, error) {
995+
if enterpriseBaseURL != "" {
996+
return github.NewEnterpriseClient(enterpriseBaseURL, "", client)
997+
}
998+
return github.NewClient(client), nil
999+
}
1000+
1001+
endpoint := xgithub.Endpoint
1002+
if enterpriseBaseURL != "" {
1003+
enterpriseURL, err := url.Parse(enterpriseBaseURL)
1004+
if err != nil {
1005+
return nil, xerrors.Errorf("parse enterprise base url: %w", err)
1006+
}
1007+
authURL, err := enterpriseURL.Parse("/login/oauth/authorize")
1008+
if err != nil {
1009+
return nil, xerrors.Errorf("parse enterprise auth url: %w", err)
1010+
}
1011+
tokenURL, err := enterpriseURL.Parse("/login/oauth/access_token")
1012+
if err != nil {
1013+
return nil, xerrors.Errorf("parse enterprise token url: %w", err)
1014+
}
1015+
endpoint = oauth2.Endpoint{
1016+
AuthURL: authURL.String(),
1017+
TokenURL: tokenURL.String(),
1018+
}
1019+
}
1020+
9911021
return &coderd.GithubOAuth2Config{
9921022
OAuth2Config: &oauth2.Config{
9931023
ClientID: clientID,
9941024
ClientSecret: clientSecret,
995-
Endpoint: xgithub.Endpoint,
1025+
Endpoint: endpoint,
9961026
RedirectURL: redirectURL.String(),
9971027
Scopes: []string{
9981028
"read:user",
@@ -1004,15 +1034,27 @@ func configureGithubOAuth2(accessURL *url.URL, clientID, clientSecret string, al
10041034
AllowOrganizations: allowOrgs,
10051035
AllowTeams: allowTeams,
10061036
AuthenticatedUser: func(ctx context.Context, client *http.Client) (*github.User, error) {
1007-
user, _, err := github.NewClient(client).Users.Get(ctx, "")
1037+
api, err := createClient(client)
1038+
if err != nil {
1039+
return nil, err
1040+
}
1041+
user, _, err := api.Users.Get(ctx, "")
10081042
return user, err
10091043
},
10101044
ListEmails: func(ctx context.Context, client *http.Client) ([]*github.UserEmail, error) {
1011-
emails, _, err := github.NewClient(client).Users.ListEmails(ctx, &github.ListOptions{})
1045+
api, err := createClient(client)
1046+
if err != nil {
1047+
return nil, err
1048+
}
1049+
emails, _, err := api.Users.ListEmails(ctx, &github.ListOptions{})
10121050
return emails, err
10131051
},
10141052
ListOrganizationMemberships: func(ctx context.Context, client *http.Client) ([]*github.Membership, error) {
1015-
memberships, _, err := github.NewClient(client).Organizations.ListOrgMemberships(ctx, &github.ListOrgMembershipsOptions{
1053+
api, err := createClient(client)
1054+
if err != nil {
1055+
return nil, err
1056+
}
1057+
memberships, _, err := api.Organizations.ListOrgMemberships(ctx, &github.ListOrgMembershipsOptions{
10161058
State: "active",
10171059
ListOptions: github.ListOptions{
10181060
PerPage: 100,
@@ -1021,7 +1063,11 @@ func configureGithubOAuth2(accessURL *url.URL, clientID, clientSecret string, al
10211063
return memberships, err
10221064
},
10231065
TeamMembership: func(ctx context.Context, client *http.Client, org, teamSlug, username string) (*github.Membership, error) {
1024-
team, _, err := github.NewClient(client).Teams.GetTeamMembershipBySlug(ctx, org, teamSlug, username)
1066+
api, err := createClient(client)
1067+
if err != nil {
1068+
return nil, err
1069+
}
1070+
team, _, err := api.Teams.GetTeamMembershipBySlug(ctx, org, teamSlug, username)
10251071
return team, err
10261072
},
10271073
}, nil

cli/server_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,39 @@ func TestServer(t *testing.T) {
436436
cancelFunc()
437437
<-serverErr
438438
})
439+
t.Run("GitHubOAuth", func(t *testing.T) {
440+
t.Parallel()
441+
ctx, cancelFunc := context.WithCancel(context.Background())
442+
defer cancelFunc()
443+
444+
fakeRedirect := "https://fake-url.com"
445+
root, cfg := clitest.New(t,
446+
"server",
447+
"--in-memory",
448+
"--address", ":0",
449+
"--oauth2-github-client-id", "fake",
450+
"--oauth2-github-client-secret", "fake",
451+
"--oauth2-github-enterprise-base-url", fakeRedirect,
452+
)
453+
serverErr := make(chan error, 1)
454+
go func() {
455+
serverErr <- root.ExecuteContext(ctx)
456+
}()
457+
accessURL := waitAccessURL(t, cfg)
458+
client := codersdk.New(accessURL)
459+
client.HTTPClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
460+
return http.ErrUseLastResponse
461+
}
462+
githubURL, err := accessURL.Parse("/api/v2/users/oauth2/github")
463+
require.NoError(t, err)
464+
res, err := client.HTTPClient.Get(githubURL.String())
465+
require.NoError(t, err)
466+
fakeURL, err := res.Location()
467+
require.NoError(t, err)
468+
require.True(t, strings.HasPrefix(fakeURL.String(), fakeRedirect), fakeURL.String())
469+
cancelFunc()
470+
<-serverErr
471+
})
439472
}
440473

441474
func generateTLSCertificate(t testing.TB) (certPath, keyPath string) {

docs/install/auth.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ server:
2525
coder server --oauth2-github-allow-signups=true --oauth2-github-allowed-orgs="your-org" --oauth2-github-client-id="8d1...e05" --oauth2-github-client-secret="57ebc9...02c24c"
2626
```
2727

28+
> For GitHub Enterprise support, specify the `--oauth2-github-enterprise-base-url` flag.
29+
2830
Alternatively, if you are running Coder as a system service, you can achieve the
2931
same result as the command above by adding the following environment variables
3032
to the `/etc/coder.d/coder.env` file:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy