scim

package
v1.9.0 Latest Latest
Warning

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

Go to latest
Published: Jul 1, 2026 License: AGPL-3.0 Imports: 7 Imported by: 0

Documentation

Overview

Package scim implements the inbound (server) side of SCIM 2.0 (RFC 7643 schema, RFC 7644 protocol) for the /scim/v2 surface: an external IdP (Okta, Entra ID, Google Workspace) lifecycle-manages users in a project by POST/GET/PUT/PATCH/DELETE-ing the /Users resource and the discovery endpoints (/ServiceProviderConfig, /Schemas, /ResourceTypes).

The package is deliberately transport- and storage-agnostic: it depends only on the Store interface (a thin slice of the host's user repository) so it can be unit-tested with an in-memory fake and mounted by the host over its own project-scoped repository. The host gates the whole surface behind config + a bearer token and resolves the project before calling in; this package never sees credentials or projects.

Index

Constants

View Source
const (
	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"
	SchemaServiceProviderConfig = "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"
	SchemaResourceTypeURN       = "urn:ietf:params:scim:schemas:core:2.0:ResourceType"
	SchemaSchemaURN             = "urn:ietf:params:scim:schemas:core:2.0:Schema"
)

SchemaListResponse, SchemaError, SchemaPatchOp, SchemaServiceProviderConfig, SchemaResourceType, and SchemaSchema are the SCIM message schema URNs.

View Source
const SchemaUser = "urn:ietf:params:scim:schemas:core:2.0:User"

SchemaUser is the SCIM core User schema URN (RFC 7643 §8.7.1).

Variables

View Source
var (
	ErrNotFound = errors.New("scim: resource not found")
	ErrConflict = errors.New("scim: uniqueness conflict")
)

Sentinel errors a Store returns; the provider maps them to SCIM HTTP statuses.

Functions

This section is empty.

Types

type Email

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

Email is a SCIM multi-valued email entry.

type ErrorResponse

type ErrorResponse struct {
	Schemas  []string `json:"schemas"`
	Detail   string   `json:"detail"`
	Status   string   `json:"status"`
	SCIMType string   `json:"scimType,omitempty"`
}

ErrorResponse is the SCIM error envelope (RFC 7644 §3.12).

type ListFilter

type ListFilter struct {
	UserName   string
	Email      string
	ExternalID string
	StartIndex int // 1-based (SCIM); the provider converts to a 0-based offset
	Count      int
}

ListFilter narrows a ListUsers query. The provider parses the subset of the SCIM filter grammar enterprises actually send (userName eq, email eq, externalId eq) into this struct; an unsupported filter is rejected before it reaches the Store.

type ListResponse

type ListResponse struct {
	Schemas      []string   `json:"schemas"`
	TotalResults int        `json:"totalResults"`
	StartIndex   int        `json:"startIndex"`
	ItemsPerPage int        `json:"itemsPerPage"`
	Resources    []Resource `json:"Resources"`
}

ListResponse is the SCIM paginated list envelope (RFC 7644 §3.4.2).

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 is the SCIM common resource metadata.

type Name

type Name struct {
	Formatted  string `json:"formatted,omitempty"`
	GivenName  string `json:"givenName,omitempty"`
	FamilyName string `json:"familyName,omitempty"`
}

Name is the SCIM complex name attribute.

type Operation

type Operation struct {
	Op    string          `json:"op"`
	Path  string          `json:"path,omitempty"`
	Value json.RawMessage `json:"value,omitempty"`
}

Operation is one entry in a PatchOp's Operations array.

type PatchRequest

type PatchRequest struct {
	Schemas    []string    `json:"schemas"`
	Operations []Operation `json:"Operations"`
}

PatchRequest is the SCIM PatchOp message (RFC 7644 §3.5.2). The provider supports the attribute set enterprises drive through PATCH — Microsoft Entra ID, for one, performs ALL profile updates (and de/re-provisioning) via PATCH replace, never PUT — so the mapped attributes (userName, emails/email, name, externalId, active) are all patchable. Operations targeting an attribute this server does not model are surfaced as errors rather than silently dropped.

type Provider

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

Provider serves the SCIM /Users surface and the discovery endpoints over a Store. It is mounted by the host under /scim/v2/ once the host has authenticated the request and resolved its project.

func NewProvider

func NewProvider(store Store) *Provider

NewProvider returns a Provider backed by store. store is required.

func (*Provider) Handler

func (p *Provider) Handler() http.Handler

Handler returns an http.Handler routing the SCIM v2 endpoints. The host mounts it at /scim/v2/ (StripPrefix not required — the provider matches on the full path suffix).

type Resource

type Resource struct {
	Schemas    []string `json:"schemas"`
	ID         string   `json:"id"`
	ExternalID string   `json:"externalId,omitempty"`
	UserName   string   `json:"userName"`
	Name       *Name    `json:"name,omitempty"`
	Emails     []Email  `json:"emails,omitempty"`
	Active     bool     `json:"active"`
	Meta       *Meta    `json:"meta,omitempty"`
}

Resource is the SCIM JSON representation of a core User. Only the attributes the host can populate are emitted; SCIM clients tolerate the absence of optional attributes.

type Store

type Store interface {
	CreateUser(ctx context.Context, u User) (User, error)
	GetUser(ctx context.Context, id string) (User, error)
	ReplaceUser(ctx context.Context, id string, u User) (User, error)
	// PatchUser applies the non-nil fields of patch to the user (SCIM
	// PATCH partial update), returning the updated user. Setting Active to
	// false maps to the host's deactivation path (which also revokes
	// sessions/refresh tokens); true reactivates. Implementations MUST return
	// ErrNotFound for a missing user and ErrConflict on a uniqueness violation
	// (userName/email/externalId).
	PatchUser(ctx context.Context, id string, patch UserPatch) (User, error)
	DeleteUser(ctx context.Context, id string) error
	// ListUsers returns users matching filter (zero value = all), ordered
	// stably, plus the total number of matches (for SCIM totalResults).
	ListUsers(ctx context.Context, filter ListFilter) (users []User, total int, err error)
}

Store is the slice of the host's user repository the SCIM provider needs. All methods operate within whatever project/tenant scope the host bound before constructing the provider. Implementations MUST return ErrNotFound for a missing user and ErrConflict when a uniqueness constraint (userName or externalId) would be violated, so the provider can map them to the correct SCIM HTTP status (404 / 409).

type User

type User struct {
	ID         string
	ExternalID string
	UserName   string // SCIM userName — mapped to the host email
	Email      string
	GivenName  string
	FamilyName string
	Active     bool
	CreatedAt  time.Time
	UpdatedAt  time.Time
}

User is the host's representation of a user, mapped to/from the SCIM core User schema by this package. It is intentionally a small value type so the Store contract does not leak the host's full domain model.

type UserPatch

type UserPatch struct {
	Active     *bool
	UserName   *string
	Email      *string
	ExternalID *string
	GivenName  *string
	FamilyName *string
}

UserPatch is a partial update to a User: every field is a pointer so the caller can distinguish "leave unchanged" (nil) from "set to this value" (non-nil). The SCIM provider builds it from a PATCH request's operations and the host Store maps the set fields onto its repository, so a PATCH replace of a single attribute never clobbers the others. The mapping mirrors the PUT (ReplaceUser) attribute mapping: userName/email → the host email, given/family → the host display name, externalId → external_id, active → the account status.

Jump to

Keyboard shortcuts

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