WARNING
This project is an unmaintained fork. You should use gopkg.in/macaroon.v1.
macaroon
--
import "github.com/rogpeppe/macaroon"
The macaroon package implements macaroons as described in the paper "Macaroons:
Cookies with Contextual Caveats for Decentralized Authorization in the Cloud"
(http://theory.stanford.edu/~ataly/Papers/macaroons.pdf)
Usage
type Caveat
type Caveat struct {
Id string
Location string
}
type Macaroon
type Macaroon struct {
}
Macaroon holds a macaroon. See Fig. 7 of
http://theory.stanford.edu/~ataly/Papers/macaroons.pdf for a description of the
data contained within. Macaroons are mutable objects - use Clone as appropriate
to avoid unwanted mutation.
func New
func New(rootKey []byte, id, loc string) (*Macaroon, error)
New returns a new macaroon with the given root key, identifier and location.
func (*Macaroon) AddFirstPartyCaveat
func (m *Macaroon) AddFirstPartyCaveat(caveatId string) error
AddFirstPartyCaveat adds a caveat that will be verified by the target service.
func (*Macaroon) AddThirdPartyCaveat
func (m *Macaroon) AddThirdPartyCaveat(rootKey []byte, caveatId string, loc string) error
AddThirdPartyCaveat adds a third-party caveat to the macaroon, using the given
shared root key, caveat id and location hint. The caveat id should encode the
root key in some way, either by encrypting it with a key known to the third
party or by holding a reference to it stored in the third party's storage.
func (*Macaroon) Bind
func (m *Macaroon) Bind(rootSig []byte)
Bind prepares the macaroon for being used to discharge the macaroon with the
given rootSig. This must be used before it is used in the discharges argument to
Verify.
func (*Macaroon) Caveats
func (m *Macaroon) Caveats() []Caveat
Caveats returns the macaroon's caveats. This method will probably change, and
it's important not to change the returned caveat.
func (*Macaroon) Clone
func (m *Macaroon) Clone() *Macaroon
Clone returns a copy of the receiving macaroon.
func (*Macaroon) Id
func (m *Macaroon) Id() string
Id returns the id of the macaroon. This can hold arbitrary information.
func (*Macaroon) Location
func (m *Macaroon) Location() string
Location returns the macaroon's location hint. This is not verified as part of
the macaroon.
func (*Macaroon) MarshalJSON
func (m *Macaroon) MarshalJSON() ([]byte, error)
MarshalJSON implements json.Marshaler.
func (*Macaroon) Signature
func (m *Macaroon) Signature() []byte
Signature returns the macaroon's signature.
func (*Macaroon) UnmarshalJSON
func (m *Macaroon) UnmarshalJSON(jsonData []byte) error
UnmarshalJSON implements json.Unmarshaler.
func (*Macaroon) Verify
func (m *Macaroon) Verify(rootKey []byte, check func(caveat string) error, discharges []*Macaroon) error
Verify verifies that the receiving macaroon is valid. The root key must be the
same that the macaroon was originally minted with. The check function is called
to verify each first-party caveat - it should return an error if the condition
is not met.
The discharge macaroons should be provided in discharges.
Verify returns true if the verification succeeds; if returns (false, nil) if the
verification fails, and (false, err) if the verification cannot be asserted (but
may not be false).
TODO(rog) is there a possible DOS attack that can cause this function to
infinitely recurse?
type Verifier
type Verifier interface {
Verify(m *Macaroon, rootKey []byte) (bool, error)
}
bakery
--
import "github.com/rogpeppe/macaroon/bakery"
The bakery package layers on top of the macaroon package, providing a transport
and storage-agnostic way of using macaroons to assert client capabilities.
Usage
var ErrNotFound = errors.New("item not found")
type Caveat
type Caveat struct {
Location string
Condition string
}
Caveat represents a condition that must be true for a check to complete
successfully. If Location is non-empty, the caveat must be discharged by a third
party at the given location.
type CaveatIdDecoder
type CaveatIdDecoder interface {
DecodeCaveatId(id string) (rootKey []byte, condition string, err error)
}
CaveatIdDecoder decodes caveat ids created by a CaveatIdEncoder.
type CaveatIdEncoder
type CaveatIdEncoder interface {
EncodeCaveatId(caveat Caveat, rootKey []byte) (string, error)
}
CaveatIdEncoder can create caveat ids for third parties. It is left abstract to
allow location-dependent caveat id creation.
type CaveatNotRecognizedError
type CaveatNotRecognizedError struct {
Caveat string
}
func (*CaveatNotRecognizedError) Error
func (e *CaveatNotRecognizedError) Error() string
type Discharger
type Discharger struct {
// Checker is used to check the caveat's condition.
Checker ThirdPartyChecker
// Decoder is used to decode the caveat id.
Decoder CaveatIdDecoder
// Factory is used to create the macaroon.
// Note that *Service implements NewMacarooner.
Factory NewMacarooner
}
A Discharger can be used to discharge third party caveats.
func (*Discharger) Discharge
func (d *Discharger) Discharge(id string) (*macaroon.Macaroon, error)
Discharge creates a macaroon that discharges the third party caveat with the
given id. The id should have been created earlier with a matching
CaveatIdEncoder. The condition implicit in the id is checked for validity using
d.Checker, and then if valid, a new macaroon is minted which discharges the
caveat, and can eventually be associated with a client request using
AddClientMacaroon.
type FirstPartyChecker
type FirstPartyChecker interface {
CheckFirstPartyCaveat(caveat string) error
}
FirstPartyChecker holds a function that checks first party caveats for validity.
If the caveat kind was not recognised, the checker should return
ErrCaveatNotRecognised.
type FirstPartyCheckerFunc
type FirstPartyCheckerFunc func(caveat string) error
func (FirstPartyCheckerFunc) CheckFirstPartyCaveat
func (c FirstPartyCheckerFunc) CheckFirstPartyCaveat(caveat string) error
type NewMacarooner
type NewMacarooner interface {
NewMacaroon(id string, rootKey []byte, capability string, caveats []Caveat) (*macaroon.Macaroon, error)
}
NewMacaroon mints a new macaroon with the given id, capability and caveats. If
the id is empty, a random id will be used. If rootKey is nil, a random root key
will be used.
If a client succeeds in discharging the returned macaroon, it can gain access to
the given capability.
type NewServiceParams
type NewServiceParams struct {
// Location will be set as the location of any macaroons
// minted by the service.
Location string
// Store will be used to store macaroon
// information locally. If it is nil,
// an in-memory storage will be used.
Store Storage
// CaveatIdEncoder is used to create third-party caveats.
CaveatIdEncoder CaveatIdEncoder
}
NewServiceParams holds the parameters for a NewService call.
type Request
type Request struct {
}
Request represents a request made to a service by a client. The request may be
long-lived. It holds a set of macaroons that the client wishes to be taken into
account.
Methods on a Request may be called concurrently with each other.
func (*Request) AddClientMacaroon
func (req *Request) AddClientMacaroon(m *macaroon.Macaroon)
AddClientMacaroon associates the given macaroon with the request. The macaroon
will be taken into account when req.Check is called.
TODO(rog) provide a way of deleting client macaroons?
func (*Request) Check
func (req *Request) Check(capability string) error
Check checks that the client has the given capability. If the verification fails
in a way which might be remediable, it returns a VerificationError that
describes the error.
A capability represents a client capability. A client can gain a capability by
presenting a valid, fully discharged macaroon that is associated with the
capability.
type Service
type Service struct {
}
Service represents a service which can use macaroons to check authorization.
func NewService
func NewService(p NewServiceParams) *Service
NewService returns a new service that can mint new macaroons and store their
associated root keys.
func (*Service) AddCaveat
func (svc *Service) AddCaveat(m *macaroon.Macaroon, cav Caveat) error
AddCaveat adds a caveat to the given macaroon.
If it's a third-party caveat, it uses the service's caveat-id encoder to create
the id of the new caveat.
func (*Service) NewMacaroon
func (svc *Service) NewMacaroon(id string, rootKey []byte, capability string, caveats []Caveat) (*macaroon.Macaroon, error)
NewMacaroon implements NewMacarooner.NewMacaroon.
func (*Service) NewRequest
func (svc *Service) NewRequest(checker FirstPartyChecker) *Request
NewRequest returns a new client request object that uses checker to verify
caveats.
func (*Service) Store
func (svc *Service) Store() Storage
Store returns the store used by the service.
type Storage
type Storage interface {
// Put stores the item at the given location, overwriting
// any item that might already be there.
// TODO(rog) would it be better to lose the overwrite
// semantics?
Put(location string, item string) error
// Get retrieves an item from the given location.
// If the item is not there, it returns ErrNotFound.
Get(location string) (item string, err error)
// Del deletes the item from the given location.
Del(location string) error
}
Storage defines storage for macaroons. Calling its methods concurrently is
allowed.
func NewMemStorage
func NewMemStorage() Storage
NewMemStorage returns an implementation of Storage that stores all items in
memory.
type ThirdPartyChecker
type ThirdPartyChecker interface {
CheckThirdPartyCaveat(caveat string) ([]Caveat, error)
}
ThirdPartyChecker holds a function that checks third party caveats for validity.
It the caveat is valid, it returns a nil error and optionally a slice of extra
caveats that will be added to the discharge macaroon.
If the caveat kind was not recognised, the checker should return
ErrCaveatNotRecognised.
type ThirdPartyCheckerFunc
type ThirdPartyCheckerFunc func(caveat string) ([]Caveat, error)
func (ThirdPartyCheckerFunc) CheckThirdPartyCaveat
func (c ThirdPartyCheckerFunc) CheckThirdPartyCaveat(caveat string) ([]Caveat, error)
type VerificationError
type VerificationError struct {
RequiredCapability string
Reason error
}
func (*VerificationError) Error
func (e *VerificationError) Error() string
checkers
--
import "github.com/rogpeppe/macaroon/bakery/checkers"
The checkers package provides some standard caveat checkers and
checker-combining functions.
Usage
var Std = Map{
"time-before": bakery.FirstPartyCheckerFunc(timeBefore),
}
func FirstParty
func FirstParty(condition string) bakery.Caveat
func ParseCaveat
func ParseCaveat(cav string) (string, string, error)
ParseCaveat parses a caveat into an identifier, identifying the checker that
should be used, and the argument to the checker (the rest of the string).
The identifier is taken from all the characters before the first space
character.
func PushFirstPartyChecker
func PushFirstPartyChecker(c0, c1 bakery.FirstPartyChecker) bakery.FirstPartyChecker
PushFirstPartyChecker returns a checker that first uses c0 to check caveats, and
falls back to using c1 if c0 returns bakery.ErrCaveatNotRecognized.
func ThirdParty
func ThirdParty(location, condition string) bakery.Caveat
func TimeBefore
func TimeBefore(t time.Time) bakery.Caveat
type Map
type Map map[string]bakery.FirstPartyCheckerFunc
func (Map) CheckFirstPartyCaveat
func (m Map) CheckFirstPartyCaveat(cav string) error
httpbakery
--
import "github.com/rogpeppe/macaroon/httpbakery"
The httpbakery package layers on top of the bakery package - it provides an
HTTP-based implementation of a macaroon client and server.
Usage
func Do
func Do(c *http.Client, req *http.Request) (*http.Response, error)
Do makes an http request to the given client. If the request fails with a
discharge-required error, any required discharge macaroons will be acquired, and
the request will be repeated with those attached.
If c.Jar field is non-nil, the macaroons will be stored there and made available
to subsequent requests.
func WriteDischargeRequiredError
func WriteDischargeRequiredError(w http.ResponseWriter, m *macaroon.Macaroon, originalErr error) error
WriteDischargeRequiredError writes a response to w that reports the given error
and sends the given macaroon to the client, indicating that it should be
discharged to allow the original request to be accepted.
If it returns an error, it will have written the http response anyway.
The cookie value is a base-64-encoded JSON serialization of the macaroon.
TODO(rog) consider an alternative approach - perhaps it would be better to
include the macaroon directly in the response and leave it up to the client to
add it to the cookies along with the discharge macaroons.
type KeyPair
type KeyPair struct {
}
KeyPair holds a public/private pair of keys.
func GenerateKey
func GenerateKey() (*KeyPair, error)
GenerateKey generates a new key pair.
type NewServiceParams
type NewServiceParams struct {
// Location holds the location of the service.
// Macaroons minted by the service will have this location.
Location string
// Store defines where macaroons are stored.
Store bakery.Storage
// Key holds the private/public key pair for
// the service to use. If it is nil, a new key pair
// will be generated.
Key *KeyPair
}
NewServiceParams holds parameters for the NewService call.
type Service
type Service struct {
*bakery.Service
}
Service represents a service that can use client-provided macaroons to authorize
requests. It layers on top of *bakery.Service, providing http-based methods to
create third-party caveats.
func NewService
func NewService(p NewServiceParams) (*Service, error)
NewService returns a new Service.
func (*Service) AddDischargeHandler
func (svc *Service) AddDischargeHandler(
root string,
mux *http.ServeMux,
checker func(req *http.Request, cav string) ([]bakery.Caveat, error),
)
AddDischargeHandler handles adds handlers to the given ServeMux to service third
party caveats.
The check function is used to check whether a client making the given request
should be allowed a discharge for the given caveat. If it does not return an
error, the caveat will be discharged, with any returned caveats also added to
the discharge macaroon.
The name space served by DischargeHandler is as follows. All parameters can be
provided either as URL attributes or form attributes. The result is always
formatted as a JSON object.
POST /discharge
params:
id: id of macaroon to discharge
location: location of original macaroon (optional (?))
result:
{
Macaroon: macaroon in json format
Error: string
}
POST /create
params:
condition: caveat condition to discharge
rootkey: root key of discharge caveat
result:
{
CaveatID: string
Error: string
}
GET /publickey
result:
public key of service
expiry time of key
func (*Service) AddPublicKeyForLocation
func (svc *Service) AddPublicKeyForLocation(loc string, prefix bool, publicKey *[32]byte)
AddPublicKeyForLocation specifies that third party caveats for the given
location will be encrypted with the given public key. If prefix is true, any
locations with loc as a prefix will be also associated with the given key. The
longest prefix match will be chosen. TODO(rog) perhaps string might be a better
representation of public keys?
func (*Service) NewRequest
func (svc *Service) NewRequest(httpReq *http.Request, checker bakery.FirstPartyChecker) *bakery.Request
NewRequest returns a new request, converting cookies from the HTTP request into
macaroons in the bakery request when they're found. Mmm.