Azure B2 c авторизация групп безопасности через настраиваемую политику с помощью Rest Post call - PullRequest
0 голосов
/ 05 августа 2020

Я пытаюсь использовать настраиваемые политики, в которых мне удалось развернуть REST API для получения групповых заявлений


    <ClaimsSchema>
          <ClaimType Id="groups">
            <DisplayName>B2C-user-test,B2C-admin-test</DisplayName>
            <DataType>stringCollection</DataType>
          </ClaimType>
    
        <!--Demo: List of permitted  security groups user can sign-in.
            Null or empty means, user any user can sign-in.
            This claim sends to REST API-->
        <ClaimType Id="onlyMembersOf">
            <DisplayName>onlyMembersOf</DisplayName>
            <DataType>string</DataType>
          </ClaimType>
    
        </ClaimsSchema>
        </BuildingBlocks>
          
      <ClaimsProviders>
        <ClaimsProvider>
          <DisplayName>Local Account</DisplayName>
          <TechnicalProfiles>
            <TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
              <OutputClaims>
                <!--Demo: Add the groups claim type to the output claim collection-->
                <OutputClaim ClaimTypeReferenceId="groups" />
              </OutputClaims>
              <ValidationTechnicalProfiles>
                <!-- Demo: Make sure you first call the login-NonInteractive technical profile, to get the user ID.
                     Then call the role-based access control REST API to get adn validate user's groups -->
                <ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
                <ValidationTechnicalProfile ReferenceId="REST-RBAC" />
              </ValidationTechnicalProfiles>        
            </TechnicalProfile>
          </TechnicalProfiles>
        </ClaimsProvider>
    
        <!-- Local account Sign-In claims provider -->
        <ClaimsProvider>
          <DisplayName>Local Account SignIn</DisplayName>
          <TechnicalProfiles>
             <TechnicalProfile Id="login-NonInteractive">
              <Metadata>
                <Item Key="client_id">444b09a2-0f8b-4f05-b454-54495b5ef601</Item>
                <Item Key="IdTokenAudience">bd80807b-81d0-4732-a517-1132b128206c</Item>
              </Metadata>
              <InputClaims>
                <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="444b09a2-0f8b-4f05-b454-54495b5ef601" />
                <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="bd80807b-81d0-4732-a517-1132b128206c" />
              </InputClaims>
            </TechnicalProfile>
          </TechnicalProfiles>
        </ClaimsProvider>
    
    <ClaimsProvider>
          <DisplayName>REST APIs</DisplayName>
          <TechnicalProfiles>
            <TechnicalProfile Id="REST-RBAC">
              <DisplayName>Read and validate user's groups</DisplayName>
              <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
              <Metadata>
                <!--Demo: Change the service URL with your REST API location-->
                <Item Key="ServiceUrl">https://test.azurewebsites.net/api/Identity/IsMemberOf</Item>
                
                <!--Demo: Change the AuthenticationType to basic or ClientCertificate.
                For more information, see: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-custom-rest-api-netfw-secure-cert-->
                <Item Key="AuthenticationType">None</Item>
                <Item Key="SendClaimsIn">Body</Item>
                <Item Key="AllowInsecureAuthInProduction">true</Item>
              </Metadata>
              <CryptographicKeys>
                <Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_RestApiUsername" />
                <Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_RestApiPassword" />
              </CryptographicKeys>
              <InputClaims>
                <InputClaim ClaimTypeReferenceId="objectId" />
                <!--Demo: set the DefaultValue to empty string or comma delimiter list 
                of security groups to validate-->
                <InputClaim ClaimTypeReferenceId="onlyMembersOf" DefaultValue="B2C-user-test" />
              </InputClaims>
              <OutputClaims>
                <OutputClaim ClaimTypeReferenceId="groups" />
              </OutputClaims>
              <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
            </TechnicalProfile>
          </TechnicalProfiles>
        </ClaimsProvider>
      </ClaimsProviders>

, поэтому политика TrustFrameworkExtensions выше вызывает метод Rest, но возвращает исключение оператора catch


    catch (Exception ex)
                {
                    if (ex.Message.Contains("Request_ResourceNotFound"))
                    {
                        return StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not read user groups, user not found", HttpStatusCode.Conflict));
                    }
    
                    return StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not read user groups", HttpStatusCode.Conflict));
                }"

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using AADB2C.RBAC.Sample.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System.Net.Http;


