0
votes

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...

enter image description here

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.

1

1 Answers

0
votes

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:

enter image description here

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.