feat: Add OIDC authentication (#3314)

* feat: Add OIDC authentication

* Extract username into a separate package and add OIDC tests

* Add test case for invalid tokens

* Add test case for username as email

* Add OIDC to the frontend

* Improve comments from self-review

* Add authentication docs

* Add telemetry

* Update docs/install/auth.md

Co-authored-by: Ammar Bandukwala <ammar@ammar.io>

* Update docs/install/auth.md

Co-authored-by: Ammar Bandukwala <ammar@ammar.io>

* Remove username package

Co-authored-by: Ammar Bandukwala <ammar@ammar.io>
This commit is contained in:
Kyle Carberry
2022-07-31 23:05:35 -05:00
committed by GitHub
co-authored by Ammar Bandukwala
parent 8b17bf98ea
commit 3d0febdd90
28 changed files with 733 additions and 137 deletions
+53
View File
@@ -23,6 +23,7 @@ import (
"sync"
"time"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/coreos/go-systemd/daemon"
embeddedpostgres "github.com/fergusstrange/embedded-postgres"
"github.com/google/go-github/v43/github"
@@ -84,6 +85,12 @@ func server() *cobra.Command {
oauth2GithubAllowedOrganizations []string
oauth2GithubAllowedTeams []string
oauth2GithubAllowSignups bool
oidcAllowSignups bool
oidcClientID string
oidcClientSecret string
oidcEmailDomain string
oidcIssuerURL string
oidcScopes []string
telemetryEnable bool
telemetryURL string
tlsCertFile string
@@ -283,6 +290,38 @@ func server() *cobra.Command {
}
}
if oidcClientSecret != "" {
if oidcClientID == "" {
return xerrors.Errorf("OIDC client ID be set!")
}
if oidcIssuerURL == "" {
return xerrors.Errorf("OIDC issuer URL must be set!")
}
oidcProvider, err := oidc.NewProvider(ctx, oidcIssuerURL)
if err != nil {
return xerrors.Errorf("configure oidc provider: %w", err)
}
redirectURL, err := accessURLParsed.Parse("/api/v2/users/oidc/callback")
if err != nil {
return xerrors.Errorf("parse oidc oauth callback url: %w", err)
}
options.OIDCConfig = &coderd.OIDCConfig{
OAuth2Config: &oauth2.Config{
ClientID: oidcClientID,
ClientSecret: oidcClientSecret,
RedirectURL: redirectURL.String(),
Endpoint: oidcProvider.Endpoint(),
Scopes: oidcScopes,
},
Verifier: oidcProvider.Verifier(&oidc.Config{
ClientID: oidcClientID,
}),
EmailDomain: oidcEmailDomain,
AllowSignups: oidcAllowSignups,
}
}
if inMemoryDatabase {
options.Database = databasefake.New()
options.Pubsub = database.NewPubsubInMemory()
@@ -341,6 +380,8 @@ func server() *cobra.Command {
Logger: logger.Named("telemetry"),
URL: telemetryURL,
GitHubOAuth: oauth2GithubClientID != "",
OIDCAuth: oidcClientID != "",
OIDCIssuerURL: oidcIssuerURL,
Prometheus: promEnabled,
STUN: len(stunServers) != 0,
Tunnel: tunnel,
@@ -637,6 +678,18 @@ func server() *cobra.Command {
"Specifies teams inside organizations the user must be a member of to authenticate with GitHub. Formatted as: <organization-name>/<team-slug>.")
cliflag.BoolVarP(root.Flags(), &oauth2GithubAllowSignups, "oauth2-github-allow-signups", "", "CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS", false,
"Specifies whether new users can sign up with GitHub.")
cliflag.BoolVarP(root.Flags(), &oidcAllowSignups, "oidc-allow-signups", "", "CODER_OIDC_ALLOW_SIGNUPS", true,
"Specifies whether new users can sign up with OIDC.")
cliflag.StringVarP(root.Flags(), &oidcClientID, "oidc-client-id", "", "CODER_OIDC_CLIENT_ID", "",
"Specifies a client ID to use for OIDC.")
cliflag.StringVarP(root.Flags(), &oidcClientSecret, "oidc-client-secret", "", "CODER_OIDC_CLIENT_SECRET", "",
"Specifies a client secret to use for OIDC.")
cliflag.StringVarP(root.Flags(), &oidcEmailDomain, "oidc-email-domain", "", "CODER_OIDC_EMAIL_DOMAIN", "",
"Specifies an email domain that clients authenticating with OIDC must match.")
cliflag.StringVarP(root.Flags(), &oidcIssuerURL, "oidc-issuer-url", "", "CODER_OIDC_ISSUER_URL", "",
"Specifies an issuer URL to use for OIDC.")
cliflag.StringArrayVarP(root.Flags(), &oidcScopes, "oidc-scopes", "", "CODER_OIDC_SCOPES", []string{oidc.ScopeOpenID, "profile", "email"},
"Specifies scopes to grant when authenticating with OIDC.")
enableTelemetryByDefault := !isTest()
cliflag.BoolVarP(root.Flags(), &telemetryEnable, "telemetry", "", "CODER_TELEMETRY", enableTelemetryByDefault, "Specifies whether telemetry is enabled or not. Coder collects anonymized usage data to help improve our product.")
cliflag.StringVarP(root.Flags(), &telemetryURL, "telemetry-url", "", "CODER_TELEMETRY_URL", "https://telemetry.coder.com", "Specifies a URL to send telemetry to.")