Azure AD B2C Custom policy SignUp & SignIn with MFA and with force password after 90 days - azure-ad-b2c

I am trying to integrate this policy to my policy:
https://github.com/azure-ad-b2c/samples/blob/master/policies/force-password-reset-after-90-days/readme.md
extension_passwordResetOn custom user attribute
I created the required custom user attribute.
Next, I edited the extensions file and the file for signin by changing the user journey.
Note that client id and object id are deliberately set to "test" to paste the code here.
I expect that when I register a new user it will set the date to 0 and after 90 days it will ask me for a change.
at the moment if I try to make a registration when I try to submit the form with the data I get a message saying "An invalid value was presented for a property".
An invalid value was presented for a property
I share relying party file: https://easyupload.io/a4tclj
This is my extension file:
'''
<BasePolicy>
<TenantId>b2c.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkLocalization</PolicyId>
</BasePolicy>
<!-- <BuildingBlocks>
<ClaimsSchema>
</ClaimsSchema>
</BuildingBlocks> -->
<ClaimsProviders>
<ClaimsProvider>
<DisplayName>Facebook</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="Facebook-OAUTH">
<Metadata>
<Item Key="client_id">facebook_clientid</Item>
<Item Key="scope">email public_profile</Item>
<Item Key="ClaimsEndpoint">https://graph.facebook.com/me?fields=id,first_name,last_name,name,email</Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Token Issuer</DisplayName>
<TechnicalProfiles>
<!-- SAML Token Issuer technical profile -->
<TechnicalProfile Id="Saml2AssertionIssuer">
<DisplayName>Token Issuer</DisplayName>
<Protocol Name="SAML2" />
<OutputTokenFormat>SAML2</OutputTokenFormat>
<CryptographicKeys>
<Key Id="SamlAssertionSigning" StorageReferenceId="B2C_1A_SAML" />
<Key Id="SamlMessageSigning" StorageReferenceId="B2C_1A_SAML" />
</CryptographicKeys>
<InputClaims />
<OutputClaims />
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Saml-issuer" />
</TechnicalProfile>
<!-- Session management technical profile for SAML-based tokens -->
<TechnicalProfile Id="SM-Saml-issuer">
<DisplayName>Session Management Provider</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.SSO.SamlSSOSessionProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Local Account SignIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="login-NonInteractive">
<Metadata>
<!-- ProxyIdentityExperienceFrameworkAppId -->
<Item Key="client_id">1257aca9-6111-abcs-adca-d740612012fa</Item>
<!-- IdentityExperienceFrameworkAppId -->
<Item Key="IdTokenAudience">10f6e761-c111-dadd-acv0-affb3875cdaf</Item>
</Metadata>
<InputClaims>
<!-- ProxyIdentityExperienceFrameworkAppId -->
<InputClaim ClaimTypeReferenceId="client_id" DefaultValue="1257aca9-6111-abcs-adca-d740612012fa" />
<!-- IdentityExperienceFrameworkAppId -->
<InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="10f6e761-c111-dadd-acv0-affb3875cdaf" />
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Local Account</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="LocalAccountWritePasswordUsingObjectId">
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-Common">
<Metadata>
<!--Insert b2c-extensions-app application ID here, for example: 11111111-1111-1111-1111-111111111111-->
<Item Key="ClientId">83axdc56-1aaa-4bbb-a666-4589cbb7a212</Item>
<!--Insert b2c-extensions-app application ObjectId here, for example: 22222222-2222-2222-2222-222222222222-->
<Item Key="ApplicationObjectId">8d93c18a-d111-4fff-8aaa-43ebedadd5b1</Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
<!--UserJourneys>
</UserJourneys-->
'''
this is what is see with fidler:
fidler capture

#denisdm91 As I am not able to see the files I think you might have found the issue. If not, FYI, the custom attribute you have created a portal is of type Boolean but in policy the same is of "datetime" dataatype. You need to delete the same from portal.

Related

Set up sign-in for multi-tenant Azure Active Directory using custom policies in Azure Active Directory B2C

