scim

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Mar 8, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package scim provides SCIM 2.0 (RFC 7643/7644) support for identity provisioning.

Index

Constants

View Source
const (
	// User scopes
	ScopeUsersRead  = "scim:users:read"
	ScopeUsersWrite = "scim:users:write"

	// Group scopes
	ScopeGroupsRead  = "scim:groups:read"
	ScopeGroupsWrite = "scim:groups:write"

	// Full access scope
	ScopeFull = "scim:full"
)

SCIM authorization scopes follow the pattern: scim:{resource}:{action}

View Source
const (
	// ErrorTypeInvalidFilter indicates the filter syntax is invalid.
	ErrorTypeInvalidFilter = "invalidFilter"

	// ErrorTypeTooMany indicates too many results would be returned.
	ErrorTypeTooMany = "tooMany"

	// ErrorTypeUniqueness indicates a uniqueness constraint was violated.
	ErrorTypeUniqueness = "uniqueness"

	// ErrorTypeMutability indicates an attempt to modify an immutable attribute.
	ErrorTypeMutability = "mutability"

	// ErrorTypeInvalidSyntax indicates the request body is invalid.
	ErrorTypeInvalidSyntax = "invalidSyntax"

	// ErrorTypeInvalidPath indicates an invalid attribute path.
	ErrorTypeInvalidPath = "invalidPath"

	// ErrorTypeNoTarget indicates no target resource was found for a PATCH operation.
	ErrorTypeNoTarget = "noTarget"

	// ErrorTypeInvalidValue indicates an invalid attribute value.
	ErrorTypeInvalidValue = "invalidValue"

	// ErrorTypeInvalidVers indicates an invalid version for optimistic locking.
	ErrorTypeInvalidVers = "invalidVers"

	// ErrorTypeSensitive indicates a sensitive attribute cannot be returned.
	ErrorTypeSensitive = "sensitive"
)

SCIM error types as defined in RFC 7644 Section 3.12.

View Source
const (
	ResourceTypeUser  = "User"
	ResourceTypeGroup = "Group"
)

Resource types for SCIM endpoints.

Variables

View Source
var (
	SchemaUser           = schema.URIUser
	SchemaGroup          = schema.URIGroup
	SchemaEnterpriseUser = schema.URIEnterpriseUser
	SchemaListResponse   = schema.URIListResponse
	SchemaPatchOp        = schema.URIPatchOp
	SchemaBulkRequest    = schema.URIBulkRequest
	SchemaBulkResponse   = schema.URIBulkResponse
	SchemaError          = schema.URIError
)

Schema URIs for SCIM resource types (re-exported from schema package for convenience).

Functions

func AuthScopesFromContext

func AuthScopesFromContext(ctx context.Context) []string

AuthScopesFromContext extracts the authenticated scopes from context.

func AuthSubjectFromContext

func AuthSubjectFromContext(ctx context.Context) string

AuthSubjectFromContext extracts the authenticated subject from context.

func GenerateETag

func GenerateETag(version string) string

GenerateETag generates an ETag value from a version string or timestamp.

func HasAuthScope

func HasAuthScope(ctx context.Context, scope string) bool

HasAuthScope checks if the context has a specific scope.

func LoggerFromContext

func LoggerFromContext(ctx context.Context) *slog.Logger

LoggerFromContext returns the logger from context, or slog.Default() if not set.

func ParseETag

func ParseETag(etag string) string

ParseETag parses an ETag value, removing quotes.

func ParseScopes

func ParseScopes(scopeString string) []string

ParseScopes parses a space-separated scope string into a slice.

func RequestIDFromContext

func RequestIDFromContext(ctx context.Context) string

RequestIDFromContext extracts the request ID from context.

func RolesFromContext

func RolesFromContext(ctx context.Context) []string

RolesFromContext extracts roles from the context.

func ScopesString

func ScopesString(scopes []string) string

ScopesString converts a scope slice to a space-separated string.

func ValidateScopes

func ValidateScopes(scopes []string) []string

ValidateScopes validates that the provided scopes are known SCIM scopes.

func WithAuthScopes

func WithAuthScopes(ctx context.Context, scopes []string) context.Context

WithAuthScopes adds the authenticated scopes to the context.

func WithAuthSubject

func WithAuthSubject(ctx context.Context, subject string) context.Context

WithAuthSubject adds the authenticated subject (user/client ID) to the context.

func WithRequestID

func WithRequestID(ctx context.Context, requestID string) context.Context

WithRequestID adds a request ID to the context.

func WithRoles

func WithRoles(ctx context.Context, roles []string) context.Context

WithRoles adds roles to the context for role-based authorization.

func WriteError

func WriteError(w http.ResponseWriter, err *Error)

WriteError writes a SCIM error response to the HTTP response writer.

func WriteResponse

func WriteResponse(w http.ResponseWriter, status int, etag string, body []byte)

WriteResponse writes a SCIM response with proper headers.

Types

type API

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

API provides HTTP handlers for SCIM 2.0 endpoints using Huma/Chi.

func NewAPI

func NewAPI(provider *Provider, opts ...Option) (*API, error)

NewAPI creates a new SCIM API with Chi router and Huma.

func (*API) Huma

