Beispiel #1
0
func (s *ClientSuite) TestSingleServiceFirstPartyWithHeader(c *gc.C) {
	// Create a target service.
	svc := newService("loc", nil)
	// No discharge required, so pass "unknown" for the third party
	// caveat discharger location so we know that we don't try
	// to discharge the location.
	ts := httptest.NewServer(serverHandler(svc, "unknown", nil))
	defer ts.Close()

	// Mint a macaroon for the target service.
	serverMacaroon, err := svc.NewMacaroon("", nil, nil)
	c.Assert(err, gc.IsNil)
	c.Assert(serverMacaroon.Location(), gc.Equals, "loc")
	err = svc.AddCaveat(serverMacaroon, checkers.Caveat{
		Condition: "is something",
	})
	c.Assert(err, gc.IsNil)

	// Serialize the macaroon slice.
	data, err := json.Marshal(macaroon.Slice{serverMacaroon})
	c.Assert(err, gc.IsNil)
	value := base64.StdEncoding.EncodeToString(data)

	// Create a client request.
	req, err := http.NewRequest("GET", ts.URL, nil)
	c.Assert(err, gc.IsNil)
	req.Header.Set(httpbakery.MacaroonsHeader, value)
	client := httpbakery.NewHTTPClient()

	// Make the request to the server.
	resp, err := client.Do(req)
	c.Assert(err, gc.IsNil)
	defer resp.Body.Close()
	assertResponse(c, resp, "done")
}
Beispiel #2
0
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
}
Beispiel #3
0
func newClient() *httpbakery.Client {
	return &httpbakery.Client{
		Client: httpbakery.NewHTTPClient(),
		VisitWebPage: func(url *url.URL) error {
			fmt.Printf("please visit this web page:\n")
			fmt.Printf("\t%s\n", url)
			return nil
		},
	}
}
Beispiel #4
0
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))
}
Beispiel #5
0
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))
}
Beispiel #6
0
func badResponseClient(resp *http.Response, err error) *csclient.Client {
	client := httpbakery.NewHTTPClient()
	client.Transport = &cannedRoundTripper{
		resp:  resp,
		error: err,
	}
	return csclient.New(csclient.Params{
		URL:        "http://0.1.2.3",
		User:       "******",
		HTTPClient: client,
	})
}
Beispiel #7
0
func (s *suite) TestLogin(c *gc.C) {
	ch := charmRepo.CharmDir("wordpress")
	url := charm.MustParseReference("~charmers/utopic/wordpress-42")
	purl := charm.MustParseReference("utopic/wordpress-42")
	err := s.client.UploadCharmWithRevision(url, ch, 42)
	c.Assert(err, gc.IsNil)

	err = s.client.Put("/"+url.Path()+"/meta/perm/read", []string{"bob"})
	c.Assert(err, gc.IsNil)
	httpClient := httpbakery.NewHTTPClient()
	client := csclient.New(csclient.Params{
		URL:        s.srv.URL,
		HTTPClient: httpClient,
	})

	var result struct{ IdRevision struct{ Revision int } }
	_, err = client.Meta(purl, &result)
	c.Assert(err, gc.NotNil)

	// Try logging in when the discharger fails.
	err = client.Login()
	c.Assert(err, gc.ErrorMatches, `cannot retrieve the authentication macaroon: cannot get discharge from ".*": third party refused discharge: cannot discharge: no discharge`)

	// Allow the discharge.
	s.discharge = func(cond, arg string) ([]checkers.Caveat, error) {
		return []checkers.Caveat{checkers.DeclaredCaveat("username", "bob")}, nil
	}
	err = client.Login()
	c.Assert(err, gc.IsNil)

	// Change discharge so that we're sure the cookies are being
	// used rather than the discharge mechanism.
	s.discharge = func(cond, arg string) ([]checkers.Caveat, error) {
		return nil, fmt.Errorf("no discharge")
	}

	// Check that the request still works.
	_, err = client.Meta(purl, &result)
	c.Assert(err, gc.IsNil)
	c.Assert(result.IdRevision.Revision, gc.Equals, url.Revision)

	// Check that we've got one cookie.
	srvURL, err := neturl.Parse(s.srv.URL)
	c.Assert(err, gc.IsNil)
	c.Assert(httpClient.Jar.Cookies(srvURL), gc.HasLen, 1)

	// Log in again.
	err = client.Login()
	c.Assert(err, gc.IsNil)

	// Check that we still only have one cookie.
	c.Assert(httpClient.Jar.Cookies(srvURL), gc.HasLen, 1)
}
Beispiel #8
0
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)
}
Beispiel #9
0
func newHTTPClient() (*cookiejar.Jar, *http.Client, error) {
	cookieFile := path.Join(utils.Home(), ".go-cookies")
	jar, err := cookiejar.New(&cookiejar.Options{
		PublicSuffixList: publicsuffix.List,
	})
	if err != nil {
		panic(err)
	}
	if err := jar.Load(cookieFile); err != nil {
		return nil, nil, err
	}
	client := httpbakery.NewHTTPClient()
	client.Jar = jar
	return jar, client, nil
}
Beispiel #10
0
// New returns a new charm store client.
func New(p Params) *Client {
	if p.URL == "" {
		p.URL = ServerURL
	}
	if p.HTTPClient == nil {
		p.HTTPClient = httpbakery.NewHTTPClient()
	}
	return &Client{
		params: p,
		bclient: &httpbakery.Client{
			Client:       p.HTTPClient,
			VisitWebPage: p.VisitWebPage,
		},
	}
}
Beispiel #11
0
func (s *suite) TestWhoAmI(c *gc.C) {
	httpClient := httpbakery.NewHTTPClient()
	client := csclient.New(csclient.Params{
		URL:        s.srv.URL,
		HTTPClient: httpClient,
	})
	response, err := client.WhoAmI()
	c.Assert(err, gc.ErrorMatches, `cannot retrieve whoami response: cannot get discharge from ".*": third party refused discharge: cannot discharge: no discharge`)
	s.discharge = func(cond, arg string) ([]checkers.Caveat, error) {
		return []checkers.Caveat{checkers.DeclaredCaveat("username", "bob")}, nil
	}

	response, err = client.WhoAmI()
	c.Assert(err, gc.IsNil)
	c.Assert(response.User, gc.Equals, "bob")
}
Beispiel #12
0
func newCachingClient(
	cache MacaroonCache,
	server *url.URL,
	makeWrapper func(*httpbakery.Client, *url.URL) csWrapper,
) (Client, error) {
	bakeryClient := &httpbakery.Client{
		Client: httpbakery.NewHTTPClient(),
	}
	client := makeWrapper(bakeryClient, server)
	server, err := url.Parse(client.ServerURL())
	if err != nil {
		return Client{}, errors.Trace(err)
	}
	jar, err := newMacaroonJar(cache, server)
	if err != nil {
		return Client{}, errors.Trace(err)
	}
	bakeryClient.Jar = jar
	return Client{client, jar}, nil
}
Beispiel #13
0
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
}
Beispiel #14
0
// 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,
	)
}
Beispiel #15
0
// could also be a web browser.
// (TODO: write javascript discharge gatherer)
package main

import (
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"

	"gopkg.in/macaroon-bakery.v1/bakery"
	"gopkg.in/macaroon-bakery.v1/httpbakery"
)

var defaultHTTPClient = httpbakery.NewHTTPClient()

func main() {
	key, err := bakery.GenerateKey()
	if err != nil {
		log.Fatalf("cannot generate auth service key pair: %v", err)
	}
	authPublicKey := &key.Public
	authEndpoint := mustServe(func(endpoint string) (http.Handler, error) {
		return authService(endpoint, key)
	})
	serverEndpoint := mustServe(func(endpoint string) (http.Handler, error) {
		return targetService(endpoint, authEndpoint, authPublicKey)
	})
	resp, err := clientRequest(newClient(), serverEndpoint)
	if err != nil {
Beispiel #16
0
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`)
}