tokens

package module
v0.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 18, 2023 License: Apache-2.0 Imports: 21 Imported by: 15

README

Overview

This package creates JWT Tokens compatible for various Choria Purposes.

Go Report Card CodeQL Unit Tests

Documentation

Index

Constants

View Source
const (
	OrgIssuerPrefix   = "I-"
	ChainIssuerPrefix = "C-"
	DefaultValidity   = time.Hour
)

Variables

View Source
var (
	ErrNotAClientToken       = fmt.Errorf("not a client token")
	ErrInvalidClientCallerID = fmt.Errorf("invalid caller id in token")
)
View Source
var (
	ErrNotAServerToken  = errors.New("not a server token")
	ErrChainIssuerToken = errors.New("chain issuers may not access servers")
)
View Source
var ErrorNotSignedByIssuer = errors.New("not signed by issuer")

ErrorNotSignedByIssuer is raised when a token did not pass validation against the issuer chain

Functions

func IsClientIDToken

func IsClientIDToken(claims StandardClaims) bool

IsClientIDToken determines if this is a client identifying token

func IsClientIDTokenString

func IsClientIDTokenString(token string) (bool, error)

IsClientIDTokenString calls IsClientIDToken on the token in a string

func IsEncodedEd25519Key

func IsEncodedEd25519Key(b []byte) bool

IsEncodedEd25519Key determines if b holds valid characters for a hex encoded public key or seed

func IsProvisioningToken

func IsProvisioningToken(claims StandardClaims) bool

IsProvisioningToken determines if this is a provisioning token

func IsServerToken

func IsServerToken(claims StandardClaims) bool

IsServerToken determines if this is a server token

func IsServerTokenString

func IsServerTokenString(token string) (bool, error)

func NatsConnectionHelpers

func NatsConnectionHelpers(token string, collective string, seedFile string, log *logrus.Entry) (inbox string, jwth func() (string, error), sigh func([]byte) ([]byte, error), err error)

NatsConnectionHelpers constructs token based private inbox and helpers for the nats.UserJWT() function. Only Server and Client tokens are supported.

func ParseToken

func ParseToken(token string, claims jwt.Claims, pk any) error

ParseToken parses token into claims and verify the token is valid using the pk, if the token is signed by a chain issuer then pk must be the org issuer pk and the chain will be verified

func ParseTokenUnverified

func ParseTokenUnverified(token string) (jwt.MapClaims, error)

ParseTokenUnverified parses token into claims and DOES not verify the token validity in any way

func SaveAndSignTokenWithKeyFile

func SaveAndSignTokenWithKeyFile(claims jwt.Claims, pkFile string, outFile string, perm os.FileMode) error

SaveAndSignTokenWithKeyFile signs a token using SignTokenWithKeyFile and saves it to outFile

func SaveAndSignTokenWithVault

func SaveAndSignTokenWithVault(ctx context.Context, claims jwt.Claims, key string, outFile string, perm os.FileMode, tlsc *tls.Config, log *logrus.Entry) error

SaveAndSignTokenWithVault signs a token using the named key in a Vault Transit engine. Requires VAULT_TOKEN and VAULT_ADDR to be set.

func SignToken

func SignToken(claims jwt.Claims, pk any) (string, error)

SignToken signs a JWT using an RSA Private Key

func SignTokenWithKeyFile

func SignTokenWithKeyFile(claims jwt.Claims, pkFile string) (string, error)

SignTokenWithKeyFile signs a JWT using an RSA Private Key in PEM format

func TokenSigningAlgorithm added in v0.0.2

func TokenSigningAlgorithm(token string) (string, error)

TokenSigningAlgorithm determines the signing algorithm used for a token

func TokenSigningAlgorithmBytes added in v0.0.2

func TokenSigningAlgorithmBytes(token []byte) (string, error)

TokenSigningAlgorithmBytes determines the signing algorithm used for a token

func UnverifiedCallerFromClientIDToken

