Skip to content

Commit

Permalink
Adding account_token_position to account exports (#76)
Browse files Browse the repository at this point in the history
* Adding account_token_position to account exports
  • Loading branch information
matthiashanel committed Jun 2, 2020
1 parent f40e018 commit 8622fff
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 14 deletions.
15 changes: 8 additions & 7 deletions exports.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,14 @@ func (sl *ServiceLatency) Validate(vr *ValidationResults) {

// Export represents a single export
type Export struct {
Name string `json:"name,omitempty"`
Subject Subject `json:"subject,omitempty"`
Type ExportType `json:"type,omitempty"`
TokenReq bool `json:"token_req,omitempty"`
Revocations RevocationList `json:"revocations,omitempty"`
ResponseType ResponseType `json:"response_type,omitempty"`
Latency *ServiceLatency `json:"service_latency,omitempty"`
Name string `json:"name,omitempty"`
Subject Subject `json:"subject,omitempty"`
Type ExportType `json:"type,omitempty"`
TokenReq bool `json:"token_req,omitempty"`
Revocations RevocationList `json:"revocations,omitempty"`
ResponseType ResponseType `json:"response_type,omitempty"`
Latency *ServiceLatency `json:"service_latency,omitempty"`
AccountTokenPosition uint `json:"account_token_position,omitempty"`
}

// IsService returns true if an export is for a service
Expand Down
32 changes: 25 additions & 7 deletions v2/exports.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package jwt

import (
"fmt"
"strings"
"time"
)

Expand Down Expand Up @@ -71,13 +72,14 @@ func (sl *ServiceLatency) Validate(vr *ValidationResults) {

// Export represents a single export
type Export struct {
Name string `json:"name,omitempty"`
Subject Subject `json:"subject,omitempty"`
Type ExportType `json:"type,omitempty"`
TokenReq bool `json:"token_req,omitempty"`
Revocations RevocationList `json:"revocations,omitempty"`
ResponseType ResponseType `json:"response_type,omitempty"`
Latency *ServiceLatency `json:"service_latency,omitempty"`
Name string `json:"name,omitempty"`
Subject Subject `json:"subject,omitempty"`
Type ExportType `json:"type,omitempty"`
TokenReq bool `json:"token_req,omitempty"`
Revocations RevocationList `json:"revocations,omitempty"`
ResponseType ResponseType `json:"response_type,omitempty"`
Latency *ServiceLatency `json:"service_latency,omitempty"`
AccountTokenPosition uint `json:"account_token_position,omitempty"`
}

// IsService returns true if an export is for a service
Expand Down Expand Up @@ -124,6 +126,22 @@ func (e *Export) Validate(vr *ValidationResults) {
e.Latency.Validate(vr)
}
e.Subject.Validate(vr)
if e.AccountTokenPosition > 0 {
if !e.Subject.HasWildCards() {
vr.AddError("Account Token Position can only be used with wildcard subjects: %s", e.Subject)
} else {
subj := string(e.Subject)
token := strings.Split(subj, ".")
tkCnt := uint(len(token))
if e.AccountTokenPosition > tkCnt {
vr.AddError("Account Token Position %d exceeds length of subject '%s'",
e.AccountTokenPosition, e.Subject)
} else if tk := token[e.AccountTokenPosition-1]; tk != "*" {
vr.AddError("Account Token Position %d matches '%s' but must match a * in: %s",
e.AccountTokenPosition, tk, e.Subject)
}
}
}
}

// Revoke enters a revocation by publickey using time.Now().
Expand Down
72 changes: 72 additions & 0 deletions v2/exports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,75 @@ func TestExport_Sorting(t *testing.T) {
t.Fatal("exports not sorted")
}
}

func TestExportAccountTokenPos(t *testing.T) {
okp := createOperatorNKey(t)
akp := createAccountNKey(t)
apk := publicKey(akp, t)
tbl := map[Subject]uint{
"*": 1,
"foo.*": 2,
"foo.*.bar.*": 2,
"foo.*.bar.>": 2,
"*.*.*.>": 2,
"*.*.>": 1,
}
for k, v := range tbl {
t.Run(string(k), func(t *testing.T) {
account := NewAccountClaims(apk)
//account.Limits = OperatorLimits{}
account.Exports = append(account.Exports,
&Export{Type: Stream, Subject: k, AccountTokenPosition: v})
actJwt := encode(account, okp, t)
account2, err := DecodeAccountClaims(actJwt)
if err != nil {
t.Fatal("error decoding account jwt", err)
}
AssertEquals(account.String(), account2.String(), t)
vr := &ValidationResults{}
account2.Validate(vr)
if len(vr.Issues) != 0 {
t.Fatal("validation issues", *vr)
}
})
}
}

func TestExportAccountTokenPosFail(t *testing.T) {
okp := createOperatorNKey(t)
akp := createAccountNKey(t)
apk := publicKey(akp, t)
tbl := map[Subject]uint{
">": 5,
"foo.>": 2,
"bar.>": 1,
"*": 5,
"*.*": 5,
"bar": 1,
"foo.bar": 2,
"foo.*.bar": 3,
"*.>": 3,
"*.*.>": 3,
"foo.*x.bar": 2,
"foo.x*.bar": 2,
}
for k, v := range tbl {
t.Run(string(k), func(t *testing.T) {
account := NewAccountClaims(apk)
//account.Limits = OperatorLimits{}
account.Exports = append(account.Exports,
&Export{Type: Stream, Subject: k, AccountTokenPosition: v})
actJwt := encode(account, okp, t)
account2, err := DecodeAccountClaims(actJwt)
if err != nil {
t.Fatal("error decoding account jwt", err)
}
AssertEquals(account.String(), account2.String(), t)
vr := &ValidationResults{}
account2.Validate(vr)
if len(vr.Issues) != 1 {
t.Fatal("validation issue expected", *vr)
}
})
}
}

0 comments on commit 8622fff

Please sign in to comment.