Help us shape the future of Go! Take the 2026 Go Developer Survey

scimsync

package
v0.0.12 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 20, 2026 License: Apache-2.0, MIT Imports: 19 Imported by: 0

Documentation

Overview

Package scimsync provisions users and groups to a remote SCIM server.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNotFound      = errors.New("scimsync: service provider not found")
	ErrUnknownClient = errors.New("scimsync: OIDC client not found")
	ErrDuplicate     = errors.New("scimsync: client already has a SCIM service provider")
	ErrInvalidToken  = errors.New("scimsync: invalid bearer token")
	ErrSyncFailed    = errors.New("scimsync: sync failed")
)

errors mapped to HTTP by the transport layer.

Functions

This section is empty.

Types

type APIFeature

type APIFeature struct {
	// contains filtered or unexported fields
}

APIFeature mounts the provider surface. The REST routes are gone: the whole surface serves ConnectRPC exclusively (see handler_rpc.go).

func New

func New(service *Service) *APIFeature

New builds the feature over the sync service.

func (*APIFeature) Name

func (*APIFeature) Name() string

Name implements federation.Feature.

func (*APIFeature) RPCService added in v0.0.12

func (f *APIFeature) RPCService() (string, http.Handler)

RPCService returns the Connect registration for the SCIM provider surface.

type Feature

type Feature struct{}

Feature is the wireable scimsync unit.

func (Feature) Name

func (Feature) Name() string

Name implements federation.Feature.

type IdentitySnapshotSource

type IdentitySnapshotSource struct {
	// contains filtered or unexported fields
}

SnapshotSource adapts the identity stores to the SCIM snapshot contract, scoped by the client's group allowlist. It reads the identity tables directly (raw SQL, no identity import) because the rows are cross-module projections.

func NewIdentitySnapshotSource

func NewIdentitySnapshotSource(db datastore.Store) IdentitySnapshotSource

NewSnapshotSource builds the identity-backed snapshot source.

func (IdentitySnapshotSource) GroupsForClient

func (s IdentitySnapshotSource) GroupsForClient(ctx context.Context, clientID string) ([]ScimGroupRow, error)

func (IdentitySnapshotSource) UsersForClient

func (s IdentitySnapshotSource) UsersForClient(ctx context.Context, clientID string) ([]ScimUserRow, error)

type ListResponse

type ListResponse[T any] struct {
	Resources    []T `json:"Resources"`
	TotalResults int `json:"totalResults"`
	StartIndex   int `json:"startIndex"`
	ItemsPerPage int `json:"itemsPerPage"`
}

ListResponse is the SCIM list envelope.

type PostgresStore

type PostgresStore struct {
	// contains filtered or unexported fields
}

PostgresStore persists service providers. Tokens are stored encrypted with the configured cipher; reads decrypt transparently.

func NewPostgresStore

func NewPostgresStore(exec datastore.Executor, cipher tokenCipher) *PostgresStore

NewPostgresStore builds the store.

func (*PostgresStore) Create

func (s *PostgresStore) Create(ctx context.Context, params UpsertParams) (ServiceProvider, error)

Create inserts a provider for a client; ErrDuplicate when the client already has one, ErrUnknownClient when the client is missing.

func (*PostgresStore) Delete

Delete removes one provider.

func (*PostgresStore) GetByClient

func (s *PostgresStore) GetByClient(ctx context.Context, clientID string) (ServiceProvider, error)

GetByClient loads the provider bound to an OIDC client; ErrNotFound when the client has none.

func (*PostgresStore) GetByID

GetByID loads one provider; ErrNotFound when missing.

func (*PostgresStore) List

List returns all providers (admin surface; the set is small).

func (*PostgresStore) MarkSynced

func (s *PostgresStore) MarkSynced(ctx context.Context, id SCIMServiceProviderID, at time.Time) error

MarkSynced stamps last_synced_at after a successful push.

func (*PostgresStore) Update

Update replaces endpoint/token for one provider.

type Resource

type Resource interface {
	GetID() string
	GetExternalID() string
	GetSchemas() []string
	GetMeta() ResourceMeta
}

Resource is the generic SCIM resource contract.

type ResourceData

type ResourceData struct {
	ID         string        `json:"id,omitempty"`
	ExternalID string        `json:"externalId,omitempty"`
	Schemas    []string      `json:"schemas"`
	Meta       *ResourceMeta `json:"meta,omitempty"`
}

ResourceData is the common SCIM resource envelope.

func (ResourceData) GetExternalID

func (r ResourceData) GetExternalID() string

GetExternalID implements Resource.

func (ResourceData) GetID

func (r ResourceData) GetID() string

GetID implements Resource.

func (ResourceData) GetMeta

func (r ResourceData) GetMeta() ResourceMeta

GetMeta implements Resource.

func (ResourceData) GetSchemas

