// targetService implements a "target service", representing // an arbitrary web service that wants to delegate authorization // to third parties. func targetService(endpoint, authEndpoint string, authPK *bakery.PublicKey) (http.Handler, error) { key, err := bakery.GenerateKey() if err != nil { return nil, err } pkLocator := bakery.NewPublicKeyRing() svc, err := bakery.NewService(bakery.NewServiceParams{ Key: key, Location: endpoint, Locator: pkLocator, }) if err != nil { return nil, err } log.Printf("adding public key for location %s: %v", authEndpoint, authPK) pkLocator.AddPublicKeyForLocation(authEndpoint, true, authPK) mux := http.NewServeMux() srv := &targetServiceHandler{ svc: svc, authEndpoint: authEndpoint, } mux.HandleFunc("/gold/", srv.serveGold) mux.HandleFunc("/silver/", srv.serveSilver) return mux, nil }
func (s *suite) SetUpSuite(c *gc.C) { key, err := bakery.GenerateKey() c.Assert(err, gc.IsNil) s.authPublicKey = &key.Public s.authEndpoint = serve(c, func(endpoint string) (http.Handler, error) { return idservice.New(idservice.Params{ Users: map[string]*idservice.UserInfo{ "rog": { Password: "******", }, "root": { Password: "******", Groups: map[string]bool{ "target-service-users": true, }, }, }, Service: bakery.NewServiceParams{ Location: endpoint, Store: bakery.NewMemStorage(), Key: key, Locator: bakery.NewPublicKeyRing(), }, }) }) c.Logf("auth endpoint at %s", s.authEndpoint) }
func (s *KeyringSuite) TestCachePrepopulated(c *gc.C) { cache := bakery.NewPublicKeyRing() key, err := bakery.GenerateKey() c.Assert(err, gc.IsNil) cache.AddPublicKeyForLocation("https://0.1.2.3/", true, &key.Public) kr := httpbakery.NewPublicKeyRing(nil, cache) pk, err := kr.PublicKeyForLocation("https://0.1.2.3/") c.Assert(err, gc.IsNil) c.Assert(*pk, gc.Equals, key.Public) }
// NewPublicKeyRing returns a new public keyring that uses // the given client to find public keys and uses the // given cache as a backing. If cache is nil, a new // cache will be created. If client is nil, http.DefaultClient will // be used. func NewPublicKeyRing(client *http.Client, cache *bakery.PublicKeyRing) *PublicKeyRing { if cache == nil { cache = bakery.NewPublicKeyRing() } if client == nil { client = http.DefaultClient } return &PublicKeyRing{ client: client, cache: cache, } }
// authService implements an authorization service, // that can discharge third-party caveats added // to other macaroons. func authService(endpoint string, key *bakery.KeyPair) (http.Handler, error) { svc, err := bakery.NewService(bakery.NewServiceParams{ Location: endpoint, Key: key, Locator: bakery.NewPublicKeyRing(), }) if err != nil { return nil, err } mux := http.NewServeMux() httpbakery.AddDischargeHandler(mux, "/", svc, thirdPartyChecker) return mux, nil }
func (s *ClientSuite) TestDischargeServerWithMacaraqOnDischarge(c *gc.C) { locator := bakery.NewPublicKeyRing() var called [3]int // create the services from leaf discharger to primary // service so that each one can know the location // to discharge at. key2, h2 := newHTTPDischarger(locator, func(svc *bakery.Service, req *http.Request, cavId, cav string) ([]checkers.Caveat, error) { called[2]++ if cav != "is-ok" { return nil, fmt.Errorf("unrecognized caveat at srv2") } return nil, nil }) srv2 := httptest.NewServer(h2) locator.AddPublicKeyForLocation(srv2.URL, true, key2) key1, h1 := newHTTPDischarger(locator, func(svc *bakery.Service, req *http.Request, cavId, cav string) ([]checkers.Caveat, error) { called[1]++ if _, err := httpbakery.CheckRequest(svc, req, nil, checkers.New()); err != nil { return nil, newDischargeRequiredError(serverHandlerParams{ service: svc, authLocation: srv2.URL, }, err, req) } if cav != "is-ok" { return nil, fmt.Errorf("unrecognized caveat at srv1") } return nil, nil }) srv1 := httptest.NewServer(h1) locator.AddPublicKeyForLocation(srv1.URL, true, key1) svc0 := newService("loc", locator) srv0 := httptest.NewServer(serverHandler(serverHandlerParams{ service: svc0, authLocation: srv1.URL, })) // Make a client request. client := httpbakery.NewClient() req, err := http.NewRequest("GET", srv0.URL, nil) c.Assert(err, gc.IsNil) resp, err := client.Do(req) c.Assert(err, gc.IsNil) defer resp.Body.Close() assertResponse(c, resp, "done") c.Assert(called, gc.DeepEquals, [3]int{0, 2, 1}) }
func (*KeysSuite) TestPublicKeyRing(c *gc.C) { for i, test := range publicKeyRingTests { c.Logf("test %d: %s", i, test.about) kr := bakery.NewPublicKeyRing() for _, add := range test.add { err := kr.AddPublicKeyForLocation(add.loc, add.prefix, &bakery.PublicKey{add.key}) c.Assert(err, gc.IsNil) } key, err := kr.PublicKeyForLocation(test.loc) if test.expectNotFound { c.Assert(err, gc.Equals, bakery.ErrNotFound) c.Assert(key, gc.IsNil) continue } c.Assert(err, gc.IsNil) c.Assert(*key, gc.Equals, bakery.PublicKey{test.expectKey}) } }
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) }