func (a *API) Huma() huma.API

Huma returns the underlying Huma API for advanced configuration.

func (*API) Logger

func (a *API) Logger() *slog.Logger

Logger returns the API's logger.

func (*API) Middleware

func (a *API) Middleware(authFn func(r *http.Request) (subject string, scopes []string, err error)) func(http.Handler) http.Handler

Middleware returns HTTP middleware for SCIM authentication. The authFn should validate the request and return the subject and scopes.

func (*API) Provider

func (a *API) Provider() *Provider

Provider returns the SCIM provider.

func (*API) Router

func (a *API) Router() chi.Router

Router returns the Chi router for mounting or serving.

func (*API) ServeHTTP

func (a *API) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler.

type Address

type Address struct {
	Formatted     string `json:"formatted,omitempty"`
	StreetAddress string `json:"streetAddress,omitempty"`
	Locality      string `json:"locality,omitempty"`
	Region        string `json:"region,omitempty"`
	PostalCode    string `json:"postalCode,omitempty"`
	Country       string `json:"country,omitempty"`
	Type          string `json:"type,omitempty"`
	Primary       bool   `json:"primary,omitempty"`
}

Address represents a physical address.

type AttributeFilter

type AttributeFilter struct {
	// Attributes to include (if empty, include all)
	Attributes []string

	// Attributes to exclude
	ExcludedAttributes []string
}

AttributeFilter filters SCIM resources to include/exclude specific attributes.

func NewAttributeFilter

func NewAttributeFilter(attributes, excludedAttributes []string) *AttributeFilter

NewAttributeFilter creates a new attribute filter.

func (*AttributeFilter) FilterGroup

func (f *AttributeFilter) FilterGroup(group *Group) *Group

FilterGroup applies attribute filtering to a Group resource.

func (*AttributeFilter) FilterListResponse

func (f *AttributeFilter) FilterListResponse(response *ListResponse) *ListResponse

FilterListResponse applies attribute filtering to all resources in a list response.

func (*AttributeFilter) FilterResource

func (f *AttributeFilter) FilterResource(resource any) any

FilterResource applies attribute filtering to any SCIM resource.

func (*AttributeFilter) FilterUser

func (f *AttributeFilter) FilterUser(user *User) *User

FilterUser applies attribute filtering to a User resource.

func (*AttributeFilter) IsEmpty

func (f *AttributeFilter) IsEmpty() bool

IsEmpty returns true if no filtering is configured.

type AuthenticationScheme

type AuthenticationScheme struct {
	Type             string `json:"type"`
	Name             string `json:"name"`
	Description      string `json:"description"`
	SpecURI          string `json:"specUri,omitempty"`
	DocumentationURI string `json:"documentationUri,omitempty"`
	Primary          bool   `json:"primary,omitempty"`
}

AuthenticationScheme describes a supported authentication method.

type AuthorizationHook

type AuthorizationHook interface {
	// CanRead checks if the authenticated user can read the resource.
	CanRead(ctx context.Context, resourceType, resourceID string) error

	// CanCreate checks if the authenticated user can create resources of this type.
	CanCreate(ctx context.Context, resourceType string) error

	// CanUpdate checks if the authenticated user can update the resource.
	CanUpdate(ctx context.Context, resourceType, resourceID string) error

	// CanDelete checks if the authenticated user can delete the resource.
	CanDelete(ctx context.Context, resourceType, resourceID string) error
}

AuthorizationHook provides authorization checks for SCIM operations.

type BcryptHasher

type BcryptHasher struct {
	// Cost is the bcrypt cost parameter. Default is bcrypt.DefaultCost (10).
	Cost int
}

BcryptHasher implements PasswordHasher using bcrypt.

func NewBcryptHasher

func NewBcryptHasher(cost int) *BcryptHasher

NewBcryptHasher creates a new bcrypt password hasher.

func (*BcryptHasher) Hash

func (h *BcryptHasher) Hash(password string) (string, error)

Hash hashes a password using bcrypt.

func (*BcryptHasher) Verify

func (h *BcryptHasher) Verify(password, hash string) error

Verify compares a password with a bcrypt hash.

type BulkInput

type BulkInput struct {
	Body *BulkRequest `doc:"Bulk request containing multiple operations"`
}

BulkInput contains the request body for bulk operations.

type BulkOperation

type BulkOperation struct {
	Method  string `json:"method"`
	BulkID  string `json:"bulkId,omitempty"`
	Version string `json:"version,omitempty"`
	Path    string `json:"path"`
	Data    any    `json:"data,omitempty"`
}

BulkOperation represents a single operation within a bulk request.

type BulkOutput

type BulkOutput struct {
	Body *BulkResponse
}

BulkOutput is the response for bulk operations.

type BulkRequest

type BulkRequest struct {
	Schemas      []string        `json:"schemas"`
	FailOnErrors int             `json:"failOnErrors,omitempty"`
	Operations   []BulkOperation `json:"Operations"`
}

BulkRequest represents a SCIM bulk request as defined in RFC 7644 Section 3.7.

type BulkResponse

type BulkResponse struct {
	Schemas    []string                `json:"schemas"`
	Operations []BulkResponseOperation `json:"Operations"`
}