func UnverifiedCallerFromClientIDToken(token string) (*jwt.Token, string, error)

UnverifiedCallerFromClientIDToken extracts the caller id from a client token.

The token is not verified as this is mainly used on clents who might not have the signer public key to verify the certificate. This is safe as the signer will later verify the token anyway.

Further, at the moment, we do not verity the Purpose for backward compatibility

An empty callerid will result in an error

func UnverifiedIdentityFromServerToken

func UnverifiedIdentityFromServerToken(token string) (*jwt.Token, string, error)

UnverifiedIdentityFromServerToken extracts the identity from a server token.

The token is not verified as this is mainly used on servers who might not have the signer public key to verify the certificate. This is safe as the signer will later verify the token anyway.

An empty identity will result in an error

Types

type ClientIDClaims

type ClientIDClaims struct {
	// CallerID is the choria caller id that will be set for this user for AAA purposes, typically provider=caller format
	CallerID string `json:"callerid"`

	// AllowedAgents is a list of agent names or agent.action names this user can perform
	AllowedAgents []string `json:"agents,omitempty"`

	// OrganizationUnit broker account a user should belong to, set to 'choria' now and issuing organization
	OrganizationUnit string `json:"ou,omitempty"`

	// UserProperties is a list of arbitrary properties that can be set for a user, OPA Policies in the token can access these
	UserProperties map[string]string `json:"user_properties,omitempty"`

	// OPAPolicy is a Open Policy Agent document to be used by the signer to limit the users actions
	OPAPolicy string `json:"opa_policy,omitempty"`

	// Permissions sets additional permissions for a client
	Permissions *ClientPermissions `json:"permissions,omitempty"`

	// AdditionalPublishSubjects are additional subjects the client can publish to
	AdditionalPublishSubjects []string `json:"pub_subjects,omitempty"`

	// AdditionalSubscribeSubjects are additional subjects the client can subscribe to
	AdditionalSubscribeSubjects []string `json:"sub_subjects,omitempty"`

	StandardClaims
}

ClientIDClaims represents a user and all AAA Authenticators should create a JWT using this format

The "purpose" claim should be set to ClientIDPurpose

func NewClientIDClaims

func NewClientIDClaims(callerID string, allowedAgents []string, org string, properties map[string]string, opaPolicy string, issuer string, validity time.Duration, perms *ClientPermissions, pk ed25519.PublicKey) (*ClientIDClaims, error)

NewClientIDClaims generates new ClientIDClaims

func ParseClientIDToken

func ParseClientIDToken(token string, pk any, verifyPurpose bool) (*ClientIDClaims, error)

ParseClientIDToken parses token and verifies it with pk

func ParseClientIDTokenUnverified

func ParseClientIDTokenUnverified(token string) (*ClientIDClaims, error)

ParseClientIDTokenUnverified parses the client token in an unverified manner.

func ParseClientIDTokenWithKeyfile

func ParseClientIDTokenWithKeyfile(token string, pkFile string, verifyPurpose bool) (*ClientIDClaims, error)

ParseClientIDTokenWithKeyfile parses token and verifies it with the RSA Public key in pkFile, does not support ed25519 public keys in a file

func (*ClientIDClaims) UniqueID

func (c *ClientIDClaims) UniqueID() (id string, uid string)

UniqueID returns the caller id and unique id used to generate private inboxes

type ClientPermissions