I have following the tutorial
https://learn.microsoft.com/en-us/azure/active-directory-b2c/identity-provider-azure-ad-multi-tenant?pivots=b2c-user-flow
I have a button showing up and it looks like it works but when I login with a work account I get
Selected user account does not exist in tenant 'Default Directory' and
cannot access the application '' in that tenant. The account needs to
be added as an external user in the tenant first. Please use a
different account.
It seems to work with a gmail account but not another tenant's account.
My question is how do I get it to work with another tenants account
Here are my 3 custom xml files
https://easyupload.io/m/w0gxlj
I tried to reproduce the same in my environment and got the same error as below:
To resolve the error, please try the below:
I created an Azure AD Application and configured redirect URI:
Now, I created a Policy Key like below:
To configure Azure AD as Identity Provider, I added the ClaimsProvider in the TrustFrameworkExtensions.xml file like below:
<ClaimsProvider>
<Domain>testaadb2c01</Domain>
<DisplayName>Common AAD</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AADCommon-OpenIdConnect">
<DisplayName>Common AAD</DisplayName>
<Description>Login with your Contoso account</Description>
<Protocol Name="OpenIdConnect"/>
<Metadata>
<Item Key="METADATA">https://login.microsoftonline.com/testaadb2c.onmicrosoft.com/v2.0/.well-known/openid-configuration</Item>
<!-- Update the Client ID below to the Application ID -->
<Item Key="client_id">CLIENTID</Item>
<Item Key="response_types">id_token</Item>
<Item Key="scope">openid profile</Item>
<Item Key="response_mode">form_post</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="DiscoverMetadataByTokenIssuer">true</Item>
<Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com/</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_AADAppSecret"/>
</CryptographicKeys>
<OutputClaims>
------
</OutputClaims>
<OutputClaimsTransformations>
------
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin"/>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-Common">
<DisplayName>Azure Active Directory</DisplayName>
<Metadata>
<Item Key="ApplicationObjectId">OBJECTID</Item>
<Item Key="ClientId">CLIENTID</Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Local Account SignIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="login-NonInteractive">
<Metadata>
<Item Key="client_id">CLIENTID</Item>
<Item Key="IdTokenAudience">AUDIENCE</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="client_id" DefaultValue="XXXXXX"/>
<InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="XXXXXX"/>
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
When I run the custom Policy, I got the login screen successfully like below:
When I tried to login with AzureAD User account, I am able to sign-in successfully like below:

Calling secure REST API from Azure B2C custom policy to embed claims

I am trying to consume a Azure B2C secured API as part of the user journey by creating custom policies. I have created a claims provider to procure a bearer token as below
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="SecureREST-AccessToken">
<DisplayName></DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://***.b2clogin.com/***.onmicrosoft.com/B2C_1A_SignUpOrSignIn/oauth2/v2.0/authorize</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Form</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_SecureRESTClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_SecureRESTClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="https://***.onmicrosoft.com/profileapi/profileapi-scope" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
And another claims provider to call my secure REST API as below
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AzureFunctions-GetRole">
<DisplayName>Get Roles </DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://***.azurewebsites.net/api/UserProfiles/CheckAdminUser</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="bearerToken"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="IsAdminUser" PartnerClaimType="IsAdminUser" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
How do I tie these two up? Should these be two steps in the user journey?
AAD B2C endpoint doesn’t support client credentials flow. Your initial call to get a token should model AAD client credentials flow:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
You would call these technical profiles from the user journey if they return no possibility of an error to the user. Or otherwise as validation technical profiles referenced from a self asserted technical profile.

Azure B2C not sending email address as input claim to REST API validation service