BulkResponse represents a SCIM bulk response.

type BulkResponseOperation

type BulkResponseOperation struct {
	Method   string `json:"method"`
	BulkID   string `json:"bulkId,omitempty"`
	Version  string `json:"version,omitempty"`
	Location string `json:"location,omitempty"`
	Status   string `json:"status"`
	Response any    `json:"response,omitempty"`
}

BulkResponseOperation represents a single operation result within a bulk response.

type CompositeAuthorizationHook

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

CompositeAuthorizationHook combines multiple authorization hooks. All hooks must pass for the operation to be allowed.

func NewCompositeAuthorizationHook

func NewCompositeAuthorizationHook(hooks ...AuthorizationHook) *CompositeAuthorizationHook

NewCompositeAuthorizationHook creates a hook that combines multiple hooks.

func (*CompositeAuthorizationHook) CanCreate

func (h *CompositeAuthorizationHook) CanCreate(ctx context.Context, resourceType string) error

CanCreate checks if all hooks allow creating the resource type.

func (*CompositeAuthorizationHook) CanDelete

func (h *CompositeAuthorizationHook) CanDelete(ctx context.Context, resourceType, resourceID string) error

CanDelete checks if all hooks allow deleting the resource.

func (*CompositeAuthorizationHook) CanRead

func (h *CompositeAuthorizationHook) CanRead(ctx context.Context, resourceType, resourceID string) error

CanRead checks if all hooks allow reading the resource.

func (*CompositeAuthorizationHook) CanUpdate

func (h *CompositeAuthorizationHook) CanUpdate(ctx context.Context, resourceType, resourceID string) error

CanUpdate checks if all hooks allow updating the resource.

type Config

type Config struct {
	// BaseURL is the base URL for SCIM resources (e.g., "https://example.com/scim/v2").
	BaseURL string

	// MaxResults is the maximum number of resources returned in a list response.
	MaxResults int

	// DefaultPageSize is the default number of resources per page.
	DefaultPageSize int

	// SupportFiltering indicates whether filtering is supported.
	SupportFiltering bool

	// SupportSorting indicates whether sorting is supported.
	SupportSorting bool

	// SupportPatch indicates whether PATCH operations are supported.
	SupportPatch bool

	// SupportBulk indicates whether bulk operations are supported.
	SupportBulk bool

	// BulkMaxOperations is the maximum number of operations in a bulk request.
	BulkMaxOperations int

	// BulkMaxPayloadSize is the maximum size of a bulk request in bytes.
	BulkMaxPayloadSize int

	// SupportChangePassword indicates whether password changes via SCIM are supported.
	SupportChangePassword bool

	// SupportETag indicates whether ETag-based optimistic locking is supported.
	SupportETag bool

	// AuthenticationSchemes defines the supported authentication methods.
	AuthenticationSchemes []AuthenticationScheme

	// DocumentationURI is an optional URI to SCIM documentation.
	DocumentationURI string
}

Config holds the SCIM server configuration.

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a Config with sensible defaults.

func (*Config) GroupLocation

func (c *Config) GroupLocation(id string) string

GroupLocation returns the full URL for a group resource.

func (*Config) ResourceLocation

func (c *Config) ResourceLocation(resourceType, id string) string

ResourceLocation returns the full URL for a resource.

func (*Config) UserLocation

func (c *Config) UserLocation(id string) string

UserLocation returns the full URL for a user resource.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks that the configuration is valid.

type CreateGroupInput

type CreateGroupInput struct {
	Body *Group `doc:"Group resource to create"`
}

CreateGroupInput contains the request body for creating a group.

type CreateGroupOutput

type CreateGroupOutput struct {
	Body     *Group
	Location string `header:"Location" doc:"URI of the created resource"`
	ETag     string `header:"ETag" doc:"Entity tag for caching and conditional requests"`
}

CreateGroupOutput is the response for creating a group.

type CreateUserInput

type CreateUserInput struct {
	Body *User `doc:"User resource to create"`
}

CreateUserInput contains the request body for creating a user.

type CreateUserOutput

type CreateUserOutput struct {
	Body     *User
	Location string `header:"Location" doc:"URI of the created resource"`
	ETag     string `header:"ETag" doc:"Entity tag for caching and conditional requests"`
}

CreateUserOutput is the response for creating a user.

type DefaultAuthorizationHook

type DefaultAuthorizationHook struct{}

DefaultAuthorizationHook is a no-op authorization hook that allows all operations.

func (DefaultAuthorizationHook) CanCreate

func (DefaultAuthorizationHook) CanCreate(ctx context.Context, resourceType string) error

CanCreate always allows create operations.

func (DefaultAuthorizationHook) CanDelete

func (DefaultAuthorizationHook) CanDelete(ctx context.Context, resourceType, resourceID string) error

CanDelete always allows delete operations.

func (DefaultAuthorizationHook) CanRead

func (DefaultAuthorizationHook) CanRead(ctx context.Context, resourceType, resourceID string) error

CanRead always allows read operations.

func (DefaultAuthorizationHook) CanUpdate

func (DefaultAuthorizationHook) CanUpdate(ctx context.Context, resourceType, resourceID string) error

CanUpdate always allows update operations.

