Skip to content

Commit ad47d16

Browse files
committed
server
1 parent 3f1d431 commit ad47d16

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)
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