public void FieldSecurityChallengeCompletedLogEntry() { var builder = new TestServerBuilder() .AddGraphType <LogTestController>(); builder.User.SetUsername("bobSmith"); var server = builder.Build(); var package = server.CreateFieldContextBuilder <LogTestController>(nameof(LogTestController.ExecuteField2)); var fieldRequest = package.FieldRequest; var authContext = package.CreateAuthorizationContext(); authContext.Result = FieldAuthorizationResult.Fail("test message 1"); var entry = new FieldAuthorizationCompletedLogEntry(authContext); Assert.AreEqual(LogEventIds.FieldAuthorizationCompleted.Id, entry.EventId); Assert.AreEqual(fieldRequest.Id, entry.PipelineRequestId); Assert.AreEqual(fieldRequest.Field.Route.Path, entry.FieldPath); Assert.AreEqual(authContext.User?.RetrieveUsername(), entry.Username); Assert.AreEqual(authContext.Result.Status.ToString(), entry.AuthorizationStatus); Assert.IsNotNull(entry.ToString()); Assert.AreEqual(authContext.Result.LogMessage, entry.LogMessage); }
/// <summary> /// Attempts to authorize the request using the field based <see cref="IAuthorizeData" /> attributes. /// </summary> /// <param name="authRequest">The request to authorize.</param> /// <param name="claimsUser">The claims user provisioned for this run.</param> /// <returns>FieldAuthorizationResult.</returns> private async Task <FieldAuthorizationResult> AuthorizeRequest(IGraphFieldAuthorizationRequest authRequest, ClaimsPrincipal claimsUser) { Validation.ThrowIfNull(authRequest?.Field, nameof(authRequest.Field)); var securityGroups = authRequest.Field.SecurityGroups; if (securityGroups == null || !securityGroups.Any()) { return(FieldAuthorizationResult.Skipped()); } // each security group represents one level of security requirements (e.g. the controller group then the action) // the user must autenticate to each of them in turn. foreach (var group in securityGroups) { if (group.AllowAnonymous) { continue; } // dont inspect these services before this // point in case the only security requirements set are all "allow anonymous" // in which case auth services don't matter if (claimsUser?.Identity == null) { return(FieldAuthorizationResult.Fail("The request contains no user context to validate.")); } if (!claimsUser.Identity.IsAuthenticated) { return(FieldAuthorizationResult.Fail($"The supplied {nameof(ClaimsPrincipal)} was not successfully authenticated.")); } foreach (var rule in group) { if (rule.IsNamedPolicy) { if (_authService == null) { return(FieldAuthorizationResult.Fail( "The field defines authorization policies but " + $"no '{nameof(IAuthorizationService)}' exists to process them.")); } // policy check via the authorization service var authResult = await _authService.AuthorizeAsync(claimsUser, rule.PolicyName).ConfigureAwait(false); if (!authResult.Succeeded) { return(FieldAuthorizationResult.Fail($"Access denied via policy '{rule.PolicyName}'.")); } } if (rule.AllowedRoles.Count > 0) { // check any defined roles if (rule.AllowedRoles.All(x => !claimsUser.IsInRole(x))) { return(FieldAuthorizationResult.Fail("Access denied due to missing a required role.")); } } if (rule.AuthenticationSchemes.Count > 0) { // check against any limiting authentication schemes if (claimsUser.Identities.All(x => !rule.AuthenticationSchemes.Contains(x.AuthenticationType))) { return(FieldAuthorizationResult.Fail("Access denied due to missing a required authentication scheme.")); } } // all checks passed } } return(FieldAuthorizationResult.Success()); }