type DeleteResourceInput

type DeleteResourceInput struct {
	ID string `path:"id" doc:"Resource ID"`
}

DeleteResourceInput contains parameters for deleting a resource.

type EnterpriseUser

type EnterpriseUser struct {
	EmployeeNumber string      `json:"employeeNumber,omitempty"`
	CostCenter     string      `json:"costCenter,omitempty"`
	Organization   string      `json:"organization,omitempty"`
	Division       string      `json:"division,omitempty"`
	Department     string      `json:"department,omitempty"`
	Manager        *ManagerRef `json:"manager,omitempty"`
}

EnterpriseUser represents the Enterprise User extension (RFC 7643 Section 4.3).

type Error

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

Error represents a SCIM error response as defined in RFC 7644 Section 3.12.

func ErrBadRequest

func ErrBadRequest(detail string) *Error

ErrBadRequest creates a 400 Bad Request error.

func ErrConflict

func ErrConflict(detail string) *Error

ErrConflict creates a 409 Conflict error for uniqueness violations.

func ErrForbidden

func ErrForbidden(detail string) *Error

ErrForbidden creates a 403 Forbidden error.

func ErrInternal

func ErrInternal(detail string) *Error

ErrInternal creates a 500 Internal Server Error.

func ErrInvalidFilter

func ErrInvalidFilter(detail string) *Error

ErrInvalidFilter creates a 400 Bad Request error for invalid filters.

func ErrInvalidPath

func ErrInvalidPath(detail string) *Error

ErrInvalidPath creates a 400 Bad Request error for invalid attribute paths.

func ErrInvalidSyntax

func ErrInvalidSyntax(detail string) *Error

ErrInvalidSyntax creates a 400 Bad Request error for invalid request syntax.

func ErrInvalidValue

func ErrInvalidValue(detail string) *Error

ErrInvalidValue creates a 400 Bad Request error for invalid values.

func ErrMutability

func ErrMutability(detail string) *Error

ErrMutability creates a 400 Bad Request error for immutable attribute modifications.

func ErrNoTarget

func ErrNoTarget(detail string) *Error

ErrNoTarget creates a 400 Bad Request error when PATCH target is not found.

func ErrNotFound

func ErrNotFound(detail string) *Error

ErrNotFound creates a 404 Not Found error.

func ErrNotImplemented

func ErrNotImplemented(detail string) *Error

ErrNotImplemented creates a 501 Not Implemented error.

func ErrPreconditionFailed

func ErrPreconditionFailed(detail string) *Error

ErrPreconditionFailed creates a 412 Precondition Failed error for ETag mismatches.

func ErrTooMany

func ErrTooMany(detail string) *Error

ErrTooMany creates a 400 Bad Request error when too many resources would be returned.

func ErrUnauthorized

func ErrUnauthorized(detail string) *Error

ErrUnauthorized creates a 401 Unauthorized error.

func NewError

func NewError(status int, scimType, detail string) *Error

NewError creates a new SCIM error.

func ToSCIMError

func ToSCIMError(err error) *Error

ToSCIMError converts a standard error to a SCIM error. If the error is already a SCIM error, it is returned as-is. Otherwise, a 500 Internal Server Error is returned.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface.

type GetGroupOutput

type GetGroupOutput struct {
	Body *Group
	ETag string `header:"ETag" doc:"Entity tag for caching and conditional requests"`
}

GetGroupOutput is the response for getting a single group.

type GetResourceInput

type GetResourceInput struct {
	ID                 string `path:"id" doc:"Resource ID"`
	Attributes         string `query:"attributes" doc:"Comma-separated list of attributes to return"`
	ExcludedAttributes string `query:"excludedAttributes" doc:"Comma-separated list of attributes to exclude"`
	IfNoneMatch        string `header:"If-None-Match" doc:"ETag for conditional request"`
}

GetResourceInput contains parameters for getting a single resource.

func (*GetResourceInput) ToAttributeFilter

func (i *GetResourceInput) ToAttributeFilter() *AttributeFilter

ToAttributeFilter creates an AttributeFilter from the input parameters.

type GetResourceTypeOutput

type GetResourceTypeOutput struct {
	Body *schema.ResourceType
}

GetResourceTypeOutput is the response for getting a single resource type.

type GetSchemaOutput

type GetSchemaOutput struct {
	Body *schema.Schema
}

GetSchemaOutput is the response for getting a single schema.

type GetUserOutput

type GetUserOutput struct {
	Body *User
	ETag string `header:"ETag" doc:"Entity tag for caching and conditional requests"`
}

GetUserOutput is the response for getting a single user.

type Group

type Group struct {
	Resource
	DisplayName string      `json:"displayName"`
	Members     []MemberRef `json:"members,omitempty"`
}

Group represents a SCIM Group resource as defined in RFC 7643 Section 4.2.

type GroupRef

type GroupRef struct {
	Value   string `json:"value,omitempty"`
	Ref     string `json:"$ref,omitempty"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"`
}

GroupRef represents a reference to a group in a user's groups attribute.

type ListGroupsOutput

type ListGroupsOutput struct {
	Body *ListResponse
}

ListGroupsOutput is the response for listing groups.

type ListOptions

