How to populate a string collection from a REST API response - azure-ad-b2c

How can I populate a StringCollection from a REST API call in an Azure AD B2C custom policy?
My Rest API is returning this as its ResponseContent
class ResponseContent {
public string version;
public int status;
public string[] strings;
}
new ResponseContent
{
version = "1.0.0",
status = (int) HttpStatusCode.OK,
strings= new [] { "str1", "str2", "str3", "str4", "str5"}
},
The technical profile executes as expected but when it populates the StringCollection shows in the claims bag via the Journey Recorder as a list of strings
When I try and show these as a dropdown list in a self-asserted page the list is empty.
Is this possible to do this and if so how?
Here is my claim definition, as you can see no Enumeration
<ClaimType Id="strings">
<DisplayName>Strings to be populated from REST Service </DisplayName>
<DataType>stringCollection</DataType>
<AdminHelpText>blah.</AdminHelpText>
<UserHelpText>blah.</UserHelpText>
<UserInputType>DropdownSingleSelect</UserInputType>
</ClaimType>
<!-- here is the technical profile that i am using to populate the claims from it -->
</TechnicalProfile>
<TechnicalProfile Id="Populate-strings-from-app">
<DisplayName>Populate-Strings</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="AuthenticationType">None</Item>
<Item Key="ServiceUrl">XXXXXXXX</Item>
<Item Key="SendClaimsIn">QueryString</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="client_id" PartnerClaimType="client_id" DefaultValue="{OIDC:ClientId}" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="strings" />
</OutputClaims>
</TechnicalProfile>
In the claims bag I can see it is showing as a generic list which means I think i should be doing a transformation on it but i dont know if i have ever seen a dynamic transformation on a list without knowing what every element is

