private IQueryable <SCIMRepresentation> ParseAndExecuteFilter(IQueryable <SCIMRepresentation> representations, string filter)
        {
            var parsed = SCIMFilterParser.Parse(filter, new List <SCIMSchema> {
                SCIMConstants.StandardSchemas.UserSchema, SCIMConstants.StandardSchemas.CommonSchema
            });
            var evaluatedExpression = parsed.Evaluate(representations);

            return((IQueryable <SCIMRepresentation>)evaluatedExpression.Compile().DynamicInvoke(representations));
        }
Exemple #2
0
        private IOrderedEnumerable <SCIMRepresentation> ParseAndExecutOrderBy(IQueryable <SCIMRepresentation> representations, string filter, SearchSCIMRepresentationOrders order)
        {
            var parsed = SCIMFilterParser.Parse(filter, new List <SCIMSchema> {
                StandardSchemas.UserSchema, CustomSchema
            });
            var evaluatedExpression = parsed.EvaluateOrderBy(representations, order);

            return((IOrderedEnumerable <SCIMRepresentation>)evaluatedExpression.Compile().DynamicInvoke(representations));
        }
Exemple #3
0
        private IQueryable <SCIMRepresentation> ParseAndExecuteFilter(IQueryable <SCIMRepresentation> representations, string filter)
        {
            var p = SCIMFilterParser.Parse("members[(value eq \"06259893-b0ae-4f76-bb1f-fe684843cfbd\" or value eq \"7a2148ba-9427-4d5d-8ae2-8aa4c4a14ce3\") or value eq \"7a2148ba-9427-4d5d-8ae2-8aa4c4a14ce3\"]", new List <SCIMSchema> {
                SCIMConstants.StandardSchemas.UserSchema
            });

            var parsed = SCIMFilterParser.Parse(filter, new List <SCIMSchema> {
                SCIMConstants.StandardSchemas.UserSchema
            });
            var evaluatedExpression = parsed.Evaluate(representations);

            return((IQueryable <SCIMRepresentation>)evaluatedExpression.Compile().DynamicInvoke(representations));
        }
