Ejemplo n.º 1
0
func (s *macaroonStore) MacaroonIdInfo(ctxt context.Context, id []byte) (rootKey []byte, ops []auth.Op, err error) {
	var mid macaroonId
	if err := json.Unmarshal(id, &mid); err != nil {
		return nil, nil, errgo.Notef(err, "bad macaroon id")
	}
	rootKey, err = s.store.Get(mid.Id)
	if err != nil {
		return nil, nil, errgo.Notef(err, "cannot find root key")
	}
	return rootKey, mid.Ops, nil
}
Ejemplo n.º 2
0
func (s *macaroonStore) NewMacaroon(ops []auth.Op, caveats []checkers.Caveat) (*macaroon.Macaroon, error) {
	rootKey, id, err := s.store.RootKey()
	if err != nil {
		return nil, errgo.Mask(err)
	}

	mid := macaroonId{
		Id:  id,
		Ops: ops,
	}
	data, _ := json.Marshal(mid)
	m, err := macaroon.New(rootKey, data, "", macaroon.LatestVersion)
	if err != nil {
		return nil, errgo.Mask(err)
	}
	for _, cav := range caveats {
		if err := bakery.AddCaveat(s.key, s.locator, m, cav); err != nil {
			return nil, errgo.Notef(err, "cannot add caveat")
		}
	}
	return m, nil
}
Ejemplo n.º 3
0
// allowAny is the internal version of AllowAny. Instead of returning an
// authInfo struct, it returns a slice describing which operations have
// been successfully authorized and a slice describing which macaroons
// have been used in the authorization.
func (a *Authorizer) allowAny(ctxt context.Context, ops []Op) (authed, used []bool, err error) {
	if err := a.init(ctxt); err != nil {
		return nil, nil, errgo.Mask(err)
	}
	logger.Infof("after authorizer init, identity %#v", a.identity)
	used = make([]bool, len(a.macaroons))
	authed = make([]bool, len(ops))
	numAuthed := 0
	for i, op := range ops {
		if op == LoginOp && len(ops) > 1 {
			// LoginOp cannot be combined with other operations in the
			// same macaroon, so ignore it if it is.
			continue
		}
		for _, mindex := range a.authIndexes[op] {
			_, err := a.checkConditions(ctxt, op, a.conditions[mindex])
			if err != nil {
				logger.Infof("caveat check failed: %v", err)
				// log error?
				continue
			}
			authed[i] = true
			numAuthed++
			used[mindex] = true
			break
		}
	}
	if a.identity != nil {
		// We've authenticated as a user, so even if the operations didn't
		// specifically require it, we add the authn macaroon and its
		// conditions to the macaroons used and its con
		indexes := a.authIndexes[LoginOp]
		if len(indexes) == 0 {
			// Should never happen because init ensures it's there.
			panic("no macaroon info found for login op")
		}
		// Note: because we never issue a macaroon which combines LoginOp
		// with other operations, if the login op macaroon is used, we
		// know that it's already checked out successfully with LoginOp,
		// so no need to check again.
		used[indexes[0]] = true
	}
	if numAuthed == len(ops) {
		// All operations allowed.
		return nil, used, nil
	}
	// There are some unauthorized operations.
	need := make([]Op, 0, len(ops)-numAuthed)
	needIndex := make([]int, cap(need))
	for i, ok := range authed {
		if !ok {
			needIndex[len(need)] = i
			need = append(need, ops[i])
		}
	}
	logger.Infof("operations needed after authz macaroons: %#v", need)
	// Try to authorize the operations even even if we haven't got an authenticated user.
	oks, caveats, err := a.service.p.UserChecker.Allow(ctxt, a.identity, need)
	if err != nil {
		return authed, used, errgo.Notef(err, "cannot check permissions")
	}
	if len(oks) != len(need) {
		return authed, used, errgo.Newf("unexpected slice length returned from Allow (got %d; want %d)", len(oks), len(need))
	}

	stillNeed := make([]Op, 0, len(need))
	for i, ok := range oks {
		if ok {
			authed[needIndex[i]] = true
		} else {
			stillNeed = append(stillNeed, ops[needIndex[i]])
		}
	}
	if len(stillNeed) == 0 && len(caveats) == 0 {
		// No more ops need to be authenticated and no caveats to be discharged.
		return authed, used, nil
	}
	logger.Infof("operations still needed after auth check: %#v", stillNeed)
	if a.identity == nil {
		// User hasn't authenticated - ask them to do so.
		return authed, used, &DischargeRequiredError{
			Message: "authentication required",
			Ops:     []Op{LoginOp},
			Caveats: a.service.p.IdentityClient.IdentityCaveats(),
		}
	}
	if len(caveats) == 0 {
		return authed, used, ErrPermissionDenied
	}
	return authed, used, &DischargeRequiredError{
		Message: "some operations have extra caveats",
		Ops:     ops,
		Caveats: caveats,
	}
}