Skip to content

Commit 938c478

Browse files
committed
perhaphs handle this in an unmarshal - this means existing JWT will work propery - new ones created by the API will ALWAYS serialize the weight - so if created with no weight expecting the old behaviour, it will set to 0 (which will not route traffic).
Signed-off-by: Alberto Ricart <[email protected]>
1 parent adf3daf commit 938c478

File tree

2 files changed

+90
-1
lines changed

2 files changed

+90
-1
lines changed

v2/account_claims.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package jwt
1717

1818
import (
19+
"encoding/json"
1920
"errors"
2021
"fmt"
2122
"sort"
@@ -136,10 +137,33 @@ func (o *OperatorLimits) Validate(vr *ValidationResults) {
136137
// WeightedMapping for publishes
137138
type WeightedMapping struct {
138139
Subject Subject `json:"subject"`
139-
Weight uint8 `json:"weight,omitempty"`
140+
Weight uint8 `json:"weight"`
140141
Cluster string `json:"cluster,omitempty"`
141142
}
142143

144+
// UnmarshalJSON implements custom JSON unmarshalling for backward compatibility.
145+
// If weight field is missing (old JWTs), it defaults to 100 so existing JWTs that
146+
// omit the weight will continue to work properly
147+
func (m *WeightedMapping) UnmarshalJSON(data []byte) error {
148+
temp := &struct {
149+
Subject Subject `json:"subject"`
150+
Weight *uint8 `json:"weight"` // pointer to detect if field is present
151+
Cluster string `json:"cluster,omitempty"`
152+
}{}
153+
if err := json.Unmarshal(data, temp); err != nil {
154+
return err
155+
}
156+
m.Subject = temp.Subject
157+
m.Cluster = temp.Cluster
158+
// if weight field is not present in JSON (old JWT), default to 100
159+
if temp.Weight == nil {
160+
m.Weight = 100
161+
} else {
162+
m.Weight = *temp.Weight
163+
}
164+
return nil
165+
}
166+
143167
// GetWeight returns the weight value.
144168
// Deprecated: use Weight field directly.
145169
func (m *WeightedMapping) GetWeight() uint8 {

v2/account_claims_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package jwt
1717

1818
import (
19+
"encoding/json"
1920
"fmt"
2021
"strings"
2122
"testing"
@@ -782,6 +783,70 @@ func TestAccountMappingWith30And0Weights(t *testing.T) {
782783
}
783784
}
784785

786+
func TestAccountMappingBackwardCompatibility(t *testing.T) {
787+
// test that old JWTs without weight field get weight 100 on unmarshal
788+
oldJWT := `{"subject":"hello", "to": "hi"}`
789+
790+
var m WeightedMapping
791+
err := json.Unmarshal([]byte(oldJWT), &m)
792+
if err != nil {
793+
t.Fatal(err)
794+
}
795+
796+
// verify weight defaults to 100 for old JWTs without weight field
797+
if m.Weight != 100 {
798+
t.Fatalf("Expected weight 100 for old JWT without weight field, got: %d", m.Weight)
799+
}
800+
801+
// test that new JWTs with weight 0 keep weight 0
802+
newJWT := `{"subject":"hello", "to": "hi", "weight": 0}`
803+
err = json.Unmarshal([]byte(newJWT), &m)
804+
if err != nil {
805+
t.Fatal(err)
806+
}
807+
808+
if m.Weight != 0 {
809+
t.Fatalf("Expected weight 0 for new JWT with weight:0, got: %d", m.Weight)
810+
}
811+
}
812+
813+
func TestAccountMappingOldJWT(t *testing.T) {
814+
// old JWT with mapping that doesn't have weight field
815+
oldJWT := `eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJCTFE3UllWSEs3QVZCN0gzRVgzRUpWRlNORTRPUEVUTkg1VlNZQkpVVTdUVTVCWkVDNjVRIiwiaWF0IjoxNzYzMjE2MDI5LCJpc3MiOiJPREo3Q0UyVklCWTdHM0dYVVZFTVFYR1ZRNlJSRlRPWFdaNEpOVzVBMklZTlNHNVk2VDRWNFNBUyIsIm5hbWUiOiJNIiwic3ViIjoiQUFYUVE3TFdQWUZGT1g1S0ZBNU02VjY3VVBOTzJKTUFKVTdKUVJRQkRDVjdRSUhGNllIUDU3Q0siLCJuYXRzIjp7ImxpbWl0cyI6eyJzdWJzIjotMSwiZGF0YSI6LTEsInBheWxvYWQiOi0xLCJpbXBvcnRzIjotMSwiZXhwb3J0cyI6LTEsIndpbGRjYXJkcyI6dHJ1ZSwiY29ubiI6LTEsImxlYWYiOi0xfSwiZGVmYXVsdF9wZXJtaXNzaW9ucyI6eyJwdWIiOnt9LCJzdWIiOnt9fSwibWFwcGluZ3MiOnsiYSI6W3sic3ViamVjdCI6ImIifV19LCJhdXRob3JpemF0aW9uIjp7fSwidHlwZSI6ImFjY291bnQiLCJ2ZXJzaW9uIjoyfX0.qFxSSQKqHxpl2qS21x1Yj8zqDufGLIp9Gncb-YBf3P-CYxB31Dtp5swSYOmsA8zEGYMdnynY7z_73LweHqedAg`
816+
817+
account, err := DecodeAccountClaims(oldJWT)
818+
if err != nil {
819+
t.Fatal(err)
820+
}
821+
822+
// verify mapping was loaded
823+
if len(account.Mappings) != 1 {
824+
t.Fatalf("Expected 1 mapping, got %d", len(account.Mappings))
825+
}
826+
827+
// verify mapping "a" -> "b" exists and has weight 100 (default for old JWTs)
828+
mappingsA, ok := account.Mappings["a"]
829+
if !ok {
830+
t.Fatal("Expected mapping 'a' to exist")
831+
}
832+
if len(mappingsA) != 1 {
833+
t.Fatalf("Expected 1 mapping for 'a', got %d", len(mappingsA))
834+
}
835+
if mappingsA[0].Subject != "b" {
836+
t.Fatalf("Expected subject 'b', got %s", mappingsA[0].Subject)
837+
}
838+
if mappingsA[0].Weight != 100 {
839+
t.Fatalf("Expected weight 100 for old JWT mapping without weight field, got %d", mappingsA[0].Weight)
840+
}
841+
842+
// validate should pass
843+
vr := &ValidationResults{}
844+
account.Validate(vr)
845+
if !vr.IsEmpty() {
846+
t.Fatalf("Expected no validation errors, got: %v", vr.Issues)
847+
}
848+
}
849+
785850
func TestAccountExternalAuthorization(t *testing.T) {
786851
akp := createAccountNKey(t)
787852
apk := publicKey(akp, t)

0 commit comments

Comments
 (0)