type ClientPermissions struct {
	// StreamsAdmin enables full access to Choria Streams for all APIs
	StreamsAdmin bool `json:"streams_admin,omitempty"`

	// StreamsUser enables user level access to Choria Streams, no stream admin features
	StreamsUser bool `json:"streams_user,omitempty"`

	// EventsViewer allows viewing lifecycle and auto agent events
	EventsViewer bool `json:"events_viewer,omitempty"`

	// ElectionUser allows using leader elections
	ElectionUser bool `json:"election_user,omitempty"`

	// SystemUser allows accessing the Choria Broker system account without verified TLS
	SystemUser bool `json:"system_user,omitempty"`

	// Governor enables access to Governors, cannot make new ones, also requires Streams permission
	Governor bool `json:"governor,omitempty"`

	// OrgAdmin has access to all subjects and broker system account
	OrgAdmin bool `json:"org_admin,omitempty"`

	// FleetManagement enables access to the choria server fleet for RPCs
	FleetManagement bool `json:"fleet_management,omitempty"`

	// SignedFleetManagement requires a user to have a valid signature by an AuthenticationDelegator to interact with the fleet
	SignedFleetManagement bool `json:"signed_fleet_management,omitempty"`

	// ExtendedServiceLifetime allows a token to have a longer than common lifetime, suitable for services users
	ExtendedServiceLifetime bool `json:"service,omitempty"`

	// AuthenticationDelegator has the right to sign requests on behalf of others
	AuthenticationDelegator bool `json:"authentication_delegator,omitempty"`

	// ServerProvisioner is required by Choria Provisioner to connect to the account where unprovisioned nodes exist
	ServerProvisioner bool `json:"provisioner,omitempty"`
}

type MapClaims

type MapClaims jwt.MapClaims

MapClaims are free form map claims

type ProvisioningClaims

type ProvisioningClaims struct {
	Token            string    `json:"cht"`
	Secure           bool      `json:"chs"`
	URLs             string    `json:"chu,omitempty"`
	SRVDomain        string    `json:"chsrv,omitempty"`
	ProvDefault      bool      `json:"chpd"`
	ProvRegData      string    `json:"chrd,omitempty"`
	ProvFacts        string    `json:"chf,omitempty"`
	ProvNatsUser     string    `json:"chusr,omitempty"`
	ProvNatsPass     string    `json:"chpwd,omitempty"`
	Extensions       MapClaims `json:"extensions"`
	OrganizationUnit string    `json:"ou,omitempty"`
	ProtoV2          bool      `json:"v2,omitempty"`
	AllowUpdate      bool      `json:"update,omitempty"`

	StandardClaims
}

func NewProvisioningClaims

func NewProvisioningClaims(secure bool, byDefault bool, token string, user string, password string, urls []string, srvDomain string, registrationDataFile string, factsDataFile string, org string, issuer string, validity time.Duration) (*ProvisioningClaims, error)

NewProvisioningClaims generates new ProvisioningClaims

func ParseProvisionTokenUnverified

func ParseProvisionTokenUnverified(token string) (*ProvisioningClaims, error)

ParseProvisionTokenUnverified parses the provisioning token in an unverified manner.

This is intended to be used for nodes to figure out their settings, they will go try them and if nothing's there no biggie. The broker and provisioner WILL validate this token so parsing it unverified there is about equivalent to just a configuration file, which is the intended purpose of this token and function.

func ParseProvisioningToken

func ParseProvisioningToken(token string, pk any) (*ProvisioningClaims, error)

ParseProvisioningToken parses token and verifies it with pk

func ParseProvisioningTokenWithKeyfile

func ParseProvisioningTokenWithKeyfile(token string, pkFile string) (*ProvisioningClaims, error)

ParseProvisioningTokenWithKeyfile parses token and verifies it with the RSA Public key in pkFile, does not support ed25519

type Purpose

type Purpose string

Purpose indicates what kind of token a JWT is and helps us parse it into the right data structure

const (
	// UnknownPurpose is a JWT that does not have a purpose set
	UnknownPurpose Purpose = ""

	// ClientIDPurpose indicates a JWT is a ClientIDClaims JWT
	ClientIDPurpose Purpose = "choria_client_id"

	// ProvisioningPurpose indicates a JWT is a ProvisioningClaims JWT
	ProvisioningPurpose Purpose = "choria_provisioning"

	// ServerPurpose indicates a JWT is a ServerClaims JWT
	ServerPurpose Purpose = "choria_server"
)