namespace AADB2C.RBAC.Sample.Controllers
{
    [Route("api/[controller]/[action]")]
    public class IdentityController : Controller
    {
        private readonly AppSettingsModel AppSettings;

        // Demo: Inject an instance of an AppSettingsModel class into the constructor of the consuming class, 
        // and let dependency injection handle the rest
        public IdentityController(IOptions<AppSettingsModel> appSettings)
        {
            this.AppSettings = appSettings.Value;
        }

        [HttpPost(Name = "IsMemberOf")]
        public async Task<ActionResult> IsMemberOf()
        {
            string input = null;

            // If not data came in, then return
            if (this.Request.Body == null)
            {
                return StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Request content is null", HttpStatusCode.Conflict));
            }

            //Read the input claims from the request body
            using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
            {
                input = await reader.ReadToEndAsync();
            }

            //string input = Request.Content.ReadAsStringAsync().Result;

            //string content = "";
            //System.Web.HttpContext.Current.Request.InputStream.Position = 0;
            //using (var reader = new StreamReader(
            //         Request.InputStream, System.Text.Encoding.UTF8, true, 4096, true))
            //{
            //    content = reader.ReadToEnd();
            //}
            ////Rest
            //System.Web.HttpContext.Current.Request.InputStream.Position = 0;

            // Check input content value
            if (string.IsNullOrEmpty(input))
            {
                return StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Request content is empty", HttpStatusCode.Conflict));
            }

            // Convert the input string into InputClaimsModel object
            InputClaimsModel inputClaims = InputClaimsModel.Parse(input);

            if (inputClaims == null)
            {
                return StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not deserialize input claims", HttpStatusCode.Conflict));
            }

            if (string.IsNullOrEmpty(inputClaims.objectId))
            {
                return StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("User 'objectId' is null or empty", HttpStatusCode.Conflict));
            }


            try
            {
                AzureADGraphClient azureADGraphClient = new AzureADGraphClient(this.AppSettings.Tenant, this.AppSettings.ClientId, this.AppSettings.ClientSecret);

                // Demo: Get user's groups
                GraphGroupsModel groups = await azureADGraphClient.GetUserGroup(inputClaims.objectId);

                // Demo: Add the groups to string collections
                List<string> groupsList = new List<string>();
                foreach (var item in groups.value)
                {
                    groupsList.Add(item.displayName);
                }

                // Demo: Set the output claims
                OutputClaimsModel output = new OutputClaimsModel() { groups = groupsList };

                // Demo: Check if user needs to be a member of a security group
                if (!string.IsNullOrEmpty(inputClaims.onlyMembersOf))
                {
                    List<string> onlyMembersOf = inputClaims.onlyMembersOf.ToLower().Split(',').ToList<string>();
                    bool isMemberOf = false;
                    foreach (var item in output.groups)
                    {
                        if (onlyMembersOf.Contains(item.ToLower()))
                        {
                            isMemberOf = true;
                            break;
                        }
                    }

                    // Demo: Throw error if user is not member of one of the security groups
                    if (isMemberOf == false)
                    {
                        return StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("You are not authorized to sign-in to this application.", HttpStatusCode.Conflict));
                    }
                }

                // Demo: Return the groups collection
                return Ok(output);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("Request_ResourceNotFound"))
                {
                    return StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not read user groups, user not found", HttpStatusCode.Conflict));
                }

                return StatusCode((int)HttpStatusCode.Conflict, new B2CResponseModel("Can not read user groups", HttpStatusCode.Conflict));
            }

        }

    }
}

Итак, я достиг точки, когда настраиваемая политика использует метод REST POST для получения сведений о группах, но этот упомянутый код не предоставляет мне сведения о группе, поскольку он переходит к оператору catch, а throws не может читать группы пользователей. Проблема здесь в том, что я не могу использовать localhost для запуска Rest API и попадать в точки останова API с помощью настраиваемой политики, поскольку он не поддерживается, я пробовал использовать ngrox.exe, но он возвращает мне неверный запрос.

Any помощь или пример будут очень полезны

...