This is unfortunately not supported today :-( The only way to populate the enumeration is by providing a list of values in the policy.
I would recommend adding this as a suggestion on the Azure AD B2C feedback page for Azure AD (or vote for one if it already exists).

Related

How to map OutputClaims with Json keys containing a dot (.) with Azure AD B2C Custom Policy

I need to develop a RESTful technical profile that is able to pass a JSON response such as:
{
"somekey.withadot": "Some value"
}
My technical profile is as follows:
<TechnicalProfile Id="SomeId">
<DisplayName>Some displayname</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="SendClaimsIn">Url</Item>
<Item Key="ServiceUrl">https://someurl.com</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="UseClaimAsBearerToken">identityProviderAccessToken</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="identityProviderAccessToken" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="somekey" PartnerClaimType="somekey.withadot"/>
</OutputClaims>
</TechnicalProfile>
However, Azure AD B2C tries parsing the JSON as a nested body due to their dot notation. Has anybody come up with a solution to this?
Set ResolveJsonPathsInJsonTokens metadata item to false.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/restful-technical-profile#metadata
Key
Required
Description
ResolveJsonPathsInJsonTokens
No
Indicates whether the technical profile resolves JSON paths. Possible values: true, or false (default). Use this metadata to read data from a nested JSON element. In an OutputClaim, set the PartnerClaimType to the JSON path element you want to output. For example: firstName.localized, or data[0].to[0].email.
Update: I have been in contact with Azure. The engineers from the engineering team who have been investigating it did some additional testing and the conclusion was: if JSON parameter name contains a dot (example: somekey.withadot) then the claim cannot be passed regardless of whether ResoveJsonPathsInJsonTokens is set to true or false. The expectation is that the JSON property name does not contain a dot.
The team does not consider this a bug because the JSON property is not expected to contain a dot, but the team will submit this as a feature and also update the public document on ResoveJsonPathsInJsonTokens.
Update: It has been added as a feature request: https://feedback.azure.com/d365community/idea/23e6ae2b-4fdb-ec11-a81b-0022484ee92d

B2C- Customization of signing up page (custom policy)

UPDATE
I used split email verification and sign up for my sign up process.
On the 4th page I added a button to allow changing the email address.
How to allow user to reset email validation (picture 1) when he clicks on the change email button, knowing that at this step of process, the input "email" and the button for sending code "email_ver_but_send" are not hidden but not exist when inspecting the page?
Those are my pages for signing up :
1-Validation email
2- Validate code
3- Change email
4- Create account
My questions are :
1- How to hide continue and cancel buttons in steps 1-2-3 and only display them in the 4th step of the process?
2- After checking the code (step 2), how to go directly to step 4?
Thanks for help
There is a metadata setting called setting.showCancelButton that can be added to the self asserted technical profile. This has the possible value of true for showing the button and false for not showing the button.
Here is an example
<TechnicalProfile Id="SelfAsserted-Page">
<DisplayName>Self Asserted Page</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="setting.showCancelButton">false</Item>
</Metadata>
<InputClaims>
</InputClaims>
<OutputClaims>
</OutputClaims>
</TechnicalProfile>
More information about the metadata keys for self-asserted technical profiles can be found on the Microsoft documentation website.

Modify the JwtIssuer ClaimsProvider in the custom policy to remove the Refresh Token in AD B2C

I'm trying to add a custom policy without refresh token
I've modifiy the ClaimsProviders this way :
<ClaimsProvider>
<DisplayName>Token Issuer</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="JwtIssuer">
<DisplayName>JWT Issuer</DisplayName>
<Protocol Name="None" />
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="client_id">{service:te}</Item>
<Item Key="SendTokenResponseBodyWithJsonNumbers">true</Item>
<Item Key="AuthenticationContextReferenceClaimPattern">None</Item>
<Item Key="token_lifetime_secs">3600</Item>
<!-- 1 H -->
<Item Key="id_token_lifetime_secs">3600</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims />
<OutputClaims />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
But it's not working.
I'm facing this js error when I try to sign in :
main.js:1 ERROR ServerError: server_error: AADB2C: Issuer technical profile 'JwtIssuer' must specify a 'issuer_refresh_token_user_identity_claim_type' to use this OAuth flow
Correlation ID: bab26044-1e53-4b4a-b5c9-d2f35030a9d7
Any ideas ?
Thanks :)
Thanks for the comment #paralight. We need to apply some workaround to achieve the same as there is no way to remove the refresh token and no direct modifications to the JWTIssuer technical profile.
Workaround:
Force a session time out by adding a tag UserJourneyBehaviors in custom policy. ex :
<UserJourneyBehaviors> <SingleSignOn Scope="Application" /> <SessionExpiryType>Absolute</SessionExpiryType> <SessionExpiryInSeconds>900</SessionExpiryInSeconds> </UserJourneyBehaviors>
Other scenario :
Claims information in the JWT token is exposed to the public. To store some sensitive information in the JWT token
Workaround: You can send claims to a REST API and send them back to B2C to encrypt.
You would create an orchestration step before the SendClaims step to send all claims to a REST API, and have the REST API respond with encrypted versions of those claims
JWT Token issuer reference https://learn.microsoft.com/en-us/azure/active-directory-b2c/jwt-issuer-technical-profile
REST API usage https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-rest-api-claims-exchange
Reference : All Technical Profiles : https://learn.microsoft.com/en-us/azure/active-directory-b2c/technicalprofiles
Reference SO Thread: Modify the JwtIssuer ClaimsProvider in the custom policy to achieve the JWE in AD B2C
Adding your comment as answer and glad to know your queries are addressed. You can accept it as answer( click on the check mark beside the answer to toggle it from greyed out to filled in). This can be beneficial to other community members.

Is it possible to force all Azure AD B2C MFA to be phone calls and never SMS?

If this can be done through configuration great.
I'd also accept customising the UI to hide the buttons that refer to SMS if possible.
It is possible in built-in policies (user flows) using a custom page UI which hides the SMS button.
It is possible in custom policies using metadata as follows.
The phone factor provider provides supports the following metadata:
setting.authenticationMode: Possible values: mixed, phone, or sms. The mixed value indicates both the "call" and "text" options are presented. The phone value indicates only the "call" option is presented. The sms value indicates only the "text" option is presented.
setting.autodial: Possible values: true or false. If setting.authenticationMode is set to call or sms and this is set to true, then the phone number is dialled or messaged automatically without any user interaction.
Example:
<ClaimsProvider>
<DisplayName>PhoneFactor</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="PhoneFactor-InputOrVerify">
<DisplayName>PhoneFactor</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.PhoneFactorProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="setting.authenticationMode">phone</Item>
<Item Key="setting.autodial">true</Item>
</Metadata>
...
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>

Mapping claims with Azure AD B2C Custom Identity Provider (OpenID Connect)