I'm trying to retrieve claims from a REST API service as described in https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-rest-api-claims-exchange. I'm trying to pass in the login email addres as an InputClaim along with another input claim (AzureTenantID). For some reason the API is always receiving the email InputClaim as empty. The other claim is populated, because it has a default value.
My understanding from the documentation is that this should work but for some reason it does not. Can anyone help me understand what I might be doing wrong? Do I have to specify a value for email?
My redacted technical profile is below. Thank you.
<TechnicalProfiles>
<!-- Custom Restful service -->
<TechnicalProfile Id="REST-API-ValidateEmail">
<DisplayName>Validate user's input data and return UserId claim</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://[servicename].azurewebsites.net/[methodname]</Item>
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">Basic</Item>
<!-- REMOVE the following line in production environments -->
<!--<Item Key="AllowInsecureAuthInProduction">true</Item>-->
</Metadata>
<CryptographicKeys>
<!-- B2C_1A_B2cRestClientId = WebServiceUser -->
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_B2cRestClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_B2cRestClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="AzureTenantId" PartnerClaimType="AzureTenantId" DefaultValue="[tenant].onmicrosoft.com" />
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="UserId" PartnerClaimType="UserId" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
<!-- Change LocalAccountSignUpWithLogonEmail technical profile to support your validation technical profile -->
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="UserId" PartnerClaimType="UserId" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-API-ValidateEmail" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
</TechnicalProfiles>
Please refer this GitHub link to Integrate REST API claims exchanges in your Azure AD B2C user journey to validate user input.
Technical profile
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="REST-ValidateProfile">
<DisplayName>Check loyaltyId Azure Function web hook</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://your-account.azurewebsites.net/api/ValidateProfile?code=your-code</Item>
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">None</Item>
<!-- REMOVE the following line in production environments -->
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="loyaltyId" />
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="userLanguage" PartnerClaimType="lang" DefaultValue="{Culture:LCID}" AlwaysUseDefaultValue="true" />
</InputClaims>
<OutputClaims>
<!-- Claims parsed from your REST API -->
<OutputClaim ClaimTypeReferenceId="promoCode" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
#Jas-Suri provided the correct answer in comments above. The proper claim to use in this scenario is signInName.

How to set SendClaimsIn for azure ad b2c REST call

I have created an AAD B2C custom policy which makes a call to call our REST API when a new user signs up by creating a custom Azure AD B2C custom policy.But i have to set two values to REST API. Ocp-Apim-Subscription-Key in header and email id in body.but i have to set SendClaimsIn only as either header or body.
so i added SendClaimsIn as header.But i cdont know how to set both values as inputclaim.My code is
<ClaimsProvider>
<DisplayName>Signup REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="REST-ValidateProfile">
<DisplayName>Check loyaltyId Azure Function web hook</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://myapicall.io/api/</Item>
<Item Key="SendClaimsIn">Header</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BearerAuthenticationToken" StorageReferenceId="B2C_1A_RestApiBearerToken" />
</CryptographicKeys>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="grant_type" "DefaultValue"="Ocp-Apim-Subscription-Key"/>
</InputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
its shows validation error while uploading
makes a reference to ClaimType with id "Ocp-Apim-Subscription-Key" but
neither the policy nor any of its base policies contain such an
element
i want to set header as Ocp-Apim-Subscription-Key as "12345"
Add the following inside of the <ClaimsSchema> tag near the top of the file:
<ClaimType Id="Ocp-Apim-Subscription-Key">
<DisplayName>OCP APIM Subscription Key</DisplayName>
<DataType>string</DataType>
</ClaimType>
Change the values inside of the <InputClaims> in your REST-ValidateProfile technical profile to the following:
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="Ocp-Apim-Subscription-Key" DefaultValue="12345" />
</InputClaims>
You don't need a grant_type input claim for a static OAuth2 bearer (see here).

Azure B2C - Custom policies / Add registration step

I'm trying to create a custom policy that will add additional step during the sign up/in process to requires more information.
I added:
1. New ClaimsProvider
<ClaimsProviders>
<ClaimsProvider>
<DisplayName>Self Asserted</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="GetCity">
<DisplayName>Local Account Sign In</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="city" Required="true" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop"/>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
New claim type
city
string
city
TextBox
New output claim in SignupSignIn RP
Additional steps before send claims during the UserJourney - SignUpOrSignIn
After the registration there is no authentication and there is no step for "city" data.
Any idea where is the problem? I already configured app insight, but there is no errors there.

Resources