macaroons: add constraint/checker options layer
This commit is contained in:
parent
d65f17f1b1
commit
5c3493bd30
86
macaroons/constraints.go
Normal file
86
macaroons/constraints.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package macaroons
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gopkg.in/macaroon-bakery.v1/bakery/checkers"
|
||||||
|
macaroon "gopkg.in/macaroon.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Constraint type adds a layer of indirection over macaroon caveats and
|
||||||
|
// checkers.
|
||||||
|
type Constraint func(*macaroon.Macaroon)
|
||||||
|
|
||||||
|
// AddConstraints returns new derived macaroon by applying every passed
|
||||||
|
// constraint and tightening its restrictions.
|
||||||
|
func AddConstraints(mac *macaroon.Macaroon, cs ...Constraint) *macaroon.Macaroon {
|
||||||
|
newMac := mac.Clone()
|
||||||
|
for _, constraint := range cs {
|
||||||
|
constraint(newMac)
|
||||||
|
}
|
||||||
|
return newMac
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each *Constraint function is a functional option, which takes a pointer
|
||||||
|
// to the macaroon and adds another restriction to it. For each *Constraint,
|
||||||
|
// the corresponding *Checker is provided.
|
||||||
|
|
||||||
|
// PermissionsConstraint restricts allowed operations set to the ones
|
||||||
|
// passed to it.
|
||||||
|
func PermissionsConstraint(ops ...string) func(*macaroon.Macaroon) {
|
||||||
|
return func(mac *macaroon.Macaroon) {
|
||||||
|
caveat := checkers.AllowCaveat(ops...)
|
||||||
|
mac.AddFirstPartyCaveat(caveat.Condition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PermissionsChecker wraps default checkers.OperationChecker.
|
||||||
|
func PermissionsChecker(method string) checkers.Checker {
|
||||||
|
return checkers.OperationChecker(method)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeoutConstraint restricts the lifetime of the macaroon
|
||||||
|
// to the amount of seconds given.
|
||||||
|
func TimeoutConstraint(seconds int64) func(*macaroon.Macaroon) {
|
||||||
|
return func(mac *macaroon.Macaroon) {
|
||||||
|
macaroonTimeout := time.Duration(seconds)
|
||||||
|
requestTimeout := time.Now().Add(time.Second * macaroonTimeout)
|
||||||
|
caveat := checkers.TimeBeforeCaveat(requestTimeout)
|
||||||
|
mac.AddFirstPartyCaveat(caveat.Condition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimeoutChecker wraps default checkers.TimeBefore checker.
|
||||||
|
func TimeoutChecker() checkers.Checker {
|
||||||
|
return checkers.TimeBefore
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPLockConstraint locks macaroon to a specific IP address.
|
||||||
|
// If address is an empty string, this constraint does nothing to
|
||||||
|
// accommodate default value's desired behavior.
|
||||||
|
func IPLockConstraint(ipAddr string) func(*macaroon.Macaroon) {
|
||||||
|
return func(mac *macaroon.Macaroon) {
|
||||||
|
if ipAddr != "" {
|
||||||
|
macaroonIPAddr := net.ParseIP(ipAddr)
|
||||||
|
caveat := checkers.ClientIPAddrCaveat(macaroonIPAddr)
|
||||||
|
mac.AddFirstPartyCaveat(caveat.Condition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPLockChecker accepts client IP from the validation context and compares it
|
||||||
|
// with IP locked in the macaroon.
|
||||||
|
func IPLockChecker(clientIP string) checkers.Checker {
|
||||||
|
return checkers.CheckerFunc{
|
||||||
|
Condition_: checkers.CondClientIPAddr,
|
||||||
|
Check_: func(_, cav string) error {
|
||||||
|
if !net.ParseIP(cav).Equal(net.ParseIP(clientIP)) {
|
||||||
|
msg := "macaroon locked to different IP address"
|
||||||
|
return fmt.Errorf(msg)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user