func (s *macaroonServerSuite) TestServerBakery(c *gc.C) { srv := newServer(c, s.State) defer srv.Stop() m, err := apiserver.ServerMacaroon(srv) c.Assert(err, gc.IsNil) bsvc, err := apiserver.ServerBakeryService(srv) c.Assert(err, gc.IsNil) // Check that we can add a third party caveat addressed to the // discharger, which indirectly ensures that the discharger's public // key has been added to the bakery service's locator. m = m.Clone() err = bsvc.AddCaveat(m, checkers.Caveat{ Location: s.discharger.Location(), Condition: "true", }) c.Assert(err, jc.ErrorIsNil) // Check that we can discharge the macaroon and check it with // the service. client := httpbakery.NewClient() ms, err := client.DischargeAll(m) c.Assert(err, jc.ErrorIsNil) err = bsvc.Check(ms, checkers.New()) c.Assert(err, gc.IsNil) }
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) }
func newCheckers(info requestInfo) checkers.Checker { return checkers.New( checkers.TimeBefore, httpbakery.Checkers(info.request), operationChecker(info.operation), requestObjectChecker(info.request, info.params), ) }
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" ] } `) }
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 (s *ClientSuite) TestMacaroonsForURL(c *gc.C) { // Create a target service. svc := newService("loc", nil) m1, err := svc.NewMacaroon("id1", []byte("key1"), nil) c.Assert(err, gc.IsNil) m2, err := svc.NewMacaroon("id2", []byte("key2"), nil) c.Assert(err, gc.IsNil) u1 := mustParseURL("http://0.1.2.3/") u2 := mustParseURL("http://0.1.2.3/x/") // Create some cookies with different cookie paths. jar, err := cookiejar.New(nil) c.Assert(err, gc.IsNil) httpbakery.SetCookie(jar, u1, macaroon.Slice{m1}) httpbakery.SetCookie(jar, u2, macaroon.Slice{m2}) jar.SetCookies(u1, []*http.Cookie{{ Name: "foo", Path: "/", Value: "ignored", }, { Name: "bar", Path: "/x/", Value: "ignored", }}) // Check that MacaroonsForURL behaves correctly // with both single and multiple cookies. mss := httpbakery.MacaroonsForURL(jar, u1) c.Assert(mss, gc.HasLen, 1) c.Assert(mss[0], gc.HasLen, 1) c.Assert(mss[0][0].Id(), gc.Equals, "id1") mss = httpbakery.MacaroonsForURL(jar, u2) checked := make(map[string]int) for _, ms := range mss { checked[ms[0].Id()]++ err := svc.Check(ms, checkers.New()) c.Assert(err, gc.IsNil) } c.Assert(checked, jc.DeepEquals, map[string]int{ "id1": 1, "id2": 1, }) }
func (u *UserAuthenticator) authenticateMacaroons( entityFinder EntityFinder, tag names.UserTag, req params.LoginRequest, ) (state.Entity, error) { // Check for a valid request macaroon. assert := map[string]string{usernameKey: tag.Id()} _, err := u.Service.CheckAny(req.Macaroons, assert, checkers.New(checkers.TimeBefore)) if err != nil { cause := err logger.Debugf("local-login macaroon authentication failed: %v", cause) if _, ok := errors.Cause(err).(*bakery.VerificationError); !ok { return nil, errors.Trace(err) } // The root keys for these macaroons are stored in MongoDB. // Expire the documents after after a set amount of time. expiryTime := u.Clock.Now().Add(localLoginExpiryTime) service, err := u.Service.ExpireStorageAt(expiryTime) if err != nil { return nil, errors.Trace(err) } m, err := service.NewMacaroon("", nil, []checkers.Caveat{ checkers.NeedDeclaredCaveat( checkers.Caveat{ Location: u.LocalUserIdentityLocation, Condition: "is-authenticated-user " + tag.Id(), }, usernameKey, ), checkers.TimeBeforeCaveat(expiryTime), }) if err != nil { return nil, errors.Annotate(err, "cannot create macaroon") } return nil, &common.DischargeRequiredError{ Cause: cause, Macaroon: m, } } entity, err := entityFinder.FindEntity(tag) if errors.IsNotFound(err) { logger.Debugf("entity %s not found", tag.String()) return nil, errors.Trace(common.ErrBadCreds) } else if err != nil { return nil, errors.Trace(err) } return entity, nil }
func (u *UserAuthenticator) authenticateMacaroons( entityFinder EntityFinder, tag names.UserTag, req params.LoginRequest, ) (state.Entity, error) { // Check for a valid request macaroon. assert := map[string]string{usernameKey: tag.Canonical()} _, err := u.Service.CheckAny(req.Macaroons, assert, checkers.New(checkers.TimeBefore)) if err != nil { return nil, errors.Trace(err) } entity, err := entityFinder.FindEntity(tag) if errors.IsNotFound(err) { return nil, errors.Trace(common.ErrBadCreds) } else if err != nil { return nil, errors.Trace(err) } return entity, nil }
func (s *Service) checkRequest(info requestInfo) (*authInfo, error) { var ms macaroon.Slice err := json.NewDecoder(info.request.Body).Decode(&ms) if err != nil { return nil, errgo.Mask(err, errgo.Any) } declared := checkers.InferDeclared(ms) // TODO: assert any declared caveats here err = s.bakery.Check(ms, checkers.New(declared, newCheckers(info))) if err != nil { return nil, errgo.Mask(err, errgo.Any) } return &authInfo{ object: info.params.ByName("object"), declared: declared, }, nil }
// CheckRequest checks that the given http request contains at least one // valid macaroon minted by the given service, using checker to check // any first party caveats. It returns an error with a // *bakery.VerificationError cause if the macaroon verification failed. // // The assert map holds any required attributes of "declared" attributes, // overriding any inferences made from the macaroons themselves. // It has a similar effect to adding a checkers.DeclaredCaveat // for each key and value, but the error message will be more // useful. // // It adds all the standard caveat checkers to the given checker. // // It returns any attributes declared in the successfully validated request. func CheckRequest(svc *bakery.Service, req *http.Request, assert map[string]string, checker checkers.Checker) (map[string]string, error) { mss := RequestMacaroons(req) if len(mss) == 0 { return nil, &bakery.VerificationError{ Reason: errgo.Newf("no macaroon cookies in request"), } } checker = checkers.New( checker, Checkers(req), checkers.TimeBefore, ) attrs, err := svc.CheckAny(mss, assert, checker) if err != nil { return nil, errgo.Mask(err, isVerificationError) } return attrs, nil }
func (*DischargeSuite) TestDischargeAllLocalDischarge(c *gc.C) { svc, err := bakery.NewService(bakery.NewServiceParams{}) c.Assert(err, gc.IsNil) clientKey, err := bakery.GenerateKey() c.Assert(err, gc.IsNil) m, err := svc.NewMacaroon("", nil, []checkers.Caveat{ bakery.LocalThirdPartyCaveat(&clientKey.Public), }) c.Assert(err, gc.IsNil) ms, err := bakery.DischargeAllWithKey(m, noDischarge(c), clientKey) c.Assert(err, gc.IsNil) err = svc.Check(ms, checkers.New()) c.Assert(err, gc.IsNil) }
func (s *CheckersSuite) TestCheckers(c *gc.C) { for i, test := range checkerTests { c.Logf("test %d: %s", i, test.about) for j, check := range test.checks { c.Logf("\tcheck %d", j) err := checkers.New(test.checker).CheckFirstPartyCaveat(check.caveat) if check.expectError != "" { c.Assert(err, gc.ErrorMatches, check.expectError) if check.expectCause == nil { check.expectCause = errgo.Any } c.Assert(check.expectCause(errgo.Cause(err)), gc.Equals, true) } else { c.Assert(err, gc.IsNil) } } } }
func (s *ServiceSuite) TestNewMacaroonWithRootKeyStorageInParams(c *gc.C) { store := bakery.NewMemRootKeyStorage() _, id, err := store.RootKey() c.Assert(err, gc.IsNil) // Check that we can create a bakery with the root key store // in its parameters too. svc, err := bakery.NewService(bakery.NewServiceParams{ Location: "elsewhere", RootKeyStore: store, }) c.Assert(err, gc.IsNil) m, err := svc.NewMacaroon("", nil, nil) c.Assert(err, gc.IsNil) c.Assert(m.Id(), gc.Matches, id+"-[0-9a-f]{32}") err = svc.Check(macaroon.Slice{m}, checkers.New()) c.Assert(err, gc.IsNil) }
func (s *ServiceSuite) TestDischargeMacaroonCannotBeUsedAsNormalMacaroon(c *gc.C) { locator := make(bakery.PublicKeyLocatorMap) firstParty := newService(c, "first", locator) thirdParty := newService(c, "third", locator) // First party mints a macaroon with a 3rd party caveat. m, err := firstParty.NewMacaroon("", nil, []checkers.Caveat{{ Location: "third", Condition: "true", }}) c.Assert(err, gc.IsNil) // Acquire the discharge macaroon, but don't bind it to the original. d, err := thirdParty.Discharge(bakery.ThirdPartyCheckerFunc(func(_, caveat string) ([]checkers.Caveat, error) { return nil, nil }), m.Caveats()[0].Id) c.Assert(err, gc.IsNil) // Make sure it cannot be used as a normal macaroon in the third party. err = thirdParty.Check(macaroon.Slice{d}, checkers.New()) c.Assert(err, gc.ErrorMatches, `verification failed: macaroon not found in storage`) }
// CheckAny checks that the given slice of slices contains at least // one macaroon minted by the given service, using checker to check // any first party caveats. It returns an error with a // *bakery.VerificationError cause if the macaroon verification failed. // // The assert map holds any required attributes of "declared" attributes, // overriding any inferences made from the macaroons themselves. // It has a similar effect to adding a checkers.DeclaredCaveat // for each key and value, but the error message will be more // useful. // // It adds all the standard caveat checkers to the given checker. // // It returns any attributes declared in the successfully validated request. func (svc *Service) CheckAny(mss []macaroon.Slice, assert map[string]string, checker checkers.Checker) (map[string]string, error) { if len(mss) == 0 { return nil, &VerificationError{ Reason: errgo.Newf("no macaroons"), } } // TODO perhaps return a slice of attribute maps, one // for each successfully validated macaroon slice? var err error for _, ms := range mss { declared := checkers.InferDeclared(ms) for key, val := range assert { declared[key] = val } err = svc.Check(ms, checkers.New(declared, checker)) if err == nil { return declared, nil } } // Return an arbitrary error from the macaroons provided. // TODO return all errors. return nil, errgo.Mask(err, isVerificationError) }
// Authenticate authenticates the provided entity. If there is no macaroon provided, it will // return a *DischargeRequiredError containing a macaroon that can be used to grant access. func (m *ExternalMacaroonAuthenticator) Authenticate(entityFinder EntityFinder, _ names.Tag, req params.LoginRequest) (state.Entity, error) { declared, err := m.Service.CheckAny(req.Macaroons, nil, checkers.New(checkers.TimeBefore)) if _, ok := errors.Cause(err).(*bakery.VerificationError); ok { return nil, m.newDischargeRequiredError(err) } if err != nil { return nil, errors.Trace(err) } username := declared[usernameKey] var tag names.UserTag if names.IsValidUserName(username) { // The name is a local name without an explicit @local suffix. // In this case, for compatibility with 3rd parties that don't // care to add their own domain, we add an @external domain // to ensure there is no confusion between local and external // users. // TODO(rog) remove this logic when deployed dischargers // always add an @ domain. tag = names.NewLocalUserTag(username).WithDomain("external") } else { // We have a name with an explicit domain (or an invalid user name). if !names.IsValidUser(username) { return nil, errors.Errorf("%q is an invalid user name", username) } tag = names.NewUserTag(username) if tag.IsLocal() { return nil, errors.Errorf("external identity provider has provided ostensibly local name %q", username) } } entity, err := entityFinder.FindEntity(tag) if errors.IsNotFound(err) { return nil, errors.Trace(common.ErrBadCreds) } else if err != nil { return nil, errors.Trace(err) } return entity, nil }
func (*ServiceSuite) TestCheckAnyWithNoMacaroons(c *gc.C) { svc := newService(c, "somewhere", nil) newMacaroons := func(caveats ...checkers.Caveat) macaroon.Slice { m, err := svc.NewMacaroon("", nil, caveats) c.Assert(err, gc.IsNil) return macaroon.Slice{m} } tests := []struct { about string macaroons []macaroon.Slice assert map[string]string checker checkers.Checker expectDeclared map[string]string expectError string }{{ about: "no macaroons", expectError: "verification failed: no macaroons", }, { about: "one macaroon, no caveats", macaroons: []macaroon.Slice{ newMacaroons(), }, }, { about: "one macaroon, one unrecognized caveat", macaroons: []macaroon.Slice{ newMacaroons(checkers.Caveat{ Condition: "bad", }), }, expectError: `verification failed: caveat "bad" not satisfied: caveat not recognized`, }, { about: "two macaroons, only one ok", macaroons: []macaroon.Slice{ newMacaroons(checkers.Caveat{ Condition: "bad", }), newMacaroons(), }, }, { about: "macaroon with declared caveats", macaroons: []macaroon.Slice{ newMacaroons( checkers.DeclaredCaveat("key1", "value1"), checkers.DeclaredCaveat("key2", "value2"), ), }, expectDeclared: map[string]string{ "key1": "value1", "key2": "value2", }, }, { about: "macaroon with declared values and asserted keys with wrong value", macaroons: []macaroon.Slice{ newMacaroons( checkers.DeclaredCaveat("key1", "value1"), checkers.DeclaredCaveat("key2", "value2"), ), }, assert: map[string]string{ "key1": "valuex", }, expectError: `verification failed: caveat "declared key1 value1" not satisfied: got key1="valuex", expected "value1"`, }, { about: "macaroon with declared values and asserted keys with correct value", macaroons: []macaroon.Slice{ newMacaroons( checkers.DeclaredCaveat("key1", "value1"), checkers.DeclaredCaveat("key2", "value2"), ), }, assert: map[string]string{ "key1": "value1", }, expectDeclared: map[string]string{ "key1": "value1", "key2": "value2", }, }} for i, test := range tests { c.Logf("test %d: %s", i, test.about) if test.expectDeclared == nil { test.expectDeclared = make(map[string]string) } if test.checker == nil { test.checker = checkers.New() } decl, err := svc.CheckAny(test.macaroons, test.assert, test.checker) if test.expectError != "" { c.Assert(err, gc.ErrorMatches, test.expectError) c.Assert(decl, gc.HasLen, 0) continue } c.Assert(err, gc.IsNil) c.Assert(decl, jc.DeepEquals, test.expectDeclared) } }
func (s *ServiceSuite) TestDischargeTwoNeedDeclared(c *gc.C) { locator := make(bakery.PublicKeyLocatorMap) firstParty := newService(c, "first", locator) thirdParty := newService(c, "third", locator) // firstParty mints a macaroon with two third party caveats // with overlapping attributes. m, err := firstParty.NewMacaroon("", nil, []checkers.Caveat{ checkers.NeedDeclaredCaveat(checkers.Caveat{ Location: "third", Condition: "x", }, "foo", "bar"), checkers.NeedDeclaredCaveat(checkers.Caveat{ Location: "third", Condition: "y", }, "bar", "baz"), }) c.Assert(err, gc.IsNil) // The client asks for a discharge macaroon for each third party caveat. // Since no declarations are added by the discharger, d, err := bakery.DischargeAll(m, func(_ string, cav macaroon.Caveat) (*macaroon.Macaroon, error) { return thirdParty.Discharge(bakery.ThirdPartyCheckerFunc(func(_, caveat string) ([]checkers.Caveat, error) { return nil, nil }), cav.Id) }) c.Assert(err, gc.IsNil) declared := checkers.InferDeclared(d) c.Assert(declared, gc.DeepEquals, checkers.Declared{ "foo": "", "bar": "", "baz": "", }) err = firstParty.Check(d, checkers.New(declared)) c.Assert(err, gc.IsNil) // If they return conflicting values, the discharge fails. // The client asks for a discharge macaroon for each third party caveat. // Since no declarations are added by the discharger, d, err = bakery.DischargeAll(m, func(_ string, cav macaroon.Caveat) (*macaroon.Macaroon, error) { return thirdParty.Discharge(bakery.ThirdPartyCheckerFunc(func(_, caveat string) ([]checkers.Caveat, error) { switch caveat { case "x": return []checkers.Caveat{ checkers.DeclaredCaveat("foo", "fooval1"), }, nil case "y": return []checkers.Caveat{ checkers.DeclaredCaveat("foo", "fooval2"), checkers.DeclaredCaveat("baz", "bazval"), }, nil } return nil, fmt.Errorf("not matched") }), cav.Id) }) c.Assert(err, gc.IsNil) declared = checkers.InferDeclared(d) c.Assert(declared, gc.DeepEquals, checkers.Declared{ "bar": "", "baz": "bazval", }) err = firstParty.Check(d, checkers.New(declared)) c.Assert(err, gc.ErrorMatches, `verification failed: caveat "declared foo fooval1" not satisfied: got foo=null, expected "fooval1"`) }
func (s *ServiceSuite) TestNeedDeclared(c *gc.C) { locator := make(bakery.PublicKeyLocatorMap) firstParty := newService(c, "first", locator) thirdParty := newService(c, "third", locator) // firstParty mints a macaroon with a third-party caveat addressed // to thirdParty with a need-declared caveat. m, err := firstParty.NewMacaroon("", nil, []checkers.Caveat{ checkers.NeedDeclaredCaveat(checkers.Caveat{ Location: "third", Condition: "something", }, "foo", "bar"), }) c.Assert(err, gc.IsNil) // The client asks for a discharge macaroon for each third party caveat. d, err := bakery.DischargeAll(m, func(_ string, cav macaroon.Caveat) (*macaroon.Macaroon, error) { return thirdParty.Discharge(strcmpChecker("something"), cav.Id) }) c.Assert(err, gc.IsNil) // The required declared attributes should have been added // to the discharge macaroons. declared := checkers.InferDeclared(d) c.Assert(declared, gc.DeepEquals, checkers.Declared{ "foo": "", "bar": "", }) // Make sure the macaroons actually check out correctly // when provided with the declared checker. err = firstParty.Check(d, checkers.New(declared)) c.Assert(err, gc.IsNil) // Try again when the third party does add a required declaration. // The client asks for a discharge macaroon for each third party caveat. d, err = bakery.DischargeAll(m, func(_ string, cav macaroon.Caveat) (*macaroon.Macaroon, error) { checker := thirdPartyCheckerWithCaveats{ checkers.DeclaredCaveat("foo", "a"), checkers.DeclaredCaveat("arble", "b"), } return thirdParty.Discharge(checker, cav.Id) }) c.Assert(err, gc.IsNil) // One attribute should have been added, the other was already there. declared = checkers.InferDeclared(d) c.Assert(declared, gc.DeepEquals, checkers.Declared{ "foo": "a", "bar": "", "arble": "b", }) err = firstParty.Check(d, checkers.New(declared)) c.Assert(err, gc.IsNil) // Try again, but this time pretend a client is sneakily trying // to add another "declared" attribute to alter the declarations. d, err = bakery.DischargeAll(m, func(_ string, cav macaroon.Caveat) (*macaroon.Macaroon, error) { checker := thirdPartyCheckerWithCaveats{ checkers.DeclaredCaveat("foo", "a"), checkers.DeclaredCaveat("arble", "b"), } m, err := thirdParty.Discharge(checker, cav.Id) c.Assert(err, gc.IsNil) // Sneaky client adds a first party caveat. m.AddFirstPartyCaveat(checkers.DeclaredCaveat("foo", "c").Condition) return m, nil }) c.Assert(err, gc.IsNil) declared = checkers.InferDeclared(d) c.Assert(declared, gc.DeepEquals, checkers.Declared{ "bar": "", "arble": "b", }) err = firstParty.Check(d, checkers.New(declared)) c.Assert(err, gc.ErrorMatches, `verification failed: caveat "declared foo a" not satisfied: got foo=null, expected "a"`) }
type checkTest struct { caveat string expectError string expectCause func(err error) bool } var isCaveatNotRecognized = errgo.Is(checkers.ErrCaveatNotRecognized) var checkerTests = []struct { about string checker checkers.Checker checks []checkTest }{{ about: "no host name declared", checker: checkers.New(httpbakery.Checkers(&http.Request{})), checks: []checkTest{{ caveat: checkers.ClientIPAddrCaveat(net.IP{0, 0, 0, 0}).Condition, expectError: `caveat "client-ip-addr 0.0.0.0" not satisfied: client has no remote address`, }, { caveat: checkers.ClientIPAddrCaveat(net.IP{127, 0, 0, 1}).Condition, expectError: `caveat "client-ip-addr 127.0.0.1" not satisfied: client has no remote address`, }, { caveat: "client-ip-addr badip", expectError: `caveat "client-ip-addr badip" not satisfied: cannot parse IP address in caveat`, }}, }, { about: "IPv4 host name declared", checker: checkers.New(httpbakery.Checkers(&http.Request{ RemoteAddr: "127.0.0.1:1234", })),
type checkTest struct { caveat string expectError string expectCause func(err error) bool } var isCaveatNotRecognized = errgo.Is(checkers.ErrCaveatNotRecognized) var checkerTests = []struct { about string checker bakery.FirstPartyChecker checks []checkTest }{{ about: "empty MultiChecker", checker: checkers.New(), checks: []checkTest{{ caveat: "something", expectError: `caveat "something" not satisfied: caveat not recognized`, expectCause: isCaveatNotRecognized, }, { caveat: "", expectError: `cannot parse caveat "": empty caveat`, expectCause: isCaveatNotRecognized, }, { caveat: " hello", expectError: `cannot parse caveat " hello": caveat starts with space character`, expectCause: isCaveatNotRecognized, }}, }, { about: "MultiChecker with some values",