Files
mesh-controller/vendor/github.com/nats-io/jwt/v2/authorization_claims.go
T

256 lines
8.3 KiB
Go

/*
* Copyright 2022-2024 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"
)
// ServerID is basic static info for a NATS server.
type ServerID struct {
Name string `json:"name"`
Host string `json:"host"`
ID string `json:"id"`
Version string `json:"version,omitempty"`
Cluster string `json:"cluster,omitempty"`
Tags TagList `json:"tags,omitempty"`
XKey string `json:"xkey,omitempty"`
}
// ClientInformation is information about a client that is trying to authorize.
type ClientInformation struct {
Host string `json:"host,omitempty"`
ID uint64 `json:"id,omitempty"`
User string `json:"user,omitempty"`
Name string `json:"name,omitempty"`
Tags TagList `json:"tags,omitempty"`
NameTag string `json:"name_tag,omitempty"`
Kind string `json:"kind,omitempty"`
Type string `json:"type,omitempty"`
MQTT string `json:"mqtt_id,omitempty"`
Nonce string `json:"nonce,omitempty"`
}
// ConnectOptions represents options that were set in the CONNECT protocol from the client
// during authorization.
type ConnectOptions struct {
JWT string `json:"jwt,omitempty"`
Nkey string `json:"nkey,omitempty"`
SignedNonce string `json:"sig,omitempty"`
Token string `json:"auth_token,omitempty"`
Username string `json:"user,omitempty"`
Password string `json:"pass,omitempty"`
Name string `json:"name,omitempty"`
Lang string `json:"lang,omitempty"`
Version string `json:"version,omitempty"`
Protocol int `json:"protocol"`
}
// ClientTLS is information about TLS state if present, including client certs.
// If the client certs were present and verified they will be under verified chains
// with the client peer cert being VerifiedChains[0]. These are complete and pem encoded.
// If they were not verified, they will be under certs.
type ClientTLS struct {
Version string `json:"version,omitempty"`
Cipher string `json:"cipher,omitempty"`
Certs StringList `json:"certs,omitempty"`
VerifiedChains []StringList `json:"verified_chains,omitempty"`
}
// AuthorizationRequest represents all the information we know about the client that
// will be sent to an external authorization service.
type AuthorizationRequest struct {
Server ServerID `json:"server_id"`
UserNkey string `json:"user_nkey"`
ClientInformation ClientInformation `json:"client_info"`
ConnectOptions ConnectOptions `json:"connect_opts"`
TLS *ClientTLS `json:"client_tls,omitempty"`
RequestNonce string `json:"request_nonce,omitempty"`
GenericFields
}
// AuthorizationRequestClaims defines an external auth request JWT.
// These wil be signed by a NATS server.
type AuthorizationRequestClaims struct {
ClaimsData
AuthorizationRequest `json:"nats"`
}
// NewAuthorizationRequestClaims creates an auth request JWT with the specific subject/public key.
func NewAuthorizationRequestClaims(subject string) *AuthorizationRequestClaims {
if subject == "" {
return nil
}
var ac AuthorizationRequestClaims
ac.Subject = subject
return &ac
}
// Validate checks the generic and specific parts of the auth request jwt.
func (ac *AuthorizationRequestClaims) Validate(vr *ValidationResults) {
if ac.UserNkey == "" {
vr.AddError("User nkey is required")
} else if !nkeys.IsValidPublicUserKey(ac.UserNkey) {
vr.AddError("User nkey %q is not a valid user public key", ac.UserNkey)
}
ac.ClaimsData.Validate(vr)
}
// Encode tries to turn the auth request claims into a JWT string.
func (ac *AuthorizationRequestClaims) Encode(pair nkeys.KeyPair) (string, error) {
return ac.EncodeWithSigner(pair, nil)
}
func (ac *AuthorizationRequestClaims) EncodeWithSigner(pair nkeys.KeyPair, fn SignFn) (string, error) {
ac.Type = AuthorizationRequestClaim
return ac.ClaimsData.encode(pair, ac, fn)
}
// DecodeAuthorizationRequestClaims tries to parse an auth request claims from a JWT string
func DecodeAuthorizationRequestClaims(token string) (*AuthorizationRequestClaims, error) {
claims, err := Decode(token)
if err != nil {
return nil, err
}
ac, ok := claims.(*AuthorizationRequestClaims)
if !ok {
return nil, errors.New("not an authorization request claim")
}
return ac, nil
}
// ExpectedPrefixes defines the types that can encode an auth request jwt, servers.
func (ac *AuthorizationRequestClaims) ExpectedPrefixes() []nkeys.PrefixByte {
return []nkeys.PrefixByte{nkeys.PrefixByteServer}
}
func (ac *AuthorizationRequestClaims) ClaimType() ClaimType {
return ac.Type
}
// Claims returns the request claims data.
func (ac *AuthorizationRequestClaims) Claims() *ClaimsData {
return &ac.ClaimsData
}
// Payload pulls the request specific payload out of the claims.
func (ac *AuthorizationRequestClaims) Payload() interface{} {
return &ac.AuthorizationRequest
}
func (ac *AuthorizationRequestClaims) String() string {
return ac.ClaimsData.String(ac)
}
func (ac *AuthorizationRequestClaims) updateVersion() {
ac.GenericFields.Version = libVersion
}
type AuthorizationResponse struct {
Jwt string `json:"jwt,omitempty"`
Error string `json:"error,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"`
GenericFields
}
type AuthorizationResponseClaims struct {
ClaimsData
AuthorizationResponse `json:"nats"`
}
func NewAuthorizationResponseClaims(subject string) *AuthorizationResponseClaims {
if subject == "" {
return nil
}
var ac AuthorizationResponseClaims
ac.Subject = subject
return &ac
}
// DecodeAuthorizationResponseClaims tries to parse an auth request claims from a JWT string
func DecodeAuthorizationResponseClaims(token string) (*AuthorizationResponseClaims, error) {
claims, err := Decode(token)
if err != nil {
return nil, err
}
ac, ok := claims.(*AuthorizationResponseClaims)
if !ok {
return nil, errors.New("not an authorization request claim")
}
return ac, nil
}
// ExpectedPrefixes defines the types that can encode an auth request jwt, servers.
func (ar *AuthorizationResponseClaims) ExpectedPrefixes() []nkeys.PrefixByte {
return []nkeys.PrefixByte{nkeys.PrefixByteAccount}
}
func (ar *AuthorizationResponseClaims) ClaimType() ClaimType {
return ar.Type
}
// Claims returns the request claims data.
func (ar *AuthorizationResponseClaims) Claims() *ClaimsData {
return &ar.ClaimsData
}
// Payload pulls the request specific payload out of the claims.
func (ar *AuthorizationResponseClaims) Payload() interface{} {
return &ar.AuthorizationResponse
}
func (ar *AuthorizationResponseClaims) String() string {
return ar.ClaimsData.String(ar)
}
func (ar *AuthorizationResponseClaims) updateVersion() {
ar.GenericFields.Version = libVersion
}
// Validate checks the generic and specific parts of the auth request jwt.
func (ar *AuthorizationResponseClaims) Validate(vr *ValidationResults) {
if !nkeys.IsValidPublicUserKey(ar.Subject) {
vr.AddError("Subject must be a user public key")
}
if !nkeys.IsValidPublicServerKey(ar.Audience) {
vr.AddError("Audience must be a server public key")
}
if ar.Error == "" && ar.Jwt == "" {
vr.AddError("Error or Jwt is required")
}
if ar.Error != "" && ar.Jwt != "" {
vr.AddError("Only Error or Jwt can be set")
}
if ar.IssuerAccount != "" && !nkeys.IsValidPublicAccountKey(ar.IssuerAccount) {
vr.AddError("issuer_account is not an account public key")
}
ar.ClaimsData.Validate(vr)
}
// Encode tries to turn the auth request claims into a JWT string.
func (ar *AuthorizationResponseClaims) Encode(pair nkeys.KeyPair) (string, error) {
return ar.EncodeWithSigner(pair, nil)
}
func (ar *AuthorizationResponseClaims) EncodeWithSigner(pair nkeys.KeyPair, fn SignFn) (string, error) {
ar.Type = AuthorizationResponseClaim
return ar.ClaimsData.encode(pair, ar, fn)
}