func (s *ErrorSuite) TestNewInteractionRequiredError(c *gc.C) { // With a request with no version header, the response // should be 407. req, err := http.NewRequest("GET", "/", nil) c.Assert(err, gc.IsNil) err = httpbakery.NewInteractionRequiredError("/visit", "/wait", nil, req) code, resp := httpbakery.ErrorToResponse(err) c.Assert(code, gc.Equals, http.StatusProxyAuthRequired) data, err := json.Marshal(resp) c.Assert(err, gc.IsNil) c.Assert(string(data), jc.JSONEquals, &httpbakery.Error{ Code: httpbakery.ErrInteractionRequired, Message: httpbakery.ErrInteractionRequired.Error(), Info: &httpbakery.ErrorInfo{ VisitURL: "/visit", WaitURL: "/wait", }, }) // With a request with a version 1 header, the response // should be 401. req.Header.Set("Bakery-Protocol-Version", "1") err = httpbakery.NewInteractionRequiredError("/visit", "/wait", nil, req) code, resp = httpbakery.ErrorToResponse(err) c.Assert(code, gc.Equals, http.StatusUnauthorized) h := make(http.Header) resp.(httprequest.HeaderSetter).SetHeader(h) c.Assert(h.Get("WWW-Authenticate"), gc.Equals, "Macaroon") data, err = json.Marshal(resp) c.Assert(err, gc.IsNil) c.Assert(string(data), jc.JSONEquals, &httpbakery.Error{ Code: httpbakery.ErrInteractionRequired, Message: httpbakery.ErrInteractionRequired.Error(), Info: &httpbakery.ErrorInfo{ VisitURL: "/visit", WaitURL: "/wait", }, }) }
func (d *InteractiveDischarger) checker(req *http.Request, cavId, cav string) ([]checkers.Caveat, error) { d.mu.Lock() id := fmt.Sprintf("%d", d.id) d.id++ d.waiting[id] = discharge{cavId, make(chan dischargeResult, 1)} d.mu.Unlock() visitURL := "/visit?waitid=" + id waitURL := "/wait?waitid=" + id return nil, httpbakery.NewInteractionRequiredError(visitURL, waitURL, nil, req) }
func (d *InteractiveDischarger) checker(req *http.Request, cavId, cav string) ([]checkers.Caveat, error) { d.mu.Lock() id := fmt.Sprintf("%d", d.id) d.id++ d.waiting[id] = discharge{cavId, make(chan dischargeResult, 1)} d.mu.Unlock() prefix := strings.TrimSuffix(req.URL.String(), "/discharge") visitURL := fmt.Sprintf("%s/visit?waitid=%s", prefix, id) waitURL := fmt.Sprintf("%s/wait?waitid=%s", prefix, id) return nil, httpbakery.NewInteractionRequiredError(visitURL, waitURL, nil, req) }
func (s *Service) checker(req *http.Request, cavID, cav string) ([]checkers.Caveat, error) { election, err := s.newElection(cavID, cav) if err != nil { return nil, errgo.Mask(err, errgo.Any) } var waitURL string if s.root != "" { waitURL = s.root + s.prefix + "/wait/" + election } else { waitURL = s.prefix + "/wait/" + election } return nil, httpbakery.NewInteractionRequiredError(waitURL, waitURL, nil, req) }
// needLogin returns an error suitable for returning // from a discharge request that can only be satisfied // if the user logs in. func (h *handler) needLogin(cavId string, caveat string, why error, req *http.Request) error { // TODO(rog) If the user is already logged in (username != ""), // we should perhaps just return an error here. log.Printf("login required") waitId, err := h.place.NewRendezvous(&thirdPartyCaveatInfo{ CaveatId: cavId, Caveat: caveat, }) if err != nil { return fmt.Errorf("cannot make rendezvous: %v", err) } log.Printf("returning redirect error") visitURL := "/login?waitid=" + waitId waitURL := "/wait?waitid=" + waitId return httpbakery.NewInteractionRequiredError(visitURL, waitURL, why, req) }
// CheckThirdPartyCaveat is part of the bakery.ThirdPartyChecker interface. func (ctx *macaroonAuthContext) CheckThirdPartyCaveat(cavId, cav string) ([]checkers.Caveat, error) { tag, err := ctx.CheckLocalLoginCaveat(cav) if err != nil { return nil, errors.Trace(err) } firstPartyCaveats, err := ctx.CheckLocalLoginRequest(ctx.req, tag) if err != nil { if _, ok := errors.Cause(err).(*bakery.VerificationError); ok { waitId, err := ctx.localUserInteractions.Start( cavId, ctx.clock.Now().Add(authentication.LocalLoginInteractionTimeout), ) if err != nil { return nil, errors.Trace(err) } visitURL := localUserIdentityLocationPath + "/login?waitid=" + waitId waitURL := localUserIdentityLocationPath + "/wait?waitid=" + waitId return nil, httpbakery.NewInteractionRequiredError(visitURL, waitURL, nil, ctx.req) } return nil, errors.Trace(err) } return firstPartyCaveats, nil }