func (r ResourceData) GetSchemas() []string

GetSchemas implements Resource.

type ResourceMeta

type ResourceMeta struct {
	Location     string    `json:"location,omitempty"`
	ResourceType string    `json:"resourceType,omitempty"`
	Created      time.Time `json:"created"`
	LastModified time.Time `json:"lastModified"`
	Version      string    `json:"version,omitempty"`
}

ResourceMeta carries location and timestamps.

type SCIMServiceProviderID

type SCIMServiceProviderID = typeid.TypeID[scimServiceProviderPrefix]

Typed IDs for the SCIM tables: UUIDv7 suffix, snake_case prefix matching the singular table name.

type ScimEmail

type ScimEmail struct {
	Value   string `json:"value"`
	Primary bool   `json:"primary,omitempty"`
}

ScimEmail is one email entry.

type ScimGroup

type ScimGroup struct {
	ResourceData
	Display string            `json:"displayName"`
	Members []ScimGroupMember `json:"members,omitempty"`
}

ScimGroup is a SCIM Groups resource.

func (ScimGroup) GetExternalID

func (g ScimGroup) GetExternalID() string

GetExternalID shadows the embedded method.

type ScimGroupMember

type ScimGroupMember struct {
	Value string `json:"value"`
}

ScimGroupMember references one user by id.

type ScimGroupRow

type ScimGroupRow struct {
	ID      string
	Name    string
	Members []string
}

ScimGroupRow is one group in a sync snapshot with member user IDs.

type ScimName

type ScimName struct {
	GivenName  string `json:"givenName,omitempty"`
	FamilyName string `json:"familyName,omitempty"`
}

ScimName splits given/family names.

type ScimPoster

type ScimPoster interface {
	Do(ctx context.Context, req ScimRequest) (ScimResponse, error)
}

scimPoster performs one outbound SCIM request. The composition root implements it over net/http; the service stays transport-free.

type ScimRequest

type ScimRequest struct {
	Method  string
	URL     string
	Headers map[string]string
	Body    []byte
}

scimRequest is one outbound SCIM call the service assembles.

type ScimResponse

type ScimResponse struct {
	StatusCode int
	// Header carries the response headers the retry policy reads
	// (Retry-After).
	Header map[string]string
	Body   []byte
}

scimResponse is the provider's answer.

type ScimUser

type ScimUser struct {
	ResourceData
	UserName string      `json:"userName"`
	Name     *ScimName   `json:"name,omitempty"`
	Display  string      `json:"displayName,omitempty"`
	Active   bool        `json:"active"`
	Emails   []ScimEmail `json:"emails,omitempty"`
}

ScimUser is a SCIM Users resource (request and response).

func (ScimUser) GetExternalID

func (u ScimUser) GetExternalID() string

GetExternalID shadows the embedded method to keep pointer/uniform use.

type ScimUserRow

type ScimUserRow struct {
	ID          string
	Username    string
	DisplayName string
	FirstName   string
	LastName    string
	Email       string
	Active      bool
}

ScimUserRow is one user in a sync snapshot (plain strings: the SCIM payload is external-facing, typed IDs stop at the store).

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service drives the outbound provisioning.

func NewService

func NewService(store *PostgresStore, source SnapshotSource, poster ScimPoster, log *slog.Logger) *Service

NewService builds the sync service.

func (*Service) SyncAll

func (s *Service) SyncAll(ctx context.Context) error

SyncAll pushes every configured provider (recurring tick path).

func (*Service) SyncProvider

func (s *Service) SyncProvider(ctx context.Context, provider ServiceProvider) error

SyncProvider pushes one provider's snapshot: list remote resources, create missing, update changed, delete remote-only entries.

type ServiceProvider

type ServiceProvider struct {
	ID           SCIMServiceProviderID `json:"id"`
	Endpoint     string                `json:"endpoint"`
	Token        string                `json:"token"` // shown once on write; empty on read
	OIDCClientID string                `json:"oidc_client_id"`
	LastSyncedAt *time.Time            `json:"last_synced_at,omitzero"`
	CreatedAt    time.Time             `json:"created_at"`
}

ServiceProvider is one configured remote SCIM provider.

type SnapshotSource

type SnapshotSource interface {
	UsersForClient(ctx context.Context, clientID string) ([]ScimUserRow, error)
	GroupsForClient(ctx context.Context, clientID string) ([]ScimGroupRow, error)
}

snapshot source for the sync: allowed users and groups of a client. The oidc store answers both; the interface keeps scimsync decoupled.

type UpsertParams

type UpsertParams struct {
	Endpoint     string
	Token        string
	OIDCClientID string
}

UpsertParams carries the fields a caller supplies.

func (UpsertParams) Validate

func (p UpsertParams) Validate() error

Validate checks the endpoint and client credentials.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL