/// <summary> /// Applies the provided local identifying properties to the build result using the supplied builder context. /// </summary> /// <param name="locallyDefinedIdentifyingProperties">The list of local identifying properties to be applied to the build result.</param> /// <param name="builderContext">The builder context.</param> /// <param name="processorContext">The composite definition processor context.</param> public void ApplyLocalIdentifyingProperties( IReadOnlyList <EntityProperty> locallyDefinedIdentifyingProperties, CompositeResourceModelBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext) { // Nothing to do }
/// <summary> /// Apply the provided property projections onto the build result with the provided builder and composite /// definition processor contexts. /// </summary> /// <param name="propertyProjections">A list of property projections to be applied to the build result.</param> /// <param name="builderContext">The builder context.</param> /// <param name="processorContext">The composite definition processor context.</param> public void ProjectProperties( IReadOnlyList <CompositePropertyProjection> propertyProjections, HqlBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext) { _next.ProjectProperties(propertyProjections, builderContext, processorContext); }
private void ProcessChildren(TBuildResult parentResult, CompositeDefinitionProcessorContext processorContext, TBuilderContext parentingBuilderContext) { var resourceModel = processorContext.ResourceModel; XElement currentElt = processorContext.CurrentElement; ResourceClassBase currentResourceClass = processorContext.CurrentResourceClass; // Iterate through children (Collection, EmbeddedObject, Resource or Reference) var otherChildren = currentElt.Elements(CompositeDefinitionHelper.Collection) .Concat(currentElt.Elements(CompositeDefinitionHelper.EmbeddedObject)) .Concat(currentElt.Elements(CompositeDefinitionHelper.LinkedCollection)) .Concat(currentElt.Elements(CompositeDefinitionHelper.ReferencedResource)); int childIndex = 0; foreach (var childElt in otherChildren) { var childProcessorContext = CreateChildProcessorContext( parentResult, processorContext, parentingBuilderContext, childElt, currentResourceClass, resourceModel, childIndex); if (childProcessorContext == null) { continue; } var childBuilderContext = _compositeBuilder.CreateChildContext(parentingBuilderContext, childProcessorContext); childIndex++; ProcessDefinition(parentResult, childBuilderContext, childProcessorContext); } }
/// <summary> /// Applies the provided local identifying properties to the build result using the suplied builder context. /// </summary> /// <param name="locallyDefinedIdentifyingProperties">The list of local identifying properties to be applied to the build result.</param> /// <param name="builderContext">The builder context.</param> /// <param name="processorContext">The composite definition processor context.</param> public void ApplyLocalIdentifyingProperties( IReadOnlyList <EntityProperty> locallyDefinedIdentifyingProperties, HqlBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext) { _next.ApplyLocalIdentifyingProperties(locallyDefinedIdentifyingProperties, builderContext, processorContext); }
/// <summary> /// Builds the artifact for the root resource of the composite definition. /// </summary> /// <param name="builderContext">The builder context.</param> /// <param name="processorContext">The composite definition processor context.</param> /// <param name="resource">The resource that is built.</param> /// <returns>The build result.</returns> public bool TryBuildForRootResource( CompositeResourceModelBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext, out Resource resource) { resource = builderContext.RootResource; return(true); }
/// <summary> /// Builds the artifact for the root resource of the composite definition. /// </summary> /// <param name="builderContext">The builder context.</param> /// <param name="processorContext">The composite definition processor context.</param> /// <param name="buildResult">The build result.</param> /// <returns><b>true</b> if the result could be built; otherwise <b>false</b>.</returns> public bool TryBuildForRootResource( HqlBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext, out CompositeQuery buildResult) { ApplyFilters(processorContext, builderContext); return(_next.TryBuildForRootResource(builderContext, processorContext, out buildResult)); }
/// <summary> /// Builds the artifact for the root resource of the composite definition. /// </summary> /// <param name="parentResult">The parent build result, for compositional behavior (if applicable).</param> /// <param name="builderContext">The builder context.</param> /// <param name="processorContext">The composite definition processor context.</param> /// <returns>The build result.</returns> public CompositeQuery BuildForChildResource( CompositeQuery parentResult, HqlBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext) { ApplyFilters(processorContext, builderContext); return(_next.BuildForChildResource(parentResult, builderContext, processorContext)); }
private void ApplyLocalIdentifyingProperties(TBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext, List <EntityProperty> nonIncomingIdentifyingProperties) { // Apply local identifying properties to the artifact under construction _compositeBuilder.ApplyLocalIdentifyingProperties( nonIncomingIdentifyingProperties, builderContext, processorContext); }
/// <summary> /// Applies the composite resource's root resource to the build result using the supplied builder context. /// </summary> /// <param name="processorContext"></param> /// <param name="builderContext">The builder context.</param> public void ApplyRootResource(CompositeDefinitionProcessorContext processorContext, CompositeResourceModelBuilderContext builderContext) { string compositeName = processorContext.CurrentElement.Ancestors("Composite") .First() .AttributeValue("name"); string resourceName = CompositeTermInflector.MakeSingular(compositeName); builderContext.RootResource = new Resource(resourceName); //resource.Entity.Name); builderContext.CurrentResource = builderContext.RootResource; }
public static IReadOnlyDictionary <string, ResourceProperty> ValidPropertiesByName( CompositeDefinitionProcessorContext processorContext, IReadOnlyDictionary <string, ResourceProperty> propertiesByName) { Preconditions.ThrowIfNull(processorContext, nameof(processorContext)); Preconditions.ThrowIfNull(propertiesByName, nameof(propertiesByName)); return(processorContext.ShouldIncludeResourceSubtype() ? propertiesByName .Where(p => p.Value.IsIdentifying) .ToDictionary(k => k.Key, v => v.Value) : propertiesByName); }
/// <summary> /// Creates a new builder context to be used for processing a child element. /// </summary> /// <param name="parentingBuilderContext">The parent context to be used to derive the new child context.</param> /// <param name="childProcessorContext"></param> /// <returns>The new builder context.</returns> public CompositeResourceModelBuilderContext CreateChildContext( CompositeResourceModelBuilderContext parentingBuilderContext, CompositeDefinitionProcessorContext childProcessorContext) { return(new CompositeResourceModelBuilderContext { RootResource = parentingBuilderContext.RootResource, ParentResource = parentingBuilderContext.CurrentResource, CurrentResource = new ResourceChildItem( childProcessorContext.CurrentResourceClass.Name, parentingBuilderContext.CurrentResource) }); }
private List <CompositePropertyProjection> GetPropertyProjectionsForNonAggregateRoot( CompositeDefinitionProcessorContext processorContext, EmbeddedObject currentMember, IEnumerable <XElement> propertyElements, string containingElementName) { var selectedElements = CompositeDefinitionHelper.CreateSelectedElements(propertyElements); var validPropertiesByName = CompositeDefinitionHelper.ValidPropertiesByName( processorContext, currentMember.ObjectType.PropertyByName); var validProperties = CompositeDefinitionHelper.GetValidProperties(selectedElements, validPropertiesByName); ValidateSelectedElements( selectedElements, validProperties, containingElementName, processorContext.ShouldIncludeResourceSubtype()); return(validProperties .Select( pn => new CompositePropertyProjection(currentMember.ObjectType.AllPropertyByName[pn.Name], pn.DisplayName)) .ToList()); }
public TBuildResult Process( XElement compositeDefinition, IResourceModel resourceModel, TBuilderContext builderContext) { var currentElt = compositeDefinition.Element(CompositeDefinitionHelper.BaseResource); if (currentElt == null) { throw new Exception("Unable to find the main 'Resource' element of the composite definition."); } var resourceLogicalName = currentElt.AttributeValue(CompositeDefinitionHelper.LogicalSchema) ?? EdFiConventions.LogicalName; var resourcePhysicalName = resourceModel.SchemaNameMapProvider .GetSchemaMapByLogicalName(resourceLogicalName) .PhysicalName; // Composites does not support extensions var currentModel = resourceModel.GetResourceByFullName( new FullName(resourcePhysicalName, currentElt.AttributeValue(CompositeDefinitionHelper.Name))); var processorContext = new CompositeDefinitionProcessorContext( compositeDefinition, resourceModel, currentElt, currentModel, null, null, null, 0, null); return(ProcessDefinition(default(TBuildResult), builderContext, processorContext)); }
private List <CompositePropertyProjection> GetPropertyProjections( CompositeDefinitionProcessorContext processorContext, IEnumerable <XElement> propertyElements) { var selectedElements = CompositeDefinitionHelper.CreateSelectedElements(propertyElements); // only allow identifying properties for pass through resources. var validPropertiesByName = CompositeDefinitionHelper.ValidPropertiesByName( processorContext, processorContext.CurrentResourceClass.AllPropertyByName); var validProperties = CompositeDefinitionHelper.GetValidProperties(selectedElements, validPropertiesByName); ValidateSelectedElements( selectedElements, validProperties, processorContext.CurrentElement.AttributeValue(CompositeDefinitionHelper.Name), processorContext.ShouldIncludeResourceSubtype()); return(validProperties.Select( pn => new CompositePropertyProjection( processorContext.CurrentResourceClass.AllPropertyByName[pn.Name], pn.DisplayName)) .ToList()); }
/// <summary> /// Creates a new builder context to be used for processing a child element. /// </summary> /// <param name="parentingBuilderContext">The parent context to be used to derive the new child context.</param> /// <param name="childProcessorContext"></param> /// <returns>The new builder context.</returns> public HqlBuilderContext CreateChildContext( HqlBuilderContext parentingBuilderContext, CompositeDefinitionProcessorContext childProcessorContext) { return(_next.CreateChildContext(parentingBuilderContext, childProcessorContext)); }
private CompositeDefinitionProcessorContext CreateChildProcessorContext(TBuildResult parentResult, CompositeDefinitionProcessorContext processorContext, TBuilderContext parentingBuilderContext, XElement childElement, ResourceClassBase currentResourceClass, IResourceModel resourceModel, int childIndex) { ResourceClassBase childModel; AssociationView association; ResourceMemberBase resourceMember; string childMemberName = childElement.AttributeValue(CompositeDefinitionHelper.Name); string childMemberDisplayName = childElement.AttributeValue(CompositeDefinitionHelper.DisplayName); string currentElementName = processorContext.CurrentElement.AttributeValue(CompositeDefinitionHelper.Name); string resourceMemberName = string.Empty; string childEntityMemberName = string.Empty; switch (childElement.Name.LocalName) { case CompositeDefinitionHelper.Collection: if (!currentResourceClass.CollectionByName.TryGetValue(childMemberName, out Collection collection)) { ApplyValidationMessage("collection", childMemberName, currentElementName); return(null); } _logger.Debug($"Current element '{currentElementName}' is a collection named '{childMemberName}'."); childModel = collection.ItemType; childEntityMemberName = childMemberName; association = collection.Association; resourceMember = collection; resourceMemberName = collection.PropertyName; break; case CompositeDefinitionHelper.LinkedCollection: var resource = currentResourceClass as Resource; if (resource == null) { _logger.Debug($"Current resource class '{currentResourceClass.Name} is not an aggregate root."); return(null); } if (!resource.LinkedResourceCollectionByName.TryGetValue( childMemberName, out LinkedCollection linkedCollection)) { ApplyValidationMessage("linked collection", childMemberName, currentElementName); return(null); } _logger.Debug( $"Current element '{currentElementName} is a linked collection named '{childMemberName}' for resource '{currentResourceClass.Name}'."); childModel = linkedCollection.Resource; childEntityMemberName = childMemberName; association = linkedCollection.Association; resourceMember = linkedCollection; resourceMemberName = linkedCollection.PropertyName; break; case CompositeDefinitionHelper.EmbeddedObject: if (!currentResourceClass.EmbeddedObjectByName.TryGetValue( childMemberName, out EmbeddedObject embeddedObject)) { ApplyValidationMessage("embedded object", childMemberName, currentElementName); return(null); } _logger.Debug($"Current element '{currentElementName}' is an embedded object named '{childMemberName}'."); childModel = embeddedObject.ObjectType; childEntityMemberName = embeddedObject.Association.Name; association = embeddedObject.Association; resourceMember = embeddedObject; resourceMemberName = embeddedObject.PropertyName; if (CompositeDefinitionHelper.ShouldFlatten(childElement)) { _logger.Debug($"Flattening embedded object {childModel.Name}"); _compositeBuilder.ApplyFlattenedMember(embeddedObject, parentingBuilderContext); var childBuilderContextForObject = _compositeBuilder.CreateFlattenedReferenceChildContext(parentingBuilderContext); var childProcessorContextForObject = new CompositeDefinitionProcessorContext( processorContext.CompositeDefinitionElement, resourceModel, childElement, childModel, association, childEntityMemberName, resourceMemberName, childIndex, resourceMember); ProcessChildren(parentResult, childProcessorContextForObject, childBuilderContextForObject); return(null); } break; case CompositeDefinitionHelper.ReferencedResource: ResourceMemberBase resourceMemberToUseForFlattening; if (!currentResourceClass.ReferenceByName.TryGetValue(childMemberName, out Reference reference)) { // Look for a "descriptor" property if (currentResourceClass.PropertyByName.TryGetValue( childMemberName, out ResourceProperty descriptorProperty)) { resourceMemberToUseForFlattening = descriptorProperty; childModel = descriptorProperty.DescriptorResource; childEntityMemberName = childMemberName; association = descriptorProperty.EntityProperty.IncomingAssociations.FirstOrDefault(); resourceMember = descriptorProperty; resourceMemberName = childMemberName; } else { ApplyValidationMessage("referenced resource", childMemberName, currentElementName); return(null); } } else { _logger.Debug( $"Current element '{currentElementName}' is a referenced resourced named '{childMemberName}'."); resourceMemberToUseForFlattening = reference; childModel = reference.ReferencedResource; childEntityMemberName = reference.Association.Name; association = reference.Association; resourceMember = reference; resourceMemberName = reference.PropertyName; } // If reference is flattened, process recursively without adding another query at this level. if (CompositeDefinitionHelper.ShouldFlatten(childElement)) { _logger.Debug($"Flattening referenced resource {childModel.Name}"); _compositeBuilder.ApplyFlattenedMember(resourceMemberToUseForFlattening, parentingBuilderContext); var childBuilderContextForReference = _compositeBuilder.CreateFlattenedReferenceChildContext(parentingBuilderContext); var childProcessorContextForReference = new CompositeDefinitionProcessorContext( processorContext.CompositeDefinitionElement, resourceModel, childElement, childModel, association, childEntityMemberName, resourceMemberName, childIndex, resourceMember); if (childModel.Entity.IsAggregateRoot) { // Provide opportunity to perform processing related to navigating into another resource (i.e. authorization) if (!_compositeBuilder.TryIncludeResource( childProcessorContextForReference, childBuilderContextForReference)) { return(null); } } ProcessChildren(parentResult, childProcessorContextForReference, childBuilderContextForReference); return(null); } break; default: throw new NotSupportedException($"Element '{childElement.Name.LocalName}' is not supported."); } return(new CompositeDefinitionProcessorContext( processorContext.CompositeDefinitionElement, resourceModel, childElement, childModel, association, childEntityMemberName, childMemberDisplayName ?? resourceMemberName, childIndex, resourceMember)); }
/// <summary> /// Applies the composite resource's child resource to the build result using the supplied builder context. /// </summary> /// <param name="builderContext">The builder context.</param> /// <param name="processorContext">The composite definition processor context.</param> public void ApplyChildResource( HqlBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext) { _next.ApplyChildResource(builderContext, processorContext); }
/// <summary> /// Applies the composite resource's root resource to the build result using the supplied builder context. /// </summary> /// <param name="processorContext"></param> /// <param name="builderContext">The builder context.</param> public void ApplyRootResource(CompositeDefinitionProcessorContext processorContext, HqlBuilderContext builderContext) { _next.ApplyRootResource(processorContext, builderContext); }
private void ProcessFlattenedMemberProperties( CompositeDefinitionProcessorContext processorContext, TBuilderContext builderContext) { string currentContainingElementName = processorContext.CurrentElement.AttributeValue(CompositeDefinitionHelper.Name); var flattenedMemberElements = processorContext.CurrentElement .Elements(CompositeDefinitionHelper.ReferencedResource) .Where(CompositeDefinitionHelper.ShouldFlatten) .ToList(); flattenedMemberElements.AddRange( processorContext.CurrentElement .Elements(CompositeDefinitionHelper.EmbeddedObject) .Where(CompositeDefinitionHelper.ShouldFlatten)); foreach (var flattenedMemberElt in flattenedMemberElements) { string flattenedMemberName = flattenedMemberElt.AttributeValue(CompositeDefinitionHelper.Name); ResourceMemberBase resourceMemberToUse = null; Resource flattenedResource = null; bool memberIsReference = flattenedMemberElt.Name.LocalName == CompositeDefinitionHelper.ReferencedResource; bool memberIsEmbeddedObject = flattenedMemberElt.Name.LocalName == CompositeDefinitionHelper.EmbeddedObject; if (memberIsReference) { if (!processorContext.CurrentResourceClass.ReferenceByName.TryGetValue( flattenedMemberName, out Reference resourceToUseAsReference)) { // Look for a "descriptor" property if (processorContext.CurrentResourceClass.PropertyByName.TryGetValue( flattenedMemberName, out ResourceProperty descriptorProperty)) { resourceMemberToUse = descriptorProperty; flattenedResource = processorContext.CurrentResourceClass.ResourceModel.GetResourceByFullName( descriptorProperty.DescriptorResource.Entity.FullName); } else { ApplyValidationMessage("resource reference", flattenedMemberName, currentContainingElementName); continue; } } else { resourceMemberToUse = resourceToUseAsReference; flattenedResource = processorContext.CurrentResourceClass.ResourceModel.GetResourceByFullName( resourceToUseAsReference.ReferencedResource.Entity.FullName); } } else if (memberIsEmbeddedObject) { if (!processorContext.CurrentResourceClass.EmbeddedObjectByName.TryGetValue( flattenedMemberName, out EmbeddedObject resourceAsEmbeddedObject)) { ApplyValidationMessage("embedded object", flattenedMemberName, currentContainingElementName); continue; } resourceMemberToUse = resourceAsEmbeddedObject; flattenedResource = processorContext.CurrentResourceClass.ResourceModel.GetResourceByFullName( resourceAsEmbeddedObject.Parent.Entity.FullName); } else { // Defensive programming, but also throw a helpful message in the event it does ever happen throw new NotSupportedException( $"Flattened elements of type '{flattenedMemberElt.Name.LocalName}' are not yet supported."); } var flattenedBuilderContext = _compositeBuilder.CreateFlattenedMemberContext(builderContext); var flattenedProcessingContext = new CompositeDefinitionProcessorContext( processorContext.CompositeDefinitionElement, processorContext.ResourceModel, flattenedMemberElt, flattenedResource, null, null, null, 0, resourceMemberToUse); var shouldContinueWithValidation = resourceMemberToUse == null && _performValidation; if (flattenedResource.Entity.IsAggregateRoot) { // Provide opportunity to perform processing related to navigating into another resource (i.e. authorization) if (!_compositeBuilder.TryIncludeResource(flattenedProcessingContext, flattenedBuilderContext)) { continue; } } if (shouldContinueWithValidation) { continue; } _compositeBuilder.ApplyFlattenedMember(resourceMemberToUse, flattenedBuilderContext); // TODO: Consider refining what is passed into Resource model classes rather than XElements var propertyElements = flattenedMemberElt .Elements(CompositeDefinitionHelper.Property) .ToList(); List <CompositePropertyProjection> flattenedPropertyProjections = new List <CompositePropertyProjection>(); if (memberIsReference) { flattenedPropertyProjections = GetPropertyProjections( flattenedProcessingContext, propertyElements); } else if (memberIsEmbeddedObject) { flattenedPropertyProjections = GetPropertyProjectionsForNonAggregateRoot( processorContext, (EmbeddedObject)resourceMemberToUse, propertyElements, currentContainingElementName); } _compositeBuilder.ProjectProperties( flattenedPropertyProjections, flattenedBuilderContext, flattenedProcessingContext); // Recursively process flattened resource properties ProcessFlattenedMemberProperties( flattenedProcessingContext, flattenedBuilderContext); } }
/// <summary> /// Apply the provided property projections onto the build result with the provided builder and composite /// definition processor contexts. /// </summary> /// <param name="propertyProjections">A list of property projections to be applied to the build result.</param> /// <param name="builderContext">The builder context.</param> /// <param name="processorContext">The composite definition processor context.</param> public void ProjectProperties( IReadOnlyList <CompositePropertyProjection> propertyProjections, CompositeResourceModelBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext) { // Local reused functional predicate var isIdProperty = new Func <CompositePropertyProjection, bool>( p => p.ResourceProperty.PropertyName.EqualsIgnoreCase("Id")); // Ensure Id property appears first var orderedPropertyProjections = propertyProjections.Where(isIdProperty) .Concat(propertyProjections.Where(p => !isIdProperty(p))); if (processorContext.ShouldIncludeResourceSubtype()) { Logger.Debug($"Adding the resource type the property collection"); AddItem( builderContext.CurrentResource.Properties, new ResourceProperty( builderContext.CurrentResource, processorContext.CurrentResourceClass.Name.ToCamelCase() + "Type", new PropertyType(DbType.AnsiString, 128, 0, 0, true), new PropertyCharacteristics( false, false, false, true, // All projected properties are "local" properties on the new object false, null), null)); } foreach (var property in orderedPropertyProjections) { Logger.Debug($"Projecting property {property.ResourceProperty.PropertyName}."); var entityProperty = property.ResourceProperty.EntityProperty; if (!builderContext.CurrentResource.IsAbstract() || builderContext.CurrentResource.IsAbstract() && entityProperty.IsIdentifying && processorContext.ShouldIncludeResourceSubtype()) { Logger.Debug($"Adding property {property.ResourceProperty.PropertyName} to the builder context."); AddItem( builderContext.CurrentResource.Properties, new ResourceProperty( builderContext.CurrentResource, property.DisplayName ?? property.ResourceProperty.PropertyName, property.ResourceProperty.PropertyType, new PropertyCharacteristics( entityProperty.IsLookup, entityProperty.IsDirectLookup, entityProperty.IsIdentifying, true, // All projected properties are "local" properties on the new object entityProperty.IsServerAssigned, entityProperty.LookupEntity == null ? null as FullName? : entityProperty.LookupEntity.FullName), property.ResourceProperty.Description)); } else { Logger.Debug($"Stripping property {property.ResourceProperty.PropertyName} from the builder context."); } } }
/// <summary> /// Applies the composite resource's child resource to the build result using the supplied builder context. /// </summary> /// <param name="builderContext">The builder context.</param> /// <param name="processorContext">The composite definition processor context.</param> public void ApplyChildResource( CompositeResourceModelBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext) { // Nothing to apply (we only need to actually build the model) }
private void ApplyFilters( CompositeDefinitionProcessorContext processorContext, HqlBuilderContext builderContext) { var entityType = GetEntityType(processorContext.CurrentResourceClass); var filters = builderContext.CurrentQueryFilterByName; // -------------------------- // Add security filtering // -------------------------- if (filters != null && filters.Any()) { foreach (var filterInfo in filters) { // Get the filter text string filterName = filterInfo.Key; string filterHqlFormat; if (!_nHibernateFilterTextProvider.TryGetHqlFilterText(entityType, filterName, out filterHqlFormat)) { throw new Exception( string.Format( "Unable to apply authorization to query because filter '{0}' could not be found on entity '{1}'.", filterName, entityType.Name)); } if (string.IsNullOrWhiteSpace(filterHqlFormat)) { throw new Exception( string.Format( "Unable to apply authorization to query because filter '{0}' on entity '{1}' was found, but was null or empty.", filterName, entityType.Name)); } // Set the current alias for the contextual fields string filterHql = string.Format(filterHqlFormat, builderContext.CurrentAlias); if (!string.IsNullOrWhiteSpace(filterHql)) { // Add HQL to the current resource query's WHERE clause builderContext.Where.AppendFormat( "{0}({1})", AndIfNeeded(builderContext.Where), filterHql); // Copy over the values of the named parameters, but only if they are actually present in the filter var authorizationFilterDetails = filterInfo.Value; string parameterName = authorizationFilterDetails.ClaimEndpointName; if (filterHql.Contains($":{parameterName}")) { if (authorizationFilterDetails.ClaimValues.Length == 1) { builderContext.CurrentQueryFilterParameterValueByName[parameterName] = authorizationFilterDetails.ClaimValues.Single(); } else { builderContext.CurrentQueryFilterParameterValueByName[parameterName] = authorizationFilterDetails.ClaimValues; } } } } } }
private TBuildResult ProcessDefinition( TBuildResult parentResult, TBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext) { // Apply authorization for aggregate roots here if (processorContext.CurrentResourceClass.Entity.IsAggregateRoot) { // Provide opportunity to perform processing related to navigating into another resource (i.e. authorization) if (!_compositeBuilder.TryIncludeResource(processorContext, builderContext)) { return(default(TBuildResult)); } } bool isMainQuery = processorContext.IsBaseResource(); if (isMainQuery) { _compositeBuilder.ApplyRootResource(processorContext, builderContext); } else { _compositeBuilder.ApplyChildResource(builderContext, processorContext); } var nonIncomingIdentifyingProperties = processorContext.NonIncomingIdentifyingProperties(); ApplyLocalIdentifyingProperties(builderContext, processorContext, nonIncomingIdentifyingProperties); // Capture current applicable builder state so it can be modified further at this level without changes affecting children _compositeBuilder.SnapshotParentingContext(builderContext); // Select projected properties var propertyProjections = GetPropertyProjections(processorContext, processorContext.PropertyElements()); // Project the properties into the artifact under construction _compositeBuilder.ProjectProperties(propertyProjections, builderContext, processorContext); // Process flattened References ProcessFlattenedMemberProperties(processorContext, builderContext); TBuildResult thisBuildResult; if (isMainQuery) { // Short circuit the rest of the processing if the root result is null if (!_compositeBuilder.TryBuildForRootResource(builderContext, processorContext, out thisBuildResult)) { return(default(TBuildResult)); } } else { thisBuildResult = _compositeBuilder.BuildForChildResource( parentResult, builderContext, processorContext); } var childBuilderContext = _compositeBuilder.CreateParentingContext(builderContext); ProcessChildren(thisBuildResult, processorContext, childBuilderContext); if (_performValidation && _validationErrors.Any()) { throw new Exception(string.Join(Environment.NewLine, _validationErrors.ToArray())); } return(thisBuildResult); }
/// <summary> /// Builds the artifact for the root resource of the composite definition. /// </summary> /// <param name="parentResult">The parent build result, for compositional behavior (if applicable).</param> /// <param name="builderContext">The builder context.</param> /// <param name="processorContext">The composite definition processor context.</param> /// <returns>The build result.</returns> public Resource BuildForChildResource( Resource parentResult, CompositeResourceModelBuilderContext builderContext, CompositeDefinitionProcessorContext processorContext) { string currentElementName = processorContext.CurrentElement.Name.LocalName; switch (currentElementName) { case Collection: AddItem( builderContext.ParentResource.Collections, new Collection( builderContext.ParentResource, builderContext.CurrentResource as ResourceChildItem, processorContext.JoinAssociation, processorContext.MemberDisplayName)); break; case LinkedCollection: AddItem( builderContext.ParentResource.Collections, new Collection( builderContext.ParentResource, builderContext.CurrentResource as ResourceChildItem, processorContext.JoinAssociation, processorContext.MemberDisplayName)); break; case ReferencedResource: AddItem( builderContext.ParentResource.EmbeddedObjects, new EmbeddedObject( builderContext.ParentResource, builderContext.CurrentResource as ResourceChildItem, processorContext.MemberDisplayName)); break; case EmbeddedObject: AddItem( builderContext.ParentResource.EmbeddedObjects, new EmbeddedObject( builderContext.ParentResource, builderContext.CurrentResource as ResourceChildItem, processorContext.MemberDisplayName)); break; default: throw new NotSupportedException($"Child element type '{currentElementName}' is not yet supported."); } // Nothing to compose (results are built in-place using the builder context) return(null); }
/// <summary> /// Applies processing related to the usage/entry to another top-level resource (e.g. applying authorization concerns). /// </summary> /// <param name="processorContext">The composite definition processor context.</param> /// <param name="builderContext">The current builder context.</param> /// <returns><b>true</b> if the resource can be processed; otherwise <b>false</b>.</returns> public bool TryIncludeResource(CompositeDefinitionProcessorContext processorContext, HqlBuilderContext builderContext) { var resourceClass = processorContext.CurrentResourceClass; if (!(resourceClass is Resource)) { throw new InvalidOperationException( $"Unable to evaluate resource '{resourceClass.FullName}' for inclusion in HQL query because it is not the root class of the resource."); } var resource = (Resource)resourceClass; // -------------------------- // Determine inclusion // -------------------------- var entityType = GetEntityType(resource); var authorizationContext = new EdFiAuthorizationContext( ClaimsPrincipal.Current, _resourceClaimUriProvider.GetResourceClaimUris(resource), RequestActions.ReadActionUri, entityType); // Authorize and apply filtering IReadOnlyList <AuthorizationFilterDetails> authorizationFilters; try { // NOTE: Possible performance optimization - Allow for "Try" semantics (so no exceptions are thrown here) authorizationFilters = _authorizationProvider.GetAuthorizationFilters(authorizationContext); } catch (EdFiSecurityException ex) { // If this is the base resource, rethrow the exception to achieve a 401 response if (processorContext.IsBaseResource()) { Logger.Debug($"BaseResource: {processorContext.CurrentResourceClass.Name} could not be authorized."); throw; } // In the case where we have an abstract class and it has no claim, eg EducationOrganization, we will allow // the join if the subtype has been included. if (processorContext.IsAbstract()) { Logger.Debug($"Resource {processorContext.CurrentResourceClass.Name} has no claim."); if (processorContext.ShouldIncludeResourceSubtype()) { Logger.Debug( $"Resource is abstract and so target resource '{processorContext.CurrentResourceClass.Name}' cannot be authorized. Join will be included, but non-identifying resource members should be stripped from results."); return(true); } } Logger.Debug($"Resource {processorContext.CurrentResourceClass.Name} is excluded from the request."); Logger.Debug($"Security Exception Message: {ex.Message}."); return(false); } // Save the filters to be applied to this query for use later in the process builderContext.CurrentQueryFilterByName = authorizationFilters.ToDictionary(x => x.FilterName, x => x); return(true); }
/// <summary> /// Applies processing related to the usage/entry to another top-level resource (e.g. applying authorization concerns). /// </summary> /// <param name="processorContext">The composite definition processor context.</param> /// <param name="builderContext">The current builder context.</param> /// <returns><b>true</b> if the resource can be processed; otherwise <b>false</b>.</returns> public bool TryIncludeResource(CompositeDefinitionProcessorContext processorContext, CompositeResourceModelBuilderContext builderContext) { // No reason not to include the resource in this usage scenario return(true); }