type ListOptions struct {
	Filter     string
	StartIndex int
	Count      int
	SortBy     string
	SortOrder  string
	Attributes []string
}

ListOptions contains parameters for list operations.

func DefaultListOptions

func DefaultListOptions() ListOptions

DefaultListOptions returns sensible defaults for list operations.

type ListResourceTypesOutput

type ListResourceTypesOutput struct {
	Body *ListResponse
}

ListResourceTypesOutput is the response for listing resource types.

type ListResourcesInput

type ListResourcesInput struct {
	Filter             string `query:"filter" doc:"SCIM filter expression (RFC 7644)"`
	Attributes         string `query:"attributes" doc:"Comma-separated list of attributes to return"`
	ExcludedAttributes string `query:"excludedAttributes" doc:"Comma-separated list of attributes to exclude"`
	SortBy             string `query:"sortBy" doc:"Attribute path to sort by"`
	SortOrder          string `query:"sortOrder" enum:"ascending,descending" default:"ascending" doc:"Sort order"`
	StartIndex         int    `query:"startIndex" minimum:"1" default:"1" doc:"1-based index of first result"`
	Count              int    `query:"count" minimum:"0" doc:"Number of resources to return per page"`
}

ListResourcesInput contains common query parameters for list operations.

func (*ListResourcesInput) ToAttributeFilter

func (i *ListResourcesInput) ToAttributeFilter() *AttributeFilter

ToAttributeFilter creates an AttributeFilter from the input parameters.

func (*ListResourcesInput) ToListOptions

func (i *ListResourcesInput) ToListOptions(defaultCount int) ListOptions

ToListOptions converts input parameters to ListOptions.

type ListResponse

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

ListResponse represents a SCIM list response as defined in RFC 7644 Section 3.4.2.

func NewListResponse

func NewListResponse(resources []any, totalResults, startIndex, itemsPerPage int) *ListResponse

NewListResponse creates a new ListResponse with the proper schema.

type ListSchemasOutput

type ListSchemasOutput struct {
	Body *ListResponse
}

ListSchemasOutput is the response for listing schemas.

type ListUsersOutput

type ListUsersOutput struct {
	Body *ListResponse
}

ListUsersOutput is the response for listing users.

type ManagerRef

type ManagerRef struct {
	Value       string `json:"value,omitempty"`
	Ref         string `json:"$ref,omitempty"`
	DisplayName string `json:"displayName,omitempty"`
}

ManagerRef represents a reference to a user's manager.

type MeOutput

type MeOutput struct {
	Body *User
	ETag string `header:"ETag" doc:"Entity tag for caching and conditional requests"`
}

MeOutput is the response for /Me endpoint.

type MePatchInput

type MePatchInput struct {
	IfMatch string        `header:"If-Match" doc:"ETag for conditional update"`
	Body    *PatchRequest `doc:"PATCH operations to apply"`
}

MePatchInput contains parameters for patching the current user.

type MemberRef

type MemberRef struct {
	Value   string `json:"value,omitempty"`
	Ref     string `json:"$ref,omitempty"`
	Display string `json:"display,omitempty"`
	Type    string `json:"type,omitempty"`
}

MemberRef represents a reference to a member in a group's members attribute.

type Meta

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

Meta contains resource metadata as defined in RFC 7643 Section 3.1.

type MultiValue

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

MultiValue represents a multi-valued attribute with metadata. Used for emails, phone numbers, addresses, etc.

type Name

type Name struct {
	Formatted       string `json:"formatted,omitempty"`
	FamilyName      string `json:"familyName,omitempty"`
	GivenName       string `json:"givenName,omitempty"`
	MiddleName      string `json:"middleName,omitempty"`
	HonorificPrefix string `json:"honorificPrefix,omitempty"`
	HonorificSuffix string `json:"honorificSuffix,omitempty"`
}

Name represents a user's name components.

type NoOpHasher

type NoOpHasher struct{}

NoOpHasher is a PasswordHasher that does not hash passwords. This is useful for testing or when passwords are hashed elsewhere.

func (*NoOpHasher) Hash

func (h *NoOpHasher) Hash(password string) (string, error)

Hash returns the password as-is.

func (*NoOpHasher) Verify

func (h *NoOpHasher) Verify(password, hash string) error

Verify compares passwords directly.

type Option

type Option func(*API)

Option configures an API.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger sets the logger for the API. If not set, slog.Default() is used.

type PasswordHasher

type PasswordHasher interface {
	// Hash hashes a plain text password.
	Hash(password string) (string, error)

	// Verify compares a plain text password with a hashed password.
	Verify(password, hash string) error
}

PasswordHasher defines the interface for password hashing operations.

func DefaultPasswordHasher

func DefaultPasswordHasher() PasswordHasher

DefaultPasswordHasher returns the default password hasher (bcrypt).

type PatchOperation

type PatchOperation struct {
	Op    string `json:"op"`
	Path  string `json:"path,omitempty"`
	Value any    `json:"value,omitempty"`
}

PatchOperation represents a single PATCH operation.

type PatchRequest

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

PatchRequest represents a SCIM PATCH request as defined in RFC 7644 Section 3.5.2.

type PatchResourceInput

