Documentation ¶
Overview ¶
Package ucan implements User-Controlled Authorization Network tokens by fission: https://whitepaper.fission.codes/access-control/ucan/ucan-tokens
From the paper: The UCAN format is designed as an authenticated digraph in some larger authorization space. The other way to view this is as a function from a set of authorizations (“UCAN proofs“) to a subset output (“UCAN capabilities”).
Example ¶
package main import ( "context" "fmt" "time" "github.com/qri-io/ucan" ) func main() { source, err := ucan.NewPrivKeySource(keyOne) panicIfError(err) audienceDID, err := ucan.DIDStringFromPublicKey(keyOne.GetPublic()) panicIfError(err) caps := ucan.NewNestedCapabilities("SUPER_USER", "OVERWRITE", "SOFT_DELETE", "REVISE", "CREATE") att := ucan.Attenuations{ {caps.Cap("SUPER_USER"), ucan.NewStringLengthResource("api", "*")}, {caps.Cap("SUPER_USER"), ucan.NewStringLengthResource("dataset", "b5:world_bank_population:*")}, } zero := time.Time{} // create a root UCAN origin, err := source.NewOriginToken(audienceDID, att, nil, zero, zero) panicIfError(err) id, err := origin.CID() panicIfError(err) fmt.Printf("cid of root UCAN: %s\n", id.String()) att = ucan.Attenuations{ {caps.Cap("SUPER_USER"), ucan.NewStringLengthResource("dataset", "third:resource")}, } if _, err = source.NewAttenuatedToken(origin, audienceDID, att, nil, zero, zero); err != nil { fmt.Println(err) } att = ucan.Attenuations{ {caps.Cap("OVERWRITE"), ucan.NewStringLengthResource("dataset", "b5:world_bank_population:*")}, } derivedToken, err := source.NewAttenuatedToken(origin, audienceDID, att, nil, zero, zero) panicIfError(err) id, err = derivedToken.CID() panicIfError(err) fmt.Printf("cid of derived UCAN: %s\n", id.String()) p := exampleParser() tok, err := p.ParseAndVerify(context.Background(), origin.Raw) panicIfError(err) fmt.Printf("issuer DID key type: %s\n", tok.Issuer.Type().String()) } func panicIfError(err error) { if err != nil { panic(err) } } func exampleParser() *ucan.TokenParser { caps := ucan.NewNestedCapabilities("SUPER_USER", "OVERWRITE", "SOFT_DELETE", "REVISE", "CREATE") ac := func(m map[string]interface{}) (ucan.Attenuation, error) { var ( cap string rsc ucan.Resource ) for key, vali := range m { val, ok := vali.(string) if !ok { return ucan.Attenuation{}, fmt.Errorf(`expected attenuation value to be a string`) } if key == ucan.CapKey { cap = val } else { rsc = ucan.NewStringLengthResource(key, val) } } return ucan.Attenuation{ Rsc: rsc, Cap: caps.Cap(cap), }, nil } store := ucan.NewMemTokenStore() return ucan.NewTokenParser(ac, ucan.StringDIDPubKeyResolver{}, store.(ucan.CIDBytesResolver)) }
Output: cid of root UCAN: bafkreih6guuxohv47s2e366l6jn6stlsukgoerkdvtsni3kxr4jjmkaf3y scope of ucan attenuations must be less than it's parent cid of derived UCAN: bafkreihpk5474uoolkqrge3yk5uy2s7rarhn5xwxfoiobcy6ye7vfxetgm issuer DID key type: RSA
Index ¶
- Constants
- Variables
- func CtxWithToken(ctx context.Context, t Token) context.Context
- func DIDStringFromPublicKey(pub crypto.PubKey) (string, error)
- type Attenuation
- type AttenuationConstructorFunc
- type Attenuations
- type CIDBytesResolver
- type Capability
- type Claims
- type CtxKey
- type DIDPubKeyResolver
- type Fact
- type NestedCapabilities
- type Proof
- type RawToken
- type RawTokens
- type Resource
- type Source
- type StringDIDPubKeyResolver
- type Token
- type TokenParser
- type TokenStore
Examples ¶
Constants ¶
const ( // UCANVersion is the current version of the UCAN spec UCANVersion = "0.4.0" // UCANVersionKey is the key used in version headers for the UCAN spec UCANVersionKey = "ucv" // PrfKey denotes "Proofs" in a UCAN. Stored in JWT Claims PrfKey = "prf" // FctKey denotes "Facts" in a UCAN. Stored in JWT Claims FctKey = "fct" // AttKey denotes "Attenuations" in a UCAN. Stored in JWT Claims AttKey = "att" // CapKey indicates a resource Capability. Used in an attenuation CapKey = "cap" )
Variables ¶
var ErrInvalidToken = errors.New("invalid access token")
ErrInvalidToken indicates an access token is invalid
var ErrTokenNotFound = errors.New("access token not found")
ErrTokenNotFound is returned by stores that cannot find an access token for a given key
Functions ¶
func CtxWithToken ¶
CtxWithToken adds a UCAN value to a context
Types ¶
type Attenuation ¶
type Attenuation struct { Cap Capability Rsc Resource }
Attenuation is a capability on a resource
func (Attenuation) Contains ¶
func (a Attenuation) Contains(b Attenuation) bool
Contains returns true if both
func (Attenuation) MarshalJSON ¶
func (a Attenuation) MarshalJSON() ([]byte, error)
MarshalJSON implements the json.Marshaller interface
func (Attenuation) String ¶
func (a Attenuation) String() string
String formats an attenuation as a string
type AttenuationConstructorFunc ¶
type AttenuationConstructorFunc func(v map[string]interface{}) (Attenuation, error)
AttenuationConstructorFunc is a function that creates an attenuation from a map Users of this package provide an Attenuation Constructor to the parser to bind attenuation logic to a UCAN
type Attenuations ¶
type Attenuations []Attenuation
Attenuations is a list of attenuations
func (Attenuations) Contains ¶
func (att Attenuations) Contains(b Attenuations) bool
Contains is true if all attenuations in b are contained
func (Attenuations) String ¶
func (att Attenuations) String() string
type CIDBytesResolver ¶
type CIDBytesResolver interface {
ResolveCIDBytes(ctx context.Context, id cid.Cid) ([]byte, error)
}
CIDBytesResolver is a small interface for turning a CID into the bytes they reference. In practice this may be backed by a network connection that can fetch CIDs, eg: IPFS.
type Capability ¶
type Capability interface { // A Capability must be expressable as a string String() string // Capabilities must be comparable to other same-type capabilities Contains(b Capability) bool }
Capability is an action users can perform
type Claims ¶
type Claims struct { *jwt.StandardClaims // the "inputs" to this token, a chain UCAN tokens with broader scopes & // deadlines than this token // Proofs are UCAN chains, leading back to a self-evident origin token Proofs []Proof `json:"prf,omitempty"` // the "outputs" of this token, an array of heterogenous resources & // capabilities Attenuations Attenuations `json:"att,omitempty"` // Facts are facts, jack. Facts []Fact `json:"fct,omitempty"` }
Claims is the claims component of a UCAN token. UCAN claims are expressed as a standard JWT claims object with additional special fields
type CtxKey ¶
type CtxKey string
CtxKey defines a distinct type for context keys used by the access package
const TokenCtxKey CtxKey = "UCAN"
TokenCtxKey is the key for adding an access UCAN to a context.Context
type DIDPubKeyResolver ¶
type DIDPubKeyResolver interface {
ResolveDIDKey(ctx context.Context, did string) (didkey.ID, error)
}
DIDPubKeyResolver turns did:key Decentralized IDentifiers into a public key, possibly using a network request
type Fact ¶
type Fact struct {
// contains filtered or unexported fields
}
Fact is self-evident statement
type NestedCapabilities ¶
type NestedCapabilities struct {
// contains filtered or unexported fields
}
NestedCapabilities is a basic implementation of the Capabilities interface based on a hierarchal list of strings ordered from most to least capable It is both a capability and a capability factory with the .Cap method
func NewNestedCapabilities ¶
func NewNestedCapabilities(strs ...string) NestedCapabilities
NewNestedCapabilities creates a set of NestedCapabilities
func (NestedCapabilities) Cap ¶
func (nc NestedCapabilities) Cap(str string) Capability
Cap creates a new capability from the hierarchy
func (NestedCapabilities) Contains ¶
func (nc NestedCapabilities) Contains(cap Capability) bool
Contains returns true if cap is equal or less than the NestedCapability value
func (NestedCapabilities) String ¶
func (nc NestedCapabilities) String() string
String returns the Capability value as a string
type Proof ¶
type Proof string
Proof is a string representing a fact. Expected to be either a raw UCAN token or the CID of a raw UCAN token
type RawTokens ¶
type RawTokens []RawToken
RawTokens is a list of tokens that implements sorting by keys
type Resource ¶
Resource is a unique identifier for a thing, usually stored state. Resources are organized by string types
func NewStringLengthResource ¶
NewStringLengthResource is a silly implementation of resource to use while I figure out what an OR filter on strings is. Don't use this.
type Source ¶
type Source interface { NewOriginToken(audienceDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*Token, error) NewAttenuatedToken(parent *Token, audienceDID string, att Attenuations, fct []Fact, notBefore, expires time.Time) (*Token, error) }
Source creates tokens, and provides a verification key for all tokens it creates
implementations of Source must conform to the assertion test defined in the spec subpackage
type StringDIDPubKeyResolver ¶
type StringDIDPubKeyResolver struct{}
StringDIDPubKeyResolver implements the DIDPubKeyResolver interface without any network backing. Works if the key string given contains the public key itself
func (StringDIDPubKeyResolver) ResolveDIDKey ¶
ResolveDIDKey extracts a public key from a did:key string
type Token ¶
type Token struct { // Entire UCAN as a signed JWT string Raw string Issuer didkey.ID Audience didkey.ID // the "inputs" to this token, a chain UCAN tokens with broader scopes & // deadlines than this token Proofs []Proof `json:"prf,omitempty"` // the "outputs" of this token, an array of heterogenous resources & // capabilities Attenuations Attenuations `json:"att,omitempty"` // Facts are facts, jack. Facts []Fact `json:"fct,omitempty"` }
Token is a JSON Web Token (JWT) that contains special keys that make the token a UCAN
type TokenParser ¶
type TokenParser struct {
// contains filtered or unexported fields
}
TokenParser parses a raw string into a Token
func NewTokenParser ¶
func NewTokenParser(ap AttenuationConstructorFunc, didr DIDPubKeyResolver, cidr CIDBytesResolver) *TokenParser
NewTokenParser constructs a token parser
func (*TokenParser) ParseAndVerify ¶
ParseAndVerify will parse, validate and return a token
type TokenStore ¶
type TokenStore interface { PutToken(ctx context.Context, key, rawToken string) error RawToken(ctx context.Context, key string) (rawToken string, err error) DeleteToken(ctx context.Context, key string) (err error) ListTokens(ctx context.Context, offset, limit int) (results []RawToken, err error) }
TokenStore is a store intended for clients, who need to persist jwts. It deals in raw, string-formatted json web tokens, which are more useful when working with APIs, but validates the tokens are well-formed when placed in the store
implementations of TokenStore must conform to the assertion test defined in the spec subpackage
func NewMemTokenStore ¶
func NewMemTokenStore() TokenStore
NewMemTokenStore creates an in-memory token store