// NewDischarger returns a new third party caveat discharger // which uses the given function to check caveats. // The cond and arg arguments to the function are as returned // by checkers.ParseCaveat. // // If locator is non-nil, it will be used to find public keys // for any third party caveats returned by the checker. // // Calling this function has the side-effect of setting // InsecureSkipVerify in http.DefaultTransport.TLSClientConfig // until all the dischargers are closed. func NewDischarger( locator bakery.PublicKeyLocator, checker func(req *http.Request, cond, arg string) ([]checkers.Caveat, error), ) *Discharger { mux := http.NewServeMux() server := httptest.NewTLSServer(mux) svc, err := bakery.NewService(bakery.NewServiceParams{ Location: server.URL, Locator: locator, }) if err != nil { panic(err) } checker1 := func(req *http.Request, cavId, cav string) ([]checkers.Caveat, error) { cond, arg, err := checkers.ParseCaveat(cav) if err != nil { return nil, err } return checker(req, cond, arg) } httpbakery.AddDischargeHandler(mux, "/", svc, checker1) startSkipVerify() return &Discharger{ Service: svc, server: server, } }
func (d *Discharger) ServeMux() *http.ServeMux { mux := http.NewServeMux() httpbakery.AddDischargeHandler(mux, "/", d.Bakery, d.checker) mux.Handle("/login", http.HandlerFunc(d.login)) mux.Handle("/wait", http.HandlerFunc(d.wait)) mux.Handle("/", http.HandlerFunc(d.notfound)) return mux }
func newHTTPDischarger(locator bakery.PublicKeyLocator, checker func(svc *bakery.Service, req *http.Request, cavId, cav string) ([]checkers.Caveat, error)) (*bakery.PublicKey, http.Handler) { svc := newService("loc", locator) mux := http.NewServeMux() httpbakery.AddDischargeHandler(mux, "/", svc, func(req *http.Request, cavId, cav string) ([]checkers.Caveat, error) { return checker(svc, req, cavId, cav) }) return svc.PublicKey(), mux }
// authService implements an authorization service, // that can discharge third-party caveats added // to other macaroons. func authService(endpoint string, key *bakery.KeyPair) (http.Handler, error) { svc, err := bakery.NewService(bakery.NewServiceParams{ Location: endpoint, Key: key, Locator: bakery.NewPublicKeyRing(), }) if err != nil { return nil, err } mux := http.NewServeMux() httpbakery.AddDischargeHandler(mux, "/", svc, thirdPartyChecker) return mux, nil }
// NewService returns a new Service instance. func NewService(config ServiceConfig) (*Service, error) { bakeryService, err := bakery.NewService(bakery.NewServiceParams{}) if err != nil { return nil, errgo.Mask(err, errgo.Any) } s := &Service{bakery: bakeryService, prefix: config.Prefix} s.mux = http.NewServeMux() httpbakery.AddDischargeHandler(s.mux, config.Prefix+"/discharger", s.bakery, s.checker) r := httprouter.New() r.GET(config.Prefix+"/wait/:election", s.wait) r.GET(config.Prefix+"/approve/:ballot", s.approve) r.GET(config.Prefix+"/deny/:ballot", s.deny) s.mux.Handle("/", r) return s, nil }
// New returns a new handler that services an identity-providing // service. This acts as a login service and can discharge third-party caveats // for users. func New(p Params) (http.Handler, error) { svc, err := bakery.NewService(p.Service) if err != nil { return nil, err } h := &handler{ svc: svc, users: p.Users, place: &place{meeting.New()}, } mux := http.NewServeMux() httpbakery.AddDischargeHandler(mux, "/", svc, h.checkThirdPartyCaveat) mux.Handle("/user/", mkHandler(handleJSON(h.userHandler))) mux.HandleFunc("/login", h.loginHandler) mux.Handle("/question", mkHandler(handleJSON(h.questionHandler))) mux.Handle("/wait", mkHandler(handleJSON(h.waitHandler))) mux.HandleFunc("/loginattempt", h.loginAttemptHandler) return mux, nil }
// NewInteractiveDischarger returns a new InteractiveDischarger. The // InteractiveDischarger will serve the following endpoints by default: // // /discharge - always causes interaction to be required. // /publickey - gets the bakery public key. // /visit - delegates to visitHandler. // /wait - blocks waiting for the interaction to complete. // // Additional endpoints may be added to Mux as necessary. // // The /discharge endpoint generates a error with the code // httpbakery.ErrInterractionRequired. The visitURL and waitURL will // point to the /visit and /wait endpoints of the InteractiveDischarger // respectively. These URLs will also carry context information in query // parameters, any handlers should be careful to preserve this context // information between calls. The easiest way to do this is to always use // the URL method when generating new URLs. // // The /visit endpoint is handled by the provided visitHandler. This // handler performs the required interactions and should result in the // FinishInteraction method being called. This handler may process the // interaction in a number of steps, possibly using additional handlers, // so long as FinishInteraction is called when no further interaction is // required. // // The /wait endpoint blocks until FinishInteraction has been called by // the corresponding /visit endpoint, or another endpoint triggered by // visitHandler. // // If locator is non-nil, it will be used to find public keys // for any third party caveats returned by the checker. // // Calling this function has the side-effect of setting // InsecureSkipVerify in http.DefaultTransport.TLSClientConfig // until all the dischargers are closed. // // The returned InteractiveDischarger must be closed when finished with. func NewInteractiveDischarger(locator bakery.PublicKeyLocator, visitHandler http.Handler) *InteractiveDischarger { d := &InteractiveDischarger{ Mux: http.NewServeMux(), waiting: map[string]discharge{}, } d.Mux.Handle("/visit", visitHandler) d.Mux.Handle("/wait", http.HandlerFunc(d.wait)) server := httptest.NewTLSServer(d.Mux) svc, err := bakery.NewService(bakery.NewServiceParams{ Location: server.URL, Locator: locator, }) if err != nil { panic(err) } httpbakery.AddDischargeHandler(d.Mux, "/", svc, d.checker) startSkipVerify() d.Discharger = Discharger{ Service: svc, server: server, } return d }
func (srv *Server) endpoints() []apihttp.Endpoint { httpCtxt := httpContext{ srv: srv, } endpoints := common.ResolveAPIEndpoints(srv.newHandlerArgs) // TODO(ericsnow) Add the following to the registry instead. add := func(pattern string, handler http.Handler) { // TODO: We can switch from all methods to specific ones for entries // where we only want to support specific request methods. However, our // tests currently assert that errors come back as application/json and // pat only does "text/plain" responses. for _, method := range common.DefaultHTTPMethods { endpoints = append(endpoints, apihttp.Endpoint{ Pattern: pattern, Method: method, Handler: handler, }) } } strictCtxt := httpCtxt strictCtxt.strictValidation = true strictCtxt.controllerModelOnly = true mainAPIHandler := srv.trackRequests(http.HandlerFunc(srv.apiHandler)) logSinkHandler := srv.trackRequests(newLogSinkHandler(httpCtxt, srv.logDir)) logStreamHandler := srv.trackRequests(newLogStreamEndpointHandler(strictCtxt)) debugLogHandler := srv.trackRequests(newDebugLogDBHandler(httpCtxt)) add("/model/:modeluuid/logsink", logSinkHandler) add("/model/:modeluuid/logstream", logStreamHandler) add("/model/:modeluuid/log", debugLogHandler) add("/model/:modeluuid/charms", &charmsHandler{ ctxt: httpCtxt, dataDir: srv.dataDir}, ) add("/model/:modeluuid/tools", &toolsUploadHandler{ ctxt: httpCtxt, }, ) add("/model/:modeluuid/tools/:version", &toolsDownloadHandler{ ctxt: httpCtxt, }, ) add("/model/:modeluuid/backups", &backupHandler{ ctxt: strictCtxt, }, ) add("/model/:modeluuid/api", mainAPIHandler) endpoints = append(endpoints, guiEndpoints("/gui/:modeluuid/", srv.dataDir, httpCtxt)...) add("/gui-archive", &guiArchiveHandler{ ctxt: httpCtxt, }) add("/gui-version", &guiVersionHandler{ ctxt: httpCtxt, }) // For backwards compatibility we register all the old paths add("/log", debugLogHandler) add("/charms", &charmsHandler{ ctxt: httpCtxt, dataDir: srv.dataDir, }, ) add("/tools", &toolsUploadHandler{ ctxt: httpCtxt, }, ) add("/tools/:version", &toolsDownloadHandler{ ctxt: httpCtxt, }, ) add("/register", ®isterUserHandler{ ctxt: httpCtxt, }, ) add("/api", mainAPIHandler) // Serve the API at / (only) for backward compatiblity. Note that the // pat muxer special-cases / so that it does not serve all // possible endpoints, but only / itself. add("/", mainAPIHandler) // Add HTTP handlers for local-user macaroon authentication. localLoginHandlers := &localLoginHandlers{srv.authCtxt, srv.state} dischargeMux := http.NewServeMux() httpbakery.AddDischargeHandler( dischargeMux, localUserIdentityLocationPath, localLoginHandlers.authCtxt.localUserThirdPartyBakeryService, localLoginHandlers.checkThirdPartyCaveat, ) dischargeMux.Handle( localUserIdentityLocationPath+"/login", makeHandler(handleJSON(localLoginHandlers.serveLogin)), ) dischargeMux.Handle( localUserIdentityLocationPath+"/wait", makeHandler(handleJSON(localLoginHandlers.serveWait)), ) add(localUserIdentityLocationPath+"/discharge", dischargeMux) add(localUserIdentityLocationPath+"/publickey", dischargeMux) add(localUserIdentityLocationPath+"/login", dischargeMux) add(localUserIdentityLocationPath+"/wait", dischargeMux) return endpoints }