Documentation
¶
Overview ¶
contract.go: Wires the scim plugin into the forge-dashboard contract surface via plugin.ContractContributor.
Index ¶
- Constants
- Variables
- type Config
- type Email
- type GroupRef
- type GroupResource
- type ListResponse
- type MemberRef
- type MemoryStore
- func (s *MemoryStore) CountAllLogsByStatus(_ context.Context, appID string) (success, errors, skipped int, err error)
- func (s *MemoryStore) CountLogsByStatus(_ context.Context, configID id.SCIMConfigID) (success, errors, skipped int, err error)
- func (s *MemoryStore) CreateConfig(_ context.Context, c *SCIMConfig) error
- func (s *MemoryStore) CreateLog(_ context.Context, l *ProvisionLog) error
- func (s *MemoryStore) CreateToken(_ context.Context, t *Token) error
- func (s *MemoryStore) DeleteConfig(_ context.Context, configID id.SCIMConfigID) error
- func (s *MemoryStore) DeleteToken(_ context.Context, tokenID id.SCIMTokenID) error
- func (s *MemoryStore) FindTokenByPlaintext(_ context.Context, plaintext string) (*Token, *SCIMConfig, error)
- func (s *MemoryStore) GetConfig(_ context.Context, configID id.SCIMConfigID) (*SCIMConfig, error)
- func (s *MemoryStore) GetToken(_ context.Context, tokenID id.SCIMTokenID) (*Token, error)
- func (s *MemoryStore) ListAllLogs(_ context.Context, appID string, limit int) ([]*ProvisionLog, error)
- func (s *MemoryStore) ListConfigs(_ context.Context, appID string) ([]*SCIMConfig, error)
- func (s *MemoryStore) ListConfigsByOrg(_ context.Context, orgID id.OrgID) ([]*SCIMConfig, error)
- func (s *MemoryStore) ListLogs(_ context.Context, configID id.SCIMConfigID, limit int) ([]*ProvisionLog, error)
- func (s *MemoryStore) ListTokens(_ context.Context, configID id.SCIMConfigID) ([]*Token, error)
- func (s *MemoryStore) UpdateConfig(_ context.Context, c *SCIMConfig) error
- func (s *MemoryStore) UpdateToken(_ context.Context, t *Token) error
- type Meta
- type MongoStore
- func (s *MongoStore) CountAllLogsByStatus(ctx context.Context, appID string) (success, errs, skipped int, err error)
- func (s *MongoStore) CountLogsByStatus(ctx context.Context, configID id.SCIMConfigID) (success, errs, skipped int, err error)
- func (s *MongoStore) CreateConfig(ctx context.Context, c *SCIMConfig) error
- func (s *MongoStore) CreateLog(ctx context.Context, l *ProvisionLog) error
- func (s *MongoStore) CreateToken(ctx context.Context, t *Token) error
- func (s *MongoStore) DeleteConfig(ctx context.Context, configID id.SCIMConfigID) error
- func (s *MongoStore) DeleteToken(ctx context.Context, tokenID id.SCIMTokenID) error
- func (s *MongoStore) FindTokenByPlaintext(ctx context.Context, plaintext string) (*Token, *SCIMConfig, error)
- func (s *MongoStore) GetConfig(ctx context.Context, configID id.SCIMConfigID) (*SCIMConfig, error)
- func (s *MongoStore) GetToken(ctx context.Context, tokenID id.SCIMTokenID) (*Token, error)
- func (s *MongoStore) ListAllLogs(ctx context.Context, appID string, limit int) ([]*ProvisionLog, error)
- func (s *MongoStore) ListConfigs(ctx context.Context, appID string) ([]*SCIMConfig, error)
- func (s *MongoStore) ListConfigsByOrg(ctx context.Context, orgID id.OrgID) ([]*SCIMConfig, error)
- func (s *MongoStore) ListLogs(ctx context.Context, configID id.SCIMConfigID, limit int) ([]*ProvisionLog, error)
- func (s *MongoStore) ListTokens(ctx context.Context, configID id.SCIMConfigID) ([]*Token, error)
- func (s *MongoStore) UpdateConfig(ctx context.Context, c *SCIMConfig) error
- func (s *MongoStore) UpdateToken(ctx context.Context, t *Token) error
- type Name
- type Operation
- type PatchOp
- type Plugin
- func (p *Plugin) DeclareSettings(m *settings.Manager) error
- func (p *Plugin) MigrationGroups(driverName string) []*migrate.Group
- func (p *Plugin) Name() string
- func (p *Plugin) OnAfterOrgDelete(ctx context.Context, orgID id.OrgID) error
- func (p *Plugin) OnInit(_ context.Context, engine plugin.Engine) error
- func (p *Plugin) RegisterContract(d *dispatcher.Dispatcher, reg contract.Registry, wreg contract.WardenRegistry, ...) error
- func (p *Plugin) RegisterRoutes(router forge.Router) error
- func (p *Plugin) SetSCIMStore(s Store)
- type ProvisionLog
- type ResourceTypeList
- type SCIMConfig
- type SCIMError
- type SQLStore
- func (s *SQLStore) CountAllLogsByStatus(ctx context.Context, appID string) (success, errs, skipped int, err error)
- func (s *SQLStore) CountLogsByStatus(ctx context.Context, configID id.SCIMConfigID) (success, errs, skipped int, err error)
- func (s *SQLStore) CreateConfig(ctx context.Context, c *SCIMConfig) error
- func (s *SQLStore) CreateLog(ctx context.Context, l *ProvisionLog) error
- func (s *SQLStore) CreateToken(ctx context.Context, t *Token) error
- func (s *SQLStore) DeleteConfig(ctx context.Context, configID id.SCIMConfigID) error
- func (s *SQLStore) DeleteToken(ctx context.Context, tokenID id.SCIMTokenID) error
- func (s *SQLStore) FindTokenByPlaintext(ctx context.Context, plaintext string) (*Token, *SCIMConfig, error)
- func (s *SQLStore) GetConfig(ctx context.Context, configID id.SCIMConfigID) (*SCIMConfig, error)
- func (s *SQLStore) GetToken(ctx context.Context, tokenID id.SCIMTokenID) (*Token, error)
- func (s *SQLStore) ListAllLogs(ctx context.Context, appID string, limit int) ([]*ProvisionLog, error)
- func (s *SQLStore) ListConfigs(ctx context.Context, appID string) ([]*SCIMConfig, error)
- func (s *SQLStore) ListConfigsByOrg(ctx context.Context, orgID id.OrgID) ([]*SCIMConfig, error)
- func (s *SQLStore) ListLogs(ctx context.Context, configID id.SCIMConfigID, limit int) ([]*ProvisionLog, error)
- func (s *SQLStore) ListTokens(ctx context.Context, configID id.SCIMConfigID) ([]*Token, error)
- func (s *SQLStore) UpdateConfig(ctx context.Context, c *SCIMConfig) error
- func (s *SQLStore) UpdateToken(ctx context.Context, t *Token) error
- type SchemaList
- type Service
- func (s *Service) ChangeUserName(ctx context.Context, cfg *SCIMConfig, u *user.User, email string) error
- func (s *Service) CountAllLogsByStatus(ctx context.Context, appID string) (success, failed, skipped int, err error)
- func (s *Service) CountLogsByStatus(ctx context.Context, configID id.SCIMConfigID) (success, failed, skipped int, err error)
- func (s *Service) CreateConfig(ctx context.Context, c *SCIMConfig) error
- func (s *Service) DeactivateUser(ctx context.Context, cfg *SCIMConfig, userID id.UserID) error
- func (s *Service) DeleteConfig(ctx context.Context, configID id.SCIMConfigID) error
- func (s *Service) GenerateToken(ctx context.Context, configID id.SCIMConfigID, name string, ...) (string, *Token, error)
- func (s *Service) GetConfig(ctx context.Context, configID id.SCIMConfigID) (*SCIMConfig, error)
- func (s *Service) ListAllLogs(ctx context.Context, appID string, limit int) ([]*ProvisionLog, error)
- func (s *Service) ListConfigs(ctx context.Context, appID string) ([]*SCIMConfig, error)
- func (s *Service) ListConfigsByOrg(ctx context.Context, orgID id.OrgID) ([]*SCIMConfig, error)
- func (s *Service) ListLogs(ctx context.Context, configID id.SCIMConfigID, limit int) ([]*ProvisionLog, error)
- func (s *Service) ListTokens(ctx context.Context, configID id.SCIMConfigID) ([]*Token, error)
- func (s *Service) LoadTeam(ctx context.Context, cfg *SCIMConfig, raw string) (*organization.Team, error)
- func (s *Service) LoadUser(ctx context.Context, cfg *SCIMConfig, raw string) (*user.User, error)
- func (s *Service) ProvisionGroup(ctx context.Context, cfg *SCIMConfig, scimGroup *GroupResource) (*organization.Team, string, error)
- func (s *Service) ProvisionUser(ctx context.Context, cfg *SCIMConfig, scimUser *UserResource) (*user.User, string, error)
- func (s *Service) RecordLog(ctx context.Context, configID id.SCIMConfigID, ...)
- func (s *Service) ReplaceUser(ctx context.Context, cfg *SCIMConfig, target *user.User, ...) error
- func (s *Service) RevokeToken(ctx context.Context, tokenID id.SCIMTokenID) error
- func (s *Service) RotateToken(ctx context.Context, oldTokenID id.SCIMTokenID, newName string, ...) (string, *Token, error)
- func (s *Service) UpdateConfig(ctx context.Context, c *SCIMConfig) error
- func (s *Service) ValidateToken(ctx context.Context, plaintext string) (*Token, *SCIMConfig, error)
- type ServiceProviderConfig
- type Store
- type Token
- type UserResource
Constants ¶
const ( SchemaUser = "urn:ietf:params:scim:schemas:core:2.0:User" SchemaGroup = "urn:ietf:params:scim:schemas:core:2.0:Group" SchemaListResponse = "urn:ietf:params:scim:api:messages:2.0:ListResponse" SchemaError = "urn:ietf:params:scim:api:messages:2.0:Error" SchemaPatchOp = "urn:ietf:params:scim:api:messages:2.0:PatchOp" SchemaServiceConfig = "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig" SchemaResourceType = "urn:ietf:params:scim:schemas:core:2.0:ResourceType" SchemaSchema = "urn:ietf:params:scim:schemas:core:2.0:Schema" )
SCIM schema URIs.
const ( LogStatusSuccess = "success" LogStatusError = "error" LogStatusSkipped = "skipped" )
Provision log statuses.
const ( ActionCreateUser = "create_user" ActionUpdateUser = "update_user" ActionDeleteUser = "delete_user" ActionSuspendUser = "suspend_user" ActionCreateGroup = "create_group" ActionUpdateGroup = "update_group" ActionDeleteGroup = "delete_group" ActionAddMember = "add_member" ActionRemoveMember = "remove_member" )
Provision log actions.
Variables ¶
var ( // SettingSCIMEnabled controls whether SCIM provisioning is enabled. SettingSCIMEnabled = settings.Define("scim.enabled", false, settings.WithDisplayName("Enable SCIM Provisioning"), settings.WithDescription("Enable SCIM 2.0 endpoints for automated user and group provisioning"), settings.WithCategory("SCIM"), settings.WithScopes(settings.ScopeGlobal, settings.ScopeApp), settings.WithOrder(10), ) // SettingAutoCreateUsers controls whether users are auto-created on SCIM push. SettingAutoCreateUsers = settings.Define("scim.auto_create_users", true, settings.WithDisplayName("Auto-Create Users"), settings.WithDescription("Automatically create new users when provisioned via SCIM"), settings.WithCategory("SCIM"), settings.WithScopes(settings.ScopeGlobal, settings.ScopeApp), settings.WithVisibleWhen("scim.enabled", "true", "eq"), settings.WithOrder(20), ) // SettingAutoSuspendUsers controls auto-suspension on SCIM deactivation. SettingAutoSuspendUsers = settings.Define("scim.auto_suspend_users", true, settings.WithDisplayName("Auto-Suspend Deprovisioned Users"), settings.WithDescription("Automatically suspend users when deactivated via SCIM"), settings.WithCategory("SCIM"), settings.WithScopes(settings.ScopeGlobal, settings.ScopeApp), settings.WithVisibleWhen("scim.enabled", "true", "eq"), settings.WithOrder(30), ) // SettingGroupSync controls whether SCIM Groups are synced to teams. SettingGroupSync = settings.Define("scim.group_sync", false, settings.WithDisplayName("Sync SCIM Groups to Teams"), settings.WithDescription("Map SCIM Group resources to organization teams"), settings.WithCategory("SCIM"), settings.WithScopes(settings.ScopeGlobal, settings.ScopeApp), settings.WithVisibleWhen("scim.enabled", "true", "eq"), settings.WithOrder(40), ) // SettingDefaultRole is the default org role for SCIM-provisioned users. SettingDefaultRole = settings.Define("scim.default_role", "member", settings.WithDisplayName("Default Member Role"), settings.WithDescription("Default organization role assigned to SCIM-provisioned users"), settings.WithCategory("SCIM"), settings.WithScopes(settings.ScopeGlobal, settings.ScopeApp), settings.WithInputType(formconfig.FieldSelect), settings.WithOptions( formconfig.SelectOption{Label: "Member", Value: "member"}, formconfig.SelectOption{Label: "Admin", Value: "admin"}, ), settings.WithVisibleWhen("scim.enabled", "true", "eq"), settings.WithOrder(50), ) // SettingTokenExpiryDays controls default token expiry. SettingTokenExpiryDays = settings.Define("scim.token_expiry_days", 365, settings.WithDisplayName("Token Expiry (days)"), settings.WithDescription("Default expiry period for new SCIM bearer tokens (0 = no expiry)"), settings.WithCategory("SCIM"), settings.WithScopes(settings.ScopeGlobal, settings.ScopeApp), settings.WithInputType(formconfig.FieldNumber), settings.WithUIValidation(formconfig.Validation{Min: intPtr(0), Max: intPtr(3650)}), settings.WithHelpText("Set to 0 for tokens that never expire. Default: 365"), settings.WithVisibleWhen("scim.enabled", "true", "eq"), settings.WithOrder(60), ) )
Dynamic setting definitions for the SCIM plugin.
var ( ErrConfigNotFound = errors.New("scim: config not found") ErrTokenNotFound = errors.New("scim: token not found") )
Store defines the persistence interface for SCIM entities. Sentinel errors every store returns for a missing row, so callers and the conformance suite can tell absence from failure.
var ErrOutOfScope = errors.New("scim: resource outside configuration scope")
ErrOutOfScope marks a row that exists but lies outside the SCIM configuration's app or organization. Handlers answer 404 so a token for one tenant cannot probe another.
var PostgresMigrations = migrate.NewGroup("authsome-scim", migrate.DependsOn("authsome"))
PostgresMigrations is the postgres migration group for the SCIM plugin.
var SqliteMigrations = migrate.NewGroup("authsome-scim", migrate.DependsOn("authsome"))
SqliteMigrations is the SQLite migration group for the SCIM plugin.
Functions ¶
This section is empty.
Types ¶
type Config ¶
type Config struct {
// BasePath is the HTTP prefix for SCIM endpoints (default: "/scim/v2").
BasePath string
// TokenLength is the number of random bytes for generated bearer tokens (default: 32).
TokenLength int
// MaxLogEntries is the maximum number of provision logs to keep per config (default: 1000).
MaxLogEntries int
}
Config holds plugin-level configuration for the SCIM plugin.
type Email ¶
type Email struct {
Value string `json:"value"`
Type string `json:"type,omitempty"`
Primary bool `json:"primary"`
}
Email represents a SCIM email address.
type GroupRef ¶
type GroupRef struct {
Value string `json:"value"`
Display string `json:"display,omitempty"`
Ref string `json:"$ref,omitempty"`
}
GroupRef is a reference to a SCIM group.
type GroupResource ¶
type GroupResource struct {
Schemas []string `json:"schemas"`
ID string `json:"id,omitempty"`
ExternalID string `json:"externalId,omitempty"`
DisplayName string `json:"displayName"`
Members []MemberRef `json:"members,omitempty"`
Meta *Meta `json:"meta,omitempty"`
}
GroupResource represents a SCIM 2.0 Group resource.
func TeamToSCIMGroup ¶
func TeamToSCIMGroup(t *organization.Team, members []*organization.Member, baseURL string) *GroupResource
TeamToSCIMGroup converts an AuthSome team to a SCIM Group resource.
type ListResponse ¶
type ListResponse struct {
Schemas []string `json:"schemas"`
TotalResults int `json:"totalResults"`
StartIndex int `json:"startIndex"`
ItemsPerPage int `json:"itemsPerPage"`
Resources []any `json:"Resources"`
}
ListResponse is a SCIM list response (RFC 7644 Section 3.4.2).
type MemberRef ¶
type MemberRef struct {
Value string `json:"value"`
Display string `json:"display,omitempty"`
Ref string `json:"$ref,omitempty"`
}
MemberRef is a member reference within a SCIM Group.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore is a thread-safe in-memory implementation of the SCIM Store.
func NewMemoryStore ¶
func NewMemoryStore() *MemoryStore
NewMemoryStore creates a new in-memory SCIM store.
func (*MemoryStore) CountAllLogsByStatus ¶
func (*MemoryStore) CountLogsByStatus ¶
func (s *MemoryStore) CountLogsByStatus(_ context.Context, configID id.SCIMConfigID) (success, errors, skipped int, err error)
func (*MemoryStore) CreateConfig ¶
func (s *MemoryStore) CreateConfig(_ context.Context, c *SCIMConfig) error
func (*MemoryStore) CreateLog ¶
func (s *MemoryStore) CreateLog(_ context.Context, l *ProvisionLog) error
func (*MemoryStore) CreateToken ¶
func (s *MemoryStore) CreateToken(_ context.Context, t *Token) error
func (*MemoryStore) DeleteConfig ¶
func (s *MemoryStore) DeleteConfig(_ context.Context, configID id.SCIMConfigID) error
func (*MemoryStore) DeleteToken ¶
func (s *MemoryStore) DeleteToken(_ context.Context, tokenID id.SCIMTokenID) error
func (*MemoryStore) FindTokenByPlaintext ¶
func (s *MemoryStore) FindTokenByPlaintext(_ context.Context, plaintext string) (*Token, *SCIMConfig, error)
FindTokenByPlaintext linearly scans stored tokens and bcrypt-compares each one against the presented plaintext. Bcrypt digests are salted, so an index lookup is not possible; a production store would want a lookup key (for example a token prefix column) to narrow the scan first.
func (*MemoryStore) GetConfig ¶
func (s *MemoryStore) GetConfig(_ context.Context, configID id.SCIMConfigID) (*SCIMConfig, error)
func (*MemoryStore) GetToken ¶
func (s *MemoryStore) GetToken(_ context.Context, tokenID id.SCIMTokenID) (*Token, error)
func (*MemoryStore) ListAllLogs ¶
func (s *MemoryStore) ListAllLogs(_ context.Context, appID string, limit int) ([]*ProvisionLog, error)
func (*MemoryStore) ListConfigs ¶
func (s *MemoryStore) ListConfigs(_ context.Context, appID string) ([]*SCIMConfig, error)
func (*MemoryStore) ListConfigsByOrg ¶
func (s *MemoryStore) ListConfigsByOrg(_ context.Context, orgID id.OrgID) ([]*SCIMConfig, error)
func (*MemoryStore) ListLogs ¶
func (s *MemoryStore) ListLogs(_ context.Context, configID id.SCIMConfigID, limit int) ([]*ProvisionLog, error)
func (*MemoryStore) ListTokens ¶
func (s *MemoryStore) ListTokens(_ context.Context, configID id.SCIMConfigID) ([]*Token, error)
func (*MemoryStore) UpdateConfig ¶
func (s *MemoryStore) UpdateConfig(_ context.Context, c *SCIMConfig) error
func (*MemoryStore) UpdateToken ¶
func (s *MemoryStore) UpdateToken(_ context.Context, t *Token) error
type Meta ¶
type Meta struct {
ResourceType string `json:"resourceType"`
Created string `json:"created,omitempty"`
LastModified string `json:"lastModified,omitempty"`
Location string `json:"location,omitempty"`
}
Meta holds SCIM resource metadata.
type MongoStore ¶
type MongoStore struct {
// contains filtered or unexported fields
}
MongoStore implements Store on MongoDB. The plugin has no mongo migration group, so the store installs its own indexes before its first write.
func NewMongoStore ¶
func NewMongoStore(db *grove.DB) *MongoStore
NewMongoStore creates a SCIM store on the mongo driver.
func (*MongoStore) CountAllLogsByStatus ¶
func (*MongoStore) CountLogsByStatus ¶
func (s *MongoStore) CountLogsByStatus(ctx context.Context, configID id.SCIMConfigID) (success, errs, skipped int, err error)
func (*MongoStore) CreateConfig ¶
func (s *MongoStore) CreateConfig(ctx context.Context, c *SCIMConfig) error
func (*MongoStore) CreateLog ¶
func (s *MongoStore) CreateLog(ctx context.Context, l *ProvisionLog) error
func (*MongoStore) CreateToken ¶
func (s *MongoStore) CreateToken(ctx context.Context, t *Token) error
func (*MongoStore) DeleteConfig ¶
func (s *MongoStore) DeleteConfig(ctx context.Context, configID id.SCIMConfigID) error
func (*MongoStore) DeleteToken ¶
func (s *MongoStore) DeleteToken(ctx context.Context, tokenID id.SCIMTokenID) error
func (*MongoStore) FindTokenByPlaintext ¶
func (s *MongoStore) FindTokenByPlaintext(ctx context.Context, plaintext string) (*Token, *SCIMConfig, error)
FindTokenByPlaintext resolves by the lookup digest and bcrypt-compares that document; documents without a lookup are compared one by one and upgraded on a match.
func (*MongoStore) GetConfig ¶
func (s *MongoStore) GetConfig(ctx context.Context, configID id.SCIMConfigID) (*SCIMConfig, error)
func (*MongoStore) GetToken ¶
func (s *MongoStore) GetToken(ctx context.Context, tokenID id.SCIMTokenID) (*Token, error)
func (*MongoStore) ListAllLogs ¶
func (s *MongoStore) ListAllLogs(ctx context.Context, appID string, limit int) ([]*ProvisionLog, error)
func (*MongoStore) ListConfigs ¶
func (s *MongoStore) ListConfigs(ctx context.Context, appID string) ([]*SCIMConfig, error)
func (*MongoStore) ListConfigsByOrg ¶
func (s *MongoStore) ListConfigsByOrg(ctx context.Context, orgID id.OrgID) ([]*SCIMConfig, error)
func (*MongoStore) ListLogs ¶
func (s *MongoStore) ListLogs(ctx context.Context, configID id.SCIMConfigID, limit int) ([]*ProvisionLog, error)
func (*MongoStore) ListTokens ¶
func (s *MongoStore) ListTokens(ctx context.Context, configID id.SCIMConfigID) ([]*Token, error)
func (*MongoStore) UpdateConfig ¶
func (s *MongoStore) UpdateConfig(ctx context.Context, c *SCIMConfig) error
func (*MongoStore) UpdateToken ¶
func (s *MongoStore) UpdateToken(ctx context.Context, t *Token) error
type Name ¶
type Name struct {
GivenName string `json:"givenName"`
FamilyName string `json:"familyName"`
Formatted string `json:"formatted,omitempty"`
}
Name represents a SCIM name component.
type Operation ¶
type Operation struct {
Op string `json:"op"`
Path string `json:"path,omitempty"`
Value any `json:"value,omitempty"`
}
Operation is a single SCIM PATCH operation.
type PatchOp ¶
type PatchOp struct {
Schemas []string `json:"schemas"`
Operations []Operation `json:"Operations"`
}
PatchOp represents a SCIM PATCH request (RFC 7644 Section 3.5.2).
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin is the SCIM 2.0 provisioning plugin for authsome.
func (*Plugin) DeclareSettings ¶
DeclareSettings registers SCIM settings with the settings manager.
func (*Plugin) MigrationGroups ¶
MigrationGroups returns SCIM-specific database migrations.
func (*Plugin) OnAfterOrgDelete ¶
OnAfterOrgDelete removes every SCIM configuration scoped to the deleted organization so we don't leave orphaned provisioning targets behind. Failures are logged and the hook returns nil so other delete-cascade listeners still run.
func (*Plugin) RegisterContract ¶
func (p *Plugin) RegisterContract( d *dispatcher.Dispatcher, reg contract.Registry, wreg contract.WardenRegistry, engine plugin.Engine, ) error
func (*Plugin) RegisterRoutes ¶
RegisterRoutes registers SCIM 2.0 API routes on a forge.Router.
func (*Plugin) SetSCIMStore ¶
SetSCIMStore overrides the store the plugin uses; call it before OnInit.
type ProvisionLog ¶
type ProvisionLog struct {
ID id.SCIMLogID `json:"id"`
ConfigID id.SCIMConfigID `json:"config_id"`
Action string `json:"action"` // "create_user", "update_user", "delete_user", "create_group", etc.
ResourceType string `json:"resource_type"` // "User" or "Group"
ExternalID string `json:"external_id"` // SCIM externalId
InternalID string `json:"internal_id"` // authsome user/team ID
Status string `json:"status"` // "success", "error", "skipped"
Detail string `json:"detail"` // error message or summary
CreatedAt time.Time `json:"created_at"`
}
ProvisionLog records a single SCIM provisioning action for audit purposes.
type ResourceTypeList ¶
ResourceTypeList is the /ResourceTypes document: the resource types on offer and the endpoint each one lives at.
type SCIMConfig ¶
type SCIMConfig struct {
ID id.SCIMConfigID `json:"id"`
AppID id.AppID `json:"app_id"`
OrgID id.OrgID `json:"org_id,omitempty"` // empty = app-level
Name string `json:"name"`
Enabled bool `json:"enabled"`
AutoCreate bool `json:"auto_create"` // auto-create users on SCIM push
AutoSuspend bool `json:"auto_suspend"` // auto-suspend on SCIM deactivate
GroupSync bool `json:"group_sync"` // sync SCIM Groups to teams
DefaultRole string `json:"default_role"` // default org role for provisioned users
Metadata map[string]string `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
SCIMConfig represents a SCIM 2.0 provisioning configuration. Each config provides a unique SCIM endpoint with its own bearer tokens, and can be scoped to an application or a specific organization.
type SCIMError ¶
type SCIMError struct {
Schemas []string `json:"schemas"`
Detail string `json:"detail"`
Status string `json:"status"`
ScimType string `json:"scimType,omitempty"`
}
SCIMError represents a SCIM error response (RFC 7644 Section 3.12).
func NewSCIMError ¶
NewSCIMError creates a SCIM error response.
type SQLStore ¶
type SQLStore struct {
// contains filtered or unexported fields
}
SQLStore implements Store over postgres or sqlite.
func NewPostgresStore ¶
NewPostgresStore creates a SCIM store on the postgres driver.
func NewSqliteStore ¶
NewSqliteStore creates a SCIM store on the sqlite driver.
func (*SQLStore) CountAllLogsByStatus ¶
func (*SQLStore) CountLogsByStatus ¶
func (*SQLStore) CreateConfig ¶
func (s *SQLStore) CreateConfig(ctx context.Context, c *SCIMConfig) error
func (*SQLStore) CreateLog ¶
func (s *SQLStore) CreateLog(ctx context.Context, l *ProvisionLog) error
func (*SQLStore) DeleteConfig ¶
func (*SQLStore) DeleteToken ¶
func (*SQLStore) FindTokenByPlaintext ¶
func (s *SQLStore) FindTokenByPlaintext(ctx context.Context, plaintext string) (*Token, *SCIMConfig, error)
FindTokenByPlaintext resolves the presented token by its SHA-256 lookup column and bcrypt-compares that one row. Rows from before the column existed carry no lookup and are found the old way, by comparing each; a match there is rewritten with its lookup so the scan is paid once.
func (*SQLStore) GetConfig ¶
func (s *SQLStore) GetConfig(ctx context.Context, configID id.SCIMConfigID) (*SCIMConfig, error)
func (*SQLStore) ListAllLogs ¶
func (*SQLStore) ListConfigs ¶
func (*SQLStore) ListConfigsByOrg ¶
func (*SQLStore) ListLogs ¶
func (s *SQLStore) ListLogs(ctx context.Context, configID id.SCIMConfigID, limit int) ([]*ProvisionLog, error)
func (*SQLStore) ListTokens ¶
func (*SQLStore) UpdateConfig ¶
func (s *SQLStore) UpdateConfig(ctx context.Context, c *SCIMConfig) error
type SchemaList ¶
SchemaList is the /Schemas document: the resource schemas on offer.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service encapsulates the SCIM business logic.
func (*Service) ChangeUserName ¶
func (s *Service) ChangeUserName(ctx context.Context, cfg *SCIMConfig, u *user.User, email string) error
ChangeUserName moves a provisioned user to a new primary address through the email-record API rather than by overwriting the user's email field: the address becomes a verified email record owned by the user and is then made primary, so uniqueness inside the environment holds and every place that reads email records sees the change. An address another account owns is refused as out of scope; the user's own current address is a no-op.
func (*Service) CountAllLogsByStatus ¶
func (s *Service) CountAllLogsByStatus(ctx context.Context, appID string) (success, failed, skipped int, err error)
CountAllLogsByStatus returns log counts across all configs for an app.
func (*Service) CountLogsByStatus ¶
func (s *Service) CountLogsByStatus(ctx context.Context, configID id.SCIMConfigID) (success, failed, skipped int, err error)
CountLogsByStatus returns log counts grouped by status for a config.
func (*Service) CreateConfig ¶
func (s *Service) CreateConfig(ctx context.Context, c *SCIMConfig) error
CreateConfig creates a new SCIM configuration.
func (*Service) DeactivateUser ¶
DeactivateUser suspends a user by setting Active=false.
func (*Service) DeleteConfig ¶
DeleteConfig deletes a SCIM configuration.
func (*Service) GenerateToken ¶
func (s *Service) GenerateToken(ctx context.Context, configID id.SCIMConfigID, name string, expiresAt *time.Time) (string, *Token, error)
GenerateToken creates a new bearer token for a SCIM config. Returns the plaintext token (shown once) and the stored token record.
func (*Service) GetConfig ¶
func (s *Service) GetConfig(ctx context.Context, configID id.SCIMConfigID) (*SCIMConfig, error)
GetConfig returns a SCIM configuration by ID.
func (*Service) ListAllLogs ¶
func (s *Service) ListAllLogs(ctx context.Context, appID string, limit int) ([]*ProvisionLog, error)
ListAllLogs returns provision logs across all configs for an app.
func (*Service) ListConfigs ¶
ListConfigs returns all SCIM configurations for an app.
func (*Service) ListConfigsByOrg ¶
ListConfigsByOrg returns all SCIM configurations for an organization.
func (*Service) ListLogs ¶
func (s *Service) ListLogs(ctx context.Context, configID id.SCIMConfigID, limit int) ([]*ProvisionLog, error)
ListLogs returns provision logs for a config.
func (*Service) ListTokens ¶
ListTokens returns all tokens for a SCIM configuration.
func (*Service) LoadTeam ¶
func (s *Service) LoadTeam(ctx context.Context, cfg *SCIMConfig, raw string) (*organization.Team, error)
LoadTeam resolves a SCIM group id to a team inside cfg's organization.
func (*Service) LoadUser ¶
LoadUser resolves a SCIM user id to a user inside cfg's scope. Any miss, including a well-formed id in another tenant, is ErrOutOfScope.
func (*Service) ProvisionGroup ¶
func (s *Service) ProvisionGroup(ctx context.Context, cfg *SCIMConfig, scimGroup *GroupResource) (*organization.Team, string, error)
ProvisionGroup creates or updates a team from SCIM Group data.
func (*Service) ProvisionUser ¶
func (s *Service) ProvisionUser(ctx context.Context, cfg *SCIMConfig, scimUser *UserResource) (*user.User, string, error)
ProvisionUser creates or updates a user from SCIM data.
func (*Service) RecordLog ¶
func (s *Service) RecordLog(ctx context.Context, configID id.SCIMConfigID, action, resourceType, externalID, internalID, status, detail string)
RecordLog records a SCIM provisioning action.
func (*Service) ReplaceUser ¶
func (s *Service) ReplaceUser(ctx context.Context, cfg *SCIMConfig, target *user.User, scimUser *UserResource) error
ReplaceUser applies a SCIM PUT to target, which the caller resolved by path id. The body's email must be the target's own address: an address that resolves to another account is out of scope, so a PUT can never re-point one user's record at another.
func (*Service) RevokeToken ¶
RevokeToken deletes a SCIM bearer token.
func (*Service) RotateToken ¶
func (s *Service) RotateToken(ctx context.Context, oldTokenID id.SCIMTokenID, newName string, grace time.Duration) (string, *Token, error)
RotateToken issues a fresh bearer token for the same SCIM config and schedules the old token for expiry after a grace window. During the grace window both tokens authenticate so in-flight provisioning runs don't fail; once the grace expires the old token is rejected by ValidateToken (via Token.IsExpired). The new token's plaintext is returned to the caller exactly once — operators must persist it before discarding the response.
Grace must be ≥ 1 minute and ≤ 30 days; values outside that range are clamped to the bound, so a misconfigured rotation can't either instantly invalidate the old token (locking out a long-running job) nor leave it valid indefinitely.
If the old token's existing ExpiresAt is already sooner than now + grace, it is left unchanged — rotation never extends the lifetime of a token that was already on a tighter expiry.
func (*Service) UpdateConfig ¶
func (s *Service) UpdateConfig(ctx context.Context, c *SCIMConfig) error
UpdateConfig updates a SCIM configuration.
func (*Service) ValidateToken ¶
ValidateToken checks a bearer token against stored hashes. Returns the matching token and its associated config, or an error.
type ServiceProviderConfig ¶
ServiceProviderConfig is the /ServiceProviderConfig document: which parts of SCIM this server implements.
type Store ¶
type Store interface {
// Config CRUD
CreateConfig(ctx context.Context, c *SCIMConfig) error
GetConfig(ctx context.Context, configID id.SCIMConfigID) (*SCIMConfig, error)
UpdateConfig(ctx context.Context, c *SCIMConfig) error
DeleteConfig(ctx context.Context, configID id.SCIMConfigID) error
ListConfigs(ctx context.Context, appID string) ([]*SCIMConfig, error)
ListConfigsByOrg(ctx context.Context, orgID id.OrgID) ([]*SCIMConfig, error)
// Token CRUD
CreateToken(ctx context.Context, t *Token) error
GetToken(ctx context.Context, tokenID id.SCIMTokenID) (*Token, error)
UpdateToken(ctx context.Context, t *Token) error
ListTokens(ctx context.Context, configID id.SCIMConfigID) ([]*Token, error)
DeleteToken(ctx context.Context, tokenID id.SCIMTokenID) error
// FindTokenByPlaintext resolves a presented bearer token to its stored
// record and owning config. Token hashes are salted bcrypt digests, so the
// plaintext cannot be hashed and looked up directly; implementations must
// scan candidates and bcrypt-compare. Expiry is not checked here.
FindTokenByPlaintext(ctx context.Context, plaintext string) (*Token, *SCIMConfig, error)
// Provision logs
CreateLog(ctx context.Context, l *ProvisionLog) error
ListLogs(ctx context.Context, configID id.SCIMConfigID, limit int) ([]*ProvisionLog, error)
ListAllLogs(ctx context.Context, appID string, limit int) ([]*ProvisionLog, error)
CountLogsByStatus(ctx context.Context, configID id.SCIMConfigID) (success, errors, skipped int, err error)
CountAllLogsByStatus(ctx context.Context, appID string) (success, errors, skipped int, err error)
}
type Token ¶
type Token struct {
ID id.SCIMTokenID `json:"id"`
ConfigID id.SCIMConfigID `json:"config_id"`
Name string `json:"name"`
TokenHash string `json:"-"`
// TokenLookup is the hex SHA-256 of the plaintext, the indexed column a
// presented token is resolved by; TokenHash, a salted bcrypt digest, is
// then compared on that single row. Empty on rows written before the
// column existed, which are found by scanning and upgraded on use.
TokenLookup string `json:"-"`
LastUsedAt *time.Time `json:"last_used_at,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
Token represents a bearer token for authenticating SCIM API requests.
type UserResource ¶
type UserResource struct {
Schemas []string `json:"schemas"`
ID string `json:"id,omitempty"`
ExternalID string `json:"externalId,omitempty"`
UserName string `json:"userName"`
Name Name `json:"name"`
Emails []Email `json:"emails,omitempty"`
Active bool `json:"active"`
Meta *Meta `json:"meta,omitempty"`
Groups []GroupRef `json:"groups,omitempty"`
}
UserResource represents a SCIM 2.0 User resource.
func UserToSCIM ¶
func UserToSCIM(u *user.User, baseURL string) *UserResource
UserToSCIM converts an AuthSome user to a SCIM User resource.
func (*UserResource) PrimaryEmail ¶
func (u *UserResource) PrimaryEmail() string
PrimaryEmail returns the primary email from the emails list, falling back to UserName.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package contract wires the scim plugin's deep-link settings page into the forge-dashboard contract registry.
|
Package contract wires the scim plugin's deep-link settings page into the forge-dashboard contract registry. |
|
Package scimtest is the store contract every SCIM store implementation must satisfy.
|
Package scimtest is the store contract every SCIM store implementation must satisfy. |