public async Task <SCIMRepresentation> Handle(AddRepresentationCommand addRepresentationCommand) { var requestedSchemas = addRepresentationCommand.Representation.Schemas; if (!requestedSchemas.Any()) { throw new SCIMBadSyntaxException(string.Format(Global.AttributeMissing, SCIMConstants.StandardSCIMRepresentationAttributes.Schemas)); } var schema = await _scimSchemaQueryRepository.FindRootSCIMSchemaByResourceType(addRepresentationCommand.ResourceType); var allSchemas = new List <string> { schema.Id }; var requiredSchemas = new List <string> { schema.Id }; allSchemas.AddRange(schema.SchemaExtensions.Select(s => s.Schema)); requiredSchemas.AddRange(schema.SchemaExtensions.Where(s => s.Required).Select(s => s.Schema)); var missingRequiredSchemas = requiredSchemas.Where(s => !requestedSchemas.Contains(s)); if (missingRequiredSchemas.Any()) { throw new SCIMBadSyntaxException(string.Format(Global.RequiredSchemasAreMissing, string.Join(",", missingRequiredSchemas))); } var unsupportedSchemas = requestedSchemas.Where(s => !allSchemas.Contains(s)); if (unsupportedSchemas.Any()) { throw new SCIMBadSyntaxException(string.Format(Global.SchemasAreUnknown, string.Join(",", unsupportedSchemas))); } var schemas = await _scimSchemaQueryRepository.FindSCIMSchemaByIdentifiers(requestedSchemas); var version = Guid.NewGuid().ToString(); var scimRepresentation = _scimRepresentationHelper.ExtractSCIMRepresentationFromJSON(addRepresentationCommand.Representation.Attributes, addRepresentationCommand.Representation.ExternalId, schema, schemas.Where(s => s.Id != schema.Id).ToList()); scimRepresentation.Id = Guid.NewGuid().ToString(); scimRepresentation.SetCreated(DateTime.UtcNow); scimRepresentation.SetUpdated(DateTime.UtcNow); scimRepresentation.SetVersion(version); scimRepresentation.SetResourceType(addRepresentationCommand.ResourceType); var uniqueServerAttributeIds = scimRepresentation.Attributes.Where(a => a.SchemaAttribute.MultiValued == false && a.SchemaAttribute.Uniqueness == SCIMSchemaAttributeUniqueness.SERVER); var uniqueGlobalAttributes = scimRepresentation.Attributes.Where(a => a.SchemaAttribute.MultiValued == false && a.SchemaAttribute.Uniqueness == SCIMSchemaAttributeUniqueness.GLOBAL); await CheckSCIMRepresentationExistsForGivenUniqueAttributes(uniqueServerAttributeIds, addRepresentationCommand.ResourceType); await CheckSCIMRepresentationExistsForGivenUniqueAttributes(uniqueGlobalAttributes); using (var transaction = await _scimRepresentationCommandRepository.StartTransaction()) { await _scimRepresentationCommandRepository.Add(scimRepresentation); await transaction.Commit(); } scimRepresentation.ApplyEmptyArray(); return(scimRepresentation); }
private OpenApiSchema GenerateReferencedSchema(DataContract dataContract, ParameterInfo parameterInfo, SchemaRepository schemaRepository) { var baseControllerType = typeof(BaseApiController); var baseParameterType = typeof(RepresentationParameter); string schemaId = dataContract.UnderlyingType.Name; Type controllerType = null; if (parameterInfo != null && baseParameterType.IsAssignableFrom(parameterInfo.ParameterType)) { if (baseControllerType.IsAssignableFrom(parameterInfo.Member.ReflectedType)) { schemaId = $"{parameterInfo.Member.ReflectedType.Name}{schemaId}"; controllerType = parameterInfo.Member.ReflectedType; } } if (schemaRepository.Schemas.ContainsKey(schemaId)) { return(new OpenApiSchema { Reference = new OpenApiReference { Id = schemaId, Type = ReferenceType.Schema } }); } schemaRepository.Schemas.Add(schemaId, null); var schema = GenerateInlineSchema(dataContract, parameterInfo, schemaRepository); ApplyFilters(schema, dataContract.UnderlyingType, schemaRepository); if (controllerType != null) { var controller = (BaseApiController)_serviceProvider.GetService(controllerType); var scimSchema = _scimSchemaQueryRepository.FindRootSCIMSchemaByResourceType(controller.ResourceType).Result; if (scimSchema != null) { Enrich(scimSchema, scimSchema.HierarchicalAttributes.Select(a => a.Leaf).ToList(), schema.Properties); } else { _logger.LogError($"the schema '{controller.ResourceType}' doesn't exist !"); } var kvp = schema.Properties.FirstOrDefault(_ => _.Key == "FlatAttributes" || _.Key == "attributes"); if (!kvp.Equals(default(KeyValuePair <string, OpenApiSchema>)) && !string.IsNullOrWhiteSpace(kvp.Key)) { schema.Properties.Remove(kvp); } } schemaRepository.Schemas[schemaId] = schema; return(new OpenApiSchema { Reference = new OpenApiReference { Id = schemaId, Type = ReferenceType.Schema } }); }
public async Task <SCIMRepresentation> Handle(ReplaceRepresentationCommand replaceRepresentationCommand) { var requestedSchemas = replaceRepresentationCommand.Representation.GetSchemas(); if (!requestedSchemas.Any()) { throw new SCIMBadSyntaxException(string.Format(Global.AttributeMissing, SCIMConstants.StandardSCIMRepresentationAttributes.Schemas)); } var schema = await _scimSchemaQueryRepository.FindRootSCIMSchemaByResourceType(replaceRepresentationCommand.ResourceType); var allSchemas = new List <string> { schema.Id }; allSchemas.AddRange(schema.SchemaExtensions.Select(s => s.Schema)); var unsupportedSchemas = requestedSchemas.Where(s => !allSchemas.Contains(s)); if (unsupportedSchemas.Any()) { throw new SCIMBadSyntaxException(string.Format(Global.SchemasAreUnknown, string.Join(",", unsupportedSchemas))); } var schemas = await _scimSchemaQueryRepository.FindSCIMSchemaByIdentifiers(requestedSchemas); var existingRepresentation = await _scimRepresentationQueryRepository.FindSCIMRepresentationById(replaceRepresentationCommand.Id); if (existingRepresentation == null) { throw new SCIMNotFoundException(string.Format(Global.ResourceNotFound, replaceRepresentationCommand.Id)); } var updatedRepresentation = _scimRepresentationHelper.ExtractSCIMRepresentationFromJSON(replaceRepresentationCommand.Representation, schemas.ToList()); existingRepresentation.RemoveAttributes(updatedRepresentation.Attributes.Select(_ => _.SchemaAttribute.Id)); foreach (var updatedAttribute in updatedRepresentation.Attributes) { if (updatedAttribute.SchemaAttribute.Mutability == SCIMSchemaAttributeMutabilities.IMMUTABLE) { throw new SCIMImmutableAttributeException(string.Format(Global.AttributeImmutable, updatedAttribute.Id)); } if (updatedAttribute.SchemaAttribute.Mutability == SCIMSchemaAttributeMutabilities.WRITEONLY || updatedAttribute.SchemaAttribute.Mutability == SCIMSchemaAttributeMutabilities.READWRITE) { existingRepresentation.AddAttribute(updatedAttribute); } } existingRepresentation.SetUpdated(DateTime.UtcNow); using (var transaction = await _scimRepresentationCommandRepository.StartTransaction()) { await _scimRepresentationCommandRepository.Update(existingRepresentation); await transaction.Commit(); } return(existingRepresentation); }
private OpenApiSchema GenerateReferencedSchema( DataContract dataContract, SchemaRepository schemaRepository, Func <OpenApiSchema> definitionFactory, ParameterInfo parameterInfo) { var dataContractType = dataContract.UnderlyingType; var baseControllerType = typeof(BaseApiController); var baseParameterType = typeof(RepresentationParameter); var schemaId = _generatorOptions.SchemaIdSelector(dataContract.UnderlyingType); Type controllerType = null; if (baseParameterType.IsAssignableFrom(dataContract.UnderlyingType)) { if (baseControllerType.IsAssignableFrom(parameterInfo.Member.ReflectedType)) { schemaId = $"{parameterInfo.Member.ReflectedType.Name}{schemaId}"; controllerType = parameterInfo.Member.ReflectedType; dataContractType = controllerType; } } if (schemaRepository.TryLookupByType(dataContractType, out OpenApiSchema referenceSchema)) { return(referenceSchema); } schemaRepository.RegisterType(dataContractType, schemaId); var schema = definitionFactory(); ApplyFilters(schema, dataContractType, schemaRepository); if (controllerType != null) { var controller = (BaseApiController)_serviceProvider.GetService(controllerType); var scimSchema = _scimSchemaQueryRepository.FindRootSCIMSchemaByResourceType(controller.ResourceType).Result; if (scimSchema != null) { Enrich(scimSchema, scimSchema.HierarchicalAttributes.Select(a => a.Leaf).ToList(), schema.Properties); } else { _logger.LogError($"the schema '{controller.ResourceType}' doesn't exist !"); } var kvp = schema.Properties.FirstOrDefault(_ => _.Key == "attributes"); if (!kvp.Equals(default(KeyValuePair <string, OpenApiSchema>)) && !string.IsNullOrWhiteSpace(kvp.Key)) { schema.Properties.Remove(kvp); } } return(schemaRepository.AddDefinition(schemaId, schema)); }
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)); } }
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 async Task <SCIMRepresentation> Handle(ReplaceRepresentationCommand replaceRepresentationCommand) { var requestedSchemas = replaceRepresentationCommand.Representation.Schemas; if (!requestedSchemas.Any()) { throw new SCIMBadSyntaxException(string.Format(Global.AttributeMissing, StandardSCIMRepresentationAttributes.Schemas)); } var schema = await _scimSchemaQueryRepository.FindRootSCIMSchemaByResourceType(replaceRepresentationCommand.ResourceType); var allSchemas = new List <string> { schema.Id }; allSchemas.AddRange(schema.SchemaExtensions.Select(s => s.Schema)); var unsupportedSchemas = requestedSchemas.Where(s => !allSchemas.Contains(s)); if (unsupportedSchemas.Any()) { throw new SCIMBadSyntaxException(string.Format(Global.SchemasAreUnknown, string.Join(",", unsupportedSchemas))); } var schemas = await _scimSchemaQueryRepository.FindSCIMSchemaByIdentifiers(requestedSchemas); var lockName = $"representation-{replaceRepresentationCommand.Id}"; await _distributedLock.WaitLock(lockName, CancellationToken.None); try { var existingRepresentation = await _scimRepresentationQueryRepository.FindSCIMRepresentationById(replaceRepresentationCommand.Id); if (existingRepresentation == null) { throw new SCIMNotFoundException(string.Format(Global.ResourceNotFound, replaceRepresentationCommand.Id)); } var oldRepresentation = (SCIMRepresentation)existingRepresentation.Clone(); var mainSchema = schemas.First(s => s.Id == schema.Id); var extensionSchemas = schemas.Where(s => s.Id != schema.Id).ToList(); var updatedRepresentation = _scimRepresentationHelper.ExtractSCIMRepresentationFromJSON( replaceRepresentationCommand.Representation.Attributes, replaceRepresentationCommand.Representation.ExternalId, mainSchema, extensionSchemas); var allExistingAttributes = existingRepresentation.HierarchicalAttributes; existingRepresentation.RemoveAttributesBySchemaAttrId(updatedRepresentation.FlatAttributes.Select(_ => _.SchemaAttribute.Id)); foreach (var kvp in updatedRepresentation.HierarchicalAttributes.GroupBy(h => h.FullPath)) { var fullPath = kvp.Key; var filteredExistingAttributes = allExistingAttributes.Where(a => a.FullPath == fullPath); var invalidAttrs = filteredExistingAttributes.Where(fa => !kvp.Any(a => a.IsMutabilityValid(fa))); if (invalidAttrs.Any()) { throw new SCIMImmutableAttributeException(string.Format(Global.AttributeImmutable, string.Join(",", invalidAttrs.Select(a => a.FullPath)))); } foreach (var rootAttr in kvp) { if (rootAttr.SchemaAttribute.Mutability == SCIMSchemaAttributeMutabilities.WRITEONLY || rootAttr.SchemaAttribute.Mutability == SCIMSchemaAttributeMutabilities.READWRITE || rootAttr.SchemaAttribute.Mutability == SCIMSchemaAttributeMutabilities.IMMUTABLE) { var flatAttrs = rootAttr.ToFlat(); foreach (var attr in flatAttrs) { existingRepresentation.AddAttribute(attr); } } } } existingRepresentation.SetDisplayName(updatedRepresentation.DisplayName); existingRepresentation.SetExternalId(updatedRepresentation.ExternalId); existingRepresentation.SetUpdated(DateTime.UtcNow); var isReferenceProperty = await _representationReferenceSync.IsReferenceProperty(replaceRepresentationCommand.Representation.Attributes.GetKeys()); var references = await _representationReferenceSync.Sync(replaceRepresentationCommand.ResourceType, oldRepresentation, existingRepresentation, replaceRepresentationCommand.Location, !isReferenceProperty); using (var transaction = await _scimRepresentationCommandRepository.StartTransaction()) { await _scimRepresentationCommandRepository.Update(existingRepresentation); foreach (var reference in references.Representations) { await _scimRepresentationCommandRepository.Update(reference); } await transaction.Commit(); } await Notify(references); existingRepresentation.ApplyEmptyArray(); return(existingRepresentation); } finally { await _distributedLock.ReleaseLock(lockName, CancellationToken.None); } }