// HandleError tries to resolve the given error, which should be a // response to the given URL, by discharging any macaroon contained in // it. That is, if the error cause is an *Error and its code is // ErrDischargeRequired, then it will try to discharge // err.Info.Macaroon. If the discharge succeeds, the discharged macaroon // will be saved to the client's cookie jar and ResolveError will return // nil. // // For any other kind of error, the original error will be returned. func (c *Client) HandleError(reqURL *url.URL, err error) error { respErr, ok := errgo.Cause(err).(*Error) if !ok { return err } if respErr.Code != ErrDischargeRequired { return respErr } if respErr.Info == nil || respErr.Info.Macaroon == nil { return errgo.New("no macaroon found in discharge-required response") } mac := respErr.Info.Macaroon macaroons, err := bakery.DischargeAllWithKey(mac, c.dischargeAcquirer().AcquireDischarge, c.Key) if err != nil { return errgo.Mask(err, errgo.Any) } var cookiePath string if path := respErr.Info.MacaroonPath; path != "" { relURL, err := parseURLPath(path) if err != nil { logger.Warningf("ignoring invalid path in discharge-required response: %v", err) } else { cookiePath = reqURL.ResolveReference(relURL).Path } } cookie, err := NewCookie(macaroons) if err != nil { return errgo.Notef(err, "cannot make cookie") } cookie.Path = cookiePath c.Jar.SetCookies(reqURL, []*http.Cookie{cookie}) return nil }
func (*DischargeSuite) TestDischargeAllLocalDischarge(c *gc.C) { svc, err := bakery.NewService(bakery.NewServiceParams{}) c.Assert(err, gc.IsNil) clientKey, err := bakery.GenerateKey() c.Assert(err, gc.IsNil) m, err := svc.NewMacaroon("", nil, []checkers.Caveat{ bakery.LocalThirdPartyCaveat(&clientKey.Public), }) c.Assert(err, gc.IsNil) ms, err := bakery.DischargeAllWithKey(m, noDischarge(c), clientKey) c.Assert(err, gc.IsNil) err = svc.Check(ms, checkers.New()) c.Assert(err, gc.IsNil) }
// DischargeAll attempts to acquire discharge macaroons for all the // third party caveats in m, and returns a slice containing all // of them bound to m. // // If the discharge fails because a third party refuses to discharge a // caveat, the returned error will have a cause of type *DischargeError. // If the discharge fails because visitWebPage returns an error, // the returned error will have a cause of *InteractionError. // // The returned macaroon slice will not be stored in the client // cookie jar (see SetCookie if you need to do that). func (c *Client) DischargeAll(m *macaroon.Macaroon) (macaroon.Slice, error) { return bakery.DischargeAllWithKey(m, c.dischargeAcquirer().AcquireDischarge, c.Key) }