func (*VisitorSuite) TestMultiVisitorSequence(c *gc.C) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprint(w, `{"method": "http://somewhere/something"}`)
	}))
	defer srv.Close()

	firstCalled, secondCalled := 0, 0
	v := httpbakery.NewMultiVisitor(
		visitorFunc(func(_ *httpbakery.Client, m map[string]*url.URL) error {
			c.Check(m["method"], gc.NotNil)
			firstCalled++
			return httpbakery.ErrMethodNotSupported
		}),
		visitorFunc(func(_ *httpbakery.Client, m map[string]*url.URL) error {
			c.Check(m["method"], gc.NotNil)
			secondCalled++
			return nil
		}),
	)
	err := v.VisitWebPage(httpbakery.NewClient(), map[string]*url.URL{
		httpbakery.UserInteractionMethod: mustParseURL(srv.URL),
	})
	c.Assert(err, gc.IsNil)
	c.Assert(firstCalled, gc.Equals, 1)
	c.Assert(secondCalled, gc.Equals, 1)
}
func (*VisitorSuite) TestUserInteractionFallback(c *gc.C) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprint(w, `{"method": "http://somewhere/something"}`)
	}))
	defer srv.Close()

	called := 0
	// Check that even though the methods didn't explicitly
	// include the "interactive" method, it is still supplied.
	v := httpbakery.NewMultiVisitor(
		visitorFunc(func(_ *httpbakery.Client, m map[string]*url.URL) error {
			c.Check(m, jc.DeepEquals, map[string]*url.URL{
				"method": mustParseURL("http://somewhere/something"),
				httpbakery.UserInteractionMethod: mustParseURL(srv.URL),
			})
			called++
			return nil
		}),
	)
	err := v.VisitWebPage(httpbakery.NewClient(), map[string]*url.URL{
		httpbakery.UserInteractionMethod: mustParseURL(srv.URL),
	})
	c.Assert(err, gc.IsNil)
	c.Assert(called, gc.Equals, 1)
}
func (*VisitorSuite) TestMultiVisitorVisitorError(c *gc.C) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprint(w, `{"method": "http://somewhere/something"}`)
	}))
	defer srv.Close()

	testError := errgo.New("test error")
	v := httpbakery.NewMultiVisitor(
		visitorFunc(func(*httpbakery.Client, map[string]*url.URL) error {
			return testError
		}),
	)
	err := v.VisitWebPage(httpbakery.NewClient(), map[string]*url.URL{
		httpbakery.UserInteractionMethod: mustParseURL(srv.URL),
	})
	c.Assert(errgo.Cause(err), gc.Equals, testError)
}
Exemple #4
0
func (s *toolsWithMacaroonsSuite) TestCanPostWithLocalLogin(c *gc.C) {
	// Create a new local user that we can log in as
	// using macaroon authentication.
	const password = "******"
	user := s.Factory.MakeUser(c, &factory.UserParams{Password: password})

	// Install a "web-page" visitor that deals with the interaction
	// method that Juju controllers support for authenticating local
	// users. Note: the use of httpbakery.NewMultiVisitor is necessary
	// to trigger httpbakery to query the authentication methods and
	// bypass browser authentication.
	var prompted bool
	jar := apitesting.NewClearableCookieJar()
	client := utils.GetNonValidatingHTTPClient()
	client.Jar = jar
	bakeryClient := httpbakery.NewClient()
	bakeryClient.Client = client
	bakeryClient.WebPageVisitor = httpbakery.NewMultiVisitor(apiauthentication.NewVisitor(
		user.UserTag().Id(),
		func(username string) (string, error) {
			c.Assert(username, gc.Equals, user.UserTag().Id())
			prompted = true
			return password, nil
		},
	))
	bakeryDo := func(req *http.Request) (*http.Response, error) {
		var body io.ReadSeeker
		if req.Body != nil {
			body = req.Body.(io.ReadSeeker)
			req.Body = nil
		}
		return bakeryClient.DoWithBodyAndCustomError(req, body, bakeryGetError)
	}

	resp := s.sendRequest(c, httpRequestParams{
		method:   "POST",
		url:      s.toolsURI(c, ""),
		tag:      user.UserTag().String(),
		password: "", // no password forces macaroon usage
		do:       bakeryDo,
	})
	s.assertErrorResponse(c, resp, http.StatusBadRequest, "expected binaryVersion argument")
	c.Assert(prompted, jc.IsTrue)
}
Exemple #5
0
func (c *changePasswordCommand) recordMacaroon(user, password string) error {
	accountDetails := &jujuclient.AccountDetails{User: user}
	args, err := c.NewAPIConnectionParams(
		c.ClientStore(), c.ControllerName(), "", accountDetails,
	)
	if err != nil {
		return errors.Trace(err)
	}
	args.DialOpts.BakeryClient.WebPageVisitor = httpbakery.NewMultiVisitor(
		authentication.NewVisitor(accountDetails.User, func(string) (string, error) {
			return password, nil
		}),
		args.DialOpts.BakeryClient.WebPageVisitor,
	)
	api, err := c.newAPIConnection(args)
	if err != nil {
		return errors.Annotate(err, "connecting to API")
	}
	return api.Close()
}
func (s *formSuite) TestFormLogin(c *gc.C) {
	d := &formDischarger{}
	d.discharger = bakerytest.NewInteractiveDischarger(nil, http.HandlerFunc(d.visit))
	defer d.discharger.Close()
	d.discharger.Mux.Handle("/form", http.HandlerFunc(d.form))
	svc, err := bakery.NewService(bakery.NewServiceParams{
		Locator: d.discharger,
	})
	c.Assert(err, gc.IsNil)
	for i, test := range formLoginTests {
		c.Logf("test %d: %s", i, test.about)
		d.dischargeOptions = test.opts
		m, err := svc.NewMacaroon("", nil, []checkers.Caveat{{
			Location:  d.discharger.Location(),
			Condition: "test condition",
		}})
		c.Assert(err, gc.Equals, nil)
		client := httpbakery.NewClient()
		filler := defaultFiller
		if test.filler != nil {
			filler = test.filler
		}
		handlers := []httpbakery.Visitor{
			form.Visitor{
				Filler: filler,
			},
		}
		if test.fallback != nil {
			handlers = append(handlers, test.fallback)
		}
		client.WebPageVisitor = httpbakery.NewMultiVisitor(handlers...)

		ms, err := client.DischargeAll(m)
		if test.expectError != "" {
			c.Assert(err, gc.ErrorMatches, test.expectError)
			continue
		}
		c.Assert(err, gc.IsNil)
		c.Assert(len(ms), gc.Equals, 2)
	}
}
Exemple #7
0
Fichier : base.go Projet : bac/juju
func newAPIConnectionParams(
	store jujuclient.ClientStore,
	controllerName,
	modelName string,
	accountDetails *jujuclient.AccountDetails,
	bakery *httpbakery.Client,
	apiOpen api.OpenFunc,
	getPassword func(string) (string, error),
) (juju.NewAPIConnectionParams, error) {
	if controllerName == "" {
		return juju.NewAPIConnectionParams{}, errors.Trace(errNoNameSpecified)
	}
	var modelUUID string
	if modelName != "" {
		modelDetails, err := store.ModelByName(controllerName, modelName)
		if err != nil {
			return juju.NewAPIConnectionParams{}, errors.Trace(err)
		}
		modelUUID = modelDetails.ModelUUID
	}
	dialOpts := api.DefaultDialOpts()
	dialOpts.BakeryClient = bakery

	if accountDetails != nil {
		bakery.WebPageVisitor = httpbakery.NewMultiVisitor(
			authentication.NewVisitor(accountDetails.User, getPassword),
			bakery.WebPageVisitor,
		)
	}

	return juju.NewAPIConnectionParams{
		Store:          store,
		ControllerName: controllerName,
		AccountDetails: accountDetails,
		ModelUUID:      modelUUID,
		DialOpts:       dialOpts,
		OpenAPI:        apiOpen,
	}, nil
}
func (s *formSuite) TestFormTitle(c *gc.C) {
	d := &formDischarger{}
	d.discharger = bakerytest.NewInteractiveDischarger(nil, http.HandlerFunc(d.visit))
	defer d.discharger.Close()
	d.discharger.Mux.Handle("/form", http.HandlerFunc(d.form))
	svc, err := bakery.NewService(bakery.NewServiceParams{
		Locator: testLocator{
			loc:     d.discharger.Location(),
			locator: d.discharger,
		},
	})
	c.Assert(err, gc.IsNil)
	for i, test := range formTitleTests {
		c.Logf("test %d: %s", i, test.host)
		m, err := svc.NewMacaroon("", nil, []checkers.Caveat{{
			Location:  "https://" + test.host,
			Condition: "test condition",
		}})
		c.Assert(err, gc.Equals, nil)
		client := httpbakery.NewClient()
		c.Logf("match %v; replace with %v", test.host, d.discharger.Location())
		client.Client.Transport = httptesting.URLRewritingTransport{
			MatchPrefix:  "https://" + test.host,
			Replace:      d.discharger.Location(),
			RoundTripper: http.DefaultTransport,
		}
		var f titleTestFiller
		client.WebPageVisitor = httpbakery.NewMultiVisitor(
			form.Visitor{
				Filler: &f,
			},
		)

		ms, err := client.DischargeAll(m)
		c.Assert(err, gc.IsNil)
		c.Assert(len(ms), gc.Equals, 2)
		c.Assert(f.title, gc.Equals, test.expect)
	}
}
Exemple #9
0
// NewAPIContext returns an API context that will use the given
// context for user interactions when authorizing.
// The returned API context must be closed after use.
//
// If ctxt is nil, no command-line authorization
// will be supported.
//
// This function is provided for use by commands that cannot use
// JujuCommandBase. Most clients should use that instead.
func NewAPIContext(ctxt *cmd.Context, opts *AuthOpts) (*APIContext, error) {
	jar, err := cookiejar.New(&cookiejar.Options{
		Filename: cookieFile(),
	})
	if err != nil {
		return nil, errors.Trace(err)
	}
	var visitors []httpbakery.Visitor
	if ctxt != nil && opts != nil && opts.NoBrowser {
		filler := &form.IOFiller{
			In:  ctxt.Stdin,
			Out: ctxt.Stdout,
		}
		visitors = append(visitors, ussologin.NewVisitor("juju", filler, jujuclient.NewTokenStore()))
	} else {
		visitors = append(visitors, httpbakery.WebBrowserVisitor)
	}
	webPageVisitor := httpbakery.NewMultiVisitor(visitors...)
	return &APIContext{
		Jar:            jar,
		WebPageVisitor: webPageVisitor,
	}, nil
}
func (*VisitorSuite) TestMultiVisitorNoInteractionMethods(c *gc.C) {
	initialPage := 0
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		initialPage++
		fmt.Fprint(w, `<html>oh yes</html>`)
	}))
	defer srv.Close()
	methods := map[string]*url.URL{
		httpbakery.UserInteractionMethod: mustParseURL(srv.URL),
	}
	visited := 0
	v := httpbakery.NewMultiVisitor(
		visitorFunc(func(_ *httpbakery.Client, m map[string]*url.URL) error {
			c.Check(m, jc.DeepEquals, methods)
			visited++
			return nil
		}),
	)
	err := v.VisitWebPage(httpbakery.NewClient(), methods)
	c.Assert(err, gc.IsNil)
	c.Assert(initialPage, gc.Equals, 1)
	c.Assert(visited, gc.Equals, 1)
}
func (*VisitorSuite) TestMultiVisitorNoUserInteractionMethod(c *gc.C) {
	v := httpbakery.NewMultiVisitor()
	err := v.VisitWebPage(httpbakery.NewClient(), nil)
	c.Assert(err, gc.ErrorMatches, `cannot get interaction methods because no "interactive" URL found`)
}