Azure / Azure/azure-functions-core-tools

Incorrect results from `ClaimsPrincipal` when running locally

Open
#2,985 1 comment 7 reactions 0 assignees View on GitHub
feature
Dominant language
C#
Stars
1.5k
Forks
498
Avg merge
4d 20h
Merged PRs (30d)
14

Description

We had https://github.com/Azure/static-web-apps-cli/issues/390 reported with the Static Web Apps CLI, in which using a `ClaimsPrincipal` in a C# Function doesn't contain the roles that you would expect and `IsInRole` returns false when it shouldn't, resulting in a different experience with auth locally compared to when it's deployed.

## Context

The SWA CLI provides a mock of EasyAuth, in which you can simulate a flow through and then a token is generated for you. This token is then handled by the proxy in the CLI and serialized before being injected into the `x-ms-client-principal` header. The header can be parsed like so:

```csharp
public static class StaticWebAppsAuth
{
private class ClientPrincipal
{
public string IdentityProvider { get; set; }
public string UserId { get; set; }
public string UserDetails { get; set; }
public IEnumerable UserRoles { get; set; }
}

public static ClaimsPrincipal Parse(HttpRequest req)
{
var principal = new ClientPrincipal();

if (req.Headers.TryGetValue("x-ms-client-principal", out var header))
{
var data = header[0];
var decoded = Convert.FromBase64String(data);
var json = Encoding.UTF8.GetString(decoded);
principal = JsonSerializer.Deserialize(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
}

principal.UserRoles = principal.UserRoles?.Except(new string[] { "anonymous" }, StringComparer.CurrentCultureIgnoreCase);

if (!principal.UserRoles?.Any() ?? true)
{
return new ClaimsPrincipal();
}

var identity = new ClaimsIdentity(principal.IdentityProvider);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, principal.UserId));
identity.AddClaim(new Claim(ClaimTypes.Name, principal.UserDetails));
identity.AddClaims(principal.UserRoles.Select(r => new Claim(ClaimTypes.Role, r)));

return new ClaimsPrincipal(identity);
}
}
```

_[Reference](https://docs.microsoft.com/en-us/azure/static-web-apps/user-information?tabs=csharp#api-functions)_

But when deployed to Azure, the `ClaimsPrincipal` is automatically populated with the claims information from that header and you are not required to do manual parsing. You can see a sample app here https://github.com/aaronpowell/swa-blazor-cli-bug, which is deployed to https://thankful-desert-0d90ef310.1.azurestaticapps.net/secured (yeah, it's an ugly dumping string of claims).

Given that the `x-ms-claims-principal` header that is injected via the SWA CLI can be decoded it's expected that the `ClaimsPrincipal` would contain the same information.

Is it possible to inject a header that the Functions runtime (locally) will be able to create a `ClaimsPrincipal` correctly, or at least one that responds to the `IsInRole` call correctly? (so, mapping the roles from the header payload correctly)

_Aside - I've tried to debug this myself and see where the problem is coming from but I'm unable to find docs on how to do end-to-end debugging of Azure Functions locally. I tried to load symbols from SourceLink but didn't managed to get the debugging working competely (I'm unable to hit the point where it creates the `ClaimsPrincipal`), and when my debugging chain consisted of `SWA CLI` -> `My Functions App` -> `Core Tools` -> `WebJobs Script Host` -> `WebJobs SDK` -> `WebJobs SDK Extensions` I gave up 🤣. I'm yet to find where the `ClaimsPrincipal` is created._

Contributor guide

Open the contributing guide

Research direction

Reproduce the discrepancy across the Static Web Apps CLI, the local Functions app, Core Tools, and the WebJobs host using the x-ms-client-principal header described in the issue. Trace where the local ClaimsPrincipal is created and compare its claims and IsInRole behavior with the deployed app; done means local role claims match the decoded header and deployed behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, csharp
Domain
authentication, cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.