chore: move organizatinon sync to runtime configuration (#15431)

Moves the configuration from environment to database backed, to allow
configuring organization sync at runtime.
This commit is contained in:
Steven Masley
2024-11-08 08:44:14 -06:00
committed by GitHub
parent 7b33ab0dcf
commit 782214bcd8
28 changed files with 883 additions and 280 deletions

View File

@ -2,72 +2,39 @@ package enidpsync
import (
"context"
"net/http"
"github.com/golang-jwt/jwt/v4"
"github.com/google/uuid"
"cdr.dev/slog"
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/idpsync"
"github.com/coder/coder/v2/coderd/util/slice"
"github.com/coder/coder/v2/codersdk"
)
func (e EnterpriseIDPSync) OrganizationSyncEnabled() bool {
return e.entitlements.Enabled(codersdk.FeatureMultipleOrganizations) && e.OrganizationField != ""
func (e EnterpriseIDPSync) OrganizationSyncEntitled() bool {
return e.entitlements.Enabled(codersdk.FeatureMultipleOrganizations)
}
func (e EnterpriseIDPSync) OrganizationSyncEnabled(ctx context.Context, db database.Store) bool {
if !e.OrganizationSyncEntitled() {
return false
}
settings, err := e.OrganizationSyncSettings(ctx, db)
if err == nil && settings.Field != "" {
return true
}
return false
}
func (e EnterpriseIDPSync) ParseOrganizationClaims(ctx context.Context, mergedClaims jwt.MapClaims) (idpsync.OrganizationParams, *idpsync.HTTPError) {
if !e.OrganizationSyncEnabled() {
if !e.OrganizationSyncEntitled() {
// Default to agpl if multi-org is not enabled
return e.AGPLIDPSync.ParseOrganizationClaims(ctx, mergedClaims)
}
// nolint:gocritic // all syncing is done as a system user
ctx = dbauthz.AsSystemRestricted(ctx)
userOrganizations := make([]uuid.UUID, 0)
// Pull extra organizations from the claims.
if e.OrganizationField != "" {
organizationRaw, ok := mergedClaims[e.OrganizationField]
if ok {
parsedOrganizations, err := idpsync.ParseStringSliceClaim(organizationRaw)
if err != nil {
return idpsync.OrganizationParams{}, &idpsync.HTTPError{
Code: http.StatusBadRequest,
Msg: "Failed to sync organizations from the OIDC claims",
Detail: err.Error(),
RenderStaticPage: false,
RenderDetailMarkdown: false,
}
}
// Keep track of which claims are not mapped for debugging purposes.
var ignored []string
for _, parsedOrg := range parsedOrganizations {
if mappedOrganization, ok := e.OrganizationMapping[parsedOrg]; ok {
// parsedOrg is in the mapping, so add the mapped organizations to the
// user's organizations.
userOrganizations = append(userOrganizations, mappedOrganization...)
} else {
ignored = append(ignored, parsedOrg)
}
}
e.Logger.Debug(ctx, "parsed organizations from claim",
slog.F("len", len(parsedOrganizations)),
slog.F("ignored", ignored),
slog.F("organizations", parsedOrganizations),
)
}
}
return idpsync.OrganizationParams{
// If the field is not set, then sync is not enabled.
SyncEnabled: e.OrganizationField != "",
IncludeDefault: e.OrganizationAssignDefault,
// Do not return duplicates
Organizations: slice.Unique(userOrganizations),
// Return true if entitled
SyncEntitled: true,
MergedClaims: mergedClaims,
}, nil
}