8000 chore: implement organization sync and create idpsync package by Emyrk · Pull Request #14432 · coder/coder · GitHub
[go: up one dir, main page]

Skip to content

chore: implement organization sync and create idpsync package #14432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
move the config into api options
  • Loading branch information
Emyrk committed Aug 29, 2024
commit b3144c0904ee91788d718cdeabf7aad163427f85
6 changes: 0 additions & 6 deletions cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ import (
"cdr.dev/slog"
"cdr.dev/slog/sloggers/sloghuman"
"github.com/coder/coder/v2/coderd/entitlements"
"github.com/coder/coder/v2/coderd/idpsync"
"github.com/coder/pretty"
"github.com/coder/quartz"
"github.com/coder/retry"
Expand Down Expand Up @@ -199,11 +198,6 @@ func createOIDCConfig(ctx context.Context, logger slog.Logger, set *entitlements
SignupsDisabledText: vals.OIDC.SignupsDisabledText.String(),
IconURL: vals.OIDC.IconURL.String(),
IgnoreEmailVerified: vals.OIDC.IgnoreEmailVerified.Value(),
IDPSync: idpsync.NewSync(logger, set, idpsync.SyncSettings{
OrganizationField: vals.OIDC.OrganizationField.Value(),
OrganizationMapping: vals.OIDC.OrganizationMapping.Value,
OrganizationAssignDefault: vals.OIDC.OrganizationAssignDefault.Value(),
}),
}, nil
}

