feat: enable GitHub OAuth2 login by default on new deployments (#16662)

Third and final PR to address
https://github.com/coder/coder/issues/16230.

This PR enables GitHub OAuth2 login by default on new deployments.
Combined with https://github.com/coder/coder/pull/16629, this will allow
the first admin user to sign up with GitHub rather than email and
password.

We take care not to enable the default on deployments that would upgrade
to a Coder version with this change.

To disable the default provider an admin can set the
`CODER_OAUTH2_GITHUB_DEFAULT_PROVIDER` env variable to false.
This commit is contained in:
Hugo Dutka
2025-02-25 16:31:33 +01:00
committed by GitHub
parent 67d89bb102
commit d3a56ae3ef
25 changed files with 544 additions and 83 deletions

View File

@ -45,6 +45,8 @@ import (
"github.com/coder/coder/v2/cli/clitest"
"github.com/coder/coder/v2/cli/config"
"github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbgen"
"github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/coderd/database/migrations"
"github.com/coder/coder/v2/coderd/httpapi"
@ -306,6 +308,145 @@ func TestServer(t *testing.T) {
require.Less(t, numLines, 20)
})
t.Run("OAuth2GitHubDefaultProvider", func(t *testing.T) {
type testCase struct {
name string
githubDefaultProviderEnabled string
githubClientID string
githubClientSecret string
expectGithubEnabled bool
expectGithubDefaultProviderConfigured bool
createUserPreStart bool
createUserPostRestart bool
}
runGitHubProviderTest := func(t *testing.T, tc testCase) {
t.Parallel()
if !dbtestutil.WillUsePostgres() {
t.Skip("test requires postgres")
}
ctx, cancelFunc := context.WithCancel(testutil.Context(t, testutil.WaitLong))
defer cancelFunc()
dbURL, err := dbtestutil.Open(t)
require.NoError(t, err)
db, _ := dbtestutil.NewDB(t, dbtestutil.WithURL(dbURL))
if tc.createUserPreStart {
_ = dbgen.User(t, db, database.User{})
}
args := []string{
"server",
"--postgres-url", dbURL,
"--http-address", ":0",
"--access-url", "https://example.com",
}
if tc.githubClientID != "" {
args = append(args, fmt.Sprintf("--oauth2-github-client-id=%s", tc.githubClientID))
}
if tc.githubClientSecret != "" {
args = append(args, fmt.Sprintf("--oauth2-github-client-secret=%s", tc.githubClientSecret))
}
if tc.githubClientID != "" || tc.githubClientSecret != "" {
args = append(args, "--oauth2-github-allow-everyone")
}
if tc.githubDefaultProviderEnabled != "" {
args = append(args, fmt.Sprintf("--oauth2-github-default-provider-enable=%s", tc.githubDefaultProviderEnabled))
}
inv, cfg := clitest.New(t, args...)
errChan := make(chan error, 1)
go func() {
errChan <- inv.WithContext(ctx).Run()
}()
accessURLChan := make(chan *url.URL, 1)
go func() {
accessURLChan <- waitAccessURL(t, cfg)
}()
var accessURL *url.URL
select {
case err := <-errChan:
require.NoError(t, err)
case accessURL = <-accessURLChan:
require.NotNil(t, accessURL)
}
client := codersdk.New(accessURL)
authMethods, err := client.AuthMethods(ctx)
require.NoError(t, err)
require.Equal(t, tc.expectGithubEnabled, authMethods.Github.Enabled)
require.Equal(t, tc.expectGithubDefaultProviderConfigured, authMethods.Github.DefaultProviderConfigured)
cancelFunc()
select {
case err := <-errChan:
require.NoError(t, err)
case <-time.After(testutil.WaitLong):
t.Fatal("server did not exit")
}
if tc.createUserPostRestart {
_ = dbgen.User(t, db, database.User{})
}
// Ensure that it stays at that setting after the server restarts.
inv, cfg = clitest.New(t, args...)
clitest.Start(t, inv)
accessURL = waitAccessURL(t, cfg)
client = codersdk.New(accessURL)
ctx = testutil.Context(t, testutil.WaitLong)
authMethods, err = client.AuthMethods(ctx)
require.NoError(t, err)
require.Equal(t, tc.expectGithubEnabled, authMethods.Github.Enabled)
require.Equal(t, tc.expectGithubDefaultProviderConfigured, authMethods.Github.DefaultProviderConfigured)
}
for _, tc := range []testCase{
{
name: "NewDeployment",
expectGithubEnabled: true,
expectGithubDefaultProviderConfigured: true,
createUserPreStart: false,
createUserPostRestart: true,
},
{
name: "ExistingDeployment",
expectGithubEnabled: false,
expectGithubDefaultProviderConfigured: false,
createUserPreStart: true,
createUserPostRestart: false,
},
{
name: "ManuallyDisabled",
githubDefaultProviderEnabled: "false",
expectGithubEnabled: false,
expectGithubDefaultProviderConfigured: false,
},
{
name: "ConfiguredClientID",
githubClientID: "123",
expectGithubEnabled: true,
expectGithubDefaultProviderConfigured: false,
},
{
name: "ConfiguredClientSecret",
githubClientSecret: "456",
expectGithubEnabled: true,
expectGithubDefaultProviderConfigured: false,
},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
runGitHubProviderTest(t, tc)
})
}
})
// Validate that a warning is printed that it may not be externally
// reachable.
t.Run("LocalAccessURL", func(t *testing.T) {