mirror of
https://github.com/openfaas/faas.git
synced 2025-06-23 23:33:25 +00:00
Bump queue-worker and NATS
NATS moved its primary library to: github.com/nats-io/stan.go This commit synchronises the library in the gateway to match the queue worker. Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
This commit is contained in:
committed by
Alex Ellis
parent
542d7c0b83
commit
9bde25aedb
16
gateway/vendor/github.com/nats-io/jwt/.gitignore
generated
vendored
Normal file
16
gateway/vendor/github.com/nats-io/jwt/.gitignore
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# IDE Files
|
||||
.vscode
|
||||
.idea/
|
22
gateway/vendor/github.com/nats-io/jwt/.travis.yml
generated
vendored
Normal file
22
gateway/vendor/github.com/nats-io/jwt/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.13.x
|
||||
- 1.12.x
|
||||
|
||||
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
|
||||
|
||||
before_script:
|
||||
- $(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
|
201
gateway/vendor/github.com/nats-io/jwt/LICENSE
generated
vendored
Normal file
201
gateway/vendor/github.com/nats-io/jwt/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
19
gateway/vendor/github.com/nats-io/jwt/Makefile
generated
vendored
Normal file
19
gateway/vendor/github.com/nats-io/jwt/Makefile
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
.PHONY: test cover
|
||||
|
||||
build:
|
||||
go build
|
||||
|
||||
test:
|
||||
gofmt -s -w *.go
|
||||
goimports -w *.go
|
||||
go vet ./...
|
||||
go test -v
|
||||
go test -v --race
|
||||
staticcheck ./...
|
||||
|
||||
fmt:
|
||||
gofmt -w -s *.go
|
||||
|
||||
cover:
|
||||
go test -v -covermode=count -coverprofile=coverage.out
|
||||
go tool cover -html=coverage.out
|
54
gateway/vendor/github.com/nats-io/jwt/README.md
generated
vendored
Normal file
54
gateway/vendor/github.com/nats-io/jwt/README.md
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
# JWT
|
||||
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.
|
||||
|
||||
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0)
|
||||
[](http://goreportcard.com/report/nats-io/jwt)
|
||||
[](http://travis-ci.org/nats-io/jwt)
|
||||
[](http://godoc.org/github.com/nats-io/jwt)
|
||||
[](https://coveralls.io/github/nats-io/jwt?branch=master)
|
||||
|
||||
```go
|
||||
// Need a private key to sign the claim, nkeys makes it easy to create
|
||||
kp, err := nkeys.CreateAccount()
|
||||
if err != nil {
|
||||
t.Fatal("unable to create account key", err)
|
||||
}
|
||||
|
||||
pk, err := kp.PublicKey()
|
||||
if err != nil {
|
||||
t.Fatal("error getting public key", err)
|
||||
}
|
||||
|
||||
// create a new claim
|
||||
claims := NewAccountClaims(pk)
|
||||
claims.Expires = time.Now().Add(time.Duration(time.Hour)).Unix()
|
||||
|
||||
|
||||
// add details by modifying claims.Account
|
||||
|
||||
// serialize the claim to a JWT token
|
||||
token, err := claims.Encode(kp)
|
||||
if err != nil {
|
||||
t.Fatal("error encoding token", err)
|
||||
}
|
||||
|
||||
// on the receiving side, decode the token
|
||||
c, err := DecodeAccountClaims(token)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// if the token was decoded, it means that it
|
||||
// validated and it wasn't tampered. the remaining and
|
||||
// required test is to insure the issuer is trusted
|
||||
pk, err := kp.PublicKey()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to read public key: %v", err)
|
||||
}
|
||||
|
||||
if c.Issuer != pk {
|
||||
t.Fatalf("the public key is not trusted")
|
||||
}
|
||||
```
|
5
gateway/vendor/github.com/nats-io/jwt/ReleaseNotes.md
generated
vendored
Normal file
5
gateway/vendor/github.com/nats-io/jwt/ReleaseNotes.md
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Release Notes
|
||||
|
||||
## 0.3.0
|
||||
|
||||
* Removed revocation claims in favor of timestamp-based revocation maps in account and export claims.
|
222
gateway/vendor/github.com/nats-io/jwt/account_claims.go
generated
vendored
Normal file
222
gateway/vendor/github.com/nats-io/jwt/account_claims.go
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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 (
|
||||
"errors"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// NoLimit is used to indicate a limit field is unlimited in value.
|
||||
const NoLimit = -1
|
||||
|
||||
// OperatorLimits are used to limit access by an account
|
||||
type OperatorLimits struct {
|
||||
Subs int64 `json:"subs,omitempty"` // Max number of subscriptions
|
||||
Conn int64 `json:"conn,omitempty"` // Max number of active connections
|
||||
LeafNodeConn int64 `json:"leaf,omitempty"` // Max number of active leaf node connections
|
||||
Imports int64 `json:"imports,omitempty"` // Max number of imports
|
||||
Exports int64 `json:"exports,omitempty"` // Max number of exports
|
||||
Data int64 `json:"data,omitempty"` // Max number of bytes
|
||||
Payload int64 `json:"payload,omitempty"` // Max message payload
|
||||
WildcardExports bool `json:"wildcards,omitempty"` // Are wildcards allowed in exports
|
||||
}
|
||||
|
||||
// IsEmpty returns true if all of the limits are 0/false.
|
||||
func (o *OperatorLimits) IsEmpty() bool {
|
||||
return *o == OperatorLimits{}
|
||||
}
|
||||
|
||||
// IsUnlimited returns true if all limits are
|
||||
func (o *OperatorLimits) IsUnlimited() bool {
|
||||
return *o == OperatorLimits{NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, true}
|
||||
}
|
||||
|
||||
// Validate checks that the operator limits contain valid values
|
||||
func (o *OperatorLimits) Validate(vr *ValidationResults) {
|
||||
// negative values mean unlimited, so all numbers are valid
|
||||
}
|
||||
|
||||
// Account holds account specific claims data
|
||||
type Account struct {
|
||||
Imports Imports `json:"imports,omitempty"`
|
||||
Exports Exports `json:"exports,omitempty"`
|
||||
Identities []Identity `json:"identity,omitempty"`
|
||||
Limits OperatorLimits `json:"limits,omitempty"`
|
||||
SigningKeys StringList `json:"signing_keys,omitempty"`
|
||||
Revocations RevocationList `json:"revocations,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks if the account is valid, based on the wrapper
|
||||
func (a *Account) Validate(acct *AccountClaims, vr *ValidationResults) {
|
||||
a.Imports.Validate(acct.Subject, vr)
|
||||
a.Exports.Validate(vr)
|
||||
a.Limits.Validate(vr)
|
||||
|
||||
for _, i := range a.Identities {
|
||||
i.Validate(vr)
|
||||
}
|
||||
|
||||
if !a.Limits.IsEmpty() && a.Limits.Imports >= 0 && int64(len(a.Imports)) > a.Limits.Imports {
|
||||
vr.AddError("the account contains more imports than allowed by the operator")
|
||||
}
|
||||
|
||||
// Check Imports and Exports for limit violations.
|
||||
if a.Limits.Imports != NoLimit {
|
||||
if int64(len(a.Imports)) > a.Limits.Imports {
|
||||
vr.AddError("the account contains more imports than allowed by the operator")
|
||||
}
|
||||
}
|
||||
if a.Limits.Exports != NoLimit {
|
||||
if int64(len(a.Exports)) > a.Limits.Exports {
|
||||
vr.AddError("the account contains more exports than allowed by the operator")
|
||||
}
|
||||
// Check for wildcard restrictions
|
||||
if !a.Limits.WildcardExports {
|
||||
for _, ex := range a.Exports {
|
||||
if ex.Subject.HasWildCards() {
|
||||
vr.AddError("the account contains wildcard exports that are not allowed by the operator")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, k := range a.SigningKeys {
|
||||
if !nkeys.IsValidPublicAccountKey(k) {
|
||||
vr.AddError("%s is not an account public key", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AccountClaims defines the body of an account JWT
|
||||
type AccountClaims struct {
|
||||
ClaimsData
|
||||
Account `json:"nats,omitempty"`
|
||||
}
|
||||
|
||||
// NewAccountClaims creates a new account JWT
|
||||
func NewAccountClaims(subject string) *AccountClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := &AccountClaims{}
|
||||
// Set to unlimited to start. We do it this way so we get compiler
|
||||
// errors if we add to the OperatorLimits.
|
||||
c.Limits = OperatorLimits{NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, true}
|
||||
c.Subject = subject
|
||||
return c
|
||||
}
|
||||
|
||||
// Encode converts account claims into a JWT string
|
||||
func (a *AccountClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicAccountKey(a.Subject) {
|
||||
return "", errors.New("expected subject to be account public key")
|
||||
}
|
||||
sort.Sort(a.Exports)
|
||||
sort.Sort(a.Imports)
|
||||
a.ClaimsData.Type = AccountClaim
|
||||
return a.ClaimsData.Encode(pair, a)
|
||||
}
|
||||
|
||||
// DecodeAccountClaims decodes account claims from a JWT string
|
||||
func DecodeAccountClaims(token string) (*AccountClaims, error) {
|
||||
v := AccountClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (a *AccountClaims) String() string {
|
||||
return a.ClaimsData.String(a)
|
||||
}
|
||||
|
||||
// Payload pulls the accounts specific payload out of the claims
|
||||
func (a *AccountClaims) Payload() interface{} {
|
||||
return &a.Account
|
||||
}
|
||||
|
||||
// Validate checks the accounts contents
|
||||
func (a *AccountClaims) Validate(vr *ValidationResults) {
|
||||
a.ClaimsData.Validate(vr)
|
||||
a.Account.Validate(a, vr)
|
||||
|
||||
if nkeys.IsValidPublicAccountKey(a.ClaimsData.Issuer) {
|
||||
if len(a.Identities) > 0 {
|
||||
vr.AddWarning("self-signed account JWTs shouldn't contain identity proofs")
|
||||
}
|
||||
if !a.Limits.IsEmpty() {
|
||||
vr.AddWarning("self-signed account JWTs shouldn't contain operator limits")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the types that can encode an account jwt, account and operator
|
||||
func (a *AccountClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteAccount, nkeys.PrefixByteOperator}
|
||||
}
|
||||
|
||||
// Claims returns the accounts claims data
|
||||
func (a *AccountClaims) Claims() *ClaimsData {
|
||||
return &a.ClaimsData
|
||||
}
|
||||
|
||||
// DidSign checks the claims against the account's public key and its signing keys
|
||||
func (a *AccountClaims) DidSign(op Claims) bool {
|
||||
if op != nil {
|
||||
issuer := op.Claims().Issuer
|
||||
if issuer == a.Subject {
|
||||
return true
|
||||
}
|
||||
return a.SigningKeys.Contains(issuer)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Revoke enters a revocation by publickey using time.Now().
|
||||
func (a *AccountClaims) Revoke(pubKey string) {
|
||||
a.RevokeAt(pubKey, time.Now())
|
||||
}
|
||||
|
||||
// RevokeAt enters a revocation by publickey and timestamp into this export
|
||||
// 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 {
|
||||
a.Revocations = RevocationList{}
|
||||
}
|
||||
|
||||
a.Revocations.Revoke(pubKey, timestamp)
|
||||
}
|
||||
|
||||
// ClearRevocation removes any revocation for the public key
|
||||
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.
|
||||
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())
|
||||
}
|
166
gateway/vendor/github.com/nats-io/jwt/activation_claims.go
generated
vendored
Normal file
166
gateway/vendor/github.com/nats-io/jwt/activation_claims.go
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2018 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 (
|
||||
"crypto/sha256"
|
||||
"encoding/base32"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// Activation defines the custom parts of an activation claim
|
||||
type Activation struct {
|
||||
ImportSubject Subject `json:"subject,omitempty"`
|
||||
ImportType ExportType `json:"type,omitempty"`
|
||||
Limits
|
||||
}
|
||||
|
||||
// IsService returns true if an Activation is for a service
|
||||
func (a *Activation) IsService() bool {
|
||||
return a.ImportType == Service
|
||||
}
|
||||
|
||||
// IsStream returns true if an Activation is for a stream
|
||||
func (a *Activation) IsStream() bool {
|
||||
return a.ImportType == Stream
|
||||
}
|
||||
|
||||
// Validate checks the exports and limits in an activation JWT
|
||||
func (a *Activation) Validate(vr *ValidationResults) {
|
||||
if !a.IsService() && !a.IsStream() {
|
||||
vr.AddError("invalid export type: %q", a.ImportType)
|
||||
}
|
||||
|
||||
if a.IsService() {
|
||||
if a.ImportSubject.HasWildCards() {
|
||||
vr.AddError("services cannot have wildcard subject: %q", a.ImportSubject)
|
||||
}
|
||||
}
|
||||
|
||||
a.ImportSubject.Validate(vr)
|
||||
a.Limits.Validate(vr)
|
||||
}
|
||||
|
||||
// ActivationClaims holds the data specific to an activation JWT
|
||||
type ActivationClaims struct {
|
||||
ClaimsData
|
||||
Activation `json:"nats,omitempty"`
|
||||
// IssuerAccount stores the public key for the account the issuer represents.
|
||||
// When set, the claim was issued by a signing key.
|
||||
IssuerAccount string `json:"issuer_account,omitempty"`
|
||||
}
|
||||
|
||||
// NewActivationClaims creates a new activation claim with the provided sub
|
||||
func NewActivationClaims(subject string) *ActivationClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
ac := &ActivationClaims{}
|
||||
ac.Subject = subject
|
||||
return ac
|
||||
}
|
||||
|
||||
// Encode turns an activation claim into a JWT strimg
|
||||
func (a *ActivationClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicAccountKey(a.ClaimsData.Subject) {
|
||||
return "", errors.New("expected subject to be an account")
|
||||
}
|
||||
a.ClaimsData.Type = ActivationClaim
|
||||
return a.ClaimsData.Encode(pair, a)
|
||||
}
|
||||
|
||||
// DecodeActivationClaims tries to create an activation claim from a JWT string
|
||||
func DecodeActivationClaims(token string) (*ActivationClaims, error) {
|
||||
v := ActivationClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
// Payload returns the activation specific part of the JWT
|
||||
func (a *ActivationClaims) Payload() interface{} {
|
||||
return a.Activation
|
||||
}
|
||||
|
||||
// Validate checks the claims
|
||||
func (a *ActivationClaims) Validate(vr *ValidationResults) {
|
||||
a.ClaimsData.Validate(vr)
|
||||
a.Activation.Validate(vr)
|
||||
if a.IssuerAccount != "" && !nkeys.IsValidPublicAccountKey(a.IssuerAccount) {
|
||||
vr.AddError("account_id is not an account public key")
|
||||
}
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the types that can sign an activation jwt, account and oeprator
|
||||
func (a *ActivationClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteAccount, nkeys.PrefixByteOperator}
|
||||
}
|
||||
|
||||
// Claims returns the generic part of the JWT
|
||||
func (a *ActivationClaims) Claims() *ClaimsData {
|
||||
return &a.ClaimsData
|
||||
}
|
||||
|
||||
func (a *ActivationClaims) String() string {
|
||||
return a.ClaimsData.String(a)
|
||||
}
|
||||
|
||||
// HashID returns a hash of the claims that can be used to identify it.
|
||||
// The hash is calculated by creating a string with
|
||||
// issuerPubKey.subjectPubKey.<subject> and constructing the sha-256 hash and base32 encoding that.
|
||||
// <subject> is the exported subject, minus any wildcards, so foo.* becomes foo.
|
||||
// the one special case is that if the export start with "*" or is ">" the <subject> "_"
|
||||
func (a *ActivationClaims) HashID() (string, error) {
|
||||
|
||||
if a.Issuer == "" || a.Subject == "" || a.ImportSubject == "" {
|
||||
return "", fmt.Errorf("not enough data in the activaion claims to create a hash")
|
||||
}
|
||||
|
||||
subject := cleanSubject(string(a.ImportSubject))
|
||||
base := fmt.Sprintf("%s.%s.%s", a.Issuer, a.Subject, subject)
|
||||
h := sha256.New()
|
||||
h.Write([]byte(base))
|
||||
sha := h.Sum(nil)
|
||||
hash := base32.StdEncoding.EncodeToString(sha)
|
||||
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
func cleanSubject(subject string) string {
|
||||
split := strings.Split(subject, ".")
|
||||
cleaned := ""
|
||||
|
||||
for i, tok := range split {
|
||||
if tok == "*" || tok == ">" {
|
||||
if i == 0 {
|
||||
cleaned = "_"
|
||||
break
|
||||
}
|
||||
|
||||
cleaned = strings.Join(split[:i], ".")
|
||||
break
|
||||
}
|
||||
}
|
||||
if cleaned == "" {
|
||||
cleaned = subject
|
||||
}
|
||||
return cleaned
|
||||
}
|
302
gateway/vendor/github.com/nats-io/jwt/claims.go
generated
vendored
Normal file
302
gateway/vendor/github.com/nats-io/jwt/claims.go
generated
vendored
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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 (
|
||||
"crypto/sha512"
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// ClaimType is used to indicate the type of JWT being stored in a Claim
|
||||
type ClaimType string
|
||||
|
||||
const (
|
||||
// AccountClaim is the type of an Account JWT
|
||||
AccountClaim = "account"
|
||||
//ActivationClaim is the type of an activation JWT
|
||||
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"
|
||||
)
|
||||
|
||||
// Claims is a JWT claims
|
||||
type Claims interface {
|
||||
Claims() *ClaimsData
|
||||
Encode(kp nkeys.KeyPair) (string, error)
|
||||
ExpectedPrefixes() []nkeys.PrefixByte
|
||||
Payload() interface{}
|
||||
String() string
|
||||
Validate(vr *ValidationResults)
|
||||
Verify(payload string, sig []byte) bool
|
||||
}
|
||||
|
||||
// ClaimsData is the base struct for all claims
|
||||
type ClaimsData struct {
|
||||
Audience string `json:"aud,omitempty"`
|
||||
Expires int64 `json:"exp,omitempty"`
|
||||
ID string `json:"jti,omitempty"`
|
||||
IssuedAt int64 `json:"iat,omitempty"`
|
||||
Issuer string `json:"iss,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
NotBefore int64 `json:"nbf,omitempty"`
|
||||
Subject string `json:"sub,omitempty"`
|
||||
Tags TagList `json:"tags,omitempty"`
|
||||
Type ClaimType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// Prefix holds the prefix byte for an NKey
|
||||
type Prefix struct {
|
||||
nkeys.PrefixByte
|
||||
}
|
||||
|
||||
func encodeToString(d []byte) string {
|
||||
return base64.RawURLEncoding.EncodeToString(d)
|
||||
}
|
||||
|
||||
func decodeString(s string) ([]byte, error) {
|
||||
return base64.RawURLEncoding.DecodeString(s)
|
||||
}
|
||||
|
||||
func serialize(v interface{}) (string, error) {
|
||||
j, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return encodeToString(j), nil
|
||||
}
|
||||
|
||||
func (c *ClaimsData) doEncode(header *Header, kp nkeys.KeyPair, claim Claims) (string, error) {
|
||||
if header == nil {
|
||||
return "", errors.New("header is required")
|
||||
}
|
||||
|
||||
if kp == nil {
|
||||
return "", errors.New("keypair is required")
|
||||
}
|
||||
|
||||
if c.Subject == "" {
|
||||
return "", errors.New("subject is not set")
|
||||
}
|
||||
|
||||
h, err := serialize(header)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
issuerBytes, err := kp.PublicKey()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
prefixes := claim.ExpectedPrefixes()
|
||||
if prefixes != nil {
|
||||
ok := false
|
||||
for _, p := range prefixes {
|
||||
switch p {
|
||||
case nkeys.PrefixByteAccount:
|
||||
if nkeys.IsValidPublicAccountKey(issuerBytes) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteOperator:
|
||||
if nkeys.IsValidPublicOperatorKey(issuerBytes) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteServer:
|
||||
if nkeys.IsValidPublicServerKey(issuerBytes) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteCluster:
|
||||
if nkeys.IsValidPublicClusterKey(issuerBytes) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteUser:
|
||||
if nkeys.IsValidPublicUserKey(issuerBytes) {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unable to validate expected prefixes - %v", prefixes)
|
||||
}
|
||||
}
|
||||
|
||||
c.Issuer = string(issuerBytes)
|
||||
c.IssuedAt = time.Now().UTC().Unix()
|
||||
|
||||
c.ID, err = c.hash()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
payload, err := serialize(claim)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sig, err := kp.Sign([]byte(payload))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
eSig := encodeToString(sig)
|
||||
return fmt.Sprintf("%s.%s.%s", h, payload, eSig), nil
|
||||
}
|
||||
|
||||
func (c *ClaimsData) hash() (string, error) {
|
||||
j, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
h := sha512.New512_256()
|
||||
h.Write(j)
|
||||
return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// Encode encodes a claim into a JWT token. The claim is signed with the
|
||||
// provided nkey's private key
|
||||
func (c *ClaimsData) Encode(kp nkeys.KeyPair, payload Claims) (string, error) {
|
||||
return c.doEncode(&Header{TokenTypeJwt, AlgorithmNkey}, kp, payload)
|
||||
}
|
||||
|
||||
// Returns a JSON representation of the claim
|
||||
func (c *ClaimsData) String(claim interface{}) string {
|
||||
j, err := json.MarshalIndent(claim, "", " ")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(j)
|
||||
}
|
||||
|
||||
func parseClaims(s string, target Claims) error {
|
||||
h, err := decodeString(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(h, &target)
|
||||
}
|
||||
|
||||
// Verify verifies that the encoded payload was signed by the
|
||||
// provided public key. Verify is called automatically with
|
||||
// the claims portion of the token and the public key in the claim.
|
||||
// Client code need to insure that the public key in the
|
||||
// claim is trusted.
|
||||
func (c *ClaimsData) Verify(payload string, sig []byte) bool {
|
||||
// decode the public key
|
||||
kp, err := nkeys.FromPublicKey(c.Issuer)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if err := kp.Verify([]byte(payload), sig); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Validate checks a claim to make sure it is valid. Validity checks
|
||||
// include expiration and not before constraints.
|
||||
func (c *ClaimsData) Validate(vr *ValidationResults) {
|
||||
now := time.Now().UTC().Unix()
|
||||
if c.Expires > 0 && now > c.Expires {
|
||||
vr.AddTimeCheck("claim is expired")
|
||||
}
|
||||
|
||||
if c.NotBefore > 0 && c.NotBefore > now {
|
||||
vr.AddTimeCheck("claim is not yet valid")
|
||||
}
|
||||
}
|
||||
|
||||
// IsSelfSigned returns true if the claims issuer is the subject
|
||||
func (c *ClaimsData) IsSelfSigned() bool {
|
||||
return c.Issuer == c.Subject
|
||||
}
|
||||
|
||||
// Decode takes a JWT string decodes it and validates it
|
||||
// and return the embedded Claims. If the token header
|
||||
// doesn't match the expected algorithm, or the claim is
|
||||
// not valid or verification fails an error is returned.
|
||||
func Decode(token string, target Claims) error {
|
||||
// must have 3 chunks
|
||||
chunks := strings.Split(token, ".")
|
||||
if len(chunks) != 3 {
|
||||
return errors.New("expected 3 chunks")
|
||||
}
|
||||
|
||||
_, err := parseHeaders(chunks[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := parseClaims(chunks[1], target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sig, err := decodeString(chunks[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !target.Verify(chunks[1], sig) {
|
||||
return errors.New("claim failed signature verification")
|
||||
}
|
||||
|
||||
prefixes := target.ExpectedPrefixes()
|
||||
if prefixes != nil {
|
||||
ok := false
|
||||
issuer := target.Claims().Issuer
|
||||
for _, p := range prefixes {
|
||||
switch p {
|
||||
case nkeys.PrefixByteAccount:
|
||||
if nkeys.IsValidPublicAccountKey(issuer) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteOperator:
|
||||
if nkeys.IsValidPublicOperatorKey(issuer) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteServer:
|
||||
if nkeys.IsValidPublicServerKey(issuer) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteCluster:
|
||||
if nkeys.IsValidPublicClusterKey(issuer) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteUser:
|
||||
if nkeys.IsValidPublicUserKey(issuer) {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("unable to validate expected prefixes - %v", prefixes)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
94
gateway/vendor/github.com/nats-io/jwt/cluster_claims.go
generated
vendored
Normal file
94
gateway/vendor/github.com/nats-io/jwt/cluster_claims.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2018 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 (
|
||||
"errors"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// Cluster stores the cluster specific elements of a cluster JWT
|
||||
type Cluster struct {
|
||||
Trust []string `json:"identity,omitempty"`
|
||||
Accounts []string `json:"accts,omitempty"`
|
||||
AccountURL string `json:"accturl,omitempty"`
|
||||
OperatorURL string `json:"opurl,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the cluster and permissions for a cluster JWT
|
||||
func (c *Cluster) Validate(vr *ValidationResults) {
|
||||
// fixme validate cluster data
|
||||
}
|
||||
|
||||
// ClusterClaims defines the data in a cluster JWT
|
||||
type ClusterClaims struct {
|
||||
ClaimsData
|
||||
Cluster `json:"nats,omitempty"`
|
||||
}
|
||||
|
||||
// NewClusterClaims creates a new cluster JWT with the specified subject/public key
|
||||
func NewClusterClaims(subject string) *ClusterClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := &ClusterClaims{}
|
||||
c.Subject = subject
|
||||
return c
|
||||
}
|
||||
|
||||
// Encode tries to turn the cluster claims into a JWT string
|
||||
func (c *ClusterClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicClusterKey(c.Subject) {
|
||||
return "", errors.New("expected subject to be a cluster public key")
|
||||
}
|
||||
c.ClaimsData.Type = ClusterClaim
|
||||
return c.ClaimsData.Encode(pair, c)
|
||||
}
|
||||
|
||||
// DecodeClusterClaims tries to parse cluster claims from a JWT string
|
||||
func DecodeClusterClaims(token string) (*ClusterClaims, error) {
|
||||
v := ClusterClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (c *ClusterClaims) String() string {
|
||||
return c.ClaimsData.String(c)
|
||||
}
|
||||
|
||||
// Payload returns the cluster specific data
|
||||
func (c *ClusterClaims) Payload() interface{} {
|
||||
return &c.Cluster
|
||||
}
|
||||
|
||||
// Validate checks the generic and cluster data in the cluster claims
|
||||
func (c *ClusterClaims) Validate(vr *ValidationResults) {
|
||||
c.ClaimsData.Validate(vr)
|
||||
c.Cluster.Validate(vr)
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the types that can encode a cluster JWT, operator or cluster
|
||||
func (c *ClusterClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteOperator, nkeys.PrefixByteCluster}
|
||||
}
|
||||
|
||||
// Claims returns the generic data
|
||||
func (c *ClusterClaims) Claims() *ClaimsData {
|
||||
return &c.ClaimsData
|
||||
}
|
203
gateway/vendor/github.com/nats-io/jwt/creds_utils.go
generated
vendored
Normal file
203
gateway/vendor/github.com/nats-io/jwt/creds_utils.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// DecorateJWT returns a decorated JWT that describes the kind of JWT
|
||||
func DecorateJWT(jwtString string) ([]byte, error) {
|
||||
gc, err := DecodeGeneric(jwtString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return formatJwt(string(gc.Type), jwtString)
|
||||
}
|
||||
|
||||
func formatJwt(kind string, jwtString string) ([]byte, error) {
|
||||
templ := `-----BEGIN NATS %s JWT-----
|
||||
%s
|
||||
------END NATS %s JWT------
|
||||
|
||||
`
|
||||
w := bytes.NewBuffer(nil)
|
||||
kind = strings.ToUpper(kind)
|
||||
_, err := fmt.Fprintf(w, templ, kind, jwtString, kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
// DecorateSeed takes a seed and returns a string that wraps
|
||||
// the seed in the form:
|
||||
// ************************* IMPORTANT *************************
|
||||
// NKEY Seed printed below can be used sign and prove identity.
|
||||
// NKEYs are sensitive and should be treated as secrets.
|
||||
//
|
||||
// -----BEGIN USER NKEY SEED-----
|
||||
// SUAIO3FHUX5PNV2LQIIP7TZ3N4L7TX3W53MQGEIVYFIGA635OZCKEYHFLM
|
||||
// ------END USER NKEY SEED------
|
||||
func DecorateSeed(seed []byte) ([]byte, error) {
|
||||
w := bytes.NewBuffer(nil)
|
||||
ts := bytes.TrimSpace(seed)
|
||||
pre := string(ts[0:2])
|
||||
kind := ""
|
||||
switch pre {
|
||||
case "SU":
|
||||
kind = "USER"
|
||||
case "SA":
|
||||
kind = "ACCOUNT"
|
||||
case "SO":
|
||||
kind = "OPERATOR"
|
||||
default:
|
||||
return nil, errors.New("seed is not an operator, account or user seed")
|
||||
}
|
||||
header := `************************* IMPORTANT *************************
|
||||
NKEY Seed printed below can be used to sign and prove identity.
|
||||
NKEYs are sensitive and should be treated as secrets.
|
||||
|
||||
-----BEGIN %s NKEY SEED-----
|
||||
`
|
||||
_, err := fmt.Fprintf(w, header, kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w.Write(ts)
|
||||
|
||||
footer := `
|
||||
------END %s NKEY SEED------
|
||||
|
||||
*************************************************************
|
||||
`
|
||||
_, err = fmt.Fprintf(w, footer, kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
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-----
|
||||
// eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5...
|
||||
// ------END NATS USER JWT------
|
||||
//
|
||||
// ************************* IMPORTANT *************************
|
||||
// NKEY Seed printed below can be used sign and prove identity.
|
||||
// NKEYs are sensitive and should be treated as secrets.
|
||||
//
|
||||
// -----BEGIN USER NKEY SEED-----
|
||||
// SUAIO3FHUX5PNV2LQIIP7TZ3N4L7TX3W53MQGEIVYFIGA635OZCKEYHFLM
|
||||
// ------END USER NKEY SEED------
|
||||
|
||||
// FormatUserConfig returns a decorated file with a decorated JWT and decorated seed
|
||||
func FormatUserConfig(jwtString string, seed []byte) ([]byte, error) {
|
||||
gc, err := DecodeGeneric(jwtString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if gc.Type != UserClaim {
|
||||
return nil, fmt.Errorf("%q cannot be serialized as a user config", string(gc.Type))
|
||||
}
|
||||
|
||||
w := bytes.NewBuffer(nil)
|
||||
|
||||
jd, err := formatJwt(string(gc.Type), jwtString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = w.Write(jd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !bytes.HasPrefix(bytes.TrimSpace(seed), []byte("SU")) {
|
||||
return nil, fmt.Errorf("nkey seed is not an user seed")
|
||||
}
|
||||
|
||||
d, err := DecorateSeed(seed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = w.Write(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
// ParseDecoratedJWT takes a creds file and returns the JWT portion.
|
||||
func ParseDecoratedJWT(contents []byte) (string, error) {
|
||||
items := userConfigRE.FindAllSubmatch(contents, -1)
|
||||
if len(items) == 0 {
|
||||
return string(contents), nil
|
||||
}
|
||||
// First result should be the user JWT.
|
||||
// We copy here so that if the file contained a seed file too we wipe appropriately.
|
||||
raw := items[0][1]
|
||||
tmp := make([]byte, len(raw))
|
||||
copy(tmp, raw)
|
||||
return string(tmp), nil
|
||||
}
|
||||
|
||||
// ParseDecoratedNKey takes a creds file, finds the NKey portion and creates a
|
||||
// key pair from it.
|
||||
func ParseDecoratedNKey(contents []byte) (nkeys.KeyPair, error) {
|
||||
var seed []byte
|
||||
|
||||
items := userConfigRE.FindAllSubmatch(contents, -1)
|
||||
if len(items) > 1 {
|
||||
seed = items[1][1]
|
||||
} else {
|
||||
lines := bytes.Split(contents, []byte("\n"))
|
||||
for _, line := range lines {
|
||||
if bytes.HasPrefix(bytes.TrimSpace(line), []byte("SO")) ||
|
||||
bytes.HasPrefix(bytes.TrimSpace(line), []byte("SA")) ||
|
||||
bytes.HasPrefix(bytes.TrimSpace(line), []byte("SU")) {
|
||||
seed = line
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if seed == nil {
|
||||
return nil, errors.New("no nkey seed found")
|
||||
}
|
||||
if !bytes.HasPrefix(seed, []byte("SO")) &&
|
||||
!bytes.HasPrefix(seed, []byte("SA")) &&
|
||||
!bytes.HasPrefix(seed, []byte("SU")) {
|
||||
return nil, errors.New("doesn't contain a seed nkey")
|
||||
}
|
||||
kp, err := nkeys.FromSeed(seed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kp, nil
|
||||
}
|
||||
|
||||
// ParseDecoratedUserNKey takes a creds file, finds the NKey portion and creates a
|
||||
// key pair from it. Similar to ParseDecoratedNKey but fails for non-user keys.
|
||||
func ParseDecoratedUserNKey(contents []byte) (nkeys.KeyPair, error) {
|
||||
nk, err := ParseDecoratedNKey(contents)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seed, err := nk.Seed()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !bytes.HasPrefix(seed, []byte("SU")) {
|
||||
return nil, errors.New("doesn't contain an user seed nkey")
|
||||
}
|
||||
kp, err := nkeys.FromSeed(seed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kp, nil
|
||||
}
|
236
gateway/vendor/github.com/nats-io/jwt/exports.go
generated
vendored
Normal file
236
gateway/vendor/github.com/nats-io/jwt/exports.go
generated
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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 (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ResponseType is used to store an export response type
|
||||
type ResponseType string
|
||||
|
||||
const (
|
||||
// ResponseTypeSingleton is used for a service that sends a single response only
|
||||
ResponseTypeSingleton = "Singleton"
|
||||
|
||||
// ResponseTypeStream is used for a service that will send multiple responses
|
||||
ResponseTypeStream = "Stream"
|
||||
|
||||
// ResponseTypeChunked is used for a service that sends a single response in chunks (so not quite a stream)
|
||||
ResponseTypeChunked = "Chunked"
|
||||
)
|
||||
|
||||
// ServiceLatency is used when observing and exported service for
|
||||
// latency measurements.
|
||||
// Sampling 1-100, represents sampling rate, defaults to 100.
|
||||
// Results is the subject where the latency metrics are published.
|
||||
// A metric will be defined by the nats-server's ServiceLatency. Time durations
|
||||
// are in nanoseconds.
|
||||
// see https://github.com/nats-io/nats-server/blob/master/server/accounts.go#L524
|
||||
// e.g.
|
||||
// {
|
||||
// "app": "dlc22",
|
||||
// "start": "2019-09-16T21:46:23.636869585-07:00",
|
||||
// "svc": 219732,
|
||||
// "nats": {
|
||||
// "req": 320415,
|
||||
// "resp": 228268,
|
||||
// "sys": 0
|
||||
// },
|
||||
// "total": 768415
|
||||
// }
|
||||
//
|
||||
type ServiceLatency struct {
|
||||
Sampling int `json:"sampling,omitempty"`
|
||||
Results Subject `json:"results"`
|
||||
}
|
||||
|
||||
func (sl *ServiceLatency) Validate(vr *ValidationResults) {
|
||||
if sl.Sampling < 1 || sl.Sampling > 100 {
|
||||
vr.AddError("sampling percentage needs to be between 1-100")
|
||||
}
|
||||
sl.Results.Validate(vr)
|
||||
if sl.Results.HasWildCards() {
|
||||
vr.AddError("results subject can not contain wildcards")
|
||||
}
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// IsService returns true if an export is for a service
|
||||
func (e *Export) IsService() bool {
|
||||
return e.Type == Service
|
||||
}
|
||||
|
||||
// IsStream returns true if an export is for a stream
|
||||
func (e *Export) IsStream() bool {
|
||||
return e.Type == Stream
|
||||
}
|
||||
|
||||
// IsSingleResponse returns true if an export has a single response
|
||||
// or no resopnse type is set, also checks that the type is service
|
||||
func (e *Export) IsSingleResponse() bool {
|
||||
return e.Type == Service && (e.ResponseType == ResponseTypeSingleton || e.ResponseType == "")
|
||||
}
|
||||
|
||||
// IsChunkedResponse returns true if an export has a chunked response
|
||||
func (e *Export) IsChunkedResponse() bool {
|
||||
return e.Type == Service && e.ResponseType == ResponseTypeChunked
|
||||
}
|
||||
|
||||
// IsStreamResponse returns true if an export has a chunked response
|
||||
func (e *Export) IsStreamResponse() bool {
|
||||
return e.Type == Service && e.ResponseType == ResponseTypeStream
|
||||
}
|
||||
|
||||
// Validate appends validation issues to the passed in results list
|
||||
func (e *Export) Validate(vr *ValidationResults) {
|
||||
if !e.IsService() && !e.IsStream() {
|
||||
vr.AddError("invalid export type: %q", e.Type)
|
||||
}
|
||||
if e.IsService() && !e.IsSingleResponse() && !e.IsChunkedResponse() && !e.IsStreamResponse() {
|
||||
vr.AddError("invalid response type for service: %q", e.ResponseType)
|
||||
}
|
||||
if e.IsStream() && e.ResponseType != "" {
|
||||
vr.AddError("invalid response type for stream: %q", e.ResponseType)
|
||||
}
|
||||
if e.Latency != nil {
|
||||
if !e.IsService() {
|
||||
vr.AddError("latency tracking only permitted for services")
|
||||
}
|
||||
e.Latency.Validate(vr)
|
||||
}
|
||||
e.Subject.Validate(vr)
|
||||
}
|
||||
|
||||
// Revoke enters a revocation by publickey using time.Now().
|
||||
func (e *Export) Revoke(pubKey string) {
|
||||
e.RevokeAt(pubKey, time.Now())
|
||||
}
|
||||
|
||||
// RevokeAt enters a revocation by publickey and timestamp into this export
|
||||
// If there is already a revocation for this public key that is newer, it is kept.
|
||||
func (e *Export) RevokeAt(pubKey string, timestamp time.Time) {
|
||||
if e.Revocations == nil {
|
||||
e.Revocations = RevocationList{}
|
||||
}
|
||||
|
||||
e.Revocations.Revoke(pubKey, timestamp)
|
||||
}
|
||||
|
||||
// ClearRevocation removes any revocation for the public key
|
||||
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.
|
||||
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())
|
||||
}
|
||||
|
||||
// Exports is a slice of exports
|
||||
type Exports []*Export
|
||||
|
||||
// Add appends exports to the list
|
||||
func (e *Exports) Add(i ...*Export) {
|
||||
*e = append(*e, i...)
|
||||
}
|
||||
|
||||
func isContainedIn(kind ExportType, subjects []Subject, vr *ValidationResults) {
|
||||
m := make(map[string]string)
|
||||
for i, ns := range subjects {
|
||||
for j, s := range subjects {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
if ns.IsContainedIn(s) {
|
||||
str := string(s)
|
||||
_, ok := m[str]
|
||||
if !ok {
|
||||
m[str] = string(ns)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(m) != 0 {
|
||||
for k, v := range m {
|
||||
var vi ValidationIssue
|
||||
vi.Blocking = true
|
||||
vi.Description = fmt.Sprintf("%s export subject %q already exports %q", kind, k, v)
|
||||
vr.Add(&vi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate calls validate on all of the exports
|
||||
func (e *Exports) Validate(vr *ValidationResults) error {
|
||||
var serviceSubjects []Subject
|
||||
var streamSubjects []Subject
|
||||
|
||||
for _, v := range *e {
|
||||
if v.IsService() {
|
||||
serviceSubjects = append(serviceSubjects, v.Subject)
|
||||
} else {
|
||||
streamSubjects = append(streamSubjects, v.Subject)
|
||||
}
|
||||
v.Validate(vr)
|
||||
}
|
||||
|
||||
isContainedIn(Service, serviceSubjects, vr)
|
||||
isContainedIn(Stream, streamSubjects, vr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasExportContainingSubject checks if the export list has an export with the provided subject
|
||||
func (e *Exports) HasExportContainingSubject(subject Subject) bool {
|
||||
for _, s := range *e {
|
||||
if subject.IsContainedIn(s.Subject) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e Exports) Len() int {
|
||||
return len(e)
|
||||
}
|
||||
|
||||
func (e Exports) Swap(i, j int) {
|
||||
e[i], e[j] = e[j], e[i]
|
||||
}
|
||||
|
||||
func (e Exports) Less(i, j int) bool {
|
||||
return e[i].Subject < e[j].Subject
|
||||
}
|
73
gateway/vendor/github.com/nats-io/jwt/genericlaims.go
generated
vendored
Normal file
73
gateway/vendor/github.com/nats-io/jwt/genericlaims.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2018 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 "github.com/nats-io/nkeys"
|
||||
|
||||
// GenericClaims can be used to read a JWT as a map for any non-generic fields
|
||||
type GenericClaims struct {
|
||||
ClaimsData
|
||||
Data map[string]interface{} `json:"nats,omitempty"`
|
||||
}
|
||||
|
||||
// NewGenericClaims creates a map-based Claims
|
||||
func NewGenericClaims(subject string) *GenericClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := GenericClaims{}
|
||||
c.Subject = subject
|
||||
c.Data = make(map[string]interface{})
|
||||
return &c
|
||||
}
|
||||
|
||||
// DecodeGeneric takes a JWT string and decodes it into a ClaimsData and map
|
||||
func DecodeGeneric(token string) (*GenericClaims, error) {
|
||||
v := GenericClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
// Claims returns the standard part of the generic claim
|
||||
func (gc *GenericClaims) Claims() *ClaimsData {
|
||||
return &gc.ClaimsData
|
||||
}
|
||||
|
||||
// Payload returns the custom part of the claims data
|
||||
func (gc *GenericClaims) Payload() interface{} {
|
||||
return &gc.Data
|
||||
}
|
||||
|
||||
// Encode takes a generic claims and creates a JWT string
|
||||
func (gc *GenericClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
return gc.ClaimsData.Encode(pair, gc)
|
||||
}
|
||||
|
||||
// Validate checks the generic part of the claims data
|
||||
func (gc *GenericClaims) Validate(vr *ValidationResults) {
|
||||
gc.ClaimsData.Validate(vr)
|
||||
}
|
||||
|
||||
func (gc *GenericClaims) String() string {
|
||||
return gc.ClaimsData.String(gc)
|
||||
}
|
||||
|
||||
// ExpectedPrefixes returns the types allowed to encode a generic JWT, which is nil for all
|
||||
func (gc *GenericClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return nil
|
||||
}
|
3
gateway/vendor/github.com/nats-io/jwt/go.mod
generated
vendored
Normal file
3
gateway/vendor/github.com/nats-io/jwt/go.mod
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
module github.com/nats-io/jwt
|
||||
|
||||
require github.com/nats-io/nkeys v0.1.3
|
9
gateway/vendor/github.com/nats-io/jwt/go.sum
generated
vendored
Normal file
9
gateway/vendor/github.com/nats-io/jwt/go.sum
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
github.com/nats-io/nkeys v0.1.3 h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
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/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=
|
71
gateway/vendor/github.com/nats-io/jwt/header.go
generated
vendored
Normal file
71
gateway/vendor/github.com/nats-io/jwt/header.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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 (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// Version is semantic version.
|
||||
Version = "0.3.2"
|
||||
|
||||
// TokenTypeJwt is the JWT token type supported JWT tokens
|
||||
// encoded and decoded by this library
|
||||
TokenTypeJwt = "jwt"
|
||||
|
||||
// AlgorithmNkey is the algorithm supported by JWT tokens
|
||||
// encoded and decoded by this library
|
||||
AlgorithmNkey = "ed25519"
|
||||
)
|
||||
|
||||
// Header is a JWT Jose Header
|
||||
type Header struct {
|
||||
Type string `json:"typ"`
|
||||
Algorithm string `json:"alg"`
|
||||
}
|
||||
|
||||
// Parses a header JWT token
|
||||
func parseHeaders(s string) (*Header, error) {
|
||||
h, err := decodeString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
header := Header{}
|
||||
if err := json.Unmarshal(h, &header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := header.Valid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &header, nil
|
||||
}
|
||||
|
||||
// Valid validates the Header. It returns nil if the Header is
|
||||
// a JWT header, and the algorithm used is the NKEY algorithm.
|
||||
func (h *Header) Valid() error {
|
||||
if TokenTypeJwt != strings.ToLower(h.Type) {
|
||||
return fmt.Errorf("not supported type %q", h.Type)
|
||||
}
|
||||
|
||||
if AlgorithmNkey != strings.ToLower(h.Algorithm) {
|
||||
return fmt.Errorf("unexpected %q algorithm", h.Algorithm)
|
||||
}
|
||||
return nil
|
||||
}
|
151
gateway/vendor/github.com/nats-io/jwt/imports.go
generated
vendored
Normal file
151
gateway/vendor/github.com/nats-io/jwt/imports.go
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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 (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Import describes a mapping from another account into this one
|
||||
type Import struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
// Subject field in an import is always from the perspective of the
|
||||
// initial publisher - in the case of a stream it is the account owning
|
||||
// the stream (the exporter), and in the case of a service it is the
|
||||
// account making the request (the importer).
|
||||
Subject Subject `json:"subject,omitempty"`
|
||||
Account string `json:"account,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
// To field in an import is always from the perspective of the subscriber
|
||||
// in the case of a stream it is the client of the stream (the importer),
|
||||
// from the perspective of a service, it is the subscription waiting for
|
||||
// requests (the exporter). If the field is empty, it will default to the
|
||||
// value in the Subject field.
|
||||
To Subject `json:"to,omitempty"`
|
||||
Type ExportType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// IsService returns true if the import is of type service
|
||||
func (i *Import) IsService() bool {
|
||||
return i.Type == Service
|
||||
}
|
||||
|
||||
// IsStream returns true if the import is of type stream
|
||||
func (i *Import) IsStream() bool {
|
||||
return i.Type == Stream
|
||||
}
|
||||
|
||||
// Validate checks if an import is valid for the wrapping account
|
||||
func (i *Import) Validate(actPubKey string, vr *ValidationResults) {
|
||||
if !i.IsService() && !i.IsStream() {
|
||||
vr.AddError("invalid import type: %q", i.Type)
|
||||
}
|
||||
|
||||
if i.Account == "" {
|
||||
vr.AddWarning("account to import from is not specified")
|
||||
}
|
||||
|
||||
i.Subject.Validate(vr)
|
||||
|
||||
if i.IsService() && i.Subject.HasWildCards() {
|
||||
vr.AddError("services cannot have wildcard subject: %q", i.Subject)
|
||||
}
|
||||
if i.IsStream() && i.To.HasWildCards() {
|
||||
vr.AddError("streams cannot have wildcard to subject: %q", i.Subject)
|
||||
}
|
||||
|
||||
var act *ActivationClaims
|
||||
|
||||
if i.Token != "" {
|
||||
// Check to see if its an embedded JWT or a URL.
|
||||
if url, err := url.Parse(i.Token); err == nil && url.Scheme != "" {
|
||||
c := &http.Client{Timeout: 5 * time.Second}
|
||||
resp, err := c.Get(url.String())
|
||||
if err != nil {
|
||||
vr.AddWarning("import %s contains an unreachable token URL %q", i.Subject, i.Token)
|
||||
}
|
||||
|
||||
if resp != nil {
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
vr.AddWarning("import %s contains an unreadable token URL %q", i.Subject, i.Token)
|
||||
} else {
|
||||
act, err = DecodeActivationClaims(string(body))
|
||||
if err != nil {
|
||||
vr.AddWarning("import %s contains a url %q with an invalid activation token", i.Subject, i.Token)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
act, err = DecodeActivationClaims(i.Token)
|
||||
if err != nil {
|
||||
vr.AddWarning("import %q contains an invalid activation token", i.Subject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if act != nil {
|
||||
if act.Issuer != i.Account {
|
||||
vr.AddWarning("activation token doesn't match account for import %q", i.Subject)
|
||||
}
|
||||
|
||||
if act.ClaimsData.Subject != actPubKey {
|
||||
vr.AddWarning("activation token doesn't match account it is being included in, %q", i.Subject)
|
||||
}
|
||||
} else {
|
||||
vr.AddWarning("no activation provided for import %s", i.Subject)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Imports is a list of import structs
|
||||
type Imports []*Import
|
||||
|
||||
// Validate checks if an import is valid for the wrapping account
|
||||
func (i *Imports) Validate(acctPubKey string, vr *ValidationResults) {
|
||||
toSet := make(map[Subject]bool, len(*i))
|
||||
for _, v := range *i {
|
||||
if v.Type == Service {
|
||||
if _, ok := toSet[v.To]; ok {
|
||||
vr.AddError("Duplicate To subjects for %q", v.To)
|
||||
}
|
||||
toSet[v.To] = true
|
||||
}
|
||||
v.Validate(acctPubKey, vr)
|
||||
}
|
||||
}
|
||||
|
||||
// Add is a simple way to add imports
|
||||
func (i *Imports) Add(a ...*Import) {
|
||||
*i = append(*i, a...)
|
||||
}
|
||||
|
||||
func (i Imports) Len() int {
|
||||
return len(i)
|
||||
}
|
||||
|
||||
func (i Imports) Swap(j, k int) {
|
||||
i[j], i[k] = i[k], i[j]
|
||||
}
|
||||
|
||||
func (i Imports) Less(j, k int) bool {
|
||||
return i[j].Subject < i[k].Subject
|
||||
}
|
204
gateway/vendor/github.com/nats-io/jwt/operator_claims.go
generated
vendored
Normal file
204
gateway/vendor/github.com/nats-io/jwt/operator_claims.go
generated
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2018 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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// Operator specific claims
|
||||
type Operator struct {
|
||||
// Slice of real identies (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.
|
||||
SigningKeys StringList `json:"signing_keys,omitempty"`
|
||||
// AccountServerURL is a partial URL like "https://host.domain.org:<port>/jwt/v1"
|
||||
// tools will use the prefix and build queries by appending /accounts/<account_id>
|
||||
// or /operator to the path provided. Note this assumes that the account server
|
||||
// can handle requests in a nats-account-server compatible way. See
|
||||
// https://github.com/nats-io/nats-account-server.
|
||||
AccountServerURL string `json:"account_server_url,omitempty"`
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// Validate checks the validity of the operators contents
|
||||
func (o *Operator) Validate(vr *ValidationResults) {
|
||||
if err := o.validateAccountServerURL(); err != nil {
|
||||
vr.AddError(err.Error())
|
||||
}
|
||||
|
||||
for _, v := range o.validateOperatorServiceURLs() {
|
||||
if v != nil {
|
||||
vr.AddError(v.Error())
|
||||
}
|
||||
}
|
||||
|
||||
for _, i := range o.Identities {
|
||||
i.Validate(vr)
|
||||
}
|
||||
|
||||
for _, k := range o.SigningKeys {
|
||||
if !nkeys.IsValidPublicOperatorKey(k) {
|
||||
vr.AddError("%s is not an operator public key", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Operator) validateAccountServerURL() error {
|
||||
if o.AccountServerURL != "" {
|
||||
// We don't care what kind of URL it is so long as it parses
|
||||
// and has a protocol. The account server may impose additional
|
||||
// constraints on the type of URLs that it is able to notify to
|
||||
u, err := url.Parse(o.AccountServerURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing account server url: %v", err)
|
||||
}
|
||||
if u.Scheme == "" {
|
||||
return fmt.Errorf("account server url %q requires a protocol", o.AccountServerURL)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateOperatorServiceURL returns an error if the URL is not a valid NATS or TLS url.
|
||||
func ValidateOperatorServiceURL(v string) error {
|
||||
// should be possible for the service url to not be expressed
|
||||
if v == "" {
|
||||
return nil
|
||||
}
|
||||
u, err := url.Parse(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing operator service url %q: %v", v, err)
|
||||
}
|
||||
|
||||
if u.User != nil {
|
||||
return fmt.Errorf("operator service url %q - credentials are not supported", v)
|
||||
}
|
||||
|
||||
if u.Path != "" {
|
||||
return fmt.Errorf("operator service url %q - paths are not supported", v)
|
||||
}
|
||||
|
||||
lcs := strings.ToLower(u.Scheme)
|
||||
switch lcs {
|
||||
case "nats":
|
||||
return nil
|
||||
case "tls":
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("operator service url %q - protocol not supported (only 'nats' or 'tls' only)", v)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Operator) validateOperatorServiceURLs() []error {
|
||||
var errors []error
|
||||
for _, v := range o.OperatorServiceURLs {
|
||||
if v != "" {
|
||||
if err := ValidateOperatorServiceURL(v); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
// OperatorClaims define the data for an operator JWT
|
||||
type OperatorClaims struct {
|
||||
ClaimsData
|
||||
Operator `json:"nats,omitempty"`
|
||||
}
|
||||
|
||||
// NewOperatorClaims creates a new operator claim with the specified subject, which should be an operator public key
|
||||
func NewOperatorClaims(subject string) *OperatorClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := &OperatorClaims{}
|
||||
c.Subject = subject
|
||||
return c
|
||||
}
|
||||
|
||||
// DidSign checks the claims against the operator's public key and its signing keys
|
||||
func (oc *OperatorClaims) DidSign(op Claims) bool {
|
||||
if op == nil {
|
||||
return false
|
||||
}
|
||||
issuer := op.Claims().Issuer
|
||||
if issuer == oc.Subject {
|
||||
return true
|
||||
}
|
||||
return oc.SigningKeys.Contains(issuer)
|
||||
}
|
||||
|
||||
// Deprecated: AddSigningKey, use claim.SigningKeys.Add()
|
||||
func (oc *OperatorClaims) AddSigningKey(pk string) {
|
||||
oc.SigningKeys.Add(pk)
|
||||
}
|
||||
|
||||
// Encode the claims into a JWT string
|
||||
func (oc *OperatorClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicOperatorKey(oc.Subject) {
|
||||
return "", errors.New("expected subject to be an operator public key")
|
||||
}
|
||||
err := oc.validateAccountServerURL()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
oc.ClaimsData.Type = OperatorClaim
|
||||
return oc.ClaimsData.Encode(pair, oc)
|
||||
}
|
||||
|
||||
// DecodeOperatorClaims tries to create an operator claims from a JWt string
|
||||
func DecodeOperatorClaims(token string) (*OperatorClaims, error) {
|
||||
v := OperatorClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (oc *OperatorClaims) String() string {
|
||||
return oc.ClaimsData.String(oc)
|
||||
}
|
||||
|
||||
// Payload returns the operator specific data for an operator JWT
|
||||
func (oc *OperatorClaims) Payload() interface{} {
|
||||
return &oc.Operator
|
||||
}
|
||||
|
||||
// Validate the contents of the claims
|
||||
func (oc *OperatorClaims) Validate(vr *ValidationResults) {
|
||||
oc.ClaimsData.Validate(vr)
|
||||
oc.Operator.Validate(vr)
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the nkey types that can sign operator claims, operator
|
||||
func (oc *OperatorClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteOperator}
|
||||
}
|
||||
|
||||
// Claims returns the generic claims data
|
||||
func (oc *OperatorClaims) Claims() *ClaimsData {
|
||||
return &oc.ClaimsData
|
||||
}
|
32
gateway/vendor/github.com/nats-io/jwt/revocation_list.go
generated
vendored
Normal file
32
gateway/vendor/github.com/nats-io/jwt/revocation_list.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RevocationList is used to store a mapping of public keys to unix timestamps
|
||||
type RevocationList map[string]int64
|
||||
|
||||
// Revoke enters a revocation by publickey and timestamp into this export
|
||||
// If there is already a revocation for this public key that is newer, it is kept.
|
||||
func (r RevocationList) Revoke(pubKey string, timestamp time.Time) {
|
||||
newTS := timestamp.Unix()
|
||||
if ts, ok := r[pubKey]; ok && ts > newTS {
|
||||
return
|
||||
}
|
||||
|
||||
r[pubKey] = newTS
|
||||
}
|
||||
|
||||
// ClearRevocation removes any revocation for the public key
|
||||
func (r RevocationList) ClearRevocation(pubKey string) {
|
||||
delete(r, pubKey)
|
||||
}
|
||||
|
||||
// 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
|
||||
// be used for testing.
|
||||
func (r RevocationList) IsRevoked(pubKey string, timestamp time.Time) bool {
|
||||
ts, ok := r[pubKey]
|
||||
return ok && ts > timestamp.Unix()
|
||||
}
|
94
gateway/vendor/github.com/nats-io/jwt/server_claims.go
generated
vendored
Normal file
94
gateway/vendor/github.com/nats-io/jwt/server_claims.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2018 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 (
|
||||
"errors"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// Server defines the custom part of a server jwt
|
||||
type Server struct {
|
||||
Permissions
|
||||
Cluster string `json:"cluster,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the cluster and permissions for a server JWT
|
||||
func (s *Server) Validate(vr *ValidationResults) {
|
||||
if s.Cluster == "" {
|
||||
vr.AddError("servers can't contain an empty cluster")
|
||||
}
|
||||
}
|
||||
|
||||
// ServerClaims defines the data in a server JWT
|
||||
type ServerClaims struct {
|
||||
ClaimsData
|
||||
Server `json:"nats,omitempty"`
|
||||
}
|
||||
|
||||
// NewServerClaims creates a new server JWT with the specified subject/public key
|
||||
func NewServerClaims(subject string) *ServerClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := &ServerClaims{}
|
||||
c.Subject = subject
|
||||
return c
|
||||
}
|
||||
|
||||
// Encode tries to turn the server claims into a JWT string
|
||||
func (s *ServerClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicServerKey(s.Subject) {
|
||||
return "", errors.New("expected subject to be a server public key")
|
||||
}
|
||||
s.ClaimsData.Type = ServerClaim
|
||||
return s.ClaimsData.Encode(pair, s)
|
||||
}
|
||||
|
||||
// DecodeServerClaims tries to parse server claims from a JWT string
|
||||
func DecodeServerClaims(token string) (*ServerClaims, error) {
|
||||
v := ServerClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (s *ServerClaims) String() string {
|
||||
return s.ClaimsData.String(s)
|
||||
}
|
||||
|
||||
// Payload returns the server specific data
|
||||
func (s *ServerClaims) Payload() interface{} {
|
||||
return &s.Server
|
||||
}
|
||||
|
||||
// Validate checks the generic and server data in the server claims
|
||||
func (s *ServerClaims) Validate(vr *ValidationResults) {
|
||||
s.ClaimsData.Validate(vr)
|
||||
s.Server.Validate(vr)
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the types that can encode a server JWT, operator or cluster
|
||||
func (s *ServerClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteOperator, nkeys.PrefixByteCluster}
|
||||
}
|
||||
|
||||
// Claims returns the generic data
|
||||
func (s *ServerClaims) Claims() *ClaimsData {
|
||||
return &s.ClaimsData
|
||||
}
|
334
gateway/vendor/github.com/nats-io/jwt/types.go
generated
vendored
Normal file
334
gateway/vendor/github.com/nats-io/jwt/types.go
generated
vendored
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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 (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ExportType defines the type of import/export.
|
||||
type ExportType int
|
||||
|
||||
const (
|
||||
// Unknown is used if we don't know the type
|
||||
Unknown ExportType = iota
|
||||
// Stream defines the type field value for a stream "stream"
|
||||
Stream
|
||||
// Service defines the type field value for a service "service"
|
||||
Service
|
||||
)
|
||||
|
||||
func (t ExportType) String() string {
|
||||
switch t {
|
||||
case Stream:
|
||||
return "stream"
|
||||
case Service:
|
||||
return "service"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the enum as a quoted json string
|
||||
func (t *ExportType) MarshalJSON() ([]byte, error) {
|
||||
switch *t {
|
||||
case Stream:
|
||||
return []byte("\"stream\""), nil
|
||||
case Service:
|
||||
return []byte("\"service\""), nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown export type")
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmashals a quoted json string to the enum value
|
||||
func (t *ExportType) UnmarshalJSON(b []byte) error {
|
||||
var j string
|
||||
err := json.Unmarshal(b, &j)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch j {
|
||||
case "stream":
|
||||
*t = Stream
|
||||
return nil
|
||||
case "service":
|
||||
*t = Service
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown export type")
|
||||
}
|
||||
|
||||
// Subject is a string that represents a NATS subject
|
||||
type Subject string
|
||||
|
||||
// Validate checks that a subject string is valid, ie not empty and without spaces
|
||||
func (s Subject) Validate(vr *ValidationResults) {
|
||||
v := string(s)
|
||||
if v == "" {
|
||||
vr.AddError("subject cannot be empty")
|
||||
}
|
||||
if strings.Contains(v, " ") {
|
||||
vr.AddError("subject %q cannot have spaces", v)
|
||||
}
|
||||
}
|
||||
|
||||
// HasWildCards is used to check if a subject contains a > or *
|
||||
func (s Subject) HasWildCards() bool {
|
||||
v := string(s)
|
||||
return strings.HasSuffix(v, ".>") ||
|
||||
strings.Contains(v, ".*.") ||
|
||||
strings.HasSuffix(v, ".*") ||
|
||||
strings.HasPrefix(v, "*.") ||
|
||||
v == "*" ||
|
||||
v == ">"
|
||||
}
|
||||
|
||||
// IsContainedIn does a simple test to see if the subject is contained in another subject
|
||||
func (s Subject) IsContainedIn(other Subject) bool {
|
||||
otherArray := strings.Split(string(other), ".")
|
||||
myArray := strings.Split(string(s), ".")
|
||||
|
||||
if len(myArray) > len(otherArray) && otherArray[len(otherArray)-1] != ">" {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(myArray) < len(otherArray) {
|
||||
return false
|
||||
}
|
||||
|
||||
for ind, tok := range otherArray {
|
||||
myTok := myArray[ind]
|
||||
|
||||
if ind == len(otherArray)-1 && tok == ">" {
|
||||
return true
|
||||
}
|
||||
|
||||
if tok != myTok && tok != "*" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// NamedSubject is the combination of a subject and a name for it
|
||||
type NamedSubject struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Subject Subject `json:"subject,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the subject
|
||||
func (ns *NamedSubject) Validate(vr *ValidationResults) {
|
||||
ns.Subject.Validate(vr)
|
||||
}
|
||||
|
||||
// TimeRange is used to represent a start and end time
|
||||
type TimeRange struct {
|
||||
Start string `json:"start,omitempty"`
|
||||
End string `json:"end,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the values in a time range struct
|
||||
func (tr *TimeRange) Validate(vr *ValidationResults) {
|
||||
format := "15:04:05"
|
||||
|
||||
if tr.Start == "" {
|
||||
vr.AddError("time ranges start must contain a start")
|
||||
} else {
|
||||
_, err := time.Parse(format, tr.Start)
|
||||
if err != nil {
|
||||
vr.AddError("start in time range is invalid %q", tr.Start)
|
||||
}
|
||||
}
|
||||
|
||||
if tr.End == "" {
|
||||
vr.AddError("time ranges end must contain an end")
|
||||
} else {
|
||||
_, err := time.Parse(format, tr.End)
|
||||
if err != nil {
|
||||
vr.AddError("end in time range is invalid %q", tr.End)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Limits are used to control acccess for users and importing accounts
|
||||
// Src is a comma separated list of CIDR specifications
|
||||
type Limits struct {
|
||||
Max int64 `json:"max,omitempty"`
|
||||
Payload int64 `json:"payload,omitempty"`
|
||||
Src string `json:"src,omitempty"`
|
||||
Times []TimeRange `json:"times,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the values in a limit struct
|
||||
func (l *Limits) Validate(vr *ValidationResults) {
|
||||
if l.Max < 0 {
|
||||
vr.AddError("limits cannot contain a negative maximum, %d", l.Max)
|
||||
}
|
||||
if l.Payload < 0 {
|
||||
vr.AddError("limits cannot contain a negative payload, %d", l.Payload)
|
||||
}
|
||||
|
||||
if l.Src != "" {
|
||||
elements := strings.Split(l.Src, ",")
|
||||
|
||||
for _, cidr := range elements {
|
||||
cidr = strings.TrimSpace(cidr)
|
||||
_, ipNet, err := net.ParseCIDR(cidr)
|
||||
if err != nil || ipNet == nil {
|
||||
vr.AddError("invalid cidr %q in user src limits", cidr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if l.Times != nil && len(l.Times) > 0 {
|
||||
for _, t := range l.Times {
|
||||
t.Validate(vr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Permission defines allow/deny subjects
|
||||
type Permission struct {
|
||||
Allow StringList `json:"allow,omitempty"`
|
||||
Deny StringList `json:"deny,omitempty"`
|
||||
}
|
||||
|
||||
// Validate the allow, deny elements of a permission
|
||||
func (p *Permission) Validate(vr *ValidationResults) {
|
||||
for _, subj := range p.Allow {
|
||||
Subject(subj).Validate(vr)
|
||||
}
|
||||
for _, subj := range p.Deny {
|
||||
Subject(subj).Validate(vr)
|
||||
}
|
||||
}
|
||||
|
||||
// ResponsePermission can be used to allow responses to any reply subject
|
||||
// that is received on a valid subscription.
|
||||
type ResponsePermission struct {
|
||||
MaxMsgs int `json:"max"`
|
||||
Expires time.Duration `json:"ttl"`
|
||||
}
|
||||
|
||||
// Validate the response permission.
|
||||
func (p *ResponsePermission) Validate(vr *ValidationResults) {
|
||||
// Any values can be valid for now.
|
||||
}
|
||||
|
||||
// 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"`
|
||||
Resp *ResponsePermission `json:"resp,omitempty"`
|
||||
}
|
||||
|
||||
// Validate the pub and sub fields in the permissions list
|
||||
func (p *Permissions) Validate(vr *ValidationResults) {
|
||||
p.Pub.Validate(vr)
|
||||
p.Sub.Validate(vr)
|
||||
if p.Resp != nil {
|
||||
p.Resp.Validate(vr)
|
||||
}
|
||||
}
|
||||
|
||||
// StringList is a wrapper for an array of strings
|
||||
type StringList []string
|
||||
|
||||
// Contains returns true if the list contains the string
|
||||
func (u *StringList) Contains(p string) bool {
|
||||
for _, t := range *u {
|
||||
if t == p {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Add appends 1 or more strings to a list
|
||||
func (u *StringList) Add(p ...string) {
|
||||
for _, v := range p {
|
||||
if !u.Contains(v) && v != "" {
|
||||
*u = append(*u, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes 1 or more strings from a list
|
||||
func (u *StringList) Remove(p ...string) {
|
||||
for _, v := range p {
|
||||
for i, t := range *u {
|
||||
if t == v {
|
||||
a := *u
|
||||
*u = append(a[:i], a[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TagList is a unique array of lower case strings
|
||||
// All tag list methods lower case the strings in the arguments
|
||||
type TagList []string
|
||||
|
||||
// Contains returns true if the list contains the tags
|
||||
func (u *TagList) Contains(p string) bool {
|
||||
p = strings.ToLower(p)
|
||||
for _, t := range *u {
|
||||
if t == p {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Add appends 1 or more tags to a list
|
||||
func (u *TagList) Add(p ...string) {
|
||||
for _, v := range p {
|
||||
v = strings.ToLower(v)
|
||||
if !u.Contains(v) && v != "" {
|
||||
*u = append(*u, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes 1 or more tags from a list
|
||||
func (u *TagList) Remove(p ...string) {
|
||||
for _, v := range p {
|
||||
v = strings.ToLower(v)
|
||||
for i, t := range *u {
|
||||
if t == v {
|
||||
a := *u
|
||||
*u = append(a[:i], a[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Identity is used to associate an account or operator with a real entity
|
||||
type Identity struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Proof string `json:"proof,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the values in an Identity
|
||||
func (u *Identity) Validate(vr *ValidationResults) {
|
||||
//Fixme identity validation
|
||||
}
|
99
gateway/vendor/github.com/nats-io/jwt/user_claims.go
generated
vendored
Normal file
99
gateway/vendor/github.com/nats-io/jwt/user_claims.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2018-2019 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 (
|
||||
"errors"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// User defines the user specific data in a user JWT
|
||||
type User struct {
|
||||
Permissions
|
||||
Limits
|
||||
}
|
||||
|
||||
// Validate checks the permissions and limits in a User jwt
|
||||
func (u *User) Validate(vr *ValidationResults) {
|
||||
u.Permissions.Validate(vr)
|
||||
u.Limits.Validate(vr)
|
||||
}
|
||||
|
||||
// UserClaims defines a user JWT
|
||||
type UserClaims struct {
|
||||
ClaimsData
|
||||
User `json:"nats,omitempty"`
|
||||
// IssuerAccount stores the public key for the account the issuer represents.
|
||||
// When set, the claim was issued by a signing key.
|
||||
IssuerAccount string `json:"issuer_account,omitempty"`
|
||||
}
|
||||
|
||||
// NewUserClaims creates a user JWT with the specific subject/public key
|
||||
func NewUserClaims(subject string) *UserClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := &UserClaims{}
|
||||
c.Subject = subject
|
||||
return c
|
||||
}
|
||||
|
||||
// Encode tries to turn the user claims into a JWT string
|
||||
func (u *UserClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicUserKey(u.Subject) {
|
||||
return "", errors.New("expected subject to be user public key")
|
||||
}
|
||||
u.ClaimsData.Type = UserClaim
|
||||
return u.ClaimsData.Encode(pair, u)
|
||||
}
|
||||
|
||||
// DecodeUserClaims tries to parse a user claims from a JWT string
|
||||
func DecodeUserClaims(token string) (*UserClaims, error) {
|
||||
v := UserClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
// Validate checks the generic and specific parts of the user jwt
|
||||
func (u *UserClaims) Validate(vr *ValidationResults) {
|
||||
u.ClaimsData.Validate(vr)
|
||||
u.User.Validate(vr)
|
||||
if u.IssuerAccount != "" && !nkeys.IsValidPublicAccountKey(u.IssuerAccount) {
|
||||
vr.AddError("account_id is not an account public key")
|
||||
}
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the types that can encode a user JWT, account
|
||||
func (u *UserClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteAccount}
|
||||
}
|
||||
|
||||
// Claims returns the generic data from a user jwt
|
||||
func (u *UserClaims) Claims() *ClaimsData {
|
||||
return &u.ClaimsData
|
||||
}
|
||||
|
||||
// Payload returns the user specific data from a user JWT
|
||||
func (u *UserClaims) Payload() interface{} {
|
||||
return &u.User
|
||||
}
|
||||
|
||||
func (u *UserClaims) String() string {
|
||||
return u.ClaimsData.String(u)
|
||||
}
|
107
gateway/vendor/github.com/nats-io/jwt/validation.go
generated
vendored
Normal file
107
gateway/vendor/github.com/nats-io/jwt/validation.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2018 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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ValidationIssue represents an issue during JWT validation, it may or may not be a blocking error
|
||||
type ValidationIssue struct {
|
||||
Description string
|
||||
Blocking bool
|
||||
TimeCheck bool
|
||||
}
|
||||
|
||||
func (ve *ValidationIssue) Error() string {
|
||||
return ve.Description
|
||||
}
|
||||
|
||||
// ValidationResults is a list of ValidationIssue pointers
|
||||
type ValidationResults struct {
|
||||
Issues []*ValidationIssue
|
||||
}
|
||||
|
||||
// CreateValidationResults creates an empty list of validation issues
|
||||
func CreateValidationResults() *ValidationResults {
|
||||
issues := []*ValidationIssue{}
|
||||
return &ValidationResults{
|
||||
Issues: issues,
|
||||
}
|
||||
}
|
||||
|
||||
//Add appends an issue to the list
|
||||
func (v *ValidationResults) Add(vi *ValidationIssue) {
|
||||
v.Issues = append(v.Issues, vi)
|
||||
}
|
||||
|
||||
// AddError creates a new validation error and adds it to the list
|
||||
func (v *ValidationResults) AddError(format string, args ...interface{}) {
|
||||
v.Add(&ValidationIssue{
|
||||
Description: fmt.Sprintf(format, args...),
|
||||
Blocking: true,
|
||||
TimeCheck: false,
|
||||
})
|
||||
}
|
||||
|
||||
// AddTimeCheck creates a new validation issue related to a time check and adds it to the list
|
||||
func (v *ValidationResults) AddTimeCheck(format string, args ...interface{}) {
|
||||
v.Add(&ValidationIssue{
|
||||
Description: fmt.Sprintf(format, args...),
|
||||
Blocking: false,
|
||||
TimeCheck: true,
|
||||
})
|
||||
}
|
||||
|
||||
// AddWarning creates a new validation warning and adds it to the list
|
||||
func (v *ValidationResults) AddWarning(format string, args ...interface{}) {
|
||||
v.Add(&ValidationIssue{
|
||||
Description: fmt.Sprintf(format, args...),
|
||||
Blocking: false,
|
||||
TimeCheck: false,
|
||||
})
|
||||
}
|
||||
|
||||
// IsBlocking returns true if the list contains a blocking error
|
||||
func (v *ValidationResults) IsBlocking(includeTimeChecks bool) bool {
|
||||
for _, i := range v.Issues {
|
||||
if i.Blocking {
|
||||
return true
|
||||
}
|
||||
|
||||
if includeTimeChecks && i.TimeCheck {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the list is empty
|
||||
func (v *ValidationResults) IsEmpty() bool {
|
||||
return len(v.Issues) == 0
|
||||
}
|
||||
|
||||
// Errors returns only blocking issues as errors
|
||||
func (v *ValidationResults) Errors() []error {
|
||||
var errs []error
|
||||
for _, v := range v.Issues {
|
||||
if v.Blocking {
|
||||
errs = append(errs, errors.New(v.Description))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
Reference in New Issue
Block a user