Skip to content

Commit a32366f

Browse files
committed
server
1 parent 639092f commit a32366f

File tree

1 file changed

+107
-41
lines changed

1 file changed

+107
-41
lines changed

cli/server.go

Lines changed: 107 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -677,24 +677,6 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
677677
}
678678
}
679679

680-
if vals.OAuth2.Github.ClientSecret != "" || vals.OAuth2.Github.DeviceFlow.Value() {
681-
options.GithubOAuth2Config, err = configureGithubOAuth2(
682-
oauthInstrument,
683-
vals.AccessURL.Value(),
684-
vals.OAuth2.Github.ClientID.String(),
685-
vals.OAuth2.Github.ClientSecret.String(),
686-
vals.OAuth2.Github.DeviceFlow.Value(),
687-
vals.OAuth2.Github.AllowSignups.Value(),
688-
vals.OAuth2.Github.AllowEveryone.Value(),
689-
vals.OAuth2.Github.AllowedOrgs,
690-
vals.OAuth2.Github.AllowedTeams,
691-
vals.OAuth2.Github.EnterpriseBaseURL.String(),
692-
)
693-
if err != nil {
694-
return xerrors.Errorf("configure github oauth2: %w", err)
695-
}
696-
}
697-
698680
// As OIDC clients can be confidential or public,
699681
// we should only check for a client id being set.
700682
// The underlying library handles the case of no
@@ -782,6 +764,20 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
782764
return xerrors.Errorf("set deployment id: %w", err)
783765
}
784766

767+
githubOAuth2ConfigParams, err := getGithubOAuth2ConfigParams(ctx, options.Database, vals)
768+
if err != nil {
769+
return xerrors.Errorf("get github oauth2 config params: %w", err)
770+
}
771+
if githubOAuth2ConfigParams != nil {
772+
options.GithubOAuth2Config, err = configureGithubOAuth2(
773+
oauthInstrument,
774+
githubOAuth2ConfigParams,
775+
)
776+
if err != nil {
777+
return xerrors.Errorf("configure github oauth2: %w", err)
778+
}
779+
}
780+
785781
options.RuntimeConfig = runtimeconfig.NewManager()
786782

787783
// This should be output before the logs start streaming.
@@ -1832,25 +1828,95 @@ func configureCAPool(tlsClientCAFile string, tlsConfig *tls.Config) error {
18321828
return nil
18331829
}
18341830

