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/ucan-wg/go-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: bafkreihl4b2ncrijeutlkppykgspz6wm3q2o4wiej6njl6tj7k2xa3zcue scope of ucan attenuations must be less than it's parent cid of derived UCAN: bafkreifhpoxctmbmvocdevfbmio6cpzltwauesyyjycipnylocoykwghzu 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.8.1" // 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 = "can" )
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
