func (s *clientMacaroonSuite) SetUpTest(c *gc.C) {
	s.MacaroonSuite.SetUpTest(c)
	s.AddModelUser(c, "testuser@somewhere")
	s.cookieJar = apitesting.NewClearableCookieJar()
	s.DischargerLogin = func() string { return "testuser@somewhere" }
	s.client = s.OpenAPI(c, nil, s.cookieJar).Client()

	// Even though we've logged into the API, we want
	// the tests below to exercise the discharging logic
	// so we clear the cookies.
	s.cookieJar.Clear()
}
Exemple #2
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 #3
0
func (s *macaroonLoginSuite) login(c *gc.C, info *api.Info) (params.LoginResult, error) {
	info.SkipLogin = true

	cookieJar := apitesting.NewClearableCookieJar()

	client := s.OpenAPI(c, info, cookieJar)
	defer client.Close()

	var (
		// Remote users start with an empty login request.
		request params.LoginRequest
		result  params.LoginResult
	)
	err := client.APICall("Admin", 3, "", "Login", &request, &result)
	c.Assert(err, jc.ErrorIsNil)

	cookieURL := &url.URL{
		Scheme: "https",
		Host:   "localhost",
		Path:   "/",
	}

	bakeryClient := httpbakery.NewClient()

	err = bakeryClient.HandleError(cookieURL, &httpbakery.Error{
		Message: result.DischargeRequiredReason,
		Code:    httpbakery.ErrDischargeRequired,
		Info: &httpbakery.ErrorInfo{
			Macaroon:     result.DischargeRequired,
			MacaroonPath: "/",
		},
	})
	c.Assert(err, jc.ErrorIsNil)
	// Add the macaroons that have been saved by HandleError to our login request.
	request.Macaroons = httpbakery.MacaroonsForURL(bakeryClient.Client.Jar, cookieURL)

	err = client.APICall("Admin", 3, "", "Login", &request, &result)
	return result, err
}
Exemple #4
0
func (s *macaroonLoginSuite) TestConnectStreamFailedDischarge(c *gc.C) {
	// This is really a test for ConnectStream, but to test ConnectStream's
	// discharge failing logic, we need an actual endpoint to test against,
	// and the debug-log endpoint makes a convenient example.

	var dischargeError bool
	s.DischargerLogin = func() string {
		if dischargeError {
			return ""
		}
		return testUserName
	}

	// Make an API connection that uses a cookie jar
	// that allows us to remove all cookies.
	jar := apitesting.NewClearableCookieJar()
	client := s.OpenAPI(c, nil, jar)

	// Ensure that the discharger won't discharge and try
	// logging in again. We should succeed in getting past
	// authorization because we have the cookies (but
	// the actual debug-log endpoint will return an error).
	dischargeError = true
	logArgs := url.Values{"noTail": []string{"true"}}
	conn, err := client.ConnectStream("/log", logArgs)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(conn, gc.NotNil)
	conn.Close()

	// Then delete all the cookies by deleting the cookie jar
	// and try again. The login should fail.
	jar.Clear()

	conn, err = client.ConnectStream("/log", logArgs)
	c.Assert(err, gc.ErrorMatches, `cannot get discharge from "https://.*": third party refused discharge: cannot discharge: login denied by discharger`)
	c.Assert(conn, gc.IsNil)
}