From c093fcc1de825c03d5ea2103de1f50a1c0431416 Mon Sep 17 00:00:00 2001 From: Waldemar Quevedo Date: Thu, 6 Feb 2020 16:27:20 -0800 Subject: [PATCH] Add support for qsub permissions Signed-off-by: Waldemar Quevedo --- types.go | 33 ++++++++++++++++++++++++++++- user_claims_test.go | 51 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/types.go b/types.go index a1f09fd..a7c2a87 100644 --- a/types.go +++ b/types.go @@ -88,6 +88,21 @@ func (s Subject) Validate(vr *ValidationResults) { } } +// SubscribeSubject is a string that represents a NATS subscription. +type SubscribeSubject string + +// Validate checks that a subject string is valid. +func (s SubscribeSubject) Validate(vr *ValidationResults) { + v := string(s) + if v == "" { + vr.AddError("subject cannot be empty") + } + vals := strings.Fields(strings.TrimSpace(v)) + if len(vals) > 2 { + vr.AddError("invalid subscription %q", v) + } +} + // HasWildCards is used to check if a subject contains a > or * func (s Subject) HasWildCards() bool { v := string(s) @@ -220,6 +235,22 @@ func (p *Permission) Validate(vr *ValidationResults) { } } +// SubscribePermission defines allow/deny subjects used for subscriptions. +type SubscribePermission struct { + Allow StringList `json:"allow,omitempty"` + Deny StringList `json:"deny,omitempty"` +} + +// Validate the allow, deny elements of a permission +func (p *SubscribePermission) Validate(vr *ValidationResults) { + for _, subj := range p.Allow { + SubscribeSubject(subj).Validate(vr) + } + for _, subj := range p.Deny { + SubscribeSubject(subj).Validate(vr) + } +} + // ResponsePermission can be used to allow responses to any reply subject // that is received on a valid subscription. type ResponsePermission struct { @@ -235,7 +266,7 @@ func (p *ResponsePermission) Validate(vr *ValidationResults) { // Permissions are used to restrict subject access, either on a user or for everyone on a server by default type Permissions struct { Pub Permission `json:"pub,omitempty"` - Sub Permission `json:"sub,omitempty"` + Sub SubscribePermission `json:"sub,omitempty"` Resp *ResponsePermission `json:"resp,omitempty"` } diff --git a/user_claims_test.go b/user_claims_test.go index c9da7fe..45b1ef5 100644 --- a/user_claims_test.go +++ b/user_claims_test.go @@ -238,15 +238,15 @@ func TestUserValidation(t *testing.T) { } uc.Permissions.Pub.Allow.Remove("bad subject") - uc.Permissions.Sub.Allow.Add("bad subject") + uc.Permissions.Sub.Allow.Add("ok subject") vr = CreateValidationResults() uc.Validate(vr) - if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) { - t.Error("bad permission should be invalid") + if !vr.IsEmpty() { + t.Error("valid user permissions should be valid") } - uc.Permissions.Sub.Allow.Remove("bad subject") + uc.Permissions.Sub.Allow.Remove("ok subject") uc.Permissions.Pub.Deny.Add("bad subject") vr = CreateValidationResults() uc.Validate(vr) @@ -256,13 +256,54 @@ func TestUserValidation(t *testing.T) { } uc.Permissions.Pub.Deny.Remove("bad subject") - uc.Permissions.Sub.Deny.Add("bad subject") + uc.Permissions.Sub.Deny.Add("ok subject") + vr = CreateValidationResults() + uc.Validate(vr) + + if !vr.IsEmpty() { + t.Error("valid user permissions should be valid") + } +} + +func TestUserQueueSubscribeValidation(t *testing.T) { + ukp := createUserNKey(t) + + uc := NewUserClaims(publicKey(ukp, t)) + uc.Permissions.Pub.Allow.Add("_INBOX.>") + uc.Permissions.Pub.Deny.Add("foo") + uc.Permissions.Sub.Allow.Add("foo") + uc.Permissions.Sub.Allow.Add("foo v2.*") + uc.Permissions.Sub.Deny.Add("foo v1") + uc.Permissions.Sub.Deny.Add("> v3") + + vr := CreateValidationResults() + uc.Validate(vr) + + if !vr.IsEmpty() { + t.Error("valid user permissions should be valid") + } + + // There should be nothing but whitespace after the name of the queue group. + uc.Permissions.Sub.Allow.Add("foo v2 v3") vr = CreateValidationResults() uc.Validate(vr) if vr.IsEmpty() || len(vr.Issues) != 1 || !vr.IsBlocking(true) { t.Error("bad permission should be invalid") } + + uc.Permissions.Sub.Allow.Remove("foo v2 v3") + + // Any number of spaces is ok since the whitespace is trimmed. + uc.Permissions.Sub.Allow.Add("foo v2") + uc.Permissions.Sub.Allow.Add(" bar v4 ") + uc.Permissions.Sub.Allow.Add(" bar v5 ") + vr = CreateValidationResults() + uc.Validate(vr) + + if !vr.IsEmpty() { + t.Error("valid user permissions should be valid") + } } func TestUserAccountID(t *testing.T) {