mirror of https://github.com/coder/coder.git
experiment: link public key to github automatically
This commit is contained in:
parent
15157c1c40
commit
28c498927d
|
@ -524,28 +524,8 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
|||
}
|
||||
}
|
||||
|
||||
extAuthEnv, err := ReadExternalAuthProvidersFromEnv(os.Environ())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("read external auth providers from env: %w", err)
|
||||
}
|
||||
|
||||
promRegistry := prometheus.NewRegistry()
|
||||
oauthInstrument := promoauth.NewFactory(promRegistry)
|
||||
vals.ExternalAuthConfigs.Value = append(vals.ExternalAuthConfigs.Value, extAuthEnv...)
|
||||
externalAuthConfigs, err := externalauth.ConvertConfig(
|
||||
oauthInstrument,
|
||||
vals.ExternalAuthConfigs.Value,
|
||||
vals.AccessURL.Value(),
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("convert external auth config: %w", err)
|
||||
}
|
||||
for _, c := range externalAuthConfigs {
|
||||
logger.Debug(
|
||||
ctx, "loaded external auth config",
|
||||
slog.F("id", c.ID),
|
||||
)
|
||||
}
|
||||
|
||||
realIPConfig, err := httpmw.ParseRealIPConfig(vals.ProxyTrustedHeaders, vals.ProxyTrustedOrigins)
|
||||
if err != nil {
|
||||
|
@ -567,7 +547,6 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
|||
Pubsub: pubsub.NewInMemory(),
|
||||
CacheDir: cacheDir,
|
||||
GoogleTokenValidator: googleTokenValidator,
|
||||
ExternalAuthConfigs: externalAuthConfigs,
|
||||
RealIPConfig: realIPConfig,
|
||||
SecureAuthCookie: vals.SecureAuthCookie.Value(),
|
||||
SSHKeygenAlgorithm: sshKeygenAlgorithm,
|
||||
|
@ -696,6 +675,27 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
|
|||
options.Database = dbmetrics.New(options.Database, options.PrometheusRegistry)
|
||||
}
|
||||
|
||||
extAuthEnv, err := ReadExternalAuthProvidersFromEnv(os.Environ())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("read external auth providers from env: %w", err)
|
||||
}
|
||||
vals.ExternalAuthConfigs.Value = append(vals.ExternalAuthConfigs.Value, extAuthEnv...)
|
||||
externalAuthConfigs, err := externalauth.ConvertConfig(
|
||||
oauthInstrument,
|
||||
vals.ExternalAuthConfigs.Value,
|
||||
options.Database,
|
||||
vals.AccessURL.Value(),
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("convert external auth config: %w", err)
|
||||
}
|
||||
for _, c := range externalAuthConfigs {
|
||||
logger.Debug(
|
||||
ctx, "loaded external auth config",
|
||||
slog.F("id", c.ID),
|
||||
)
|
||||
}
|
||||
|
||||
var deploymentID string
|
||||
err = options.Database.InTx(func(tx database.Store) error {
|
||||
// This will block until the lock is acquired, and will be
|
||||
|
|
|
@ -300,6 +300,17 @@ func (api *API) externalAuthCallback(externalAuthConfig *externalauth.Config) ht
|
|||
}
|
||||
}
|
||||
|
||||
if externalAuthConfig.CallbackFunc != nil {
|
||||
err = externalAuthConfig.CallbackFunc(ctx, state.Token.AccessToken)
|
||||
if err != nil {
|
||||
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
|
||||
Message: "Failed to run external auth callback action.",
|
||||
Detail: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
redirect := state.Redirect
|
||||
if redirect == "" {
|
||||
// This is a nicely rendered screen on the frontend. Passing the query param lets the
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package externalauth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/google/go-github/v61/github"
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
)
|
||||
|
||||
type githubCallback struct {
|
||||
accessURL *url.URL
|
||||
db database.Store
|
||||
}
|
||||
|
||||
func (c githubCallback) LinkPublicKey(ctx context.Context, userID uuid.UUID, token string) error {
|
||||
client := github.NewClient(nil).WithAuthToken(token)
|
||||
|
||||
ghKeys, _, err := client.Users.ListKeys(ctx, "", nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("list github keys: %w", err)
|
||||
}
|
||||
|
||||
dbKey, err := c.db.GetGitSSHKey(ctx, userID)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get git ssh key: %w", err)
|
||||
}
|
||||
|
||||
for _, key := range ghKeys {
|
||||
if key.GetKey() == dbKey.PublicKey {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
_, _, err = client.Users.CreateKey(ctx, &github.Key{
|
||||
Key: &dbKey.PublicKey,
|
||||
Title: github.String(fmt.Sprintf("%s Workspaces", c.accessURL.String())),
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("create github key: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -18,6 +18,7 @@ import (
|
|||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/google/go-github/v43/github"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sqlc-dev/pqtype"
|
||||
xgithub "golang.org/x/oauth2/github"
|
||||
|
||||
|
@ -74,6 +75,7 @@ type Config struct {
|
|||
// AppInstallationsURL is an API endpoint that returns a list of
|
||||
// installations for the user. This is used for GitHub Apps.
|
||||
AppInstallationsURL string
|
||||
CallbackFunc func(ctx context.Context, userID uuid.UUID, token string) error
|
||||
}
|
||||
|
||||
// GenerateTokenExtra generates the extra token data to store in the database.
|
||||
|
@ -442,7 +444,7 @@ func (c *DeviceAuth) formatDeviceCodeURL() (string, error) {
|
|||
|
||||
// ConvertConfig converts the SDK configuration entry format
|
||||
// to the parsed and ready-to-consume in coderd provider type.
|
||||
func ConvertConfig(instrument *promoauth.Factory, entries []codersdk.ExternalAuthConfig, accessURL *url.URL) ([]*Config, error) {
|
||||
func ConvertConfig(instrument *promoauth.Factory, entries []codersdk.ExternalAuthConfig, db database.Store, accessURL *url.URL) ([]*Config, error) {
|
||||
ids := map[string]struct{}{}
|
||||
configs := []*Config{}
|
||||
for _, entry := range entries {
|
||||
|
@ -538,6 +540,17 @@ func ConvertConfig(instrument *promoauth.Factory, entries []codersdk.ExternalAut
|
|||
}
|
||||
}
|
||||
|
||||
if entry.LinkPublicKey {
|
||||
if entry.Type == string(codersdk.EnhancedExternalAuthProviderGitHub) {
|
||||
cfg.CallbackFunc = func(ctx context.Context, userID uuid.UUID, token string) error {
|
||||
return githubCallback{
|
||||
accessURL: accessURL,
|
||||
db: db,
|
||||
}.LinkPublicKey(ctx, userID, token)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configs = append(configs, cfg)
|
||||
}
|
||||
return configs, nil
|
||||
|
|
|
@ -402,7 +402,8 @@ type ExternalAuthConfig struct {
|
|||
// DisplayName is shown in the UI to identify the auth config.
|
||||
DisplayName string `json:"display_name" yaml:"display_name"`
|
||||
// DisplayIcon is a URL to an icon to display in the UI.
|
||||
DisplayIcon string `json:"display_icon" yaml:"display_icon"`
|
||||
DisplayIcon string `json:"display_icon" yaml:"display_icon"`
|
||||
LinkPublicKey bool `json:"link_public_key" yaml:"link_public_key"`
|
||||
}
|
||||
|
||||
type ProvisionerConfig struct {
|
||||
|
|
Loading…
Reference in New Issue