Repository: nats-io/nsc
Pull request #345 (2021-01-13 01:10:38)

[added] ability to set queue subscribe permissions
Signed-off-by: Matthias Hanel <mh@synadia.com>


Patch:
diff --git a/cmd/adduser.go b/cmd/adduser.go
index d79aaca..05a2071 100644
--- a/cmd/adduser.go
+++ b/cmd/adduser.go
@@ -20,6 +20,7 @@ import (
 	"fmt"
 	"sort"
 	"strconv"
+	"strings"
 	"time"
 
 	cli "github.com/nats-io/cliprompts/v2"
@@ -50,6 +51,11 @@ nsc add user --name <n> --deny-pubsub <subject>,...
 nsc add user --name <n> --deny-pub <subject>,...
 nsc add user --name <n> --deny-sub <subject>,...
 
+# Set subscribe permissions with queue names (separated from subject by space)
+# When added this way, the corresponding remove command needs to be presented with the exact same string
+nsc add user --name <n> --deny-sub "<subject> <queue>,..."
+nsc add user --name <n> --allow-sub "<subject> <queue>,..."
+
 # To dynamically allow publishing to reply subjects, this works well for service responders:
 nsc add user --name <n> --allow-pub-response
 
@@ -433,6 +439,21 @@ func (p *PermissionsParams) Validate() error {
 	if err := p.ttlValidator(p.respTTL); err != nil {
 		return err
 	}
+	for _, v := range [][]string{p.allowPubs, p.allowPubsub, p.denyPubs, p.denyPubsub} {
+		for _, sub := range v {
+			if strings.Contains(sub, " ") {
+				return fmt.Errorf("publish permission subject %q contains illegal space", sub)
+			}
+		}
+	}
+	for _, v := range [][]string{p.allowSubs, p.denySubs} {
+		for _, sub := range v {
+			if strings.Count(sub, " ") > 1 {
+				return fmt.Errorf("subscribe permission subject %q can at most contain one space", sub)
+			}
+		}
+	}
+
 	return nil
 }
 
diff --git a/cmd/edituser.go b/cmd/edituser.go
index da8d74f..5ae844b 100644
--- a/cmd/edituser.go
+++ b/cmd/edituser.go
@@ -42,6 +42,11 @@ nsc edit user --name <n> --deny-pubsub <subject>,...
 nsc edit user --name <n> --deny-pub <subject>,...
 nsc edit user --name <n> --deny-sub <subject>,...
 
+# Set subscribe permissions with queue names (separated from subject by space)
+# When added this way, the corresponding remove command needs to be presented with the exact same string
+nsc edit user --name <n> --deny-sub "<subject> <queue>,..."
+nsc edit user --name <n> --allow-sub "<subject> <queue>,..."
+
 # Remove a previously set permissions
 nsc edit user --name <n> --rm <subject>,...
 


Test patch:
diff --git a/cmd/adduser_test.go b/cmd/adduser_test.go
index 877c933..ba350e5 100644
--- a/cmd/adduser_test.go
+++ b/cmd/adduser_test.go
@@ -46,6 +46,14 @@ func Test_AddUser(t *testing.T) {
 		{CreateAddUserCmd(), []string{"add", "user", "--name", "bar", "--public-key", bar}, nil, nil, false},
 		{CreateAddUserCmd(), []string{"add", "user", "--name", "badbar", "--public-key", badBar}, nil, []string{"invalid user key"}, true},
 		{CreateAddUserCmd(), []string{"add", "user", "--name", "badexp", "--expiry", "30d"}, nil, nil, false},
+		{CreateAddUserCmd(), []string{"add", "user", "--name", "usra", "--deny-sub", "foo queue"}, nil, []string{"added user"}, false},
+		{CreateAddUserCmd(), []string{"add", "user", "--name", "usrb", "--allow-sub", "foo queue"}, nil, []string{"added user"}, false},
+		{CreateAddUserCmd(), []string{"add", "user", "--name", "usrc", "--deny-pub", "foo queue"}, nil, []string{"contains illegal space"}, true},
+		{CreateAddUserCmd(), []string{"add", "user", "--name", "usrd", "--allow-pub", "foo queue"}, nil, []string{"contains illegal space"}, true},
+		{CreateAddUserCmd(), []string{"add", "user", "--name", "usre", "--deny-pubsub", "foo queue"}, nil, []string{"contains illegal space"}, true},
+		{CreateAddUserCmd(), []string{"add", "user", "--name", "usrf", "--allow-pubsub", "foo queue"}, nil, []string{"contains illegal space"}, true},
+		{CreateAddUserCmd(), []string{"add", "user", "--name", "usrg", "--deny-sub", "foo queue doo"}, nil, []string{"can at most contain one space"}, true},
+		{CreateAddUserCmd(), []string{"add", "user", "--name", "usrh", "--allow-sub", "foo queue doo"}, nil, []string{"can at most contain one space"}, true},
 	}
 
 	tests.Run(t, "root", "add")
@@ -430,3 +438,18 @@ func Test_AddUserWithSigningKeyInteractive(t *testing.T) {
 	require.NotEqual(t, claim.Issuer, claim.IssuerAccount)
 	require.Equal(t, claim.Issuer, pk)
 }
+
+func Test_AddUser_QueuePermissions(t *testing.T) {
+	ts := NewTestStore(t, "O")
+	defer ts.Done(t)
+
+	ts.AddAccount(t, "A")
+
+	_, _, err := ExecuteCmd(HoistRootFlags(CreateAddUserCmd()), "--name", "UA", "--allow-sub", "foo queue", "--deny-sub", "bar queue")
+	require.NoError(t, err)
+
+	u, err := ts.Store.ReadUserClaim("A", "UA")
+	require.NoError(t, err)
+	require.True(t, u.Sub.Allow.Contains("foo queue"))
+	require.True(t, u.Sub.Deny.Contains("bar queue"))
+}
diff --git a/cmd/natsresolverconfigbuilder_test.go b/cmd/natsresolverconfigbuilder_test.go
index 341a9c3..bab6636 100644
--- a/cmd/natsresolverconfigbuilder_test.go
+++ b/cmd/natsresolverconfigbuilder_test.go
@@ -49,6 +49,4 @@ func Test_NatsResolverServerParse(t *testing.T) {
 	require.NoError(t, opts.ProcessConfigFile(serverconf))
 	require.NotEmpty(t, opts.SystemAccount)
 	require.NotEmpty(t, opts.TrustedOperators)
-	_, ok := opts.AccountResolver.(server.AccountResolver)
-	require.True(t, ok)
 }