Exemplo n.º 1
0
// checkers implements the caveat checking for the service.
// Note how we add context-sensitive checkers
// (remote-host checks information from the HTTP request)
// to the standard checkers implemented by checkers.Std.
func (svc *targetServiceHandler) checkers(req *http.Request, operation string) bakery.FirstPartyChecker {
	m := checkers.Map{
		"remote-host": func(s string) error {
			// TODO(rog) do we want to distinguish between
			// the two kinds of errors below?
			_, host, err := checkers.ParseCaveat(s)
			if err != nil {
				return err
			}
			remoteHost, _, err := net.SplitHostPort(req.RemoteAddr)
			if err != nil {
				return fmt.Errorf("cannot parse request remote address")
			}
			if remoteHost != host {
				return fmt.Errorf("remote address mismatch (need %q, got %q)", host, remoteHost)
			}
			return nil
		},
		"operation": func(s string) error {
			_, op, err := checkers.ParseCaveat(s)
			if err != nil {
				return err
			}
			if op != operation {
				return fmt.Errorf("macaroon not valid for operation")
			}
			return nil
		},
	}
	return checkers.PushFirstPartyChecker(m, checkers.Std)
}
Exemplo n.º 2
0
func (ctxt *context) CheckThirdPartyCaveat(cavId, cav string) ([]bakery.Caveat, error) {
	h := ctxt.handler
	log.Printf("checking third party caveat %q", cav)
	op, rest, err := checkers.ParseCaveat(cav)
	if err != nil {
		return nil, fmt.Errorf("cannot parse caveat %q: %v", cav, err)
	}
	switch op {
	case "can-speak-for":
		// TODO(rog) We ignore the currently logged in user here,
		// but perhaps it would be better to let the user be in control
		// of which user they're currently "declared" as, rather than
		// getting privileges of users we currently have macaroons for.
		checkErr := ctxt.canSpeakFor(rest)
		if checkErr == nil {
			return ctxt.firstPartyCaveats(), nil
		}
		return nil, h.needLogin(cavId, cav, checkErr.Error())
	case "member-of-group":
		// The third-party caveat is asking if the currently logged in
		// user is a member of a particular group.
		// We can find the currently logged in user by checking
		// the username cookie (which doesn't provide any power, but
		// indicates which user name to check)
		if ctxt.declaredUser == "" {
			return nil, h.needLogin(cavId, cav, "not logged in")
		}
		if err := ctxt.canSpeakFor(ctxt.declaredUser); err != nil {
			return nil, errgo.Notef(err, "cannot speak for declared user %q", ctxt.declaredUser)
		}
		info, ok := h.users[ctxt.declaredUser]
		if !ok {
			return nil, errgo.Newf("user %q not found", ctxt.declaredUser)
		}
		group := rest
		if !info.Groups[group] {
			return nil, errgo.Newf("not privileged enough")
		}
		return ctxt.firstPartyCaveats(), nil
	default:
		return nil, &bakery.CaveatNotRecognizedError{cav}
	}
}
Exemplo n.º 3
0
func (ctxt *context) CheckFirstPartyCaveat(caveat string) error {
	op, rest, err := checkers.ParseCaveat(caveat)
	if err != nil {
		return fmt.Errorf("cannot parse caveat %q: %v", caveat, err)
	}
	switch op {
	case "user-is":
		if rest != ctxt.declaredUser {
			return fmt.Errorf("not logged in as %q", rest)
		}
		return nil
	case "operation":
		if ctxt.operation != "" && rest == ctxt.operation {
			return nil
		}
		return errgo.Newf("operation mismatch")
	default:
		return &bakery.CaveatNotRecognizedError{caveat}
	}
}