type PatchResourceInput struct {
	ID      string        `path:"id" doc:"Resource ID"`
	IfMatch string        `header:"If-Match" doc:"ETag for conditional update"`
	Body    *PatchRequest `doc:"PATCH operations to apply"`
}

PatchResourceInput contains parameters for patching a resource.

type Provider

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

Provider is the main entry point for SCIM operations. It wraps a Store implementation and provides the Service interface.

func NewProvider

func NewProvider(config *Config, store Store, opts ...ProviderOption) (*Provider, error)

NewProvider creates a new SCIM provider.

func (*Provider) Config

func (p *Provider) Config() *Config

Config returns the SCIM configuration.

func (*Provider) PasswordHasher

func (p *Provider) PasswordHasher() PasswordHasher

PasswordHasher returns the configured password hasher.

func (*Provider) ResourceTypes

func (p *Provider) ResourceTypes() []schema.ResourceType

ResourceTypes returns all supported resource types.

func (*Provider) Schemas

func (p *Provider) Schemas() []schema.Schema

Schemas returns all supported SCIM schemas.

func (*Provider) Service

func (p *Provider) Service() Service

Service returns the SCIM service interface.

func (*Provider) ServiceProviderConfig

func (p *Provider) ServiceProviderConfig() schema.ServiceProviderConfig

ServiceProviderConfig returns the SCIM service provider configuration.

type ProviderOption

type ProviderOption func(*Provider)

ProviderOption configures a Provider.

func WithAuthorizationHook

func WithAuthorizationHook(hook AuthorizationHook) ProviderOption

WithAuthorizationHook sets a custom authorization hook.

func WithPasswordHasher

func WithPasswordHasher(hasher PasswordHasher) ProviderOption

WithPasswordHasher sets a custom password hasher.

type RequestMetadata

type RequestMetadata struct {
	// Filter is the SCIM filter expression.
	Filter string

	// StartIndex is the 1-based index of the first result (default 1).
	StartIndex int

	// Count is the number of resources to return per page.
	Count int

	// SortBy is the attribute to sort by.
	SortBy string

	// SortOrder is "ascending" or "descending".
	SortOrder string

	// Attributes specifies which attributes to return.
	Attributes []string

	// ExcludedAttributes specifies which attributes to exclude.
	ExcludedAttributes []string

	// IfMatch is the ETag value from If-Match header.
	IfMatch string

	// IfNoneMatch is the ETag value from If-None-Match header.
	IfNoneMatch string
}

RequestMetadata contains metadata extracted from a SCIM request.

func ExtractRequestMetadata

func ExtractRequestMetadata(r *http.Request) RequestMetadata

ExtractRequestMetadata extracts SCIM request metadata from an HTTP request.

func (RequestMetadata) ToListOptions

func (m RequestMetadata) ToListOptions(defaultCount int) ListOptions

ToListOptions converts RequestMetadata to ListOptions.

type Resource

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

Resource is the base type for all SCIM resources.

type ResourceTypeNameInput

type ResourceTypeNameInput struct {
	Name string `path:"name" doc:"Resource type name"`
}

ResourceTypeNameInput contains the resource type name path parameter.

type RoleBasedAuthorizationHook

type RoleBasedAuthorizationHook struct {
	// AdminRoles are roles that have full SCIM access.
	AdminRoles []string

	// ReadOnlyRoles are roles that have read-only SCIM access.
	ReadOnlyRoles []string

	// RoleExtractor extracts roles from context.
	// If nil, defaults to looking for "roles" in context values.
	RoleExtractor func(ctx context.Context) []string
}

RoleBasedAuthorizationHook implements AuthorizationHook using role-based access. It checks that the authenticated user has an appropriate role for the operation.

func NewRoleBasedAuthorizationHook

func NewRoleBasedAuthorizationHook(adminRoles, readOnlyRoles []string) *RoleBasedAuthorizationHook

NewRoleBasedAuthorizationHook creates a new role-based authorization hook.

func (*RoleBasedAuthorizationHook) CanCreate

func (h *RoleBasedAuthorizationHook) CanCreate(ctx context.Context, resourceType string) error

CanCreate checks if the authenticated user can create resources of this type.

func (*RoleBasedAuthorizationHook) CanDelete

func (h *RoleBasedAuthorizationHook) CanDelete(ctx context.Context, resourceType, resourceID string) error

CanDelete checks if the authenticated user can delete the resource.

func (*RoleBasedAuthorizationHook) CanRead

func (h *RoleBasedAuthorizationHook) CanRead(ctx context.Context, resourceType, resourceID string) error

CanRead checks if the authenticated user can read the resource.

func (*RoleBasedAuthorizationHook) CanUpdate

func (h *RoleBasedAuthorizationHook) CanUpdate(ctx context.Context, resourceType, resourceID string) error

CanUpdate checks if the authenticated user can update the resource.

type SchemaIDInput

type SchemaIDInput struct {
	ID string `path:"id" doc:"Schema URN"`
}

SchemaIDInput contains the schema ID path parameter.

type ScopedAuthorizationHook

type ScopedAuthorizationHook struct {
	// RequireScopes determines whether to enforce scope checking.
	// If false, all operations are allowed (useful for development/testing).
	RequireScopes bool
}

