Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JWT V2 #66

Merged
merged 18 commits into from
Jun 1, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@

# IDE Files
.vscode
.idea/
.idea/

coverage.out
44 changes: 27 additions & 17 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
os: linux
language: go
sudo: false
go:
- 1.13.x
- 1.12.x

- 1.13.x
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably want to have 1.14.x and 1.13.x and drop 1.12.x now (I know, PR was originally created long ago).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

- 1.14.x
git:
depth: false
env:
- V=
- V=v2
install:
- go get -t ./...
- go get github.com/mattn/goveralls
- go get github.com/wadey/gocovmerge
- go get -u honnef.co/go/tools/cmd/staticcheck
- go get -u github.com/client9/misspell/cmd/misspell

- go get -t ./...
- go get -u honnef.co/go/tools/cmd/staticcheck
- go get -u github.com/client9/misspell/cmd/misspell
- go get github.com/mattn/goveralls
- go get github.com/wadey/gocovmerge
before_script:
- $(exit $(go fmt ./... | wc -l))
- go vet ./...
- misspell -error -locale US .
- staticcheck ./...

- cd $TRAVIS_BUILD_DIR/${V}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you do move to that directory to run the tests down below, not sure you need it here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

- $(exit $(go fmt ./... | wc -l))
- go vet ./...
- misspell -error -locale US .
- staticcheck ./...
script:
- go test -v -race ./...
- if [[ "$TRAVIS_GO_VERSION" =~ 1.12 ]]; then ./scripts/cov.sh TRAVIS; fi
- go test -v -coverprofile=./coverage.out ./...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are going to report coverage only once, you may want to simply not run it here for matrixes that do not report. Say you report only for Go 1.14 and v2, then you should run only then. That being said, jwt tests are run quickly, so that is less of a concern.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not quite sure what the coverage report means for the multi version repo.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's my point, we should do the coverage only once per PR. Here it will run for all the matrix entries, but we should post only once.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, why run the coverage if you are not going to report it? Since down below we push it on v2, for linux, and Go 1.14, I would have run the coverage code only in those conditions.

deploy:
- provider: script
script: $HOME/gopath/bin/goveralls -coverprofile=v2/coverage.out -service travis-ci
on:
tags: true
condition: ${V} = v2 && $TRAVIS_GO_VERSION =~ ^1.14.


2 changes: 1 addition & 1 deletion activation_claims_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func TestInvalidActivationClaimIssuer(t *testing.T) {

for _, i := range inputs {
bad := encode(temp, i.kp, t)
_, err = DecodeAccountClaims(bad)
_, err = DecodeActivationClaims(bad)
if i.ok && err != nil {
t.Fatal(fmt.Sprintf("unexpected error for %q: %v", i.name, err))
}
Expand Down
9 changes: 6 additions & 3 deletions claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,15 @@ const (
ActivationClaim = "activation"
//UserClaim is the type of an user JWT
UserClaim = "user"
//OperatorClaim is the type of an operator JWT
OperatorClaim = "operator"

//ServerClaim is the type of an server JWT
// Deprecated: ServerClaim is not supported
ServerClaim = "server"
//ClusterClaim is the type of an cluster JWT
// ClusterClaim is the type of an cluster JWT
// Deprecated: ClusterClaim is not supported
ClusterClaim = "cluster"
//OperatorClaim is the type of an operator JWT
OperatorClaim = "operator"
)

// Claims is a JWT claims
Expand Down
6 changes: 5 additions & 1 deletion cluster_claims.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2018 The NATS Authors
* Copyright 2018-2020 The NATS Authors
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
Expand All @@ -22,6 +22,7 @@ import (
)

// Cluster stores the cluster specific elements of a cluster JWT
// Deprecated: ClusterClaims are not supported
type Cluster struct {
Trust []string `json:"identity,omitempty"`
Accounts []string `json:"accts,omitempty"`
Expand All @@ -35,12 +36,14 @@ func (c *Cluster) Validate(vr *ValidationResults) {
}

// ClusterClaims defines the data in a cluster JWT
// Deprecated: ClusterClaims are not supported
type ClusterClaims struct {
ClaimsData
Cluster `json:"nats,omitempty"`
}

// NewClusterClaims creates a new cluster JWT with the specified subject/public key
// Deprecated: ClusterClaims are not supported
func NewClusterClaims(subject string) *ClusterClaims {
if subject == "" {
return nil
Expand All @@ -60,6 +63,7 @@ func (c *ClusterClaims) Encode(pair nkeys.KeyPair) (string, error) {
}

// DecodeClusterClaims tries to parse cluster claims from a JWT string
// Deprecated: ClusterClaims are not supported
func DecodeClusterClaims(token string) (*ClusterClaims, error) {
v := ClusterClaims{}
if err := Decode(token, &v); err != nil {
Expand Down
17 changes: 16 additions & 1 deletion creds_utils.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright 2019-2020 The NATS Authors
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package jwt

import (
Expand Down Expand Up @@ -82,7 +97,7 @@ NKEYs are sensitive and should be treated as secrets.
return w.Bytes(), nil
}

var userConfigRE = regexp.MustCompile(`\s*(?:(?:[-]{3,}.*[-]{3,}\r?\n)([\w\-.=]+)(?:\r?\n[-]{3,}.*[-]{3,}\r?\n))`)
var userConfigRE = regexp.MustCompile(`\s*(?:(?:[-]{3,}[^\n]*[-]{3,}\n)(.+)(?:\n\s*[-]{3,}[^\n]*[-]{3,}\n))`)

// An user config file looks like this:
// -----BEGIN NATS USER JWT-----
Expand Down
78 changes: 15 additions & 63 deletions creds_utils_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright 2019-2020 The NATS Authors
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package jwt

import (
Expand Down Expand Up @@ -209,66 +224,3 @@ func Test_DecorateNKeys(t *testing.T) {
t.Fatal("required error parsing bad nkey")
}
}

func Test_ParseCreds(t *testing.T) {
token, kp := makeJWT(t)
d, err := FormatUserConfig(token, seedKey(kp, t))
if err != nil {
t.Fatal(err)
}
pk, err := kp.PublicKey()
if err != nil {
t.Fatal(err)
}

token2, err := ParseDecoratedJWT(d)
if err != nil {
t.Fatal(err)
}
if token != token2 {
t.Fatal("expected jwts to match")
}
kp2, err := ParseDecoratedUserNKey(d)
if err != nil {
t.Fatal(err)
}
pk2, err := kp2.PublicKey()
if err != nil {
t.Fatal(err)
}
if pk != pk2 {
t.Fatal("expected keys to match")
}
}

func Test_ParseCredsWithCrLfs(t *testing.T) {
token, kp := makeJWT(t)
d, err := FormatUserConfig(token, seedKey(kp, t))
if err != nil {
t.Fatal(err)
}
pk, err := kp.PublicKey()
if err != nil {
t.Fatal(err)
}
d = bytes.ReplaceAll(d, []byte{'\n'}, []byte{'\r', '\n'})

token2, err := ParseDecoratedJWT(d)
if err != nil {
t.Fatal(err)
}
if token != token2 {
t.Fatal("expected jwts to match")
}
kp2, err := ParseDecoratedUserNKey(d)
if err != nil {
t.Fatal(err)
}
pk2, err := kp2.PublicKey()
if err != nil {
t.Fatal(err)
}
if pk != pk2 {
t.Fatal("expected keys to match")
}
}
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
module github.com/nats-io/jwt

require github.com/nats-io/nkeys v0.1.4
require (
github.com/nats-io/nkeys v0.1.4
github.com/stretchr/testify v1.5.1 // indirect
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully that does not bring this dep in the nats-server/go client. I know you are a big fan of it, but I like to minimize any dependency unless really required. So far, all testing in nats-server/streaming-server have not needed any feature that testify may bring that could not be done with std lib.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

)

go 1.13
go 1.14
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/nats-io/nkeys v0.1.3 h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.4 h1:aEsHIssIk6ETN5m2/MD8Y4B2X7FfXrBAUdkyRvbVYzA=
github.com/nats-io/nkeys v0.1.4/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
9 changes: 4 additions & 5 deletions operator_claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (

// Operator specific claims
type Operator struct {
// Slice of real identies (like websites) that can be used to identify the operator.
// Slice of real identities (like websites) that can be used to identify the operator.
Identities []Identity `json:"identity,omitempty"`
// Slice of other operator NKeys that can be used to sign on behalf of the main
// operator identity.
Expand Down Expand Up @@ -65,7 +65,6 @@ func (o *Operator) Validate(vr *ValidationResults) {
vr.AddError("%s is not an operator public key", k)
}
}

if o.SystemAccount != "" {
if !nkeys.IsValidPublicAccountKey(o.SystemAccount) {
vr.AddError("%s is not an account public key", o.SystemAccount)
Expand Down Expand Up @@ -120,15 +119,15 @@ func ValidateOperatorServiceURL(v string) error {
}

func (o *Operator) validateOperatorServiceURLs() []error {
var errors []error
var errs []error
for _, v := range o.OperatorServiceURLs {
if v != "" {
if err := ValidateOperatorServiceURL(v); err != nil {
errors = append(errors, err)
errs = append(errs, err)
}
}
}
return errors
return errs
}

// OperatorClaims define the data for an operator JWT
Expand Down
57 changes: 33 additions & 24 deletions operator_claims_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,30 +235,6 @@ func testAccountWithAccountServerURL(t *testing.T, u string) error {
return nil
}

func Test_AccountServerURL(t *testing.T) {
var asuTests = []struct {
u string
shouldFail bool
}{
{"", false},
{"HTTP://foo.bar.com", false},
{"http://foo.bar.com/foo/bar", false},
{"http://user:pass@foo.bar.com/foo/bar", false},
{"https://foo.bar.com", false},
{"nats://foo.bar.com", false},
{"/hello", true},
}

for i, tt := range asuTests {
err := testAccountWithAccountServerURL(t, tt.u)
if err != nil && tt.shouldFail == false {
t.Fatalf("expected not to fail: %v", err)
} else if err == nil && tt.shouldFail {
t.Fatalf("test %s expected to fail but didn't", asuTests[i].u)
}
}
}

func Test_SystemAccount(t *testing.T) {
operatorWithSystemAcc := func(t *testing.T, u string) error {
kp := createOperatorNKey(t)
Expand Down Expand Up @@ -300,6 +276,30 @@ func Test_SystemAccount(t *testing.T) {
}
}

func Test_AccountServerURL(t *testing.T) {
var asuTests = []struct {
u string
shouldFail bool
}{
{"", false},
{"HTTP://foo.bar.com", false},
{"http://foo.bar.com/foo/bar", false},
{"http://user:pass@foo.bar.com/foo/bar", false},
{"https://foo.bar.com", false},
{"nats://foo.bar.com", false},
{"/hello", true},
}

for i, tt := range asuTests {
err := testAccountWithAccountServerURL(t, tt.u)
if err != nil && tt.shouldFail == false {
t.Fatalf("expected not to fail: %v", err)
} else if err == nil && tt.shouldFail {
t.Fatalf("test %s expected to fail but didn't", asuTests[i].u)
}
}
}

func testOperatorWithOperatorServiceURL(t *testing.T, u string) error {
kp := createOperatorNKey(t)
pk := publicKey(kp, t)
Expand Down Expand Up @@ -393,3 +393,12 @@ func Test_OperatorServiceURL(t *testing.T) {
errs := vr.Errors()
AssertEquals(len(errs), shouldFail, t)
}

func Test_ForwardCompatibility(t *testing.T) {
newOp := `eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJTSUYyR0ZRSEhWWUtDQlZYRklYUURYV1FCQUcyWEw3SVZLVVJZT0ZTWlhVT0tTRUpLWDdBIiwiaWF0IjoxNTkwNTI0NTAwLCJpc3MiOiJPQlQ2REtGSzQ2STM3TjdCUkwyUkpMVVJLWUdSQTZBWVJQREFISFFFQUFBR05ZWExNR1JEUEtMQyIsInN1YiI6Ik9CVDZES0ZLNDZJMzdON0JSTDJSSkxVUktZR1JBNkFZUlBEQUhIUUVBQUFHTllYTE1HUkRQS0xDIiwibmF0cyI6eyJ0YWdzIjpbIm9uZSIsInR3byIsInRocmVlIl0sInR5cGUiOiJvcGVyYXRvciIsInZlcnNpb24iOjJ9fQ.u6JFiISIh2o-CWxktfEw3binmCLhLaFVMyuIa2HNo_x_6EGWVPVICVWc_MOLFS-6Nm17Cj4SmOh3zUtlTRkfDA`
if _, err := DecodeOperatorClaims(newOp); err == nil {
t.Fatal("Expected error")
} else if err.Error() != `unexpected "ed25519-nkey" algorithm` {
t.Fatal("Expected different error, got: ", err)
}
}
Loading