Skip to content

feat: implement organization role sync #14649

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 13 commits into from
Sep 17, 2024
Next Next commit
rolesync start
  • Loading branch information
Emyrk committed Sep 16, 2024
commit 9a73013458d110bdf5ba03f095c6593a8f978878
7 changes: 7 additions & 0 deletions coderd/idpsync/idpsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/coder/coder/v2/coderd/runtimeconfig"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/site"
"github.com/coder/serpent"
)

// IDPSync is an interface, so we can implement this as AGPL and as enterprise,
Expand Down Expand Up @@ -76,6 +77,11 @@ type DeploymentSyncSettings struct {
GroupAllowList map[string]struct{}
// Legacy deployment settings that only apply to the default org.
Legacy DefaultOrgLegacySettings

// SiteRoleField syncs a user's site wide roles from an IDP.
SiteRoleField string
SiteRoleMapping serpent.Struct[map[string][]string]
SiteDefaultRoles []string
}

type DefaultOrgLegacySettings struct {
Expand Down Expand Up @@ -112,6 +118,7 @@ type SyncSettings struct {
DeploymentSyncSettings

Group runtimeconfig.RuntimeEntry[*GroupSyncSettings]
Role runtimeconfig.RuntimeEntry[*RoleSyncSettings]
}

func NewAGPLSync(logger slog.Logger, manager *runtimeconfig.Manager, settings DeploymentSyncSettings) *AGPLIDPSync {
Expand Down
52 changes: 52 additions & 0 deletions coderd/idpsync/role.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package idpsync

import (
"context"

"github.com/golang-jwt/jwt/v4"

"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/runtimeconfig"
)

type RoleParams struct {
// SyncEnabled if false will skip syncing the user's roles
SyncEnabled bool
MergedClaims jwt.MapClaims
}

func (AGPLIDPSync) RoleSyncEnabled() bool {
// AGPL does not support syncing groups.
return false
}
func (s AGPLIDPSync) RoleSyncSettings() runtimeconfig.RuntimeEntry[*RoleSyncSettings] {
return s.Role
}

func (s AGPLIDPSync) ParseRoleClaims(_ context.Context, _ jwt.MapClaims) (RoleParams, *HTTPError) {
return RoleParams{
SyncEnabled: s.RoleSyncEnabled(),
}, nil
}

func (s AGPLIDPSync) SyncRoles(ctx context.Context, db database.Store, user database.User, params RoleParams) error {
// Nothing happens if sync is not enabled
if !params.SyncEnabled {
return nil
}

// nolint:gocritic // all syncing is done as a system user
ctx = dbauthz.AsSystemRestricted(ctx)

return nil
}

type RoleSyncSettings struct {
// Field selects the claim field to be used as the created user's
// groups. If the group field is the empty string, then no group updates
// will ever come from the OIDC provider.
Field string `json:"field"`
// Mapping maps from an OIDC group --> Coder organization role
Mapping map[string][]string `json:"mapping"`
}