How to enable Javascript on Custom Azure AD B2C SignUpOrSignin Policy - azure-active-directory

I am trying to enable Javascript on my custom "SignUpOrSignin.xml" policy, so I can take custom actions on the Reset Password and Sign Up buttons.
I did the following steps on SignUpOrSignin.xml :
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignIn" />
<UserJourneyBehaviors>
<ScriptExecution>Allow</ScriptExecution>
</UserJourneyBehaviors>
.........
.........
.........
</RelyingParty>
and on TrustFrameworkBase.xml :
<ContentDefinition Id="api.signuporsignin">
<LoadUri>https://ttt.blob.core.windows.net/b2c-migration-users/pages/unified.html</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:unifiedssp:1.1.0</DataUri>
<Metadata>
<Item Key="DisplayName">Signin and Signup</Item>
<Item Key="TemplateId">azureBlue</Item>
</Metadata>
</ContentDefinition>
Unfortunetly, when I try to upload the SignUpOrSignin.xml policy in the AAD B2C Instance, I receive the following validation error:
Validation failed: 1 validation error(s) found in policy "B2C_1A_JITMIGRAION_SIGNUP_SIGNIN" of tenant "mytenant.onmicrosoft.com". Please use page contract in content definitions when enabling JavaScript.
What am I missing ? Any help will be much appreciated!

For any ContentDefinition that you want to enable JS on, the DataUri needs to be the contract version. That means urn:com:microsoft:aad:b2c:elements:unifiedssp:1.1.0 needs to be changed to urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:1.2.0 (See Content Definitions Documentation). The page layout version is also different, and you can see what those differences are by going here.

Related

How can I get a value of an open / directory extension in an Azure AD B2C custom policy?

I'm using Microsoft Graph API to set a custom value (string) on a user.
I've tried using both open & directory extensions to store the data and both seem to work fine in the API level as I'm able to get the data back on a user.
What I'm trying to do next is to get the value of this extension into a B2C custom policy claim. I haven't been able to find any documentation that shows how to get an open extension's value in a custom policy even though the docs state it is supported so I've tried doing it with a directory extension.
The extension's name is extension_{appId}_myString and was created through this HTTP call:
POST https://graph.microsoft.com/v1.0/applications/graph-app-object-id/extensionProperties
{
"name": "myString",
"dataType": "String",
"targetObjects": [
"User"
]
}
I've added the claim type definition as follows:
<ClaimType Id="myString">
<DisplayName>This is my string</DisplayName>
<DataType>string</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OpenIdConnect" PartnerClaimType="extension_myString" />
<Protocol Name="OAuth2" PartnerClaimType="extension_myString" />
</DefaultPartnerClaimTypes>
</ClaimType>
My user journey definition:
<UserJourney Id="SignIn">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.selfasserted">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninExchange" TechnicalProfileReferenceId="LocalAccountDiscoveryUsingID" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
I've added this output claim in the technical profiles of steps 1 & 2:
<OutputClaim ClaimTypeReferenceId="myString" PartnerClaimType="extension_myString" />
My AAD-Common technical profile has the b2c-extensions-app client ID & object ID metadata items and I'm able to successfully complete the authentication process and get to the JWT screen but my extension's value isn't shown there.
I don't understand if I did something wrong or just missed another place in which the custom claim should be added in order for it to be shown in the token. Is there some kind of way to "print" the value of the claim to see if it's present in the policy's runtime? At least I know the value is there and I only need to put it in the token..
One more thing that I'm not sure of is the creation of the extension value through Graph API. I've used the graph application's credentials to get the Graph API token and also used it's object ID to create the directory extension on the user object. On the other hand, there's the b2c-extensions-app which is the app that queries the data during the custom policy's runtime. From my understanding both apps work against the same Active Directory instance so it shouldn't be a problem but maybe I misunderstood something.
You can’t. Open extensions are supported by MS Graph API. B2C policy uses AAD Graph behind the scenes, it can only fetch the old extension attribute type. To fetch an open extension, you’d have to call your own api, which in turn calls MS Graph API to fetch this open extension.
Instead of using an open extension use the older type:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/microsoft-graph-operations#application-extension-directory-extension-properties
https://learn.microsoft.com/en-us/graph/api/resources/extensionproperty?view=graph-rest-1.0
For configuring a custom claim in Azure B2C custom profile, as per https://learn.microsoft.com/en-us/azure/active-directory-b2c/user-flow-custom-attributes?pivots=b2c-custom-policy#create-a-custom-attribute-through-azure-portal, you must prefix the claim type ID with extension_ to allow the correct data mapping
Within Claims Schema the claim should be defined as:
The following example demonstrates the use of a custom attribute in Azure AD B2C custom policy in a technical profile, input, output, and persisted claims.
Thanks

