Skip to content

Commit

Permalink
Use DateTimeOffset for claims fields
Browse files Browse the repository at this point in the history
  • Loading branch information
mtmk committed Aug 23, 2024
1 parent 9646d72 commit e4331b1
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 37 deletions.
19 changes: 10 additions & 9 deletions NATS.Jwt.Tests/Models/JwtClaimsDataTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Text.Json;
using NATS.Jwt.Models;
using Xunit;
Expand All @@ -16,12 +17,12 @@ public void SerializeDeserialize_FullJwtClaimsData_ShouldSucceed()
{
Audience = "test_audience",
Id = "test_id",
IssuedAt = 1609459200, // 2021-01-01
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
Issuer = "test_issuer",
Name = "Test JWT",
Subject = "test_subject",
Expires = 1735689600, // 2025-01-01
NotBefore = 1609459200, // 2021-01-01
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600), // 2025-01-01
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
};

string json = JsonSerializer.Serialize(claims);
Expand Down Expand Up @@ -53,10 +54,10 @@ public void SerializeDeserialize_MinimalJwtClaimsData_ShouldSucceed()
Assert.Equal(claims.Issuer, deserialized.Issuer);
Assert.Null(deserialized.Audience);
Assert.Null(deserialized.Id);
Assert.Equal(0, deserialized.IssuedAt);
Assert.Null(deserialized.IssuedAt);
Assert.Null(deserialized.Name);
Assert.Equal(0, deserialized.Expires);
Assert.Equal(0, deserialized.NotBefore);
Assert.Null(deserialized.Expires);
Assert.Null(deserialized.NotBefore);
}

[Fact]
Expand All @@ -76,10 +77,10 @@ public void Deserialize_ExtraFields_ShouldIgnore()
Assert.Equal("test_issuer", deserialized.Issuer);
Assert.Null(deserialized.Audience);
Assert.Null(deserialized.Id);
Assert.Equal(0, deserialized.IssuedAt);
Assert.Null(deserialized.IssuedAt);
Assert.Null(deserialized.Name);
Assert.Equal(0, deserialized.Expires);
Assert.Equal(0, deserialized.NotBefore);
Assert.Null(deserialized.Expires);
Assert.Null(deserialized.NotBefore);
}

[Fact]
Expand Down
6 changes: 3 additions & 3 deletions NATS.Jwt.Tests/Models/NatsAccountClaimsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ public void SerializeDeserialize_FullNatsAccountClaims_ShouldSucceed()
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Account",
Audience = "test_audience",
Expires = 1735689600, // 2025-01-01
IssuedAt = 1609459200, // 2021-01-01
NotBefore = 1609459200, // 2021-01-01
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600), // 2025-01-01
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
Id = "jti_test",
Account = new NatsAccount
{
Expand Down
7 changes: 4 additions & 3 deletions NATS.Jwt.Tests/Models/NatsActivationClaimsTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Text.Json;
using NATS.Jwt.Models;
using Xunit;
Expand All @@ -18,9 +19,9 @@ public void SerializeDeserialize_FullNatsActivationClaims_ShouldSucceed()
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Activation",
Audience = "test_audience",
Expires = 1735689600, // 2025-01-01
IssuedAt = 1609459200, // 2021-01-01
NotBefore = 1609459200, // 2021-01-01
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600), // 2025-01-01
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
Id = "jti_test",
Activation = new NatsActivation
{
Expand Down
7 changes: 4 additions & 3 deletions NATS.Jwt.Tests/Models/NatsAuthorizationRequestClaimsTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Collections.Generic;
using System.Text.Json;
using NATS.Jwt.Models;
Expand All @@ -19,9 +20,9 @@ public void SerializeDeserialize_FullNatsAuthorizationRequestClaims_ShouldSuccee
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Authorization Request",
Audience = "test_audience",
Expires = 1735689600,
IssuedAt = 1609459200,
NotBefore = 1609459200,
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600),
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200),
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200),
Id = "jti_test",
AuthorizationRequest = new NatsAuthorizationRequest
{
Expand Down
7 changes: 4 additions & 3 deletions NATS.Jwt.Tests/Models/NatsAuthorizationResponseClaimsTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Text.Json;
using NATS.Jwt.Models;
using Xunit;
Expand All @@ -18,9 +19,9 @@ public void SerializeDeserialize_FullNatsAuthorizationResponseClaims_ShouldSucce
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Authorization Response",
Audience = "test_audience",
Expires = 1735689600,
IssuedAt = 1609459200,
NotBefore = 1609459200,
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600),
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200),
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200),
Id = "jti_test",
AuthorizationResponse = new NatsAuthorizationResponse
{
Expand Down
7 changes: 4 additions & 3 deletions NATS.Jwt.Tests/Models/NatsGenericFieldsClaimsTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Text.Json;
using NATS.Jwt.Models;
using Xunit;
Expand All @@ -18,9 +19,9 @@ public void SerializeDeserialize_FullNatsGenericFieldsClaims_ShouldSucceed()
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Generic Fields",
Audience = "test_audience",
Expires = 1735689600,
IssuedAt = 1609459200,
NotBefore = 1609459200,
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600),
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200),
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200),
Id = "jti_test",
GenericFields = new NatsGenericFields
{
Expand Down
7 changes: 4 additions & 3 deletions NATS.Jwt.Tests/Models/NatsOperatorClaimsTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Collections.Generic;
using System.Text.Json;
using NATS.Jwt.Models;
Expand All @@ -19,9 +20,9 @@ public void SerializeDeserialize_FullNatsOperatorClaims_ShouldSucceed()
Issuer = "OIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test Operator",
Audience = "test_audience",
Expires = 1735689600, // 2025-01-01
IssuedAt = 1609459200, // 2021-01-01
NotBefore = 1609459200, // 2021-01-01
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600), // 2025-01-01
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200), // 2021-01-01
Id = "jti_test",
Operator = new NatsOperator
{
Expand Down
6 changes: 3 additions & 3 deletions NATS.Jwt.Tests/Models/NatsUserClaimsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ public void SerializeDeserialize_FullNatsUserClaims_ShouldSucceed()
Issuer = "IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII",
Name = "Full Test User",
Audience = "test_audience",
Expires = 1735689600,
IssuedAt = 1609459200,
NotBefore = 1609459200,
Expires = DateTimeOffset.FromUnixTimeSeconds(1735689600),
IssuedAt = DateTimeOffset.FromUnixTimeSeconds(1609459200),
NotBefore = DateTimeOffset.FromUnixTimeSeconds(1609459200),
Id = "jti_test",
User = new NatsUser
{
Expand Down
44 changes: 44 additions & 0 deletions NATS.Jwt/Internal/NatsJsonDateTimeOffsetConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using NATS.Jwt.Models;

namespace NATS.Jwt.Internal;

/// <inheritdoc />
internal class NatsJsonDateTimeOffsetConverter : JsonConverter<DateTimeOffset?>
{
/// <inheritdoc />
public override DateTimeOffset? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.Number)
{
throw new InvalidOperationException("Expected number");
}

var numberValue = reader.GetInt64();

if (typeToConvert == typeof(DateTimeOffset?))
{
return DateTimeOffset.FromUnixTimeSeconds(numberValue);
}

throw new InvalidOperationException($"Reading unknown date type {typeToConvert.Name} or value {numberValue}");
}

/// <inheritdoc />
public override void Write(Utf8JsonWriter writer, DateTimeOffset? value, JsonSerializerOptions options)
{
if (value is { } dateTimeOffset)
{
writer.WriteNumberValue(dateTimeOffset.ToUnixTimeSeconds());
}
else
{
writer.WriteNullValue();
}
}
}
11 changes: 8 additions & 3 deletions NATS.Jwt/Models/JwtClaimsData.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Copyright (c) The NATS Authors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Text.Json.Serialization;
using NATS.Jwt.Internal;