Exemple #4
0
        public void When_Extract_Attributes()
        {
            var userSchema = SCIMSchemaBuilder.Create("urn:ietf:params:scim:schemas:core:2.0:User", "User", "User Account")
                             .AddStringAttribute("userName", caseExact: true, uniqueness: SCIMSchemaAttributeUniqueness.SERVER)
                             .AddComplexAttribute("phones", opt =>
            {
                opt.AddStringAttribute("phoneNumber", description: "Phone number");
                opt.AddStringAttribute("type", description: "Type");
            }, multiValued: true, mutability: SCIMSchemaAttributeMutabilities.READWRITE)
                             .Build();
            var userRepresentation = SCIMRepresentationBuilder.Create(new List <SCIMSchema> {
                userSchema
            })
                                     .AddStringAttribute("userName", "urn:ietf:params:scim:schemas:core:2.0:User", new List <string> {
                "john"
            })
                                     .AddComplexAttribute("phones", "urn:ietf:params:scim:schemas:core:2.0:User", (b) =>
            {
                b.AddStringAttribute("phoneNumber", new List <string> {
                    "01"
                });
                b.AddStringAttribute("type", new List <string> {
                    "mobile"
                });
            })
                                     .AddComplexAttribute("phones", "urn:ietf:params:scim:schemas:core:2.0:User", (b) =>
            {
                b.AddStringAttribute("phoneNumber", new List <string> {
                    "02"
                });
                b.AddStringAttribute("type", new List <string> {
                    "home"
                });
            })
                                     .Build();

            var firstFilter = SCIMFilterParser.Parse("phones.phoneNumber", new List <SCIMSchema> {
                userSchema
            });
            var secondFilter = SCIMFilterParser.Parse("phones[phoneNumber eq 02]", new List <SCIMSchema> {
                userSchema
            });
            var thirdFilter = SCIMFilterParser.Parse("userName", new List <SCIMSchema> {
                userSchema
            });
            var fourthFilter = SCIMFilterParser.Parse("phones.phoneNumber", new List <SCIMSchema> {
                userSchema
            });
            var fifthFilter = SCIMFilterParser.Parse("phones[phoneNumber eq 02]", new List <SCIMSchema> {
                userSchema
            });
            var sixFilter = SCIMFilterParser.Parse("meta.lastModified", new List <SCIMSchema> {
                userSchema
            });
            var sevenFilter = SCIMFilterParser.Parse("meta.lastModified", new List <SCIMSchema> {
                userSchema
            });
            var eightFilter = SCIMFilterParser.Parse("id", new List <SCIMSchema> {
                userSchema
            });
            var nineFilter = SCIMFilterParser.Parse("id", new List <SCIMSchema> {
                userSchema
            });

            var firstJSON = userRepresentation.ToResponseWithIncludedAttributes(new List <SCIMExpression> {
                firstFilter
            });
            var secondJSON = userRepresentation.ToResponseWithIncludedAttributes(new List <SCIMExpression> {
                secondFilter
            });
            var thirdJSON = userRepresentation.ToResponseWithExcludedAttributes(new List <SCIMExpression> {
                thirdFilter
            }, "http://localhost");
            var fourthJSON = userRepresentation.ToResponseWithExcludedAttributes(new List <SCIMExpression> {
                fourthFilter
            }, "http://localhost");
            var fifthJSON = userRepresentation.ToResponseWithExcludedAttributes(new List <SCIMExpression> {
                fifthFilter
            }, "http://localhost");
            var sixJSON = userRepresentation.ToResponseWithIncludedAttributes(new List <SCIMExpression> {
                sixFilter
            });
            var sevenJSON = userRepresentation.ToResponseWithExcludedAttributes(new List <SCIMExpression> {
                sevenFilter
            }, "http://localhost");
            var eightJSON = userRepresentation.ToResponseWithExcludedAttributes(new List <SCIMExpression> {
                eightFilter
            }, "http://localhost");
            var nineJSON = userRepresentation.ToResponseWithIncludedAttributes(new List <SCIMExpression> {
                nineFilter
            });

            Assert.Equal("01", firstJSON.SelectToken("phones[0].phoneNumber").ToString());
            Assert.Equal("02", secondJSON.SelectToken("phones[0].phoneNumber").ToString());
            Assert.Equal("home", secondJSON.SelectToken("phones[0].type").ToString());
            Assert.Null(thirdJSON.SelectToken("userName"));
            Assert.Null(fourthJSON.SelectToken("phones[0].phoneNumber"));
            Assert.True((fifthJSON.SelectToken("phones") as JArray).Count == 1);
            Assert.NotNull(sixJSON.SelectToken("meta.lastModified"));
            Assert.Null(sevenJSON.SelectToken("meta.lastModified"));
            Assert.NotNull(eightJSON.SelectToken("id"));
            Assert.NotNull(nineJSON.SelectToken("id"));
        }
Exemple #5
0
        private async Task <IActionResult> InternalSearch(SearchSCIMResourceParameter searchRequest)
        {
            _logger.LogInformation(Global.StartGetResources);
            try
            {
                if (searchRequest.Count > _options.MaxResults)
                {
                    searchRequest.Count = _options.MaxResults;
                }

                var schema = await _scimSchemaQueryRepository.FindRootSCIMSchemaByResourceType(_resourceType);

                var schemaIds = new List <string> {
                    schema.Id
                };
                schemaIds.AddRange(schema.SchemaExtensions.Select(s => s.Schema));
                var schemas = (await _scimSchemaQueryRepository.FindSCIMSchemaByIdentifiers(schemaIds)).ToList();
                var result  = await _scimRepresentationQueryRepository.FindSCIMRepresentations(new SearchSCIMRepresentationsParameter(_resourceType, searchRequest.StartIndex - 1, searchRequest.Count, searchRequest.SortBy, searchRequest.SortOrder, SCIMFilterParser.Parse(searchRequest.Filter, schemas)));

                var jObj = new JObject
                {
                    { SCIMConstants.StandardSCIMRepresentationAttributes.Schemas, new JArray(new [] { SCIMConstants.StandardSchemas.ListResponseSchemas.Id }) },
                    { SCIMConstants.StandardSCIMRepresentationAttributes.TotalResults, result.TotalResults },
                    { SCIMConstants.StandardSCIMRepresentationAttributes.ItemsPerPage, searchRequest.Count },
                    { SCIMConstants.StandardSCIMRepresentationAttributes.StartIndex, searchRequest.StartIndex }
                };
                var resources       = new JArray();
                var baseUrl         = Request.GetAbsoluteUriWithVirtualPath();
                var representations = result.Content.ToList();
                await _attributeReferenceEnricher.Enrich(_resourceType, representations, baseUrl);

                foreach (var record in representations)
                {
                    JObject newJObj  = null;
                    var     location = $"{baseUrl}/{_resourceType}/{record.Id}";
                    if (searchRequest.Attributes.Any())
                    {
                        newJObj = record.ToResponseWithIncludedAttributes(searchRequest.Attributes.Select(a => SCIMFilterParser.Parse(a, schemas)).ToList());
                    }
                    else if (searchRequest.ExcludedAttributes.Any())
                    {
                        newJObj = record.ToResponseWithExcludedAttributes(searchRequest.ExcludedAttributes.Select(a => SCIMFilterParser.Parse(a, schemas)).ToList(), location);
                    }
                    else
                    {
                        newJObj = record.ToResponse(location, true);
                    }

                    resources.Add(newJObj);
                }

                jObj.Add(SCIMConstants.StandardSCIMRepresentationAttributes.Resources, resources);
                return(new ContentResult
                {
                    StatusCode = (int)HttpStatusCode.OK,
                    Content = jObj.ToString(),
                    ContentType = SCIMConstants.STANDARD_SCIM_CONTENT_TYPE
                });
            }
            catch (SCIMFilterException ex)
            {
                _logger.LogError(ex, ex.Message);
                return(this.BuildError(HttpStatusCode.BadRequest, ex.Message, SCIMConstants.ErrorSCIMTypes.InvalidFilter));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
                return(this.BuildError(HttpStatusCode.InternalServerError, ex.ToString(), SCIMConstants.ErrorSCIMTypes.InternalServerError));
            }
        }
        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);
                        }
                    }
                }
            }
        }
        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);
        }
