macaroon

package module
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Sep 19, 2023 License: Apache-2.0 Imports: 17 Imported by: 11

README

github.com/superfly/macaroon

Our macaroon implementation. TKTK

Documentation

Overview

package macaroon defines Fly.io's Macaroon token format.

Tokens are created with New, and refined with [Add] and [Add3P] to add conditions, called caveats. Their signature is updated as caveats are added. They're serialized with [Encode]

Serialized tokens are parsed with Decode, to get a Macaroon. To do real things with it, [Verify] it to receive the set of usable caveats.

Serialized tokens can also be scanned with [DischargeMacaroon] to find caveats that need third-party discharges.

Once fully parsed, a service using these tokens calls Validate to check the caveats.

Index

Constants

View Source
const (
	ActionAll  = ActionRead | ActionWrite | ActionCreate | ActionDelete | ActionControl
	ActionNone = Action(0)
)
View Source
const (
	CavValidityWindow CaveatType

	Cav3P
	CavBindToParentToken
	CavIfPresent

	// Globally-recognized user-registerable caveat types may be requested via
	// pull requests to this repository. Add a meaningful name of the caveat
	// type (e.g. CavAcmeCorpWidgetID) on the line prior to
	// CavMaxUserRegisterable.
	CavMinUserRegisterable = 1 << 32
	CavMaxUserRegisterable = 1<<48 - 1

	CavMinUserDefined = 1 << 48
	CavMaxUserDefined = 1<<64 - 2
	CavUnregistered   = 1<<64 - 1
)
View Source
const (
	EncryptionKeySize = 32
)

Variables

View Source
var (
	ErrUnrecognizedToken          = errors.New("bad token")
	ErrUnauthorized               = errors.New("unauthorized")
	ErrInvalidAccess              = fmt.Errorf("%w: bad data for token verification", ErrUnauthorized)
	ErrResourcesMutuallyExclusive = fmt.Errorf("%w: resources are mutually exclusive", ErrInvalidAccess)
	ErrResourceUnspecified        = fmt.Errorf("%w: must specify", ErrInvalidAccess)
	ErrUnauthorizedForResource    = fmt.Errorf("%w for", ErrUnauthorized)
	ErrUnauthorizedForAction      = fmt.Errorf("%w for", ErrUnauthorized)
	ErrBadCaveat                  = fmt.Errorf("%w: bad caveat", ErrUnauthorized)
)

Functions

func DischargeCID

func DischargeCID(ka EncryptionKey, location string, cid []byte) ([]Caveat, *Macaroon, error)

Decyrpts the CID from the 3p caveat and prepares a discharge token. Returned caveats, if any, must be validated before issuing the discharge token to the user.

func FindPermissionAndDischargeTokens

func FindPermissionAndDischargeTokens(tokens [][]byte, location string) ([]*Macaroon, [][]byte, []*Macaroon, [][]byte, error)

func GetCaveats

func GetCaveats[T Caveat](c *CaveatSet) (ret []T)

GetCaveats gets any caveats of type T, including those nested within IfPresent caveats.

func Parse

func Parse(header string) ([][]byte, error)

Parses an Authorization header into its constituent tokens.

func ParsePermissionAndDischargeTokens

func ParsePermissionAndDischargeTokens(header string, location string) ([]byte, [][]byte, error)

Parse a string token and find the contained permission token for the given location.

func RegisterCaveatType

func RegisterCaveatType(name string, typ CaveatType, zeroValue Caveat)

Register a caveat type for use with this library.

func ThirdPartyCID

func ThirdPartyCID(encodedMacaroon []byte, thirdPartyLocation string) ([]byte, error)

Checks the macaroon for a third party caveat for the specified location. Returns the caveat's encrypted CID, if found.

func ToAuthorizationHeader

func ToAuthorizationHeader(toks ...[]byte) string

ToAuthorizationHeader formats a collection of tokens as an HTTP Authorization header.

func Validate

func Validate[A Access](cs *CaveatSet, accesses ...A) error

Helper for validating concretely-typed accesses.

Types

type Access

type Access interface {
	// The action being attempted by the principal
	GetAction() Action

	// The current time
	Now() time.Time

	// Callback for validating the structure
	Validate() error
}

Access represents the user's attempt to access some resource. Different caveats will require different contextual information.

type Action

type Action uint16

Action is an RWX-style bitmap of actions that can be taken on a resource (eg org, app, machine). An Action can describe the permission limitations expressed by a caveat or the action a principal is attempting to take on a resource. The precise semantics of Actions are left to Caveat/AuthAttempt implementations.

const (
	// ActionRead indicates reading attributes of the specified objects.
	ActionRead Action = 1 << iota

	// ActionWrite indicates writing attributes of the specified objects.
	ActionWrite

	// ActionCreate indicates creating the specified object. Since the ID of an
	// object will be unknown before creation, this is mostly meaningless
	// unless inherited from a parent. E.g. org:123:create lets you create
	// app:234 belonging to org:123.
	ActionCreate

	// ActionDelete indicates deleting the specified object.
	ActionDelete

	// ActionControl indicates changing the state of the specified object, but
	// not modifying other attributes. In practice, this mostly applies to
	// starting/stopping/signaling machines.
	ActionControl
)

