Beispiel #1
0
Datei: user.go Projekt: bac/juju
func (m *ExternalMacaroonAuthenticator) newDischargeRequiredError(cause error) error {
	if m.Service == nil || m.Macaroon == nil {
		return errors.Trace(cause)
	}
	mac := m.Macaroon.Clone()
	// TODO(fwereade): 2016-03-17 lp:1558657
	expiryTime := time.Now().Add(externalLoginExpiryTime)
	if err := addMacaroonTimeBeforeCaveat(m.Service, mac, expiryTime); err != nil {
		return errors.Annotatef(err, "cannot create macaroon")
	}
	err := m.Service.AddCaveat(mac, checkers.NeedDeclaredCaveat(
		checkers.Caveat{
			Location:  m.IdentityLocation,
			Condition: "is-authenticated-user",
		},
		usernameKey,
	))
	if err != nil {
		return errors.Annotatef(err, "cannot create macaroon")
	}
	return &common.DischargeRequiredError{
		Cause:    cause,
		Macaroon: mac,
	}
}
Beispiel #2
0
func (s *userAuthenticatorSuite) TestAuthenticateLocalLoginMacaroon(c *gc.C) {
	service := mockBakeryService{}
	clock := testing.NewClock(time.Time{})
	authenticator := &authentication.UserAuthenticator{
		Service: &service,
		Clock:   clock,
		LocalUserIdentityLocation: "https://testing.invalid:1234/auth",
	}

	service.SetErrors(&bakery.VerificationError{})
	_, err := authenticator.Authenticate(
		authentication.EntityFinder(nil),
		names.NewUserTag("bobbrown"),
		params.LoginRequest{},
	)
	c.Assert(err, gc.FitsTypeOf, &common.DischargeRequiredError{})

	service.CheckCallNames(c, "CheckAny", "ExpireStorageAt", "NewMacaroon")
	calls := service.Calls()
	c.Assert(calls[1].Args, jc.DeepEquals, []interface{}{clock.Now().Add(24 * time.Hour)})
	c.Assert(calls[2].Args, jc.DeepEquals, []interface{}{
		"", []byte(nil), []checkers.Caveat{
			checkers.NeedDeclaredCaveat(
				checkers.Caveat{
					Location:  "https://testing.invalid:1234/auth",
					Condition: "is-authenticated-user bobbrown@local",
				},
				"username",
			),
			{Condition: "time-before 0001-01-02T00:00:00Z"},
		},
	})
}
Beispiel #3
0
Datei: user.go Projekt: bac/juju
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
}
Beispiel #4
0
func (m *MacaroonAuthenticator) newDischargeRequiredError(cause error) error {
	if m.Service == nil || m.Macaroon == nil {
		return errors.Trace(cause)
	}
	mac := m.Macaroon.Clone()
	err := m.Service.AddCaveat(mac, checkers.TimeBeforeCaveat(time.Now().Add(time.Hour)))
	if err != nil {
		return errors.Annotatef(err, "cannot create macaroon")
	}
	err = m.Service.AddCaveat(mac, checkers.NeedDeclaredCaveat(
		checkers.Caveat{
			Location:  m.IdentityLocation,
			Condition: "is-authenticated-user",
		},
		usernameKey,
	))
	if err != nil {
		return errors.Annotatef(err, "cannot create macaroon")
	}
	return &common.DischargeRequiredError{
		Cause:    cause,
		Macaroon: mac,
	}
}
Beispiel #5
0
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"`)
}
Beispiel #6
0
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"`)
}