namespace NATS.Jwt.Models;

Expand Down Expand Up @@ -33,7 +35,8 @@ public record JwtClaimsData
/// </remarks>
[JsonPropertyName("iat")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public long IssuedAt { get; set; }
[JsonConverter(typeof(NatsJsonDateTimeOffsetConverter))]
public DateTimeOffset? IssuedAt { get; set; }

/// <summary>
/// Gets or sets the issuer claim in a JWT token.
Expand Down Expand Up @@ -66,7 +69,8 @@ public record JwtClaimsData
/// </summary>
[JsonPropertyName("exp")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public long Expires { get; set; }
[JsonConverter(typeof(NatsJsonDateTimeOffsetConverter))]
public DateTimeOffset? Expires { get; set; }

/// <summary>
/// Gets or sets the "nbf" claim in a JWT token.
Expand All @@ -75,5 +79,6 @@ public record JwtClaimsData
/// </summary>
[JsonPropertyName("nbf")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public long NotBefore { get; set; }
[JsonConverter(typeof(NatsJsonDateTimeOffsetConverter))]
public DateTimeOffset? NotBefore { get; set; }
}
2 changes: 1 addition & 1 deletion NATS.Jwt/NatsJwt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ private string DoEncode<T>(JwtHeader jwtHeader, KeyPair keyPair, T claim, JsonTy
var c = claim;

c.Issuer = issuerBytes;
c.IssuedAt = issuedAt.ToUnixTimeSeconds();
c.IssuedAt = issuedAt;

// TODO: ID generation same as Go implementation
// c.Id = Hash(c, typeInfo);
Expand Down
6 changes: 3 additions & 3 deletions NATS.Jwt/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ NATS.Jwt.Models.JetStreamLimits.Streams.set -> void
NATS.Jwt.Models.JwtClaimsData
NATS.Jwt.Models.JwtClaimsData.Audience.get -> string!
NATS.Jwt.Models.JwtClaimsData.Audience.set -> void
NATS.Jwt.Models.JwtClaimsData.Expires.get -> long
NATS.Jwt.Models.JwtClaimsData.Expires.get -> System.DateTimeOffset?
NATS.Jwt.Models.JwtClaimsData.Expires.set -> void
NATS.Jwt.Models.JwtClaimsData.Id.get -> string!
NATS.Jwt.Models.JwtClaimsData.Id.set -> void
NATS.Jwt.Models.JwtClaimsData.IssuedAt.get -> long
NATS.Jwt.Models.JwtClaimsData.IssuedAt.get -> System.DateTimeOffset?
NATS.Jwt.Models.JwtClaimsData.IssuedAt.set -> void
NATS.Jwt.Models.JwtClaimsData.Issuer.get -> string!
NATS.Jwt.Models.JwtClaimsData.Issuer.set -> void
NATS.Jwt.Models.JwtClaimsData.Name.get -> string!
NATS.Jwt.Models.JwtClaimsData.Name.set -> void
NATS.Jwt.Models.JwtClaimsData.NotBefore.get -> long
NATS.Jwt.Models.JwtClaimsData.NotBefore.get -> System.DateTimeOffset?
NATS.Jwt.Models.JwtClaimsData.NotBefore.set -> void
NATS.Jwt.Models.JwtClaimsData.Subject.get -> string!
NATS.Jwt.Models.JwtClaimsData.Subject.set -> void
Expand Down

0 comments on commit e4331b1

Please sign in to comment.