func (s *KeyringSuite) TestPublicKey(c *gc.C) { d := bakerytest.NewDischarger(nil, noCaveatChecker) defer d.Close() client := httpbakery.NewHTTPClient() publicKey, err := httpbakery.PublicKeyForLocation(client, d.Location()) c.Assert(err, gc.IsNil) expectedKey := d.Service.PublicKey() c.Assert(publicKey, gc.DeepEquals, expectedKey) // Check that it works with client==nil. publicKey, err = httpbakery.PublicKeyForLocation(nil, d.Location()) c.Assert(err, gc.IsNil) c.Assert(publicKey, gc.DeepEquals, expectedKey) }
// newExternalMacaroonAuth returns an authenticator that can authenticate // macaroon-based logins for external users. This is just a helper function // for authCtxt.macaroonAuth. func newExternalMacaroonAuth(st *state.State) (*authentication.ExternalMacaroonAuthenticator, error) { envCfg, err := st.ModelConfig() if err != nil { return nil, errors.Annotate(err, "cannot get model config") } idURL := envCfg.IdentityURL() if idURL == "" { return nil, errMacaroonAuthNotConfigured } // The identity server has been configured, // so configure the bakery service appropriately. idPK := envCfg.IdentityPublicKey() if idPK == nil { // No public key supplied - retrieve it from the identity manager. idPK, err = httpbakery.PublicKeyForLocation(http.DefaultClient, idURL) if err != nil { return nil, errors.Annotate(err, "cannot get identity public key") } } svc, err := newBakeryService(st, bakery.PublicKeyLocatorMap{ idURL: idPK, }) if err != nil { return nil, errors.Annotate(err, "cannot make bakery service") } var auth authentication.ExternalMacaroonAuthenticator auth.Service = svc auth.Macaroon, err = svc.NewMacaroon("api-login", nil, nil) if err != nil { return nil, errors.Annotate(err, "cannot make macaroon") } auth.IdentityLocation = idURL return &auth, nil }
func (s *KeyringSuite) TestPublicKeyReturnsStatusInternalServerError(c *gc.C) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) })) defer ts.Close() client := httpbakery.NewHTTPClient() _, err := httpbakery.PublicKeyForLocation(client, ts.URL) c.Assert(err, gc.ErrorMatches, fmt.Sprintf(`cannot get public key from "%s/publickey": got status 500 Internal Server Error`, ts.URL)) }
func (s *KeyringSuite) TestPublicKeyReturnsInvalidJSON(c *gc.C) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "BADJSON") })) defer ts.Close() client := httpbakery.NewHTTPClient() _, err := httpbakery.PublicKeyForLocation(client, ts.URL) c.Assert(err, gc.ErrorMatches, fmt.Sprintf(`failed to decode response from "%s/publickey": invalid character 'B' looking for beginning of value`, ts.URL)) }
// newExternalMacaroonAuth returns an authenticator that can authenticate // macaroon-based logins for external users. This is just a helper function // for authCtxt.macaroonAuth. func newExternalMacaroonAuth(st *state.State) (*authentication.ExternalMacaroonAuthenticator, error) { envCfg, err := st.ModelConfig() if err != nil { return nil, errors.Annotate(err, "cannot get model config") } idURL := envCfg.IdentityURL() if idURL == "" { return nil, errMacaroonAuthNotConfigured } // The identity server has been configured, // so configure the bakery service appropriately. idPK := envCfg.IdentityPublicKey() if idPK == nil { // No public key supplied - retrieve it from the identity manager. idPK, err = httpbakery.PublicKeyForLocation(http.DefaultClient, idURL) if err != nil { return nil, errors.Annotate(err, "cannot get identity public key") } } // We pass in nil for the storage, which leads to in-memory storage // being used. We only use in-memory storage for now, since we never // expire the keys, and don't want garbage to accumulate. // // TODO(axw) we should store the key in mongo, so that multiple servers // can authenticate. That will require that we encode the server's ID // in the macaroon ID so that servers don't overwrite each others' keys. svc, _, err := newBakeryService(st, nil, bakery.PublicKeyLocatorMap{idURL: idPK}) if err != nil { return nil, errors.Annotate(err, "cannot make bakery service") } var auth authentication.ExternalMacaroonAuthenticator auth.Service = svc auth.Macaroon, err = svc.NewMacaroon("api-login", nil, nil) if err != nil { return nil, errors.Annotate(err, "cannot make macaroon") } auth.IdentityLocation = idURL return &auth, 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) }
func (s *KeyringSuite) TestPublicKeyWrongURL(c *gc.C) { client := httpbakery.NewHTTPClient() _, err := httpbakery.PublicKeyForLocation(client, "http://localhost:0") c.Assert(err, gc.ErrorMatches, `cannot get public key from "http://localhost:0/publickey": Get http://localhost:0/publickey: dial tcp 127.0.0.1:0: .*connection refused`) }