Exemple #8
0
        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);
                        }
                    }
                }
            }
        }
        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;
                }
            }
        }
Exemple #10
0
        public async Task <IActionResult> Get()
        {
            var searchRequest = SearchSCIMResourceParameter.Create(Request.Query);

            try
            {
                if (searchRequest.Count > _options.MaxResults)
                {
                    searchRequest.Count = _options.MaxResults;
                }

                var result = await _scimRepresentationQueryRepository.FindSCIMRepresentations(new SearchSCIMRepresentationsParameter(_scimEndpoint, searchRequest.StartIndex, searchRequest.Count, searchRequest.SortBy, searchRequest.SortOrder, SCIMFilterParser.Parse(searchRequest.Filter, _schemas)));

                var jObj = new JObject
                {
                    { SCIMConstants.StandardSCIMRepresentationAttributes.Schemas, new JArray(new [] { SCIMConstants.StandardSchemas.ListResponseSchemas.Id }) },
                    { SCIMConstants.StandardSCIMRepresentationAttributes.TotalResults, result.TotalResults },
                    { SCIMConstants.StandardSCIMRepresentationAttributes.ItemsPerPage, searchRequest.Count },
                    { SCIMConstants.StandardSCIMRepresentationAttributes.StartIndex, searchRequest.StartIndex }
                };
                var resources = new JArray();
                foreach (var record in result.Content)
                {
                    JObject newJObj  = null;
                    var     location = $"{Request.GetAbsoluteUriWithVirtualPath()}/{_scimEndpoint}/{record.Id}";
                    if (searchRequest.Attributes.Any())
                    {
                        newJObj = record.ToResponseWithIncludedAttributes(searchRequest.Attributes.Select(a => SCIMFilterParser.Parse(a, _schemas)).ToList());
                    }
                    else if (searchRequest.ExcludedAttributes.Any())
                    {
                        newJObj = record.ToResponseWithExcludedAttributes(searchRequest.ExcludedAttributes.Select(a => SCIMFilterParser.Parse(a, _schemas)).ToList(), location);
                    }
                    else
                    {
                        newJObj = record.ToResponse(location, true);
                    }

                    resources.Add(newJObj);
                }

                jObj.Add(SCIMConstants.StandardSCIMRepresentationAttributes.Resources, resources);
                return(new ContentResult
                {
                    StatusCode = (int)HttpStatusCode.OK,
                    Content = jObj.ToString(),
                    ContentType = SCIMConstants.STANDARD_SCIM_CONTENT_TYPE
                });
            }
            catch (SCIMFilterException ex)
            {
                return(this.BuildError(HttpStatusCode.BadRequest, ex.Message, "invalidFilter"));
            }
        }
        protected async Task <IActionResult> InternalSearch(SearchSCIMResourceParameter searchRequest, string resourceType)
        {
            try
            {
                var schema = await _scimSchemaQueryRepository.FindRootSCIMSchemaByResourceType(resourceType);

                var schemaIds = new List <string> {
                    schema.Id
                };
                schemaIds.AddRange(schema.SchemaExtensions.Select(s => s.Schema));
                var schemas = (await _scimSchemaQueryRepository.FindSCIMSchemaByIdentifiers(schemaIds)).ToList();
                if (searchRequest.StartIndex <= 0)
                {
                    return(this.BuildError(HttpStatusCode.BadRequest, Global.StartIndexMustBeSuperiorOrEqualTo1));
                }

                var sortByFilter    = SCIMFilterParser.Parse(searchRequest.SortBy, schemas);
                var standardSchemas = new List <SCIMSchema>
                {
                    StandardSchemas.StandardResponseSchemas
                };
                standardSchemas.AddRange(schemas);
                var includedAttributes = searchRequest.Attributes == null ? new List <SCIMAttributeExpression>() : searchRequest.Attributes.Select(a => SCIMFilterParser.Parse(a, standardSchemas)).Cast <SCIMAttributeExpression>().ToList();
                var excludedAttributes = searchRequest.ExcludedAttributes == null ? new List <SCIMAttributeExpression>() : searchRequest.ExcludedAttributes.Select(a => SCIMFilterParser.Parse(a, standardSchemas)).Cast <SCIMAttributeExpression>().ToList();
                var result             = await _scimRepresentationQueryRepository.FindSCIMRepresentations(new SearchSCIMRepresentationsParameter(resourceType, searchRequest.StartIndex, searchRequest.Count.Value, sortByFilter, searchRequest.SortOrder, SCIMFilterParser.Parse(searchRequest.Filter, schemas), includedAttributes, excludedAttributes));

                var jObj = new JObject
                {
                    { StandardSCIMRepresentationAttributes.Schemas, new JArray(new [] { StandardSchemas.ListResponseSchemas.Id }) },
                    { StandardSCIMRepresentationAttributes.TotalResults, result.TotalResults },
                    { StandardSCIMRepresentationAttributes.ItemsPerPage, searchRequest.Count },
                    { StandardSCIMRepresentationAttributes.StartIndex, searchRequest.StartIndex }
                };
                var resources       = new JArray();
                var baseUrl         = Request.GetAbsoluteUriWithVirtualPath();
                var representations = result.Content.ToList();
                foreach (var representation in representations)
                {
                    representation.Schemas = schemas;
                }

                await _attributeReferenceEnricher.Enrich(resourceType, representations, baseUrl);

                foreach (var record in representations)
                {
                    JObject newJObj  = null;
                    var     location = $"{baseUrl}/{_resourceTypeResolver.ResolveByResourceType(resourceType).ControllerName}/{record.Id}";
                    bool    includeStandardRequest = true;
                    if (searchRequest.Attributes.Any())
                    {
                        record.AddStandardAttributes(location, searchRequest.Attributes, true, false);
                        includeStandardRequest = false;
                    }
                    else if (searchRequest.ExcludedAttributes.Any())
                    {
                        record.AddStandardAttributes(location, searchRequest.ExcludedAttributes, false, false);
                        includeStandardRequest = false;
                    }
                    else
                    {
                        record.ApplyEmptyArray();
                    }

                    newJObj = record.ToResponse(location, true, includeStandardRequest);
                    resources.Add(newJObj);
                }

                jObj.Add(StandardSCIMRepresentationAttributes.Resources, resources);
                return(new ContentResult
                {
                    StatusCode = (int)HttpStatusCode.OK,
                    Content = jObj.ToString(),
                    ContentType = SCIMConstants.STANDARD_SCIM_CONTENT_TYPE
                });
            }
            catch (SCIMFilterException ex)
            {
                return(this.BuildError(HttpStatusCode.BadRequest, ex.Message, SCIMConstants.ErrorSCIMTypes.InvalidFilter));
            }
            catch (Exception ex)
            {
                return(this.BuildError(HttpStatusCode.InternalServerError, ex.ToString(), SCIMConstants.ErrorSCIMTypes.InternalServerError));
            }
        }
        public void When_Parse_Filters()
        {
            var firstFilter = SCIMFilterParser.Parse("members[display eq \"Babs Jensen\" and value co \"2819\"]");

            Assert.NotNull(firstFilter);
        }