Documentation
¶
Overview ¶
Example ¶
package main import ( "bytes" "fmt" "time" "github.com/superfly/macaroon" ) const ( // pick caveat type identifier from user-defined range CavWidgets = iota + macaroon.CavMinUserDefined ) // implements macaroon.Caveat. Constrains access to widgets type Widgets struct { Widgets ResourceSet[string] `json:"widgets"` } // register our Widgets caveat with the macaroons library so it's able to // encode/decode them func init() { macaroon.RegisterCaveatType(&Widgets{}) } // implements macaroon.Caveat func (c *Widgets) CaveatType() macaroon.CaveatType { return CavWidgets } // implements macaroon.Caveat func (c *Widgets) Name() string { return "Widgets" } // implements macaroon.Caveat func (c *Widgets) Prohibits(f macaroon.Access) error { wf, isWF := f.(*WidgetAccess) if !isWF { return macaroon.ErrInvalidAccess } return c.Widgets.Prohibits(wf.WidgetName, wf.Action) } // implements macaroon.Access; describes an attempt to access a widget type WidgetAccess struct { Action Action WidgetName *string } // implements macaroon.Access func (f *WidgetAccess) GetAction() Action { return f.Action } // implements macaroon.Access func (f *WidgetAccess) Now() time.Time { return time.Now() } // implements macaroon.Access func (f *WidgetAccess) Validate() error { return nil } const ( // location identifies macaroons belonging to our widget factory widgetFactoryLocation = "https://widget-factory.example" ) var ( widgetFactoryKeyID = []byte("widget-factory-key-id") widgetFactoryKey = macaroon.NewSigningKey() ) func main() { // create a new macaroon with no caveats userMacaroon, err := macaroon.New( widgetFactoryKeyID, widgetFactoryLocation, widgetFactoryKey, ) if err != nil { panic(err) } // constrain the macaroon to accessing widget "foo" with any action or // reading widget "bar". err = userMacaroon.Add(&Widgets{ResourceSet[string]{ "foo": ActionAll, "bar": ActionRead, }}) if err != nil { panic(err) } // encode macaraoon in order to give it to the user encodedMacaroon, err := userMacaroon.Encode() if err != nil { panic(err) } // ... // some time later the user makes a request to our widget factory, // presenting us with the encoded macaroon // ... // decode the user's macaroon decoded, err := macaroon.Decode(encodedMacaroon) if err != nil { panic(err) } if !bytes.Equal(widgetFactoryKeyID, decoded.Nonce.KID) { panic("macaroon signed with wrong key") } // verify the signature on the macaroon verifiedCaveats, err := decoded.Verify(widgetFactoryKey, nil, nil) if err != nil { panic(err) } // validate the user's attempt to write to widget "foo" err = verifiedCaveats.Validate(&WidgetAccess{ Action: ActionWrite, WidgetName: ptr("foo"), }) if err != nil { panic(err) } fmt.Println(`macaroon allows write access to widget "foo"`) } func ptr[T any](v T) *T { return &v }
Output: macaroon allows write access to widget "foo"
Index ¶
- Constants
- Variables
- func ZeroID[ID uint64 | string]() (ret ID)
- type Access
- type Action
- func (c *Action) CaveatType() macaroon.CaveatType
- func (a Action) IsSubsetOf(other Action) bool
- func (a Action) MarshalJSON() ([]byte, error)
- func (c *Action) Name() string
- func (c *Action) Prohibits(a macaroon.Access) error
- func (a Action) Remove(other Action) Action
- func (a Action) String() string
- func (a *Action) UnmarshalJSON(b []byte) error
- type IfPresent
- type Prefix
- type ResourceSet
Examples ¶
Constants ¶
const ( ActionAll = ActionRead | ActionWrite | ActionCreate | ActionDelete | ActionControl ActionNone = Action(0) )
Variables ¶
var ( ErrResourceUnspecified = fmt.Errorf("%w: must specify", macaroon.ErrInvalidAccess) ErrResourcesMutuallyExclusive = fmt.Errorf("%w: resources are mutually exclusive", macaroon.ErrInvalidAccess) )
Functions ¶
Types ¶
type Access ¶ added in v0.0.4
Access describes an Action being taken on a resource. Must be implemented to use IfPresent caveats.
type Action ¶ added in v0.0.4
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 ¶ added in v0.0.4
func (*Action) CaveatType ¶ added in v0.2.11
func (c *Action) CaveatType() macaroon.CaveatType
func (Action) IsSubsetOf ¶ added in v0.0.4
IsSubsetOf returns wether all bits in p are set in other.
func (Action) MarshalJSON ¶ added in v0.0.4
func (*Action) UnmarshalJSON ¶ added in v0.0.4
type IfPresent ¶ added in v0.0.4
IfPresent attempts to apply the specified `Ifs` caveats if the relevant resources are specified. If none of the relevant resources are specified, the `Else` permission is applied.
This is only meaningful to use with caveats that return macaroon ErrResourceUnspecified if the Access doesn't specify the resource constrained by the caveat. The Access must implement the resset.Access interface.
func (*IfPresent) CaveatType ¶ added in v0.0.4
func (c *IfPresent) CaveatType() macaroon.CaveatType
type ResourceSet ¶
ResourceSet is a helper type for defining caveat types specifying object->permission mappings. ResourceSets implement custom msgpack marshalling. As a result, they should be wrapped in a struct rather than simply aliasing the type. For example, don't do this:
type myCaveat resset.ResourceSet[uint64]
Instead, do this:
type myCaveat struct { Resources resset.ResourceSet[uint64] }
func (ResourceSet[ID]) EncodeMsgpack ¶
func (rs ResourceSet[ID]) EncodeMsgpack(enc *msgpack.Encoder) error
func (ResourceSet[ID]) Prohibits ¶
func (rs ResourceSet[ID]) Prohibits(id *ID, action Action) error