0
votes

All users have a user attribute "extension_isApproved". They can only log in or receive token when it is set to True. However, I can't figure out how to do this in a ROPC Flow. The behavior I want is to send back an error message if the user asking the tokens is not approved.

I started from the base template found at https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack/blob/master/scenarios/source/aadb2c-ief-ropc/TrustFrameworkExtensions.xml

There is my code (I've already tried some things to restrict the user but it doesn't work):

<TechnicalProfile Id="ResourceOwnerPasswordCredentials-OAUTH2">
      <DisplayName>Local Account SignIn</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <Metadata>
        <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">You are not approved. Contact your administrator for approval.</Item>
        <Item Key="UserMessageIfClaimsPrincipalDoesNotExist">We can't seem to find your account</Item>
        <Item Key="UserMessageIfInvalidPassword">Your password is incorrect</Item>
        <Item Key="UserMessageIfOldPasswordUsed">Looks like you used an old password</Item>
        <Item Key="DiscoverMetadataByTokenIssuer">true</Item>
        <Item Key="ValidTokenIssuerPrefixes">https://sts.windows.net/</Item>
        <Item Key="METADATA">https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration</Item>
        <Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item>
        <Item Key="response_types">id_token</Item>
        <Item Key="response_mode">query</Item>
        <Item Key="scope">email openid</Item>
      </Metadata>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="logonIdentifier" PartnerClaimType="username" Required="true" DefaultValue="{OIDC:Username}"/>
        <InputClaim ClaimTypeReferenceId="password" Required="true" DefaultValue="{OIDC:Password}" />
        <InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" />
        <InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" />
        <InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" />

        <InputClaim ClaimTypeReferenceId="client_id" DefaultValue="{Settings:ProxyIdentityExperienceFrameworkAppId}" />
        <InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="{Settings:IdentityExperienceFrameworkAppId}" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" />
        <OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" />
      </OutputClaims>
      <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID" />
      </OutputClaimsTransformations>
      <ValidationTechnicalProfiles>
        <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingObjectId" />
        <ValidationTechnicalProfile ReferenceId="ClaimsTransformation-AssertIsApproved" />
      </ValidationTechnicalProfiles>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
    </TechnicalProfile>

<ClaimsProvider>
  <DisplayName>Session Management</DisplayName>
  <TechnicalProfiles>
    <TechnicalProfile Id="SM-RefreshTokenReadAndSetup">
      <DisplayName>Trustframework Policy Engine Refresh Token Setup Technical Profile</DisplayName>
      <Protocol Name="None" />
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="objectId" />
        <OutputClaim ClaimTypeReferenceId="refreshTokenIssuedOnDateTime" />
      </OutputClaims>
      <ValidationTechnicalProfiles>
        <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingObjectId" />
        <ValidationTechnicalProfile ReferenceId="ClaimsTransformation-AssertIsApproved" />
      </ValidationTechnicalProfiles>
    </TechnicalProfile>
  </TechnicalProfiles>
</ClaimsProvider>

<ClaimsTransformation Id="AssertIsApproved" TransformationMethod="AssertBooleanClaimIsEqualToValue">
    <InputClaims>
      <InputClaim ClaimTypeReferenceId="extension_isApproved" TransformationClaimType="inputClaim" />
    </InputClaims>
    <InputParameters>
      <InputParameter Id="valueToCompareTo" DataType="boolean" Value="true" />
    </InputParameters>
  </ClaimsTransformation>

The rest of the code is the same as the base template for what touches the ROPC Flow.

2

2 Answers

0
votes

ROPC doesn’t work when there is any interruption to the authentication flow that needs user interaction.For example, when a password has expired or needs to be changed, multi-factor authentication is required, or when more information needs to be collected during sign-in (for example, user consent). Refer this link: https://docs.microsoft.com/en-us/azure/active-directory-b2c/configure-ropc?tabs=app-reg-ga

0
votes

Finally, what we did is to add <OutputClaim ClaimTypeReferenceId="extension_isApproved" /> in the technical profile ROPC_Auth.xml.

By doing that, you will receive the custom attribute directly in the id_token of the response when you call your ROPC flow.

We contacted Microsoft Support and they told us that the way we wanted to do it at first (by blocking the user and returning an error) was too advanced for them and they don't know how to do it or even if it is possible.