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() }
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) }
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 }
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) }