feat: allow external services to be authable (#9996)

* feat: allow external services to be authable

* Refactor external auth config structure for defaults

* Add support for new config properties

* Change the name of external auth

* Move externalauth -> external-auth

* Run gen

* Fix tests

* Fix MW tests

* Fix git auth redirect

* Fix lint

* Fix name

* Allow any ID

* Fix invalid type test

* Fix e2e tests

* Fix comments

* Fix colors

* Allow accepting any type as string

* Run gen

* Fix href
This commit is contained in:
Kyle Carberry
2023-10-03 14:04:39 +00:00
committed by GitHub
parent f62f45a303
commit 45b53c285f
58 changed files with 1140 additions and 1027 deletions
+67 -54
View File
@@ -134,52 +134,52 @@ type DeploymentValues struct {
DocsURL clibase.URL `json:"docs_url,omitempty"`
RedirectToAccessURL clibase.Bool `json:"redirect_to_access_url,omitempty"`
// HTTPAddress is a string because it may be set to zero to disable.
HTTPAddress clibase.String `json:"http_address,omitempty" typescript:",notnull"`
AutobuildPollInterval clibase.Duration `json:"autobuild_poll_interval,omitempty"`
JobHangDetectorInterval clibase.Duration `json:"job_hang_detector_interval,omitempty"`
DERP DERP `json:"derp,omitempty" typescript:",notnull"`
Prometheus PrometheusConfig `json:"prometheus,omitempty" typescript:",notnull"`
Pprof PprofConfig `json:"pprof,omitempty" typescript:",notnull"`
ProxyTrustedHeaders clibase.StringArray `json:"proxy_trusted_headers,omitempty" typescript:",notnull"`
ProxyTrustedOrigins clibase.StringArray `json:"proxy_trusted_origins,omitempty" typescript:",notnull"`
CacheDir clibase.String `json:"cache_directory,omitempty" typescript:",notnull"`
InMemoryDatabase clibase.Bool `json:"in_memory_database,omitempty" typescript:",notnull"`
PostgresURL clibase.String `json:"pg_connection_url,omitempty" typescript:",notnull"`
OAuth2 OAuth2Config `json:"oauth2,omitempty" typescript:",notnull"`
OIDC OIDCConfig `json:"oidc,omitempty" typescript:",notnull"`
Telemetry TelemetryConfig `json:"telemetry,omitempty" typescript:",notnull"`
TLS TLSConfig `json:"tls,omitempty" typescript:",notnull"`
Trace TraceConfig `json:"trace,omitempty" typescript:",notnull"`
SecureAuthCookie clibase.Bool `json:"secure_auth_cookie,omitempty" typescript:",notnull"`
StrictTransportSecurity clibase.Int64 `json:"strict_transport_security,omitempty" typescript:",notnull"`
StrictTransportSecurityOptions clibase.StringArray `json:"strict_transport_security_options,omitempty" typescript:",notnull"`
SSHKeygenAlgorithm clibase.String `json:"ssh_keygen_algorithm,omitempty" typescript:",notnull"`
MetricsCacheRefreshInterval clibase.Duration `json:"metrics_cache_refresh_interval,omitempty" typescript:",notnull"`
AgentStatRefreshInterval clibase.Duration `json:"agent_stat_refresh_interval,omitempty" typescript:",notnull"`
AgentFallbackTroubleshootingURL clibase.URL `json:"agent_fallback_troubleshooting_url,omitempty" typescript:",notnull"`
BrowserOnly clibase.Bool `json:"browser_only,omitempty" typescript:",notnull"`
SCIMAPIKey clibase.String `json:"scim_api_key,omitempty" typescript:",notnull"`
ExternalTokenEncryptionKeys clibase.StringArray `json:"external_token_encryption_keys,omitempty" typescript:",notnull"`
Provisioner ProvisionerConfig `json:"provisioner,omitempty" typescript:",notnull"`
RateLimit RateLimitConfig `json:"rate_limit,omitempty" typescript:",notnull"`
Experiments clibase.StringArray `json:"experiments,omitempty" typescript:",notnull"`
UpdateCheck clibase.Bool `json:"update_check,omitempty" typescript:",notnull"`
MaxTokenLifetime clibase.Duration `json:"max_token_lifetime,omitempty" typescript:",notnull"`
Swagger SwaggerConfig `json:"swagger,omitempty" typescript:",notnull"`
Logging LoggingConfig `json:"logging,omitempty" typescript:",notnull"`
Dangerous DangerousConfig `json:"dangerous,omitempty" typescript:",notnull"`
DisablePathApps clibase.Bool `json:"disable_path_apps,omitempty" typescript:",notnull"`
SessionDuration clibase.Duration `json:"max_session_expiry,omitempty" typescript:",notnull"`
DisableSessionExpiryRefresh clibase.Bool `json:"disable_session_expiry_refresh,omitempty" typescript:",notnull"`
DisablePasswordAuth clibase.Bool `json:"disable_password_auth,omitempty" typescript:",notnull"`
Support SupportConfig `json:"support,omitempty" typescript:",notnull"`
GitAuthProviders clibase.Struct[[]GitAuthConfig] `json:"git_auth,omitempty" typescript:",notnull"`
SSHConfig SSHConfig `json:"config_ssh,omitempty" typescript:",notnull"`
WgtunnelHost clibase.String `json:"wgtunnel_host,omitempty" typescript:",notnull"`
DisableOwnerWorkspaceExec clibase.Bool `json:"disable_owner_workspace_exec,omitempty" typescript:",notnull"`
ProxyHealthStatusInterval clibase.Duration `json:"proxy_health_status_interval,omitempty" typescript:",notnull"`
EnableTerraformDebugMode clibase.Bool `json:"enable_terraform_debug_mode,omitempty" typescript:",notnull"`
UserQuietHoursSchedule UserQuietHoursScheduleConfig `json:"user_quiet_hours_schedule,omitempty" typescript:",notnull"`
HTTPAddress clibase.String `json:"http_address,omitempty" typescript:",notnull"`
AutobuildPollInterval clibase.Duration `json:"autobuild_poll_interval,omitempty"`
JobHangDetectorInterval clibase.Duration `json:"job_hang_detector_interval,omitempty"`
DERP DERP `json:"derp,omitempty" typescript:",notnull"`
Prometheus PrometheusConfig `json:"prometheus,omitempty" typescript:",notnull"`
Pprof PprofConfig `json:"pprof,omitempty" typescript:",notnull"`
ProxyTrustedHeaders clibase.StringArray `json:"proxy_trusted_headers,omitempty" typescript:",notnull"`
ProxyTrustedOrigins clibase.StringArray `json:"proxy_trusted_origins,omitempty" typescript:",notnull"`
CacheDir clibase.String `json:"cache_directory,omitempty" typescript:",notnull"`
InMemoryDatabase clibase.Bool `json:"in_memory_database,omitempty" typescript:",notnull"`
PostgresURL clibase.String `json:"pg_connection_url,omitempty" typescript:",notnull"`
OAuth2 OAuth2Config `json:"oauth2,omitempty" typescript:",notnull"`
OIDC OIDCConfig `json:"oidc,omitempty" typescript:",notnull"`
Telemetry TelemetryConfig `json:"telemetry,omitempty" typescript:",notnull"`
TLS TLSConfig `json:"tls,omitempty" typescript:",notnull"`
Trace TraceConfig `json:"trace,omitempty" typescript:",notnull"`
SecureAuthCookie clibase.Bool `json:"secure_auth_cookie,omitempty" typescript:",notnull"`
StrictTransportSecurity clibase.Int64 `json:"strict_transport_security,omitempty" typescript:",notnull"`
StrictTransportSecurityOptions clibase.StringArray `json:"strict_transport_security_options,omitempty" typescript:",notnull"`
SSHKeygenAlgorithm clibase.String `json:"ssh_keygen_algorithm,omitempty" typescript:",notnull"`
MetricsCacheRefreshInterval clibase.Duration `json:"metrics_cache_refresh_interval,omitempty" typescript:",notnull"`
AgentStatRefreshInterval clibase.Duration `json:"agent_stat_refresh_interval,omitempty" typescript:",notnull"`
AgentFallbackTroubleshootingURL clibase.URL `json:"agent_fallback_troubleshooting_url,omitempty" typescript:",notnull"`
BrowserOnly clibase.Bool `json:"browser_only,omitempty" typescript:",notnull"`
SCIMAPIKey clibase.String `json:"scim_api_key,omitempty" typescript:",notnull"`
ExternalTokenEncryptionKeys clibase.StringArray `json:"external_token_encryption_keys,omitempty" typescript:",notnull"`
Provisioner ProvisionerConfig `json:"provisioner,omitempty" typescript:",notnull"`
RateLimit RateLimitConfig `json:"rate_limit,omitempty" typescript:",notnull"`
Experiments clibase.StringArray `json:"experiments,omitempty" typescript:",notnull"`
UpdateCheck clibase.Bool `json:"update_check,omitempty" typescript:",notnull"`
MaxTokenLifetime clibase.Duration `json:"max_token_lifetime,omitempty" typescript:",notnull"`
Swagger SwaggerConfig `json:"swagger,omitempty" typescript:",notnull"`
Logging LoggingConfig `json:"logging,omitempty" typescript:",notnull"`
Dangerous DangerousConfig `json:"dangerous,omitempty" typescript:",notnull"`
DisablePathApps clibase.Bool `json:"disable_path_apps,omitempty" typescript:",notnull"`
SessionDuration clibase.Duration `json:"max_session_expiry,omitempty" typescript:",notnull"`
DisableSessionExpiryRefresh clibase.Bool `json:"disable_session_expiry_refresh,omitempty" typescript:",notnull"`
DisablePasswordAuth clibase.Bool `json:"disable_password_auth,omitempty" typescript:",notnull"`
Support SupportConfig `json:"support,omitempty" typescript:",notnull"`
ExternalAuthConfigs clibase.Struct[[]ExternalAuthConfig] `json:"external_auth,omitempty" typescript:",notnull"`
SSHConfig SSHConfig `json:"config_ssh,omitempty" typescript:",notnull"`
WgtunnelHost clibase.String `json:"wgtunnel_host,omitempty" typescript:",notnull"`
DisableOwnerWorkspaceExec clibase.Bool `json:"disable_owner_workspace_exec,omitempty" typescript:",notnull"`
ProxyHealthStatusInterval clibase.Duration `json:"proxy_health_status_interval,omitempty" typescript:",notnull"`
EnableTerraformDebugMode clibase.Bool `json:"enable_terraform_debug_mode,omitempty" typescript:",notnull"`
UserQuietHoursSchedule UserQuietHoursScheduleConfig `json:"user_quiet_hours_schedule,omitempty" typescript:",notnull"`
Config clibase.YAMLConfigPath `json:"config,omitempty" typescript:",notnull"`
WriteConfig clibase.Bool `json:"write_config,omitempty" typescript:",notnull"`
@@ -321,21 +321,34 @@ type TraceConfig struct {
DataDog clibase.Bool `json:"data_dog" typescript:",notnull"`
}
type GitAuthConfig struct {
type ExternalAuthConfig struct {
// Type is the type of external auth config.
Type string `json:"type"`
ClientID string `json:"client_id"`
ClientSecret string `json:"-" yaml:"client_secret"`
// ID is a unique identifier for the auth config.
// It defaults to `type` when not provided.
ID string `json:"id"`
Type string `json:"type"`
ClientID string `json:"client_id"`
ClientSecret string `json:"-" yaml:"client_secret"`
AuthURL string `json:"auth_url"`
TokenURL string `json:"token_url"`
ValidateURL string `json:"validate_url"`
AppInstallURL string `json:"app_install_url"`
AppInstallationsURL string `json:"app_installations_url"`
Regex string `json:"regex"`
NoRefresh bool `json:"no_refresh"`
Scopes []string `json:"scopes"`
DeviceFlow bool `json:"device_flow"`
DeviceCodeURL string `json:"device_code_url"`
// Regex allows API requesters to match an auth config by
// a string (e.g. coder.com) instead of by it's type.
//
// Git clone makes use of this by parsing the URL from:
// 'Username for "https://github.com":'
// And sending it to the Coder server to match against the Regex.
Regex string `json:"regex"`
// DisplayName is shown in the UI to identify the auth config.
DisplayName string `json:"display_name"`
// DisplayIcon is a URL to an icon to display in the UI.
DisplayIcon string `json:"display_icon"`
}
type ProvisionerConfig struct {
@@ -1710,12 +1723,12 @@ Write out the current server config as YAML to stdout.`,
},
{
// Env handling is done in cli.ReadGitAuthFromEnvironment
Name: "Git Auth Providers",
Description: "Git Authentication providers.",
Name: "External Auth Providers",
Description: "External Authentication providers.",
// We need extra scrutiny to ensure this works, is documented, and
// tested before enabling.
// YAML: "gitAuthProviders",
Value: &c.GitAuthProviders,
Value: &c.ExternalAuthConfigs,
Hidden: true,
},
{
+3 -3
View File
@@ -65,9 +65,9 @@ func TestDeploymentValues_HighlyConfigurable(t *testing.T) {
flag: true,
env: true,
},
"Git Auth Providers": {
// Technically Git Auth Providers can be provided through the env,
// but bypassing clibase. See cli.ReadGitAuthProvidersFromEnv.
"External Auth Providers": {
// Technically External Auth Providers can be provided through the env,
// but bypassing clibase. See cli.ReadExternalAuthProvidersFromEnv.
flag: true,
env: true,
},
+33 -4
View File
@@ -7,10 +7,39 @@ import (
"net/http"
)
// EnhancedExternalAuthProvider is a constant that represents enhanced
// support for a type of external authentication. All of the Git providers
// are examples of enhanced, because they support intercepting "git clone".
type EnhancedExternalAuthProvider string
func (e EnhancedExternalAuthProvider) String() string {
return string(e)
}
// Git returns whether the provider is a Git provider.
func (e EnhancedExternalAuthProvider) Git() bool {
switch e {
case EnhancedExternalAuthProviderGitHub,
EnhancedExternalAuthProviderGitLab,
EnhancedExternalAuthProviderBitBucket,
EnhancedExternalAuthProviderAzureDevops:
return true
default:
return false
}
}
const (
EnhancedExternalAuthProviderAzureDevops EnhancedExternalAuthProvider = "azure-devops"
EnhancedExternalAuthProviderGitHub EnhancedExternalAuthProvider = "github"
EnhancedExternalAuthProviderGitLab EnhancedExternalAuthProvider = "gitlab"
EnhancedExternalAuthProviderBitBucket EnhancedExternalAuthProvider = "bitbucket"
)
type ExternalAuth struct {
Authenticated bool `json:"authenticated"`
Device bool `json:"device"`
Type string `json:"type"`
DisplayName string `json:"display_name"`
// User is the user that authenticated with the provider.
User *ExternalAuthUser `json:"user"`
@@ -50,7 +79,7 @@ type ExternalAuthDeviceExchange struct {
}
func (c *Client) ExternalAuthDeviceByID(ctx context.Context, provider string) (ExternalAuthDevice, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/externalauth/%s/device", provider), nil)
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/external-auth/%s/device", provider), nil)
if err != nil {
return ExternalAuthDevice{}, err
}
@@ -64,7 +93,7 @@ func (c *Client) ExternalAuthDeviceByID(ctx context.Context, provider string) (E
// ExchangeGitAuth exchanges a device code for an external auth token.
func (c *Client) ExternalAuthDeviceExchange(ctx context.Context, provider string, req ExternalAuthDeviceExchange) error {
res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/externalauth/%s/device", provider), req)
res, err := c.Request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/external-auth/%s/device", provider), req)
if err != nil {
return err
}
@@ -77,7 +106,7 @@ func (c *Client) ExternalAuthDeviceExchange(ctx context.Context, provider string
// ExternalAuthByID returns the external auth for the given provider by ID.
func (c *Client) ExternalAuthByID(ctx context.Context, provider string) (ExternalAuth, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/externalauth/%s", provider), nil)
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/external-auth/%s", provider), nil)
if err != nil {
return ExternalAuth{}, err
}
+7 -5
View File
@@ -34,10 +34,12 @@ type TemplateVersion struct {
}
type TemplateVersionExternalAuth struct {
ID string `json:"id"`
Type ExternalAuthProvider `json:"type"`
AuthenticateURL string `json:"authenticate_url"`
Authenticated bool `json:"authenticated"`
ID string `json:"id"`
Type string `json:"type"`
DisplayName string `json:"display_name"`
DisplayIcon string `json:"display_icon"`
AuthenticateURL string `json:"authenticate_url"`
Authenticated bool `json:"authenticated"`
}
type ValidationMonotonicOrder string
@@ -134,7 +136,7 @@ func (c *Client) TemplateVersionRichParameters(ctx context.Context, version uuid
// TemplateVersionExternalAuth returns authentication providers for the requested template version.
func (c *Client) TemplateVersionExternalAuth(ctx context.Context, version uuid.UUID) ([]TemplateVersionExternalAuth, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/externalauth", version), nil)
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/external-auth", version), nil)
if err != nil {
return nil, err
}
-29
View File
@@ -744,35 +744,6 @@ func (c *Client) WorkspaceAgentLogsAfter(ctx context.Context, agentID uuid.UUID,
}), nil
}
// ExternalAuthProvider is a constant that represents the
// type of providers that are supported within Coder.
type ExternalAuthProvider string
func (g ExternalAuthProvider) Pretty() string {
switch g {
case ExternalAuthProviderAzureDevops:
return "Azure DevOps"
case ExternalAuthProviderGitHub:
return "GitHub"
case ExternalAuthProviderGitLab:
return "GitLab"
case ExternalAuthProviderBitBucket:
return "Bitbucket"
case ExternalAuthProviderOpenIDConnect:
return "OpenID Connect"
default:
return string(g)
}
}
const (
ExternalAuthProviderAzureDevops ExternalAuthProvider = "azure-devops"
ExternalAuthProviderGitHub ExternalAuthProvider = "github"
ExternalAuthProviderGitLab ExternalAuthProvider = "gitlab"
ExternalAuthProviderBitBucket ExternalAuthProvider = "bitbucket"
ExternalAuthProviderOpenIDConnect ExternalAuthProvider = "openid-connect"
)
type WorkspaceAgentLog struct {
ID int64 `json:"id"`
CreatedAt time.Time `json:"created_at" format:"date-time"`