func ActionFromString

func ActionFromString(ms string) Action

func (Action) IsSubsetOf

func (a Action) IsSubsetOf(other Action) bool

IsSubsetOf returns wether all bits in p are set in other.

func (Action) MarshalJSON

func (a Action) MarshalJSON() ([]byte, error)

func (Action) Remove

func (a Action) Remove(other Action) Action

Remove returns the bits in p but not other

func (Action) String

func (a Action) String() string

func (*Action) UnmarshalJSON

func (a *Action) UnmarshalJSON(b []byte) error

type BindToParentToken

type BindToParentToken []byte

BindToParentToken is used by discharge tokens to state that they may only be used to discharge 3P caveats for a specific root token or further attenuated versions of that token. This prevents a discharge token from being used with less attenuated versions of the specified token, effectively binding the discharge token to the root token. This caveat may appear multiple times to iteratively clamp down which versions of the root token the discharge token may be used with.

The parent token is identified by a prefix of the SHA256 digest of the token's signature.

func (*BindToParentToken) CaveatType

func (c *BindToParentToken) CaveatType() CaveatType

func (*BindToParentToken) IsAttestation

func (c *BindToParentToken) IsAttestation() bool

func (*BindToParentToken) Prohibits

func (c *BindToParentToken) Prohibits(f Access) error

type Caveat

type Caveat interface {
	// The numeric caveat type identifier.
	CaveatType() CaveatType

	// Callback for checking if the authorization check is blocked by this
	// caveat. Implementors must take care to return appropriate error types,
	// as they have bearing on the evaluation of IfPresent caveats.
	// Specifically, returning ErrResourceUnspecified indicates that caveat
	// constrains access to a resource type that isn't specified by the Access.
	Prohibits(f Access) error

	// Whether or not this caveat type is an attestation. Attestations make a
	// positive assertion rather than constraining access to a resource. Most
	// caveats are not attestations.
	IsAttestation() bool
}

Caveat is the interface implemented by all caveats.

type Caveat3P

type Caveat3P struct {
	Location string
	VID      []byte // used by the initial issuer to verify discharge macaroon
	CID      []byte // used by the 3p service to construct discharge macaroon
	// contains filtered or unexported fields
}

Caveat3P is a requirement that the token be presented along with a 3P discharge token.

func (*Caveat3P) CaveatType

func (c *Caveat3P) CaveatType() CaveatType

func (*Caveat3P) IsAttestation

func (c *Caveat3P) IsAttestation() bool

func (*Caveat3P) Prohibits

func (c *Caveat3P) Prohibits(f Access) error

type CaveatSet

type CaveatSet struct {
	Caveats []Caveat
}

CaveatSet is how a set of caveats is serailized/encoded.

func DecodeCaveats

func DecodeCaveats(buf []byte) (*CaveatSet, error)

Decodes a set of serialized caveats.

func NewCaveatSet

func NewCaveatSet(caveats ...Caveat) *CaveatSet

Create a new CaveatSet comprised of the specified caveats.

func (*CaveatSet) DecodeMsgpack

func (c *CaveatSet) DecodeMsgpack(dec *msgpack.Decoder) error

Implements msgpack.CustomDecoder

func (CaveatSet) EncodeMsgpack

func (c CaveatSet) EncodeMsgpack(enc *msgpack.Encoder) error

Implements msgpack.CustomEncoder

func (CaveatSet) MarshalJSON

func (c CaveatSet) MarshalJSON() ([]byte, error)

func (CaveatSet) MarshalMsgpack

func (c CaveatSet) MarshalMsgpack() ([]byte, error)

Implements msgpack.Marshaler

func (*CaveatSet) UnmarshalJSON

func (c *CaveatSet) UnmarshalJSON(b []byte) error

func (*CaveatSet) Validate

func (c *CaveatSet) Validate(accesses ...Access) error

Validates that the caveat set permits the specified accesses.

type CaveatType

type CaveatType uint64

A numeric identifier for caveat types. Values less than CavMinUserRegisterable (0x100000000) are reserved for use by fly.io. Users may request a globally-recognized caveat type via pull requests to this repository. Implementations that don't need to integrate with fly.io itself can pick from the user-defined range (>0x1000000000000).

type EncryptionKey

type EncryptionKey []byte

func NewEncryptionKey

func NewEncryptionKey() EncryptionKey

type IfPresent

type IfPresent struct {
	Ifs  *CaveatSet `json:"ifs"`
	Else Action     `json:"else"`
}

IfPresent attempts to apply the specified `Ifs` caveats if the relevant resources are specified. If none of the relevant resources are specified, the `Else` caveats are applied.

This is only meaningful to use with "resource" caveats: org, app, feature, volume, machine. Notably, it explicitly doesn't work with the Mutations caveat.

func (*IfPresent) CaveatType

func (c *IfPresent) CaveatType() CaveatType

func (*IfPresent) IsAttestation

func (c *IfPresent) IsAttestation() bool

