From 82e33c296d11ffb972bbce1d359966b5dbc28844 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Sun, 9 May 2021 13:04:13 -0300 Subject: [PATCH] Fix JSON encode/decode of lifetime_in_seconds --- management/client.go | 63 ++++++++++++++++++++++++++++++++++++++- management/client_test.go | 34 +++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/management/client.go b/management/client.go index b03e77db..0ad363af 100644 --- a/management/client.go +++ b/management/client.go @@ -1,5 +1,13 @@ package management +import ( + "encoding/json" + "fmt" + "strconv" + + "gopkg.in/auth0.v5" +) + type Client struct { // The name of the client Name *string `json:"name,omitempty"` @@ -88,7 +96,7 @@ type Client struct { type ClientJWTConfiguration struct { // The amount of seconds the JWT will be valid (affects exp claim) - LifetimeInSeconds *int `json:"lifetime_in_seconds,omitempty"` + LifetimeInSeconds *int `json:"-"` // True if the client secret is base64 encoded, false otherwise. Defaults to // true @@ -196,3 +204,56 @@ func (m *ClientManager) RotateSecret(id string, opts ...RequestOption) (c *Clien func (m *ClientManager) Delete(id string, opts ...RequestOption) error { return m.Request("DELETE", m.URI("clients", id), nil, opts...) } + +// UnmarshalJSON implements the json.Unmarshaler interface. +// +// It is required to handle the json field lifetime_in_seconds, which can either +// be an int, or a string in older tenants. +func (jc *ClientJWTConfiguration) UnmarshalJSON(b []byte) error { + type clientJWTConfiguration ClientJWTConfiguration + type clientJWTConfigurationWrapper struct { + *clientJWTConfiguration + RawLifetimeInSeconds interface{} `json:"lifetime_in_seconds,omitempty"` + } + + alias := &clientJWTConfigurationWrapper{(*clientJWTConfiguration)(jc), nil} + + err := json.Unmarshal(b, alias) + if err != nil { + return err + } + + unexpectedTypeError := fmt.Errorf("unexpected type for field lifetime_in_seconds") + + if alias.RawLifetimeInSeconds != nil { + switch rawLifetimeInSeconds := alias.RawLifetimeInSeconds.(type) { + case float64: + jc.LifetimeInSeconds = auth0.Int(int(rawLifetimeInSeconds)) + case string: + value, err := strconv.Atoi(rawLifetimeInSeconds) + if err != nil { + return unexpectedTypeError + } + jc.LifetimeInSeconds = &value + default: + return unexpectedTypeError + } + } + + return nil +} + +func (jc *ClientJWTConfiguration) MarshalJSON() ([]byte, error) { + type clientJWTConfiguration ClientJWTConfiguration + type clientJWTConfigurationWrapper struct { + *clientJWTConfiguration + RawLifetimeInSeconds interface{} `json:"lifetime_in_seconds,omitempty"` + } + + alias := &clientJWTConfigurationWrapper{(*clientJWTConfiguration)(jc), nil} + if jc.LifetimeInSeconds != nil { + alias.RawLifetimeInSeconds = jc.LifetimeInSeconds + } + + return json.Marshal(alias) +} diff --git a/management/client_test.go b/management/client_test.go index 5e44b116..fd2f3ee8 100644 --- a/management/client_test.go +++ b/management/client_test.go @@ -1,11 +1,13 @@ package management import ( + "encoding/json" "strings" "testing" "time" "gopkg.in/auth0.v5" + "gopkg.in/auth0.v5/internal/testing/expect" ) func TestClient(t *testing.T) { @@ -78,3 +80,35 @@ func TestClient(t *testing.T) { } }) } + +func TestJWTConfiguration(t *testing.T) { + + t.Run("MarshalJSON", func(t *testing.T) { + for u, expected := range map[*ClientJWTConfiguration]string{ + {}: `{}`, + {LifetimeInSeconds: auth0.Int(1000)}: `{"lifetime_in_seconds":1000}`, + } { + b, err := json.Marshal(u) + if err != nil { + t.Error(err) + } + expect.Expect(t, string(b), expected) + } + }) + + t.Run("UnmarshalJSON", func(t *testing.T) { + for b, expected := range map[string]*ClientJWTConfiguration{ + `{}`: {LifetimeInSeconds: nil}, + `{"lifetime_in_seconds":1000}`: {LifetimeInSeconds: auth0.Int(1000)}, + `{"lifetime_in_seconds":"1000"}`: {LifetimeInSeconds: auth0.Int(1000)}, + } { + var jc ClientJWTConfiguration + err := json.Unmarshal([]byte(b), &jc) + if err != nil { + t.Error(err) + } + expect.Expect(t, jc.GetLifetimeInSeconds(), expected.GetLifetimeInSeconds()) + } + }) + +}