Ejemplo n.º 1
0
func (d *formDischarger) login(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	if r.Form.Get("fallback") != "" {
		d.discharger.FinishInteraction(w, r, nil, nil)
		return
	}
	if d.ignoreAccept {
		w.Write([]byte("OK"))
		return
	}
	if r.Header.Get("Accept") != "application/json" {
		d.errorf(w, r, "bad accept header %q", r.Header.Get("Accept"))
	}
	if d.loginError {
		httprequest.WriteJSON(w, http.StatusInternalServerError, testError)
		d.discharger.FinishInteraction(w, r, nil, testError)
		return
	}
	methods := map[string]string{}
	if !d.formUnsupported {
		r.ParseForm()
		methods["form"] = d.discharger.URL("/form", r)
	}
	httprequest.WriteJSON(w, http.StatusOK, methods)
}
Ejemplo n.º 2
0
func (d *formDischarger) visit(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	if r.Form.Get("fallback") != "" {
		d.discharger.FinishInteraction(w, r, nil, nil)
		return
	}
	if d.ignoreAccept {
		w.Write([]byte("OK"))
		return
	}
	if r.Header.Get("Accept") != "application/json" {
		d.errorf(w, r, "bad accept header %q", r.Header.Get("Accept"))
	}
	if d.visitError {
		httprequest.WriteJSON(w, http.StatusInternalServerError, testError)
		d.discharger.FinishInteraction(w, r, nil, testError)
		return
	}
	methods := map[string]string{
		form.InteractionMethod: d.discharger.HostRelativeURL("/form", r),
		"othermethod":          d.discharger.HostRelativeURL("/visit", r),
	}
	if d.formUnsupported {
		delete(methods, form.InteractionMethod)
	}
	httprequest.WriteJSON(w, http.StatusOK, methods)
}
Ejemplo n.º 3
0
func (d *InteractiveDischarger) wait(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	d.mu.Lock()
	discharge, ok := d.waiting[r.Form.Get("waitid")]
	d.mu.Unlock()
	if !ok {
		code, body := httpbakery.ErrorToResponse(errgo.Newf("invalid waitid %q", r.Form.Get("waitid")))
		httprequest.WriteJSON(w, code, body)
		return
	}
	defer func() {
		d.mu.Lock()
		delete(d.waiting, r.Form.Get("waitid"))
		d.mu.Unlock()
	}()
	var err error
	var cavs []checkers.Caveat
	select {
	case res := <-discharge.c:
		err = res.err
		cavs = res.cavs
	case <-time.After(5 * time.Minute):
		code, body := httpbakery.ErrorToResponse(errgo.New("timeout waiting for interaction to complete"))
		httprequest.WriteJSON(w, code, body)
		return
	}
	if err != nil {
		code, body := httpbakery.ErrorToResponse(err)
		httprequest.WriteJSON(w, code, body)
		return
	}
	m, err := d.Service.Discharge(
		bakery.ThirdPartyCheckerFunc(
			func(cavId, caveat string) ([]checkers.Caveat, error) {
				return cavs, nil
			},
		),
		discharge.cavId,
	)
	if err != nil {
		code, body := httpbakery.ErrorToResponse(err)
		httprequest.WriteJSON(w, code, body)
		return
	}
	httprequest.WriteJSON(
		w,
		http.StatusOK,
		httpbakery.WaitResponse{
			Macaroon: m,
		},
	)
}
Ejemplo n.º 4
0
func (s *httpSuite) TestControllerMachineAuthForHostedModel(c *gc.C) {
	// Create a controller machine & hosted model.
	const nonce = "gary"
	m, password := s.Factory.MakeMachineReturningPassword(c, &factory.MachineParams{
		Jobs:  []state.MachineJob{state.JobManageModel},
		Nonce: nonce,
	})
	hostedState := s.Factory.MakeModel(c, nil)
	defer hostedState.Close()

	// Connect to the hosted model using the credentials of the
	// controller machine.
	apiInfo := s.APIInfo(c)
	apiInfo.Tag = m.Tag()
	apiInfo.Password = password
	apiInfo.ModelTag = hostedState.ModelTag()
	apiInfo.Nonce = nonce
	conn, err := api.Open(apiInfo, api.DialOpts{})
	c.Assert(err, jc.ErrorIsNil)
	httpClient, err := conn.HTTPClient()
	c.Assert(err, jc.ErrorIsNil)

	// Test with a dummy HTTP server returns the auth related headers used.
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		username, password, ok := req.BasicAuth()
		if ok {
			httprequest.WriteJSON(w, http.StatusOK, map[string]string{
				"username": username,
				"password": password,
				"nonce":    req.Header.Get(params.MachineNonceHeader),
			})
		} else {
			httprequest.WriteJSON(w, http.StatusUnauthorized, params.Error{
				Message: "no auth header",
			})
		}
	}))
	defer srv.Close()
	httpClient.BaseURL = srv.URL
	var out map[string]string
	c.Assert(httpClient.Get("/", &out), jc.ErrorIsNil)
	c.Assert(out, gc.DeepEquals, map[string]string{
		"username": m.Tag().String(),
		"password": password,
		"nonce":    nonce,
	})
}
Ejemplo n.º 5
0
func (s *ClientSuite) TestDoWithBodyAndCustomError(c *gc.C) {
	d := bakerytest.NewDischarger(nil, noCaveatChecker)
	defer d.Close()

	// Create a target service.
	svc := newService("loc", d)

	type customError struct {
		CustomError *httpbakery.Error
	}
	callCount := 0
	handler := func(w http.ResponseWriter, req *http.Request) {
		callCount++
		if _, checkErr := httpbakery.CheckRequest(svc, req, nil, checkers.New()); checkErr != nil {
			httprequest.WriteJSON(w, http.StatusTeapot, customError{
				CustomError: newDischargeRequiredError(svc, d.Location(), nil, checkErr, req).(*httpbakery.Error),
			})
			return
		}
		fmt.Fprintf(w, "hello there")
	}
	srv := httptest.NewServer(http.HandlerFunc(handler))
	defer srv.Close()

	req, err := http.NewRequest("GET", srv.URL, nil)
	c.Assert(err, gc.IsNil)

	// First check that a normal request fails.
	resp, err := httpbakery.NewClient().Do(req)
	c.Assert(err, gc.IsNil)
	defer resp.Body.Close()
	c.Assert(resp.StatusCode, gc.Equals, http.StatusTeapot)
	c.Assert(callCount, gc.Equals, 1)
	callCount = 0

	// Then check that a request with a custom error getter succeeds.
	errorGetter := func(resp *http.Response) error {
		if resp.StatusCode != http.StatusTeapot {
			return nil
		}
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			panic(err)
		}
		var respErr customError
		if err := json.Unmarshal(data, &respErr); err != nil {
			panic(err)
		}
		return respErr.CustomError
	}

	resp, err = httpbakery.NewClient().DoWithBodyAndCustomError(req, nil, errorGetter)
	c.Assert(err, gc.IsNil)

	data, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, gc.IsNil)
	c.Assert(string(data), gc.Equals, "hello there")
	c.Assert(callCount, gc.Equals, 2)
}
Ejemplo n.º 6
0
func (*handlerSuite) TestSetHeader(c *gc.C) {
	rec := httptest.NewRecorder()
	err := httprequest.WriteJSON(rec, http.StatusTeapot, HeaderNumber{1234})
	c.Assert(err, gc.IsNil)
	c.Assert(rec.Code, gc.Equals, http.StatusTeapot)
	c.Assert(rec.Body.String(), gc.Equals, `{"N":1234}`)
	c.Assert(rec.Header().Get("content-type"), gc.Equals, "application/json")
	c.Assert(rec.Header().Get("some-custom-header"), gc.Equals, "yes")
}
Ejemplo n.º 7
0
func (d *formDischarger) form(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	if r.Form.Get("waitid") == "" {
		d.errorf(w, r, "no waitid")
		return
	}
	if r.Method == "GET" {
		if d.getError {
			httprequest.WriteJSON(w, http.StatusInternalServerError, testError)
			d.discharger.FinishInteraction(w, r, nil, testError)
			return
		}
		var sr form.SchemaResponse
		if !d.emptySchema {
			sr.Schema = environschema.Fields{
				"username": environschema.Attr{
					Type: environschema.Tstring,
				},
				"password": environschema.Attr{
					Type:   environschema.Tstring,
					Secret: true,
				},
			}
		}
		httprequest.WriteJSON(w, http.StatusOK, sr)
		return
	}
	if r.Method != "POST" {
		d.errorf(w, r, "bad method %q", r.Method)
		return
	}
	if d.postError {
		httprequest.WriteJSON(w, http.StatusInternalServerError, testError)
		d.discharger.FinishInteraction(w, r, nil, testError)
		return
	}
	var lr form.LoginRequest
	err := httprequest.Unmarshal(httprequest.Params{Request: r}, &lr)
	if err != nil {
		d.errorf(w, r, "bad login request: %s", err)
		return
	}
	d.discharger.FinishInteraction(w, r, nil, nil)
}
Ejemplo n.º 8
0
func (*handlerSuite) TestWriteJSON(c *gc.C) {
	rec := httptest.NewRecorder()
	type Number struct {
		N int
	}
	err := httprequest.WriteJSON(rec, http.StatusTeapot, Number{1234})
	c.Assert(err, gc.IsNil)
	c.Assert(rec.Code, gc.Equals, http.StatusTeapot)
	c.Assert(rec.Body.String(), gc.Equals, `{"N":1234}`)
	c.Assert(rec.Header().Get("content-type"), gc.Equals, "application/json")
}
Ejemplo n.º 9
0
// FinishInteraction signals to the InteractiveDischarger that a
// particular interaction is complete. It causes any waiting requests to
// return. If err is not nil then it will be returned by the
// corresponding /wait request.
func (d *InteractiveDischarger) FinishInteraction(w http.ResponseWriter, r *http.Request, cavs []checkers.Caveat, err error) {
	r.ParseForm()
	d.mu.Lock()
	discharge, ok := d.waiting[r.Form.Get("waitid")]
	d.mu.Unlock()
	if !ok {
		code, body := httpbakery.ErrorToResponse(errgo.Newf("invalid waitid %q", r.Form.Get("waitid")))
		httprequest.WriteJSON(w, code, body)
		return
	}
	select {
	case discharge.c <- dischargeResult{err: err, cavs: cavs}:
	default:
		panic("cannot finish interaction " + r.Form.Get("waitid"))
	}
	return
}
Ejemplo n.º 10
0
func (s *clientSuite) TestAddLocalCharmError(c *gc.C) {
	client := s.APIState.Client()

	// AddLocalCharm does not use the facades, so instead of patching the
	// facade call, we set up a fake endpoint to test.
	defer fakeAPIEndpoint(c, client, envEndpoint(c, s.APIState, "charms"), "POST",
		func(w http.ResponseWriter, r *http.Request) {
			httprequest.WriteJSON(w, http.StatusMethodNotAllowed, &params.CharmsResponse{
				Error:     "the POST method is not allowed",
				ErrorCode: params.CodeMethodNotAllowed,
			})
		},
	).Close()

	charmArchive := testcharms.Repo.CharmArchive(c.MkDir(), "dummy")
	curl := charm.MustParseURL(
		fmt.Sprintf("local:quantal/%s-%d", charmArchive.Meta().Name, charmArchive.Revision()),
	)

	_, err := client.AddLocalCharm(curl, charmArchive)
	c.Assert(err, gc.ErrorMatches, `POST http://.+: the POST method is not allowed`)
}
Ejemplo n.º 11
0
	client, err := s.APIState.HTTPClient()
	c.Assert(err, gc.IsNil)
	s.client = client
}

var httpClientTests = []struct {
	about           string
	handler         http.HandlerFunc
	expectResponse  interface{}
	expectError     string
	expectErrorCode string
	expectErrorInfo *params.ErrorInfo
}{{
	about: "success",
	handler: func(w http.ResponseWriter, req *http.Request) {
		httprequest.WriteJSON(w, http.StatusOK, "hello, world")
	},
	expectResponse: newString("hello, world"),
}, {
	about: "unauthorized status without discharge-required error",
	handler: func(w http.ResponseWriter, req *http.Request) {
		httprequest.WriteJSON(w, http.StatusUnauthorized, params.Error{
			Message: "something",
		})
	},
	expectError: `GET http://.*/: something`,
}, {
	about:       "non-JSON error response",
	handler:     http.NotFound,
	expectError: `GET http://.*/: unexpected content type text/plain; want application/json; content: 404 page not found`,
}, {