Exemple #1
0
func (s *suite) TestDischargerTwoLevels(c *gc.C) {
	d1checker := func(_ *http.Request, cond, arg string) ([]checkers.Caveat, error) {
		if cond != "xtrue" {
			return nil, fmt.Errorf("caveat refused")
		}
		return nil, nil
	}
	d1 := bakerytest.NewDischarger(nil, d1checker)
	defer d1.Close()
	d2checker := func(_ *http.Request, cond, arg string) ([]checkers.Caveat, error) {
		return []checkers.Caveat{{
			Location:  d1.Location(),
			Condition: "x" + cond,
		}}, nil
	}
	d2 := bakerytest.NewDischarger(d1, d2checker)
	defer d2.Close()
	locator := bakery.PublicKeyLocatorMap{
		d1.Location(): d1.Service.PublicKey(),
		d2.Location(): d2.Service.PublicKey(),
	}
	c.Logf("map: %s", locator)
	svc, err := bakery.NewService(bakery.NewServiceParams{
		Location: "here",
		Locator:  locator,
	})
	c.Assert(err, gc.IsNil)
	m, err := svc.NewMacaroon("", nil, []checkers.Caveat{{
		Location:  d2.Location(),
		Condition: "true",
	}})
	c.Assert(err, gc.IsNil)

	ms, err := s.client.DischargeAll(m)
	c.Assert(err, gc.IsNil)
	c.Assert(ms, gc.HasLen, 3)

	err = svc.Check(ms, failChecker)
	c.Assert(err, gc.IsNil)

	err = svc.AddCaveat(m, checkers.Caveat{
		Location:  d2.Location(),
		Condition: "nope",
	})
	c.Assert(err, gc.IsNil)

	ms, err = s.client.DischargeAll(m)
	c.Assert(err, gc.ErrorMatches, `cannot get discharge from "https://[^"]*": third party refused discharge: cannot discharge: caveat refused`)
	c.Assert(ms, gc.HasLen, 0)
}
func (s ClientSuite) TestWithLargeBody(c *gc.C) {
	// This test is designed to fail when run with the race
	// checker enabled and when go issue #12796
	// is not fixed.

	d := bakerytest.NewDischarger(nil, noCaveatChecker)
	defer d.Close()

	// Create a target service.
	svc := newService("loc", d)

	ts := httptest.NewServer(serverHandler(serverHandlerParams{
		service:      svc,
		authLocation: d.Location(),
	}))
	defer ts.Close()

	// Create a client request.
	req, err := http.NewRequest("POST", ts.URL+"/no-body", nil)
	c.Assert(err, gc.IsNil)

	body := &largeReader{total: 3 * 1024 * 1024}
	resp, err := httpbakery.NewClient().DoWithBody(req, body)
	c.Assert(err, gc.IsNil)
	resp.Body.Close()
	body.Close()

	c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
}
func (s *ClientSuite) TestThirdPartyDischargeRefused(c *gc.C) {
	d := bakerytest.NewDischarger(nil, func(_ *http.Request, cond, arg string) ([]checkers.Caveat, error) {
		return nil, errgo.New("boo! cond " + cond)
	})
	defer d.Close()

	// Create a target service.
	svc := newService("loc", d)

	ts := httptest.NewServer(serverHandler(serverHandlerParams{
		service:      svc,
		authLocation: d.Location(),
	}))
	defer ts.Close()

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

	client := httpbakery.NewClient()

	// Make the request to the server.
	resp, err := client.Do(req)
	c.Assert(errgo.Cause(err), gc.FitsTypeOf, (*httpbakery.DischargeError)(nil))
	c.Assert(err, gc.ErrorMatches, `cannot get discharge from ".*": third party refused discharge: cannot discharge: boo! cond is-ok`)
	c.Assert(resp, gc.IsNil)
}
Exemple #4
0
func (s *macaroonServerSuite) SetUpTest(c *gc.C) {
	s.discharger = bakerytest.NewDischarger(nil, noCheck)
	s.ConfigAttrs = map[string]interface{}{
		config.IdentityURL: s.discharger.Location(),
	}
	s.JujuConnSuite.SetUpTest(c)
}
Exemple #5
0
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)
	})
}
Exemple #6
0
func (s *suite) TestInsecureSkipVerifyRestoration(c *gc.C) {
	d1 := bakerytest.NewDischarger(nil, noCaveatChecker)
	d2 := bakerytest.NewDischarger(nil, noCaveatChecker)
	d2.Close()
	c.Assert(http.DefaultTransport.(*http.Transport).TLSClientConfig.InsecureSkipVerify, gc.Equals, true)
	d1.Close()
	c.Assert(http.DefaultTransport.(*http.Transport).TLSClientConfig.InsecureSkipVerify, gc.Equals, false)

	// When InsecureSkipVerify is already true, it should not
	// be restored to false.
	http.DefaultTransport.(*http.Transport).TLSClientConfig.InsecureSkipVerify = true
	d3 := bakerytest.NewDischarger(nil, noCaveatChecker)
	d3.Close()

	c.Assert(http.DefaultTransport.(*http.Transport).TLSClientConfig.InsecureSkipVerify, gc.Equals, true)
}
Exemple #7
0
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
	})

	// Set up the charm store testing server.
	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,
	})

	// Initialize the charm cache dir.
	s.PatchValue(&charmrepo.CacheDir, c.MkDir())

	// Point the CLI to the charm store testing server.
	original := newCharmStoreClient
	s.PatchValue(&newCharmStoreClient, func() (*csClient, error) {
		csclient, err := original()
		if err != nil {
			return nil, err
		}
		csclient.params.URL = s.srv.URL
		// 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())
		if err != nil {
			panic(err)
		}
		csclient.params.HTTPClient.Jar.SetCookies(lurl, []*http.Cookie{{
			Name:  clientUserCookie,
			Value: clientUserName,
		}})
		return csclient, nil
	})

	// Point the Juju API server to the charm store testing server.
	s.PatchValue(&csclient.ServerURL, s.srv.URL)
}
Exemple #8
0
func (s *ClientSuite) TestDoWithBodyAndCustomError(c *gc.C) {
	d := bakerytest.NewDischarger(nil, noCaveatChecker)
	defer d.Close()

	// Create a target service.
	svc := newService("loc", d)

	type customError struct {
		CustomError *httpbakery.Error
	}
	callCount := 0
	handler := func(w http.ResponseWriter, req *http.Request) {
		callCount++
		if _, checkErr := httpbakery.CheckRequest(svc, req, nil, checkers.New()); checkErr != nil {
			httprequest.WriteJSON(w, http.StatusTeapot, customError{
				CustomError: newDischargeRequiredError(svc, d.Location(), nil, checkErr, req).(*httpbakery.Error),
			})
			return
		}
		fmt.Fprintf(w, "hello there")
	}
	srv := httptest.NewServer(http.HandlerFunc(handler))
	defer srv.Close()

	req, err := http.NewRequest("GET", srv.URL, nil)
	c.Assert(err, gc.IsNil)

	// First check that a normal request fails.
	resp, err := httpbakery.NewClient().Do(req)
	c.Assert(err, gc.IsNil)
	defer resp.Body.Close()
	c.Assert(resp.StatusCode, gc.Equals, http.StatusTeapot)
	c.Assert(callCount, gc.Equals, 1)
	callCount = 0

	// Then check that a request with a custom error getter succeeds.
	errorGetter := func(resp *http.Response) error {
		if resp.StatusCode != http.StatusTeapot {
			return nil
		}
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			panic(err)
		}
		var respErr customError
		if err := json.Unmarshal(data, &respErr); err != nil {
			panic(err)
		}
		return respErr.CustomError
	}

	resp, err = httpbakery.NewClient().DoWithBodyAndCustomError(req, nil, errorGetter)
	c.Assert(err, gc.IsNil)

	data, err := ioutil.ReadAll(resp.Body)
	c.Assert(err, gc.IsNil)
	c.Assert(string(data), gc.Equals, "hello there")
	c.Assert(callCount, gc.Equals, 2)
}
Exemple #9
0
func (*suite) TestMacaraq(c *gc.C) {
	checked := false
	d := bakerytest.NewDischarger(nil, func(_ *http.Request, cond, arg string) ([]checkers.Caveat, error) {
		if cond != "something" {
			return nil, fmt.Errorf("unexpected 3rd party cond")
		}
		checked = true
		return nil, nil
	})

	bsvc, err := bakery.NewService(bakery.NewServiceParams{
		Location: "here",
		Locator:  d,
	})
	c.Assert(err, gc.IsNil)
	svc := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		req.ParseForm()
		_, checkErr := httpbakery.CheckRequest(bsvc, req, nil, checkers.New())
		if checkErr == nil {
			w.Header().Set("Content-Type", "application/json")
			data, err := json.Marshal(req.Form)
			c.Check(err, gc.IsNil)
			w.Write(data)
			return
		}
		m, err := bsvc.NewMacaroon("", nil, []checkers.Caveat{{
			Location:  d.Service.Location(),
			Condition: "something",
		}})
		c.Check(err, gc.IsNil)
		httpbakery.WriteDischargeRequiredError(w, m, "/", checkErr)
	}))

	fset := flag.NewFlagSet("http", flag.ContinueOnError)
	ctxt, params, err := newContext(fset, []string{
		svc.URL,
		"x=y",
	})
	c.Assert(err, gc.IsNil)
	client := httpbakery.NewClient()
	resp, err := ctxt.doRequest(client, nil)
	c.Assert(err, gc.IsNil)
	defer resp.Body.Close()
	c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
	c.Assert(checked, jc.IsTrue)

	var stdout bytes.Buffer
	err = showResponse(params, resp, &stdout)
	c.Assert(err, gc.IsNil)
	c.Assert(stdout.String(), gc.Equals, `{
	x: [
		"y"
	]
}
`)
}
Exemple #10
0
func (s *macaroonServerWrongPublicKeySuite) SetUpTest(c *gc.C) {
	s.discharger = bakerytest.NewDischarger(nil, noCheck)
	wrongKey, err := bakery.GenerateKey()
	c.Assert(err, gc.IsNil)
	s.ConfigAttrs = map[string]interface{}{
		config.IdentityURL:       s.discharger.Location(),
		config.IdentityPublicKey: wrongKey.Public.String(),
	}
	s.JujuConnSuite.SetUpTest(c)
}
func (s *ClientSuite) TestHandleError(c *gc.C) {
	d := bakerytest.NewDischarger(nil, noCaveatChecker)
	defer d.Close()

	// Create a target service.
	svc := newService("loc", d)

	srv := httptest.NewServer(serverHandler(serverHandlerParams{
		service:      svc,
		authLocation: "unknown",
		mutateError:  nil,
	}))
	defer srv.Close()

	m, err := svc.NewMacaroon("", nil, []checkers.Caveat{{
		Location:  d.Location(),
		Condition: "something",
	}})
	c.Assert(err, gc.IsNil)

	u, err := url.Parse(srv.URL + "/bar")
	c.Assert(err, gc.IsNil)

	respErr := &httpbakery.Error{
		Message: "an error",
		Code:    httpbakery.ErrDischargeRequired,
		Info: &httpbakery.ErrorInfo{
			Macaroon:     m,
			MacaroonPath: "/foo",
		},
	}
	client := httpbakery.NewClient()
	err = client.HandleError(u, respErr)
	c.Assert(err, gc.Equals, nil)
	// No cookies at the original location.
	c.Assert(client.Client.Jar.Cookies(u), gc.HasLen, 0)

	u.Path = "/foo"
	cookies := client.Client.Jar.Cookies(u)
	c.Assert(cookies, gc.HasLen, 1)

	// Check that we can actually make a request
	// with the newly acquired macaroon cookies.

	req, err := http.NewRequest("GET", srv.URL+"/foo", nil)
	c.Assert(err, gc.IsNil)

	resp, err := client.Do(req)
	c.Assert(err, gc.IsNil)
	resp.Body.Close()
	c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
}
Exemple #12
0
func (s *suite) TestConcurrentDischargers(c *gc.C) {
	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func() {
			d := bakerytest.NewDischarger(nil, noCaveatChecker)
			d.Close()
			wg.Done()
		}()
	}
	wg.Wait()
	c.Assert(http.DefaultTransport.(*http.Transport).TLSClientConfig.InsecureSkipVerify, gc.Equals, false)
}
Exemple #13
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)
}
func (s *ClientSuite) TestDischargeWithVisitURLError(c *gc.C) {
	visitor := newVisitHandler(nil)
	visitSrv := httptest.NewServer(visitor)
	defer visitSrv.Close()

	d := bakerytest.NewDischarger(nil, func(_ *http.Request, cond, arg string) ([]checkers.Caveat, error) {
		return nil, &httpbakery.Error{
			Code:    httpbakery.ErrInteractionRequired,
			Message: "interaction required",
			Info: &httpbakery.ErrorInfo{
				VisitURL: visitSrv.URL + "/visit",
				WaitURL:  visitSrv.URL + "/wait",
			},
		}
	})
	defer d.Close()

	// Create a target service.
	svc := newService("loc", d)
	ts := httptest.NewServer(serverHandler(serverHandlerParams{
		service:      svc,
		authLocation: d.Location(),
	}))
	defer ts.Close()

	for i, test := range dischargeWithVisitURLErrorTests {
		c.Logf("test %d: %s", i, test.about)
		visitor.respond = test.respond

		client := httpbakery.NewClient()
		client.VisitWebPage = func(u *url.URL) error {
			resp, err := http.Get(u.String())
			if err != nil {
				return err
			}
			resp.Body.Close()
			return nil
		}

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

		// Make the request to the server.
		_, err = client.Do(req)
		c.Assert(err, gc.ErrorMatches, test.expectError)
	}
}
Exemple #15
0
func (s *macaroonAuthenticatorSuite) TestMacaroonAuthentication(c *gc.C) {
	discharger := bakerytest.NewDischarger(nil, s.Checker)
	defer discharger.Close()
	for i, test := range authenticateSuccessTests {
		c.Logf("\ntest %d; %s", i, test.about)
		s.username = test.dischargedUsername

		svc, err := bakery.NewService(bakery.NewServiceParams{
			Locator: discharger,
		})
		c.Assert(err, jc.ErrorIsNil)
		mac, err := svc.NewMacaroon("", nil, nil)
		c.Assert(err, jc.ErrorIsNil)
		authenticator := &authentication.ExternalMacaroonAuthenticator{
			Service:          svc,
			IdentityLocation: discharger.Location(),
			Macaroon:         mac,
		}

		// Authenticate once to obtain the macaroon to be discharged.
		_, err = authenticator.Authenticate(test.finder, nil, params.LoginRequest{
			Credentials: "",
			Nonce:       "",
			Macaroons:   nil,
		})

		// Discharge the macaroon.
		dischargeErr := errors.Cause(err).(*common.DischargeRequiredError)
		client := httpbakery.NewClient()
		ms, err := client.DischargeAll(dischargeErr.Macaroon)
		c.Assert(err, jc.ErrorIsNil)

		// Authenticate again with the discharged macaroon.
		entity, err := authenticator.Authenticate(test.finder, nil, params.LoginRequest{
			Credentials: "",
			Nonce:       "",
			Macaroons:   []macaroon.Slice{ms},
		})
		if test.expectError != "" {
			c.Assert(err, gc.ErrorMatches, test.expectError)
			c.Assert(entity, gc.Equals, nil)
		} else {
			c.Assert(err, jc.ErrorIsNil)
			c.Assert(entity.Tag().String(), gc.Equals, test.expectTag)
		}
	}
}
Exemple #16
0
func (s *KeyringSuite) TestCacheMiss(c *gc.C) {
	d := bakerytest.NewDischarger(nil, nil)
	defer d.Close()
	kr := httpbakery.NewPublicKeyRing(nil, nil)

	expectPublicKey := d.Service.PublicKey()
	pk, err := kr.PublicKeyForLocation(d.Location())
	c.Assert(err, gc.IsNil)
	c.Assert(*pk, gc.Equals, *expectPublicKey)

	// Close down the service and make sure that
	// the key is cached.
	d.Close()

	pk, err = kr.PublicKeyForLocation(d.Location())
	c.Assert(err, gc.IsNil)
	c.Assert(*pk, gc.Equals, *expectPublicKey)
}
func (s *ClientSuite) TestRepeatedRequestWithBody(c *gc.C) {
	d := bakerytest.NewDischarger(nil, noCaveatChecker)
	defer d.Close()

	// Create a target service.
	svc := newService("loc", d)

	ts := httptest.NewServer(serverHandler(serverHandlerParams{
		service:        svc,
		authLocation:   d.Location(),
		alwaysReadBody: true,
	}))
	defer ts.Close()

	// Create a client request.
	req, err := http.NewRequest("POST", ts.URL, nil)
	c.Assert(err, gc.IsNil)

	// Make the request to the server.

	// First try with a body in the request, which should be denied
	// because we must use DoWithBody.
	req.Body = ioutil.NopCloser(strings.NewReader("postbody"))
	resp, err := httpbakery.NewClient().Do(req)
	c.Assert(err, gc.ErrorMatches, "body unexpectedly provided in request - use DoWithBody")
	c.Assert(resp, gc.IsNil)

	// Then try with no authorization, so make sure that httpbakery.Do
	// really will retry the request.

	req.Body = nil

	bodyText := "postbody"
	bodyReader := &readCounter{ReadSeeker: strings.NewReader(bodyText)}

	resp, err = httpbakery.NewClient().DoWithBody(req, bodyReader)
	c.Assert(err, gc.IsNil)
	defer resp.Body.Close()
	assertResponse(c, resp, "done postbody")

	// Sanity check that the body really was read twice and hence
	// that we are checking the logic we intend to check.
	c.Assert(bodyReader.byteCount, gc.Equals, len(bodyText)*2)
}
Exemple #18
0
func (s *MacaroonSuite) SetUpTest(c *gc.C) {
	s.discharger = bakerytest.NewDischarger(nil, func(req *http.Request, cond, arg string) ([]checkers.Caveat, error) {
		if cond != "is-authenticated-user" {
			return nil, errors.New("unknown caveat")
		}
		var username string
		if s.DischargerLogin != nil {
			username = s.DischargerLogin()
		}
		if username == "" {
			return nil, errors.New("login denied by discharger")
		}
		return []checkers.Caveat{checkers.DeclaredCaveat("username", username)}, nil
	})
	s.JujuConnSuite.ConfigAttrs = map[string]interface{}{
		config.IdentityURL: s.discharger.Location(),
	}
	s.JujuConnSuite.SetUpTest(c)
}
func (s *ClientSuite) TestDischargeWithInteractionRequiredErrorAndWebPageVisitor(c *gc.C) {
	d := bakerytest.NewDischarger(nil, func(_ *http.Request, cond, arg string) ([]checkers.Caveat, error) {
		return nil, &httpbakery.Error{
			Code:    httpbakery.ErrInteractionRequired,
			Message: "interaction required",
			Info: &httpbakery.ErrorInfo{
				VisitURL: "http://0.1.2.3/",
				WaitURL:  "http://0.1.2.3/",
			},
		}
	})
	defer d.Close()

	// Create a target service.
	svc := newService("loc", d)

	ts := httptest.NewServer(serverHandler(serverHandlerParams{
		service:      svc,
		authLocation: d.Location(),
	}))
	defer ts.Close()

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

	errCannotVisit := errgo.New("cannot visit")
	client := httpbakery.NewClient()
	client.WebPageVisitor = visitorFunc(func(_ *httpbakery.Client, m map[string]*url.URL) error {
		return errCannotVisit
	})

	// Make the request to the server.
	resp, err := client.Do(req)
	c.Assert(err, gc.ErrorMatches, `cannot get discharge from "https://.*": cannot start interactive session: cannot visit`)
	c.Assert(httpbakery.IsInteractionError(errgo.Cause(err)), gc.Equals, true)
	ierr, ok := errgo.Cause(err).(*httpbakery.InteractionError)
	c.Assert(ok, gc.Equals, true)
	c.Assert(ierr.Reason, gc.Equals, errCannotVisit)
	c.Assert(resp, gc.IsNil)
}
Exemple #20
0
func (s *suite) TestDischargerSimple(c *gc.C) {
	d := bakerytest.NewDischarger(nil, noCaveatChecker)
	defer d.Close()

	svc, err := bakery.NewService(bakery.NewServiceParams{
		Location: "here",
		Locator:  d,
	})
	c.Assert(err, gc.IsNil)
	m, err := svc.NewMacaroon("", nil, []checkers.Caveat{{
		Location:  d.Location(),
		Condition: "something",
	}})
	c.Assert(err, gc.IsNil)
	ms, err := s.client.DischargeAll(m)
	c.Assert(err, gc.IsNil)
	c.Assert(ms, gc.HasLen, 2)

	err = svc.Check(ms, failChecker)
	c.Assert(err, gc.IsNil)
}
Exemple #21
0
func (s *KeyringSuite) TestInsecureURL(c *gc.C) {
	// Set up a discharger with an non-HTTPS access point.
	d := bakerytest.NewDischarger(nil, nil)
	defer d.Close()
	httpsDischargeURL, err := url.Parse(d.Location())
	c.Assert(err, gc.IsNil)

	srv := httptest.NewServer(httputil.NewSingleHostReverseProxy(httpsDischargeURL))
	defer srv.Close()

	// Check that we are refused because it's an insecure URL.
	kr := httpbakery.NewPublicKeyRing(nil, nil)
	pk, err := kr.PublicKeyForLocation(srv.URL)
	c.Assert(err, gc.ErrorMatches, `untrusted discharge URL "http://.*"`)
	c.Assert(pk, gc.IsNil)

	// Check that it does work when we've enabled AllowInsecure.
	kr.AllowInsecure()
	pk, err = kr.PublicKeyForLocation(srv.URL)
	c.Assert(err, gc.IsNil)
	c.Assert(*pk, gc.Equals, *d.Service.PublicKey())
}
Exemple #22
0
func (s *suite) startServer(c *gc.C, session *mgo.Session) {
	s.discharge = func(cond, arg string) ([]checkers.Caveat, error) {
		return nil, fmt.Errorf("no discharge")
	}

	discharger := bakerytest.NewDischarger(nil, func(_ *http.Request, cond, arg string) ([]checkers.Caveat, error) {
		return s.discharge(cond, arg)
	})

	serverParams := charmstore.ServerParams{
		AuthUsername:     "******",
		AuthPassword:     "******",
		IdentityLocation: discharger.Service.Location(),
		PublicKeyLocator: discharger,
	}

	db := session.DB("charmstore")
	handler, err := charmstore.NewServer(db, nil, "", serverParams, charmstore.V4)
	c.Assert(err, gc.IsNil)
	s.handler = handler
	s.srv = httptest.NewServer(handler)
	s.serverParams = serverParams

}
func (s *ClientSuite) TestMacaroonCookieName(c *gc.C) {
	d := bakerytest.NewDischarger(nil, noCaveatChecker)
	defer d.Close()

	svc := newService("loc", nil)

	// We arrange things so that although we use the same client
	// (with the same cookie jar), the macaroon verification only
	// succeeds once, so the client always fetches a new macaroon.

	caveatSeq := 0
	checked := make(map[string]bool)
	cookieName := ""
	ts := httptest.NewServer(serverHandler(serverHandlerParams{
		service: svc,
		mutateError: func(e *httpbakery.Error) {
			e.Info.CookieNameSuffix = cookieName
			e.Info.MacaroonPath = "/"
		},
		checker: checkers.CheckerFunc{
			Condition_: "once",
			Check_: func(_, arg string) error {
				if checked[arg] {
					return errgo.Newf("caveat %q has already been checked once", arg)
				}
				checked[arg] = true
				return nil
			},
		},
		caveats: func() []checkers.Caveat {
			caveatSeq++
			return []checkers.Caveat{{
				Condition: fmt.Sprintf("once %d", caveatSeq),
			}}
		},
	}))
	defer ts.Close()

	client := httpbakery.NewClient()
	doRequest := func() {
		req, err := http.NewRequest("GET", ts.URL+"/foo/bar/", nil)
		c.Assert(err, gc.IsNil)
		resp, err := client.Do(req)
		c.Assert(err, gc.IsNil)
		defer resp.Body.Close()
		assertResponse(c, resp, "done")
	}
	assertCookieNames := func(names ...string) {
		u, err := url.Parse(ts.URL)
		c.Assert(err, gc.IsNil)
		sort.Strings(names)
		var gotNames []string
		for _, c := range client.Jar.Cookies(u) {
			gotNames = append(gotNames, c.Name)
		}
		sort.Strings(gotNames)
		c.Assert(gotNames, jc.DeepEquals, names)
	}
	cookieName = "foo"
	doRequest()
	assertCookieNames("macaroon-foo")

	// Another request with the same cookie name should
	// overwrite the old cookie.
	doRequest()
	assertCookieNames("macaroon-foo")

	// A subsequent request with a different cookie name
	// should create a new cookie, but the old one will still
	// be around.
	cookieName = "bar"
	doRequest()
	assertCookieNames("macaroon-foo", "macaroon-bar")
}
Exemple #24
0
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)
}
Exemple #25
0
func (s *macaroonAuthenticatorSuite) SetUpTest(c *gc.C) {
	s.discharger = bakerytest.NewDischarger(nil, s.Checker)
}