Documentation
¶
Index ¶
- Constants
- type AuthenticationScheme
- type AuthenticationType
- type ListRequestParams
- type Logger
- type Meta
- type Page
- type PatchOperation
- type Resource
- type ResourceAttributes
- type ResourceHandler
- type ResourceType
- type SchemaExtension
- type Server
- type ServerArgs
- type ServerOption
- type ServiceProviderConfig
Examples ¶
Constants ¶
const ( // PatchOperationAdd is used to add a new attribute value to an existing resource. PatchOperationAdd = "add" // PatchOperationRemove removes the value at the target location specified by the required attribute "path". PatchOperationRemove = "remove" // PatchOperationReplace replaces the value at the target location specified by the "path". PatchOperationReplace = "replace" )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AuthenticationScheme ¶
type AuthenticationScheme struct { // Type is the authentication scheme. This specification defines the values "oauth", "oauth2", "oauthbearertoken", // "httpbasic", and "httpdigest". Type AuthenticationType // Name is the common authentication scheme name, e.g., HTTP Basic. Name string // Description of the authentication scheme. Description string // SpecURI is an HTTP-addressable URL pointing to the authentication scheme's specification. SpecURI optional.String // DocumentationURI is an HTTP-addressable URL pointing to the authentication scheme's usage documentation. DocumentationURI optional.String // Primary is a boolean value indicating the 'primary' or preferred authentication scheme. Primary bool }
AuthenticationScheme specifies a supported authentication scheme property.
type AuthenticationType ¶
type AuthenticationType string
AuthenticationType is a single keyword indicating the authentication type of the authentication scheme.
const ( // AuthenticationTypeOauth indicates that the authentication type is OAuth. AuthenticationTypeOauth AuthenticationType = "oauth" // AuthenticationTypeOauth2 indicates that the authentication type is OAuth2. AuthenticationTypeOauth2 AuthenticationType = "oauth2" // AuthenticationTypeOauthBearerToken indicates that the authentication type is OAuth2 Bearer Token. AuthenticationTypeOauthBearerToken AuthenticationType = "oauthbearertoken" // AuthenticationTypeHTTPBasic indicated that the authentication type is Basic Access Authentication. AuthenticationTypeHTTPBasic AuthenticationType = "httpbasic" // AuthenticationTypeHTTPDigest indicated that the authentication type is Digest Access Authentication. AuthenticationTypeHTTPDigest AuthenticationType = "httpdigest" )
type ListRequestParams ¶
type ListRequestParams struct { // Count specifies the desired maximum number of query results per page. A negative value SHALL be interpreted as "0". // A value of "0" indicates that no resource results are to be returned except for "totalResults". Count int // Filter represents the parsed and tokenized filter query parameter. // It is an optional parameter and thus will be nil when the parameter is not present. FilterValidator *filter.Validator // StartIndex The 1-based index of the first query result. A value less than 1 SHALL be interpreted as 1. StartIndex int }
ListRequestParams request parameters sent to the API via a "GetAll" route.
type Logger ¶
type Logger interface {
Error(args ...interface{})
}
Logger defines an interface for logging errors.
type Meta ¶
type Meta struct { // Created is the time that the resource was added to the service provider. Created *time.Time // LastModified is the most recent time that the details of this resource were updated at the service provider. LastModified *time.Time // Version is the version / entity-tag of the resource Version string }
Meta represents the metadata of a resource.
type Page ¶
type Page struct { // TotalResults is the total number of results returned by the list or query operation. TotalResults int // Resources is a multi-valued list of complex objects containing the requested resources. Resources []Resource }
Page represents a paginated resource query response.
type PatchOperation ¶
type PatchOperation struct { // Op indicates the operation to perform and MAY be one of "add", "remove", or "replace". Op string // Path contains an attribute path describing the target of the operation. The "path" attribute is OPTIONAL for // "add" and "replace" and is REQUIRED for "remove" operations. Path *filter.Path // Value specifies the value to be added or replaced. Value interface{} }
PatchOperation represents a single PATCH operation.
type Resource ¶
type Resource struct { // ID is the unique identifier created by the callback method "Create". ID string // ExternalID is an identifier for the resource as defined by the provisioning client. ExternalID optional.String // Attributes is a list of attributes defining the resource. Attributes ResourceAttributes // Meta contains dates and the version of the resource. Meta Meta }
Resource represents an entity returned by a callback method.
type ResourceAttributes ¶
type ResourceAttributes map[string]interface{}
ResourceAttributes represents a list of attributes given to the callback method to create or replace a resource based on the given attributes.
type ResourceHandler ¶
type ResourceHandler interface { // Create stores given attributes. Returns a resource with the attributes that are stored and a (new) unique identifier. Create(r *http.Request, attributes ResourceAttributes) (Resource, error) // Get returns the resource corresponding with the given identifier. Get(r *http.Request, id string) (Resource, error) // GetAll returns a paginated list of resources. // An empty list of resources will be represented as `null` in the JSON response if `nil` is assigned to the // Page.Resources. Otherwise, is an empty slice is assigned, an empty list will be represented as `[]`. GetAll(r *http.Request, params ListRequestParams) (Page, error) // Replace replaces ALL existing attributes of the resource with given identifier. Given attributes that are empty // are to be deleted. Returns a resource with the attributes that are stored. Replace(r *http.Request, id string, attributes ResourceAttributes) (Resource, error) // Delete removes the resource with corresponding ID. Delete(r *http.Request, id string) error // Patch update one or more attributes of a SCIM resource using a sequence of // operations to "add", "remove", or "replace" values. // If you return no Resource.Attributes, a 204 No Content status code will be returned. // This case is only valid in the following scenarios: // 1. the Add/Replace operation should return No Content only when the value already exists AND is the same. // 2. the Remove operation should return No Content when the value to be remove is already absent. // More information in Section 3.5.2 of RFC 7644: https://tools.ietf.org/html/rfc7644#section-3.5.2 Patch(r *http.Request, id string, operations []PatchOperation) (Resource, error) }
ResourceHandler represents a set of callback method that connect the SCIM server with a provider of a certain resource.
Example ¶
package main import ( "fmt" "math/rand" "net/http" "strings" "time" "github.com/elimity-com/scim/errors" "github.com/elimity-com/scim/optional" ) func main() { var r interface{} = testResourceHandler{} _, ok := r.(ResourceHandler) fmt.Println(ok) } type testData struct { resourceAttributes ResourceAttributes meta map[string]string } // simple in-memory resource database. type testResourceHandler struct { data map[string]testData } func (h testResourceHandler) Create(r *http.Request, attributes ResourceAttributes) (Resource, error) { // create unique identifier rng := rand.New(rand.NewSource(time.Now().UnixNano())) id := fmt.Sprintf("%04d", rng.Intn(9999)) // store resource h.data[id] = testData{ resourceAttributes: attributes, } now := time.Now() // return stored resource return Resource{ ID: id, ExternalID: h.externalID(attributes), Attributes: attributes, Meta: Meta{ Created: &now, LastModified: &now, Version: fmt.Sprintf("v%s", id), }, }, nil } func (h testResourceHandler) Delete(r *http.Request, id string) error { // check if resource exists _, ok := h.data[id] if !ok { return errors.ScimErrorResourceNotFound(id) } // delete resource delete(h.data, id) return nil } func (h testResourceHandler) Get(r *http.Request, id string) (Resource, error) { // check if resource exists data, ok := h.data[id] if !ok { return Resource{}, errors.ScimErrorResourceNotFound(id) } created, _ := time.ParseInLocation(time.RFC3339, fmt.Sprintf("%v", data.meta["created"]), time.UTC) lastModified, _ := time.Parse(time.RFC3339, fmt.Sprintf("%v", data.meta["lastModified"])) // return resource with given identifier return Resource{ ID: id, ExternalID: h.externalID(data.resourceAttributes), Attributes: data.resourceAttributes, Meta: Meta{ Created: &created, LastModified: &lastModified, Version: fmt.Sprintf("%v", data.meta["version"]), }, }, nil } func (h testResourceHandler) GetAll(r *http.Request, params ListRequestParams) (Page, error) { if params.Count == 0 { return Page{ TotalResults: len(h.data), }, nil } resources := make([]Resource, 0) i := 1 for k, v := range h.data { if i > (params.StartIndex + params.Count - 1) { break } if i >= params.StartIndex { resources = append(resources, Resource{ ID: k, ExternalID: h.externalID(v.resourceAttributes), Attributes: v.resourceAttributes, }) } i++ } return Page{ TotalResults: len(h.data), Resources: resources, }, nil } func (h testResourceHandler) Patch(r *http.Request, id string, operations []PatchOperation) (Resource, error) { if h.shouldReturnNoContent(id, operations) { return Resource{}, nil } for _, op := range operations { switch op.Op { case PatchOperationAdd: if op.Path != nil { h.data[id].resourceAttributes[op.Path.String()] = op.Value } else { valueMap := op.Value.(map[string]interface{}) for k, v := range valueMap { if arr, ok := h.data[id].resourceAttributes[k].([]interface{}); ok { arr = append(arr, v) h.data[id].resourceAttributes[k] = arr } else { h.data[id].resourceAttributes[k] = v } } } case PatchOperationReplace: if op.Path != nil { h.data[id].resourceAttributes[op.Path.String()] = op.Value } else { valueMap := op.Value.(map[string]interface{}) for k, v := range valueMap { h.data[id].resourceAttributes[k] = v } } case PatchOperationRemove: h.data[id].resourceAttributes[op.Path.String()] = nil } } created, _ := time.ParseInLocation(time.RFC3339, fmt.Sprintf("%v", h.data[id].meta["created"]), time.UTC) now := time.Now() // return resource with replaced attributes return Resource{ ID: id, ExternalID: h.externalID(h.data[id].resourceAttributes), Attributes: h.data[id].resourceAttributes, Meta: Meta{ Created: &created, LastModified: &now, Version: fmt.Sprintf("%s.patch", h.data[id].meta["version"]), }, }, nil } func (h testResourceHandler) Replace(r *http.Request, id string, attributes ResourceAttributes) (Resource, error) { // check if resource exists _, ok := h.data[id] if !ok { return Resource{}, errors.ScimErrorResourceNotFound(id) } // replace (all) attributes h.data[id] = testData{ resourceAttributes: attributes, } // return resource with replaced attributes return Resource{ ID: id, ExternalID: h.externalID(attributes), Attributes: attributes, }, nil } func (h testResourceHandler) externalID(attributes ResourceAttributes) optional.String { if eID, ok := attributes["externalId"]; ok { externalID, ok := eID.(string) if !ok { return optional.String{} } return optional.NewString(externalID) } return optional.String{} } func (h testResourceHandler) noContentOperation(id string, op PatchOperation) bool { isRemoveOp := strings.EqualFold(op.Op, PatchOperationRemove) dataValue, ok := h.data[id] if !ok { return isRemoveOp } var path string if op.Path != nil { path = op.Path.String() } attrValue, ok := dataValue.resourceAttributes[path] if ok && attrValue == op.Value { return true } if !ok && isRemoveOp { return true } switch opValue := op.Value.(type) { case map[string]interface{}: for k, v := range opValue { if v == dataValue.resourceAttributes[k] { return true } } case []map[string]interface{}: for _, m := range opValue { for k, v := range m { if v == dataValue.resourceAttributes[k] { return true } } } } return false } func (h testResourceHandler) shouldReturnNoContent(id string, ops []PatchOperation) bool { for _, op := range ops { if h.noContentOperation(id, op) { continue } return false } return true }
Output: true
type ResourceType ¶
type ResourceType struct { // ID is the resource type's server unique id. This is often the same value as the "name" attribute. ID optional.String // Name is the resource type name. This name is referenced by the "meta.resourceType" attribute in all resources. Name string // Description is the resource type's human-readable description. Description optional.String // Endpoint is the resource type's HTTP-addressable endpoint relative to the Base URL of the service provider, // e.g., "/Users". Endpoint string // Schema is the resource type's primary/base schema. Schema schema.Schema // SchemaExtensions is a list of the resource type's schema extensions. SchemaExtensions []SchemaExtension // Handler is the set of callback method that connect the SCIM server with a provider of the resource type. Handler ResourceHandler }
ResourceType specifies the metadata about a resource type.
type SchemaExtension ¶
type SchemaExtension struct { // Schema is the URI of an extended schema, e.g., "urn:edu:2.0:Staff". Schema schema.Schema // Required is a boolean value that specifies whether or not the schema extension is required for the resource // type. If true, a resource of this type MUST include this schema extension and also include any attributes // declared as required in this schema extension. If false, a resource of this type MAY omit this schema // extension. Required bool }
SchemaExtension is one of the resource type's schema extensions.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server represents a SCIM server which implements the HTTP-based SCIM protocol that makes managing identities in multi-domain scenarios easier to support via a standardized service.
func NewServer ¶
func NewServer(args *ServerArgs, opts ...ServerOption) (Server, error)
Example ¶
args := &ServerArgs{ ServiceProviderConfig: &ServiceProviderConfig{}, ResourceTypes: []ResourceType{}, } server, err := NewServer(args) if err != nil { logger.Fatal(err) } logger.Fatal(http.ListenAndServe(":7643", server))
Output:
Example (BasePath) ¶
args := &ServerArgs{ ServiceProviderConfig: &ServiceProviderConfig{}, ResourceTypes: []ResourceType{}, } server, err := NewServer(args) if err != nil { logger.Fatal(err) } // You can host the SCIM server on a custom path, make sure to strip the prefix, so only `/v2/` is left. http.Handle("/scim/", http.StripPrefix("/scim", server)) logger.Fatal(http.ListenAndServe(":7643", nil))
Output:
Example (Logger) ¶
loggingMiddleware := func(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { logger.Println(r.Method, r.URL.Path) next.ServeHTTP(w, r) } return http.HandlerFunc(fn) } args := &ServerArgs{ ServiceProviderConfig: &ServiceProviderConfig{}, ResourceTypes: []ResourceType{}, } server, err := NewServer(args) if err != nil { logger.Fatal(err) } logger.Fatal(http.ListenAndServe(":7643", loggingMiddleware(server)))
Output:
type ServerArgs ¶
type ServerArgs struct { ServiceProviderConfig *ServiceProviderConfig ResourceTypes []ResourceType }
type ServerOption ¶
type ServerOption func(*Server)
func WithLogger ¶
func WithLogger(logger Logger) ServerOption
WithLogger sets the logger for the server.
type ServiceProviderConfig ¶
type ServiceProviderConfig struct { // DocumentationURI is an HTTP-addressable URL pointing to the service provider's human-consumable help // documentation. DocumentationURI optional.String // AuthenticationSchemes is a multi-valued complex type that specifies supported authentication scheme properties. AuthenticationSchemes []AuthenticationScheme // MaxResults denotes the the integer value specifying the maximum number of resources returned in a response. It defaults to 100. MaxResults int // SupportFiltering whether you SCIM implementation will support filtering. SupportFiltering bool // SupportPatch whether your SCIM implementation will support patch requests. SupportPatch bool }
ServiceProviderConfig enables a service provider to discover SCIM specification features in a standardized form as well as provide additional implementation details to clients.