Documentation
¶
Overview ¶
Package scimsync provisions users and groups to a remote SCIM server.
Index ¶
- Variables
- type APIFeature
- type Feature
- type IdentitySnapshotSource
- type ListResponse
- type PostgresStore
- func (s *PostgresStore) Create(ctx context.Context, params UpsertParams) (ServiceProvider, error)
- func (s *PostgresStore) Delete(ctx context.Context, id SCIMServiceProviderID) error
- func (s *PostgresStore) GetByClient(ctx context.Context, clientID string) (ServiceProvider, error)
- func (s *PostgresStore) GetByID(ctx context.Context, id SCIMServiceProviderID) (ServiceProvider, error)
- func (s *PostgresStore) List(ctx context.Context) ([]ServiceProvider, error)
- func (s *PostgresStore) MarkSynced(ctx context.Context, id SCIMServiceProviderID, at time.Time) error
- func (s *PostgresStore) Update(ctx context.Context, id SCIMServiceProviderID, params UpsertParams) (ServiceProvider, error)
- type Resource
- type ResourceData
- type ResourceMeta
- type SCIMServiceProviderID
- type ScimEmail
- type ScimGroup
- type ScimGroupMember
- type ScimGroupRow
- type ScimName
- type ScimPoster
- type ScimRequest
- type ScimResponse
- type ScimUser
- type ScimUserRow
- type Service
- type ServiceProvider
- type SnapshotSource
- type UpsertParams
Constants ¶
This section is empty.
Variables ¶
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 (*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 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 ¶
func (s *PostgresStore) Delete(ctx context.Context, id SCIMServiceProviderID) error
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 ¶
func (s *PostgresStore) GetByID(ctx context.Context, id SCIMServiceProviderID) (ServiceProvider, error)
GetByID loads one provider; ErrNotFound when missing.
func (*PostgresStore) List ¶
func (s *PostgresStore) List(ctx context.Context) ([]ServiceProvider, error)
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 ¶
func (s *PostgresStore) Update(ctx context.Context, id SCIMServiceProviderID, params UpsertParams) (ServiceProvider, error)
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) 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 ¶
Typed IDs for the SCIM tables: UUIDv7 suffix, snake_case prefix matching the singular table name.
type ScimGroup ¶
type ScimGroup struct {
ResourceData
Display string `json:"displayName"`
Members []ScimGroupMember `json:"members,omitempty"`
}
ScimGroup is a SCIM Groups resource.
func (ScimGroup) GetExternalID ¶
GetExternalID shadows the embedded method.
type ScimGroupMember ¶
type ScimGroupMember struct {
Value string `json:"value"`
}
ScimGroupMember references one user by id.
type ScimGroupRow ¶
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 ¶
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 ¶
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) 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 ¶
UpsertParams carries the fields a caller supplies.
func (UpsertParams) Validate ¶
func (p UpsertParams) Validate() error
Validate checks the endpoint and client credentials.