Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why is the 'identityProvider' claim missing in the ClaimsPrincipal running in an Azure Function v2? #4212

Closed
kzryzstof opened this issue Mar 20, 2019 · 8 comments

Comments

@kzryzstof
Copy link

I have an Azure Function App that is deployed in 2 environments, one for Development and one Production, each with their own URL.

In both environments, the functions are configured to enable users to authenticate using their Facebook account. I actually configured 2 different Facebook applications: one for Development environment and one for the Production environment.

Here is the code of one Azure Function which simply logs in Application Insights all the headers of the HTTP request as well as all the claims of the injected ClaimsPrincipal instance:

public sealed class FindAccountFunction
{
    private readonly ILogger m_logger;

    public FindAccountFunction(ILoggerFactory loggerFactory)
    {
        m_logger = loggerFactory.CreateLogger<FindAccountFunction>();
    }

    [FunctionName("FindAccount")]
    public async Task<IActionResult> Run(
            [HttpTrigger(
                AuthorizationLevel.Function,
                "get",
                Route = "v1/accounts"
            )]
            HttpRequest httpRequest,
            ClaimsPrincipal claimsPrincipal)
     {
         // Logs all Headers of the httpRequest
         // Logs all the claims of claimsPrincipal.

         return new OkObjectResult("Ok");
     }
}

Everything works great in the Production environment because I can identify the user connected by getting the nameidentifier and the identityprovider claims, as seen in the following logs:

Logs with stable_sid

The problem appears in the Development environment. For some reason, I am getting a number as the nameidentifier (instead of an hexadecimal number starting with sid:) and the identityprovider is missing altogether from the claims:

Logs without stable_sid

Question

What can cause the nameidentifier to be a number in the Development environment and the identityprovider claim to be missing from the ClaimsPrincipal instance?

Is there any permissions that could be missing?

Update

I have added the setting WEBSITE_AUTH_HIDE_DEPRECATED_SID and set it to true in both environments.

Here is the JWT token from the Development environment:

{
  "sub": "sid:a3xxxxxxxxxxxxx",
  "idp": "facebook",
  "ver": "4",
  "iss": "https://dev.company.ca/",
  "aud": "https://dev.company.ca/",
  "exp": 1557524710,
  "nbf": 1552343212
}

Here is the JWT token from the Production environment:

{
  "sub": "sid:06afxxxxxxxx",
  "idp": "facebook",
  "ver": "4",
  "iss": "https://prod.company.ca/",
  "aud": "https://prod.company.ca/",
  "exp": 1557526156,
  "nbf": 1552342494
}

Still, the Development environment did not provide the expected identityprovider claim and the nameidentifier claim in the ClaimsPrincipal instance is different from the JWT's.

For now, as a workaround, I simply use the JWT to extract the sid but I would rather have the framework to provide me this.

@mhoeger
Copy link
Contributor

mhoeger commented Mar 29, 2019

@ConnorMcMahon - are you the right person to look into this?

@ConnorMcMahon ConnorMcMahon self-assigned this Mar 29, 2019
@ConnorMcMahon
Copy link
Contributor

@kzryzstof

There are two places you should check.

  1. Take the X-MS-CLIENT-PRINCIPAL headers from both scenarios, and base64 decode them. This is the json representation of the ClaimsPrincipal object we use to actually populate the value in Azure Functions. See if there are any obvious differences in the json.

  2. Hit the /.auth/me endpoint with an authenticated request for both scenarios. See if there are any obvious differences in the claims listed at that endpoint.

Depending on what differences appear in those locations, it will tell us where in the pipeline something went wrong.

@ghost
Copy link

ghost commented Apr 3, 2019

This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment.

@kzryzstof
Copy link
Author

kzryzstof commented Apr 3, 2019

@ConnorMcMahon

Here is the information that you requested. Looking into the X-MS-CLIENT-PRINCIPAL header, the most obvious thing is the auth_type that is different. The one that I am expecting is Federation and the other one that I do not like is Facebook. I am not sure yet what it means and I will continue investigating.

Prod environment

X-MS-CLIENT-PRINCIPAL

As can be seen here, X-MS-CLIENT-PRINCIPAL contains the sid as the nameidentifier claim:

{
  "auth_typ": "Federation",
  "claims": [
    {
      "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
      "val": "sid:06af45xxxxxxxxxxxx"
    },
    {
      "typ": "http://schemas.microsoft.com/identity/claims/identityprovider",
      "val": "facebook"
    },
    {
      "typ": "ver",
      "val": "4"
    },
    {
      "typ": "iss",
      "val": "https://demo****.nosuchcompany.ca/"
    },
    {
      "typ": "aud",
      "val": "https://demo****.nosuchcompany.ca/"
    },
    {
      "typ": "exp",
      "val": "1559424452"
    },
    {
      "typ": "nbf",
      "val": "1554294202"
    }
  ],
  "name_typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
  "role_typ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
}

However the nameidentifier claim returned by .auth/me is different here:

.auth/me

UserClaims = {List<Claim>} Count = 5
 [0] = {Claim} "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 101XXXXXXX"
 [1] = {Claim} "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: christophe*********@********.ca"
 [2] = {Claim} "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: Christophe XXXXXX"
 [3] = {Claim} "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname: Christophe"
 [4] = {Claim} "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname: XXXXX"

