func (s *charmStoreSuite) SetUpTest(c *gc.C) { s.JujuConnSuite.SetUpTest(c) // Set up the charm store testing server. db := s.Session.DB("juju-testing") params := charmstore.ServerParams{ AuthUsername: "******", AuthPassword: "******", } handler, err := charmstore.NewServer(db, nil, "", params, charmstore.V5) c.Assert(err, jc.ErrorIsNil) s.handler = handler s.srv = httptest.NewServer(handler) s.client = csclient.New(csclient.Params{ URL: s.srv.URL, User: params.AuthUsername, Password: params.AuthPassword, }) application.PatchNewCharmStoreClient(s, s.srv.URL) // Initialize the charm cache dir. s.PatchValue(&charmrepo.CacheDir, c.MkDir()) // Point the CLI to the charm store testing server. // Point the Juju API server to the charm store testing server. s.PatchValue(&csclient.ServerURL, s.srv.URL) }
func (s *CharmStoreSuite) SetUpTest(c *gc.C) { s.CleanupSuite.SetUpTest(c) s.discharger = bakerytest.NewDischarger(nil, func(_ *http.Request, cond string, arg string) ([]checkers.Caveat, error) { if s.DischargeUser == "" { return nil, fmt.Errorf("discharge denied") } return []checkers.Caveat{ checkers.DeclaredCaveat("username", s.DischargeUser), }, nil }) db := s.Session.DB("juju-testing") params := charmstore.ServerParams{ AuthUsername: "******", AuthPassword: "******", IdentityLocation: s.discharger.Location(), PublicKeyLocator: s.discharger, } handler, err := charmstore.NewServer(db, nil, "", params, charmstore.V4) c.Assert(err, jc.ErrorIsNil) s.handler = handler s.Srv = httptest.NewServer(handler) s.Client = csclient.New(csclient.Params{ URL: s.Srv.URL, User: params.AuthUsername, Password: params.AuthPassword, }) s.PatchValue(&charmrepo.CacheDir, c.MkDir()) s.PatchValue(&service.NewCharmStore, func(p charmrepo.NewCharmStoreParams) charmrepo.Interface { p.URL = s.Srv.URL return charmrepo.NewCharmStore(p) }) }
// authorize acquires and return the charm store delegatable macaroon to be // used to add the charm corresponding to the given URL. // The macaroon is properly attenuated so that it can only be used to deploy // the given charm URL. func (c *csClient) authorize(curl *charm.URL) (*macaroon.Macaroon, error) { if curl == nil { return nil, errors.New("empty charm url not allowed") } client := csclient.New(csclient.Params{ URL: c.params.URL, HTTPClient: c.params.HTTPClient, VisitWebPage: c.params.VisitWebPage, }) endpoint := "/delegatable-macaroon" endpoint += "?id=" + url.QueryEscape(curl.String()) var m *macaroon.Macaroon if err := client.Get(endpoint, &m); err != nil { return nil, errors.Trace(err) } // We need to add the is-entity first party caveat to the // delegatable macaroon in case we're talking to the old // version of the charmstore. // TODO (ashipika) - remove this once the new charmstore // is deployed. if err := m.AddFirstPartyCaveat("is-entity " + curl.String()); err != nil { return nil, errors.Trace(err) } return m, nil }
func (s *CharmSuite) SetUpTest(c *gc.C) { db := s.jcSuite.Session.DB("juju-testing") params := charmstore.ServerParams{ AuthUsername: "******", AuthPassword: "******", } handler, err := charmstore.NewServer(db, nil, "", params, charmstore.V4) c.Assert(err, jc.ErrorIsNil) s.Handler = handler s.Server = httptest.NewServer(handler) s.Client = csclient.New(csclient.Params{ URL: s.Server.URL, User: params.AuthUsername, Password: params.AuthPassword, }) urls := map[string]string{ "mysql": "quantal/mysql-23", "dummy": "quantal/dummy-24", "riak": "quantal/riak-25", "wordpress": "quantal/wordpress-26", "logging": "quantal/logging-27", } for name, url := range urls { testcharms.UploadCharm(c, s.Client, url, name) } s.jcSuite.PatchValue(&charmrepo.CacheDir, c.MkDir()) // Patch the charm repo initializer function: it is replaced with a charm // store repo pointing to the testing server. s.jcSuite.PatchValue(&charmrevisionupdater.NewCharmStore, func(p charmrepo.NewCharmStoreParams) *charmrepo.CharmStore { p.URL = s.Server.URL return charmrepo.NewCharmStore(p) }) s.charms = make(map[string]*state.Charm) }
// ResolveCharm resolves the best available charm URLs with series, for charm // locations without a series specified. func ResolveCharms(st *state.State, args params.ResolveCharms) (params.ResolveCharmResults, error) { var results params.ResolveCharmResults envConfig, err := st.ModelConfig() if err != nil { return params.ResolveCharmResults{}, err } repo := config.SpecializeCharmRepo( NewCharmStoreRepo(csclient.New(csclient.Params{})), envConfig) for _, ref := range args.References { result := params.ResolveCharmResult{} curl, err := charm.ParseURL(ref) if err != nil { result.Error = err.Error() } else { curl, err := resolveCharm(curl, repo) if err != nil { result.Error = err.Error() } else { result.URL = curl.String() } } results.URLs = append(results.URLs, result) } return results, nil }
func PatchNewCharmStoreClient(s Patcher, url string) { s.PatchValue(&newCharmStoreClient, func(bakeryClient *httpbakery.Client) *csclient.Client { return csclient.New(csclient.Params{ URL: url, BakeryClient: bakeryClient, }) }) }
func makeWrapper(bakeryClient *httpbakery.Client, server *url.URL) csWrapper { p := csclient.Params{ BakeryClient: bakeryClient, } if server != nil { p.URL = server.String() } return csclientImpl{csclient.New(p)} }
// NewClient returns a Juju charm store client for the given client // config. func NewClient(config ClientConfig) Client { var url string if config.URL != nil { url = config.URL.String() } cs := csclient.New(csclient.Params{ URL: url, BakeryClient: config.BakeryClient, }) return Client{lowLevel: csclientImpl{cs}} }
// Connect implements CharmstoreSpec. func (cs charmstoreSpec) Connect() (CharmstoreClient, error) { params, apiContext, err := cs.connect() if err != nil { return nil, errors.Trace(err) } baseClient := csclient.New(csclient.Params{ URL: params.URL, HTTPClient: params.HTTPClient, VisitWebPage: params.VisitWebPage, }) csClient := &charmstoreClient{ Client: baseClient, apiContext: apiContext, } return csClient, nil }
func (s *UpgradeCharmErrorsSuite) SetUpTest(c *gc.C) { s.RepoSuite.SetUpTest(c) // Set up the charm store testing server. handler, err := charmstore.NewServer(s.Session.DB("juju-testing"), nil, "", charmstore.ServerParams{ AuthUsername: "******", AuthPassword: "******", }, charmstore.V5) c.Assert(err, jc.ErrorIsNil) s.handler = handler s.srv = httptest.NewServer(handler) s.PatchValue(&charmrepo.CacheDir, c.MkDir()) s.PatchValue(&newCharmStoreClient, func(bakeryClient *httpbakery.Client) *csclient.Client { return csclient.New(csclient.Params{ URL: s.srv.URL, BakeryClient: bakeryClient, }) }) }
// authorize acquires and return the charm store delegatable macaroon to be // used to add the charm corresponding to the given URL. // The macaroon is properly attenuated so that it can only be used to deploy // the given charm URL. func (c *csClient) authorize(curl *charm.URL) (*macaroon.Macaroon, error) { if curl == nil { return nil, errors.New("empty charm url not allowed") } client := csclient.New(csclient.Params{ URL: c.params.URL, HTTPClient: c.params.HTTPClient, VisitWebPage: c.params.VisitWebPage, }) endpoint := "/delegatable-macaroon" endpoint += "?id=" + url.QueryEscape(curl.String()) var m *macaroon.Macaroon if err := client.Get(endpoint, &m); err != nil { return nil, errors.Trace(err) } return m, nil }
func (s *serviceSuite) TestAddCharmWithAuthorization(c *gc.C) { // Upload a new charm to the charm store. curl, _ := s.UploadCharm(c, "cs:~restricted/precise/wordpress-3", "wordpress") // Change permissions on the new charm such that only bob // can read from it. s.DischargeUser = "******" err := s.Client.Put("/"+curl.Path()+"/meta/perm/read", []string{"bob"}) c.Assert(err, jc.ErrorIsNil) // Try to add a charm to the environment without authorization. s.DischargeUser = "" err = s.APIState.Client().AddCharm(curl) c.Assert(err, gc.ErrorMatches, `cannot retrieve charm "cs:~restricted/precise/wordpress-3": cannot get archive: cannot get discharge from "https://.*": third party refused discharge: cannot discharge: discharge denied`) tryAs := func(user string) error { client := csclient.New(csclient.Params{ URL: s.Srv.URL, }) s.DischargeUser = user var m *macaroon.Macaroon err = client.Get("/delegatable-macaroon", &m) c.Assert(err, gc.IsNil) return service.AddCharmWithAuthorization(s.State, params.AddCharmWithAuthorization{URL: curl.String()}) } // Try again with authorization for the wrong user. err = tryAs("joe") c.Assert(err, gc.ErrorMatches, `cannot retrieve charm "cs:~restricted/precise/wordpress-3": cannot get archive: unauthorized: access denied for user "joe"`) // Try again with the correct authorization this time. err = tryAs("bob") c.Assert(err, gc.IsNil) // Verify that it has actually been uploaded. _, err = s.State.Charm(curl) c.Assert(err, gc.IsNil) }
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 }
func (s *charmStoreSuite) SetUpTest(c *gc.C) { s.JujuConnSuite.SetUpTest(c) // Set up the third party discharger. s.discharger = bakerytest.NewDischarger(nil, func(req *http.Request, cond string, arg string) ([]checkers.Caveat, error) { cookie, err := req.Cookie(clientUserCookie) if err != nil { return nil, errors.Annotate(err, "discharge denied to non-clients") } return []checkers.Caveat{ checkers.DeclaredCaveat("username", cookie.Value), }, nil }) s.termsDischargerError = nil // Set up the third party terms discharger. s.termsDischarger = bakerytest.NewDischarger(nil, func(req *http.Request, cond string, arg string) ([]checkers.Caveat, error) { s.termsString = arg return nil, s.termsDischargerError }) s.termsString = "" keyring := bakery.NewPublicKeyRing() pk, err := httpbakery.PublicKeyForLocation(http.DefaultClient, s.discharger.Location()) c.Assert(err, gc.IsNil) err = keyring.AddPublicKeyForLocation(s.discharger.Location(), true, pk) c.Assert(err, gc.IsNil) pk, err = httpbakery.PublicKeyForLocation(http.DefaultClient, s.termsDischarger.Location()) c.Assert(err, gc.IsNil) err = keyring.AddPublicKeyForLocation(s.termsDischarger.Location(), true, pk) c.Assert(err, gc.IsNil) // Set up the charm store testing server. db := s.Session.DB("juju-testing") params := charmstore.ServerParams{ AuthUsername: "******", AuthPassword: "******", IdentityLocation: s.discharger.Location(), PublicKeyLocator: keyring, TermsLocation: s.termsDischarger.Location(), } handler, err := charmstore.NewServer(db, nil, "", params, charmstore.V5) c.Assert(err, jc.ErrorIsNil) s.handler = handler s.srv = httptest.NewServer(handler) c.Logf("started charmstore on %v", s.srv.URL) s.client = csclient.New(csclient.Params{ URL: s.srv.URL, User: params.AuthUsername, Password: params.AuthPassword, }) // Initialize the charm cache dir. s.PatchValue(&charmrepo.CacheDir, c.MkDir()) // Point the CLI to the charm store testing server. s.PatchValue(&newCharmStoreClient, func(client *httpbakery.Client) *csclient.Client { // Add a cookie so that the discharger can detect whether the // HTTP client is the juju environment or the juju client. lurl, err := url.Parse(s.discharger.Location()) c.Assert(err, jc.ErrorIsNil) client.Jar.SetCookies(lurl, []*http.Cookie{{ Name: clientUserCookie, Value: clientUserName, }}) return csclient.New(csclient.Params{ URL: s.srv.URL, BakeryClient: client, }) }) // Point the Juju API server to the charm store testing server. s.PatchValue(&csclient.ServerURL, s.srv.URL) }
if err != nil { return nil, nil, maybeTermsAgreementError(err) } if err := client.AddCharmWithAuthorization(curl, channel, m); err != nil { return nil, nil, errors.Trace(err) } csMac = m } return curl, csMac, nil } // newCharmStoreClient is called to obtain a charm store client. // It is defined as a variable so it can be changed for testing purposes. var newCharmStoreClient = func(client *httpbakery.Client) *csclient.Client { return csclient.New(csclient.Params{ BakeryClient: client, }) } // TODO(natefinch): change the code in this file to use the // github.com/juju/juju/charmstore package to interact with the charmstore. // authorizeCharmStoreEntity acquires and return the charm store delegatable macaroon to be // used to add the charm corresponding to the given URL. // The macaroon is properly attenuated so that it can only be used to deploy // the given charm URL. func authorizeCharmStoreEntity(csClient *csclient.Client, curl *charm.URL) (*macaroon.Macaroon, error) { endpoint := "/delegatable-macaroon?id=" + url.QueryEscape(curl.String()) var m *macaroon.Macaroon if err := csClient.Get(endpoint, &m); err != nil { return nil, errors.Trace(err)