func TokenPurpose

func TokenPurpose(token string) Purpose

TokenPurpose parses, without validating, token and checks for a Purpose field in it

func TokenPurposeBytes

func TokenPurposeBytes(token []byte) Purpose

TokenPurposeBytes called TokenPurpose with a bytes input

type ServerClaims

type ServerClaims struct {
	// ChoriaIdentity is the server identity
	ChoriaIdentity string `json:"identity"`

	// Collectives sets what collectives this server belongs to within the organization
	Collectives []string `json:"collectives"`

	// Permissions are additional abilities the server will have
	Permissions *ServerPermissions `json:"permissions,omitempty"`

	// OrganizationUnit broker account a user should belong to, set to 'choria' now and issuing organization
	OrganizationUnit string `json:"ou,omitempty"`

	// AdditionalPublishSubjects are additional subjects the server can publish to facilitate for example custom registration paths
	AdditionalPublishSubjects []string `json:"pub_subjects,omitempty"`

	StandardClaims
}

func NewServerClaims

func NewServerClaims(identity string, collectives []string, org string, perms *ServerPermissions, additionalPublish []string, pk ed25519.PublicKey, issuer string, validity time.Duration) (*ServerClaims, error)

func ParseServerToken

func ParseServerToken(token string, pk any) (*ServerClaims, error)

ParseServerToken parses token and verifies it with pk

func ParseServerTokenFileUnverified

func ParseServerTokenFileUnverified(file string) (*ServerClaims, error)

ParseServerTokenFileUnverified calls ParseServerTokenUnverified using the contents of file

func ParseServerTokenUnverified

func ParseServerTokenUnverified(token string) (*ServerClaims, error)

ParseServerTokenUnverified parses the server token in an unverified manner.

func ParseServerTokenWithKeyfile

func ParseServerTokenWithKeyfile(token string, pkFile string) (*ServerClaims, error)

ParseServerTokenWithKeyfile parses token and verifies it with the RSA Public key or ed25519 public key in pkFile

func (*ServerClaims) IsMatchingPublicKey

func (c *ServerClaims) IsMatchingPublicKey(pubK ed25519.PublicKey) (bool, error)

IsMatchingPublicKey checks that the stored public key matches the supplied one

func (*ServerClaims) IsMatchingSeedFile

func (c *ServerClaims) IsMatchingSeedFile(file string) (bool, error)

IsMatchingSeedFile determines if the token public key matches the seed in file

func (*ServerClaims) UniqueID

func (c *ServerClaims) UniqueID() (id string, uid string)

UniqueID returns the identity and unique id used to generate private inboxes

type ServerPermissions

type ServerPermissions struct {
	// Submission enables access to <collective>.submission.in.>
	Submission bool `json:"submission,omitempty"`

	// Streams allow access to Choria Streams such as reading KV values and using Governors
	Streams bool `json:"streams,omitempty"`

	// Governor enables access to Governors, cannot make new ones, also requires Streams permission
	Governor bool `json:"governor,omitempty"`

	// ServiceHost allows a node to listen for service requests
	ServiceHost bool `json:"service_host,omitempty"`
}

type StandardClaims

type StandardClaims struct {
	// Purpose indicates the type of JWT for type discovery
	Purpose Purpose `json:"purpose"`

	// TrustChainSignature is a structure that helps to verify a chain of trust to a org issuer
	TrustChainSignature string `json:"tcs,omitempty"`

	// PublicKey is a ED25519 public key associated with this token
	PublicKey string `json:"public_key,omitempty"`

	// IssuerExpiresAt is the expiry time of the issuer, if set will be checked in addition to the expiry time of the token itself
	IssuerExpiresAt *jwt.NumericDate `json:"issexp,omitempty"`

	jwt.RegisteredClaims
}

func (*StandardClaims) AddChainIssuerData

func (c *StandardClaims) AddChainIssuerData(chainIssuer *ClientIDClaims, prik ed25519.PrivateKey) error

