public static JObject ToResponse(this SCIMRepresentation representation, string location, bool isGetRequest = false) { var meta = new JObject { { SCIMConstants.StandardSCIMMetaAttributes.ResourceType, representation.ResourceType }, { SCIMConstants.StandardSCIMMetaAttributes.Created, representation.Created }, { SCIMConstants.StandardSCIMMetaAttributes.LastModified, representation.LastModified }, { SCIMConstants.StandardSCIMMetaAttributes.Version, representation.Version }, { SCIMConstants.StandardSCIMMetaAttributes.Location, location } }; var jObj = new JObject { { SCIMConstants.StandardSCIMRepresentationAttributes.Id, representation.Id }, { SCIMConstants.StandardSCIMRepresentationAttributes.Schemas, new JArray(representation.Schemas.Select(s => s.Id)) }, { SCIMConstants.StandardSCIMRepresentationAttributes.Meta, meta } }; if (!string.IsNullOrWhiteSpace(representation.ExternalId)) { jObj.Add(SCIMConstants.StandardSCIMRepresentationAttributes.ExternalId, representation.ExternalId); } EnrichResponse(representation.Attributes.AsQueryable(), jObj, isGetRequest); return(jObj); }
public static void FilterAttributes(this SCIMRepresentation representation, IEnumerable <SCIMAttributeExpression> includedAttributes, IEnumerable <SCIMAttributeExpression> excludedAttributes) { var allAttributes = new List <SCIMRepresentationAttribute>(); allAttributes.AddRange(representation.FlatAttributes); allAttributes.AddRange(representation.HierarchicalAttributes); var queryableAttributes = representation.FlatAttributes.AsQueryable(); if (includedAttributes != null && includedAttributes.Any()) { var attrs = queryableAttributes.FilterAttributes(includedAttributes).ToList(); var includedFullPathLst = (includedAttributes != null && includedAttributes.Any()) ? includedAttributes.Where(i => i is SCIMComplexAttributeExpression).Select(i => i.GetFullPath()) : new List <string>(); representation.FlatAttributes = attrs.Where(a => a != null).SelectMany(_ => { var lst = new List <SCIMRepresentationAttribute> { _ }; lst.AddRange(_.Children.Where(c => includedFullPathLst.Any(f => c.FullPath.StartsWith(f)))); return(lst); }).ToList(); } else if (excludedAttributes != null && excludedAttributes.Any()) { representation.FlatAttributes = queryableAttributes.FilterAttributes(excludedAttributes, false).ToList(); } }
public static JObject ToResponse(this SCIMRepresentation representation, string location, bool isGetRequest = false, bool includeStandardAttributes = true, bool addEmptyArray = false) { var jObj = new JObject { { StandardSCIMRepresentationAttributes.Id, representation.Id } }; if (includeStandardAttributes) { representation.AddStandardAttributes(location, new List <string> { }, ignore: true); } if (addEmptyArray) { representation.ApplyEmptyArray(); } var attributes = representation.HierarchicalAttributes.Select(a => { var schema = representation.GetSchema(a); var order = 1; if (schema != null && schema.IsRootSchema) { order = 0; } return(new EnrichParameter(schema, order, a)); }); EnrichResponse(attributes, jObj, isGetRequest); return(jObj); }
public static JObject ToResponse(this SCIMRepresentation representation, string location, bool isGetRequest = false) { var jObj = new JObject { { SCIMConstants.StandardSCIMRepresentationAttributes.Id, representation.Id }, { SCIMConstants.StandardSCIMRepresentationAttributes.Schemas, new JArray(representation.Schemas.Select(s => s.Id)) } }; EnrichResponse(representation.Attributes.AsQueryable(), jObj, isGetRequest); var metaObj = (JObject)jObj.SelectToken(SCIMConstants.StandardSCIMRepresentationAttributes.Meta); if (metaObj == null) { jObj.Add(SCIMConstants.StandardSCIMRepresentationAttributes.Meta, new JObject { { SCIMConstants.StandardSCIMMetaAttributes.Location, location } }); } else { metaObj.Add(SCIMConstants.StandardSCIMMetaAttributes.Location, location); } return(jObj); }
public static JObject ToResponseWithExcludedAttributes(this SCIMRepresentation representation, ICollection <SCIMExpression> excludedAttributes, string location) { var result = (SCIMRepresentation)representation.Clone(); foreach (var excludedAttribute in excludedAttributes) { var attributes = GetRepresentationAttributeFromPath(result.Attributes.AsQueryable(), excludedAttribute).ToList(); foreach (var attr in attributes) { if (attr.Parent != null) { attr.Parent.Values.Remove(attr); } else { result.Attributes.Remove(attr); } } } var jObj = result.ToResponse(location, true); foreach (var excludedAttribute in excludedAttributes) { var fullPath = (excludedAttribute as SCIMAttributeExpression).GetFullPath(); if (COMMNON_PROPERTY_NAMES.Contains(fullPath)) { jObj.SelectToken(fullPath).Parent.Remove(); } } return(jObj); }
public static JObject ToResponseWithIncludedAttributes(this SCIMRepresentation representation, ICollection <SCIMExpression> includedAttributes) { var result = new JObject(); foreach (var includedAttribute in includedAttributes) { representation.IncludeAttribute(includedAttribute, result); } return(result); }
private static void IncludeAttribute(this SCIMRepresentation scimRepresentation, SCIMExpression scimExpression, JObject result) { var scimAttributeExpression = scimExpression as SCIMAttributeExpression; if (scimAttributeExpression == null) { throw new SCIMAttributeException(Global.InvalidAttributeExpression); } IncludeAttribute(scimAttributeExpression, scimRepresentation.Attributes.AsQueryable(), result); var fullPath = scimAttributeExpression.GetFullPath(); if (!COMMNON_PROPERTY_NAMES.Contains(fullPath)) { return; } if (fullPath == SCIMConstants.StandardSCIMRepresentationAttributes.Id) { result.Add(SCIMConstants.StandardSCIMRepresentationAttributes.Id, scimRepresentation.Id); } else if (fullPath == SCIMConstants.StandardSCIMRepresentationAttributes.ExternalId) { result.Add(SCIMConstants.StandardSCIMRepresentationAttributes.ExternalId, scimRepresentation.ExternalId); } else if (fullPath == $"{SCIMConstants.StandardSCIMRepresentationAttributes.Meta}.{SCIMConstants.StandardSCIMMetaAttributes.ResourceType}") { result.Add(SCIMConstants.StandardSCIMRepresentationAttributes.Meta, new JObject { { SCIMConstants.StandardSCIMMetaAttributes.ResourceType, scimRepresentation.ResourceType } }); } else if (fullPath == $"{SCIMConstants.StandardSCIMRepresentationAttributes.Meta}.{SCIMConstants.StandardSCIMMetaAttributes.Created}") { result.Add(SCIMConstants.StandardSCIMRepresentationAttributes.Meta, new JObject { { SCIMConstants.StandardSCIMMetaAttributes.Created, scimRepresentation.Created } }); } else if (fullPath == $"{SCIMConstants.StandardSCIMRepresentationAttributes.Meta}.{SCIMConstants.StandardSCIMMetaAttributes.LastModified}") { result.Add(SCIMConstants.StandardSCIMRepresentationAttributes.Meta, new JObject { { SCIMConstants.StandardSCIMMetaAttributes.LastModified, scimRepresentation.LastModified } }); } else if (fullPath == $"{SCIMConstants.StandardSCIMRepresentationAttributes.Meta}.{SCIMConstants.StandardSCIMMetaAttributes.Version}") { result.Add(SCIMConstants.StandardSCIMRepresentationAttributes.Meta, new JObject { { SCIMConstants.StandardSCIMMetaAttributes.Version, scimRepresentation.Version } }); } }
private static void IncludeAttribute(this SCIMRepresentation scimRepresentation, SCIMExpression scimExpression, JObject result) { var scimAttributeExpression = scimExpression as SCIMAttributeExpression; if (scimAttributeExpression == null) { throw new SCIMAttributeException("not a valid attribute expression"); } IncludeAttribute(scimAttributeExpression, scimRepresentation.Attributes.AsQueryable(), result); }
public static void ApplyPatches(this SCIMRepresentation representation, ICollection <SCIMPatchOperationRequest> patches) { var queryableRepresentationAttributes = representation.Attributes.AsQueryable(); foreach (var patch in patches) { var attributes = GetRepresentationAttributeFromPath(queryableRepresentationAttributes, SCIMFilterParser.Parse(patch.Path, representation.Schemas)).ToList(); if (!attributes.Any()) { throw new SCIMAttributeException("PATCH can be applied only on existing attributes"); } var removeCallback = new Action <ICollection <SCIMRepresentationAttribute> >((attrs) => { foreach (var a in attrs) { if (a.Parent != null) { a.Parent.Values.Remove(a); } else { representation.Attributes.Remove(a); } } }); if (patch.Operation == SCIMPatchOperations.REMOVE || patch.Operation == SCIMPatchOperations.REPLACE) { removeCallback(attributes); } if (patch.Operation == SCIMPatchOperations.ADD) { removeCallback(attributes.Where(a => !a.SchemaAttribute.MultiValued).ToList()); } if (patch.Operation == SCIMPatchOperations.ADD || patch.Operation == SCIMPatchOperations.REPLACE) { var firstAttribute = attributes.First(); var newAttributes = ExtractRepresentationAttributesFromJSON(firstAttribute.SchemaAttribute, patch.Value); foreach (var newAttribute in newAttributes) { if (firstAttribute.Parent != null) { firstAttribute.Parent.Values.Add(newAttribute); } else { representation.Attributes.Add(newAttribute); } } } } }
private static void CheckDuplicate(IEnumerable <SCIMRepresentationAttribute> existingAttributes, ICollection <SCIMRepresentationAttribute> newFlatAttributes) { var rootAttributes = SCIMRepresentation.BuildHierarchicalAttributes(newFlatAttributes); foreach (var newAttribute in rootAttributes) { if (existingAttributes.Any(a => a.IsSimilar(newAttribute, true))) { throw new SCIMDuplicateAttributeException(string.Format(Global.AttributeMustBeUnique, newAttribute.FullPath)); } } }
public static void ApplyEmptyArray(this SCIMRepresentation representation) { var attrs = representation.Schemas.SelectMany(s => s.Attributes.Where(a => a.MultiValued)); foreach (var attr in attrs) { if (!representation.Attributes.Any(a => a.SchemaAttribute.Name == attr.Name)) { representation.Attributes.Add(new SCIMRepresentationAttribute { SchemaAttribute = attr }); } } }
public static void ApplyEmptyArray(this SCIMRepresentation representation) { foreach (var schema in representation.Schemas) { var attrs = schema.HierarchicalAttributes.Select(a => a.Leaf).Where(a => a.MultiValued); foreach (var attr in attrs) { if (!representation.FlatAttributes.Any(a => a.SchemaAttribute.Name == attr.Name)) { representation.FlatAttributes.Add(new SCIMRepresentationAttribute(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), attr, schema.Id)); } } } }
public static JObject ToResponse(this SCIMRepresentation representation, string location, bool isGetRequest = false) { var meta = new JObject { { SCIMConstants.StandardSCIMMetaAttributes.ResourceType, representation.ResourceType }, { SCIMConstants.StandardSCIMMetaAttributes.Created, representation.Created }, { SCIMConstants.StandardSCIMMetaAttributes.LastModified, representation.LastModified }, { SCIMConstants.StandardSCIMMetaAttributes.Version, representation.Version } }; if (!string.IsNullOrWhiteSpace(location)) { meta.Add(SCIMConstants.StandardSCIMMetaAttributes.Location, location); } var jObj = new JObject { { SCIMConstants.StandardSCIMRepresentationAttributes.Id, representation.Id }, { SCIMConstants.StandardSCIMRepresentationAttributes.Schemas, new JArray(representation.Schemas.Select(s => s.Id)) }, { SCIMConstants.StandardSCIMRepresentationAttributes.Meta, meta } }; if (!string.IsNullOrWhiteSpace(representation.ExternalId)) { jObj.Add(SCIMConstants.StandardSCIMRepresentationAttributes.ExternalId, representation.ExternalId); } var attributes = representation.Attributes.Select(a => { var schema = representation.GetSchema(a); int order = 1; if (schema != null && schema.IsRootSchema) { order = 0; } return(new EnrichParameter(schema, order, a)); }); EnrichResponse(attributes, jObj, isGetRequest); return(jObj); }
private static void IncludeAttribute(SCIMRepresentation scimRepresentation, SCIMAttributeExpression scimExpression, IQueryable <SCIMRepresentationAttribute> attributes, JObject result) { var filteredAttributes = GetAttributes(scimExpression, attributes); if (!filteredAttributes.Any()) { return; } if (scimExpression.Child != null) { foreach (var kvp in filteredAttributes.GroupBy(f => f.SchemaAttribute.Name)) { var representationAttr = kvp.First(); if (representationAttr.SchemaAttribute.MultiValued == false) { var jObjVal = new JObject(); IncludeAttribute(scimRepresentation, scimExpression.Child, representationAttr.Values.AsQueryable(), jObjVal); result.Add(representationAttr.SchemaAttribute.Name, jObjVal); } else { var jArr = new JArray(); foreach (var attr in kvp) { var jObjVal = new JObject(); IncludeAttribute(scimRepresentation, scimExpression.Child, attr.Values.AsQueryable(), jObjVal); jArr.Add(jObjVal); } result.Add(representationAttr.SchemaAttribute.Name, jArr); } } return; } var enrichParameters = filteredAttributes.Select(at => new EnrichParameter(scimRepresentation.GetSchema(at), 0, at)); EnrichResponse(enrichParameters, result); }
public static JObject ToResponseWithExcludedAttributes(this SCIMRepresentation representation, ICollection <SCIMExpression> excludedAttributes, string location) { var result = (SCIMRepresentation)representation.Clone(); foreach (var excludedAttribute in excludedAttributes) { var attributes = GetRepresentationAttributeFromPath(result.Attributes.AsQueryable(), excludedAttribute).ToList(); foreach (var attr in attributes) { if (attr.Parent != null) { attr.Parent.Values.Remove(attr); } else { result.Attributes.Remove(attr); } } } return(result.ToResponse(location, true)); }
public static List <SCIMPatchResult> ApplyPatches(this SCIMRepresentation representation, ICollection <PatchOperationParameter> patches, bool ignoreUnsupportedCanonicalValues) { var result = new List <SCIMPatchResult>(); foreach (var patch in patches) { var scimFilter = SCIMFilterParser.Parse(patch.Path, representation.Schemas); var schemaAttributes = representation.Schemas.SelectMany(_ => _.Attributes); List <SCIMRepresentationAttribute> attributes = null; string fullPath = null; if (scimFilter != null) { var scimAttributeExpression = scimFilter as SCIMAttributeExpression; if (scimAttributeExpression == null) { throw new SCIMAttributeException(Global.InvalidAttributeExpression); } fullPath = scimAttributeExpression.GetFullPath(); schemaAttributes = representation.Schemas .Select(s => s.GetAttribute(fullPath)) .Where(s => s != null); attributes = scimAttributeExpression.EvaluateAttributes(representation.HierarchicalAttributes.AsQueryable(), true).ToList(); } else { attributes = representation.FlatAttributes.Where(h => h.IsLeaf()).ToList(); } var removeCallback = new Action <ICollection <SCIMRepresentationAttribute> >((attrs) => { foreach (var a in attrs) { var removedAttrs = representation.RemoveAttributeById(a); foreach (var removedAttr in removedAttrs) { result.Add(new SCIMPatchResult { Attr = removedAttr, Operation = SCIMPatchOperations.REMOVE, Path = removedAttr.FullPath }); } } }); switch (patch.Operation) { case SCIMPatchOperations.ADD: try { if (schemaAttributes == null || !schemaAttributes.Any()) { throw new SCIMNoTargetException(string.Format(Global.AttributeIsNotRecognirzed, patch.Path)); } var newAttributes = ExtractRepresentationAttributesFromJSON(representation.Schemas, schemaAttributes.ToList(), patch.Value, ignoreUnsupportedCanonicalValues); CheckDuplicate(attributes, newAttributes); removeCallback(attributes.Where(a => !a.SchemaAttribute.MultiValued && a.FullPath == fullPath).ToList()); var isAttributeExits = !string.IsNullOrWhiteSpace(fullPath) && attributes.Any(a => a.FullPath == fullPath); foreach (var newAttribute in newAttributes.OrderBy(a => a.GetLevel())) { var path = newAttribute.FullPath; var schemaAttr = newAttribute.SchemaAttribute; IEnumerable <SCIMRepresentationAttribute> parentAttributes = null; if (fullPath == path) { var attr = attributes.FirstOrDefault(a => a.FullPath == fullPath); if (attr != null) { var parent = representation.GetParentAttribute(attr); if (parent != null) { parentAttributes = new[] { parent }; } } else { parentAttributes = representation.GetParentAttributesByPath(fullPath).ToList(); } } if (schemaAttr.MultiValued && schemaAttr.Type != SCIMSchemaAttributeTypes.COMPLEX) { var filteredAttribute = attributes.FirstOrDefault(_ => _.FullPath == path); if (filteredAttribute != null) { newAttribute.AttributeId = filteredAttribute.AttributeId; } representation.AddAttribute(newAttribute); } else if (parentAttributes != null && parentAttributes.Any()) { foreach (var parentAttribute in parentAttributes) { representation.AddAttribute(parentAttribute, newAttribute); } } else { representation.FlatAttributes.Add(newAttribute); } attributes.Add(newAttribute); result.Add(new SCIMPatchResult { Attr = newAttribute, Operation = SCIMPatchOperations.ADD, Path = fullPath }); } if (TryGetExternalId(patch, out string externalId)) { representation.ExternalId = externalId; } } catch (SCIMSchemaViolatedException) { continue; } break; case SCIMPatchOperations.REMOVE: { if (scimFilter == null) { throw new SCIMNoTargetException(string.Format(Global.InvalidPath, patch.Path)); } if (SCIMFilterParser.DontContainsFilter(patch.Path) && patch.Value != null) { var excludedAttributes = ExtractRepresentationAttributesFromJSON(representation.Schemas, schemaAttributes.ToList(), patch.Value, ignoreUnsupportedCanonicalValues); excludedAttributes = SCIMRepresentation.BuildHierarchicalAttributes(excludedAttributes); attributes = attributes.Where(a => excludedAttributes.Any(ea => ea.IsSimilar(a, true))).ToList(); } removeCallback(attributes); } break; case SCIMPatchOperations.REPLACE: { if (TryGetExternalId(patch, out string externalId)) { representation.ExternalId = externalId; continue; } if (schemaAttributes == null || !schemaAttributes.Any()) { throw new SCIMNoTargetException(string.Format(Global.AttributeIsNotRecognirzed, patch.Path)); } var complexAttr = scimFilter as SCIMComplexAttributeExpression; if (complexAttr != null && !attributes.Any() && complexAttr.GroupingFilter != null) { throw new SCIMNoTargetException(Global.PatchMissingAttribute); } try { List <SCIMRepresentationAttribute> parents = new List <SCIMRepresentationAttribute>(); if (complexAttr != null) { var attr = attributes.First(a => a.FullPath == fullPath); var parent = string.IsNullOrWhiteSpace(attr.ParentAttributeId) ? attr : representation.GetParentAttribute(attributes.First(a => a.FullPath == fullPath)); if (parent != null) { parents = new List <SCIMRepresentationAttribute> { parent }; } } else { parents = representation.GetParentAttributesByPath(fullPath).ToList(); } if (scimFilter != null && parents.Any()) { foreach (var parent in parents) { var flatHiearchy = representation.GetFlatHierarchicalChildren(parent).ToList(); var scimAttributeExpression = scimFilter as SCIMAttributeExpression; var newAttributes = ExtractRepresentationAttributesFromJSON(representation.Schemas, schemaAttributes.ToList(), patch.Value, ignoreUnsupportedCanonicalValues); foreach (var newAttribute in newAttributes.OrderBy(l => l.GetLevel())) { if (!flatHiearchy.Any(a => a.FullPath == newAttribute.FullPath)) { var parentPath = SCIMRepresentation.GetParentPath(newAttribute.FullPath); var p = flatHiearchy.FirstOrDefault(a => a.FullPath == parentPath); if (p != null) { representation.AddAttribute(p, newAttribute); } else { representation.AddAttribute(newAttribute); } result.Add(new SCIMPatchResult { Attr = newAttribute, Operation = SCIMPatchOperations.ADD, Path = fullPath }); } } result.AddRange(Merge(flatHiearchy, newAttributes, fullPath)); } } else { var newAttributes = ExtractRepresentationAttributesFromJSON(representation.Schemas, schemaAttributes.ToList(), patch.Value, ignoreUnsupportedCanonicalValues); var flatHiearchy = representation.FlatAttributes.ToList(); var missingAttributes = newAttributes.Where(na => string.IsNullOrEmpty(na.ParentAttributeId) && !flatHiearchy.Any(fh => string.IsNullOrWhiteSpace(fh.ParentAttributeId) && fh.SchemaAttributeId == na.SchemaAttributeId)).ToList(); missingAttributes.ForEach((ma) => { representation.AddAttribute(ma); result.Add(new SCIMPatchResult { Attr = ma, Operation = SCIMPatchOperations.ADD, Path = ma.FullPath }); }); result.AddRange(Merge(flatHiearchy, newAttributes, fullPath)); } } catch (SCIMSchemaViolatedException) { continue; } } break; } } var displayNameAttr = representation.FlatAttributes.FirstOrDefault(a => a.FullPath == "displayName"); if (displayNameAttr != null) { representation.SetDisplayName(displayNameAttr.ValueString); } return(result); }
public static void ApplyPatches(this SCIMRepresentation representation, ICollection <PatchOperationParameter> patches, bool ignoreUnsupportedCanonicalValues) { var queryableRepresentationAttributes = representation.Attributes.AsQueryable(); foreach (var patch in patches) { var scimFilter = SCIMFilterParser.Parse(patch.Path, representation.Schemas); var attributeExpression = scimFilter as SCIMAttributeExpression; var schemaAttributes = representation.Schemas.SelectMany(_ => _.Attributes); List <SCIMRepresentationAttribute> attributes = null; string fullPath = null; if (attributeExpression != null) { fullPath = attributeExpression.GetFullPath(); schemaAttributes = representation.Schemas .Select(s => s.GetAttribute(fullPath)) .Where(s => s != null); attributes = GetRepresentationAttributeFromPath(queryableRepresentationAttributes, scimFilter).ToList(); } else { attributes = queryableRepresentationAttributes.ToList(); } var removeCallback = new Func <ICollection <SCIMRepresentationAttribute>, List <SCIMRepresentationAttribute> >((attrs) => { var result = new List <SCIMRepresentationAttribute>(); foreach (var a in attrs) { if (a.Parent != null) { a.Parent.Values.Remove(a); result.Add(a.Parent); } else { representation.Attributes.Remove(a); } } return(result); }); switch (patch.Operation) { case SCIMPatchOperations.ADD: try { // If the target location already contains the value then do nothing ... if (schemaAttributes == null || !schemaAttributes.Any()) { throw new SCIMNoTargetException(string.Format(Global.AttributeIsNotRecognirzed, patch.Path)); } var newAttributes = ExtractRepresentationAttributesFromJSON(representation.Schemas, schemaAttributes.ToList(), patch.Value, ignoreUnsupportedCanonicalValues); var parentAttrs = removeCallback(attributes.Where(a => !a.SchemaAttribute.MultiValued && newAttributes.Any(_ => _.SchemaAttribute.Name == a.SchemaAttribute.Name)).ToList()); foreach (var newAttribute in newAttributes.Where(x => x.HasValue)) { var path = string.IsNullOrWhiteSpace(fullPath) ? newAttribute.SchemaAttribute.Name : fullPath; var schemaAttr = newAttribute.SchemaAttribute; var parentAttribute = representation.GetParentAttribute(path); if (schemaAttr.MultiValued && schemaAttr.Type != SCIMSchemaAttributeTypes.COMPLEX) { var filteredAttributes = attributes.Where(_ => _.GetFullPath() == path); foreach (var attribute in filteredAttributes) { if (schemaAttr.Type == SCIMSchemaAttributeTypes.BOOLEAN) { foreach (var b in newAttribute.ValuesBoolean) { attribute.ValuesBoolean.Add(b); } } else if (schemaAttr.Type == SCIMSchemaAttributeTypes.DATETIME) { foreach (var d in newAttribute.ValuesDateTime) { attribute.ValuesDateTime.Add(d); } } else if (schemaAttr.Type == SCIMSchemaAttributeTypes.INTEGER) { foreach (var i in newAttribute.ValuesInteger) { attribute.ValuesInteger.Add(i); } } else if (schemaAttr.Type == SCIMSchemaAttributeTypes.REFERENCE) { foreach (var r in newAttribute.ValuesReference) { attribute.ValuesReference.Add(r); } } else if (schemaAttr.Type == SCIMSchemaAttributeTypes.STRING) { foreach (var s in newAttribute.ValuesString) { attribute.ValuesString.Add(s); } } else if (schemaAttr.Type == SCIMSchemaAttributeTypes.DECIMAL) { foreach (var d in newAttribute.ValuesDecimal) { attribute.ValuesDecimal.Add(d); } } else if (schemaAttr.Type == SCIMSchemaAttributeTypes.BINARY) { foreach (var b in newAttribute.ValuesBinary) { attribute.ValuesBinary.Add(b); } } } } else if (parentAttribute != null) { if (parentAttrs.Any()) { foreach (var parentAttr in parentAttrs) { parentAttr.Add(newAttribute); } } else { parentAttribute.Add(newAttribute); } } else { if (!representation.ContainsAttribute(newAttribute)) { representation.Attributes.Add(newAttribute); } } } } catch (SCIMSchemaViolatedException) { continue; } break; case SCIMPatchOperations.REMOVE: { if (attributeExpression == null) { throw new SCIMNoTargetException(string.Format(Global.InvalidPath, patch.Path)); } removeCallback(attributes); } break; case SCIMPatchOperations.REPLACE: { if (schemaAttributes == null || !schemaAttributes.Any()) { throw new SCIMNoTargetException(string.Format(Global.AttributeIsNotRecognirzed, patch.Path)); } var complexAttr = attributeExpression as SCIMComplexAttributeExpression; if (complexAttr != null && !attributes.Any() && complexAttr.GroupingFilter != null) { throw new SCIMNoTargetException(Global.PatchMissingAttribute); } try { var newAttributes = ExtractRepresentationAttributesFromJSON(representation.Schemas, schemaAttributes.ToList(), patch.Value, ignoreUnsupportedCanonicalValues); var parentFullPath = attributes.First().Parent?.GetFullPath(); if (!string.IsNullOrWhiteSpace(parentFullPath)) { scimFilter = SCIMFilterParser.Parse(parentFullPath, representation.Schemas); var allAttrs = GetRepresentationAttributeFromPath(queryableRepresentationAttributes, scimFilter); foreach (var attr in allAttrs) { if (!attr.Values.Any(_ => attributes.Any(a => a.SchemaAttribute.Name == _.SchemaAttribute.Name))) { attr.Add(attributes.First()); } } } Merge(attributes, newAttributes); } catch (SCIMSchemaViolatedException) { continue; } } break; } } }
public static void ApplyPatches(this SCIMRepresentation representation, ICollection <PatchOperationParameter> patches, bool ignoreUnsupportedCanonicalValues) { var queryableRepresentationAttributes = representation.Attributes.AsQueryable(); foreach (var patch in patches) { var scimFilter = SCIMFilterParser.Parse(patch.Path, representation.Schemas); var attributeExpression = scimFilter as SCIMAttributeExpression; if (attributeExpression == null) { throw new SCIMAttributeException(string.Format(Global.InvalidPath, patch.Path)); } var fullPath = attributeExpression.GetFullPath(); var schemaAttributes = representation.Schemas.Select(s => s.GetAttribute(fullPath)).Where(s => s != null); if (!schemaAttributes.Any()) { throw new SCIMAttributeException(string.Format(Global.UnknownPath, patch.Path)); } var schemaAttribute = schemaAttributes.First(); var attributes = GetRepresentationAttributeFromPath(queryableRepresentationAttributes, scimFilter).ToList(); if (!attributes.Any() && schemaAttribute.Type != SCIMSchemaAttributeTypes.COMPLEX && !schemaAttribute.MultiValued) { throw new SCIMAttributeException(Global.PatchMissingAttribute); } var removeCallback = new Action <ICollection <SCIMRepresentationAttribute> >((attrs) => { foreach (var a in attrs) { if (a.Parent != null) { a.Parent.Values.Remove(a); } else { representation.Attributes.Remove(a); } } }); if (patch.Operation == SCIMPatchOperations.REMOVE || patch.Operation == SCIMPatchOperations.REPLACE) { removeCallback(attributes); } if (patch.Operation == SCIMPatchOperations.ADD) { removeCallback(attributes.Where(a => !a.SchemaAttribute.MultiValued).ToList()); } if (patch.Operation == SCIMPatchOperations.ADD || patch.Operation == SCIMPatchOperations.REPLACE) { var newAttributes = ExtractRepresentationAttributesFromJSON(schemaAttribute, patch.Value, ignoreUnsupportedCanonicalValues); foreach (var newAttribute in newAttributes) { var parentAttribute = representation.GetParentAttribute(fullPath); var attribute = representation.GetAttribute(fullPath); if (schemaAttribute.Type == SCIMSchemaAttributeTypes.COMPLEX && parentAttribute != null) { parentAttribute.Values.Add(newAttribute); continue; } if (attribute != null && schemaAttribute.Type != SCIMSchemaAttributeTypes.COMPLEX) { if (schemaAttribute.Type == SCIMSchemaAttributeTypes.BOOLEAN) { foreach (var b in newAttribute.ValuesBoolean) { attribute.ValuesBoolean.Add(b); } } else if (schemaAttribute.Type == SCIMSchemaAttributeTypes.DATETIME) { foreach (var d in newAttribute.ValuesDateTime) { attribute.ValuesDateTime.Add(d); } } else if (schemaAttribute.Type == SCIMSchemaAttributeTypes.INTEGER) { foreach (var i in newAttribute.ValuesInteger) { attribute.ValuesInteger.Add(i); } } else if (schemaAttribute.Type == SCIMSchemaAttributeTypes.REFERENCE) { foreach (var r in newAttribute.ValuesReference) { attribute.ValuesReference.Add(r); } } else if (schemaAttribute.Type == SCIMSchemaAttributeTypes.STRING) { foreach (var s in newAttribute.ValuesString) { attribute.ValuesString.Add(s); } } else if (schemaAttribute.Type == SCIMSchemaAttributeTypes.DECIMAL) { foreach (var d in newAttribute.ValuesDecimal) { attribute.ValuesDecimal.Add(d); } } else if (schemaAttribute.Type == SCIMSchemaAttributeTypes.BINARY) { foreach (var b in newAttribute.ValuesBinary) { attribute.ValuesBinary.Add(b); } } } else { representation.Attributes.Add(newAttribute); } } } } }