Skip to content

Commit 7b28c2b

Browse files
Fix JWT DateTimeOffset handling with DateTime.MinValue (#33651)
1 parent e858e3d commit 7b28c2b

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

src/Security/Authentication/JwtBearer/src/JwtBearerHandler.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
143143
SecurityToken = validatedToken
144144
};
145145

146-
tokenValidatedContext.Properties.ExpiresUtc = validatedToken.ValidTo;
147-
tokenValidatedContext.Properties.IssuedUtc = validatedToken.ValidFrom;
146+
tokenValidatedContext.Properties.ExpiresUtc = GetSafeDateTime(validatedToken.ValidTo);
147+
tokenValidatedContext.Properties.IssuedUtc = GetSafeDateTime(validatedToken.ValidFrom);
148148

149149
await Events.TokenValidated(tokenValidatedContext);
150150
if (tokenValidatedContext.Result != null)
@@ -202,6 +202,17 @@ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
202202
}
203203
}
204204

205+
private static DateTime? GetSafeDateTime(DateTime dateTime)
206+
{
207+
// Assigning DateTime.MinValue or default(DateTime) to a DateTimeOffset when in a UTC+X timezone will throw
208+
// Since we don't really care about DateTime.MinValue in this case let's just set the field to null
209+
if (dateTime == DateTime.MinValue)
210+
{
211+
return null;
212+
}
213+
return dateTime;
214+
}
215+
205216
/// <inheritdoc />
206217
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
207218
{

src/Security/Authentication/test/JwtBearerTests.cs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,47 @@ public async Task ExpirationAndIssuedSetOnAuthenticateResult()
846846
Assert.Equal(token.ValidFrom, dom.RootElement.GetProperty("issued").GetDateTimeOffset());
847847
}
848848

849+
[Fact]
850+
public async Task ExpirationAndIssuedNullWhenMinOrMaxValue()
851+
{
852+
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(new string('a', 128)));
853+
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
854+
855+
var claims = new[]
856+
{
857+
new Claim(ClaimTypes.NameIdentifier, "Bob")
858+
};
859+
860+
var token = new JwtSecurityToken(
861+
issuer: "issuer.contoso.com",
862+
audience: "audience.contoso.com",
863+
claims: claims,
864+
expires: DateTime.MaxValue,
865+
signingCredentials: creds);
866+
867+
var tokenText = new JwtSecurityTokenHandler().WriteToken(token);
868+
869+
using var host = await CreateHost(o =>
870+
{
871+
o.SaveToken = true;
872+
o.TokenValidationParameters = new TokenValidationParameters()
873+
{
874+
ValidIssuer = "issuer.contoso.com",
875+
ValidAudience = "audience.contoso.com",
876+
IssuerSigningKey = key,
877+
};
878+
});
879+
880+
var newBearerToken = "Bearer " + tokenText;
881+
using var server = host.GetTestServer();
882+
var response = await SendAsync(server, "http://example.com/expiration", newBearerToken);
883+
Assert.Equal(HttpStatusCode.OK, response.Response.StatusCode);
884+
var responseBody = await response.Response.Content.ReadAsStringAsync();
885+
using var dom = JsonDocument.Parse(responseBody);
886+
Assert.Equal(JsonValueKind.Null, dom.RootElement.GetProperty("expires").ValueKind);
887+
Assert.Equal(JsonValueKind.Null, dom.RootElement.GetProperty("issued").ValueKind);
888+
}
889+
849890
class InvalidTokenValidator : ISecurityTokenValidator
850891
{
851892
public InvalidTokenValidator()
@@ -1065,7 +1106,7 @@ private static async Task<IHost> CreateHost(Action<JwtBearerOptions> options = n
10651106
{
10661107
var authenticationResult = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
10671108
await context.Response.WriteAsJsonAsync(
1068-
new { Expires = authenticationResult.Properties.ExpiresUtc, Issued = authenticationResult.Properties.IssuedUtc });
1109+
new { Expires = authenticationResult.Properties?.ExpiresUtc, Issued = authenticationResult.Properties?.IssuedUtc });
10691110
}
10701111
else
10711112
{

0 commit comments

Comments
 (0)