Expand Down
11 changes: 11 additions & 0 deletions coderd/coderd.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (

"cdr.dev/slog"
"github.com/coder/coder/v2/coderd/entitlements"
"github.com/coder/coder/v2/coderd/idpsync"
"github.com/coder/quartz"
"github.com/coder/serpent"

Expand Down Expand Up @@ -243,6 +244,9 @@ type Options struct {
WorkspaceUsageTracker *workspacestats.UsageTracker
// NotificationsEnqueuer handles enqueueing notifications for delivery by SMTP, webhook, etc.
NotificationsEnqueuer notifications.Enqueuer

// IDPSync holds all configured values for syncing external IDP users into Coder.
IDPSync idpsync.IDPSync
}

// @title Coder API
Expand Down Expand Up @@ -270,6 +274,13 @@ func New(options *Options) *API {
if options.Entitlements == nil {
options.Entitlements = entitlements.New()
}
if options.IDPSync == nil {
options.IDPSync = idpsync.NewAGPLSync(options.Logger, idpsync.SyncSettings{
OrganizationField: options.DeploymentValues.OIDC.OrganizationField.Value(),
OrganizationMapping: options.DeploymentValues.OIDC.OrganizationMapping.Value,
OrganizationAssignDefault: options.DeploymentValues.OIDC.OrganizationAssignDefault.Value(),
})
}
if options.NewTicker == nil {
options.NewTicker = func(duration time.Duration) (tick <-chan time.Time, done func()) {
ticker := time.NewTicker(duration)
Expand Down
13 changes: 1 addition & 12 deletions coderd/idpsync/idpsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,11 @@ import (

"cdr.dev/slog"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/entitlements"
"github.com/coder/coder/v2/coderd/httpapi"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/site"
)

// NewSync is a factory function for creating an IDP sync object.
// Due to the way we instantiate Coder, there is no way for the enterprise
// cli wrapper to pass in the enterprise IDP sync object.
// So instead, if the code is compiled with the enterprise logic, it will
// override this function to return the enterprise IDP sync object.
// For unit testing, the callers can specifically choose which "NewSync" to use.
var NewSync = func(logger slog.Logger, set *entitlements.Set, settings SyncSettings) IDPSync {
return NewAGPLSync(logger, set, settings)
}

type IDPSync interface {
// ParseOrganizationClaims takes claims from an OIDC provider, and returns the
// organization sync params for assigning users into organizations.
Expand Down Expand Up @@ -57,7 +46,7 @@ type SyncSettings struct {
OrganizationAssignDefault bool
}

func NewAGPLSync(logger slog.Logger, _ *entitlements.Set, settings SyncSettings) *AGPLIDPSync {
func NewAGPLSync(logger slog.Logger, settings SyncSettings) *AGPLIDPSync {
return &AGPLIDPSync{
Logger: logger.Named("idp-sync"),
SyncSettings: settings,
Expand Down
2 changes: 1 addition & 1 deletion coderd/idpsync/organization.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"github.com/coder/coder/v2/coderd/util/slice"
)

func (s AGPLIDPSync) ParseOrganizationClaims(ctx context.Context, _ jwt.MapClaims) (OrganizationParams, *HTTPError) {
func (s AGPLIDPSync) ParseOrganizationClaims(_ context.Context, _ jwt.MapClaims) (OrganizationParams, *HTTPError) {
// For AGPL we only sync the default organization.
return OrganizationParams{
SyncEnabled: false,
Expand Down
9 changes: 2 additions & 7 deletions coderd/userauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -742,9 +742,6 @@ type OIDCConfig struct {
// support the userinfo endpoint, or if the userinfo endpoint causes
// undesirable behavior.
IgnoreUserInfo bool
// IDPSync contains all the configuration for syncing user information
// from the external IDP.
IDPSync idpsync.IDPSync

// TODO: Move all idp fields into the IDPSync struct
// GroupField selects the claim field to be used as the created user's
Expand Down Expand Up @@ -1030,7 +1027,7 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) {
return
}

orgSync, orgSyncErr := api.OIDCConfig.IDPSync.ParseOrganizationClaims(ctx, mergedClaims)
orgSync, orgSyncErr := api.IDPSync.ParseOrganizationClaims(ctx, mergedClaims)
if orgSyncErr != nil {
orgSyncErr.Write(rw, r)
return
Expand Down Expand Up @@ -1491,9 +1488,7 @@ func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.C
}
}

// Only OIDC really supports syncing like this. At some point, we might
// want to move this configuration and allow github to allow do org syncing.
err = api.OIDCConfig.IDPSync.SyncOrganizations(ctx, tx, user, params.OrganizationSync)
err = api.IDPSync.SyncOrganizations(ctx, tx, user, params.OrganizationSync)
if err != nil {
return xerrors.Errorf("sync organizations: %w", err)
}
Expand Down
25 changes: 25 additions & 0 deletions codersdk/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -1545,6 +1545,31 @@ when required by your organization's security policy.`,
Group: &deploymentGroupOIDC,
YAML: "ignoreUserInfo",
},
{
Name: "OIDC Organization Field",
Description: "This field must be set if using the organization sync feature." +
" Set to the claim to be used for organizations.",
Flag: "oidc-organization-field",
Env: "CODER_OIDC_ORGANIZATION_FIELD",
// Empty value means sync is disabled
Default: "",
Value: &c.OIDC.OrganizationField,
Group: &deploymentGroupOIDC,
YAML: "organizationField",
},
{
Name: "OIDC Assign Default Organization",
Description: "If set to true, users will always be added to the default organization. " +
"If organization sync is enabled, then the default org is always added to the user's set of expected" +
"organizations.",
Flag: "oidc-organization-assign-default",
Env: "CODER_OIDC_ORGANIZATION_ASSIGN_DEFAULT",
// Single org deployments should always have this enabled.
Default: "true",
Value: &c.OIDC.OrganizationAssignDefault,
Group: &deploymentGroupOIDC,
YAML: "organizationAssignDefault",
},
{
Name: "OIDC Group Field",
Description: "This field must be set if using the group sync feature and the scope name is not 'groups'. Set to the claim to be used for groups.",
Expand Down
9 changes: 9 additions & 0 deletions enterprise/coderd/coderd.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import (
"github.com/coder/coder/v2/coderd/appearance"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/entitlements"
"github.com/coder/coder/v2/coderd/idpsync"
agplportsharing "github.com/coder/coder/v2/coderd/portsharing"
"github.com/coder/coder/v2/coderd/rbac/policy"
"github.com/coder/coder/v2/enterprise/coderd/enidpsync"
"github.com/coder/coder/v2/enterprise/coderd/portsharing"

"golang.org/x/xerrors"
Expand Down Expand Up @@ -78,6 +80,13 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
if options.Entitlements == nil {
options.Entitlements = entitlements.New()
}
if options.IDPSync == nil {
options.IDPSync = enidpsync.NewSync(options.Logger, options.Entitlements, idpsync.SyncSettings{
OrganizationField: options.DeploymentValues.OIDC.OrganizationField.Value(),
OrganizationMapping: options.DeploymentValues.OIDC.OrganizationMapping.Value,
OrganizationAssignDefault: options.DeploymentValues.OIDC.OrganizationAssignDefault.Value(),
})
}

ctx, cancelFunc := context.WithCancel(ctx)

Expand Down
0