/// <summary> /// An extension method that provides simpler syntax when using the <see cref="IOpenApiAccessChecker"/> /// to check access for a single operation. /// </summary> /// <param name="checker">The underlying <see cref="IOpenApiAccessChecker"/> to use.</param> /// <param name="context">The current <see cref="IOpenApiContext"/>.</param> /// <param name="path">The request path.</param> /// <param name="operationId">The request Operation Id.</param> /// <param name="httpMethod">The request Http method.</param> /// <returns>A task that resolves to the result of the access check.</returns> public static async Task <AccessControlPolicyResult> CheckAccessPolicyAsync( this IOpenApiAccessChecker checker, IOpenApiContext context, string path, string operationId, string httpMethod) { var request = new AccessCheckOperationDescriptor(path, operationId, httpMethod); IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> result = await checker.CheckAccessPoliciesAsync(context, request).ConfigureAwait(false); return(result.Values.Single()); }
/// <summary> /// Searches through a <see cref="HalDocument"/> and removes any links that the current /// principal does not have access to. /// </summary> /// <param name="that"> /// The <see cref="IOpenApiAccessChecker"/> that will be used to check the individual links. /// </param> /// <param name="target"> /// The <see cref="HalDocument"/> to check. /// </param> /// <param name="context"> /// The <see cref="IOpenApiContext"/> used to get information about the current principal. /// </param> /// <param name="options"> /// The <see cref="HalDocumentLinkRemovalOptions"/> to apply when checking links. /// </param> /// <returns>A task that completes when all links have been checked.</returns> public static async Task RemoveForbiddenLinksAsync(this IOpenApiAccessChecker that, HalDocument target, IOpenApiContext context, HalDocumentLinkRemovalOptions options = default) { // First, we need to build a collection of all the links. For each one we need: // 1. The link itself. // 2. The HalDocument(s) to which it belongs - it is possible that we may encounter the same link twice and we need to be able to deal with that // 3. The link relation name. var linkMap = new Dictionary <(string, OpenApiWebLink), List <HalDocument> >(); AddHalDocumentLinksToMap( target, linkMap, (options & HalDocumentLinkRemovalOptions.NonRecursive) == 0, (options & HalDocumentLinkRemovalOptions.Unsafe) != 0); // Build a second map of operation descriptors (needed to invoke the access policy check) to our OpenApiWebLinks. var operationDescriptorMap = linkMap .Keys .Select(link => (Descriptor: new AccessCheckOperationDescriptor(link.Item2.Href, link.Item2.OperationId, link.Item2.OperationType.ToString().ToLowerInvariant()), Link: link)) .GroupBy(x => x.Descriptor) .ToDictionary(descriptor => descriptor.Key, descriptor => descriptor.Select(link => link.Link).ToArray()); AccessCheckOperationDescriptor[] operationDescriptors = operationDescriptorMap.Keys.ToArray(); // Perform the access policy check. IDictionary <AccessCheckOperationDescriptor, AccessControlPolicyResult> accessCheckResults = await that.CheckAccessPoliciesAsync(context, operationDescriptors).ConfigureAwait(false); // Now use the results of the access policy check to remove links/documents that don't belong because the access policy denies them. foreach (KeyValuePair <AccessCheckOperationDescriptor, AccessControlPolicyResult> accessCheckResult in accessCheckResults.Where(result => !result.Value.Allow)) { foreach ((string, OpenApiWebLink)link in operationDescriptorMap[accessCheckResult.Key]) { foreach (HalDocument document in linkMap[link]) { document.RemoveLink(link.Item1, link.Item2); // Also remove from embedded resources if present. document.RemoveEmbeddedResource(link.Item1, link.Item2); } } } }
/// <summary> /// Creates an instance of the <see cref="OpenApiOperationInvoker{TRequest, TResponse}"/>. /// </summary> /// <param name="operationLocator">The operation locator.</param> /// <param name="parameterBuilder">The parameter builder.</param> /// <param name="accessChecker">The access checker.</param> /// <param name="exceptionMapper">The exception mapper.</param> /// <param name="resultBuilder">The result builder.</param> /// <param name="configuration">The <see cref="IOpenApiConfiguration"/>.</param> /// <param name="auditContext">The audit context.</param> /// <param name="logger">The logger.</param> /// <param name="operationsInstrumentation">Operations instrumentation.</param> /// <param name="exceptionsInstrumentation">Exceptions instrumentation.</param> public OpenApiOperationInvoker( IOpenApiServiceOperationLocator operationLocator, IOpenApiParameterBuilder <TRequest> parameterBuilder, IOpenApiAccessChecker accessChecker, IOpenApiExceptionMapper exceptionMapper, IOpenApiResultBuilder <TResponse> resultBuilder, IOpenApiConfiguration configuration, IAuditContext auditContext, ILogger <OpenApiOperationInvoker <TRequest, TResponse> > logger, IOperationsInstrumentation <OpenApiOperationInvoker <TRequest, TResponse> > operationsInstrumentation, IExceptionsInstrumentation <OpenApiOperationInvoker <TRequest, TResponse> > exceptionsInstrumentation) { this.operationLocator = operationLocator; this.parameterBuilder = parameterBuilder; this.accessChecker = accessChecker; this.exceptionMapper = exceptionMapper; this.resultBuilder = resultBuilder; this.auditContext = auditContext; this.logger = logger; this.operationsInstrumentation = operationsInstrumentation; this.configuration = configuration; this.exceptionsInstrumentation = exceptionsInstrumentation; }