resset

package
v0.2.13 Latest Latest
Warning

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

Go to latest
Published: Apr 17, 2024 License: Apache-2.0 Imports: 9 Imported by: 0

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

Examples

Constants

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

Variables

View Source
var (
	ErrResourceUnspecified        = fmt.Errorf("%w: must specify", macaroon.ErrInvalidAccess)
	ErrResourcesMutuallyExclusive = fmt.Errorf("%w: resources are mutually exclusive", macaroon.ErrInvalidAccess)
	ErrUnauthorizedForResource    = fmt.Errorf("%w for", macaroon.ErrUnauthorized)
	ErrUnauthorizedForAction      = fmt.Errorf("%w for", macaroon.ErrUnauthorized)
)

Functions

func ZeroID

func ZeroID[ID uint64 | string]() (ret ID)

ZeroID gets the zero value (0, or "") for a resource. This is used to refer to an unspecified resource. For example, when creating a new app, you would check for app:0:c permission.

Types

type Access added in v0.0.4

type Access interface {
	macaroon.Access
	GetAction() Action
}

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 ActionFromString(ms string) Action

func (*Action) CaveatType added in v0.2.11

func (c *Action) CaveatType() macaroon.CaveatType

func (Action) IsSubsetOf added in v0.0.4

func (a Action) IsSubsetOf(other Action) bool

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

func (Action) MarshalJSON added in v0.0.4

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

func (*Action) Name added in v0.2.11

func (c *Action) Name() string

func (*Action) Prohibits added in v0.2.11

func (c *Action) Prohibits(a macaroon.Access) error

Implements macaroon.Caveat

func (Action) Remove added in v0.0.4

func (a Action) Remove(other Action) Action

Remove returns the bits in p but not other

func (Action) String added in v0.0.4

func (a Action) String() string

func (*Action) UnmarshalJSON added in v0.0.4

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

type IfPresent added in v0.0.4

type IfPresent struct {
	Ifs  *macaroon.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` 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

func (*IfPresent) Name added in v0.0.5

func (c *IfPresent) Name() string

func (*IfPresent) Prohibits added in v0.0.4

func (c *IfPresent) Prohibits(a macaroon.Access) error

func (*IfPresent) Unwrap added in v0.0.4

func (c *IfPresent) Unwrap() *macaroon.CaveatSet

type Prefix

type Prefix string

func (Prefix) Match

func (p Prefix) Match(other Prefix) bool

type ResourceSet

type ResourceSet[ID uint64 | string | Prefix] map[ID]Action

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 New

func New[ID uint64 | string | Prefix](p Action, ids ...ID) ResourceSet[ID]

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

Jump to

Keyboard shortcuts

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