/// <summary> /// Called by the runtime to invoke the middleware logic. In most cases, the middleware component should return the task /// generated by calling the next delegate in the request chain with the provided context. /// </summary> /// <param name="context">The invocation request governing data in this pipeline run.</param> /// <param name="next">The next delegate in the chain to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public async Task InvokeAsync(GraphFieldExecutionContext context, GraphMiddlewareInvocationDelegate <GraphFieldExecutionContext> next, CancellationToken cancelToken) { FieldAuthorizationResult result = FieldAuthorizationResult.Default(); if (context.IsValid) { // execute the authorization pipeline var authRequest = new GraphFieldAuthorizationRequest(context.Request); var authContext = new GraphFieldAuthorizationContext(context, authRequest); await _authPipeline.InvokeAsync(authContext, cancelToken).ConfigureAwait(false); result = authContext.Result ?? FieldAuthorizationResult.Default(); // by default, deny any stati not explicitly declared as "successful" by this component. if (!result.Status.IsAuthorized()) { context.Messages.Critical( $"Access Denied to field {context.Field.Route.Path}", Constants.ErrorCodes.ACCESS_DENIED, context.Request.Origin); } } if (!result.Status.IsAuthorized()) { context.ResolvedSourceItems.AddRange(context.Request.DataSource.Items); context.ResolvedSourceItems.ForEach(x => x.Fail()); } await next(context, cancelToken).ConfigureAwait(false); }
/// <summary> /// Invokes this middleware component allowing it to perform its work against the supplied context. /// </summary> /// <param name="context">The context containing the request passed through the pipeline.</param> /// <param name="next">The delegate pointing to the next piece of middleware to be invoked.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns>Task.</returns> public async Task InvokeAsync(GraphFieldAuthorizationContext context, GraphMiddlewareInvocationDelegate <GraphFieldAuthorizationContext> next, CancellationToken cancelToken) { context.Logger?.FieldResolutionSecurityChallenge(context); var result = await this.AuthorizeRequest(context.Request, context.User).ConfigureAwait(false); context.Result = result ?? FieldAuthorizationResult.Default(); context.Logger?.FieldResolutionSecurityChallengeResult(context); await next(context, cancelToken).ConfigureAwait(false); }
/// <summary> /// Iterates over every secure field in the operation on the context, attempting to authorize the /// user to each one. /// </summary> /// <param name="context">The primary query context.</param> /// <param name="cancelToken">The cancel token.</param> /// <returns><c>true</c> if authorization was successful, otherwise false.</returns> private async Task <bool> AuthorizeOperation(GraphQueryExecutionContext context, CancellationToken cancelToken) { var authTasks = new List <Task>(); bool anyFieldFailed = false; foreach (var fieldContext in context.QueryOperation.SecureFieldContexts) { var authRequest = new GraphFieldAuthorizationRequest(fieldContext); var authContext = new GraphFieldAuthorizationContext(context, authRequest); var pipelineTask = _authPipeline.InvokeAsync(authContext, cancelToken) .ContinueWith( (_) => { var authResult = authContext.Result ?? FieldAuthorizationResult.Default(); // fake the path elements from the field route. since we don't have a full resolution chain // when doing query level authorization (no indexers on potential child fields since // nothing is actually resolved yet) if (!authResult.Status.IsAuthorized()) { context.Messages.Critical( $"Access Denied to field {fieldContext.Field.Route.Path}", Constants.ErrorCodes.ACCESS_DENIED, fieldContext.Origin); anyFieldFailed = true; } }, cancelToken); authTasks.Add(pipelineTask); } await Task.WhenAll(authTasks).ConfigureAwait(false); return(anyFieldFailed); }