func (s *ClientSuite) TestMacaroonsForURL(c *gc.C) { // Create a target service. svc := newService("loc", nil) m1, err := svc.NewMacaroon("id1", []byte("key1"), nil) c.Assert(err, gc.IsNil) m2, err := svc.NewMacaroon("id2", []byte("key2"), nil) c.Assert(err, gc.IsNil) u1 := mustParseURL("http://0.1.2.3/") u2 := mustParseURL("http://0.1.2.3/x/") // Create some cookies with different cookie paths. jar, err := cookiejar.New(nil) c.Assert(err, gc.IsNil) httpbakery.SetCookie(jar, u1, macaroon.Slice{m1}) httpbakery.SetCookie(jar, u2, macaroon.Slice{m2}) jar.SetCookies(u1, []*http.Cookie{{ Name: "foo", Path: "/", Value: "ignored", }, { Name: "bar", Path: "/x/", Value: "ignored", }}) // Check that MacaroonsForURL behaves correctly // with both single and multiple cookies. mss := httpbakery.MacaroonsForURL(jar, u1) c.Assert(mss, gc.HasLen, 1) c.Assert(mss[0], gc.HasLen, 1) c.Assert(mss[0][0].Id(), gc.Equals, "id1") mss = httpbakery.MacaroonsForURL(jar, u2) checked := make(map[string]int) for _, ms := range mss { checked[ms[0].Id()]++ err := svc.Check(ms, checkers.New()) c.Assert(err, gc.IsNil) } c.Assert(checked, jc.DeepEquals, map[string]int{ "id1": 1, "id2": 1, }) }
func clientRequestWithCookies(c *gc.C, u string, macaroons macaroon.Slice) *http.Client { client := httpbakery.NewHTTPClient() url, err := url.Parse(u) c.Assert(err, gc.IsNil) err = httpbakery.SetCookie(client.Jar, url, macaroons) c.Assert(err, gc.IsNil) return client }
func (MacaroonJarSuite) TestActivate(c *gc.C) { cache := fakeCache{} u, err := url.Parse("http://charmstore.com") c.Assert(err, jc.ErrorIsNil) jar, err := newMacaroonJar(cache, u) c.Assert(err, jc.ErrorIsNil) ch := charm.MustParseURL("cs:mysql") err = jar.Activate(ch) c.Assert(err, jc.ErrorIsNil) m, err := macaroon.New([]byte("key"), "id", "loc") c.Assert(err, jc.ErrorIsNil) ms := macaroon.Slice{m} httpbakery.SetCookie(jar, u, ms) c.Assert(cache[ch], gc.DeepEquals, ms) }
func openCSClient(args params.AddCharmWithAuthorization) (*csclient.Client, error) { csURL, err := url.Parse(csclient.ServerURL) if err != nil { return nil, err } csParams := csclient.Params{ URL: csURL.String(), HTTPClient: httpbakery.NewHTTPClient(), } if args.CharmStoreMacaroon != nil { // Set the provided charmstore authorizing macaroon // as a cookie in the HTTP client. // TODO(cmars) discharge any third party caveats in the macaroon. ms := []*macaroon.Macaroon{args.CharmStoreMacaroon} httpbakery.SetCookie(csParams.HTTPClient.Jar, csURL, ms) } csClient := csclient.New(csParams) channel := csparams.Channel(args.Channel) if channel != csparams.NoChannel { csClient = csClient.WithChannel(channel) } return csClient, nil }
// AddCharmWithAuthorization adds the given charm URL (which must include revision) to // the environment, if it does not exist yet. Local charms are not // supported, only charm store URLs. See also AddLocalCharm(). // // The authorization macaroon, args.CharmStoreMacaroon, may be // omitted, in which case this call is equivalent to AddCharm. func AddCharmWithAuthorization(st *state.State, args params.AddCharmWithAuthorization) error { charmURL, err := charm.ParseURL(args.URL) if err != nil { return err } if charmURL.Schema != "cs" { return fmt.Errorf("only charm store charm URLs are supported, with cs: schema") } if charmURL.Revision < 0 { return fmt.Errorf("charm URL must include revision") } // First, check if a pending or a real charm exists in state. stateCharm, err := st.PrepareStoreCharmUpload(charmURL) if err != nil { return err } if stateCharm.IsUploaded() { // Charm already in state (it was uploaded already). return nil } // Get the charm and its information from the store. envConfig, err := st.EnvironConfig() if err != nil { return err } csURL, err := url.Parse(csclient.ServerURL) if err != nil { return err } csParams := charmrepo.NewCharmStoreParams{ URL: csURL.String(), HTTPClient: httpbakery.NewHTTPClient(), } if args.CharmStoreMacaroon != nil { // Set the provided charmstore authorizing macaroon // as a cookie in the HTTP client. // TODO discharge any third party caveats in the macaroon. ms := []*macaroon.Macaroon{args.CharmStoreMacaroon} httpbakery.SetCookie(csParams.HTTPClient.Jar, csURL, ms) } repo := config.SpecializeCharmRepo( NewCharmStore(csParams), envConfig, ) downloadedCharm, err := repo.Get(charmURL) if err != nil { cause := errors.Cause(err) if httpbakery.IsDischargeError(cause) || httpbakery.IsInteractionError(cause) { return errors.NewUnauthorized(err, "") } return errors.Trace(err) } // Open it and calculate the SHA256 hash. downloadedBundle, ok := downloadedCharm.(*charm.CharmArchive) if !ok { return errors.Errorf("expected a charm archive, got %T", downloadedCharm) } archive, err := os.Open(downloadedBundle.Path) if err != nil { return errors.Annotate(err, "cannot read downloaded charm") } defer archive.Close() bundleSHA256, size, err := utils.ReadSHA256(archive) if err != nil { return errors.Annotate(err, "cannot calculate SHA256 hash of charm") } if _, err := archive.Seek(0, 0); err != nil { return errors.Annotate(err, "cannot rewind charm archive") } // Store the charm archive in environment storage. return StoreCharmArchive( st, charmURL, downloadedCharm, archive, size, bundleSHA256, ) }