Although, I've set all the claim mappings well so they match those issued by our Identity Server 3, we don't seem to have those values on Azure AD side. Name and email are claims which can be used as an example. And which is weird, this happens only with Custom Identity Provider (Open ID Connect) while for example Facebook built-in Identity Provider works well and takes those claims received from IdP. Is there anyone who made this work ever?
[EDITED]
Additionally, I have also tried to achieve this trough custom polices as it was suggested here: How to store claims from IdentityServer 3 in Azure AD B2C or just include it in tokens issued by AAD B2C. Now, I'm facing with another problem to simply connect AAD B2C to Identity Server 3 by using custom policies. Here is my TechnicalProfile definition from TrustFrameworkExnsion.xml:
<TechnicalProfile Id="IdentityServerProfile">
<DisplayName>IdentityServer</DisplayName>
<Description>Login with your IdentityServer account</Description>
<Protocol Name="OpenIdConnect"/>
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="METADATA">https://{identity_server_hostname}/identity/.well-known/openid-configuration</Item>
<Item Key="ProviderName">https://{identity_server_hostname}/identity</Item>
<Item Key="client_id">00000000-0000-0000-0000-000000000000</Item>
<Item Key="IdTokenAudience">00000000-0000-0000-0000-000000000000</Item>
<Item Key="response_types">code</Item>
<Item Key="scope">openid profile customScope</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="AccessTokenResponseFormat">json</Item>
<Item Key="HttpBinding">POST</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_IdentityServerAppSecret"/>
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="IdentityServer" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="tid" />
<OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="sub" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop"/>
</TechnicalProfile>
Basically, after authentication on IdentityServer side, I got redirected back to my web page which initialized the sign-in and then I get this error:
AADB2C: An exception has occurred.
Correlation ID: 6797f691-4adb-4963-ad12-f31add3e1919
Timestamp: 2018-08-23 08:42:54Z
While analyzing the log on AAD B2C for the given correlation ID, I didn't find anything useful which would lead me to the possible solution.
Yesterday, after quiet a long time spent on trying so many different things, I finally realized why we were not getting all claims back on the client. They actually didn't exist in identity token but only in access token. AAD B2C uses the first one, the identity token, while doing mappings defined in custom policies and that was the whole point. In the end I had to make some small changes on IdentityServer3 side (take a look at the code below).
This is how the class which is responsible for issuing claims and generating both identity and access tokens now looks like:
public class CustomClaimsProvider : DefaultClaimsProvider
{
private readonly IIndex claimDefinitions;
public CustomClaimsProvider(
IUserService users,
IIndex<string, IClaimsDefinition> claimDefinitions)
: base(users)
{
this.claimDefinitions = claimDefinitions;
}
public override async Task<IEnumerable<Claim>> GetIdentityTokenClaimsAsync(
ClaimsPrincipal subject,
Client client,
IEnumerable<Scope> scopes,
bool includeAllIdentityClaims,
ValidatedRequest request)
{
var claims = await base.GetIdentityTokenClaimsAsync(subject, client, scopes, includeAllIdentityClaims, request).ConfigureAwait(false);
return GetAdditionalClaims(scopes, claims);
}
public override async Task<IEnumerable<Claim>> GetAccessTokenClaimsAsync(
ClaimsPrincipal subject,
Client client,
IEnumerable<Scope> scopes,
ValidatedRequest request)
{
var claims = await base.GetAccessTokenClaimsAsync(subject, client, scopes, request).ConfigureAwait(false);
return GetAdditionalClaims(scopes, claims);
}
private IEnumerable<Claim> GetAdditionalClaims(IEnumerable<Scope> scopes, IEnumerable<Claim> claims)
{
var scopesList = scopes.ToList();
var claimsList = claims.ToList();
foreach (var scope in scopesList.Select(x => x.Name))
{
if (claimDefinitions.TryGetValue(scope, out IClaimsDefinition claimDef))
{
claimsList.AddRange(claimDef.GetClaims(claims));
}
}
return claimsList;
}
}
So, the main point is, you should also override GetIdentityTokenClaimsAsync method in the class derived from DefaultClaimsProvider if you want to have some additional claims as a part of your identity token.
Big thanks to Microsoft Support which helped me a lot with troubleshooting the issue.

Resources