Skip to content

Commit

Permalink
add test verifying that we can login users with a jwt from query para…
Browse files Browse the repository at this point in the history
…ms, fix bug where forgot password would not authenticate because of duplicate jti claims
  • Loading branch information
hahn-kev committed Nov 21, 2023
1 parent 1773b99 commit 64704ca
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 6 deletions.
2 changes: 1 addition & 1 deletion backend/LexBoxApi/Auth/JwtTicketDataFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static string ConvertAuthTicketToJwt(AuthenticationTicket data,
{
var jwtDate = DateTime.UtcNow;
_jwtSecurityTokenHandler.MapInboundClaims = jwtBearerOptions.MapInboundClaims;
var claimsIdentity = new ClaimsIdentity(data.Principal.Claims, data.Principal.Identity?.AuthenticationType);
var claimsIdentity = new ClaimsIdentity(data.Principal.Claims.Where(c => c.Type != JwtRegisteredClaimNames.Jti), data.Principal.Identity?.AuthenticationType);
var keyId = Guid.NewGuid().ToString().GetHashCode().ToString("x", CultureInfo.InvariantCulture);
claimsIdentity.AddClaim(new Claim(JwtRegisteredClaimNames.Jti, keyId));
//there may already be an audience claim, we want to reuse that if it exists, if not fallback to the default audience
Expand Down
38 changes: 33 additions & 5 deletions backend/Testing/LexCore/LexAuthUserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Logging;
using Microsoft.IdentityModel.Tokens;
using Shouldly;

namespace Testing.LexCore;

public class LexAuthUserTests
{
static LexAuthUserTests()
{
IdentityModelEventSource.ShowPII = true;
}
private readonly LexAuthService _lexAuthService = new LexAuthService(
new OptionsWrapper<JwtOptions>(JwtOptions.TestingOptions),
null,
Expand All @@ -30,6 +35,12 @@ public class LexAuthUserTests
Projects = new[] { new AuthUserProject("test-flex", ProjectRole.Manager, Guid.NewGuid()) }
};

private static readonly JwtBearerOptions JwtBearerOptions = new()
{
TokenValidationParameters = LexAuthService.TokenValidationParameters(JwtOptions.TestingOptions),
MapInboundClaims = false
};

[Fact]
public void CanGetClaimsFromUser()
{
Expand Down Expand Up @@ -73,11 +84,7 @@ public void CanRoundTripClaimsWhenUsingSecurityTokenDescriptor()
var jwt = JwtTicketDataFormat.ConvertAuthTicketToJwt(
new AuthenticationTicket(_user.GetPrincipal("test"), "test"),
"testing",
new JwtBearerOptions
{
TokenValidationParameters = LexAuthService.TokenValidationParameters(jwtUserOptions),
MapInboundClaims = false
},
JwtBearerOptions,
jwtUserOptions
);
var tokenHandler = new JwtSecurityTokenHandler();
Expand All @@ -97,4 +104,25 @@ public void CanRoundTripJwtFromUserThroughLexAuthService()
var newUser = LexAuthUser.FromClaimsPrincipal(principal);
_user.ShouldBeEquivalentTo(newUser);
}

[Fact]
public void CanRoundTripThroughRefresh()
{
var (forgotJwt, _) = _lexAuthService.GenerateJwt(_user, audience:LexboxAudience.ForgotPassword);
//simulate parsing the token into a claims principal
var tokenHandler = new JwtSecurityTokenHandler();
var forgotPrincipal = new ClaimsPrincipal(new ClaimsIdentity(tokenHandler.ReadJwtToken(forgotJwt).Claims, "Testing"));

//simulate redirect refreshing the token
var redirectJwt = JwtTicketDataFormat.ConvertAuthTicketToJwt(
new AuthenticationTicket(forgotPrincipal, "test"),
"testing",
JwtBearerOptions,
JwtOptions.TestingOptions
);

var loggedInPrincipal = new ClaimsPrincipal(new ClaimsIdentity(tokenHandler.ReadJwtToken(redirectJwt).Claims, "Testing"));
var newUser = LexAuthUser.FromClaimsPrincipal(loggedInPrincipal);
(_user with { Audience = LexboxAudience.ForgotPassword }).ShouldBeEquivalentTo(newUser);
}
}

0 comments on commit 64704ca

Please sign in to comment.