コード例 #1
0
        /// <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());
        }