0

I can't get past this weird exception. Please, need your help.

Even though Application Insights (in vscode) shows that the email claim is in fact retrieved, I keep getting this error and don't make it to the Saml2Issuer orchestration step, hence, no SAML token. See the screenshot form the ApplicationInsights extension in vscode. Sensitive information screened. The claimsTransformation shown copies user email from an extension attribute into the email claim, which is to b eused in the SAML token.

Screenshot from Application Insights vscode extension

RP File (irrelevant parts removed)

<TrustFrameworkPolicy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06" PolicySchemaVersion="0.3.0.0" TenantId="{Settings:Tenant}" PolicyId="B2C_1A_signup_signin_saml" PublicPolicyUri="http://{Settings:Tenant}/B2C_1A_signup_signin_saml" DeploymentMode="Development" UserJourneyRecorderEndpoint="urn:journeyrecorder:applicationinsights">

  <BasePolicy>
    <TenantId>{Settings:Tenant}</TenantId>
    <PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
  </BasePolicy>


  <RelyingParty>
    <DefaultUserJourney ReferenceId="SignUpOrSignIn" />
    <UserJourneyBehaviors>
      <SingleSignOn Scope="Tenant" />
      <SessionExpiryType>Absolute</SessionExpiryType>
      <SessionExpiryInSeconds>86400</SessionExpiryInSeconds>
      <JourneyInsights TelemetryEngine="ApplicationInsights" InstrumentationKey="{Settings:ApplicationInsightskey}" DeveloperMode="true" ClientEnabled="false" ServerEnabled="true" TelemetryVersion="1.0.0" />
      <!-- Enable JavaScript-->
      <ScriptExecution>Allow</ScriptExecution>
    </UserJourneyBehaviors>
    <TechnicalProfile Id="PolicyProfile">
      <DisplayName>PolicyProfile</DisplayName>
      <Protocol Name="SAML2"/>
      <Metadata>
        <Item Key="XmlSignatureAlgorithm">Sha256</Item>
      </Metadata>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="displayName" />
        <OutputClaim ClaimTypeReferenceId="givenName" />
        <OutputClaim ClaimTypeReferenceId="surname" />
        <OutputClaim ClaimTypeReferenceId="email"/>
        <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="" />
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="objectId"/>
      </OutputClaims>
      
      <SubjectNamingInfo ClaimType="email" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" ExcludeAsClaim="true"/>
    </TechnicalProfile>
  </RelyingParty>
</TrustFrameworkPolicy>

TFE File (irrelevant parts removed)

<TrustFrameworkPolicy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06" PolicySchemaVersion="0.3.0.0" TenantId="{Settings:Tenant}" PolicyId="B2C_1A_TrustFrameworkExtensions" PublicPolicyUri="http://{Settings:Tenant}/B2C_1A_TrustFrameworkExtensions">


  <BasePolicy>
    <TenantId>{Settings:Tenant}</TenantId>
    <PolicyId>B2C_1A_TrustFrameworkBase</PolicyId>
  </BasePolicy>
  <BuildingBlocks>

    <ClaimsSchema>
...
...
      
      <!--Overriding this here to add a partner claim type for SAML2-->
      <ClaimType Id="email">
        <DisplayName>Email Address</DisplayName>
        <DataType>string</DataType>
        <DefaultPartnerClaimTypes>
          <Protocol Name="OpenIdConnect" PartnerClaimType="email" />
          <Protocol Name="SAML2" PartnerClaimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" />
        </DefaultPartnerClaimTypes>

      </ClaimType>

      <ClaimType Id="extension_XXXX">
        <DisplayName>Email Address</DisplayName>
        <DataType>string</DataType>
        <DefaultPartnerClaimTypes>
          <Protocol Name="OpenIdConnect" PartnerClaimType="extension_XXXX" />
          <Protocol Name="SAML2" PartnerClaimType="extension_XXXX" />
        </DefaultPartnerClaimTypes>
        <UserInputType>TextBox</UserInputType>
      </ClaimType>

     ...
    </ClaimsSchema>

    <ClaimsTransformations>
      <!--We use this claims transformation to copy the value in extension_ExternalUserEmail claim to the
      email claim after extension_XXXX is read from AAD using the AAD-UserReadWithObjectId Technical Profile. 
      -->
      <ClaimsTransformation Id="CopyXXXXEmailAddress" TransformationMethod="CopyClaim">
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="extension_XXXX" TransformationClaimType="inputClaim"/>
        </InputClaims>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="email" TransformationClaimType="outputClaim"/>
        </OutputClaims>
      </ClaimsTransformation>
      ...
    </ClaimsTransformations>

    <ContentDefinitions>
