Documentation
¶
Overview ¶
Package scim is the pure SCIM 2.0 wire layer Wardyn serves to an identity provider's provisioning client: types, the one filter form, PatchOp parsing (including the non-RFC shapes Entra sends) and the RFC 7644 error envelope. It has no HTTP handlers, no store and no routes.
Index ¶
- Constants
- func ParseFilter(s string, allowed ...string) (Filter, *Error)
- func ParseGroup(body []byte) (*Group, *Error)
- func ParsePatch(body []byte) ([]Op, *PatchError)
- func ParseUser(body []byte) (*User, *Error)
- type Email
- type Error
- type Filter
- type Group
- type ListResponse
- type Member
- type Meta
- type Op
- type OpError
- type OpKind
- type PatchError
- type User
Constants ¶
const ( TypeInvalidFilter = "invalidFilter" TypeInvalidSyntax = "invalidSyntax" TypeInvalidPath = "invalidPath" TypeInvalidValue = "invalidValue" TypeNoTarget = "noTarget" )
scimType values of the RFC 7644 error envelope (section 3.12) this package produces.
const ( AttrActive = "active" AttrUserName = "userName" AttrExternalID = "externalId" AttrDisplayName = "displayName" AttrEmail = "emails.value" AttrMembers = "members" )
Canonical attribute names of the attributes Wardyn acts on. Op.Attr is one of these, or, for any other attribute, the path exactly as the client sent it.
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" SchemaPatchOp = "urn:ietf:params:scim:api:messages:2.0:PatchOp" SchemaError = "urn:ietf:params:scim:api:messages:2.0:Error" MediaType = "application/scim+json" )
Schema URNs and the media type of every SCIM body.
Variables ¶
This section is empty.
Functions ¶
func ParseFilter ¶
ParseFilter parses `attr eq "value"` where attr is one of allowed (compared case-insensitively, as SCIM attribute names are) and value is a JSON string literal. Anything else, including `and`/`or`, other operators, unquoted values and unlisted attributes, is invalidFilter. A client that sends an unquoted value (a Microsoft sample shows one) is refused too: RFC 7644 requires the quotes.
func ParseGroup ¶
ParseGroup parses a POST /Groups body. displayName and externalId are required (invalidValue).
func ParsePatch ¶
func ParsePatch(body []byte) ([]Op, *PatchError)
ParsePatch is the pre-validation pass: it resolves every operation of the PATCH before the caller applies any, so a request with one invalid operation yields a *PatchError listing each bad operation by index and no ops at all. It never returns a partial result. Whether a well-formed operation is allowed (an externalId change on a bound identity, say) is the caller's decision, per Op.
Types ¶
type Email ¶
type Email struct {
Value string `json:"value"`
Type string `json:"type,omitempty"`
Primary bool `json:"primary,omitempty"`
}
Email is one entry of a User's emails.
type Error ¶
Error is the RFC 7644 error envelope. Status is the HTTP status the handler answers with; the wire form carries it as a string, as the RFC's examples do.
func NewError ¶
NewError builds an envelope for status and scimType (empty for the types the RFC leaves untyped, such as 404).
func (*Error) MarshalJSON ¶
MarshalJSON renders the wire envelope.
type Filter ¶
type Filter struct {
// Attr is spelled as in the allowed list passed to ParseFilter, whatever case the client used.
Attr string
Value string
}
Filter is the one filter form Wardyn serves: `attr eq "value"`.
type Group ¶
type Group struct {
Schemas []string `json:"schemas"`
ID string `json:"id,omitempty"`
ExternalID string `json:"externalId"`
DisplayName string `json:"displayName"`
Members []Member `json:"members,omitempty"`
Meta *Meta `json:"meta,omitempty"`
}
Group is the SCIM Group subset Wardyn serves. ExternalID is required for the same reason as User's.
type ListResponse ¶
type ListResponse[T any] struct { Schemas []string `json:"schemas"` TotalResults int `json:"totalResults"` StartIndex int `json:"startIndex"` ItemsPerPage int `json:"itemsPerPage"` Resources []T `json:"Resources"` }
ListResponse is the RFC 7644 list envelope. Wardyn does no paging, so StartIndex is always 1.
func NewListResponse ¶
func NewListResponse[T any](resources []T) ListResponse[T]
NewListResponse renders resources as one page; a nil slice becomes `[]`, never null.
type Member ¶
type Member struct {
Value string `json:"value"`
Ref string `json:"$ref,omitempty"`
Display string `json:"display,omitempty"`
}
Member is one entry of a Group's members or of a members PatchOp value. Ref is `$ref`, which Entra sends as null.
type Meta ¶
type Meta struct {
ResourceType string `json:"resourceType,omitempty"`
Created string `json:"created,omitempty"`
LastModified string `json:"lastModified,omitempty"`
Location string `json:"location,omitempty"`
}
Meta is the resource metadata block. A client's meta is ignored on input.
type Op ¶
Op is one resolved PatchOp change. A path-less replace carrying a value object becomes one Op per key, all with the same Index.
Value by Attr: AttrActive is a bool (Entra's string "False" and "True" are accepted); AttrUserName, AttrExternalID, AttrDisplayName and AttrEmail are a non-empty string; AttrMembers is a []Member (a filter-path remove becomes one member; nil on a remove means every member); any other attribute is its json.RawMessage, unvalidated, for the caller to ignore. A remove carries a nil Value except for members. The `emails[type eq "work"]` selector is dropped: Wardyn keeps one address per person.
type PatchError ¶
PatchError is the refusal of a whole PATCH. Invalid is empty when the request envelope itself was bad (not JSON, wrong schema, no Operations).
type User ¶
type User struct {
Schemas []string `json:"schemas"`
ID string `json:"id,omitempty"`
ExternalID string `json:"externalId"`
UserName string `json:"userName"`
DisplayName string `json:"displayName,omitempty"`
Emails []Email `json:"emails,omitempty"`
Active bool `json:"active"`
// ActiveSet is whether the body named active at all; a PUT that omits it leaves the identity as it is.
ActiveSet bool `json:"-"`
Meta *Meta `json:"meta,omitempty"`
}
User is the SCIM User subset Wardyn serves. Attributes outside it are dropped on parse.
ExternalID is required: Entra's default mapping sends the Entra objectId as externalId, and Wardyn binds the projection to a sign-in identity through it. ParseUser refuses a User without one.