Documentation
¶
Overview ¶
Package scimprotocol implements SCIM 2.0 (RFC 7643 and RFC 7644) for receiving provisioning requests from identity providers.
The import path is github.com/singlestore-labs/scim.
Resources ¶
Define User, Group, and other resources by embedding SCIMResourceMarker and tagging fields with scim struct tags. See github.com/singlestore-labs/scim/scimtag for supported characteristics. Call github.com/singlestore-labs/scim/scimtag.BuildAllSCIMCharacsCache once at startup for each resource type.
HTTP endpoints ¶
Implement Server and pass it to SCIMRouter, or build your own handlers with helpers such as GetResourceHelper and GetListResourceHelper. Marshal and unmarshal with Marshal and Unmarshal; they honor scim tags for attribute selection, required fields, and empty-value handling.
A complete in-memory example lives in the scimtest package.
Index ¶
- Variables
- func CompareValueAddIfAzure(target reflect.Value, targetCharacs *scimtag.Characteristics, op CompareOp, ...) (bool, error)
- func CreateResourceHelper[T Resource](r *http.Request, scimID string, ...) (nvelope.Response, error)
- func EvalHelper(e Expression, p *Node, objV reflect.Value, ...) (bool, error)
- func GetFilteredResources[T Resource](filter *OrExpression, inputs []T) ([]T, error)
- func GetListResourceHelper[T Resource](r *http.Request, trace util.Trace, defaultPageSize int, scimID string, ...) (nvelope.Response, error)
- func GetResourceHelper[T Resource](r *http.Request, scimID string, resourceID string, ...) (nvelope.Response, error)
- func GetSCIMDataType(t reflect.Type, scimAttrName string) (string, error)
- func GetSchemasHelper(resourceTypes []ResourceType) (nvelope.Response, error)
- func Marshal(obj any) ([]byte, error)
- func MarshalWithSelectedAttr(obj any, selectedAttr []string, excludeSelected bool) (_ []byte, err error)
- func Patch(objV reflect.Value, path *Node, op string, value []byte) error
- func PatchResourceHelper[T Resource](r *http.Request, scimID string, resourceID string, ...) (nvelope.Response, error)
- func SCIMRouter(tracer util.Trace, server Server) func(*nchi.Mux)
- func Unmarshal(data []byte, obj any) (err error)
- func UpdateResourceHelper[T Resource](r *http.Request, scimID string, resourceID string, ...) (nvelope.Response, error)
- type AndTerm
- type AttributeSchema
- type AuthType
- type AuthenticationScheme
- type Common
- type CompValue
- type CompareOp
- type Config
- type EndpointSCIMID
- type EndpointSCIMIDAndResourceID
- type Expr
- type Expression
- type ListResponse
- type MultiValueElement
- type Node
- type NotExpression
- type OrExpression
- type PatchOperation
- type Path
- type PrimaryDataType
- type Resource
- type ResourceType
- type ResourceTypeMeta
- type SCIMConnectionErr
- type SCIMMarshaler
- type SCIMResourceMarker
- type SCIMUnmarshaler
- type SQLGenerator
- type Schema
- type SchemaExtention
- type Server
Constants ¶
This section is empty.
Variables ¶
var Lex = lexer.MustSimple([]lexer.SimpleRule{
{Name: "String", Pattern: stringPattern},
{Name: "Number", Pattern: numberPattern},
{Name: "URI", Pattern: uriPattern},
{Name: "Ident", Pattern: `[a-zA-Z][-a-zA-Z0-9_]*`},
{Name: "(", Pattern: `\(`},
{Name: ")", Pattern: `\)`},
{Name: "[", Pattern: `\[`},
{Name: "]", Pattern: `\]`},
{Name: "Whitespace", Pattern: `[ \t]+`},
{Name: "Dot", Pattern: `\.`},
{Name: "Colon", Pattern: `\:`},
})
Lex tokenizes shapes only, never keywords.
Rules are distinguishable by their first character, so ordering is only significant for URI, which must precede Ident.
var URIPattenRegexp = regexp.MustCompile(uriPattern)
Functions ¶
func CompareValueAddIfAzure ¶
func CompareValueAddIfAzure(target reflect.Value, targetCharacs *scimtag.Characteristics, op CompareOp, value string, azureAdd bool) (bool, error)
CompareValueAddIfAzure compare the target reflect value with input op and value. if azureAdd is true, it will set the target value when op is 'eq'.
func CreateResourceHelper ¶
func EvalHelper ¶
func EvalHelper(e Expression, p *Node, objV reflect.Value, scimCharacs *scimtag.Characteristics, azureFilterAdd bool) (bool, error)
EvalHelper is a function that evaluates filter expressions against refelect.Value objects scimCharacs should be nil when object is not SCIM attribute
azureFilterAdd is hacky way to be compatible with azure's 'add' patch. Following patch should add new email that fit the filter and value. since it's hacky way so currently only support following two, no more complex op.
{
"op": "add",
"path": "emails[type eq \"work\"].value",
"value": "zoey@mcglynn.name"
},
{
"op": "add",
"path": "emails[type eq \"work\"].primary",
"value": true
},
the azureFilterAdd should only be turned on in patch processing when op is 'add'.
func GetFilteredResources ¶
func GetFilteredResources[T Resource](filter *OrExpression, inputs []T) ([]T, error)
func GetListResourceHelper ¶
func GetResourceHelper ¶
func GetSchemasHelper ¶
func GetSchemasHelper(resourceTypes []ResourceType) (nvelope.Response, error)
func MarshalWithSelectedAttr ¶
func PatchResourceHelper ¶
func PatchResourceHelper[T Resource]( r *http.Request, scimID string, resourceID string, getResourceFromDB func(ctx context.Context, scimID string, resourceID string) (T, error), updateResourceToDB func(ctx context.Context, scimID string, resourceID string, _ T) (T, error), ) (nvelope.Response, error)
func SCIMRouter ¶
Types ¶
type AndTerm ¶
type AndTerm struct {
Left Expr `parser:"@@"` // Expr will be recursive parse either Expression or Not(Group)
Right []Expr `parser:"(Whitespace 'and' Whitespace @@)*"`
}
func (AndTerm) RedactedString ¶
type AttributeSchema ¶
type AttributeSchema struct {
Name string `json:"name"`
Type string `json:"type"`
MultiValued bool `json:"multiValued"`
Required bool `json:"required"`
CaseExact *bool `json:"caseExact,omitempty"`
Mutability scimtag.Mutability `json:"mutability"`
Returned scimtag.Returned `json:"returned"`
Uniqueness *string `json:"uniqueness,omitempty"`
CanonicalValues *[]string `json:"canonicalValues,omitempty"`
ReferenceTypes []string `json:"referenceTypes,omitempty"`
SubAttributes []AttributeSchema `json:"subAttributes,omitempty"`
}
type AuthenticationScheme ¶
type CompValue ¶ added in v0.0.2
type CompValue string
CompValue holds the raw JSON literal of a comparison value, quotes included for strings, so that it stays consumable by json.Unmarshal.
compValue = false / null / true / number / string ; rules from JSON (RFC 7159)
type CompareOp ¶ added in v0.0.2
type CompareOp string
const ( OpPR CompareOp = "pr" OpEQ CompareOp = "eq" OpNE CompareOp = "ne" OpCO CompareOp = "co" OpSW CompareOp = "sw" OpEW CompareOp = "ew" OpGT CompareOp = "gt" OpLT CompareOp = "lt" OpGE CompareOp = "ge" OpLE CompareOp = "le" )
RFC 7644 §3.4.2.2 attribute operators. The parser tag on Expression is the allow-list; these constants are for Go comparisons after Capture.
type Config ¶
type EndpointSCIMID ¶
type EndpointSCIMID struct {
SCIMID string `nvelope:"path,name=scimID"`
}
type Expression ¶
type Expression struct {
Path Path `parser:"@@"`
// Operator is optional, like `emails[type eq "work"]`
CompareOp CompareOp `parser:"(Whitespace (@'pr' | (@('eq'|'ne'|'co'|'sw'|'ew'|'gt'|'lt'|'ge'|'le')"`
Value CompValue `parser:" Whitespace @(String|Number|'true'|'false'|'null'))))?"`
}
Expression is an attribute expression.
attrExp = (attrPath SP "pr") / (attrPath SP compareOp SP compValue)
func (Expression) RedactedString ¶
func (e Expression) RedactedString() string
func (Expression) String ¶
func (e Expression) String() string
func (Expression) ToSqlizer ¶
func (e Expression) ToSqlizer(sg SQLGenerator, not bool) (sq.Sqlizer, error)
type ListResponse ¶
type ListResponse[T any] struct { Resources []T StartIndex int ItemsPerPage int // return actual items number per page TotalResults int }
func (ListResponse[T]) MarshalSCIM ¶
func (l ListResponse[T]) MarshalSCIM(selectedAttr []string, excludeSelected bool) ([]byte, error)
type MultiValueElement ¶
type MultiValueElement interface {
// contains filtered or unexported methods
}
type NotExpression ¶
type NotExpression struct {
Not bool `parser:"(@'not' Whitespace?)?"`
Group OrExpression `parser:"'(' Whitespace? @@ Whitespace? ')'"`
}
NotExpression is a grouped filter, optionally negated. 'not' has the highest precedence so it sits at the deepest level.
FILTER = ... / *1"not" "(" FILTER ")"
The ABNF puts no SP after "not" while the RFC examples and identity providers send "not (", so both are accepted.
func (NotExpression) RedactedString ¶
func (ne NotExpression) RedactedString() string
func (NotExpression) String ¶
func (ne NotExpression) String() string
func (NotExpression) ToSqlizer ¶
func (ne NotExpression) ToSqlizer(sg SQLGenerator, not bool) (sq.Sqlizer, error)
type OrExpression ¶
type OrExpression struct {
Left *AndTerm `parser:"@@"`
Right []*AndTerm `parser:"(Whitespace 'or' Whitespace @@)*"`
}
func ParseFilter ¶
func ParseFilter(filterStr string) (*OrExpression, error)
func (OrExpression) Eval ¶
Eval evaluates the OrExpression against the given reflect.Value v. The azureAdd parameter indicates whether to apply Azure-specific filtering logic. Detail explained in filter.go EvalHelper.
func (OrExpression) RedactedString ¶
func (oe OrExpression) RedactedString() string
func (OrExpression) String ¶
func (oe OrExpression) String() string
func (OrExpression) ToSqlizer ¶
func (oe OrExpression) ToSqlizer(sg SQLGenerator, not bool) (sq.Sqlizer, error)
type PatchOperation ¶
type PatchOperation struct {
Op string `json:"op"`
Path string `json:"path"`
Value json.RawMessage `json:"value"`
}
func UnmarshalPatchRequest ¶
func UnmarshalPatchRequest(data []byte) ([]PatchOperation, error)
type Path ¶
type Path struct {
URI string `parser:"(@URI"`
Colon string `parser:" ':')?"`
AttrName string `parser:"@Ident"`
Filter *OrExpression `parser:"('[' Whitespace? @@ Whitespace?']')?"`
SubAttrName string `parser:"('.'@Ident)?"`
}
type PrimaryDataType ¶
type ResourceType ¶
type ResourceType struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Endpoint string `json:"endpoint"` // "/Users" or "/Groups"
Description string `json:"description,omitempty"`
ResourceObjectType reflect.Type `json:"-"`
Meta ResourceTypeMeta `json:"meta"`
}
func (ResourceType) MarshalSCIM ¶
func (r ResourceType) MarshalSCIM([]string, bool) ([]byte, error)
type ResourceTypeMeta ¶
type SCIMConnectionErr ¶
type SCIMConnectionErr error
type SCIMMarshaler ¶
type SCIMMarshaler interface {
MarshalSCIM(selectedAttr []string, excludeSelected bool) ([]byte, error)
}
SCIMMarshaler and SCIMUnmarshaler allow customized marshal and unmarshal for SCIM Note: if you choose to have SCIMMarshaler or SCIMUnmarshaler, means you take full control of marshal. And the patch and filter may not work as expected.
type SCIMResourceMarker ¶
type SCIMResourceMarker struct{}
type SCIMUnmarshaler ¶
type SQLGenerator ¶
type SQLGenerator interface {
// sq.And, sq.Or, sq.Eq .... returns sq.Sqlizer
Generate(Common, bool) (sq.Sqlizer, error)
}
SQLGenerator is a interface used to convert expression to sql with SICM tag
type Schema ¶
type Schema struct {
ID string `json:"id"`
Attributes []AttributeSchema `json:"attributes"`
}
Schema's name and description is option in rfc and not fit in scim tag, so not include for now.
func GetResourceSchema ¶
resource is User or Groups or... , that User contains Core User attributes group and Extensions attributes group
type SchemaExtention ¶
func GetSchemaURIFromResource ¶
func GetSchemaURIFromResource(resourceT reflect.Type, resourceVforFilterEmpty *reflect.Value) (coreSchemaURI string, extensions []SchemaExtention, err error)
GetSchemaURIFromResource is a helper function to get schema URI and extension URIs for ResourceType from self-defined SCIM resource struct, like User, Group resourceV is only needed when you need filter out empty URI struct, like extension URI should not include in when it's empty during marshal if input type is not Resource, then return ErrNotFound error if input type is Resource but doesn't have URI, return error
type Server ¶
type Server interface {
// Authorization middleware for SCIM requests
Authorization(inner func() error, r *http.Request) error
// GetResourceTypes returns the list of supported resource types
GetResourceTypes() []ResourceType
// Resource handlers for individual resource operations
GetResourceHandler(r *http.Request, resourceType ResourceType, params EndpointSCIMIDAndResourceID) (nvelope.Response, error)
GetResourceListHandler(r *http.Request, resourceType ResourceType, params EndpointSCIMID) (nvelope.Response, error)
PostResourceHandler(r *http.Request, resourceType ResourceType, params EndpointSCIMID) (nvelope.Response, error)
UpdateResourceHandler(r *http.Request, resourceType ResourceType, params EndpointSCIMIDAndResourceID) (nvelope.Response, error)
PatchResourceHandler(r *http.Request, resourceType ResourceType, params EndpointSCIMIDAndResourceID) (nvelope.Response, error)
DeleteResourceHandler(r *http.Request, resourceType ResourceType, params EndpointSCIMIDAndResourceID) (nvelope.Response, error)
// Bulk operations handler
BulkHandler() (nvelope.Response, error)
// SCIM metadata handlers
GetResourceTypesHandler() (nvelope.Response, error)
SchemasHandler() (nvelope.Response, error)
GetServiceProviderConfigHandler(r *http.Request, w http.ResponseWriter) (nvelope.Response, error)
}
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package scimerror defines SCIM protocol errors as specified in RFC 7644 section 3.12.
|
Package scimerror defines SCIM protocol errors as specified in RFC 7644 section 3.12. |
|
Package scimtag parses scim struct tags into RFC 7643 attribute characteristics and caches them for marshal, unmarshal, filter, patch, and schema generation.
|
Package scimtag parses scim struct tags into RFC 7643 attribute characteristics and caches them for marshal, unmarshal, filter, patch, and schema generation. |
|
Package scimtest is an in-memory example SCIM server used by tests and as a usage example for github.com/singlestore-labs/scim.
|
Package scimtest is an in-memory example SCIM server used by tests and as a usage example for github.com/singlestore-labs/scim. |
|
Package util provides small helpers used by the SCIM protocol implementation and its tests.
|
Package util provides small helpers used by the SCIM protocol implementation and its tests. |