func (*IfPresent) Prohibits

func (c *IfPresent) Prohibits(f Access) error

type Macaroon

type Macaroon struct {
	Nonce         Nonce     `json:"-"`
	Location      string    `json:"location"`
	UnsafeCaveats CaveatSet `json:"caveats"`
	Tail          []byte    `json:"-"`
	// contains filtered or unexported fields
}

Macaroon is the fully-functioning internal representation of a token --- you've got a Macaroon either because you're constructing a new token yourself, or because you've parsed a token from the wire.

func Decode

func Decode(buf []byte) (*Macaroon, error)

Decode parses a token off the wire; To get usable caveats, call Verify.

func New

func New(kid []byte, loc string, key SigningKey) (*Macaroon, error)

New creates a new token given a key-id string (which can be any opaque string and doesn't need to be cryptographically random or anything; the key-id is how you're going to relate the token back to a key you've saved somewhere; it's probably a database rowid somehow) and a location, which is ordinarily a URL. The key is the signing secret.

func (*Macaroon) Add

func (m *Macaroon) Add(caveats ...Caveat) error

Add adds a caveat to a Macaroon, adjusting the tail signature in the process. This is how you'd "attenuate" a token, taking a read-write token and turning it into a read-only token, for instance.

func (*Macaroon) Add3P

func (m *Macaroon) Add3P(ka EncryptionKey, loc string, cs ...Caveat) error

Add3P adds a third-party caveat to a Macaroon. A third-party caveat is checked not by evaluating what it means, but instead by looking for a "discharge token" --- a second token sent along with the token that says "some other service verified that the claims corresponding to this caveat are true".

Add3P needs a key, which binds this token to the service that validates it. Every authentication caveat, for instance, shares an authentication key; the key connects the root service to the authentication service.

Add3P takes a location, which is used to figure out which keys to use to check which caveats. The location is normally a URL. The authentication service has an authentication location URL.

func (*Macaroon) Bind

func (m *Macaroon) Bind(parent []byte) error

Bind binds this (discharge) token to the specified root token (parent) with a BindToParentToken caveat.

func (*Macaroon) BindToParentMacaroon

func (m *Macaroon) BindToParentMacaroon(parent *Macaroon) error

func (*Macaroon) Encode

func (m *Macaroon) Encode() ([]byte, error)

Encode encodes a Macaroon to bytes after creating it or decoding it and adding more caveats.

func (*Macaroon) Expiration

func (m *Macaroon) Expiration() time.Time

Expiration calculates when this macaroon will expire

func (*Macaroon) ThirdPartyCID

func (m *Macaroon) ThirdPartyCID(location string, existingDischarges ...[]byte) ([]byte, error)

Checks the macaroon for a third party caveat for the specified location. Returns the caveat's encrypted CID, if found.

func (*Macaroon) ThirdPartyCIDs

func (m *Macaroon) ThirdPartyCIDs(existingDischarges ...[]byte) (map[string][]byte, error)

ThirdPartyCIDs extracts the encrypted CIDs from a token's third party caveats. Each is identified by the location of the third party. The CID can then be exchanged with the third party for a discharge token. Third party caveats are checked against existing discharge tokens and discharged caveats are omitted from the results.

func (*Macaroon) Verify

func (m *Macaroon) Verify(k SigningKey, discharges [][]byte, trusted3Ps map[string]EncryptionKey) (*CaveatSet, error)

Verify checks the signature on a Decode()'ed Macaroon and returns the the set of caveats that require validation against the user's request. This excludes caveats that have already been validated (e.g. 3P caveats and others relating to the signing of the Macaroon).

type Nonce

type Nonce struct {
	// contains filtered or unexported fields
}

Nonce encodes the key ID that signed the macaroon as well as some randomness

func DecodeNonce

func DecodeNonce(buf []byte) (Nonce, error)

DecodeNonce parses just the nonce from an encoded macaroon.

func (*Nonce) DecodeMsgpack

func (n *Nonce) DecodeMsgpack(d *msgpack.Decoder) error

DecodeMsgpack implements msgpack.CustomDecoder

func (*Nonce) EncodeMsgpack

func (n *Nonce) EncodeMsgpack(e *msgpack.Encoder) error

DecodeMsgpack implements msgpack.CustomDecoder

func (Nonce) MustEncode

func (n Nonce) MustEncode() []byte

func (*Nonce) UUID

func (n *Nonce) UUID() uuid.UUID

UUID is a simple globally unique identifier string for a nonce.

type SigningKey

type SigningKey []byte

func NewSigningKey

func NewSigningKey() SigningKey

type ValidityWindow

type ValidityWindow struct {
	NotBefore int64 `json:"not_before"`
	NotAfter  int64 `json:"not_after"`
}

ValidityWindow establishes the window of time the token is valid for.

func (*ValidityWindow) CaveatType

func (c *ValidityWindow) CaveatType() CaveatType

func (*ValidityWindow) IsAttestation

func (c *ValidityWindow) IsAttestation() bool

func (*ValidityWindow) Prohibits

func (c *ValidityWindow) Prohibits(f Access) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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