...
    </ContentDefinitions>



  </BuildingBlocks>

  <ClaimsProviders>
    <ClaimsProvider>
      <DisplayName>Application Insights</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="AppInsights-Common">
          <DisplayName>Application Insights</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.Insights.AzureApplicationInsightsProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <!-- The ApplicationInsights instrumentation key, which you use for logging the events -->
            <Item Key="InstrumentationKey">{Settings:ApplicationInsightskey}</Item>
            <Item Key="DeveloperMode">true</Item>
            <Item Key="DisableTelemetry ">false</Item>
          </Metadata>
          <InputClaims>
            <!-- Properties of an event are added through the syntax {property:NAME}, where NAME is the property being added to the event. DefaultValue can be either a static value or a value that's resolved by one of the supported DefaultClaimResolvers. -->
            <InputClaim ClaimTypeReferenceId="EventTimestamp" PartnerClaimType="{property:EventTimestamp}" DefaultValue="{Context:DateTimeInUtc}" />
            <InputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="{property:TenantId}" DefaultValue="{Policy:TrustFrameworkTenantId}" />
            <InputClaim ClaimTypeReferenceId="PolicyId" PartnerClaimType="{property:Policy}" DefaultValue="{Policy:PolicyId}" />
            <InputClaim ClaimTypeReferenceId="CorrelationId" PartnerClaimType="{property:CorrelationId}" DefaultValue="{Context:CorrelationId}" />
            <InputClaim ClaimTypeReferenceId="Culture" PartnerClaimType="{property:Culture}" DefaultValue="{Culture:RFC5646}" />
          </InputClaims>
        </TechnicalProfile>

        <TechnicalProfile Id="AppInsights-SignInRequest">
          <InputClaims>
            <!-- An input claim with a PartnerClaimType="eventName" is required. This is used by the AzureApplicationInsightsProvider to create an event with the specified value. -->
            <InputClaim ClaimTypeReferenceId="EventType" PartnerClaimType="eventName" DefaultValue="SignInRequest" />
          </InputClaims>
          <IncludeTechnicalProfile ReferenceId="AppInsights-Common" />
        </TechnicalProfile>

        <TechnicalProfile Id="AppInsights-UserSignUp">
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="EventType" PartnerClaimType="eventName" DefaultValue="UserSignUp" />
          </InputClaims>
          <IncludeTechnicalProfile ReferenceId="AppInsights-Common" />
        </TechnicalProfile>

        <TechnicalProfile Id="AppInsights-SignInComplete">
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="EventType" PartnerClaimType="eventName" DefaultValue="SignInComplete" />
            <InputClaim ClaimTypeReferenceId="federatedUser" PartnerClaimType="{property:FederatedUser}" DefaultValue="false" />
            <InputClaim ClaimTypeReferenceId="parsedDomain" PartnerClaimType="{property:FederationPartner}" DefaultValue="Not Applicable" />
            <InputClaim ClaimTypeReferenceId="identityProvider" PartnerClaimType="{property:IDP}" DefaultValue="Local" />
          </InputClaims>
          <IncludeTechnicalProfile ReferenceId="AppInsights-Common" />
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>


    <ClaimsProvider>
      <DisplayName>Local Account</DisplayName>
      <TechnicalProfiles>
        ...
      </TechnicalProfiles>
    </ClaimsProvider>


    <ClaimsProvider>
      <DisplayName>Azure Active Directory</DisplayName>
      <TechnicalProfiles>
        ...
      </TechnicalProfiles>
    </ClaimsProvider>

    <ClaimsProvider>
      <DisplayName>Local Account SignIn</DisplayName>
      <TechnicalProfiles>
        <!-- This technical profile is used to read a local B2C user from AAD using an objectId.
        I am overriding it here so as to call the CopyXXXXEmailAddress Claims Transformation, which
        will copy the value in the extension_XXXX claim to the email claim. That way, when I add the email
        claim to output claims, there is something in it when it is added to the claims bag. So,
        when the email claim is used in the technical profile (PolicyProfile) in the relying party file
        to populate the NameID attribute in the Subject Naming Info element, it is not null. If it is,
        this error is thown "The relying party technical profile of policy 'B2C_1A_signup_signin_saml'
        in tenant '<tenant>.onmicrosoft.com' specifies the claim type 'email' as the subject naming info 
        claim, but the claim is not present or is null" -->
        <TechnicalProfile Id="AAD-UserReadUsingObjectId">
          <OutputClaims>
            <!--Read user's email from extension attribute-->
            <OutputClaim ClaimTypeReferenceId="extension_XXXX"/>

          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CopyXXXXEmailAddress" />
            
          </OutputClaimsTransformations>
        </TechnicalProfile>


