Example #1
0
// userHandler handles requests to add new users, change user details, etc.
// It is only accessible to users that are members of the admin group.
func (h *handler) userHandler(_ http.Header, req *http.Request) (interface{}, error) {
	ctxt := h.newContext(req, "change-user")
	breq := h.svc.NewRequest(req, ctxt)
	err := breq.Check()
	if err != nil {
		// We issue a macaroon with a third-party caveat targetting
		// the id service itself. This means that the flow for self-created
		// macaroons is just the same as for any other service.
		// Theoretically, we could just redirect the user to the
		// login page, but that would require a different flow
		// and it's not clear that it would be an advantage.
		m, err := h.svc.NewMacaroon("", nil, []bakery.Caveat{
			checkers.ThirdParty(h.svc.Location(), "member-of-group admin"),
			checkers.FirstParty("operation change-user"),
		})
		if err != nil {
			return nil, errgo.Notef(err, "cannot mint new macaroon")
		}
		return nil, &httpbakery.Error{
			Message: err.Error(),
			Code:    httpbakery.ErrDischargeRequired,
			Info: &httpbakery.ErrorInfo{
				Macaroon: m,
			},
		}
	}
	// PUT /user/$user - create new user
	// PUT /user/$user/group-membership - change group membership of user
	return nil, errgo.New("not implemented yet")
}
Example #2
0
// writeError writes an error to w. If the error was generated because
// of a required macaroon that the client does not have, we mint a
// macaroon that, when discharged, will grant the client the
// right to execute the given operation.
//
// The logic in this function is crucial to the security of the service
// - it must determine for a given operation what caveats to attach.
func (srv *targetServiceHandler) writeError(w http.ResponseWriter, operation string, verr error) {
	fail := func(code int, msg string, args ...interface{}) {
		if code == http.StatusInternalServerError {
			msg = "internal error: " + msg
		}
		http.Error(w, fmt.Sprintf(msg, args...), code)
	}

	if _, ok := verr.(*bakery.VerificationError); !ok {
		fail(http.StatusForbidden, "%v", verr)
		return
	}

	// Work out what caveats we need to apply for the given operation.
	// Could special-case the operation here if desired.
	caveats := []bakery.Caveat{
		checkers.TimeBefore(time.Now().Add(5 * time.Minute)),
		checkers.ThirdParty(srv.authEndpoint, "access-allowed"),
		checkers.FirstParty("operation " + operation),
	}
	// Mint an appropriate macaroon and send it back to the client.
	m, err := srv.svc.NewMacaroon("", nil, caveats)
	if err != nil {
		fail(http.StatusInternalServerError, "cannot mint macaroon: %v", err)
		return
	}
	httpbakery.WriteDischargeRequiredError(w, m, verr)
}