1835-
// TODO: convert the argument list to a struct, it's easy to mix up the order of the arguments
1836-
//
1831+
type githubOAuth2ConfigParams struct {
1832+
accessURL *url.URL
1833+
clientID string
1834+
clientSecret string
1835+
deviceFlow bool
1836+
allowSignups bool
1837+
allowEveryone bool
1838+
allowOrgs []string
1839+
rawTeams []string
1840+
enterpriseBaseURL string
1841+
}
1842+
1843+
func getGithubOAuth2ConfigParams(ctx context.Context, db database.Store, vals *codersdk.DeploymentValues) (*githubOAuth2ConfigParams, error) {
1844+
params := githubOAuth2ConfigParams{
1845+
accessURL: vals.AccessURL.Value(),
1846+
clientID: vals.OAuth2.Github.ClientID.String(),
1847+
clientSecret: vals.OAuth2.Github.ClientSecret.String(),
1848+
deviceFlow: vals.OAuth2.Github.DeviceFlow.Value(),
1849+
allowSignups: vals.OAuth2.Github.AllowSignups.Value(),
1850+
allowEveryone: vals.OAuth2.Github.AllowEveryone.Value(),
1851+
allowOrgs: vals.OAuth2.Github.AllowedOrgs.Value(),
1852+
rawTeams: vals.OAuth2.Github.AllowedTeams.Value(),
1853+
enterpriseBaseURL: vals.OAuth2.Github.EnterpriseBaseURL.String(),
1854+
}
1855+
1856+
// If the user manually configured the GitHub OAuth2 provider,
1857+
// we won't add the default configuration.
1858+
if params.clientID != "" || params.clientSecret != "" || params.enterpriseBaseURL != "" {
1859+
return &params, nil
1860+
}
1861+
1862+
// Check if the user manually disabled the default GitHub OAuth2 provider.
1863+
if !vals.OAuth2.Github.DefaultProvider.Value() {
1864+
return nil, nil //nolint:nilnil
1865+
}
1866+
1867+
// Check if the deployment is eligible for the default GitHub OAuth2 provider.
1868+
// We want to enable it only for new deployments, and avoid enabling it
1869+
// if a deployment was upgraded from an older version.
1870+
// nolint:gocritic // Requires system privileges
1871+
defaultEligible, err := db.GetOAuth2GithubDefaultEligible(dbauthz.AsSystemRestricted(ctx))
1872+
if err != nil && !errors.Is(err, sql.ErrNoRows) {
1873+
return nil, xerrors.Errorf("get github default eligible: %w", err)
1874+
}
1875+
defaultEligibleNotSet := errors.Is(err, sql.ErrNoRows)
1876+
1877+
if defaultEligibleNotSet {
1878+
// nolint:gocritic // User count requires system privileges
1879+
userCount, err := db.GetUserCount(dbauthz.AsSystemRestricted(ctx))
1880+
if err != nil {
1881+
return nil, xerrors.Errorf("get user count: %w", err)
1882+
}
1883+
// We check if a deployment is new by checking if it has any users.
1884+
defaultEligible = userCount == 0
1885+
// nolint:gocritic // Requires system privileges
1886+
if err := db.UpsertOAuth2GithubDefaultEligible(dbauthz.AsSystemRestricted(ctx), defaultEligible); err != nil {
1887+
return nil, xerrors.Errorf("upsert github default eligible: %w", err)
1888+
}
1889+
}
1890+
1891+
if !defaultEligible {
1892+
return nil, nil //nolint:nilnil
1893+
}
1894+
1895+
// TODO: before merging, change this to use Coder's client ID instead of my dev one.
1896+
params.clientID = "Iv23liSBHklRMBNx5lk9"
1897+
params.allowEveryone = true
1898+
params.deviceFlow = true
1899+
1900+
return &params, nil
1901+
}
1902+
18371903
//nolint:revive // Ignore flag-parameter: parameter 'allowEveryone' seems to be a control flag, avoid control coupling (revive)
1838-
func configureGithubOAuth2(instrument *promoauth.Factory, accessURL *url.URL, clientID, clientSecret string, deviceFlow, allowSignups, allowEveryone bool, allowOrgs []string, rawTeams []string, enterpriseBaseURL string) (*coderd.GithubOAuth2Config, error) {
1839-
redirectURL, err := accessURL.Parse("/api/v2/users/oauth2/github/callback")
1904+
func configureGithubOAuth2(instrument *promoauth.Factory, params *githubOAuth2ConfigParams) (*coderd.GithubOAuth2Config, error) {
1905+
redirectURL, err := params.accessURL.Parse("/api/v2/users/oauth2/github/callback")
18401906
if err != nil {
18411907
return nil, xerrors.Errorf("parse github oauth callback url: %w", err)
18421908
}
1843-
if allowEveryone && len(allowOrgs) > 0 {
1909+
if params.allowEveryone && len(params.allowOrgs) > 0 {
18441910
return nil, xerrors.New("allow everyone and allowed orgs cannot be used together")
18451911
}
1846-
if allowEveryone && len(rawTeams) > 0 {
1912+
if params.allowEveryone && len(params.rawTeams) > 0 {
18471913
return nil, xerrors.New("allow everyone and allowed teams cannot be used together")
18481914
}
1849-
if !allowEveryone && len(allowOrgs) == 0 {
1915+
if !params.allowEveryone && len(params.allowOrgs) == 0 {
18501916
return nil, xerrors.New("allowed orgs is empty: must specify at least one org or allow everyone")
18511917
}
1852-
allowTeams := make([]coderd.GithubOAuth2Team, 0, len(rawTeams))
1853-
for _, rawTeam := range rawTeams {
1918+
allowTeams := make([]coderd.GithubOAuth2Team, 0, len(params.rawTeams))
1919+
for _, rawTeam := range params.rawTeams {
18541920
parts := strings.SplitN(rawTeam, "/", 2)
18551921
if len(parts) != 2 {
18561922
return nil, xerrors.Errorf("github team allowlist is formatted incorrectly. got %s; wanted <organization>/<team>", rawTeam)
@@ -1862,8 +1928,8 @@ func configureGithubOAuth2(instrument *promoauth.Factory, accessURL *url.URL, cl
18621928
}
18631929

18641930
endpoint := xgithub.Endpoint
1865-
if enterpriseBaseURL != "" {
1866-
enterpriseURL, err := url.Parse(enterpriseBaseURL)
1931+
if params.enterpriseBaseURL != "" {
1932+
enterpriseURL, err := url.Parse(params.enterpriseBaseURL)
18671933
if err != nil {
18681934
return nil, xerrors.Errorf("parse enterprise base url: %w", err)
18691935
}
@@ -1882,8 +1948,8 @@ func configureGithubOAuth2(instrument *promoauth.Factory, accessURL *url.URL, cl
18821948
}
18831949

18841950
instrumentedOauth := instrument.NewGithub("github-login", &oauth2.Config{
1885-
ClientID: clientID,
1886-
ClientSecret: clientSecret,
1951+
ClientID: params.clientID,
1952+
ClientSecret: params.clientSecret,
18871953
Endpoint: endpoint,
18881954
RedirectURL: redirectURL.String(),
18891955
Scopes: []string{
@@ -1895,17 +1961,17 @@ func configureGithubOAuth2(instrument *promoauth.Factory, accessURL *url.URL, cl
18951961

18961962
createClient := func(client *http.Client, source promoauth.Oauth2Source) (*github.Client, error) {
18971963
client = instrumentedOauth.InstrumentHTTPClient(client, source)
1898-
if enterpriseBaseURL != "" {
1899-
return github.NewEnterpriseClient(enterpriseBaseURL, "", client)
1964+
if params.enterpriseBaseURL != "" {
1965+
return github.NewEnterpriseClient(params.enterpriseBaseURL, "", client)
19001966
}
19011967
return github.NewClient(client), nil
19021968
}
19031969

19041970
var deviceAuth *externalauth.DeviceAuth
1905-
if deviceFlow {
1971+
if params.deviceFlow {
19061972
deviceAuth = &externalauth.DeviceAuth{
19071973
Config: instrumentedOauth,
1908-
ClientID: clientID,
1974+
ClientID: params.clientID,
19091975
TokenURL: endpoint.TokenURL,
19101976
Scopes: []string{"read:user", "read:org", "user:email"},
19111977
CodeURL: endpoint.DeviceAuthURL,
@@ -1914,9 +1980,9 @@ func configureGithubOAuth2(instrument *promoauth.Factory, accessURL *url.URL, cl
19141980

19151981
return &coderd.GithubOAuth2Config{
19161982
OAuth2Config: instrumentedOauth,
1917-
AllowSignups: allowSignups,
1918-
AllowEveryone: allowEveryone,
1919-
AllowOrganizations: allowOrgs,
1983+
AllowSignups: params.allowSignups,
1984+
AllowEveryone: params.allowEveryone,
1985+
AllowOrganizations: params.allowOrgs,
19201986
AllowTeams: allowTeams,
19211987
AuthenticatedUser: func(ctx context.Context, client *http.Client) (*github.User, error) {
19221988
api, err := createClient(client, promoauth.SourceGitAPIAuthUser)
@@ -1955,15 +2021,15 @@ func configureGithubOAuth2(instrument *promoauth.Factory, accessURL *url.URL, cl
19552021
team, _, err := api.Teams.GetTeamMembershipBySlug(ctx, org, teamSlug, username)
19562022
return team, err
19572023
},
1958-
DeviceFlowEnabled: deviceFlow,
2024+
DeviceFlowEnabled: params.deviceFlow,
19592025
ExchangeDeviceCode: func(ctx context.Context, deviceCode string) (*oauth2.Token, error) {
1960-
if !deviceFlow {
2026+
if !params.deviceFlow {
19612027
return nil, xerrors.New("device flow is not enabled")
19622028
}
19632029
return deviceAuth.ExchangeDeviceCode(ctx, deviceCode)
19642030
},
19652031
AuthorizeDevice: func(ctx context.Context) (*codersdk.ExternalAuthDevice, error) {
1966-
if !deviceFlow {
2032+
if !params.deviceFlow {
19672033
return nil, xerrors.New("device flow is not enabled")
19682034
}
19692035
return deviceAuth.AuthorizeDevice(ctx)

0 commit comments

Comments
 (0)