...
      </TechnicalProfiles>
    </ClaimsProvider>

    <ClaimsProvider>
      <DisplayName>Self Asserted</DisplayName>
      <TechnicalProfiles>
...
      </TechnicalProfiles>
    </ClaimsProvider>

  </ClaimsProviders>

  <UserJourneys>
    <UserJourney Id="SignUpOrSignIn">
      <OrchestrationSteps>

        <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
          <ClaimsProviderSelections>

            <ClaimsProviderSelection TargetClaimsExchangeId="MyOrgExchange" />
            
            <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
          </ClaimsProviderSelections>
          <ClaimsExchanges>
            <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
          </ClaimsExchanges>
        </OrchestrationStep>


        <!-- Check if the user has selected to sign in using one of the social providers -->
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>

            <ClaimsExchange Id="MyOrgExchange" TechnicalProfileReferenceId="OIDC-MyOrg" />
            <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
            <ClaimsExchange Id="TrackSignInRequest" TechnicalProfileReferenceId="AppInsights-SignInRequest" />
            
          </ClaimsExchanges>
        </OrchestrationStep>

       
        <!-- For social IDP authentication, attempt to find the user account in the directory. -->
        <OrchestrationStep Order="3" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>authenticationSource</Value>
              <Value>localAccountAuthentication</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId-NoError" />
          </ClaimsExchanges>
        </OrchestrationStep>

        
        <!-- This step reads any user attributes that we may not have received when authenticating using ESTS so they can be sent 
          in the token. -->
        <OrchestrationStep Order="4" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimEquals" ExecuteActionsIf="true">
              <Value>authenticationSource</Value>
              <Value>socialIdpAuthentication</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
          </ClaimsExchanges>
        </OrchestrationStep>

        ...

        <OrchestrationStep Order="10" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="Saml2AssertionIssuer" />

        <!-- Track that we have successfully sent a token -->
        <OrchestrationStep Order="11" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="TrackSignInComplete" TechnicalProfileReferenceId="AppInsights-SignInComplete" />
          </ClaimsExchanges>
        </OrchestrationStep>

      </OrchestrationSteps>
      <ClientDefinition ReferenceId="DefaultWeb" />
    </UserJourney>


  </UserJourneys>

</TrustFrameworkPolicy>
Bandz
  • 253
  • 4
  • 15

0 Answers0