Get error "login.live.com page can’t be found" when invoking Azure Ad as external IDP in IdentitySrever4

I try to follow this tutorial to add Azure Ad as another external IDP for my IdentityServer4 service (I have gotten Windows and Google working already). I can get the "Azure Ad" button displayed on my IdentityServer login page now, but when I click on it, I get the following error returned:
Here is how I configured Azure Ad in ConfigureServices of my Startup class. I also tried replacing "aad" with "oidc", which is what I used and worked in Google, but no difference here.
and here is how my Azure Ad account configuration looks like. The colors match up with above indicating the values I use in my code:
Can someone tell me what I may be doing wrong here?
Initially please try by deleting history in the browser and use "login.microsoftonline.com/<tenantId>/v2.0/" as authority string.
And options.CallbackPath = "/signin-oidc"; options.ResponseType = "code id_token";
NOTE : The identity platform which is used by Microsoft has a character limit for links. This type of error will appear if the authorization request or link is longer than the said limit,.
Protocols like OpenID Connect, allow state as a parameter in the authorization request, and the identity provider will return that state in the response as you can find that in error page you provided .
Because of which the request URL becomes large as sometimes the state parameter is long.(which might be the possible case here)
Try to call the AddOidcStateDataFormatterCache extension method on the IServiceCollection in startup class which uses the distributed cache in the backend like:
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddTestUsers(Config.GetUsers());
services.AddAuthentication()
.AddOpenIdConnect("aad", "Azure AD", options =>
{
// ...
})
you can write the way as below :
services.AddOidcStateDataFormatterCache(); //Add this line
services.AddAuthentication()
.AddOpenIdConnect("aad", "Azure AD", options =>
{
// ...
})
You may check these similar References for more details :
Sign-in with External Identity Providers — IdentityServer4 1.0.0 documentation
(Or)
See section : 22.4 Handling the callback and signing in the user in IdentityServer4 Documentation
At least check for dns or firewall issues .

Multiple open id connect ad providers in a CMS setup

