-
Notifications
You must be signed in to change notification settings - Fork 68
Expand file tree
/
Copy pathresource_handler.go
More file actions
202 lines (172 loc) · 8.3 KB
/
resource_handler.go
File metadata and controls
202 lines (172 loc) · 8.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package scim
import (
"net/http"
"time"
"github.com/elimity-com/scim/filter"
"github.com/elimity-com/scim/optional"
"github.com/elimity-com/scim/schema"
)
// ListRequestParams request parameters sent to the API via a "GetAll" route.
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
// FilterValidator 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
}
// Meta represents the metadata of a resource.
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
}
// Resource represents an entity returned by a callback method.
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
}
func (r Resource) response(resourceType ResourceType, location string) ResourceAttributes {
response := r.Attributes
if response == nil {
response = ResourceAttributes{}
}
response[schema.CommonAttributeID] = r.ID
if r.ExternalID.Present() {
response[schema.CommonAttributeExternalID] = r.ExternalID.Value()
}
schemas := []string{resourceType.Schema.ID}
for _, s := range resourceType.SchemaExtensions {
schemas = append(schemas, s.Schema.ID)
}
response["schemas"] = schemas
m := meta{
ResourceType: resourceType.Name,
Location: location,
}
if r.Meta.Created != nil {
m.Created = r.Meta.Created.Format(time.RFC3339)
}
if r.Meta.LastModified != nil {
m.LastModified = r.Meta.LastModified.Format(time.RFC3339)
}
if len(r.Meta.Version) != 0 {
m.Version = r.Meta.Version
}
response[schema.CommonAttributeMeta] = m
return response
}
// ResourceAttributes represents a list of attributes given to the callback method to create or replace
// a resource based on the given attributes.
type ResourceAttributes map[string]interface{}
// ResourceHandler represents a set of callback method that connect the SCIM server with a provider of a certain resource.
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)
}
// ResourceSearcher is an optional interface that a ResourceHandler can implement to support
// POST /.search on a resource endpoint (e.g. POST /Users/.search).
// Per RFC 7644 Section 3.4.3, this provides an alternative to GET with query parameters.
type ResourceSearcher interface {
Search(r *http.Request, params SearchParams) (Page, error)
}
// ResourceTypeFilter associates a resource type with a validated filter.
type ResourceTypeFilter struct {
// ResourceType is the resource type whose schema the filter validated against.
ResourceType ResourceType
// Validator is the filter validator for this resource type's schema.
Validator filter.Validator
}
// ValidateFilterForResourceTypes validates a raw filter expression against each of the given resource types' schemas.
// It returns a ResourceTypeFilter for each resource type whose schema the filter is valid for.
// This is useful for RootQueryHandler implementations to determine which resource types a filter applies to.
// An empty result means the filter is not valid for any of the given resource types.
// A parse error in the filter expression results in an empty result.
func ValidateFilterForResourceTypes(rawFilter string, resourceTypes []ResourceType) []ResourceTypeFilter {
var results []ResourceTypeFilter
for _, rt := range resourceTypes {
s := rt.Schema
attrs := make([]schema.CoreAttribute, len(s.Attributes), len(s.Attributes)+len(schema.CommonAttributes()))
copy(attrs, s.Attributes)
s.Attributes = append(attrs, schema.CommonAttributes()...)
v, err := filter.NewValidator(rawFilter, s, rt.getSchemaExtensions()...)
if err != nil {
return nil
}
if err := v.Validate(); err != nil {
continue
}
results = append(results, ResourceTypeFilter{
ResourceType: rt,
Validator: v,
})
}
return results
}
// RootQueryHandler represents an optional callback that handles queries against the server root endpoint (GET /).
// Per RFC 7644 Section 3.4.2.1, a query against the server root indicates that all resources within the server
// shall be included, subject to filtering.
//
// The server does not validate or parse the filter for root queries because there is no single target schema.
// ListRequestParams.FilterValidator will always be nil for root queries. The raw filter string can be
// obtained from the request via r.URL.Query().Get("filter"). The handler is responsible for interpreting
// the filter (e.g. meta.resourceType eq "User") as appropriate for its backing store.
type RootQueryHandler interface {
// GetAll returns a paginated list of resources across all resource types.
GetAll(r *http.Request, params ListRequestParams) (Page, error)
}
// SearchParams contains the parameters from a POST /.search request body.
// Per RFC 7644 Section 3.4.3, this includes all query parameters that would normally be sent
// as URL query parameters in a GET request.
type SearchParams struct {
// Attributes is a list of attribute names to return in the response.
// If empty, all attributes are returned.
Attributes []string
// Count specifies the desired maximum number of query results per page.
Count int
// ExcludedAttributes is a list of attribute names to exclude from the response.
ExcludedAttributes []string
// Filter is the raw filter expression string.
Filter string
// FilterValidator represents the parsed and tokenized filter.
// For resource-level search, this is set by the server after validating
// against the resource type's schema. For root-level search, this is nil.
FilterValidator *filter.Validator
// SortBy specifies the attribute whose value will be used to order the returned responses.
SortBy string
// SortOrder specifies the order in which the sortBy parameter is applied. Allowed values
// are "ascending" and "descending".
SortOrder string
// StartIndex is the 1-based index of the first query result.
StartIndex int
}