azure-activedirectory-identitymodel-extensions-for-dotnet
azure-activedirectory-identitymodel-extensions-for-dotnet copied to clipboard
[Bug] when read claims from JWT is skipping even claims and only reading odds.
Which version of Microsoft.IdentityModel are you using? 7.5.0
Where is the issue?
- [x] M.IM.JsonWebTokens
- [ ] M.IM.KeyVaultExtensions
- [ ] M.IM.Logging
- [ ] M.IM.ManagedKeyVaultSecurityKey
- [ ] M.IM.Protocols
- [ ] M.IM.Protocols.OpenIdConnect
- [ ] M.IM.Protocols.SignedHttpRequest
- [ ] M.IM.Protocols.WsFederation
- [ ] M.IM.TestExtensions
- [ ] M.IM.Tokens
- [ ] M.IM.Tokens.Saml
- [ ] M.IM.Validators
- [ ] M.IM.Xml
- [x] S.IM.Tokens.Jwt
- Other (please describe)
Is this a new or an existing app? The app is on development.
Repro Attached is a UnitTest project which includes three tests:
- The first test is designed to fail in order to demonstrate the error.
- The second test includes additional claims to show that the library skips even-numbered claims, yet it passes because the extra claims help by making the real ones able to be read.
- The final test demonstrates other issues stemming from this error, such as failing to validate the Issuer, audience, or expiration. These issues depend on whether the preceding number of claims results in an even or odd total.
Expected behavior When claims are added to the token, all of them should be retrievable independen of the order or parity.
Actual behavior The library is skipping one claim in between. To be more precise, the odd-numbered claims are retrievable, while the even-numbered claims are skipped. It appears that everything was fine until version 7.3.1. However, if you test it with version 7.4 or higher, the bug will start to appear.
Same problem. Every second claim is skipped, including the expiration date (which breaks the JWT logic). The JwtPayload.CreatePayload method uses Utf8JsonReader to parse the token and calls reader.Read() each time to read the value and keys forward. Therefore my first guess: it must be a misplaced “reader.Read()” in the code.
I debugged the parsing loop cycle in case of a custom claim-id/name and it led me to the first (reader index at first Entry.Key), second (first Entry.Value) and third (second Entry.Key) reader.Read() in one cycle. When the parsing cycle tries to parse the next key it gets value of the second Entry.
I reverted to 7.3.1 as @jmborroto said and it works again.
@jmborroto & @ArthurSett, issue is related to dependency mismatch on the test you provide, please update your transitive dependencies to match Version="7.5.0" for certain transitive dependencies.
Please try the following in on the JWT token Test.csproj.
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.3" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.5.0" />
<PackageReference Include="Microsoft.IdentityModel.Protocols" Version="7.5.0" />
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="7.5.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="xunit" Version="2.7.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
Please confirm if this works to close this issue. Thanks!
This is a new project created only to add the test class and added the MI.JsonWebToken nugget package to make it easy to demonstrate, if any dependency that is needed is not included by default is because the nugget package is not configured to include the correct ones. That also caused issues in our big project where we first notice the issue so if the nugget package is not fix then anyone just installing the nugget package will have the same issue.
We are working on this issue but, we are tracking it on a separate issue here https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/2513 to avoid having multiple issues related to the same bug please refer to the status of https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/2513.
Yikes I just ran into this when I installed Openiddict and it referneced a newer version of the identity model packages, but the Identity openIDConnect was an old version being referneced by Aspnet.Core JwtBearer. I hope this can get figured out so it's less painful to debug.
I'm confused as to how to solve this. I have recently upgraded to .NET 8.0 and also upgraded the Microsofr.IdentityModel and System.IdentityModel packages. All of those packages are at 7.6.0 and I'm still experiencing this issue. Here are all of my packages.
<PackageReference Include="AWSSDK.AWSMarketplaceMetering" Version="3.7.300.103" />
<PackageReference Include="AWSSDK.MarketplaceEntitlementService" Version="3.7.302.20" />
<PackageReference Include="AWSSDK.RDS" Version="3.7.313.11" />
<PackageReference Include="AWSSDK.SSO" Version="3.7.300.103" />
<PackageReference Include="AWSSDK.SSOOIDC" Version="3.7.302.14" />
<PackageReference Include="Braintree" Version="5.25.0" />
<PackageReference Include="CustomerApi" Version="1.0.0-CI-20231122-210852" />
<PackageReference Include="Duende.IdentityServer.AspNetIdentity" Version="7.0.5" />
<PackageReference Include="EntityFramework6.Npgsql" Version="6.4.3" />
<PackageReference Include="EventApi" Version="1.0.0-CI-20231115-172843" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="IdentityModel" Version="7.0.0" />
<PackageReference Include="MediaTypeMap.Core" Version="2.3.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.6" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Extensions" Version="8.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.6" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.6" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="3.1.32" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Features" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Features" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.10.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.10.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="7.6.0" />
<PackageReference Include="Microsoft.TypeScript.MSBuild" Version="5.4.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="3.0.0" />
<PackageReference Include="Serilog.Enrichers.Sensitive" Version="1.7.3" />
<PackageReference Include="Serilog.Sinks.Datadog.Logs" Version="0.5.2" />
<PackageReference Include="System.IO.FileSystem.Watcher" Version="4.3.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Reactive.Linq" Version="6.0.1" />
<PackageReference Include="System.Xml.XmlSerializer" Version="4.3.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.2" />
<PackageReference Include="Mono.TextTemplating" Version="2.3.1" />
<PackageReference Include="Mono.TextTemplating.Roslyn" Version="2.3.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SharpZipLib" Version="1.4.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.6.2" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.6.0" />
<PackageReference Include="Venminder.CQRS" Version="1.2.1" />
@ItWorksOnMyMachine , @jmborroto . I was experiencing this issue in a project that I upgraded from .net 6 to .net 8. I was able to fix these replacing the way I was reading the JWT. I was previously using System.IdentityModel.Tokens.Jwt and I replace it to Microsoft.IdentityModel.JsonWebTokens. I change the way I generate token to use JsonWebTokenHandler instead of JwtSecurityTokenHandler. And I did the same changes to read the claims from jwt token. Here's the code. Hope it helps.
public static IEnumerable<Claim> ReturnClaimsFromToken(string tk) { JsonWebTokenHandler tokenHandler = new JsonWebTokenHandler(); JsonWebToken jwtToken = tokenHandler.ReadJsonWebToken(tk); return jwtToken.Claims; }
The versions of packages are:
"Microsoft.IdentityModel.JsonWebTokens" Version="7.6.2" "Microsoft.IdentityModel.Tokens" Version="7.6.2"
Ok, I punted on upgrading from 7.6.0 and just dropped back to 7.3.1. Now that the 8.X versions are out I tried again and I'm still having problems getting things to work. @SamuelFormigheri , I'm not doing anything with the JWT myself. This is all Microsoft middleware invoked as part of the AddOpenIdConnect() wireup. This is stock stuff that's just simply failing. I discovered it was reading every other claim by turning off the "Just my code" setting in Visual Studion and stepping into the framework code in my debugger. So, what works is net8.0 framework with all libraries upgraded except the Microsoft.IdentityModel.* and System.IdentityModel.*. Those have to stay at 7.3.1.
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "oidc";
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
// Cookie wireup bits here
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = appSettings.Authority;
options.RequireHttpsMetadata = true;
options.ClientId = appSettings.ClientID;
options.ResponseType = "code";
options.UsePkce = true;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("<scope I care about>");
options.Scope.Add("<scope I care about>");
options.Scope.Add("<scope I care about>");
options.Scope.Add("<scope I care about>");
});
Ok, a few minutes after posting my last I found the issue. That's how it always happens. I decided to validate the transitive versions of the relevant packages. I ran the following: dotnet list package --include-transitive | sls "Microsoft.IdentityModel|System.IdentityModel"
What I found is that I had a transitive dependency on Microsoft.IdentityModel.Protocols and Microsoft.IdentityModel.Protocols.OpenIdConnect, both for version 7.1.2. These transitive dependencies came from Microsoft.AspNetCore.Authentication.JwtBearer.8.0.7. So, if you have upgraded to net8.0 and take out a direct dependency on any of the .IdentityModel. packages, make sure you take out a direct reference on ALL of those packages because the AspNetCore framework does not depend on the latest versions and it will cost you literally days of your life and handfuls of hair.
@ItWorksOnMyMachine @hahn-kev @jmborroto We will be tracking this issue over here as it is a duplicate. closing this one.