Repository: nats-io/nsc
Pull request #664 (2024-09-04 18:44:42)

[FIX] edit user was unable to remove a connection type when in lowercase
this change ensures that connection types are uppercased, and autofixes any type that is lowercase in an existing JWT


Patch:
diff --git a/cmd/edituser.go b/cmd/edituser.go
index 2b0fc5f..0338590 100644
--- a/cmd/edituser.go
+++ b/cmd/edituser.go
@@ -109,6 +109,14 @@ func (p *EditUserParams) SetDefaults(ctx ActionCtx) error {
 		ctx.CurrentCmd().SilenceUsage = false
 		return fmt.Errorf("specify an edit option")
 	}
+	// allow the user to enter inputs in lc
+	for i, v := range p.connTypes {
+		p.connTypes[i] = strings.ToUpper(v)
+	}
+	for i, v := range p.rmConnTypes {
+		p.rmConnTypes[i] = strings.ToUpper(v)
+	}
+
 	return nil
 }
 
@@ -161,6 +169,11 @@ func (p *EditUserParams) Load(ctx ActionCtx) error {
 		return err
 	}
 
+	// if the JWT has an allowed connection type in lowercase fix it
+	for i, v := range p.claim.UserPermissionLimits.AllowedConnectionTypes {
+		p.claim.UserPermissionLimits.AllowedConnectionTypes[i] = strings.ToUpper(v)
+	}
+
 	p.UserPermissionLimits.Load(ctx, p.claim.UserPermissionLimits)
 
 	return err
@@ -409,7 +422,15 @@ func (p *UserPermissionLimits) Validate(ctx ActionCtx) error {
 	}
 	rmConnTypes := make([]string, len(p.rmConnTypes))
 	for i, k := range p.rmConnTypes {
-		rmConnTypes[i] = strings.ToUpper(k)
+		u := strings.ToUpper(k)
+		switch u {
+		case jwt.ConnectionTypeLeafnode, jwt.ConnectionTypeMqtt, jwt.ConnectionTypeStandard,
+			jwt.ConnectionTypeWebsocket, jwt.ConnectionTypeLeafnodeWS, jwt.ConnectionTypeMqttWS,
+			jwt.ConnectionTypeInProcess:
+		default:
+			return fmt.Errorf("unknown rm connection type %s", k)
+		}
+		rmConnTypes[i] = u
 	}
 	p.rmConnTypes = rmConnTypes
 


Test patch:
diff --git a/cmd/edituser_test.go b/cmd/edituser_test.go
index a569e2f..7a4b706 100644
--- a/cmd/edituser_test.go
+++ b/cmd/edituser_test.go
@@ -16,6 +16,8 @@
 package cmd
 
 import (
+	"github.com/nats-io/nsc/v2/cmd/store"
+	"strings"
 	"testing"
 	"time"
 
@@ -520,3 +522,76 @@ func Test_EditUserConnection(t *testing.T) {
 	_, _, err = ExecuteCmd(createEditUserCmd(), "--conn-type", jwt.ConnectionTypeInProcess)
 	require.NoError(t, err)
 }
+
+func Test_EditUserConnectionCase(t *testing.T) {
+	ts := NewTestStore(t, "O")
+	defer ts.Done(t)
+	ts.AddAccount(t, "A")
+	ts.AddUser(t, "A", "U")
+
+	ac, err := ts.Store.ReadAccountClaim("A")
+	require.NoError(t, err)
+	akp, err := ts.KeyStore.GetKeyPair(ac.Subject)
+	require.NoError(t, err)
+
+	claim, err := ts.Store.ReadUserClaim("A", "U")
+	require.NoError(t, err)
+
+	// add lower case conn type - this is prevented now, but worked in the past
+	claim.AllowedConnectionTypes.Add(strings.ToLower(jwt.ConnectionTypeStandard))
+	token, err := claim.Encode(akp)
+	require.NoError(t, err)
+
+	err = ts.Store.Write([]byte(token), store.Accounts, "A", store.Users, store.JwtName("U"))
+	require.NoError(t, err)
+
+	claim, err = ts.Store.ReadUserClaim("A", "U")
+	require.NoError(t, err)
+	require.Len(t, claim.AllowedConnectionTypes, 1)
+	require.Contains(t, claim.AllowedConnectionTypes, strings.ToLower(jwt.ConnectionTypeStandard))
+
+	_, _, err = ExecuteCmd(createEditUserCmd(), "--conn-type", strings.ToLower(jwt.ConnectionTypeMqtt))
+	require.NoError(t, err)
+
+	claim, err = ts.Store.ReadUserClaim("A", "U")
+	require.NoError(t, err)
+	require.Len(t, claim.AllowedConnectionTypes, 2)
+	require.Contains(t, claim.AllowedConnectionTypes, jwt.ConnectionTypeMqtt)
+	// we expect the set fixed it
+	require.Contains(t, claim.AllowedConnectionTypes, jwt.ConnectionTypeStandard)
+}
+
+func Test_EditUserConnectionDeleteCase(t *testing.T) {
+	ts := NewTestStore(t, "O")
+	defer ts.Done(t)
+	ts.AddAccount(t, "A")
+	ts.AddUser(t, "A", "U")
+
+	ac, err := ts.Store.ReadAccountClaim("A")
+	require.NoError(t, err)
+	akp, err := ts.KeyStore.GetKeyPair(ac.Subject)
+	require.NoError(t, err)
+
+	claim, err := ts.Store.ReadUserClaim("A", "U")
+	require.NoError(t, err)
+
+	// add lower case conn type - this is prevented now, but worked in the past
+	claim.AllowedConnectionTypes.Add(strings.ToLower(jwt.ConnectionTypeStandard))
+	token, err := claim.Encode(akp)
+	require.NoError(t, err)
+
+	err = ts.Store.Write([]byte(token), store.Accounts, "A", store.Users, store.JwtName("U"))
+	require.NoError(t, err)
+
+	claim, err = ts.Store.ReadUserClaim("A", "U")
+	require.NoError(t, err)
+	require.Len(t, claim.AllowedConnectionTypes, 1)
+	require.Contains(t, claim.AllowedConnectionTypes, strings.ToLower(jwt.ConnectionTypeStandard))
+
+	_, _, err = ExecuteCmd(createEditUserCmd(), "--rm-conn-type", jwt.ConnectionTypeStandard)
+	require.NoError(t, err)
+
+	claim, err = ts.Store.ReadUserClaim("A", "U")
+	require.NoError(t, err)
+	require.Len(t, claim.AllowedConnectionTypes, 0)
+}