AddChainIssuerData adds the data that a Signed token needs from a Chain Issuer in an Org managed by an Issuer

func (*StandardClaims) AddOrgIssuerData

func (c *StandardClaims) AddOrgIssuerData(priK ed25519.PrivateKey) error

AddOrgIssuerData adds the data that a Chain Issuer needs to be able to issue clients in an Org managed by an Issuer

func (*StandardClaims) AddOrgIssuerDataUsingVault

func (c *StandardClaims) AddOrgIssuerDataUsingVault(ctx context.Context, tlsc *tls.Config, priK string, log *logrus.Entry) error

AddOrgIssuerDataUsingVault adds the data that a Chain Issuer needs to be able to issue clients in an Org managed by an Issuer by using Vault to sign the data using the named key `priK`.

func (*StandardClaims) ChainIssuerData

func (c *StandardClaims) ChainIssuerData(chainSig string) ([]byte, error)

ChainIssuerData is the data that should be signed on a user to create a chain of trust between Org Issuer, Client Login Handler and Client.

The Issuer should already be set using SetChainIssuer()

See AddChainIssuerData for a one-shot way to set the needed data when you have access to the private key.

func (*StandardClaims) ExpireTime

func (c *StandardClaims) ExpireTime() time.Time

ExpireTime determines the expiry time based on issuer expiry and token expiry

func (*StandardClaims) IsChainedIssuer

func (c *StandardClaims) IsChainedIssuer(verify bool) bool

IsChainedIssuer determines if this is a token capable of issuing users as part of a chain without verify being true one can not be 100% certain it's valid to do that but its a strong hint

func (*StandardClaims) IsExpired

func (c *StandardClaims) IsExpired() bool

IsExpired checks if the token has expired

func (*StandardClaims) IsSignedByIssuer

func (c *StandardClaims) IsSignedByIssuer(pk ed25519.PublicKey) (bool, ed25519.PublicKey, error)

IsSignedByIssuer uses the chain data in Issuer and TrustChainSignature to determine if an issuer signed a token

func (*StandardClaims) OrgIssuerChainData

func (c *StandardClaims) OrgIssuerChainData() ([]byte, error)

OrgIssuerChainData creates data that the org issuer would sign and embed in the token as TrustChainSignature. See AddOrgIssuerData for a one-shot way to set the needed data when you have access to the private key.

func (*StandardClaims) ParseChainIssuerData

func (c *StandardClaims) ParseChainIssuerData() (id string, pk ed25519.PublicKey, tcs string, sig []byte, err error)

ParseChainIssuerData extract the chain verifier based signature and metadata from a token

func (*StandardClaims) SetChainIssuer

func (c *StandardClaims) SetChainIssuer(ci *ClientIDClaims) error

SetChainIssuer used by Login Handlers that create users in a chain to set an appropriate issuer on created users See AddChainIssuerData for a one-shot way to set the needed data when you have access to the private key.

func (*StandardClaims) SetChainIssuerTrustSignature

func (c *StandardClaims) SetChainIssuerTrustSignature(sig []byte)

SetChainIssuerTrustSignature sets the TrustChainSignature for a user who may issue others like a AAA Login Server

See AddChainIssuerData for a one-shot way to set the needed data when you have access to the private key.

func (*StandardClaims) SetChainUserTrustSignature

func (c *StandardClaims) SetChainUserTrustSignature(h *ClientIDClaims, sig []byte)

SetChainUserTrustSignature sets the TrustChainSignature for a user issued by a ChainIssuer like AAA Login Server

See AddChainIssuerData for a one-shot way to set the needed data when you have access to the private key.

func (*StandardClaims) SetOrgIssuer

func (c *StandardClaims) SetOrgIssuer(pk ed25519.PublicKey)

SetOrgIssuer sets the issuer field for users issued by the Org Issuer See AddOrgIssuerData for a one-shot way to set the needed data when you have access to the private key.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL