Migrate to Go modules

Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
This commit is contained in:
Alex Ellis (OpenFaaS Ltd)
2021-01-20 12:12:11 +00:00
committed by Alex Ellis
parent 2e2250afe8
commit 7ce266adc0
667 changed files with 211781 additions and 17546 deletions

View File

@ -13,4 +13,6 @@
# IDE Files
.vscode
.idea/
.idea/
coverage.out

View File

@ -1,22 +1,38 @@
os:
- linux
- windows
language: go
sudo: false
go:
- 1.13.x
- 1.12.x
- 1.13.x
- 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}
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then EXCLUDE_VENDOR=$(go list ./... | grep -v "/vendor/") && $(exit $(go fmt $EXCLUDE_VENDOR | wc -l)) && go vet $EXCLUDE_VENDOR; fi
- go vet ./...
- misspell -error -locale US .
- staticcheck ./...
script:
- go test -v -race ./...
- if [[ "$TRAVIS_GO_VERSION" =~ 1.12 ]]; then ./scripts/cov.sh TRAVIS; fi
- mkdir cov
- go test -v -race -covermode=atomic -coverprofile=./cov/coverage.out -coverpkg=github.com/nats-io/jwt .
- gocovmerge ./cov/*.out > coverage.out
deploy:
- provider: script
skip_cleanup: true
script: $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service travis-ci
on:
condition: ${V} = "" && $TRAVIS_OS_NAME = linux && $TRAVIS_GO_VERSION =~ ^1.14

View File

@ -11,8 +11,20 @@ test:
go test -v --race
staticcheck ./...
cd v2/
gofmt -s -w *.go
goimports -w *.go
go vet ./...
go test -v
go test -v --race
staticcheck ./...
fmt:
gofmt -w -s *.go
go mod tidy
cd v2/
gofmt -w -s *.go
go mod tidy
cover:
go test -v -covermode=count -coverprofile=coverage.out

View File

@ -1,11 +1,11 @@
# JWT
A [JWT](https://jwt.io/) implementation that uses [nkeys](https://github.com/nats-io/nkeys) to digitally sign JWT tokens.
A [JWT](https://jwt.io/) implementation that uses [nkeys](https://github.com/nats-io/nkeys) to digitally sign JWT tokens.
Nkeys use [Ed25519](https://ed25519.cr.yp.to/) to provide authentication of JWT claims.
[![License Apache 2](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
[![ReportCard](http://goreportcard.com/badge/nats-io/jwt)](http://goreportcard.com/report/nats-io/jwt)
[![Build Status](https://travis-ci.org/nats-io/jwt.svg?branch=master)](http://travis-ci.org/nats-io/jwt)
[![Build Status](https://travis-ci.com/nats-io/jwt.svg?branch=master)](https://travis-ci.com/github/nats-io/jwt)
[![GoDoc](http://godoc.org/github.com/nats-io/jwt?status.png)](http://godoc.org/github.com/nats-io/jwt)
[![Coverage Status](https://coveralls.io/repos/github/nats-io/jwt/badge.svg?branch=master&t=NmEFup)](https://coveralls.io/github/nats-io/jwt?branch=master)

View File

@ -1,5 +1,5 @@
/*
* Copyright 2018-2019 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
@ -194,7 +194,8 @@ func (a *AccountClaims) Revoke(pubKey string) {
a.RevokeAt(pubKey, time.Now())
}
// RevokeAt enters a revocation by publickey and timestamp into this export
// RevokeAt enters a revocation by public key and timestamp into this account
// This will revoke all jwt issued for pubKey, prior to timestamp
// If there is already a revocation for this public key that is newer, it is kept.
func (a *AccountClaims) RevokeAt(pubKey string, timestamp time.Time) {
if a.Revocations == nil {
@ -209,14 +210,24 @@ func (a *AccountClaims) ClearRevocation(pubKey string) {
a.Revocations.ClearRevocation(pubKey)
}
// IsRevokedAt checks if the public key is in the revoked list with a timestamp later than
// the one passed in. Generally this method is called with time.Now() but other time's can
// be used for testing.
// IsRevokedAt checks if the public key is in the revoked list with a timestamp later than the one passed in.
// Generally this method is called with the subject and issue time of the jwt to be tested.
// DO NOT pass time.Now(), it will not produce a stable/expected response.
// The value is expected to be a public key or "*" (means all public keys)
func (a *AccountClaims) IsRevokedAt(pubKey string, timestamp time.Time) bool {
return a.Revocations.IsRevoked(pubKey, timestamp)
}
// IsRevoked checks if the public key is in the revoked list with time.Now()
func (a *AccountClaims) IsRevoked(pubKey string) bool {
return a.Revocations.IsRevoked(pubKey, time.Now())
// IsRevoked does not perform a valid check. Use IsRevokedAt instead.
func (a *AccountClaims) IsRevoked(_ string) bool {
return true
}
// IsClaimRevoked checks if the account revoked the claim passed in.
// Invalid claims (nil, no Subject or IssuedAt) will return true.
func (a *AccountClaims) IsClaimRevoked(claim *UserClaims) bool {
if claim == nil || claim.IssuedAt == 0 || claim.Subject == "" {
return true
}
return a.Revocations.IsRevoked(claim.Subject, time.Unix(claim.IssuedAt, 0))
}

View File

@ -38,12 +38,15 @@ const (
ActivationClaim = "activation"
//UserClaim is the type of an user JWT
UserClaim = "user"
//ServerClaim is the type of an server JWT
ServerClaim = "server"
//ClusterClaim is the type of an cluster JWT
ClusterClaim = "cluster"
//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
// Deprecated: ClusterClaim is not supported
ClusterClaim = "cluster"
)
// Claims is a JWT claims

View File

@ -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
@ -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"`
@ -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
@ -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 {

View File

@ -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 (

View File

@ -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
@ -108,6 +109,10 @@ func (e *Export) IsStreamResponse() bool {
// Validate appends validation issues to the passed in results list
func (e *Export) Validate(vr *ValidationResults) {
if e == nil {
vr.AddError("null export is not allowed")
return
}
if !e.IsService() && !e.IsStream() {
vr.AddError("invalid export type: %q", e.Type)
}
@ -146,16 +151,16 @@ func (e *Export) ClearRevocation(pubKey string) {
e.Revocations.ClearRevocation(pubKey)
}
// IsRevokedAt checks if the public key is in the revoked list with a timestamp later than
// the one passed in. Generally this method is called with time.Now() but other time's can
// be used for testing.
// IsRevokedAt checks if the public key is in the revoked list with a timestamp later than the one passed in.
// Generally this method is called with the subject and issue time of the jwt to be tested.
// DO NOT pass time.Now(), it will not produce a stable/expected response.
func (e *Export) IsRevokedAt(pubKey string, timestamp time.Time) bool {
return e.Revocations.IsRevoked(pubKey, timestamp)
}
// IsRevoked checks if the public key is in the revoked list with time.Now()
func (e *Export) IsRevoked(pubKey string) bool {
return e.Revocations.IsRevoked(pubKey, time.Now())
// IsRevoked does not perform a valid check. Use IsRevokedAt instead.
func (e *Export) IsRevoked(_ string) bool {
return true
}
// Exports is a slice of exports
@ -199,6 +204,10 @@ func (e *Exports) Validate(vr *ValidationResults) error {
var streamSubjects []Subject
for _, v := range *e {
if v == nil {
vr.AddError("null export is not allowed")
continue
}
if v.IsService() {
serviceSubjects = append(serviceSubjects, v.Subject)
} else {

View File

@ -1,3 +1,5 @@
module github.com/nats-io/jwt
require github.com/nats-io/nkeys v0.1.3
require github.com/nats-io/nkeys v0.2.0
go 1.14

View File

@ -1,8 +1,8 @@
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.2.0 h1:WXKF7diOaPU9cJdLD7nuzwasQy9vT1tBqzXZZf3AMJM=
github.com/nats-io/nkeys v0.2.0/go.mod h1:XdZpAbhgyyODYqjTawOnIOI7VlbKSarI9Gfy1tqEu/s=
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=

View File

@ -23,7 +23,7 @@ import (
const (
// Version is semantic version.
Version = "0.3.2"
Version = "1.2.2"
// TokenTypeJwt is the JWT token type supported JWT tokens
// encoded and decoded by this library
@ -64,7 +64,10 @@ func (h *Header) Valid() error {
return fmt.Errorf("not supported type %q", h.Type)
}
if AlgorithmNkey != strings.ToLower(h.Algorithm) {
if alg := strings.ToLower(h.Algorithm); alg != AlgorithmNkey {
if alg == "ed25519-nkey" {
return fmt.Errorf("more recent jwt version")
}
return fmt.Errorf("unexpected %q algorithm", h.Algorithm)
}
return nil

View File

@ -53,6 +53,10 @@ func (i *Import) IsStream() bool {
// Validate checks if an import is valid for the wrapping account
func (i *Import) Validate(actPubKey string, vr *ValidationResults) {
if i == nil {
vr.AddError("null import is not allowed")
return
}
if !i.IsService() && !i.IsStream() {
vr.AddError("invalid import type: %q", i.Type)
}
@ -123,6 +127,10 @@ type Imports []*Import
func (i *Imports) Validate(acctPubKey string, vr *ValidationResults) {
toSet := make(map[Subject]bool, len(*i))
for _, v := range *i {
if v == nil {
vr.AddError("null import is not allowed")
continue
}
if v.Type == Service {
if _, ok := toSet[v.To]; ok {
vr.AddError("Duplicate To subjects for %q", v.To)

View File

@ -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.
@ -40,6 +40,8 @@ type Operator struct {
// A list of NATS urls (tls://host:port) where tools can connect to the server
// using proper credentials.
OperatorServiceURLs StringList `json:"operator_service_urls,omitempty"`
// Identity of the system account
SystemAccount string `json:"system_account,omitempty"`
}
// Validate checks the validity of the operators contents
@ -63,6 +65,11 @@ 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)
}
}
}
func (o *Operator) validateAccountServerURL() error {
@ -112,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

View File

@ -1,9 +1,26 @@
/*
* Copyright 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 (
"time"
)
const All = "*"
// RevocationList is used to store a mapping of public keys to unix timestamps
type RevocationList map[string]int64
@ -24,9 +41,19 @@ func (r RevocationList) ClearRevocation(pubKey string) {
}
// IsRevoked checks if the public key is in the revoked list with a timestamp later than
// the one passed in. Generally this method is called with time.Now() but other time's can
// the one passed in. Generally this method is called with an issue time but other time's can
// be used for testing.
func (r RevocationList) IsRevoked(pubKey string, timestamp time.Time) bool {
if r.allRevoked(timestamp) {
return true
}
ts, ok := r[pubKey]
return ok && ts > timestamp.Unix()
return ok && ts >= timestamp.Unix()
}
// allRevoked returns true if All is set and the timestamp is later or same as the
// one passed. This is called by IsRevoked.
func (r RevocationList) allRevoked(timestamp time.Time) bool {
ts, ok := r[All]
return ok && ts >= timestamp.Unix()
}

View File

@ -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
@ -21,7 +21,7 @@ import (
"github.com/nats-io/nkeys"
)
// Server defines the custom part of a server jwt
// Deprecated: ServerClaims are not supported
type Server struct {
Permissions
Cluster string `json:"cluster,omitempty"`
@ -34,13 +34,13 @@ func (s *Server) Validate(vr *ValidationResults) {
}
}
// ServerClaims defines the data in a server JWT
// Deprecated: ServerClaims are not supported
type ServerClaims struct {
ClaimsData
Server `json:"nats,omitempty"`
}
// NewServerClaims creates a new server JWT with the specified subject/public key
// Deprecated: ServerClaims are not supported
func NewServerClaims(subject string) *ServerClaims {
if subject == "" {
return nil
@ -59,7 +59,7 @@ func (s *ServerClaims) Encode(pair nkeys.KeyPair) (string, error) {
return s.ClaimsData.Encode(pair, s)
}
// DecodeServerClaims tries to parse server claims from a JWT string
// Deprecated: ServerClaims are not supported
func DecodeServerClaims(token string) (*ServerClaims, error) {
v := ServerClaims{}
if err := Decode(token, &v); err != nil {

View File

@ -25,12 +25,14 @@ import (
type User struct {
Permissions
Limits
BearerToken bool `json:"bearer_token,omitempty"`
}
// Validate checks the permissions and limits in a User jwt
func (u *User) Validate(vr *ValidationResults) {
u.Permissions.Validate(vr)
u.Limits.Validate(vr)
// When BearerToken is true server will ignore any nonce-signing verification
}
// UserClaims defines a user JWT
@ -97,3 +99,8 @@ func (u *UserClaims) Payload() interface{} {
func (u *UserClaims) String() string {
return u.ClaimsData.String(u)
}
// IsBearerToken returns true if nonce-signing requirements should be skipped
func (u *UserClaims) IsBearerToken() bool {
return u.BearerToken
}

View File

@ -105,3 +105,14 @@ func (v *ValidationResults) Errors() []error {
}
return errs
}
// Warnings returns only non blocking issues as strings
func (v *ValidationResults) Warnings() []string {
var errs []string
for _, v := range v.Issues {
if !v.Blocking {
errs = append(errs, v.Description)
}
}
return errs
}