func newHTTPHandler(h *debugstatus.Handler) http.Handler { errMapper := httprequest.ErrorMapper(func(err error) (httpStatus int, errorBody interface{}) { code, status := "", http.StatusInternalServerError switch errgo.Cause(err) { case errUnauthorized: code, status = "unauthorized", http.StatusUnauthorized case debugstatus.ErrNoPprofConfigured: code, status = "forbidden", http.StatusForbidden case debugstatus.ErrNoTraceConfigured: code, status = "forbidden", http.StatusForbidden } return status, httprequest.RemoteError{ Code: code, Message: err.Error(), } }) handlers := errMapper.Handlers(func(httprequest.Params) (*debugstatus.Handler, error) { return h, nil }) r := httprouter.New() for _, h := range handlers { r.Handle(h.Method, h.Path, h.Handle) } return r }
func (s *httpAuthChecker) writeError(w http.ResponseWriter, err error, req *http.Request) { err1, ok := errgo.Cause(err).(*auth.DischargeRequiredError) if !ok { logger.Infof("error when authorizing: %#v", err) // TODO permission denied error. http.Error(w, err.Error(), http.StatusInternalServerError) return } logger.Infof("got discharge-required error: %#v", err) if len(err1.Caveats) == 0 { panic("no caveats on discharge-required error!") } cookieName := "authz" expiry := 5 * time.Second if len(err1.Ops) == 1 && err1.Ops[0] == auth.LoginOp { cookieName = "authn" expiry = 24 * time.Hour } caveats := append(err1.Caveats, checkers.TimeBeforeCaveat(time.Now().Add(expiry))) m, err := s.store.NewMacaroon(err1.Ops, caveats) if err != nil { panic("cannot make new macaroon: " + err.Error()) } // It's a discharge-required error. Write the expected httpbakery response. berr := httpbakery.NewDischargeRequiredErrorForRequest(m, "/", err, req) berr.(*httpbakery.Error).Info.CookieNameSuffix = cookieName // TODO we need some way of telling the client that the response shouldn't // be persisted. httprequest.ErrorMapper(httpbakery.ErrorToResponse).WriteError(w, berr) }
c.Assert(err, gc.ErrorMatches, `cannot get discharge from "https://.*": cannot start interactive session: cannot visit`) c.Assert(httpbakery.IsInteractionError(errgo.Cause(err)), gc.Equals, true) ierr, ok := errgo.Cause(err).(*httpbakery.InteractionError) c.Assert(ok, gc.Equals, true) c.Assert(ierr.Reason, gc.Equals, errCannotVisit) c.Assert(resp, gc.IsNil) } var dischargeWithVisitURLErrorTests = []struct { about string respond func(http.ResponseWriter) expectError string }{{ about: "error message", respond: func(w http.ResponseWriter) { httprequest.ErrorMapper(httpbakery.ErrorToResponse).WriteError(w, fmt.Errorf("an error")) }, expectError: `cannot get discharge from ".*": failed to acquire macaroon after waiting: third party refused discharge: an error`, }, { about: "non-JSON error", respond: func(w http.ResponseWriter) { w.Write([]byte("bad response")) }, // TODO fix this unhelpful error message expectError: `cannot get discharge from ".*": cannot unmarshal wait response: invalid character 'b' looking for beginning of value`, }} func (s *ClientSuite) TestDischargeWithVisitURLError(c *gc.C) { visitor := newVisitHandler(nil) visitSrv := httptest.NewServer(visitor) defer visitSrv.Close()
"log" "net/http" "github.com/juju/httprequest" "github.com/julienschmidt/httprouter" "gopkg.in/errgo.v1" "gopkg.in/macaroon.v1" "gopkg.in/macaroon-bakery.v1/bakery" "gopkg.in/macaroon-bakery.v1/bakery/checkers" "gopkg.in/macaroon-bakery.v1/bakery/example/meeting" "gopkg.in/macaroon-bakery.v1/httpbakery" ) var ( handleJSON = httprequest.ErrorMapper(errorToResponse).HandleJSON ) const ( cookieUser = "******" ) // handler implements http.Handler to serve the name space // provided by the id service. type handler struct { svc *bakery.Service place *place users map[string]*UserInfo } // UserInfo holds information about a user.