The case
Currently trying to setup two AD providers (both on OpenID Connect (OIDC) protocol).
One would need to handle users for the back office and the other should be used in all other cases to login external users with different roles. Content on the website is only accessible for certain roles.
The setup
EPiServer (CMS)
.Net 4.7.2 framework
Important notes:
Both open id connect middlewares are currently set to authentication mode 'active' .
Status
Both AD providers can be challenged directly where the right login portal shows, however there are some problems i cannot explain. Working with two open id connect middelwares is a first for me.
Problem 1
In a CMS setup certain location/paths are defined in the web.config like the following
<location path="episerver">
<system.web>
<authorization>
<allow roles="WebEditors, WebAdmins, Administrators" />
<deny users="*" />
</authorization>
</system.web>
When the '/episerver' path is hit it triggers an authentication flow. If one middleware has been marked to run in the pipeline stage 'authentication' that middleware seems to always handle such requests, however if both middleware are registered to run in same pipeline stage 'authentication' the last registered middleware (in the owin startup file) always seems to handle all requests. Why is that ?
Problem 2
When the first middleware is registered to run for the authentication pipeline stage, and the second is registered to run for a later pipeline stage (the default seems to be 'PreRequestHandlerExecute' when its not specified) another strange behaviour happens.
When any controller that has a '[Authorize]' attribute assigned is hit with a request, my guess would be the first middleware would be challenged because it is the first 'active' middleware defined in the Owin pipeline, however it is the second middleware that is hit. I can't find any explaination on this strange behaviour ?
You need to configure the back-office azure ad config to only trigger on /episerver and the regular users on everything else in startup.cs
Both can use the same cookie auth setup but will need 2 instances of OpenIdConnectAuthenticationOptions, one for each azure ad.
So you can do like this:
app.MapWhen(!ctx.Request.Path.StartsWith("/episerver"), cmsApp =>
{
cmsApp.UseOpenIdConnectAuthentication(cmsOptions);
}
app.Map("/episerver", editorApp =>
{
editorApp.UseOpenIdConnectAuthentication(editorOptions);
}

Azure AD B2C custom Sign Up invitation policy is returning 401 when trying to hit metadata endpoint

I implemented what is described here: Signup with email invitation
This works flawlessly when the Azure app service uses the B2C Azure AD for authentication\login, that is, the invitation e-mail is sent when I'm logged in through an account authenticated by the B2C AD.
Now I have another app service pointing to a B2B Azure AD for user login\authentication and so the invitation e-mail is sent when I'm logged in through an account authenticated by the B2B AD.
The email with the invitation link that points to the B2C AD is sent correctly. However after clicking the link, the B2C signup invitation policy takes action and I'm presented with a 401 error (unauthorized). This looks like the B2C policy can't access the metadata endpoint set in the policy configs for any reason...
The message being displayed is:
Correlation ID: 78292d04-7184-42d0-ac2d-a60bb98a532f
Timestamp: 2019-09-20 16:19:25Z AADB2C: The metadata endpoint
'https://mywebsite.azurewebsites.net/.well-known/openid-configuration'
returned the following status code: '401'
This is the custom signup invitation policy <ClaimsProvider> in which this metadata endpoint is specified:
<!--This technical profile specifies how B2C should validate the token, and what claims you want B2C to extract from the token.
The METADATA value in the TechnicalProfile meta-data is required.
The “IdTokenAudience” and “issuer” arguments are optional (see later section)-->
<ClaimsProvider>
<DisplayName>ID Token Hint ClaimsProvider</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="IdTokenHint_ExtractClaims">
<DisplayName>ID Token Hint TechnicalProfile</DisplayName>
<Protocol Name="None" />
<Metadata>
<!-- Action required: replace with endpoint location -->
<Item Key="METADATA">https://mywebsite.azurewebsites.net/.well-known/openid-configuration</Item>
<!-- <Item Key="IdTokenAudience">your_optional_audience_override</Item> -->
<!-- <Item Key="issuer">your_optional_issuer</Item> -->
</Metadata>
<OutputClaims>
<!--Read the email claim from the id_token_hint-->
<OutputClaim ClaimTypeReferenceId="email" />
<OutputClaim ClaimTypeReferenceId="shardTenantId"/>
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
My question is: why this 401 (unauthorized) is being thrown? When I try to access the metadata endpoint: https://mywebsite.azurewebsites.net/.well-known/openid-configuration it opens just fine and returns the required json output:
{
issuer: "https://mywebsite.azurewebsites.net/",
jwks_uri: "https://mywebsite.azurewebsites.net/.well-known/keys",
id_token_signing_alg_values_supported: [
"RS256"
]
}
This is the web API method that outputs the json described above:
[AllowAnonymous]
[Route(".well-known/openid-configuration", Name = "OIDCMetadata")]
[HttpGet]
public HttpResponseMessage Metadata()
{
var json = JsonConvert.SerializeObject(new OidcModel
{
// The issuer name is the application root path
Issuer = InvitationHelper.GetBaseUrl(),
// Include the absolute URL to JWKs endpoint
JwksUri = Url.Link("JWKS", null),
// Sample: Include the supported signing algorithms
IdTokenSigningAlgValuesSupported = new[] { SigningCredentials.Value.Algorithm }
});
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(json, Encoding.UTF8, "application/json");
return response;
}
I even tried adding [AllowAnonymous] annotation to the API method but that didn't make any change.
Why can't the custom signup invitation policy access the metadata endpoint that is in an app service hosted on a different B2B AD tenant?
NOTE 1: added Application Insights instrumentation to this custom policy and the only message I saw there was Fatal Exception 401 without any more valuable info:
{"Kind":"FatalException","Content":{"Time":"4:15 PM","Exception":{"Kind":"Handled","HResult":"80131500","Message":"The
metadata endpoint
'https://mywebsite.azurewebsites.net/.well-known/openid-configuration'
returned the following status code:
'401'","Data":{"IsPolicySpecificError":false,"uri":"https://mywebsite.azurewebsites.net/.well-known/openid-configuration"}​}}​}
NOTE 2: if you look at the <ClaimsProvider> above there are these 2 settings:
<!-- <Item Key="IdTokenAudience">your_optional_audience_override</Item> -->
<!-- <Item Key="issuer">your_optional_issuer</Item> -->
I'm not sure how to use these other 2 settings as those were not described in the doc # GitHub.
Maybe the issuer is the problem... I'm trying things here but nothing is working so far. So I decided to ask this question. I hope someone can shed some light.
I got in contact with Jas Suri through LinkedIn. He's the guy that did the last commit in that GitHub repo.
He asked me for the real metadata endpoint (the one I posted here is a dummy URL).
When he tried to access that URL he was prompted to login... what!? Login!? Yep. That answered the question. I got SSO here on my developer box and that's why I didn't catch that... but wait: I had [AllowAnonymous] annotation in that web API method, right? So why was it still asking for login!?
He promptly asked me if I had enabled Authentication on the app service level... I went to Azure Portal and checked the app service Authorization/Authentication settings. Guess what... I had it turned ON but the problem was not that directly. See the highlighted setting below:
We can keep it on, but the real problem was that sometime ago I had set
Action to take when request is not authenticated
Log in with Azure Active Directory
That was overrides the [AllowAnonymous] annotation placed on the web API method.
As soon as I selected in the dropdown:
Allow Anonymous requests (no action)
and saved, then the B2C policy started working as expected.
Anonymous access is enabled on the App Service app. Users will not be
prompted for login.

How to change saml2p:NameIDPolicy that wso2is sends to IdP?

I have a WSO2IS 5.2 acting as a federation hub. The AuthnRequest that it sends to IdP (in this case PingFederate) includes this NameIDPolicy:
<saml2p:NameIDPolicy AllowCreate="true"
Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
SPNameQualifier="WSO2IS"
xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"
/>
After logging in at PingFederate it sends back SAML message including this:
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Requester">
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy" />
</samlp:StatusCode>
<samlp:StatusMessage>Cannot provide requested name identifier qualified with WSO2IS</samlp:StatusMessage>
</samlp:Status>
I've tried uid and mail NameID values in PingFederate but I always get this response. I would like to try changing the NameIDPolicy format that wso2is sends but have not found a way to do it. I think it should be a SAML:2.0 format.
Only thing I found was "Include NameID Policy" check box in IdP settings but it stays checked even if I uncheck it and save.
How to change the NameIDPolicy format?
UPDATE: I solved the problem by enabling pseudonym identifier at PingFederate and sending username as attribute. Still it would be good to know the answer to my question.
Yes your understanding is correct. You could need to change the NameIDPolicy. You can found it in service provider (SP) creation page. Go to WSO2 IS management console, Home>service Provider>Add> .
After that need to enter the name for SP and click the register button.
Now you are in Service provider configuration page.
GO to Inbound Authentication Configuration>SAML2 Web SSO Configuration>configure.
This page you can configure SAML2 Web SSO configuration and page header show as
Register New Service Provider and go to NameID format change the urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress instead of urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress.
You can found more details from WSO2 documentation [1].
[1] https://docs.wso2.com/display/IS500/Configuring+Single+Sign-On+with+SAML+2.0

Resources