ScopedAuthorizationHook implements AuthorizationHook using OAuth scopes. It checks that the request context contains appropriate scopes for the operation.

func NewScopedAuthorizationHook

func NewScopedAuthorizationHook(requireScopes bool) *ScopedAuthorizationHook

NewScopedAuthorizationHook creates a new scoped authorization hook.

func (*ScopedAuthorizationHook) CanCreate

func (h *ScopedAuthorizationHook) CanCreate(ctx context.Context, resourceType string) error

CanCreate checks if the authenticated user can create resources of this type.

func (*ScopedAuthorizationHook) CanDelete

func (h *ScopedAuthorizationHook) CanDelete(ctx context.Context, resourceType, resourceID string) error

CanDelete checks if the authenticated user can delete the resource.

func (*ScopedAuthorizationHook) CanRead

func (h *ScopedAuthorizationHook) CanRead(ctx context.Context, resourceType, resourceID string) error

CanRead checks if the authenticated user can read the resource.

func (*ScopedAuthorizationHook) CanUpdate

func (h *ScopedAuthorizationHook) CanUpdate(ctx context.Context, resourceType, resourceID string) error

CanUpdate checks if the authenticated user can update the resource.

type SearchInput

type SearchInput struct {
	Body *SearchRequest `doc:"Search request body"`
}

SearchInput contains the request body for a search operation.

type SearchOutput

type SearchOutput struct {
	Body *ListResponse
}

SearchOutput is the response for search operations.

type SearchRequest

type SearchRequest struct {
	Schemas            []string `json:"schemas,omitempty"`
	Attributes         []string `json:"attributes,omitempty"`
	ExcludedAttributes []string `json:"excludedAttributes,omitempty"`
	Filter             string   `json:"filter,omitempty"`
	SortBy             string   `json:"sortBy,omitempty"`
	SortOrder          string   `json:"sortOrder,omitempty"`
	StartIndex         int      `json:"startIndex,omitempty"`
	Count              int      `json:"count,omitempty"`
}

SearchRequest represents a SCIM search request body (POST /.search).

func (*SearchRequest) ToAttributeFilter

func (s *SearchRequest) ToAttributeFilter() *AttributeFilter

ToAttributeFilter creates an AttributeFilter from the search request.

func (*SearchRequest) ToListOptions

func (s *SearchRequest) ToListOptions(defaultCount int) ListOptions

ToListOptions converts a SearchRequest to ListOptions.

type Service

type Service interface {

	// GetUser retrieves a user by ID.
	GetUser(ctx context.Context, id string) (*User, error)

	// ListUsers lists users with optional filtering and pagination.
	ListUsers(ctx context.Context, opts ListOptions) (*ListResponse, error)

	// CreateUser creates a new user.
	CreateUser(ctx context.Context, user *User) (*User, error)

	// UpdateUser replaces a user (PUT semantics).
	UpdateUser(ctx context.Context, id string, user *User, etag string) (*User, error)

	// PatchUser applies partial modifications to a user.
	PatchUser(ctx context.Context, id string, patch *PatchRequest, etag string) (*User, error)

	// DeleteUser removes a user.
	DeleteUser(ctx context.Context, id string) error

	// GetGroup retrieves a group by ID.
	GetGroup(ctx context.Context, id string) (*Group, error)

	// ListGroups lists groups with optional filtering and pagination.
	ListGroups(ctx context.Context, opts ListOptions) (*ListResponse, error)

	// CreateGroup creates a new group.
	CreateGroup(ctx context.Context, group *Group) (*Group, error)

	// UpdateGroup replaces a group (PUT semantics).
	UpdateGroup(ctx context.Context, id string, group *Group, etag string) (*Group, error)

	// PatchGroup applies partial modifications to a group.
	PatchGroup(ctx context.Context, id string, patch *PatchRequest, etag string) (*Group, error)

	// DeleteGroup removes a group.
	DeleteGroup(ctx context.Context, id string) error

	// ProcessBulk processes a bulk request.
	ProcessBulk(ctx context.Context, req *BulkRequest) (*BulkResponse, error)

	// GetMe retrieves the current user based on context.
	GetMe(ctx context.Context) (*User, error)

	// PatchMe applies partial modifications to the current user.
	PatchMe(ctx context.Context, patch *PatchRequest, etag string) (*User, error)
}

Service defines the SCIM service interface for managing users and groups.

type ServiceProviderConfigOutput

type ServiceProviderConfigOutput struct {
	Body schema.ServiceProviderConfig
}

ServiceProviderConfigOutput is the response for the ServiceProviderConfig endpoint.

type Store