X-ZUMO-AUTH

Here is the X-ZUMO-AUTH header as well:

{
  "sub": "sid:06af4xxxxxxx",
  "idp": "facebook",
  "ver": "4",
  "iss": "https://demo*****.nosuchcompany.ca/",
  "aud": "https://demo****.nosuchcompany.ca/",
  "exp": 1559424452,
  "nbf": 1554294202
}

Dev environment

As you can see, in this environment, there are no differences between X-MS-CLIENT-PRINCIPAL and .auth/me:

X-MS-CLIENT-PRINCIPAL

{
  "auth_typ": "facebook",
  "claims": [
    {
      "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
      "val": "101XXXXXXXXXXXX"
    },
    {
      "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
      "val": "Christophe XXXXX"
    },
    {
      "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
      "val": "Christophe"
    },
    {
      "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
      "val": "XXXXXX"
    }
  ],
  "name_typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
  "role_typ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
}

.auth/me

UserClaims = {List<Claim>} Count = 4
 [0] = {Claim} "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier: 101XXXXXXX"
 [1] = {Claim} "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: Christophe XXXXX"
 [2] = {Claim} "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname: Christophe"
 [3] = {Claim} "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname: XXXXXX"

However the X-ZUMO-AUTH does contain the "right" information, including the sid which I expect to be the nameidentifier claims:

{
  "sub": "sid:a3b0fXXXXXXXXXXXXXX",
  "idp": "facebook",
  "ver": "4",
  "iss": "https://demo*****-dev.nosuchcompany.ca/",
  "aud": "https://demo*****-dev.nosuchcompany.ca/",
  "exp": 1559428253,
  "nbf": 1554293587
}

@kzryzstof
Copy link
Author

kzryzstof commented Apr 4, 2019

I tried to find any differences between the two registered applications in Facebook (the prod one and the dev one) but I got nothing. I also looked into the Identification / Authorization of the two Function Apps (the prod one and the dev one) and again, nothing obviously different...

@ConnorMcMahon
Copy link
Contributor

ConnorMcMahon commented Apr 5, 2019

Ah, I think I understand what is going on here.

Summary: The App Service Authentication/Authorization feature made a breaking change for X-ZUMO-AUTH token behavior for apps that enabled EasyAuth after mid-2018. That breaking change is being reverted in the next few weeks.

Workaround

In the meantime, if you want your dev application behavior to match your production application's behavior, you can do so by deleting the "runtimeVersion" property in your site auth settings. You can do so with the following.

  1. Navigate to https://resources.azure.com/
  2. Via the drop down menus on the side, navigate to subscriptions > (subName) > resourceGroups > (resourceGroupName) > providers > Microsoft.Web > sites > (siteName) > config > authSettings.
  3. Edit the json object under properties and set "runtimeVersion" to "".
  4. Use the PUT operation to make those changes.
  5. If these steps were successful you should see "runtimeVersion" no longer present in your application.

NOTE: If you disable and then reenable Authentication/Authorization at any point, it will add a value for "runtimeVersion", and you will have to follow the above steps again to remove it.

More Details if interested

When first designing this feature, we thought we wanted the ClaimsPrincipal that was returned to have the same claims regardless of whether the customer was using server-directed flow (browser redirect) or client-directed flow (X-ZUMO-AUTH). Before mid-2018, this was not the case; if you used client-directed flow, the ClaimsPrincipal would be populated with the claims of the X-ZUMO-AUTH jwt token. If you used server-directed flow, it would populate the claims based on what the identity provider you used gave us in the id token.

To achieve this parity, in mid-2018 we updated the App Service Authentication/Authorization feature (EasyAuth) to use the claims from the original id-token if using client-directed flow instead of the claims from the zumo token jwt. Since this was technically a breaking change, we put this behind a site auth setting: "runtimeVersion". This site auth setting is not exposed in the Portal, however it is something you can view on https://resources.azure.com/ or via ARM. Only apps created after ~ July 2018 had a value for "runtimeVersion" set, so only new applications received this new behavior.

It turns out it was a good thing we only affected new applications, as it turns out this broke new apps that were trying to use Azure Mobile Apps (you can see here at this issue). We realized that having this breaking change without a major version change of the Authentication/Authorization feature was a bad idea; we are in the process of releasing an update to the features that reverts the ClaimsPrincipal behavior to the way it was before mid 2018, regardless of whether or not a value is set for "runtimeVersion". This update should be out in the near future (next few weeks), and should make your dev application's behavior identical to your production app's behavior.

Sorry for the inconvenience this has caused. Our upcoming update should fix this, so that new applications and old applications should behave the same way.

@kzryzstof
Copy link
Author

kzryzstof commented Apr 6, 2019

@ConnorMcMahon Thank you for the quick and detailed answer. I really appreciate it!

I followed the procedure you provided and it does work. My dev environment now does get the "right" information (i.e. the one I was expecting) :)

I had a question opened on stack overflow for this issue. Would you prefer I let you post this as an answer or is that ok if I copy-paste your answer and provide a link to the github issue?

@fabiocav
Copy link
Member

@kzryzstof thank you for the follow up. @ConnorMcMahon will be out for the next few days, so I'll let him follow up on the SO question when he gets back.

Closing this as resolved.

@Azure Azure locked as resolved and limited conversation to collaborators Dec 31, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants