diff --git a/authorizer.go b/authorizer.go index 8700112..cf0cdfd 100644 --- a/authorizer.go +++ b/authorizer.go @@ -1,7 +1,6 @@ package tokenizer import ( - "bytes" "crypto/sha256" "crypto/subtle" "encoding/base64" @@ -13,6 +12,9 @@ import ( "github.com/sirupsen/logrus" "github.com/superfly/macaroon" + "github.com/superfly/macaroon/bundle" + "github.com/superfly/macaroon/flyio" + "github.com/superfly/macaroon/flyio/machinesapi" tkmac "github.com/superfly/tokenizer/macaroon" ) @@ -58,34 +60,22 @@ func (c *MacaroonAuthConfig) AuthRequest(req *http.Request) error { var ( expectedKID = tkmac.KeyFingerprint(c.Key) log = logrus.WithField("expected-kid", hex.EncodeToString(expectedKID)) + ctx = req.Context() ) for _, tok := range proxyAuthorizationTokens(req) { - permission, discharges, err := macaroon.ParsePermissionAndDischargeTokens(tok, tkmac.Location) - if err != nil { - log.WithError(err).Warn("bad macaroon encoding") - continue - } - - m, err := macaroon.Decode(permission) + bun, err := bundle.ParseBundle(tkmac.Location, tok) if err != nil { log.WithError(err).Warn("bad macaroon format") continue } - log = log.WithFields(logrus.Fields{"uuid": m.Nonce.UUID()}) - if !bytes.Equal(m.Nonce.KID, expectedKID) { - log.WithField("kid", hex.EncodeToString(m.Nonce.KID)).Warn("wrong macaroon key") - continue - } - - cavs, err := m.Verify(c.Key, discharges, nil) - if err != nil { + if _, err = bun.Verify(ctx, bundle.WithKey(expectedKID, c.Key, nil)); err != nil { log.WithError(err).Warn("bad macaroon signature") continue } - if err = cavs.Validate(&tkmac.Access{Request: req}); err != nil { + if err = bun.Validate(&tkmac.Access{Request: req}); err != nil { log.WithError(err).Warn("bad macaroon authz") continue } @@ -114,6 +104,42 @@ func (c *MacaroonAuthConfig) Macaroon(caveats ...macaroon.Caveat) (string, error return macaroon.ToAuthorizationHeader(mb), nil } +type FlyioMacaroonAuthConfig struct { + Access flyio.Access `json:"access"` +} + +func NewFlyioMacaroonAuthConfig(access *flyio.Access) *FlyioMacaroonAuthConfig { + return &FlyioMacaroonAuthConfig{Access: *access} +} + +var _ AuthConfig = new(FlyioMacaroonAuthConfig) + +func (c *FlyioMacaroonAuthConfig) AuthRequest(req *http.Request) error { + var ctx = req.Context() + + for _, tok := range proxyAuthorizationTokens(req) { + bun, err := flyio.ParseBundle(tok) + if err != nil { + logrus.WithError(err).Warn("bad macaroon format") + continue + } + + if _, err := bun.Verify(ctx, machinesapi.DefaultClient); err != nil { + logrus.WithError(err).Warn("bad macaroon signature") + continue + } + + if err := bun.Validate(&c.Access); err != nil { + logrus.WithError(err).Warn("bad macaroon authz") + continue + } + + return nil + } + + return fmt.Errorf("%w: bad or missing proxy auth", ErrNotAuthorized) +} + func proxyAuthorizationTokens(req *http.Request) (ret []string) { hdrLoop: for _, hdr := range req.Header.Values(headerProxyAuthorization) { diff --git a/go.mod b/go.mod index 670eaa7..74a6e1b 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,10 @@ module github.com/superfly/tokenizer go 1.20 require ( - github.com/alecthomas/assert/v2 v2.2.2 + github.com/alecthomas/assert/v2 v2.3.0 github.com/elazarl/goproxy v0.0.0-20230731152917-f99041a5c027 github.com/sirupsen/logrus v1.9.3 - github.com/superfly/macaroon v0.0.5 + github.com/superfly/macaroon v0.2.14-0.20240718172852-139f90b76537 golang.org/x/crypto v0.12.0 golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 ) @@ -14,6 +14,7 @@ require ( require ( github.com/alecthomas/repr v0.2.0 // indirect github.com/google/uuid v1.3.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index e938235..619b9f4 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= -github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= +github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0= +github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -11,6 +11,8 @@ github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy0 github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -22,8 +24,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/superfly/macaroon v0.0.5 h1:Rw48kdYc2k0PHccGnNWO0Byc5TQoJBjbQtzGZJPFKcU= -github.com/superfly/macaroon v0.0.5/go.mod h1:5DZuLe1e3EiEDs9R7snKQJVslVjgBhlJ9jbnOmKasRg= +github.com/superfly/macaroon v0.2.14-0.20240718172852-139f90b76537 h1:xL2tIkau3Dr3dd4WOLbGz14kRcF49x15bVIMdOkLTyI= +github.com/superfly/macaroon v0.2.14-0.20240718172852-139f90b76537/go.mod h1:Kt6/EdSYfFjR4GIe+erMwcJgU8iMu1noYVceQ5dNdKo= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -36,5 +38,5 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/secret.go b/secret.go index 178c85f..c3eeb9a 100644 --- a/secret.go +++ b/secret.go @@ -55,6 +55,7 @@ type wireSecret struct { *OAuthProcessorConfig `json:"oauth2_processor,omitempty"` *BearerAuthConfig `json:"bearer_auth,omitempty"` *MacaroonAuthConfig `json:"macaroon_auth,omitempty"` + *FlyioMacaroonAuthConfig `json:"flyio_macaroon_auth,omitempty"` AllowHosts []string `json:"allowed_hosts,omitempty"` AllowHostPattern string `json:"allowed_host_pattern,omitempty"` } @@ -67,6 +68,8 @@ func (s *Secret) MarshalJSON() ([]byte, error) { ws.BearerAuthConfig = a case *MacaroonAuthConfig: ws.MacaroonAuthConfig = a + case *FlyioMacaroonAuthConfig: + ws.FlyioMacaroonAuthConfig = a default: return nil, errors.New("bad auth config") } @@ -131,6 +134,10 @@ func (s *Secret) UnmarshalJSON(b []byte) error { na += 1 s.AuthConfig = ws.MacaroonAuthConfig } + if ws.FlyioMacaroonAuthConfig != nil { + na += 1 + s.AuthConfig = ws.FlyioMacaroonAuthConfig + } if na != 1 { return errors.New("bad auth config") }