type Store interface {

	// GetUserByID retrieves a user by SCIM ID.
	GetUserByID(ctx context.Context, id string) (*User, error)

	// GetUserByUserName retrieves a user by userName (typically email).
	GetUserByUserName(ctx context.Context, userName string) (*User, error)

	// GetUserByExternalID retrieves a user by externalId.
	GetUserByExternalID(ctx context.Context, externalID string) (*User, error)

	// ListUsers lists users with filtering and pagination.
	// Returns resources, total count, and error.
	ListUsers(ctx context.Context, opts ListOptions) ([]*User, int, error)

	// CreateUser creates a new user.
	CreateUser(ctx context.Context, user *User) (*User, error)

	// UpdateUser updates an existing user.
	UpdateUser(ctx context.Context, id string, user *User) (*User, error)

	// DeleteUser deletes a user.
	DeleteUser(ctx context.Context, id string) error

	// GetGroupByID retrieves a group by SCIM ID.
	GetGroupByID(ctx context.Context, id string) (*Group, error)

	// GetGroupByDisplayName retrieves a group by displayName.
	GetGroupByDisplayName(ctx context.Context, displayName string) (*Group, error)

	// GetGroupByExternalID retrieves a group by externalId.
	GetGroupByExternalID(ctx context.Context, externalID string) (*Group, error)

	// ListGroups lists groups with filtering and pagination.
	// Returns resources, total count, and error.
	ListGroups(ctx context.Context, opts ListOptions) ([]*Group, int, error)

	// CreateGroup creates a new group.
	CreateGroup(ctx context.Context, group *Group) (*Group, error)

	// UpdateGroup updates an existing group.
	UpdateGroup(ctx context.Context, id string, group *Group) (*Group, error)

	// DeleteGroup deletes a group.
	DeleteGroup(ctx context.Context, id string) error

	// GetGroupsForUser returns all groups a user belongs to.
	GetGroupsForUser(ctx context.Context, userID string) ([]GroupRef, error)

	// GetMembersForGroup returns all members of a group.
	GetMembersForGroup(ctx context.Context, groupID string) ([]MemberRef, error)

	// AddMemberToGroup adds a user to a group.
	AddMemberToGroup(ctx context.Context, groupID, userID string) error

	// RemoveMemberFromGroup removes a user from a group.
	RemoveMemberFromGroup(ctx context.Context, groupID, userID string) error
}

Store defines the persistence layer interface for SCIM resources. Implementations map SCIM operations to the underlying data store.

type UpdateGroupInput

type UpdateGroupInput struct {
	ID      string `path:"id" doc:"Group ID"`
	IfMatch string `header:"If-Match" doc:"ETag for conditional update"`
	Body    *Group `doc:"Group resource to replace"`
}

UpdateGroupInput contains parameters for replacing a group.

type UpdateGroupOutput

type UpdateGroupOutput struct {
	Body *Group
	ETag string `header:"ETag" doc:"Entity tag for caching and conditional requests"`
}

UpdateGroupOutput is the response for updating a group.

type UpdateUserInput

type UpdateUserInput struct {
	ID      string `path:"id" doc:"User ID"`
	IfMatch string `header:"If-Match" doc:"ETag for conditional update"`
	Body    *User  `doc:"User resource to replace"`
}

UpdateUserInput contains parameters for replacing a user.

type UpdateUserOutput

type UpdateUserOutput struct {
	Body *User
	ETag string `header:"ETag" doc:"Entity tag for caching and conditional requests"`
}

UpdateUserOutput is the response for updating a user.

type User

type User struct {
	Resource
	UserName          string       `json:"userName"`
	Name              *Name        `json:"name,omitempty"`
	DisplayName       string       `json:"displayName,omitempty"`
	NickName          string       `json:"nickName,omitempty"`
	ProfileURL        string       `json:"profileUrl,omitempty"`
	Title             string       `json:"title,omitempty"`
	UserType          string       `json:"userType,omitempty"`
	PreferredLanguage string       `json:"preferredLanguage,omitempty"`
	Locale            string       `json:"locale,omitempty"`
	Timezone          string       `json:"timezone,omitempty"`
	Active            *bool        `json:"active,omitempty"`
	Password          string       `json:"password,omitempty"` //nolint:gosec // G117: field holds SCIM password attribute, not hardcoded secret
	Emails            []MultiValue `json:"emails,omitempty"`
	PhoneNumbers      []MultiValue `json:"phoneNumbers,omitempty"`
	IMs               []MultiValue `json:"ims,omitempty"`
	Photos            []MultiValue `json:"photos,omitempty"`
	Addresses         []Address    `json:"addresses,omitempty"`
	Groups            []GroupRef   `json:"groups,omitempty"`
	Entitlements      []MultiValue `json:"entitlements,omitempty"`
	Roles             []MultiValue `json:"roles,omitempty"`
	X509Certificates  []MultiValue `json:"x509Certificates,omitempty"`

	// Enterprise User Extension
	EnterpriseUser *EnterpriseUser `json:"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User,omitempty"`
}

User represents a SCIM User resource as defined in RFC 7643 Section 4.1.

Directories

Path Synopsis
Package filter provides SCIM filter expression parsing and evaluation.
Package filter provides SCIM filter expression parsing and evaluation.
Package mapper provides mapping between SCIM resources and CoreForge entities.
Package mapper provides mapping between SCIM resources and CoreForge entities.
Package patch provides SCIM PATCH operation handling.
Package patch provides SCIM PATCH operation handling.
Package schema provides SCIM schema definitions for discovery endpoints.
Package schema provides SCIM schema definitions for discovery endpoints.
Package store provides SCIM Store implementations.
Package store provides SCIM Store implementations.

Jump to

Keyboard shortcuts

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