mirror of
https://github.com/coder/coder.git
synced 2025-07-23 21:32:07 +00:00
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:
187
cli/server.go
187
cli/server.go
@@ -98,85 +98,6 @@ import (
|
||||
"github.com/coder/wgtunnel/tunnelsdk"
|
||||
)
|
||||
|
||||
// ReadGitAuthProvidersFromEnv is provided for compatibility purposes with the
|
||||
// viper CLI.
|
||||
// DEPRECATED
|
||||
func ReadGitAuthProvidersFromEnv(environ []string) ([]codersdk.GitAuthConfig, error) {
|
||||
// The index numbers must be in-order.
|
||||
sort.Strings(environ)
|
||||
|
||||
var providers []codersdk.GitAuthConfig
|
||||
for _, v := range clibase.ParseEnviron(environ, "CODER_GITAUTH_") {
|
||||
tokens := strings.SplitN(v.Name, "_", 2)
|
||||
if len(tokens) != 2 {
|
||||
return nil, xerrors.Errorf("invalid env var: %s", v.Name)
|
||||
}
|
||||
|
||||
providerNum, err := strconv.Atoi(tokens[0])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse number: %s", v.Name)
|
||||
}
|
||||
|
||||
var provider codersdk.GitAuthConfig
|
||||
switch {
|
||||
case len(providers) < providerNum:
|
||||
return nil, xerrors.Errorf(
|
||||
"provider num %v skipped: %s",
|
||||
len(providers),
|
||||
v.Name,
|
||||
)
|
||||
case len(providers) == providerNum:
|
||||
// At the next next provider.
|
||||
providers = append(providers, provider)
|
||||
case len(providers) == providerNum+1:
|
||||
// At the current provider.
|
||||
provider = providers[providerNum]
|
||||
}
|
||||
|
||||
key := tokens[1]
|
||||
switch key {
|
||||
case "ID":
|
||||
provider.ID = v.Value
|
||||
case "TYPE":
|
||||
provider.Type = v.Value
|
||||
case "CLIENT_ID":
|
||||
provider.ClientID = v.Value
|
||||
case "CLIENT_SECRET":
|
||||
provider.ClientSecret = v.Value
|
||||
case "AUTH_URL":
|
||||
provider.AuthURL = v.Value
|
||||
case "TOKEN_URL":
|
||||
provider.TokenURL = v.Value
|
||||
case "VALIDATE_URL":
|
||||
provider.ValidateURL = v.Value
|
||||
case "REGEX":
|
||||
provider.Regex = v.Value
|
||||
case "DEVICE_FLOW":
|
||||
b, err := strconv.ParseBool(v.Value)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse bool: %s", v.Value)
|
||||
}
|
||||
provider.DeviceFlow = b
|
||||
case "DEVICE_CODE_URL":
|
||||
provider.DeviceCodeURL = v.Value
|
||||
case "NO_REFRESH":
|
||||
b, err := strconv.ParseBool(v.Value)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse bool: %s", v.Value)
|
||||
}
|
||||
provider.NoRefresh = b
|
||||
case "SCOPES":
|
||||
provider.Scopes = strings.Split(v.Value, " ")
|
||||
case "APP_INSTALL_URL":
|
||||
provider.AppInstallURL = v.Value
|
||||
case "APP_INSTALLATIONS_URL":
|
||||
provider.AppInstallationsURL = v.Value
|
||||
}
|
||||
providers[providerNum] = provider
|
||||
}
|
||||
return providers, nil
|
||||
}
|
||||
|
||||
func createOIDCConfig(ctx context.Context, vals *codersdk.DeploymentValues) (*coderd.OIDCConfig, error) {
|
||||
if vals.OIDC.ClientID == "" {
|
||||
return nil, xerrors.Errorf("OIDC client ID must be set!")
|
||||
@@ -568,14 +489,14 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
}
|
||||
}
|
||||
|
||||
gitAuthEnv, err := ReadGitAuthProvidersFromEnv(os.Environ())
|
||||
extAuthEnv, err := ReadExternalAuthProvidersFromEnv(os.Environ())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("read git auth providers from env: %w", err)
|
||||
return xerrors.Errorf("read external auth providers from env: %w", err)
|
||||
}
|
||||
|
||||
vals.GitAuthProviders.Value = append(vals.GitAuthProviders.Value, gitAuthEnv...)
|
||||
vals.ExternalAuthConfigs.Value = append(vals.ExternalAuthConfigs.Value, extAuthEnv...)
|
||||
externalAuthConfigs, err := externalauth.ConvertConfig(
|
||||
vals.GitAuthProviders.Value,
|
||||
vals.ExternalAuthConfigs.Value,
|
||||
vals.AccessURL.Value(),
|
||||
)
|
||||
if err != nil {
|
||||
@@ -816,7 +737,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
||||
if vals.Telemetry.Enable {
|
||||
gitAuth := make([]telemetry.GitAuth, 0)
|
||||
// TODO:
|
||||
var gitAuthConfigs []codersdk.GitAuthConfig
|
||||
var gitAuthConfigs []codersdk.ExternalAuthConfig
|
||||
for _, cfg := range gitAuthConfigs {
|
||||
gitAuth = append(gitAuth, telemetry.GitAuth{
|
||||
Type: cfg.Type,
|
||||
@@ -2242,3 +2163,101 @@ func ConfigureHTTPServers(inv *clibase.Invocation, cfg *codersdk.DeploymentValue
|
||||
|
||||
return httpServers, nil
|
||||
}
|
||||
|
||||
// ReadExternalAuthProvidersFromEnv is provided for compatibility purposes with
|
||||
// the viper CLI.
|
||||
func ReadExternalAuthProvidersFromEnv(environ []string) ([]codersdk.ExternalAuthConfig, error) {
|
||||
providers, err := parseExternalAuthProvidersFromEnv("CODER_EXTERNAL_AUTH_", environ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Deprecated: To support legacy git auth!
|
||||
gitProviders, err := parseExternalAuthProvidersFromEnv("CODER_GITAUTH_", environ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(providers, gitProviders...), nil
|
||||
}
|
||||
|
||||
// parseExternalAuthProvidersFromEnv consumes environment variables to parse
|
||||
// external auth providers. A prefix is provided to support the legacy
|
||||
// parsing of `GITAUTH` environment variables.
|
||||
func parseExternalAuthProvidersFromEnv(prefix string, environ []string) ([]codersdk.ExternalAuthConfig, error) {
|
||||
// The index numbers must be in-order.
|
||||
sort.Strings(environ)
|
||||
|
||||
var providers []codersdk.ExternalAuthConfig
|
||||
for _, v := range clibase.ParseEnviron(environ, prefix) {
|
||||
tokens := strings.SplitN(v.Name, "_", 2)
|
||||
if len(tokens) != 2 {
|
||||
return nil, xerrors.Errorf("invalid env var: %s", v.Name)
|
||||
}
|
||||
|
||||
providerNum, err := strconv.Atoi(tokens[0])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse number: %s", v.Name)
|
||||
}
|
||||
|
||||
var provider codersdk.ExternalAuthConfig
|
||||
switch {
|
||||
case len(providers) < providerNum:
|
||||
return nil, xerrors.Errorf(
|
||||
"provider num %v skipped: %s",
|
||||
len(providers),
|
||||
v.Name,
|
||||
)
|
||||
case len(providers) == providerNum:
|
||||
// At the next next provider.
|
||||
providers = append(providers, provider)
|
||||
case len(providers) == providerNum+1:
|
||||
// At the current provider.
|
||||
provider = providers[providerNum]
|
||||
}
|
||||
|
||||
key := tokens[1]
|
||||
switch key {
|
||||
case "ID":
|
||||
provider.ID = v.Value
|
||||
case "TYPE":
|
||||
provider.Type = v.Value
|
||||
case "CLIENT_ID":
|
||||
provider.ClientID = v.Value
|
||||
case "CLIENT_SECRET":
|
||||
provider.ClientSecret = v.Value
|
||||
case "AUTH_URL":
|
||||
provider.AuthURL = v.Value
|
||||
case "TOKEN_URL":
|
||||
provider.TokenURL = v.Value
|
||||
case "VALIDATE_URL":
|
||||
provider.ValidateURL = v.Value
|
||||
case "REGEX":
|
||||
provider.Regex = v.Value
|
||||
case "DEVICE_FLOW":
|
||||
b, err := strconv.ParseBool(v.Value)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse bool: %s", v.Value)
|
||||
}
|
||||
provider.DeviceFlow = b
|
||||
case "DEVICE_CODE_URL":
|
||||
provider.DeviceCodeURL = v.Value
|
||||
case "NO_REFRESH":
|
||||
b, err := strconv.ParseBool(v.Value)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("parse bool: %s", v.Value)
|
||||
}
|
||||
provider.NoRefresh = b
|
||||
case "SCOPES":
|
||||
provider.Scopes = strings.Split(v.Value, " ")
|
||||
case "APP_INSTALL_URL":
|
||||
provider.AppInstallURL = v.Value
|
||||
case "APP_INSTALLATIONS_URL":
|
||||
provider.AppInstallationsURL = v.Value
|
||||
case "DISPLAY_NAME":
|
||||
provider.DisplayName = v.Value
|
||||
case "DISPLAY_ICON":
|
||||
provider.DisplayIcon = v.Value
|
||||
}
|
||||
providers[providerNum] = provider
|
||||
}
|
||||
return providers, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user